def slt(arg1, arg2, arg3): """If @arg2 is less than @arg3 (signed), @arg1 is set to one. It gets zero otherwise.""" arg1 = m2_expr.ExprCond( m2_expr.ExprOp(m2_expr.TOK_INF_SIGNED, arg2, arg3), m2_expr.ExprInt(1, arg1.size), m2_expr.ExprInt(0, arg1.size) )
def expr_simp_equal(expr_simp, e): """(x - y)?(0:1) == (x == y)""" to_match = m2_expr.ExprCond(jok1 + jok2, m2_expr.ExprInt(0, 1), m2_expr.ExprInt(1, 1)) r = __match_expr_wrap(e, to_match, [jok1, jok2]) if r is False: return e return ExprOp_equal(r[jok1], expr_simp(-r[jok2]))
def get_ir(self, instr): args = instr.args instr_ir, extra_ir = get_mnemo_expr(self, instr, *args) fixed_regs = { self.pc: m2_expr.ExprInt(instr.offset + 4, 32), ZERO: m2_expr.ExprInt(0, 32) } instr_ir = [m2_expr.ExprAssign(expr.dst, expr.src.replace_expr(fixed_regs)) for expr in instr_ir] new_extra_ir = [irblock.modify_exprs(mod_src=lambda expr: expr.replace_expr(fixed_regs)) for irblock in extra_ir] return instr_ir, new_extra_ir
def block2assignblks(self, block): irblocks_list = super(mipsCGen, self).block2assignblks(block) for irblocks in irblocks_list: for blk_idx, irblock in enumerate(irblocks): has_breakflow = any(assignblock.instr.breakflow() for assignblock in irblock) if not has_breakflow: continue irs = [] for assignblock in irblock: if self.ir_arch.pc not in assignblock: irs.append(AssignBlock(assignments, assignblock.instr)) continue assignments = dict(assignblock) # Add internal branch destination assignments[self.delay_slot_dst] = assignblock[ self.ir_arch.pc] assignments[self.delay_slot_set] = m2_expr.ExprInt(1, 32) # Replace IRDst with next instruction dst_loc_key = self.ir_arch.get_next_instr( assignblock.instr) assignments[self.ir_arch.IRDst] = m2_expr.ExprLoc( dst_loc_key, 32) irs.append(AssignBlock(assignments, assignblock.instr)) irblocks[blk_idx] = IRBlock(irblock.loc_key, irs) return irblocks_list
def elements(self): value = self.cbReg.value if value in self.stk_args: line = self.ircfg.blocks[self.loc_key][self.line_nb].instr arg_num = self.stk_args[value] stk_high = m2_expr.ExprInt(idc.get_spd(line.offset), ir_arch.sp.size) stk_off = m2_expr.ExprInt(self.ira.sp.size // 8 * arg_num, ir_arch.sp.size) element = m2_expr.ExprMem(self.mn.regs.regs_init[ir_arch.sp] + stk_high + stk_off, self.ira.sp.size) element = expr_simp(element) # Force stack unaliasing self.stk_unalias_force = True elif value: element = self.ira.arch.regs.all_regs_ids_byname.get(value, None) else: raise ValueError("Unknown element '%s'!" % value) return set([element])
def bltzl(arg1, arg2): """Branches on @arg2 if the register @arg1 is less than zero""" dst_o = arg2 if m2_expr.ExprOp( m2_expr.TOK_INF_SIGNED, arg1, m2_expr.ExprInt( 0, arg1.size)) else m2_expr.ExprLoc( ir.get_next_delay_loc_key(instr), ir.IRDst.size) PC = dst_o ir.IRDst = dst_o
def bgtzl(arg1, arg2): """Branches on @arg2 if the register @arg1 is greater than zero""" cond = m2_expr.ExprOp(m2_expr.TOK_INF_EQUAL_SIGNED, arg1, m2_expr.ExprInt(0, arg1.size)) dst_o = m2_expr.ExprLoc(ir.get_next_delay_loc_key(instr), ir.IRDst.size) if cond else arg2 PC = dst_o ir.IRDst = dst_o
def blezl(arg1, arg2): """Branches on @arg2 if the register @arg1 is less than or equal to zero""" cond = m2_expr.ExprOp(m2_expr.TOK_INF_EQUAL_SIGNED, arg1, m2_expr.ExprInt(0, arg1.size)) dst_o = arg2 if cond else m2_expr.ExprLoc(ir.get_next_delay_loc_key(instr), ir.IRDst.size) PC = dst_o ir.IRDst = dst_o
def _simp_handle_segm(self, e_s, expr): """Handle 'segm' operation""" if not is_op_segm(expr): return expr if not expr.args[0].is_int(): return expr segm_nb = int(expr.args[0]) segmaddr = self.cpu.get_segm_base(segm_nb) return e_s(m2_expr.ExprInt(segmaddr, expr.size) + expr.args[1])
def bgezl(arg1, arg2): """Branches on @arg2 if the quantities of register @arg1 is greater than or equal to zero""" dst = m2_expr.ExprLoc(ir.get_next_delay_loc_key(instr), ir.IRDst.size) if m2_expr.ExprOp( m2_expr.TOK_INF_SIGNED, arg1, m2_expr.ExprInt(0, arg1.size)) else arg2 PC = dst ir.IRDst = dst
def resolve_args_with_symbols(self, symbols=None): if symbols is None: symbols = LocationDB() args_out = [] for expr in self.args: # try to resolve symbols using symbols (0 for default value) loc_keys = m2_expr.get_expr_locs(expr) fixed_expr = {} for exprloc in loc_keys: loc_key = exprloc.loc_key names = symbols.get_location_names(loc_key) # special symbols if b'$' in names: fixed_expr[exprloc] = self.get_asm_offset(exprloc) continue if b'_' in names: fixed_expr[exprloc] = self.get_asm_next_offset(exprloc) continue arg_int = symbols.get_location_offset(loc_key) if arg_int is not None: fixed_expr[exprloc] = m2_expr.ExprInt( arg_int, exprloc.size) continue if not names: raise ValueError('Unresolved symbol: %r' % exprloc) offset = symbols.get_location_offset(loc_key) if offset is None: raise ValueError( 'The offset of loc_key "%s" cannot be determined' % names) else: # Fix symbol with its offset size = exprloc.size if size is None: default_size = self.get_symbol_size(exprloc, symbols) size = default_size value = m2_expr.ExprInt(offset, size) fixed_expr[exprloc] = value expr = expr.replace_expr(fixed_expr) expr = expr_simp(expr) args_out.append(expr) return args_out
def update_engine_from_cpu(self): """Updates CPU values according to @cpu instance""" for symbol in self.symbols: if isinstance(symbol, m2_expr.ExprId): if hasattr(self.cpu, symbol.name): value = m2_expr.ExprInt(getattr(self.cpu, symbol.name), symbol.size) self.symbols.symbols_id[symbol] = value else: raise NotImplementedError("Type not handled: %s" % symbol)
def _simp_handle_x86_cpuid(self, e_s, expr): """From miasm/jitter/op_semantics.h: x86_cpuid""" if expr.op != "x86_cpuid": return expr if any(not arg.is_int() for arg in expr.args): return expr a, reg_num = (int(arg) for arg in expr.args) # Not found error is keeped on purpose return m2_expr.ExprInt(self.x86_cpuid[a][reg_num], expr.size)
def gen_finalize(self, block): """ Generate the C code for the final block instruction """ loc_key = self.get_block_post_label(block) offset = self.ir_arch.loc_db.get_location_offset(loc_key) out = (self.CODE_RETURN_NO_EXCEPTION % (loc_key, self.C_PC, m2_expr.ExprId('branch_dst_irdst', 32), m2_expr.ExprId('branch_dst_irdst', 32), self.id_to_c(m2_expr.ExprInt(offset, 32)))).split('\n') return out
def mem_read(self, expr_mem): """Memory read wrapper for symbolic execution @expr_mem: ExprMem""" addr = expr_mem.ptr if not addr.is_int(): return super(EmulatedSymbExec, self).mem_read(expr_mem) addr = int(addr) size = expr_mem.size // 8 value = self.vm.get_mem(addr, size) if self.vm.is_little_endian(): value = value[::-1] self.vm.add_mem_read(addr, size) return m2_expr.ExprInt(int(encode_hex(value), 16), expr_mem.size)
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 eval_updt_irblock(self, irb, step=False): """ Symbolic execution of the @irb on the current state @irb: irblock instance @step: display intermediate steps """ offset2cmt = {} for index, assignblk in enumerate(irb): if set(assignblk) == set([self.lifter.IRDst, self.lifter.pc]): # Don't display on jxx continue instr = assignblk.instr tmp_r = assignblk.get_r() tmp_w = assignblk.get_w() todo = set() # Replace PC with value to match IR args pc_fixed = { self.lifter.pc: m2_expr.ExprInt(instr.offset + instr.l, self.lifter.pc.size) } inputs = tmp_r inputs.update(arg for arg in tmp_w if arg.is_mem()) for arg in inputs: arg = expr_simp(arg.replace_expr(pc_fixed)) if arg in tmp_w and not arg.is_mem(): continue todo.add(arg) for expr in todo: if expr.is_int(): continue for c_str, c_type in self.chandler.expr_to_c_and_types( expr, self.symbols): expr = self.cst_propag_link.get((irb.loc_key, index), {}).get(expr, expr) offset2cmt.setdefault(instr.offset, set()).add( "\n%s: %s\n%s" % (expr, c_str, c_type)) self.eval_updt_assignblk(assignblk) for offset, value in viewitems(offset2cmt): idc.set_cmt(offset, '\n'.join(value), 0) print("%x\n" % offset, '\n'.join(value)) return self.eval_expr(self.lifter.IRDst)
def tne(ir, instr, arg1, arg2): e = [] loc_except, loc_except_expr = ir.gen_loc_key_and_expr(ir.IRDst.size) loc_next = ir.get_next_loc_key(instr) loc_next_expr = m2_expr.ExprLoc(loc_next, ir.IRDst.size) do_except = [] do_except.append(m2_expr.ExprAssign(exception_flags, m2_expr.ExprInt( EXCEPT_DIV_BY_ZERO, exception_flags.size))) do_except.append(m2_expr.ExprAssign(ir.IRDst, loc_next_expr)) blk_except = IRBlock(ir.loc_db, loc_except, [AssignBlock(do_except, instr)]) cond = arg1 ^ arg2 e = [] e.append(m2_expr.ExprAssign(ir.IRDst, m2_expr.ExprCond(cond, loc_next_expr, loc_except_expr))) return e, [blk_except]
def merge_sliceto_slice(expr): """ Apply basic factorisation on ExprCompose sub components @expr: ExprCompose """ out_args = [] last_index = 0 for index, arg in expr.iter_args(): # Init if len(out_args) == 0: out_args.append(arg) continue last_value = out_args[-1] # Consecutive if last_index + last_value.size == index: # Merge consecutive integers if (isinstance(arg, m2_expr.ExprInt) and isinstance(last_value, m2_expr.ExprInt)): new_size = last_value.size + arg.size value = int(arg) << last_value.size value |= int(last_value) out_args[-1] = m2_expr.ExprInt(value, size=new_size) continue # Merge consecuvite slice elif (isinstance(arg, m2_expr.ExprSlice) and isinstance(last_value, m2_expr.ExprSlice)): value = arg.arg if (last_value.arg == value and last_value.stop == arg.start): out_args[-1] = value[last_value.start:arg.stop] continue # Unmergeable last_index = index out_args.append(arg) return out_args
def number(cls, size=32): """Return a random number @size: (optional) number max bits """ num = random.randint(0, cls.number_max % (2**size)) return m2_expr.ExprInt(num, size)
def get_asm_offset(self, expr): return m2_expr.ExprInt(self.offset, expr.size)
def get_asm_next_offset(self, expr): return m2_expr.ExprInt(self.offset+self.l, expr.size)
# 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', 32) 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 gen_pc_update(self, assignments, instr): offset = m2_expr.ExprInt(instr.offset, self.pc.size) assignments.append(AssignBlock({self.pc: offset}, instr))
class imm64_noarg(object): int2expr = lambda self, x: m2_expr.ExprInt(x, 64)
def reset_regs(self): """Set registers value to 0. Ignore register aliases""" for reg in self.lifter.arch.regs.all_regs_ids_no_alias: self.symbols.symbols_id[reg] = m2_expr.ExprInt(0, size=reg.size)
def int2expr(self, v): if (v & ~self.intmask) != 0: return None return m2_expr.ExprInt(v, self.intsize)
def to_constraint(self): return m2_expr.ExprAssign(self.expr, m2_expr.ExprInt(0, self.expr.size))
def ast_int2expr(a): return m2_expr.ExprInt(a, 32)
def to_constraint(self): cst1, cst2 = m2_expr.ExprInt(0, 1), m2_expr.ExprInt(1, 1) return m2_expr.ExprAssign(cst1, m2_expr.ExprCond(self.expr, cst1, cst2))