def call_effects(self, addr, instr): assignblks, extra = super(IRADelModCallStack, self).call_effects(addr, instr) if use_ida_stack: stk_before = idc.get_spd(instr.offset) stk_after = idc.get_spd(instr.offset + instr.l) stk_diff = stk_after - stk_before print(hex(stk_diff)) call_assignblk = AssignBlock([ ExprAssign(self.ret_reg, ExprOp('call_func_ret', addr)), ExprAssign(self.sp, self.sp + ExprInt(stk_diff, self.sp.size)) ], instr) return [call_assignblk], [] else: if not dontmodstack: return assignblks, extra out = [] for assignblk in assignblks: dct = dict(assignblk) dct = { dst: src for (dst, src) in viewitems(dct) if dst != self.sp } out.append(AssignBlock(dct, assignblk.instr)) return out, extra
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 udiv(ir, instr, a, b, c=None): e = [] if c is None: b, c = a, b loc_div = ExprLoc(ir.loc_db.add_location(), ir.IRDst.size) loc_except = ExprLoc(ir.loc_db.add_location(), ir.IRDst.size) loc_next = ExprLoc(ir.get_next_loc_key(instr), ir.IRDst.size) e.append(ExprAssign(ir.IRDst, ExprCond(c, loc_div, loc_except))) do_except = [] do_except.append( ExprAssign(exception_flags, ExprInt(EXCEPT_DIV_BY_ZERO, exception_flags.size))) do_except.append(ExprAssign(ir.IRDst, loc_next)) blk_except = IRBlock(loc_except.loc_key, [AssignBlock(do_except, instr)]) r = ExprOp("udiv", b, c) do_div = [] do_div.append(ExprAssign(a, r)) dst = get_dst(a) if dst is not None: do_div.append(ExprAssign(ir.IRDst, r)) do_div.append(ExprAssign(ir.IRDst, loc_next)) blk_div = IRBlock(loc_div.loc_key, [AssignBlock(do_div, instr)]) return e, [blk_div, blk_except]
def gen_irblock(label, exprs_list): irs = [] for exprs in exprs_list: if isinstance(exprs, AssignBlock): irs.append(exprs) else: irs.append(AssignBlock(exprs)) irs.append(AssignBlock({IRDst: dummy})) irbl = IRBlock(label, irs) return irbl
def process(self, pending, merging_val, reached_funcs): if len(self.flat_loops) == 0: # add all reached functions for func_addr, possible_merge_vars, loc_key in self.possible_merge_funcs: reached_funcs.add(func_addr) for expr, val in possible_merge_vars: pending.setdefault(func_addr, {}).setdefault(expr, set()).add(val) return None assert len(self.asmcfg.heads()) == 1 # add merging var to the ircfg if self.pad: initial_block_bak = self.ircfg.blocks[LocKey(0)] if merging_val and self.merging_var: asgn_blk = AssignBlock( [ExprAssign(self.merging_var, merging_val)]) else: asgn_blk = AssignBlock() assignblks = tuple( [asgn_blk, *self.ircfg.blocks[LocKey(0)].assignblks]) self.ircfg.blocks[LocKey(0)] = IRBlock(LocKey(0), assignblks) head = self.asmcfg.heads()[0] head_block = self.asmcfg.loc_key_to_block(head) new_head = self._deobfuscate_cff_loops( head_block, self.asmcfg.machine.mn.regs.regs_init) if self.pad: self.ircfg.blocks[LocKey(0)] = initial_block_bak if merging_val and self.merging_var: mode = self.asmcfg.mode fix_dct = { self.asmcfg.machine.mn.regs.regs_init[self.ir_arch.sp]: self.ir_arch.sp } mov = instruction_x86( "MOV", mode, [self.merging_var.replace_expr(fix_dct), merging_val]) mov.additional_info = additional_info() mov.additional_info.g1.value = 0 self.out_asmcfg.loc_key_to_block(LocKey(0)).lines.insert( 0, mov) loc_keys = self.relevant_nodes for func_addr, possible_merge_vars, loc_key in self.possible_merge_funcs: if loc_key in loc_keys: reached_funcs.add(func_addr) for expr, val in possible_merge_vars: pending.setdefault(func_addr, {}).setdefault(expr, set()).add(val) return new_head
def add_condition_expr(ir, instr, cond, instr_ir, extra_ir): if cond == COND_AL: return instr_ir, extra_ir if not cond in tab_cond: raise ValueError('unknown condition %r' % cond) cond = tab_cond[cond] loc_next = ir.get_next_loc_key(instr) loc_next_expr = ExprLoc(loc_next, 32) loc_do = ir.loc_db.add_location() loc_do_expr = ExprLoc(loc_do, 32) dst_cond = ExprCond(cond, loc_do_expr, loc_next_expr) assert (isinstance(instr_ir, list)) has_irdst = False for e in instr_ir: if e.dst == ir.IRDst: has_irdst = True break if not has_irdst: instr_ir.append(ExprAssign(ir.IRDst, loc_next_expr)) e_do = IRBlock(loc_do, [AssignBlock(instr_ir, instr)]) e = [ExprAssign(ir.IRDst, dst_cond)] return e, [e_do] + extra_ir
def _recog_init(self, merging_var_candidates): # recognize cff loops and initiate deobfuscation self._merging_var_candidates = merging_var_candidates self.ircfg = self.ir_arch.new_ircfg_from_asmcfg(self.asmcfg) self.asmcfg.rebuild_edges() # TODO put constant propagation here when fixed in Miasm # simp = IRCFGSimplifierSSA(self.ir_arch) # from datetime import datetime # startTime = datetime.now() # ssa = simp.ircfg_to_ssa(self.ircfg, LocKey(0)) # simp.do_propagate_expressions(ssa, LocKey(0)) # self.ircfg = simp.ssa_to_unssa(ssa, LocKey(0)) # print(datetime.now() - startTime) # init_infos = self.ir_arch.arch.regs.regs_init # cst_propag_link = cst_prop.propagate_cst_expr(self.ir_arch, self.ircfg, self.asmcfg.func_addr, init_infos) # raise Exception("test") self._normalize_ircfg(self.conn) irb_bak = None if merging_var_candidates: self.pad = True new_line = AssignBlock([ExprAssign(k, k) for k in merging_var_candidates]) irb_bak = self.ircfg.blocks[LocKey(0)] new_irb = IRBlock(LocKey(0), tuple([new_line, *self.ircfg.blocks[LocKey(0)].assignblks])) self.ircfg.blocks[LocKey(0)] = new_irb self.analyses = Analyses(self.ircfg, self.asmcfg) return irb_bak
def sanitize_graph_head(ircfg, head): """ In multiple algorithm, the @head of the ircfg may not have predecessors. The function transform the @ircfg in order to ensure this property @ircfg: IRCFG instance @head: the location of the graph's head """ if not ircfg.predecessors(head): return original_edges = ircfg.predecessors(head) sub_head = ircfg.loc_db.add_location() # Duplicate graph, replacing references to head by sub_head replaced_expr = { ExprLoc(head, ircfg.IRDst.size): ExprLoc(sub_head, ircfg.IRDst.size) } ircfg.simplify(lambda expr: expr.replace_expr(replaced_expr)) # Duplicate head block ircfg.add_irblock(IRBlock(ircfg.loc_db, sub_head, list(ircfg.blocks[head]))) # Remove original head block ircfg.del_node(head) for src in original_edges: ircfg.add_edge(src, sub_head) # Create new head, jumping to sub_head assignblk = AssignBlock({ircfg.IRDst: ExprLoc(sub_head, ircfg.IRDst.size)}) new_irblock = IRBlock(ircfg.loc_db, head, [assignblk]) ircfg.add_irblock(new_irblock)
def eval_updt_irblock(self, irb, step=False): """ Symbolic execution of the @irb on the current state @irb: IRBlock instance @step: display intermediate steps """ assignblks = [] for index, assignblk in enumerate(irb): new_assignblk = {} links = {} for dst, src in viewitems(assignblk): src = self.propag_expr_cst(src) if dst.is_mem(): ptr = dst.ptr ptr = self.propag_expr_cst(ptr) dst = ExprMem(ptr, dst.size) new_assignblk[dst] = src if assignblk.instr is not None: for arg in assignblk.instr.args: new_arg = self.propag_expr_cst(arg) links[new_arg] = arg self.cst_propag_link[(irb.loc_key, index)] = links self.eval_updt_assignblk(assignblk) assignblks.append(AssignBlock(new_assignblk, assignblk.instr)) self.ircfg.blocks[irb.loc_key] = IRBlock(irb.loc_key, assignblks)
def exec_instruction(mn_str, init_values, results, index=0, offset=0): """Symbolically execute an instruction and check the expected results.""" # Assemble and disassemble the instruction instr = mn_mep.fromstring(mn_str, "b") instr.mode = "b" mn_bin = mn_mep.asm(instr)[index] try: instr = mn_mep.dis(mn_bin, "b") except Disasm_Exception: assert (False) # miasm don't know what to do # Specify the instruction offset and compute the destination label instr.offset = offset loc_db = LocationDB() if instr.dstflow(): instr.dstflow2label(loc_db) # Get the IR im = Lifter_MEPb(loc_db) iir, eiir = im.get_ir(instr) # Filter out IRDst iir = [ ir for ir in iir if not (isinstance(ir, ExprAssign) and isinstance(ir.dst, ExprId) and ir.dst.name == "IRDst") ] # Prepare symbolic execution sb = SymbolicExecutionEngine(LifterModelCallMepb(loc_db), regs_init) # Assign int values before symbolic evaluation for expr_id, expr_value in init_values: sb.symbols[expr_id] = expr_value # Execute the IR ab = AssignBlock(iir) sb.eval_updt_assignblk(ab) # Check if expected expr_id were modified matched_results = 0 for expr_id, expr_value in results: result = sb.eval_expr(expr_id) if isinstance(result, ExprLoc): addr = loc_db.get_location_offset(result.loc_key) if expr_value.arg == addr: matched_results += 1 continue elif result == expr_value: matched_results += 1 continue # Ensure that all expected results were verified if len(results) is not matched_results: print("Expected:", results) print("Modified:", [r for r in sb.modified(mems=False)]) assert (False)
def call_effects(self, addr, instr): call_assignblk = AssignBlock([ ExprAssign( self.ret_reg, ExprOp('call_func_ret', addr, self.sp, self.arch.regs.R15)), ExprAssign(self.sp, ExprOp('call_func_stack', addr, self.sp)) ], instr) return [call_assignblk], []
def call_effects(self, addr, instr): assignblks, extra = super(IRADelModCallStack, self).call_effects(addr, instr) out = [] for assignblk in assignblks: dct = dict(assignblk) dct = {dst: src for (dst, src) in viewitems(dct) if dst != self.sp} out.append(AssignBlock(dct, assignblk.instr)) return out, extra
def call_effects(self, ad, instr): print(hex(instr.offset), instr) stk_before = idc.get_spd(instr.offset) stk_after = idc.get_spd(instr.offset + instr.l) stk_diff = stk_after - stk_before print(hex(stk_diff)) call_assignblk = AssignBlock([ ExprAssign(self.ret_reg, ExprOp('call_func_ret', ad)), ExprAssign(self.sp, self.sp + ExprInt(stk_diff, self.sp.size)) ], instr) return [call_assignblk], []
def insert_parallel_copy(self): """ Naive Out-of-SSA from CSSA (without coalescing for now) - Replace Phi - Create room for parallel copies in Phi's parents """ ircfg = self.ssa.graph for irblock in list(viewvalues(ircfg.blocks)): if not irblock_has_phi(irblock): continue # Replace Phi with Phi's dst = new_var parallel_copies = {} for dst in self.phi_destinations[irblock.loc_key]: new_var = self.phi_new_var[dst] parallel_copies[dst] = new_var assignblks = list(irblock) assignblks[0] = AssignBlock(parallel_copies, irblock[0].instr) new_irblock = IRBlock(irblock.loc_db, irblock.loc_key, assignblks) ircfg.blocks[irblock.loc_key] = new_irblock # Insert new_var = src in each Phi's parent, at the end of the block parent_to_parallel_copies = {} parallel_copies = {} for dst in irblock[0]: new_var = self.phi_new_var[dst] for parent, src in self.phi_parent_sources[dst]: parent_to_parallel_copies.setdefault(parent, {})[new_var] = src for parent, parallel_copies in viewitems( parent_to_parallel_copies): parent = ircfg.blocks[parent] assignblks = list(parent) assignblks.append( AssignBlock(parallel_copies, parent[-1].instr)) new_irblock = IRBlock(parent.loc_db, parent.loc_key, assignblks) ircfg.blocks[parent.loc_key] = new_irblock
def _convert_phi(self): """Inserts corresponding phi functions inplace into IRBlock at the beginning""" for loc_key in self._phinodes: irblock = self.get_block(loc_key) if irblock is None: continue assignblk = AssignBlock(self._phinodes[loc_key]) if irblock_has_phi(irblock): # If first block contains phi, we are updating an existing ssa form # so update phi assignblks = list(irblock.assignblks) out = dict(assignblks[0]) out.update(dict(assignblk)) assignblks[0] = AssignBlock(out, assignblk.instr) new_irblock = IRBlock(self.ircfg.loc_db, loc_key, assignblks) else: # insert at the beginning new_irblock = IRBlock(self.ircfg.loc_db, loc_key, [assignblk] + list(irblock.assignblks)) self.ircfg.blocks[loc_key] = new_irblock
def casp(ir, instr, arg1, arg2, arg3): # XXX TODO: memory barrier e = [] if arg1.size == 32: regs = gpregs32_expr else: regs = gpregs64_expr index1 = regs.index(arg1) index2 = regs.index(arg2) # TODO endianness comp_value = ExprCompose(regs[index1], regs[index1 + 1]) new_value = ExprCompose(regs[index2], regs[index2 + 1]) assert arg3.is_op('preinc') ptr = arg3.args[0] data = ExprMem(ptr, comp_value.size) loc_store = ExprLoc(ir.loc_db.add_location(), ir.IRDst.size) loc_do = ExprLoc(ir.loc_db.add_location(), ir.IRDst.size) loc_next = ExprLoc(ir.get_next_loc_key(instr), ir.IRDst.size) e.append( ExprAssign( ir.IRDst, ExprCond(ExprOp("FLAG_EQ_CMP", data, comp_value), loc_do, loc_store))) e_store = [] e_store.append(ExprAssign(data, new_value)) e_store.append(ExprAssign(ir.IRDst, loc_do)) blk_store = IRBlock(loc_store.loc_key, [AssignBlock(e_store, instr)]) e_do = [] e_do.append(ExprAssign(regs[index1], data[:data.size // 2])) e_do.append(ExprAssign(regs[index1 + 1], data[data.size // 2:])) e_do.append(ExprAssign(ir.IRDst, loc_next)) blk_do = IRBlock(loc_do.loc_key, [AssignBlock(e_do, instr)]) return e, [blk_store, blk_do]
def gen_irblock(label, exprs_list): """ Returns an IRBlock. Used only for tests purpose """ irs = [] for exprs in exprs_list: if isinstance(exprs, AssignBlock): irs.append(exprs) else: irs.append(AssignBlock(exprs)) irbl = IRBlock(loc_db, label, irs) return irbl
def eval_updt_expr(self, expr): """ Evaluate @expr and apply side effect if needed (ie. if expr is an assignment). Return the evaluated value """ # Update value if needed if expr.is_aff(): ret = self.eval_expr(expr.src) self.eval_updt_assignblk(AssignBlock([expr])) else: ret = self.eval_expr(expr) return ret
def assignblk_to_irbloc(self, instr, assignblk): """ Ensure IRDst is always set in the head @assignblk of the @instr @instr: an instruction instance @assignblk: Assignblk instance """ new_assignblk = dict(assignblk) if self.ir_arch.IRDst not in assignblk: offset = instr.offset + instr.l loc_key = self.ir_arch.loc_db.get_or_create_offset_location(offset) dst = ExprLoc(loc_key, self.ir_arch.IRDst.size) new_assignblk[self.ir_arch.IRDst] = dst irs = [AssignBlock(new_assignblk, instr)] return IRBlock(self.ir_arch.get_loc_key_for_instr(instr), irs)
def add_out_reg_end(ir_arch_a, ircfg_a): # Add dummy dependency to uncover out regs affectation for loc in ircfg_a.leaves(): irblock = ircfg_a.blocks.get(loc) if irblock is None: continue regs = {} for reg in ir_arch_a.get_out_regs(irblock): regs[reg] = reg assignblks = list(irblock) new_assiblk = AssignBlock(regs, assignblks[-1].instr) assignblks.append(new_assiblk) new_irblock = IRBlock(loc_db, irblock.loc_key, assignblks) ircfg_a.blocks[loc] = new_irblock
def call_effects(self, ad, instr): call_assignblk = AssignBlock([ ExprAssign( self.ret_reg, ExprOp( 'call_func_ret', ad, self.arch.regs.R0, self.arch.regs.R1, self.arch.regs.R2, self.arch.regs.R3, )), ExprAssign(self.sp, ExprOp('call_func_stack', ad, self.sp)), ], instr) cond = instr.additional_info.cond if cond == 14: # COND_ALWAYS: return [call_assignblk], [] # Call is a conditional instruction cond = tab_cond[cond] loc_next = self.get_next_loc_key(instr) loc_next_expr = ExprLoc(loc_next, 32) loc_do = self.loc_db.add_location() loc_do_expr = ExprLoc(loc_do, 32) dst_cond = ExprCond(cond, loc_do_expr, loc_next_expr) call_assignblks = [ call_assignblk, AssignBlock([ExprAssign(self.IRDst, loc_next_expr)], instr), ] e_do = IRBlock(loc_do, call_assignblks) assignblks_out = [ AssignBlock([ExprAssign(self.IRDst, dst_cond)], instr) ] return assignblks_out, [e_do]
def call_effects(self, ad, instr): call_assignblk = AssignBlock([ ExprAssign( self.ret_reg, ExprOp( 'call_func_ret', ad, self.arch.regs.A0, self.arch.regs.A1, self.arch.regs.A2, self.arch.regs.A3, )), ], instr) return [call_assignblk], []
def remove_assign_eq(self): """ Remove trivial expressions (a=a) in the current graph """ for irblock in list(viewvalues(self.ssa.graph.blocks)): assignblks = list(irblock) for i, assignblk in enumerate(assignblks): out = {} for dst, src in viewitems(assignblk): if dst == src: continue out[dst] = src assignblks[i] = AssignBlock(out, assignblk.instr) self.ssa.graph.blocks[irblock.loc_key] = IRBlock( irblock.loc_db, irblock.loc_key, assignblks)
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, addr, *args): #print(*args) if all(isinstance(arg, Expr) for arg in args): call_assignblk = [ ExprAssign(self.ret_reg, ExprOp('call_func', addr, *args)), ] return call_assignblk else: call_assignblk = AssignBlock([ ExprAssign(self.ret_reg, ExprOp('call_func_ret', addr, self.sp)), ExprAssign(self.sp, ExprOp('call_func_stack', addr, self.sp)) ], args) return [call_assignblk], []
def addIRBlock(self, newIRCFG, state, lockey): assignBlocks = [] lastAssign = None lastIndex = None for dst, src in state.items(): newAssign = AssignBlock({dst: src}) if dst == newIRCFG._irdst: lastAssign = newAssign lastIndex = len(assignBlocks) assignBlocks.append(newAssign) tmp = assignBlocks[-1] assignBlocks[-1] = lastAssign assignBlocks[lastIndex] = tmp newIRBlock = IRBlock(lockey, assignBlocks) newIRCFG.add_irblock(newIRBlock) return newIRBlock
def simplify(self): simplifier = IRCFGSimplifierCommon(self.custom_ira1) simplifier.simplify(self.ircfg, self.head) for loc in self.ircfg.leaves(): irblock = self.ircfg.blocks.get(loc) if irblock is None: continue regs = {} for reg in self.custom_ira1.get_out_regs(irblock): regs[reg] = reg assignblks = list(irblock) newAssignBlk = AssignBlock(regs, assignblks[-1].instr) assignblks.append(newAssignBlk) newIrBlock = IRBlock(irblock.loc_key, assignblks) self.ircfg.blocks[loc] = newIrBlock simplifier = CustomIRCFGSimplifierSSA(self.custom_ira2) simplifier.simplify(self.ircfg, self.head)
def remove_phi(self): """ Remove phi operators in @ifcfg @ircfg: IRDiGraph instance """ for irblock in list(viewvalues(self.ssa.graph.blocks)): assignblks = list(irblock) out = {} for dst, src in viewitems(assignblks[0]): if src.is_op('Phi'): assert set([dst]) == set(src.args) continue out[dst] = src assignblks[0] = AssignBlock(out, assignblks[0].instr) self.ssa.graph.blocks[irblock.loc_key] = IRBlock( irblock.loc_db, irblock.loc_key, assignblks)
def _fix_no_def_var(self, head): """ Replace phi source variables which are not ssa vars by ssa vars. @head: loc_key of the graph head """ var_to_insert = set() for loc_key in self._phinodes: for dst, sources in viewitems(self._phinodes[loc_key]): for src in sources.args: if src in self.ssa_variable_to_expr: continue var_to_insert.add(src) var_to_newname = {} newname_to_var = {} for var in var_to_insert: new_var = self._transform_var_lhs(var) var_to_newname[var] = new_var newname_to_var[new_var] = var # Replace non modified node used in phi with new variable self.ircfg.simplify(lambda expr: expr.replace_expr(var_to_newname)) if newname_to_var: irblock = self.ircfg.blocks[head] assignblks = list(irblock) assignblks[0:0] = [ AssignBlock(newname_to_var, assignblks[0].instr) ] self.ircfg.blocks[head] = IRBlock(self.ircfg.loc_db, head, assignblks) # Updt structure for loc_key in self._phinodes: for dst, sources in viewitems(self._phinodes[loc_key]): self._phinodes[loc_key][dst] = sources.replace_expr( var_to_newname) for var, (loc_key, index) in list(viewitems(self.ssa_to_location)): if loc_key == head: self.ssa_to_location[var] = loc_key, index + 1 for newname, var in viewitems(newname_to_var): self.ssa_to_location[newname] = head, 0 self.ssa_variable_to_expr[newname] = var self.expressions[newname] = var
def del_dst_zr(self, instr, instr_ir, extra_ir): "Writes to zero register are discarded" regs_to_fix = [WZR, XZR] instr_ir = [expr for expr in instr_ir if expr.dst not in regs_to_fix] new_irblocks = [] for irblock in extra_ir: irs = [] for assignblk in irblock: new_dsts = { dst: src for dst, src in viewitems(assignblk) if dst not in regs_to_fix } irs.append(AssignBlock(new_dsts, assignblk.instr)) new_irblocks.append(IRBlock(irblock.loc_key, irs)) return instr_ir, new_irblocks
def test_ClassDef(self): from miasm.expression.expression import ExprInt, ExprId, ExprMem, \ ExprCompose, ExprAssign from miasm.arch.x86.sem import ir_x86_32 from miasm.core.locationdb import LocationDB from miasm.ir.symbexec import SymbolicExecutionEngine from miasm.ir.ir import AssignBlock loc_db = LocationDB() ira = ir_x86_32(loc_db) ircfg = ira.new_ircfg() id_x = ExprId('x', 32) id_a = ExprId('a', 32) id_b = ExprId('b', 32) id_c = ExprId('c', 32) id_d = ExprId('d', 32) id_e = ExprId('e', 64) class CustomSymbExec(SymbolicExecutionEngine): def mem_read(self, expr): if expr == ExprMem(ExprInt(0x1000, 32), 32): return id_x return super(CustomSymbExec, self).mem_read(expr) sb = CustomSymbExec(ira, { ExprMem(ExprInt(0x4, 32), 8): ExprInt(0x44, 8), ExprMem(ExprInt(0x5, 32), 8): ExprInt(0x33, 8), ExprMem(ExprInt(0x6, 32), 8): ExprInt(0x22, 8), ExprMem(ExprInt(0x7, 32), 8): ExprInt(0x11, 8), ExprMem(ExprInt(0x20, 32), 32): id_x, ExprMem(ExprInt(0x40, 32), 32): id_x, ExprMem(ExprInt(0x44, 32), 32): id_a, ExprMem(ExprInt(0x54, 32), 32): ExprInt(0x11223344, 32), ExprMem(id_a, 32): ExprInt(0x11223344, 32), id_a: ExprInt(0, 32), id_b: ExprInt(0, 32), ExprMem(id_c, 32): ExprMem(id_d + ExprInt(0x4, 32), 32), ExprMem(id_c + ExprInt(0x4, 32), 32): ExprMem(id_d + ExprInt(0x8, 32), 32), }) self.assertEqual(sb.eval_expr(ExprInt(1, 32)-ExprInt(1, 32)), ExprInt(0, 32)) ## Test with unknown mem + integer self.assertEqual(sb.eval_expr(ExprMem(ExprInt(0, 32), 32)), ExprMem(ExprInt(0, 32), 32)) self.assertEqual(sb.eval_expr(ExprMem(ExprInt(1, 32), 32)), ExprCompose(ExprMem(ExprInt(1, 32), 24), ExprInt(0x44, 8))) self.assertEqual(sb.eval_expr(ExprMem(ExprInt(2, 32), 32)), ExprCompose(ExprMem(ExprInt(2, 32), 16), ExprInt(0x3344, 16))) self.assertEqual(sb.eval_expr(ExprMem(ExprInt(3, 32), 32)), ExprCompose(ExprMem(ExprInt(3, 32), 8), ExprInt(0x223344, 24))) self.assertEqual(sb.eval_expr(ExprMem(ExprInt(4, 32), 32)), ExprInt(0x11223344, 32)) self.assertEqual(sb.eval_expr(ExprMem(ExprInt(5, 32), 32)), ExprCompose(ExprInt(0x112233, 24), ExprMem(ExprInt(8, 32), 8))) self.assertEqual(sb.eval_expr(ExprMem(ExprInt(6, 32), 32)), ExprCompose(ExprInt(0x1122, 16), ExprMem(ExprInt(8, 32), 16))) self.assertEqual(sb.eval_expr(ExprMem(ExprInt(7, 32), 32)), ExprCompose(ExprInt(0x11, 8), ExprMem(ExprInt(8, 32), 24))) self.assertEqual(sb.eval_expr(ExprMem(ExprInt(8, 32), 32)), ExprMem(ExprInt(8, 32), 32)) ## Test with unknown mem + integer self.assertEqual(sb.eval_expr(ExprMem(ExprInt(0x50, 32), 32)), ExprMem(ExprInt(0x50, 32), 32)) self.assertEqual(sb.eval_expr(ExprMem(ExprInt(0x51, 32), 32)), ExprCompose(ExprMem(ExprInt(0x51, 32), 24), ExprInt(0x44, 8))) self.assertEqual(sb.eval_expr(ExprMem(ExprInt(0x52, 32), 32)), ExprCompose(ExprMem(ExprInt(0x52, 32), 16), ExprInt(0x3344, 16))) self.assertEqual(sb.eval_expr(ExprMem(ExprInt(0x53, 32), 32)), ExprCompose(ExprMem(ExprInt(0x53, 32), 8), ExprInt(0x223344, 24))) self.assertEqual(sb.eval_expr(ExprMem(ExprInt(0x54, 32), 32)), ExprInt(0x11223344, 32)) self.assertEqual(sb.eval_expr(ExprMem(ExprInt(0x55, 32), 32)), ExprCompose(ExprInt(0x112233, 24), ExprMem(ExprInt(0x58, 32), 8))) self.assertEqual(sb.eval_expr(ExprMem(ExprInt(0x56, 32), 32)), ExprCompose(ExprInt(0x1122, 16), ExprMem(ExprInt(0x58, 32), 16))) self.assertEqual(sb.eval_expr(ExprMem(ExprInt(0x57, 32), 32)), ExprCompose(ExprInt(0x11, 8), ExprMem(ExprInt(0x58, 32), 24))) self.assertEqual(sb.eval_expr(ExprMem(ExprInt(0x58, 32), 32)), ExprMem(ExprInt(0x58, 32), 32)) ## Test with unknown mem + id self.assertEqual(sb.eval_expr(ExprMem(ExprInt(0x1D, 32), 32)), ExprCompose(ExprMem(ExprInt(0x1D, 32), 24), id_x[:8])) self.assertEqual(sb.eval_expr(ExprMem(ExprInt(0x1E, 32), 32)), ExprCompose(ExprMem(ExprInt(0x1E, 32), 16), id_x[:16])) self.assertEqual(sb.eval_expr(ExprMem(ExprInt(0x1F, 32), 32)), ExprCompose(ExprMem(ExprInt(0x1F, 32), 8), id_x[:24])) self.assertEqual(sb.eval_expr(ExprMem(ExprInt(0x20, 32), 32)), id_x) self.assertEqual(sb.eval_expr(ExprMem(ExprInt(0x21, 32), 32)), ExprCompose(id_x[8:], ExprMem(ExprInt(0x24, 32), 8))) self.assertEqual(sb.eval_expr(ExprMem(ExprInt(0x22, 32), 32)), ExprCompose(id_x[16:], ExprMem(ExprInt(0x24, 32), 16))) self.assertEqual(sb.eval_expr(ExprMem(ExprInt(0x23, 32), 32)), ExprCompose(id_x[24:], ExprMem(ExprInt(0x24, 32), 24))) self.assertEqual(sb.eval_expr(ExprMem(ExprInt(0x24, 32), 32)), ExprMem(ExprInt(0x24, 32), 32)) ## Partial read self.assertEqual(sb.eval_expr(ExprMem(ExprInt(4, 32), 8)), ExprInt(0x44, 8)) self.assertEqual(sb.eval_expr(ExprMem(ExprInt(0x20, 32), 8)), id_x[:8]) self.assertEqual(sb.eval_expr(ExprMem(ExprInt(0x23, 32), 8)), id_x[24:]) ## Merge self.assertEqual(sb.eval_expr(ExprMem(ExprInt(0x40, 32), 64)), ExprCompose(id_x, id_a)) self.assertEqual(sb.eval_expr(ExprMem(ExprInt(0x42, 32), 32)), ExprCompose(id_x[16:], id_a[:16])) # Merge memory self.assertEqual(sb.eval_expr(ExprMem(ExprInt(0x100, 32), 32)), ExprMem(ExprInt(0x100, 32), 32)) self.assertEqual(sb.eval_expr(ExprMem(id_c + ExprInt(0x2, 32), 32)), ExprMem(id_d + ExprInt(0x6, 32), 32)) ## Unmodified read self.assertEqual(sb.eval_expr(ExprMem(ExprInt(4, 32), 8)), ExprInt(0x44, 8)) ## Modified read self.assertEqual(sb.eval_expr(ExprMem(ExprInt(0x1000, 32), 32)), id_x) ## Apply_change / eval_ir / apply_expr ## x = a (with a = 0x0) assignblk = AssignBlock({id_x:id_a}) sb.eval_updt_assignblk(assignblk) self.assertEqual(sb.eval_expr(id_x), ExprInt(0, 32)) ## x = a (without replacing 'a' with 0x0) sb.apply_change(id_x, id_a) self.assertEqual(sb.eval_expr(id_x), id_a) ## x = a (with a = 0x0) self.assertEqual(sb.eval_updt_expr(assignblk.dst2ExprAssign(id_x)), ExprInt(0, 32)) self.assertEqual(sb.eval_expr(id_x), ExprInt(0, 32)) self.assertEqual(sb.eval_updt_expr(id_x), ExprInt(0, 32)) sb.dump() ## state reads = set() for dst, src in sb.modified(): reads.update(ExprAssign(dst, src).get_r()) self.assertEqual(reads, set([ id_x, id_a, ExprMem(id_d + ExprInt(0x4, 32), 32), ExprMem(id_d + ExprInt(0x8, 32), 32), ])) # Erase low id_x byte with 0xFF sb.apply_change(ExprMem(ExprInt(0x20, 32), 8), ExprInt(0xFF, 8)) state = dict(sb.modified(ids=False)) self.assertEqual(state[ExprMem(ExprInt(0x20, 32), 8)], ExprInt(0xFF, 8)) self.assertEqual(state[ExprMem(ExprInt(0x21, 32), 24)], id_x[8:32]) # Erase high id_x byte with 0xEE sb.apply_change(ExprMem(ExprInt(0x23, 32), 8), ExprInt(0xEE, 8)) state = dict(sb.modified(ids=False)) self.assertEqual(state[ExprMem(ExprInt(0x20, 32), 8)], ExprInt(0xFF, 8)) self.assertEqual(state[ExprMem(ExprInt(0x21, 32), 16)], id_x[8:24]) self.assertEqual(state[ExprMem(ExprInt(0x23, 32), 8)], ExprInt(0xEE, 8)) self.assertEqual(sb.eval_expr(ExprMem(ExprInt(0x22, 32), 32)), ExprCompose(id_x[16:24], ExprInt(0xEE, 8), ExprMem(ExprInt(0x24, 32), 16))) # Erase low byte of 0x11223344 with 0xFF at 0x54 sb.apply_change(ExprMem(ExprInt(0x54, 32), 8), ExprInt(0xFF, 8)) # Erase low byte of 0x11223344 with 0xFF at id_a sb.apply_change(ExprMem(id_a + ExprInt(0x1, 32), 8), ExprInt(0xFF, 8)) state = dict(sb.modified(ids=False)) self.assertEqual(state[ExprMem(id_a + ExprInt(0x1, 32), 8)], ExprInt(0xFF, 8)) self.assertEqual(state[ExprMem(id_a + ExprInt(0x2, 32), 16)], ExprInt(0x1122, 16)) # Write uint32_t at 0xFFFFFFFE sb.apply_change(ExprMem(ExprInt(0xFFFFFFFE, 32), 32), ExprInt(0x11223344, 32)) self.assertEqual(sb.eval_expr(ExprMem(ExprInt(0, 32), 16)), ExprInt(0x1122, 16)) # Revert memory to original value at 0x42 sb.apply_change(ExprMem(ExprInt(0x42, 32), 32), ExprMem(ExprInt(0x42, 32), 32)) self.assertEqual(sb.eval_expr(ExprMem(ExprInt(0x42, 32), 32)), ExprMem(ExprInt(0x42, 32), 32)) # Revert memory to original value at c + 0x2 sb.apply_change(ExprMem(id_c + ExprInt(0x2, 32), 32), ExprMem(id_c + ExprInt(0x2, 32), 32)) self.assertEqual(sb.eval_expr(ExprMem(id_c + ExprInt(0x2, 32), 32)), ExprMem(id_c + ExprInt(0x2, 32), 32)) # Test del symbol del sb.symbols[id_a] sb.dump() del sb.symbols[ExprMem(id_a, 8)] print("*"*40, 'Orig:') sb.dump() sb_cp = sb.symbols.copy() print("*"*40, 'Copy:') sb_cp.dump() # Add symbol at address limit sb.apply_change(ExprMem(ExprInt(0xFFFFFFFE, 32), 32), id_c) sb.dump() found = False for dst, src in viewitems(sb.symbols): if dst == ExprMem(ExprInt(0xFFFFFFFE, 32), 32) and src == id_c: found = True assert found # Add symbol at address limit sb.apply_change(ExprMem(ExprInt(0x7FFFFFFE, 32), 32), id_c) sb.dump() found = False for dst, src in viewitems(sb.symbols): if dst == ExprMem(ExprInt(0x7FFFFFFE, 32), 32) and src == id_c: found = True assert found # Add truncated symbol at address limit sb.apply_change(ExprMem(ExprInt(0xFFFFFFFC, 32), 64), id_e) # Revert parts of memory sb.apply_change(ExprMem(ExprInt(0xFFFFFFFC, 32), 16), ExprMem(ExprInt(0xFFFFFFFC, 32), 16)) sb.apply_change(ExprMem(ExprInt(0x2, 32), 16), ExprMem(ExprInt(0x2, 32), 16)) sb.dump() found = False for dst, src in viewitems(sb.symbols): if dst == ExprMem(ExprInt(0xFFFFFFFE, 32), 32) and src == id_e[16:48]: found = True assert found sb_empty = SymbolicExecutionEngine(ira) sb_empty.dump() # Test memory full print('full') arch_addr8 = ir_x86_32(loc_db) ircfg = arch_addr8.new_ircfg() # Hack to obtain tiny address space arch_addr8.addrsize = 5 sb_addr8 = SymbolicExecutionEngine(arch_addr8) sb_addr8.dump() # Fulfill memory sb_addr8.apply_change(ExprMem(ExprInt(0, 5), 256), ExprInt(0, 256)) sb_addr8.dump() variables = list(viewitems(sb_addr8.symbols)) assert variables == [(ExprMem(ExprInt(0, 5), 256), ExprInt(0, 256))] print(sb_addr8.symbols.symbols_mem) sb_addr8.apply_change(ExprMem(ExprInt(0x5, 5), 256), ExprInt(0x123, 256)) sb_addr8.dump() variables = list(viewitems(sb_addr8.symbols)) assert variables == [(ExprMem(ExprInt(0x5, 5), 256), ExprInt(0x123, 256))] print(sb_addr8.symbols.symbols_mem) print('dump') sb_addr8.symbols.symbols_mem.dump() sb.dump() try: del sb.symbols.symbols_mem[ExprMem(ExprInt(0xFFFFFFFF, 32), 32)] except KeyError: # ok pass else: raise RuntimeError("Should raise error!") del sb.symbols.symbols_mem[ExprMem(ExprInt(0xFFFFFFFF, 32), 16)] sb.dump() self.assertEqual(sb.eval_expr(ExprMem(ExprInt(0xFFFFFFFE, 32), 32)), ExprCompose(id_e[16:24], ExprMem(ExprInt(0xFFFFFFFF, 32), 16), id_e[40:48])) sb.symbols.symbols_mem.delete_partial(ExprMem(ExprInt(0xFFFFFFFF, 32), 32)) self.assertEqual(sb.eval_expr(ExprMem(ExprInt(0xFFFFFFFE, 32), 32)), ExprCompose(id_e[16:24], ExprMem(ExprInt(0xFFFFFFFF, 32), 24))) sb.dump() assert ExprMem(ExprInt(0xFFFFFFFE, 32), 8) in sb.symbols assert ExprMem(ExprInt(0xFFFFFFFE, 32), 32) not in sb.symbols assert sb.symbols.symbols_mem.contains_partial(ExprMem(ExprInt(0xFFFFFFFE, 32), 32)) assert not sb.symbols.symbols_mem.contains_partial(ExprMem(ExprInt(0xFFFFFFFF, 32), 8)) assert list(sb_addr8.symbols) == [ExprMem(ExprInt(0x5, 5), 256)]