def simp_cmp_int_arg(expr_simp, expr): """ (0x10 <= R0) ? A:B => (R0 < 0x10) ? B:A """ cond = expr.cond if not cond.is_op(): return expr op = cond.op if op not in ['==', '<s', '<=s', '<u', '<=u']: return expr arg1, arg2 = cond.args if arg2.is_int(): return expr if not arg1.is_int(): return expr src1, src2 = expr.src1, expr.src2 if op == "==": return ExprCond(ExprOp('==', arg2, arg1), src1, src2) arg1, arg2 = arg2, arg1 src1, src2 = src2, src1 if op == '<s': op = '<=s' elif op == '<=s': op = '<s' elif op == '<u': op = '<=u' elif op == '<=u': op = '<u' return ExprCond(ExprOp(op, arg1, arg2), src1, src2)
def simp_cmp_int_arg(expr_simp, expr): """ (0x10 <= R0) ? A:B => (R0 < 0x10) ? B:A """ cond = expr.cond if not cond.is_op(): return expr op = cond.op if op not in [ TOK_EQUAL, TOK_INF_SIGNED, TOK_INF_EQUAL_SIGNED, TOK_INF_UNSIGNED, TOK_INF_EQUAL_UNSIGNED ]: return expr arg1, arg2 = cond.args if arg2.is_int(): return expr if not arg1.is_int(): return expr src1, src2 = expr.src1, expr.src2 if op == TOK_EQUAL: return ExprCond(ExprOp(TOK_EQUAL, arg2, arg1), src1, src2) arg1, arg2 = arg2, arg1 src1, src2 = src2, src1 if op == TOK_INF_SIGNED: op = TOK_INF_EQUAL_SIGNED elif op == TOK_INF_EQUAL_SIGNED: op = TOK_INF_SIGNED elif op == TOK_INF_UNSIGNED: op = TOK_INF_EQUAL_UNSIGNED elif op == TOK_INF_EQUAL_UNSIGNED: op = TOK_INF_UNSIGNED return ExprCond(ExprOp(op, arg1, arg2), src1, src2)
def simp_cmp_int(expr_simp, expr): """ ({X, 0} == int) => X == int[:] X + int1 == int2 => X == int2-int1 """ if (expr.is_op(TOK_EQUAL) and expr.args[1].is_int() and expr.args[0].is_compose() and len(expr.args[0].args) == 2 and expr.args[0].args[1].is_int(0)): # ({X, 0} == int) => X == int[:] src = expr.args[0].args[0] int_val = int(expr.args[1]) new_int = ExprInt(int_val, src.size) expr = expr_simp(ExprOp(TOK_EQUAL, src, new_int)) elif (expr.is_op() and expr.op in [ TOK_EQUAL, ] and expr.args[1].is_int() and expr.args[0].is_op("+") and expr.args[0].args[-1].is_int()): # X + int1 == int2 => X == int2-int1 # WARNING: # X - 0x10 <=u 0x20 gives X in [0x10 0x30] # which is not equivalet to A <=u 0x10 left, right = expr.args left, int_diff = left.args[:-1], left.args[-1] if len(left) == 1: left = left[0] else: left = ExprOp('+', *left) new_int = expr_simp(right - int_diff) expr = expr_simp(ExprOp(expr.op, left, new_int), ) return expr
def simp_zeroext_and_cst_eq_cst(expr_s, expr): """ A.zeroExt(X) & ... & int == int => A & ... & int[:A.size] == int[:A.size] """ if not expr.is_op(TOK_EQUAL): return expr arg1, arg2 = expr.args if not arg2.is_int(): return expr if not arg1.is_op('&'): return expr is_ok = True sizes = set() for arg in arg1.args: if arg.is_int(): continue if (arg.is_op() and arg.op.startswith("zeroExt")): sizes.add(arg.args[0].size) continue is_ok = False break if not is_ok: return expr if len(sizes) != 1: return expr size = list(sizes)[0] if int(arg2) > ((1 << size) - 1): return expr args = [expr_s(arg[:size]) for arg in arg1.args] left = ExprOp('&', *args) right = expr_s(arg2[:size]) ret = ExprOp(TOK_EQUAL, left, right) return ret
def test_sbvck3(self): """Test SBVCK3 execution""" # SBVCK3 R0,Rn,Rm exec_instruction( "SBVCK3 R0, R1, R2", [(ExprId("R1", 32), ExprInt(2, 32)), (ExprId("R2", 32), ExprInt(1, 32))], [(ExprId("R0", 32), ExprCond( ExprOp( ">", ExprInt(3, 32), ExprCond(ExprOp(">", ExprInt(0x2, 32), ExprInt(0x1, 32)), ExprInt(0x2, 32), ExprInt(0x1, 32))), ExprInt(1, 32), ExprInt(0, 32)))]) exec_instruction( "SBVCK3 R0, R1, R2", [(ExprId("R1", 32), ExprInt(0, 32)), (ExprId("R2", 32), ExprInt(1, 32))], [(ExprId("R0", 32), ExprCond( ExprOp( ">", ExprInt(1, 32), ExprCond(ExprOp(">", ExprInt(0, 32), ExprInt(1, 32)), ExprInt(0, 32), ExprInt(1, 32))), ExprInt( 1, 32), ExprInt(0, 32)))])
def simp_cond_op_int(e_s, expr): "Extract conditions from operations" # x?a:b + x?c:d + e => x?(a+c+e:b+d+e) if not expr.op in ["+", "|", "^", "&", "*", '<<', '>>', 'a>>']: return expr if len(expr.args) < 2: return expr conds = set() for arg in expr.args: if arg.is_cond(): conds.add(arg) if len(conds) != 1: return expr cond = list(conds).pop() args1, args2 = [], [] for arg in expr.args: if arg.is_cond(): args1.append(arg.src1) args2.append(arg.src2) else: args1.append(arg) args2.append(arg) return ExprCond(cond.cond, ExprOp(expr.op, *args1), ExprOp(expr.op, *args2))
def fcmpe(ir, instr, arg1, arg2): e = [] e.append(ExprAssign(nf, ExprOp('fcom_c0', arg1, arg2))) e.append(ExprAssign(cf, ~ExprOp('fcom_c0', arg1, arg2))) e.append(ExprAssign(zf, ExprOp('fcom_c3', arg1, arg2))) e.append(ExprAssign(of, ExprInt(0, 1))) return e, []
def simp_cond_int(expr_simp, expr): if (expr.cond.is_op(TOK_EQUAL) and expr.cond.args[1].is_int() and expr.cond.args[0].is_compose() and len(expr.cond.args[0].args) == 2 and expr.cond.args[0].args[1].is_int(0)): # ({X, 0} == int) => X == int[:] src = expr.cond.args[0].args[0] int_val = int(expr.cond.args[1]) new_int = ExprInt(int_val, src.size) expr = expr_simp( ExprCond(ExprOp(TOK_EQUAL, src, new_int), expr.src1, expr.src2)) elif (expr.cond.is_op() and expr.cond.op in [ TOK_EQUAL, TOK_INF_SIGNED, TOK_INF_EQUAL_SIGNED, TOK_INF_UNSIGNED, TOK_INF_EQUAL_UNSIGNED ] and expr.cond.args[1].is_int() and expr.cond.args[0].is_op("+") and expr.cond.args[0].args[-1].is_int()): # X + int1 == int2 => X == int2-int1 left, right = expr.cond.args left, int_diff = left.args[:-1], left.args[-1] if len(left) == 1: left = left[0] else: left = ExprOp('+', *left) new_int = expr_simp(right - int_diff) expr = expr_simp( ExprCond(ExprOp(expr.cond.op, left, new_int), expr.src1, expr.src2)) return expr
def simp_cond_factor(e_s, expr): "Merge similar conditions" if not expr.op in ["+", "|", "^", "&", "*", '<<', '>>', 'a>>']: return expr if len(expr.args) < 2: return expr conds = {} not_conds = [] multi_cond = False for arg in expr.args: if not arg.is_cond(): not_conds.append(arg) continue cond = arg.cond if not cond in conds: conds[cond] = [] else: multi_cond = True conds[cond].append(arg) if not multi_cond: return expr c_out = not_conds[:] for cond, vals in conds.items(): new_src1 = [x.src1 for x in vals] new_src2 = [x.src2 for x in vals] src1 = e_s.expr_simp_wrapper(ExprOp(expr.op, *new_src1)) src2 = e_s.expr_simp_wrapper(ExprOp(expr.op, *new_src2)) c_out.append(ExprCond(cond, src1, src2)) if len(c_out) == 1: new_e = c_out[0] else: new_e = ExprOp(expr.op, *c_out) return new_e
def ucvtf(ir, instr, arg1, arg2): # XXX TODO: rounding e = [] src = ExprOp('uint_to_fp', arg2) if arg1.size != src.size: src = ExprOp('fpconvert_fp%d' % arg1.size, src) e.append(ExprAssign(arg1, src)) return e, []
def fcvtzu(ir, instr, arg1, arg2): # XXX TODO: rounding e = [] e.append( ExprAssign( arg1, ExprOp('fp_to_uint%d' % arg1.size, ExprOp('fpround_towardszero', arg2)))) return e, []
def call_effects(self, ad): """ Default simulation of a function call to @ad @ad: (Expr) address of the called function """ return [ AssignBlock([ ExprAff(self.ret_reg, ExprOp('call_func_ret', ad, self.sp)), ExprAff(self.sp, ExprOp('call_func_stack', ad, self.sp)), ]) ]
def call_effects(self, ad, instr): new_sp = ExprOp("+", self.sp, ExprOp("-", ExprInt(0x4, 32))) next_addr = instr.offset + len(instr.b) next_label = self.symbol_pool.getby_offset(next_addr) block1 = AssignBlock([ ExprAff(self.sp, new_sp), ExprAff(ExprMem(new_sp, 32), ExprId(next_label, 32)) ]) block2 = AssignBlock([ExprAff(self.IRDst, ad)]) return [block1, block2]
def call_effects(self, ad, instr): return [AssignBlock([ExprAff(self.ret_reg, ExprOp('call_func_ret', ad, self.sp, self.arch.regs.R3, self.arch.regs.R4, self.arch.regs.R5, )), ExprAff(self.sp, ExprOp('call_func_stack', ad, self.sp)), ], instr )]
def add3(ir, instr, reg_dst, reg_src, reg_or_imm): """ADD3 - Add two register and store the result to a register, or add a register and an immediate and store the result to a register""" if isinstance(reg_or_imm, ExprId): # Rl <- Rn + Rm result = ExprOp("+", reg_src, reg_or_imm) else: # Rn <- Rm + SignExt(imm16) value = int(reg_or_imm.arg) result = ExprOp("+", reg_src, ExprInt(value, 32)) return [ExprAff(reg_dst, result)], []
def to_expr(self): """Generate Miasm expression representing the C access""" if isinstance(self.ctype, ObjCPtr): return ExprOp( "addr", ExprOp("[]", self.name.to_expr(), ExprInt(self.element, self.default_size))) elif isinstance(self.ctype, ObjCArray): return ExprOp("[]", self.name.to_expr(), ExprInt(self.element, self.default_size)) else: raise RuntimeError("Strange case")
def jmp(ir, instr, reg_or_imm): """JMP - Change PC to a register content or an immediate. Note: the behavior in VLIW mode is not implemented""" take_jmp = ExprInt(1, 32) if isinstance(reg_or_imm, ExprId): # PC <- Rm31..1||0 new_PC = ExprAssign(PC, reg_or_imm) else: # PC <- PC31..28||0000||(target24)23..1||0 new_PC = ExprAssign(PC, ExprOp("+", ExprOp("&", PC, ExprInt(0xF0000000, 32)), reg_or_imm)) return [new_PC, ExprAssign(ir.IRDst, new_PC)], []
def simp_cmp_int(expr_simp, expr): """ ({X, 0} == int) => X == int[:] X + int1 == int2 => X == int2-int1 X ^ int1 == int2 => X == int1^int2 """ if (expr.is_op(TOK_EQUAL) and expr.args[1].is_int() and expr.args[0].is_compose() and len(expr.args[0].args) == 2 and expr.args[0].args[1].is_int(0)): # ({X, 0} == int) => X == int[:] src = expr.args[0].args[0] int_val = int(expr.args[1]) new_int = ExprInt(int_val, src.size) expr = expr_simp(ExprOp(TOK_EQUAL, src, new_int)) elif not expr.is_op(TOK_EQUAL): return expr assert len(expr.args) == 2 left, right = expr.args if left.is_int() and not right.is_int(): left, right = right, left if not right.is_int(): return expr if not (left.is_op() and left.op in ['+', '^']): return expr if not left.args[-1].is_int(): return expr # X + int1 == int2 => X == int2-int1 # WARNING: # X - 0x10 <=u 0x20 gives X in [0x10 0x30] # which is not equivalet to A <=u 0x10 left_orig = left left, last_int = left.args[:-1], left.args[-1] if len(left) == 1: left = left[0] else: left = ExprOp(left.op, *left) if left_orig.op == "+": new_int = expr_simp(right - last_int) elif left_orig.op == '^': new_int = expr_simp(right ^ last_int) else: raise RuntimeError("Unsupported operator") expr = expr_simp(ExprOp(TOK_EQUAL, left, new_int), ) return expr
def ast_get_c_access_expr(ast, expr_types, lvl=0): """Transform C ast object into a C Miasm expression @ast: parsed pycparser.c_ast object @expr_types: a dictionnary linking ID names to their types @lvl: actual recursion level Example: IN: StructRef: -> ID: ptr_Test ID: a OUT: ExprOp('->', ExprId('ptr_Test', 64), ExprId('a', 64)) """ if isinstance(ast, c_ast.Constant): obj = ExprInt(int(ast.value), 64) elif isinstance(ast, c_ast.StructRef): name, field = ast.name, ast.field.name name = ast_get_c_access_expr(name, expr_types) if ast.type == "->": s_name = name s_field = ExprId(field, 64) obj = ExprOp('->', s_name, s_field) elif ast.type == ".": s_name = name s_field = ExprId(field, 64) obj = ExprOp("field", s_name, s_field) else: raise RuntimeError("Unknown struct access") elif isinstance(ast, c_ast.UnaryOp) and ast.op == "&": tmp = ast_get_c_access_expr(ast.expr, expr_types, lvl + 1) obj = ExprOp("addr", tmp) elif isinstance(ast, c_ast.ArrayRef): tmp = ast_get_c_access_expr(ast.name, expr_types, lvl + 1) index = ast_get_c_access_expr(ast.subscript, expr_types, lvl + 1) obj = ExprOp("[]", tmp, index) elif isinstance(ast, c_ast.ID): assert ast.name in expr_types obj = ExprId(ast.name, 64) elif isinstance(ast, c_ast.UnaryOp) and ast.op == "*": tmp = ast_get_c_access_expr(ast.expr, expr_types, lvl + 1) obj = ExprOp("deref", tmp) else: raise NotImplementedError("Unknown type") return obj
def simp_cond_sign_bit(_, expr): """(a & .. & 0x80000000) ? A:B => (a & ...) <s 0 ? A:B""" cond = expr.cond if not cond.is_op('&'): return expr last = cond.args[-1] if not last.is_int(1 << (last.size - 1)): return expr zero = ExprInt(0, expr.cond.size) if len(cond.args) == 2: args = [cond.args[0], zero] else: args = [ExprOp('&', *list(cond.args[:-1])), zero] cond = ExprOp(TOK_INF_SIGNED, *args) return ExprCond(cond, expr.src1, expr.src2)
def call_effects(self, ad, instr): call_assignblks = AssignBlock([ ExprAssign( self.ret_reg, ExprOp( 'call_func_ret', ad, self.sp, self.arch.regs.R3, self.arch.regs.R4, self.arch.regs.R5, )), ExprAssign(self.sp, ExprOp('call_func_stack', ad, self.sp)), ], instr) return [call_assignblks], []
def call_effects(self, ad, instr): """Default modelisation of a function call to @ad. This may be used to: * insert dependencies to arguments (stack base, registers, ...) * add some side effects (stack clean, return value, ...) @ad: (Expr) address of the called function @instr: native instruction which is responsible of the call """ return [AssignBlock( [ExprAff(self.ret_reg, ExprOp('call_func_ret', ad, self.sp)), ExprAff(self.sp, ExprOp( 'call_func_stack', ad, self.sp)), ])]
def test_ExprOp_strcst(self): from miasm2.expression.expression import ExprInt, ExprOp from miasm2.ir.translators.translator import Translator translator_smt2 = Translator.to_language("smt2") args = [ExprInt(i, 32) for i in xrange(9)] self.assertEqual(translator_smt2.from_expr(ExprOp('|', *args[:2])), r'(bvor (_ bv0 32) (_ bv1 32))') self.assertEqual(translator_smt2.from_expr(ExprOp('-', *args[:2])), r'(bvsub (_ bv0 32) (_ bv1 32))') self.assertEqual(translator_smt2.from_expr(ExprOp('+', *args[:3])), r'(bvadd (bvadd (_ bv0 32) (_ bv1 32)) (_ bv2 32))') self.assertRaises(NotImplementedError, translator_smt2.from_expr, ExprOp('X', *args[:1]))
def call_effects(self, ad, instr): call_assignblk = AssignBlock([ ExprAff( self.ret_reg, ExprOp( 'call_func_ret', ad, self.sp, self.arch.regs.RCX, self.arch.regs.RDX, self.arch.regs.R8, self.arch.regs.R9, )), ExprAff(self.sp, ExprOp('call_func_stack', ad, self.sp)), ], instr) return [call_assignblk], []
def simp_slice_of_op_ext(expr_s, expr): """ (X.zeroExt() + {Z, } + ... + Int)[0:8] => X + ... + int[:] (X.zeroExt() | ... | Int)[0:8] => X | ... | int[:] ... """ if expr.start != 0: return expr src = expr.arg if not src.is_op(): return expr if src.op not in ['+', '|', '^', '&']: return expr is_ok = True for arg in src.args: if arg.is_int(): continue if (arg.is_op() and arg.op.startswith("zeroExt") and arg.args[0].size == expr.stop): continue if arg.is_compose(): continue is_ok = False break if not is_ok: return expr args = [expr_s(arg[:expr.stop]) for arg in src.args] return ExprOp(src.op, *args)
def simp_cond_logic_ext(expr_s, expr): """(X.zeroExt() + ... + Int) ? A:B => X + ... + int[:] ? A:B""" cond = expr.cond if not cond.is_op(): return expr if cond.op not in ["&", "^", "|"]: return expr is_ok = True sizes = set() for arg in cond.args: if arg.is_int(): continue if (arg.is_op() and arg.op.startswith("zeroExt")): sizes.add(arg.args[0].size) continue is_ok = False break if not is_ok: return expr if len(sizes) != 1: return expr size = list(sizes)[0] args = [expr_s(arg[:size]) for arg in cond.args] cond = ExprOp(cond.op, *args) return ExprCond(cond, expr.src1, expr.src2)
def call_effects(self, ad): irs = [[ ExprAff( self.ret_reg, ExprOp( 'call_func_ret', ad, self.sp, self.arch.regs.RCX, self.arch.regs.RDX, self.arch.regs.R8, self.arch.regs.R9, )), ExprAff(self.sp, ExprOp('call_func_stack', ad, self.sp)), ]] return irs
def access_simplifier(expr): """Expression visitor to simplify a C access represented in Miasm @expr: Miasm expression representing the C access Example: IN: (In c: ['*(&((&((*(ptr_Test)).a))[0]))']) [ExprOp('deref', ExprOp('addr', ExprOp('[]', ExprOp('addr', ExprOp('field', ExprOp('deref', ExprId('ptr_Test', 64)), ExprId('a', 64))), ExprInt(0x0, 64))))] OUT: (In c: ['(ptr_Test)->a']) [ExprOp('->', ExprId('ptr_Test', 64), ExprId('a', 64))] """ if (expr.is_op("addr") and expr.args[0].is_op("[]") and expr.args[0].args[1] == ExprInt(0, 64)): return expr.args[0].args[0] elif (expr.is_op("[]") and expr.args[0].is_op("addr") and expr.args[1] == ExprInt(0, 64)): return expr.args[0].args[0] elif (expr.is_op("addr") and expr.args[0].is_op("deref")): return expr.args[0].args[0] elif (expr.is_op("deref") and expr.args[0].is_op("addr")): return expr.args[0].args[0] elif (expr.is_op("field") and expr.args[0].is_op("deref")): return ExprOp("->", expr.args[0].args[0], expr.args[1]) return expr
def update_flag_arith_sub_zn(arg1, arg2): """ Compute zf and nf flags for (arg1 - arg2) """ e = [] e += update_flag_zf_eq(arg1, arg2) e += [ExprAssign(nf, ExprOp("FLAG_SIGN_SUB", arg1, arg2))] return e
def update_flag_arith_subwc_zn(arg1, arg2, arg3): """ Compute znp flags for (arg1 - (arg2 + cf)) """ e = [] e += update_flag_zfsubwc_eq(arg1, arg2, arg3) e += [ExprAssign(nf, ExprOp("FLAG_SIGN_SUBWC", arg1, arg2, arg3))] return e