def ast_parse_op(t): if len(t) == 1: return t[0] if len(t) == 2: if t[0] in ['-', '+', '!']: return m2_expr.ExprOp(t[0], t[1]) if len(t) == 3: args = [t[0], t[2]] if t[1] == '-': # a - b => a + (-b) t[1] = '+' t[2] = -t[2] return m2_expr.ExprOp(t[1], t[0], t[2]) t = t[::-1] while len(t) >= 3: o1, op, o2 = t.pop(), t.pop(), t.pop() if op == '-': # a - b => a + (-b) op = '+' o2 = -o2 e = m2_expr.ExprOp(op, o1, o2) t.append(e) if len(t) != 1: raise NotImplementedError('strange op') return t[0]
def patch_rotate_tpl(ir, instr, dst, src, op, left=False): '''Template to generate a rotater with operation @op A temporary basic block is generated to handle 0-rotate @op: operation to execute @left (optional): indicates a left rotate if set, default is False ''' # Compute results shifter = get_shift(dst, src) res = m2_expr.ExprOp(op, dst, shifter) # CF is computed with 1-less round than `res` new_cf = m2_expr.ExprOp( op, dst, shifter - m2_expr.ExprInt(1, size=shifter.size)) new_cf = new_cf.msb() if left else new_cf[:1] # OF is defined only for @b == 1 new_of = m2_expr.ExprCond( src - m2_expr.ExprInt(1, size=src.size), m2_expr.ExprInt(0, size=of.size), res.msb() ^ new_cf if left else (dst ^ res).msb()) # Build basic blocks e_do = [ m2_expr.ExprAff(cf, new_cf), m2_expr.ExprAff(of, new_of), m2_expr.ExprAff(dst, res) ] # Don't generate conditional shifter on constant return (e_do, [])
def patch_div(ir, instr, src1): # print '[*] Calling patched div.' e = [] size = src1.size if size == 8: src2 = mRAX[instr.mode][:16] elif size in [16, 32, 64]: s1, s2 = mRDX[size], mRAX[size] src2 = m2_expr.ExprCompose(s2, s1) else: raise ValueError('div arg not impl', src1) c_d = m2_expr.ExprOp('udiv', src2, src1.zeroExtend(src2.size)) c_r = m2_expr.ExprOp('umod', src2, src1.zeroExtend(src2.size)) # if 8 bit div, only ax is affected if size == 8: e.append( m2_expr.ExprAff(src2, m2_expr.ExprCompose(c_d[:8], c_r[:8]))) else: e.append(m2_expr.ExprAff(s1, c_r[:size])) e.append(m2_expr.ExprAff(s2, c_d[:size])) return e, []
def patch_rotate_with_carry_tpl(ir, instr, op, dst, src): # Compute results shifter = get_shift(dst, src).zeroExtend(dst.size + 1) result = m2_expr.ExprOp(op, m2_expr.ExprCompose(dst, cf), shifter) new_cf = result[dst.size:dst.size + 1] new_dst = result[:dst.size] result_trunc = result[:dst.size] if op == '<<<': of_value = result_trunc.msb() ^ new_cf else: of_value = (dst ^ result_trunc).msb() # OF is defined only for @b == 1 new_of = m2_expr.ExprCond(src - m2_expr.ExprInt(1, size=src.size), m2_expr.ExprInt(0, size=of.size), of_value) # Build basic blocks e_do = [ m2_expr.ExprAff(cf, new_cf), m2_expr.ExprAff(of, new_of), m2_expr.ExprAff(dst, new_dst) ] return (e_do, [])
def substract_mems(self, a, b): ex = b.arg - a.arg ex = self.expr_simp(self.eval_expr(ex, {})) if not isinstance(ex, m2_expr.ExprInt): return None ptr_diff = int(int32(ex.arg)) out = [] if ptr_diff < 0: # [a ] #[b ]XXX sub_size = b.size + ptr_diff * 8 if sub_size >= a.size: pass else: ex = m2_expr.ExprOp('+', a.arg, m2_expr.ExprInt_from(a.arg, sub_size / 8)) ex = self.expr_simp(self.eval_expr(ex, {})) rest_ptr = ex rest_size = a.size - sub_size val = self.symbols[a][sub_size:a.size] out = [(m2_expr.ExprMem(rest_ptr, rest_size), val)] else: #[a ] # XXXX[b ]YY #[a ] # XXXX[b ] out = [] # part X if ptr_diff > 0: val = self.symbols[a][0:ptr_diff * 8] out.append((m2_expr.ExprMem(a.arg, ptr_diff * 8), val)) # part Y if ptr_diff * 8 + b.size < a.size: ex = m2_expr.ExprOp('+', b.arg, m2_expr.ExprInt_from(b.arg, b.size / 8)) ex = self.expr_simp(self.eval_expr(ex, {})) rest_ptr = ex rest_size = a.size - (ptr_diff * 8 + b.size) val = self.symbols[a][ptr_diff * 8 + b.size:a.size] out.append((m2_expr.ExprMem(ex, val.size), val)) return out
def _simp_handle_segm(self, e_s, expr): """Handle 'segm' operation""" if expr.op != "segm": return expr segm_nb = int(expr.args[0]) segmaddr = self.cpu.get_segm_base(segm_nb) return e_s( m2_expr.ExprOp("+", m2_expr.ExprInt(segmaddr, expr.size), expr.args[1]))
def get_ir(self, instr): args = instr.args if len(args) and isinstance(args[-1], m2_expr.ExprOp): if (args[-1].op in ['<<', '>>', '<<a', 'a>>', '<<<', '>>>'] and isinstance(args[-1].args[-1], m2_expr.ExprId)): args[-1] = m2_expr.ExprOp(args[-1].op, args[-1].args[0], args[-1].args[-1][:8].zeroExtend(32)) instr_ir, extra_ir = get_mnemo_expr(self, instr, *args) self.mod_pc(instr, instr_ir, extra_ir) instr_ir, extra_ir = self.del_dst_zr(instr, instr_ir, extra_ir) return instr_ir, extra_ir
def apply_expr_on_state_visit_cache(self, expr, state, cache, level=0): """ Deep First evaluate nodes: 1. evaluate node's sons 2. simplify """ expr = self.expr_simp(expr) #print '\t'*level, "Eval:", expr if expr in cache: ret = cache[expr] #print "In cache!", ret elif expr.is_int(): return expr elif expr.is_id(): if isinstance(expr.name, asmblock.AsmLabel) and expr.name.offset is not None: ret = m2_expr.ExprInt(expr.name.offset, expr.size) else: ret = state.get(expr, expr) elif expr.is_mem(): ptr = self.apply_expr_on_state_visit_cache(expr.arg, state, cache, level+1) ret = m2_expr.ExprMem(ptr, expr.size) ret = self.get_mem_state(ret) assert expr.size == ret.size elif expr.is_cond(): cond = self.apply_expr_on_state_visit_cache(expr.cond, state, cache, level+1) src1 = self.apply_expr_on_state_visit_cache(expr.src1, state, cache, level+1) src2 = self.apply_expr_on_state_visit_cache(expr.src2, state, cache, level+1) ret = m2_expr.ExprCond(cond, src1, src2) elif expr.is_slice(): arg = self.apply_expr_on_state_visit_cache(expr.arg, state, cache, level+1) ret = m2_expr.ExprSlice(arg, expr.start, expr.stop) elif expr.is_op(): args = [] for oarg in expr.args: arg = self.apply_expr_on_state_visit_cache(oarg, state, cache, level+1) assert oarg.size == arg.size args.append(arg) ret = m2_expr.ExprOp(expr.op, *args) elif expr.is_compose(): args = [] for arg in expr.args: args.append(self.apply_expr_on_state_visit_cache(arg, state, cache, level+1)) ret = m2_expr.ExprCompose(*args) else: raise TypeError("Unknown expr type") #print '\t'*level, "Result", ret ret = self.expr_simp(ret) #print '\t'*level, "Result simpl", ret assert expr.size == ret.size cache[expr] = ret return ret
def asm_ast_to_expr_with_size(arg, symbol_pool, size): if isinstance(arg, AstId): return m2_expr.ExprId(arg.name, size) if isinstance(arg, AstOp): args = [ asm_ast_to_expr_with_size(tmp, symbol_pool, size) for tmp in arg.args ] return m2_expr.ExprOp(arg.op, *args) if isinstance(arg, AstInt): return m2_expr.ExprInt(arg.value, size) return None
def ast_parse_op(tokens): if len(tokens) == 1: return tokens[0] if len(tokens) == 2: if tokens[0] in ['-', '+', '!']: return m2_expr.ExprOp(tokens[0], tokens[1]) if len(tokens) == 3: if tokens[1] == '-': # a - b => a + (-b) tokens[1] = '+' tokens[2] = -tokens[2] return m2_expr.ExprOp(tokens[1], tokens[0], tokens[2]) tokens = tokens[::-1] while len(tokens) >= 3: o1, op, o2 = tokens.pop(), tokens.pop(), tokens.pop() if op == '-': # a - b => a + (-b) op = '+' o2 = -o2 e = m2_expr.ExprOp(op, o1, o2) tokens.append(e) if len(tokens) != 1: raise NotImplementedError('strange op') return tokens[0]
def simp_add_mul(expr_simp, expr): "Naive Simplification: a + a + a == a * 3" # Match the expected form ## isinstance(expr, m2_expr.ExprOp) is not needed: simplifications are ## attached to expression types if expr.op == "+" and \ len(expr.args) == 3 and \ expr.args.count(expr.args[0]) == len(expr.args): # Effective simplification return m2_expr.ExprOp("*", expr.args[0], m2_expr.ExprInt(3, expr.args[0].size)) else: # Do not simplify return expr
def operation(cls, size=32, depth=1): """Return an ExprOp @size: (optional) Operation size @depth: (optional) Expression depth """ operand_type = random.choice(cls.operations_by_args_number.keys()) if isinstance(operand_type, str) and "+" in operand_type: number_args = random.randint(int(operand_type[:-1]), cls.operations_max_args_number) else: number_args = operand_type args = [ cls._gen(size=size, depth=depth - 1) for _ in xrange(number_args) ] operand = random.choice(cls.operations_by_args_number[operand_type]) return m2_expr.ExprOp(operand, *args)
def udiv(arg1, arg2, arg3): if arg3: arg1 = m2_expr.ExprOp('udiv', arg2, arg3) else: exception_flags = m2_expr.ExprInt(EXCEPT_DIV_BY_ZERO, exception_flags.size)
def asr(arg1, arg2, arg3): arg1 = m2_expr.ExprOp( 'a>>', arg2, (arg3 & m2_expr.ExprInt(arg3.size - 1, arg3.size)))
def asr(arg1, arg2, arg3): arg1 = m2_expr.ExprOp('a>>', arg2, (arg3 & m2_expr.ExprInt_from(arg3, arg3.size - 1)))
def eval_ExprMem(self, e, eval_cache=None): if eval_cache is None: eval_cache = {} a_val = self.expr_simp(self.eval_expr(e.arg, eval_cache)) if a_val != e.arg: a = self.expr_simp(m2_expr.ExprMem(a_val, size=e.size)) else: a = e if a in self.symbols: return self.symbols[a] tmp = None # test if mem lookup is known if a_val in self.symbols.symbols_mem: tmp = self.symbols.symbols_mem[a_val][0] if tmp is None: v = self.find_mem_by_addr(a_val) if not v: out = [] ov = self.get_mem_overlapping(a, eval_cache) off_base = 0 ov.sort() # ov.reverse() for off, x in ov: # off_base = off * 8 # x_size = self.symbols[x].size if off >= 0: m = min(a.size - off * 8, x.size) ee = m2_expr.ExprSlice(self.symbols[x], 0, m) ee = self.expr_simp(ee) out.append((ee, off_base, off_base + m)) off_base += m else: m = min(a.size - off * 8, x.size) ee = m2_expr.ExprSlice(self.symbols[x], -off * 8, m) ff = self.expr_simp(ee) new_off_base = off_base + m + off * 8 out.append((ff, off_base, new_off_base)) off_base = new_off_base if out: missing_slice = self.rest_slice(out, 0, a.size) for sa, sb in missing_slice: ptr = self.expr_simp( a_val + m2_expr.ExprInt_from(a_val, sa / 8)) mm = m2_expr.ExprMem(ptr, size=sb - sa) mm.is_term = True mm.is_simp = True out.append((mm, sa, sb)) out.sort(key=lambda x: x[1]) # for e, sa, sb in out: # print str(e), sa, sb ee = m2_expr.ExprSlice(m2_expr.ExprCompose(out), 0, a.size) ee = self.expr_simp(ee) return ee if self.func_read and isinstance(a.arg, m2_expr.ExprInt): return self.func_read(a) else: # XXX hack test a.is_term = True return a # bigger lookup if a.size > tmp.size: rest = a.size ptr = a_val out = [] ptr_index = 0 while rest: v = self.find_mem_by_addr(ptr) if v is None: # raise ValueError("cannot find %s in mem"%str(ptr)) val = m2_expr.ExprMem(ptr, 8) v = val diff_size = 8 elif rest >= v.size: val = self.symbols[v] diff_size = v.size else: diff_size = rest val = self.symbols[v][0:diff_size] val = (val, ptr_index, ptr_index + diff_size) out.append(val) ptr_index += diff_size rest -= diff_size ptr = self.expr_simp( self.eval_expr( m2_expr.ExprOp('+', ptr, m2_expr.ExprInt_from(ptr, v.size / 8)), eval_cache)) e = self.expr_simp(m2_expr.ExprCompose(out)) return e # part lookup tmp = self.expr_simp(m2_expr.ExprSlice(self.symbols[tmp], 0, a.size)) return tmp
def __ExprOp_cond(op, arg1, arg2): "Return an ExprOp standing for arg1 op arg2 with size to 1" ec = m2_expr.ExprOp(op, arg1, arg2) return ec
def mul(ir, instr, a, b, c): """Multiplies @b by $c and stores the result in @a.""" e = [] e.append(m2_expr.ExprAff(a, m2_expr.ExprOp('imul', b, c))) return e, []
# Match the expected form ## isinstance(expr, m2_expr.ExprOp) is not needed: simplifications are ## attached to expression types if expr.op == "+" and \ len(expr.args) == 3 and \ expr.args.count(expr.args[0]) == len(expr.args): # Effective simplification return m2_expr.ExprOp("*", expr.args[0], m2_expr.ExprInt(3, expr.args[0].size)) else: # Do not simplify return expr a = m2_expr.ExprId('a') base_expr = a + a + a print "Without adding the simplification:" print "\t%s = %s" % (base_expr, expr_simp(base_expr)) # Enable pass expr_simp.enable_passes({m2_expr.ExprOp: [simp_add_mul]}) print "After adding the simplification:" print "\t%s = %s" % (base_expr, expr_simp(base_expr)) # Automatic fail assert (expr_simp(base_expr) == m2_expr.ExprOp("*", a, m2_expr.ExprInt(3, a.size)))
def swc1(ir, instr, a, b): e = [] src = m2_expr.ExprOp('single_to_mem_%.2d' % a.size, a) e.append(m2_expr.ExprAff(b, src)) return e, []
def lwc1(ir, instr, a, b): e = [] src = m2_expr.ExprOp('mem_%.2d_to_single' % b.size, b) e.append(m2_expr.ExprAff(a, src)) return e, []
def mul_d(ir, instr, a, b, c): # XXX TODO check e = [] e.append(m2_expr.ExprAff(a, m2_expr.ExprOp('fmul', b, c))) return e, []
def udiv(arg1, arg2, arg3): arg1 = m2_expr.ExprOp('udiv', arg2, arg3)
def srav(ir, instr, a, b, c): e = [] value = m2_expr.ExprOp('a>>', b, c&m2_expr.ExprInt32(0x1F)) e.append(m2_expr.ExprAff(a, value)) return e, []
def sra(ir, instr, a, b, c): """Shifts a register value @b right by the shift amount @c and places the value in the destination register @a. The sign bit is shifted in.""" e = [] e.append(m2_expr.ExprAff(a, m2_expr.ExprOp('a>>', b, c))) return e, []
def possible_values(expr): """Return possible values for expression @expr, associated with their condition constraint as a ConstrainedValues instance @expr: Expr instance """ consvals = ConstrainedValues() # Terminal expression if (isinstance(expr, m2_expr.ExprInt) or isinstance(expr, m2_expr.ExprId)): consvals.add(ConstrainedValue(frozenset(), expr)) # Unary expression elif isinstance(expr, m2_expr.ExprSlice): consvals.update(ConstrainedValue(consval.constraints, consval.value[expr.start:expr.stop]) for consval in possible_values(expr.arg)) elif isinstance(expr, m2_expr.ExprMem): consvals.update(ConstrainedValue(consval.constraints, m2_expr.ExprMem(consval.value, expr.size)) for consval in possible_values(expr.arg)) elif isinstance(expr, m2_expr.ExprAff): consvals.update(possible_values(expr.src)) # Special case: constraint insertion elif isinstance(expr, m2_expr.ExprCond): to_ret = set() src1cond = CondConstraintNotZero(expr.cond) src2cond = CondConstraintZero(expr.cond) consvals.update(ConstrainedValue(consval.constraints.union([src1cond]), consval.value) for consval in possible_values(expr.src1)) consvals.update(ConstrainedValue(consval.constraints.union([src2cond]), consval.value) for consval in possible_values(expr.src2)) # N-ary expression elif isinstance(expr, m2_expr.ExprOp): # For details, see ExprCompose consvals_args = [possible_values(arg) for arg in expr.args] for consvals_possibility in itertools.product(*consvals_args): args_value = [consval.value for consval in consvals_possibility] args_constraint = itertools.chain(*[consval.constraints for consval in consvals_possibility]) consvals.add(ConstrainedValue(frozenset(args_constraint), m2_expr.ExprOp(expr.op, *args_value))) elif isinstance(expr, m2_expr.ExprCompose): # Generate each possibility for sub-argument, associated with the start # and stop bit consvals_args = [map(lambda x: x, possible_values(arg)) for arg in expr.args] for consvals_possibility in itertools.product(*consvals_args): # Merge constraint of each sub-element args_constraint = itertools.chain(*[consval.constraints for consval in consvals_possibility]) # Gen the corresponding constraints / ExprCompose args = [consval.value for consval in consvals_possibility] consvals.add( ConstrainedValue(frozenset(args_constraint), m2_expr.ExprCompose(*args))) else: raise RuntimeError("Unsupported type for expr: %s" % type(expr)) return consvals
def c_le_d(ir, instr, a, b, c): e = [] e.append(m2_expr.ExprAff(a, m2_expr.ExprOp('fcomp_le', b, c))) return e, []
def cvt_d_w(ir, instr, a, b): e = [] # TODO XXX e.append(m2_expr.ExprAff(a, m2_expr.ExprOp('flt_d_w', b))) return e, []
def rotr(ir, instr, a, b, c): e = [] e.append(m2_expr.ExprAff(a, m2_expr.ExprOp('>>>', b, c))) return e, []
"Naive Simplification: a + a + a == a * 3" # Match the expected form ## isinstance(expr, m2_expr.ExprOp) is not needed: simplifications are ## attached to expression types if expr.op == "+" and \ len(expr.args) == 3 and \ expr.args.count(expr.args[0]) == len(expr.args): # Effective simplification return m2_expr.ExprOp("*", expr.args[0], m2_expr.ExprInt_from(expr.args[0], 3)) else: # Do not simplify return expr a = m2_expr.ExprId('a') base_expr = a + a + a print "Without adding the simplification:" print "\t%s = %s" % (base_expr, expr_simp(base_expr)) # Enable pass expr_simp.enable_passes({m2_expr.ExprOp: [simp_add_mul]}) print "After adding the simplification:" print "\t%s = %s" % (base_expr, expr_simp(base_expr)) # Automatic fail assert(expr_simp(base_expr) == m2_expr.ExprOp("*", a, m2_expr.ExprInt_from(a, 3)))