def emul(self, ctx=None, step=False): """Symbolic execution of relevant nodes according to the history Return the values of inputs nodes' elements @ctx: (optional) Initial context as dictionnary @step: (optional) Verbose execution Warning: The emulation is not sound if the inputs nodes depend on loop variant. """ # Init ctx_init = self._ira.arch.regs.regs_init if ctx is not None: ctx_init.update(ctx) assignblks = [] # Build a single affectation block according to history last_index = len(self.relevant_labels) for index, label in enumerate(reversed(self.relevant_labels), 1): if index == last_index and label == self.initial_state.label: line_nb = self.initial_state.line_nb else: line_nb = None assignblks += self.irblock_slice(self._ira.blocks[label], line_nb).assignblks # Eval the block temp_label = AsmLabel("Temp") symb_exec = SymbolicExecutionEngine(self._ira, ctx_init) symb_exec.eval_updt_irblock(IRBlock(temp_label, assignblks), step=step) # Return only inputs values (others could be wrongs) return {element: symb_exec.symbols[element] for element in self.inputs}
def symbolic_exec(): from miasm2.ir.symbexec import SymbolicExecutionEngine from miasm2.core.bin_stream_ida import bin_stream_ida from utils import guess_machine bs = bin_stream_ida() machine = guess_machine() mdis = machine.dis_engine(bs) start, end = idc.SelStart(), idc.SelEnd() mdis.dont_dis = [end] asmcfg = mdis.dis_multiblock(start) ira = machine.ira(symbol_pool=mdis.symbol_pool) for block in asmcfg.blocks: ira.add_block(block) print "Run symbolic execution..." sb = SymbolicExecutionEngine(ira, machine.mn.regs.regs_init) sb.run_at(start) modified = {} for dst, src in sb.modified(init_state=machine.mn.regs.regs_init): modified[dst] = src view = symbolicexec_t() all_views.append(view) if not view.Create(modified, machine, mdis.symbol_pool, "Symbolic Execution - 0x%x to 0x%x" % (start, end)): return view.Show()
def symbolic_exec(): from miasm2.ir.symbexec import SymbolicExecutionEngine from miasm2.core.bin_stream_ida import bin_stream_ida from utils import guess_machine bs = bin_stream_ida() machine = guess_machine() mdis = machine.dis_engine(bs) start, end = idc.SelStart(), idc.SelEnd() mdis.dont_dis = [end] asmcfg = mdis.dis_multiblock(start) ira = machine.ira(symbol_pool=mdis.symbol_pool) for block in asmcfg.blocks: ira.add_block(block) print "Run symbolic execution..." sb = SymbolicExecutionEngine(ira, machine.mn.regs.regs_init) sb.run_at(start) modified = {} for dst, src in sb.modified(init_state=machine.mn.regs.regs_init): modified[dst] = src view = symbolicexec_t() all_views.append(view) if not view.Create(modified, machine, mdis.symbol_pool, "Symbolic Execution - 0x%x to 0x%x" % (start, end)): return view.Show()
def emul(self, ir_arch, ctx=None, step=False): # Init ctx_init = {} if ctx is not None: ctx_init.update(ctx) solver = z3.Solver() symb_exec = SymbolicExecutionEngine(ir_arch, ctx_init) history = self.history[::-1] history_size = len(history) translator = Translator.to_language("z3") size = self._ircfg.IRDst.size for hist_nb, loc_key in enumerate(history, 1): if hist_nb == history_size and loc_key == self.initial_state.loc_key: line_nb = self.initial_state.line_nb else: line_nb = None irb = self.irblock_slice(self._ircfg.blocks[loc_key], line_nb) # Emul the block and get back destination dst = symb_exec.eval_updt_irblock(irb, step=step) # Add constraint if hist_nb < history_size: next_loc_key = history[hist_nb] expected = symb_exec.eval_expr(ExprLoc(next_loc_key, size)) solver.add(self._gen_path_constraints(translator, dst, expected)) # Save the solver self._solver = solver # Return only inputs values (others could be wrongs) return {element: symb_exec.eval_expr(element) for element in self.inputs}
def intra_block_flow_symbexec(ir_arch, flow_graph, irb, in_nodes, out_nodes): """ Create data flow for an irbloc using symbolic execution """ current_nodes = {} symbols_init = dict(ir_arch.arch.regs.regs_init) sb = SymbolicExecutionEngine(ir_arch, dict(symbols_init)) sb.emulbloc(irb) # print "*"*40 # print irb # print sb.dump_id() # print sb.dump_mem() for n_w in sb.symbols: # print n_w v = sb.symbols[n_w] if n_w in symbols_init and symbols_init[n_w] == v: continue read_values = v.get_r(cst_read=True) # print n_w, v, [str(x) for x in read_values] node_n_w = get_node_name(irb.label, len(irb.irs), n_w) for n_r in read_values: if n_r in current_nodes: node_n_r = current_nodes[n_r] else: node_n_r = get_node_name(irb.label, 0, n_r) current_nodes[n_r] = node_n_r in_nodes[n_r] = node_n_r out_nodes[n_w] = node_n_w flow_graph.add_uniq_edge(node_n_r, node_n_w)
def symexec(handler): inst_bytes = handler.bytes_without_jmp machine = Machine("x86_32") cont = Container.from_string(inst_bytes) bs = cont.bin_stream mdis = machine.dis_engine(bs, symbol_pool=cont.symbol_pool) end_offset = len(inst_bytes) mdis.dont_dis = [end_offset] asm_block = mdis.dis_block(0) # print asm_block ira = machine.ira(mdis.symbol_pool) ira.add_block(asm_block) symb = SymbolicExecutionEngine(ira, symbols_init) cur_addr = symb.emul_ir_block(0) count = 0 while cur_addr != ExprInt(end_offset, 32): # execute to end cur_addr = symb.emul_ir_block(cur_addr) count += 1 if count > 1000: print '[!] to many loop at %s' % handler.name break return symb
def intra_block_flow_symbexec(ir_arch, flow_graph, irb, in_nodes, out_nodes): """ Create data flow for an irbloc using symbolic execution """ current_nodes = {} symbols_init = dict(ir_arch.arch.regs.regs_init) sb = SymbolicExecutionEngine(ir_arch, dict(symbols_init)) sb.emulbloc(irb) # print "*"*40 # print irb # print sb.dump_id() # print sb.dump_mem() for n_w in sb.symbols: # print n_w v = sb.symbols[n_w] if n_w in symbols_init and symbols_init[n_w] == v: continue read_values = v.get_r(cst_read=True) # print n_w, v, [str(x) for x in read_values] node_n_w = get_node_name(irb.label, len(irb.irs), n_w) for n_r in read_values: if n_r in current_nodes: node_n_r = current_nodes[n_r] else: node_n_r = get_node_name(irb.label, 0, n_r) current_nodes[n_r] = node_n_r in_nodes[n_r] = node_n_r out_nodes[n_w] = node_n_w flow_graph.add_uniq_edge(node_n_r, node_n_w)
def intra_block_flow_symbexec(ir_arch, flow_graph, irb, in_nodes, out_nodes): """ Create data flow for an irbloc using symbolic execution """ current_nodes = {} symbols_init = dict(ir_arch.arch.regs.regs_init) sb = SymbolicExecutionEngine(ir_arch, dict(symbols_init)) sb.emulbloc(irb) for n_w in sb.symbols: v = sb.symbols[n_w] if n_w in symbols_init and symbols_init[n_w] == v: continue read_values = v.get_r(cst_read=True) node_n_w = get_node_name(irb.loc_key, len(irb), n_w) for n_r in read_values: if n_r in current_nodes: node_n_r = current_nodes[n_r] else: node_n_r = get_node_name(irb.loc_key, 0, n_r) current_nodes[n_r] = node_n_r in_nodes[n_r] = node_n_r out_nodes[n_w] = node_n_w flow_graph.add_uniq_edge(node_n_r, node_n_w)
def compute(asm, inputstate={}, debug=False): loc_db = LocationDB() sympool = dict(regs_init) sympool.update({k: ExprInt(v, k.size) for k, v in inputstate.iteritems()}) ir_tmp = ir_arch(loc_db) ircfg = ir_tmp.new_ircfg() symexec = SymbolicExecutionEngine(ir_tmp, sympool) instr = mn.fromstring(asm, loc_db, "l") code = mn.asm(instr)[0] instr = mn.dis(code, "l") instr.offset = inputstate.get(PC, 0) lbl = ir_tmp.add_instr_to_ircfg(instr, ircfg) symexec.run_at(ircfg, lbl) if debug: for k, v in symexec.symbols.items(): if regs_init.get(k, None) != v: print k, v out = {} for k, v in symexec.symbols.items(): if k in EXCLUDE_REGS: continue elif regs_init.get(k, None) == v: continue elif isinstance(v, ExprInt): out[k] = long(v) else: out[k] = v return out
def emul(self, ir_arch, ctx=None, step=False): """Symbolic execution of relevant nodes according to the history Return the values of inputs nodes' elements @ir_arch: IntermediateRepresentation instance @ctx: (optional) Initial context as dictionnary @step: (optional) Verbose execution Warning: The emulation is not sound if the inputs nodes depend on loop variant. """ # Init ctx_init = {} if ctx is not None: ctx_init.update(ctx) assignblks = [] # Build a single affectation block according to history last_index = len(self.relevant_loc_keys) for index, loc_key in enumerate(reversed(self.relevant_loc_keys), 1): if index == last_index and loc_key == self.initial_state.loc_key: line_nb = self.initial_state.line_nb else: line_nb = None assignblks += self.irblock_slice(self._ircfg.blocks[loc_key], line_nb).assignblks # Eval the block loc_db = LocationDB() temp_loc = loc_db.get_or_create_name_location("Temp") symb_exec = SymbolicExecutionEngine(ir_arch, ctx_init) symb_exec.eval_updt_irblock(IRBlock(temp_loc, assignblks), step=step) # Return only inputs values (others could be wrongs) return {element: symb_exec.symbols[element] for element in self.inputs}
def emul(self, ir_arch, ctx=None, step=False): """Symbolic execution of relevant nodes according to the history Return the values of inputs nodes' elements @ir_arch: IntermediateRepresentation instance @ctx: (optional) Initial context as dictionnary @step: (optional) Verbose execution Warning: The emulation is not sound if the inputs nodes depend on loop variant. """ # Init ctx_init = {} if ctx is not None: ctx_init.update(ctx) assignblks = [] # Build a single affectation block according to history last_index = len(self.relevant_loc_keys) for index, loc_key in enumerate(reversed(self.relevant_loc_keys), 1): if index == last_index and loc_key == self.initial_state.loc_key: line_nb = self.initial_state.line_nb else: line_nb = None assignblks += self.irblock_slice(self._ircfg.blocks[loc_key], line_nb).assignblks # Eval the block loc_db = LocationDB() temp_loc = loc_db.get_or_create_name_location("Temp") symb_exec = SymbolicExecutionEngine(ir_arch, ctx_init) symb_exec.eval_updt_irblock(IRBlock(temp_loc, assignblks), step=step) # Return only inputs values (others could be wrongs) return {element: symb_exec.symbols[element] for element in self.inputs}
def emul(self, ctx=None, step=False): # Init ctx_init = self._ira.arch.regs.regs_init if ctx is not None: ctx_init.update(ctx) solver = z3.Solver() symb_exec = SymbolicExecutionEngine(self._ira, ctx_init) history = self.history[::-1] history_size = len(history) translator = Translator.to_language("z3") size = self._ira.IRDst.size for hist_nb, label in enumerate(history, 1): if hist_nb == history_size and label == self.initial_state.label: line_nb = self.initial_state.line_nb else: line_nb = None irb = self.irblock_slice(self._ira.blocks[label], line_nb) # Emul the block and get back destination dst = symb_exec.emulbloc(irb, step=step) # Add constraint if hist_nb < history_size: next_label = history[hist_nb] expected = symb_exec.eval_expr(m2_expr.ExprId(next_label, size)) solver.add( self._gen_path_constraints(translator, dst, expected)) # Save the solver self._solver = solver # Return only inputs values (others could be wrongs) return {element: symb_exec.eval_expr(element) for element in self.inputs}
def emul(self, ctx=None, step=False): """Symbolic execution of relevant nodes according to the history Return the values of inputs nodes' elements @ctx: (optional) Initial context as dictionnary @step: (optional) Verbose execution Warning: The emulation is not sound if the inputs nodes depend on loop variant. """ # Init ctx_init = self._ira.arch.regs.regs_init if ctx is not None: ctx_init.update(ctx) assignblks = [] # Build a single affectation block according to history last_index = len(self.relevant_labels) for index, label in enumerate(reversed(self.relevant_labels), 1): if index == last_index and label == self.initial_state.label: line_nb = self.initial_state.line_nb else: line_nb = None assignblks += self.irblock_slice(self._ira.blocks[label], line_nb).irs # Eval the block temp_label = AsmLabel("Temp") symb_exec = SymbolicExecutionEngine(self._ira, ctx_init) symb_exec.emulbloc(IRBlock(temp_label, assignblks), step=step) # Return only inputs values (others could be wrongs) return {element: symb_exec.symbols[element] for element in self.inputs}
def __init__(self, code, architecture): self.code = code self.machine = Machine(architecture) self.mdis = self.machine.dis_engine(code) self.ira = SubIRA64(self.mdis.symbol_pool) self.se_engine = SymbolicExecutionEngine( self.ira, self.machine.mn.regs.regs_init)
class MiasmSEOracle: def __init__(self, code, architecture): self.code = code self.machine = Machine(architecture) self.mdis = self.machine.dis_engine(code) self.ira = SubIRA64(self.mdis.symbol_pool) self.se_engine = SymbolicExecutionEngine( self.ira, self.machine.mn.regs.regs_init) def determine_ira(self, architecture): if architecture == "x86_64": return SubIRA64(self.mdis.symbol_pool) elif architecture == "x86_32": return SubIRA32(self.mdis.symbol_pool) else: raise NotImplementedError( "Architecture {} not supported".format(architecture)) def execute(self): addr = 0 while addr < len(self.code): basic_block = self.mdis.dis_block(addr) self.ira.add_block(basic_block) ira_block = self.ira.get_block(addr) self.se_engine.emulbloc(ira_block) addr = basic_block.get_range()[1]
def compute(asm, inputstate={}, debug=False): sympool = dict(regs_init) sympool.update({k: ExprInt(v, k.size) for k, v in inputstate.iteritems()}) interm = ir_arch() symexec = SymbolicExecutionEngine(interm, sympool) instr = mn.fromstring(asm, symbol_pool, "l") code = mn.asm(instr)[0] instr = mn.dis(code, "l") instr.offset = inputstate.get(PC, 0) lbl = interm.add_instr(instr) symexec.run_at(lbl) if debug: for k, v in symexec.symbols.items(): if regs_init.get(k, None) != v: print k, v out = {} for k, v in symexec.symbols.items(): if k in EXCLUDE_REGS: continue elif regs_init.get(k, None) == v: continue elif isinstance(v, ExprInt): out[k] = v.arg.arg else: out[k] = v return out
def exec_instruction(hex_asm, init_values): """Symbolically execute an instruction""" print "Hex:", hex_asm # Disassemble an instruction mn = mn_mep.dis(hex_asm.decode("hex"), "b") print "Dis:", mn # Get the IR im = ir_mepb() iir, eiir, = im.get_ir(mn) print "\nInternal representation:", iir # Symbolic execution loc_db = LocationDB() sb = SymbolicExecutionEngine(ir_a_mepb(loc_db), regs_init) # Assign register values before symbolic evaluation for reg_expr_id, reg_expr_value in init_values: sb.symbols[reg_expr_id] = reg_expr_value print "\nModified registers:", [ reg for reg in sb.modified(mems=False) ] print "Modified memories:", [mem for mem in sb.modified()] print "\nFinal registers:" sb.dump(mems=False) print "\nFinal mems:" sb.dump()
def symb_exec(lbl, ir_arch, ircfg, inputstate, debug): sympool = dict(regs_init) sympool.update(inputstate) symexec = SymbolicExecutionEngine(ir_arch, sympool) symexec.run_at(ircfg, lbl) if debug: for k, v in symexec.symbols.items(): if regs_init.get(k, None) != v: print k, v return {k: v for k, v in symexec.symbols.items() if k not in EXCLUDE_REGS and regs_init.get(k, None) != v}
def intra_bloc_flow_symb(ir_arch, flow_graph, irblock): symbols_init = ir_arch.arch.regs.regs_init.copy() sb = SymbolicExecutionEngine(ir_arch, symbols_init) sb.emulbloc(irblock) print '*' * 40 print irblock in_nodes = {} out_nodes = {} out = get_modified_symbols(sb) current_nodes = {} # Gen mem arg to mem node links for dst, src in out.items(): for n in [dst, src]: all_mems = set() all_mems.update(get_expr_mem(n)) for n in all_mems: node_n_w = get_node_name(irblock.label, 0, n) if not n == src: continue o_r = n.arg.get_r(mem_read=False, cst_read=True) for i, n_r in enumerate(o_r): if n_r in current_nodes: node_n_r = current_nodes[n_r] else: node_n_r = get_node_name(irblock.label, i, n_r) if not n_r in in_nodes: in_nodes[n_r] = node_n_r flow_graph.add_uniq_edge(node_n_r, node_n_w) # Gen data flow links for dst, src in out.items(): nodes_r = src.get_r(mem_read=False, cst_read=True) nodes_w = set([dst]) for n_r in nodes_r: if n_r in current_nodes: node_n_r = current_nodes[n_r] else: node_n_r = get_node_name(irblock.label, 0, n_r) if not n_r in in_nodes: in_nodes[n_r] = node_n_r flow_graph.add_node(node_n_r) for n_w in nodes_w: node_n_w = get_node_name(irblock.label, 1, n_w) out_nodes[n_w] = node_n_w flow_graph.add_node(node_n_w) flow_graph.add_uniq_edge(node_n_r, node_n_w) irblock.in_nodes = in_nodes irblock.out_nodes = out_nodes
def symb_exec(lbl, interm, inputstate, debug): sympool = dict(regs_init) sympool.update(inputstate) symexec = SymbolicExecutionEngine(interm, sympool) symexec.run_at(lbl) if debug: for k, v in symexec.symbols.items(): if regs_init.get(k, None) != v: print k, v return {k: v for k, v in symexec.symbols.items() if k not in EXCLUDE_REGS and regs_init.get(k, None) != v}
def intra_bloc_flow_symb(ir_arch, flow_graph, irblock): symbols_init = ir_arch.arch.regs.regs_init.copy() sb = SymbolicExecutionEngine(ir_arch, symbols_init) sb.emulbloc(irblock) print '*' * 40 print irblock in_nodes = {} out_nodes = {} out = get_modified_symbols(sb) current_nodes = {} # Gen mem arg to mem node links for dst, src in out.items(): for n in [dst, src]: all_mems = set() all_mems.update(get_expr_mem(n)) for n in all_mems: node_n_w = get_node_name(irblock.label, 0, n) if not n == src: continue o_r = n.arg.get_r(mem_read=False, cst_read=True) for i, n_r in enumerate(o_r): if n_r in current_nodes: node_n_r = current_nodes[n_r] else: node_n_r = get_node_name(irblock.label, i, n_r) if not n_r in in_nodes: in_nodes[n_r] = node_n_r flow_graph.add_uniq_edge(node_n_r, node_n_w) # Gen data flow links for dst, src in out.items(): nodes_r = src.get_r(mem_read=False, cst_read=True) nodes_w = set([dst]) for n_r in nodes_r: if n_r in current_nodes: node_n_r = current_nodes[n_r] else: node_n_r = get_node_name(irblock.label, 0, n_r) if not n_r in in_nodes: in_nodes[n_r] = node_n_r flow_graph.add_node(node_n_r) for n_w in nodes_w: node_n_w = get_node_name(irblock.label, 1, n_w) out_nodes[n_w] = node_n_w flow_graph.add_node(node_n_w) flow_graph.add_uniq_edge(node_n_r, node_n_w) irblock.in_nodes = in_nodes irblock.out_nodes = out_nodes
def exec_instruction(hex_asm, init_values): """Symbolically execute an instruction""" print "Hex:", hex_asm # Disassemble an instruction mn = mn_mep.dis(hex_asm.decode("hex"), "b") print "Dis:", mn # Get the IR im = ir_mepb() iir, eiir, = im.get_ir(mn) print "\nInternal representation:", iir # Symbolic execution loc_db = LocationDB() sb = SymbolicExecutionEngine(ir_a_mepb(loc_db), regs_init) # Assign register values before symbolic evaluation for reg_expr_id, reg_expr_value in init_values: sb.symbols[reg_expr_id] = reg_expr_value print "\nModified registers:", [reg for reg in sb.modified(mems=False)] print "Modified memories:", [mem for mem in sb.modified()] print "\nFinal registers:" sb.dump(mems=False) print "\nFinal mems:" sb.dump()
def symb_exec(interm, inputstate, debug): sympool = dict(regs_init) sympool.update(inputstate) symexec = SymbolicExecutionEngine(interm, sympool) symexec.emul_ir_blocks(0) if debug: for k, v in symexec.symbols.items(): if regs_init.get(k, None) != v: print k, v return { k: v for k, v in symexec.symbols.items() if k not in EXCLUDE_REGS and regs_init.get(k, None) != v }
def gen_equations(self): for irb in self.blocks.values(): symbols_init = dict(self.arch.regs.all_regs_ids_init) sb = SymbolicExecutionEngine(self, dict(symbols_init)) sb.emulbloc(irb) eqs = [] for n_w in sb.symbols: v = sb.symbols[n_w] if n_w in symbols_init and symbols_init[n_w] == v: continue eqs.append(ExprAff(n_w, v)) print '*' * 40 print irb irb.irs = [AssignBlock(eqs)]
def load_asm(asm): """Transform a machine code into a block and symbolically execute it. Args: asm (string): machine code """ bin_stream = bin_stream_str(asm) mdis = machine.dis_engine(bin_stream) asm_block = mdis.dis_block(0) ira = machine.ira(mdis.symbol_pool) ira.add_block(asm_block) symbols_init = ira.arch.regs.regs_init symbolic = SymbolicExecutionEngine(ira, symbols_init) symbolic.run_block_at(0) return symbolic
def compute(asm, inputstate={}, debug=False): sympool = dict(regs_init) sympool.update({k: ExprInt(v, k.size) for k, v in inputstate.iteritems()}) interm = ir_arch() symexec = SymbolicExecutionEngine(interm, sympool) instr = mn.fromstring(asm, mode) code = mn.asm(instr)[0] instr = mn.dis(code, mode) instr.offset = inputstate.get(PC, 0) interm.add_instr(instr) symexec.run_at(instr.offset) if debug: for k, v in symexec.symbols.items(): if regs_init.get(k, None) != v: print k, v return {k: v.arg.arg for k, v in symexec.symbols.items() if k not in EXCLUDE_REGS and regs_init.get(k, None) != v}
def compute(asm, inputstate={}, debug=False): sympool = dict(regs_init) sympool.update({k: ExprInt(v, k.size) for k, v in inputstate.iteritems()}) interm = ir_arch() symexec = SymbolicExecutionEngine(interm, sympool) instr = mn.fromstring(asm, mode) code = mn.asm(instr)[0] instr = mn.dis(code, mode) instr.offset = inputstate.get(PC, 0) interm.add_instr(instr) symexec.emul_ir_blocks(instr.offset) if debug: for k, v in symexec.symbols.items(): if regs_init.get(k, None) != v: print k, v return {k: v.arg.arg for k, v in symexec.symbols.items() if k not in EXCLUDE_REGS and regs_init.get(k, None) != v}
class MiasmSEOracle: def __init__(self, code, architecture): self.code = code self.machine = Machine(architecture) self.mdis = self.machine.dis_engine(code) self.ira = SubIRA64(self.mdis.symbol_pool) self.se_engine = SymbolicExecutionEngine( self.ira, self.machine.mn.regs.regs_init) def execute(self): addr = 0 while addr < len(self.code): basic_block = self.mdis.dis_block(addr) self.ira.add_block(basic_block) ira_block = self.ira.get_block(addr) self.se_engine.emulbloc(ira_block) addr = basic_block.get_range()[1]
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 = ir_mepb(loc_db) iir, eiir = im.get_ir(instr) # Filter out IRDst iir = [ ir for ir in iir if not (isinstance(ir, ExprAff) and isinstance(ir.dst, ExprId) and ir.dst.name == "IRDst") ] # Prepare symbolic execution sb = SymbolicExecutionEngine(ir_a_mepb(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 compute(asm, inputstate={}, debug=False): loc_db = LocationDB() sympool = dict(regs_init) sympool.update({k: ExprInt(v, k.size) for k, v in inputstate.iteritems()}) ir_tmp = ir_arch(loc_db) ircfg = ir_tmp.new_ircfg() symexec = SymbolicExecutionEngine(ir_tmp, sympool) instr = mn.fromstring(asm, mode) code = mn.asm(instr)[0] instr = mn.dis(code, mode) instr.offset = inputstate.get(PC, 0) loc_key = ir_tmp.add_instr_to_ircfg(instr, ircfg) symexec.run_at(ircfg, loc_key) if debug: for k, v in symexec.symbols.items(): if regs_init.get(k, None) != v: print k, v return {k: v.arg.arg for k, v in symexec.symbols.items() if k not in EXCLUDE_REGS and regs_init.get(k, None) != v}
def emul_symb(ir_arch, mdis, states_todo, states_done): while states_todo: addr, symbols, conds = states_todo.pop() print '*' * 40, "addr", addr, '*' * 40 if (addr, symbols, conds) in states_done: print 'Known state, skipping', addr continue states_done.add((addr, symbols, conds)) symbexec = SymbolicExecutionEngine(ir_arch, {}) symbexec.symbols = symbols.copy() if ir_arch.pc in symbexec.symbols: del symbexec.symbols[ir_arch.pc] irblock = get_block(ir_arch, mdis, addr) print 'Run block:' print irblock addr = symbexec.eval_updt_irblock(irblock) print 'Final state:' symbexec.dump(mems=False) assert addr is not None if isinstance(addr, ExprCond): # Create 2 states, each including complementary conditions cond_group_a = {addr.cond: ExprInt(0, addr.cond.size)} cond_group_b = {addr.cond: ExprInt(1, addr.cond.size)} addr_a = expr_simp( symbexec.eval_expr(addr.replace_expr(cond_group_a), {})) addr_b = expr_simp( symbexec.eval_expr(addr.replace_expr(cond_group_b), {})) if not (addr_a.is_int() or asmblock.expr_is_label(addr_a) and addr_b.is_int() or asmblock.expr_is_label(addr_b)): print str(addr_a), str(addr_b) raise ValueError("Unsupported condition") if isinstance(addr_a, ExprInt): addr_a = int(addr_a.arg) if isinstance(addr_b, ExprInt): addr_b = int(addr_b.arg) states_todo.add((addr_a, symbexec.symbols.copy(), tuple(list(conds) + cond_group_a.items()))) states_todo.add((addr_b, symbexec.symbols.copy(), tuple(list(conds) + cond_group_b.items()))) elif isinstance(addr, ExprInt): addr = int(addr.arg) states_todo.add((addr, symbexec.symbols.copy(), tuple(conds))) elif asmblock.expr_is_label(addr): addr = addr.name states_todo.add((addr, symbexec.symbols.copy(), tuple(conds))) elif addr == ret_addr: print 'Return address reached' continue else: raise ValueError("Unsupported destination")
def symbolic_exec(): from miasm2.ir.symbexec import SymbolicExecutionEngine from miasm2.core.bin_stream_ida import bin_stream_ida from utils import guess_machine bs = bin_stream_ida() machine = guess_machine() mdis = machine.dis_engine(bs) start, end = idc.SelStart(), idc.SelEnd() mdis.dont_dis = [end] blocks = mdis.dis_multiblock(start) ira = machine.ira() for block in blocks: ira.add_block(block) print "Run symbolic execution..." sb = SymbolicExecutionEngine(ira, machine.mn.regs.regs_init) sb.emul_ir_blocks(start) modified = {} for ident in sb.symbols.symbols_id: if ident in sb.ir_arch.arch.regs.regs_init and \ ident in sb.symbols.symbols_id and \ sb.symbols.symbols_id[ident] == sb.ir_arch.arch.regs.regs_init[ident]: continue modified[ident] = sb.symbols.symbols_id[ident] for ident in sb.symbols.symbols_mem: modified[sb.symbols.symbols_mem[ident][0]] = sb.symbols.symbols_mem[ident][1] view = symbolicexec_t() all_views.append(view) if not view.Create(modified, machine, "Symbolic Execution - 0x%x to 0x%x" % (start, end)): return view.Show()
def symbolic_exec(): from miasm2.ir.symbexec import SymbolicExecutionEngine from miasm2.core.bin_stream_ida import bin_stream_ida from utils import guess_machine bs = bin_stream_ida() machine = guess_machine() mdis = machine.dis_engine(bs) start, end = SelStart(), SelEnd() mdis.dont_dis = [end] blocks = mdis.dis_multibloc(start) ira = machine.ira() for block in blocks: ira.add_bloc(block) print "Run symbolic execution..." sb = SymbolicExecutionEngine(ira, machine.mn.regs.regs_init) sb.emul_ir_blocks(start) modified = {} for ident in sb.symbols.symbols_id: if ident in sb.ir_arch.arch.regs.regs_init and \ ident in sb.symbols.symbols_id and \ sb.symbols.symbols_id[ident] == sb.ir_arch.arch.regs.regs_init[ident]: continue modified[ident] = sb.symbols.symbols_id[ident] for ident in sb.symbols.symbols_mem: modified[sb.symbols.symbols_mem[ident][0]] = sb.symbols.symbols_mem[ident][1] view = symbolicexec_t() if not view.Create(modified, machine, "Symbolic Execution - 0x%x to 0x%x" % (start, end)): return view.Show()
def compute(asm, inputstate={}, debug=False): loc_db = LocationDB() sympool = dict(regs_init) sympool.update({k: ExprInt(v, k.size) for k, v in inputstate.iteritems()}) ir_tmp = ir_arch(loc_db) ircfg = ir_tmp.new_ircfg() symexec = SymbolicExecutionEngine(ir_tmp, sympool) instr = mn.fromstring(asm, mode) code = mn.asm(instr)[0] instr = mn.dis(code, mode) instr.offset = inputstate.get(PC, 0) loc_key = ir_tmp.add_instr_to_ircfg(instr, ircfg) symexec.run_at(ircfg, loc_key) if debug: for k, v in symexec.symbols.items(): if regs_init.get(k, None) != v: print k, v return { k: v.arg.arg for k, v in symexec.symbols.items() if k not in EXCLUDE_REGS and regs_init.get(k, None) != v }
def symbolic_exec(): from miasm2.ir.symbexec import SymbolicExecutionEngine from miasm2.core.bin_stream_ida import bin_stream_ida from utils import guess_machine start, end = idc.SelStart(), idc.SelEnd() bs = bin_stream_ida() machine = guess_machine(addr=start) mdis = machine.dis_engine(bs) if start == idc.BADADDR and end == idc.BADADDR: start = idc.ScreenEA() end = idc.next_head(start) # Get next instruction address mdis.dont_dis = [end] asmcfg = mdis.dis_multiblock(start) ira = machine.ira(loc_db=mdis.loc_db) for block in asmcfg.blocks: ira.add_block(block) print "Run symbolic execution..." sb = SymbolicExecutionEngine(ira, machine.mn.regs.regs_init) sb.run_at(start) modified = {} for dst, src in sb.modified(init_state=machine.mn.regs.regs_init): modified[dst] = src view = symbolicexec_t() all_views.append(view) if not view.Create( modified, machine, mdis.loc_db, "Symbolic Execution - 0x%x to 0x%x" % (start, idc.prev_head(end))): return view.Show()
def symbolic_exec(): from miasm2.ir.symbexec import SymbolicExecutionEngine from miasm2.core.bin_stream_ida import bin_stream_ida from utils import guess_machine start, end = idc.SelStart(), idc.SelEnd() bs = bin_stream_ida() machine = guess_machine(addr=start) mdis = machine.dis_engine(bs) if start == idc.BADADDR and end == idc.BADADDR: start = idc.ScreenEA() end = idc.next_head(start) # Get next instruction address mdis.dont_dis = [end] asmcfg = mdis.dis_multiblock(start) ira = machine.ira(loc_db=mdis.loc_db) ircfg = ira.new_ircfg_from_asmcfg(asmcfg) print "Run symbolic execution..." sb = SymbolicExecutionEngine(ira, machine.mn.regs.regs_init) sb.run_at(ircfg, start) modified = {} for dst, src in sb.modified(init_state=machine.mn.regs.regs_init): modified[dst] = src view = symbolicexec_t() all_views.append(view) if not view.Create(modified, machine, mdis.loc_db, "Symbolic Execution - 0x%x to 0x%x" % (start, idc.prev_head(end))): return view.Show()
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 = ir_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(ir_a_mepb(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 intra_block_flow_symb(ir_arch, _, flow_graph, irblock, in_nodes, out_nodes): symbols_init = ir_arch.arch.regs.regs_init.copy() sb = SymbolicExecutionEngine(ir_arch, symbols_init) sb.eval_updt_irblock(irblock) print '*' * 40 print irblock out = sb.modified(mems=False) current_nodes = {} # Gen mem arg to mem node links for dst, src in out: src = sb.eval_expr(dst) for n in [dst, src]: all_mems = set() all_mems.update(get_expr_mem(n)) for n in all_mems: node_n_w = get_node_name(irblock.loc_key, 0, n) if not n == src: continue o_r = n.ptr.get_r(mem_read=False, cst_read=True) for i, n_r in enumerate(o_r): if n_r in current_nodes: node_n_r = current_nodes[n_r] else: node_n_r = get_node_name(irblock.loc_key, i, n_r) if not n_r in in_nodes: in_nodes[n_r] = node_n_r flow_graph.add_uniq_edge(node_n_r, node_n_w) # Gen data flow links for dst in out: src = sb.eval_expr(dst) nodes_r = src.get_r(mem_read=False, cst_read=True) nodes_w = set([dst]) for n_r in nodes_r: if n_r in current_nodes: node_n_r = current_nodes[n_r] else: node_n_r = get_node_name(irblock.loc_key, 0, n_r) if not n_r in in_nodes: in_nodes[n_r] = node_n_r flow_graph.add_node(node_n_r) for n_w in nodes_w: node_n_w = get_node_name(irblock.loc_key, 1, n_w) out_nodes[n_w] = node_n_w flow_graph.add_node(node_n_w) flow_graph.add_uniq_edge(node_n_r, node_n_w)
def intra_block_flow_symb(ir_arch, _, flow_graph, irblock, in_nodes, out_nodes): symbols_init = ir_arch.arch.regs.regs_init.copy() sb = SymbolicExecutionEngine(ir_arch, symbols_init) sb.eval_updt_irblock(irblock) print '*' * 40 print irblock out = sb.modified(mems=False) current_nodes = {} # Gen mem arg to mem node links for dst, src in out: src = sb.eval_expr(dst) for n in [dst, src]: all_mems = set() all_mems.update(get_expr_mem(n)) for n in all_mems: node_n_w = get_node_name(irblock.loc_key, 0, n) if not n == src: continue o_r = n.ptr.get_r(mem_read=False, cst_read=True) for i, n_r in enumerate(o_r): if n_r in current_nodes: node_n_r = current_nodes[n_r] else: node_n_r = get_node_name(irblock.loc_key, i, n_r) if not n_r in in_nodes: in_nodes[n_r] = node_n_r flow_graph.add_uniq_edge(node_n_r, node_n_w) # Gen data flow links for dst in out: src = sb.eval_expr(dst) nodes_r = src.get_r(mem_read=False, cst_read=True) nodes_w = set([dst]) for n_r in nodes_r: if n_r in current_nodes: node_n_r = current_nodes[n_r] else: node_n_r = get_node_name(irblock.loc_key, 0, n_r) if not n_r in in_nodes: in_nodes[n_r] = node_n_r flow_graph.add_node(node_n_r) for n_w in nodes_w: node_n_w = get_node_name(irblock.loc_key, 1, n_w) out_nodes[n_w] = node_n_w flow_graph.add_node(node_n_w) flow_graph.add_uniq_edge(node_n_r, node_n_w)
def do_step(self): if len(self.todo) == 0: return None if self.total_done > 600: print "symbexec watchdog!" return None self.total_done += 1 print 'CPT', self.total_done while self.todo: state = self.get_next_state() parent, ad, s = state self.states_done.add(state) self.states_var_done.add(state) sb = SymbolicExecutionEngine(self.ir_arch, dict(s)) return parent, ad, sb return None
def emul_symb(ir_arch, ircfg, mdis, states_todo, states_done): while states_todo: addr, symbols, conds = states_todo.pop() print '*' * 40, "addr", addr, '*' * 40 if (addr, symbols, conds) in states_done: print 'Known state, skipping', addr continue states_done.add((addr, symbols, conds)) symbexec = SymbolicExecutionEngine(ir_arch) symbexec.symbols = symbols.copy() if ir_arch.pc in symbexec.symbols: del symbexec.symbols[ir_arch.pc] irblock = get_block(ir_arch, ircfg, mdis, addr) print 'Run block:' print irblock addr = symbexec.eval_updt_irblock(irblock) print 'Final state:' symbexec.dump(mems=False) assert addr is not None if isinstance(addr, ExprCond): # Create 2 states, each including complementary conditions cond_group_a = {addr.cond: ExprInt(0, addr.cond.size)} cond_group_b = {addr.cond: ExprInt(1, addr.cond.size)} addr_a = expr_simp(symbexec.eval_expr(addr.replace_expr(cond_group_a), {})) addr_b = expr_simp(symbexec.eval_expr(addr.replace_expr(cond_group_b), {})) if not (addr_a.is_int() or addr_a.is_loc() and addr_b.is_int() or addr_b.is_loc()): print str(addr_a), str(addr_b) raise ValueError("Unsupported condition") if isinstance(addr_a, ExprInt): addr_a = int(addr_a.arg) if isinstance(addr_b, ExprInt): addr_b = int(addr_b.arg) states_todo.add((addr_a, symbexec.symbols.copy(), tuple(list(conds) + cond_group_a.items()))) states_todo.add((addr_b, symbexec.symbols.copy(), tuple(list(conds) + cond_group_b.items()))) elif addr == ret_addr: print 'Return address reached' continue elif addr.is_int(): addr = int(addr.arg) states_todo.add((addr, symbexec.symbols.copy(), tuple(conds))) elif addr.is_loc(): states_todo.add((addr, symbexec.symbols.copy(), tuple(conds))) else: raise ValueError("Unsupported destination")
def do_step(self): if len(self.todo) == 0: return None if self.total_done > 600: print "symbexec watchdog!" return None self.total_done += 1 print 'CPT', self.total_done while self.todo: # if self.total_done>20: # self.get_next_min() # state = self.todo.pop() state = self.get_next_state() parent, ad, s = state self.states_done.add(state) self.states_var_done.add(state) # if s in self.states_var_done: # print "state done" # continue sb = SymbolicExecutionEngine(self.ir_arch, dict(s)) return parent, ad, sb return None
states_todo.add((addr, symbexec.symbols.copy(), tuple(conds))) else: raise ValueError("Unsupported destination") if __name__ == '__main__': translator_smt2 = Translator.to_language("smt2") addr = int(options.address, 16) cont = Container.from_stream(open(args[0])) mdis = machine.dis_engine(cont.bin_stream, loc_db=cont.loc_db) ir_arch = machine.ir(mdis.loc_db) ircfg = ir_arch.new_ircfg() symbexec = SymbolicExecutionEngine(ir_arch) asmcfg, loc_db = parse_asm.parse_txt(machine.mn, 32, ''' init: PUSH argv PUSH argc PUSH ret_addr ''', loc_db=mdis.loc_db) argc_lbl = loc_db.get_name_location('argc') argv_lbl = loc_db.get_name_location('argv') ret_addr_lbl = loc_db.get_name_location('ret_addr') init_lbl = loc_db.get_name_location('init')
line = machine.mn.fromstring("MOV EAX, EBX", loc_db, 32) asm = machine.mn.asm(line)[0] # Get back block bin_stream = bin_stream_str(asm) mdis = machine.dis_engine(bin_stream, loc_db=loc_db) mdis.lines_wd = 1 asm_block = mdis.dis_block(START_ADDR) # Translate ASM -> IR ira = machine.ira(mdis.loc_db) ircfg = ira.new_ircfg() ira.add_asmblock_to_ircfg(asm_block, ircfg) # Instanciate a Symbolic Execution engine with default value for registers symb = SymbolicExecutionEngine(ira) # Emulate one IR basic block ## Emulation of several basic blocks can be done through .emul_ir_blocks cur_addr = symb.run_at(ircfg, START_ADDR) # Modified elements print 'Modified registers:' symb.dump(mems=False) print 'Modified memory (should be empty):' symb.dump(ids=False) # Check final status eax, ebx = ira.arch.regs.EAX, ira.arch.regs.EBX assert symb.symbols[eax] == ebx assert eax in symb.symbols
base_expr.setParseAction(my_var_parser) argc = ExprId('argc', 32) argv = ExprId('argv', 32) ret_addr = ExprId('ret_addr') reg_and_id[argc.name] = argc reg_and_id[argv.name] = argv reg_and_id[ret_addr.name] = ret_addr my_symbols = [argc, argv, ret_addr] my_symbols = dict([(x.name, x) for x in my_symbols]) my_symbols.update(mn_x86.regs.all_regs_ids_byname) ir_arch = ir_x86_32(mdis.symbol_pool) sb = SymbolicExecutionEngine(ir_arch, symbols_init) blocks, symbol_pool = parse_asm.parse_txt(mn_x86, 32, ''' PUSH argv PUSH argc PUSH ret_addr ''') b = list(blocks)[0] print b # add fake address and len to parsed instructions for i, line in enumerate(b.lines): line.offset, line.l = i, 1 ir_arch.add_bloc(b) irb = get_block(ir_arch, mdis, 0)
def test_ClassDef(self): from miasm2.expression.expression import ExprInt, ExprId, ExprMem, \ ExprCompose, ExprAff from miasm2.arch.x86.sem import ir_x86_32 from miasm2.ir.symbexec import SymbolicExecutionEngine from miasm2.ir.ir import AssignBlock addrX = ExprInt(-1, 32) addr0 = ExprInt(0, 32) addr1 = ExprInt(1, 32) addr8 = ExprInt(8, 32) addr9 = ExprInt(9, 32) addr20 = ExprInt(20, 32) addr40 = ExprInt(40, 32) addr50 = ExprInt(50, 32) mem0 = ExprMem(addr0) mem1 = ExprMem(addr1, 8) mem8 = ExprMem(addr8) mem9 = ExprMem(addr9) mem20 = ExprMem(addr20) mem40v = ExprMem(addr40, 8) mem40w = ExprMem(addr40, 16) mem50v = ExprMem(addr50, 8) mem50w = ExprMem(addr50, 16) id_x = ExprId('x') id_y = ExprId('y', 8) id_a = ExprId('a') id_eax = ExprId('eax_init') e = SymbolicExecutionEngine( ir_x86_32(), { mem0: id_x, mem1: id_y, mem9: id_x, mem40w: id_x[:16], mem50v: id_y, id_a: addr0, id_eax: addr0 }) self.assertEqual(e.find_mem_by_addr(addr0), mem0) self.assertEqual(e.find_mem_by_addr(addrX), None) self.assertEqual(e.eval_expr(ExprMem(addr1 - addr1)), id_x) self.assertEqual(e.eval_expr(ExprMem(addr1, 8)), id_y) self.assertEqual(e.eval_expr(ExprMem(addr1 + addr1)), ExprCompose(id_x[16:32], ExprMem(ExprInt(4, 32), 16))) self.assertEqual(e.eval_expr(mem8), ExprCompose(id_x[0:24], ExprMem(ExprInt(11, 32), 8))) self.assertEqual(e.eval_expr(mem40v), id_x[:8]) self.assertEqual(e.eval_expr(mem50w), ExprCompose(id_y, ExprMem(ExprInt(51, 32), 8))) self.assertEqual(e.eval_expr(mem20), mem20) e.func_read = lambda x: x self.assertEqual(e.eval_expr(mem20), mem20) self.assertEqual(set(e.modified()), set(e.symbols)) self.assertRaises(KeyError, e.symbols.__getitem__, ExprMem(ExprInt(100, 32))) self.assertEqual(e.apply_expr(id_eax), addr0) self.assertEqual(e.apply_expr(ExprAff(id_eax, addr9)), addr9) self.assertEqual(e.apply_expr(id_eax), addr9) # apply_change / eval_ir / apply_expr ## x = a (with a = 0x0) assignblk = AssignBlock({id_x: id_a}) e.eval_ir(assignblk) self.assertEqual(e.apply_expr(id_x), addr0) ## x = a (without replacing 'a' with 0x0) e.apply_change(id_x, id_a) self.assertEqual(e.apply_expr(id_x), id_a) ## x = a (with a = 0x0) self.assertEqual(e.apply_expr(assignblk.dst2ExprAff(id_x)), addr0) self.assertEqual(e.apply_expr(id_x), addr0)
def emul_symb(ir_arch, mdis, states_todo, states_done): while states_todo: ad, symbols, conds = states_todo.pop() print '*' * 40, "addr", ad, '*' * 40 if (ad, symbols, conds) in states_done: print 'skip', ad continue states_done.add((ad, symbols, conds)) sb = SymbolicExecutionEngine(ir_arch, {}) sb.symbols = symbols.copy() if ir_arch.pc in sb.symbols: del(sb.symbols[ir_arch.pc]) b = get_block(ir_arch, mdis, ad) print 'run block' print b # print blocks[ad] ad = sb.emulbloc(b) print 'final state' sb.dump_id() print 'dataflow' # data_flow_graph_from_expr(sb) assert(ad is not None) print "DST", ad if isinstance(ad, ExprCond): # Create 2 states, each including complementary conditions p1 = sb.symbols.copy() p2 = sb.symbols.copy() c1 = {ad.cond: ExprInt(0, ad.cond.size)} c2 = {ad.cond: ExprInt(1, ad.cond.size)} print ad.cond p1[ad.cond] = ExprInt(0, ad.cond.size) p2[ad.cond] = ExprInt(1, ad.cond.size) ad1 = expr_simp(sb.eval_expr(ad.replace_expr(c1), {})) ad2 = expr_simp(sb.eval_expr(ad.replace_expr(c2), {})) if not (isinstance(ad1, ExprInt) or (isinstance(ad1, ExprId) and isinstance(ad1.name, asmblock.AsmLabel)) and isinstance(ad2, ExprInt) or (isinstance(ad2, ExprId) and isinstance(ad2.name, asmblock.AsmLabel))): print str(ad1), str(ad2) raise ValueError("zarb condition") conds1 = list(conds) + c1.items() conds2 = list(conds) + c2.items() if isinstance(ad1, ExprId): ad1 = ad1.name if isinstance(ad2, ExprId): ad2 = ad2.name if isinstance(ad1, ExprInt): ad1 = ad1.arg if isinstance(ad2, ExprInt): ad2 = ad2.arg states_todo.add((ad1, p1, tuple(conds1))) states_todo.add((ad2, p2, tuple(conds2))) elif isinstance(ad, ExprInt): ad = int(ad.arg) states_todo.add((ad, sb.symbols.copy(), tuple(conds))) elif isinstance(ad, ExprId) and isinstance(ad.name, asmblock.AsmLabel): if isinstance(ad, ExprId): ad = ad.name states_todo.add((ad, sb.symbols.copy(), tuple(conds))) elif ad == ret_addr: print 'ret reached' continue else: raise ValueError("zarb eip")
machine.base_expr.setParseAction(my_var_parser) argc = ExprId('argc', 32) argv = ExprId('argv', 32) ret_addr = ExprId('ret_addr', 32) reg_and_id[argc.name] = argc reg_and_id[argv.name] = argv reg_and_id[ret_addr.name] = ret_addr my_symbols = [argc, argv, ret_addr] my_symbols = dict([(x.name, x) for x in my_symbols]) my_symbols.update(machine.mn.regs.all_regs_ids_byname) ir_arch = machine.ir(mdis.symbol_pool) symbexec = SymbolicExecutionEngine(ir_arch, symbols_init) blocks, symbol_pool = parse_asm.parse_txt(machine.mn, 32, ''' PUSH argv PUSH argc PUSH ret_addr ''') b = list(blocks)[0] print b # add fake address and len to parsed instructions for i, line in enumerate(b.lines): line.offset, line.l = i, 1 ir_arch.add_block(b) irb = get_block(ir_arch, mdis, 0)
line = machine.mn.fromstring("MOV EAX, EBX", 32) asm = machine.mn.asm(line)[0] # Get back block bin_stream = bin_stream_str(asm) mdis = machine.dis_engine(bin_stream) asm_block = mdis.dis_bloc(START_ADDR) # Translate ASM -> IR ira = machine.ira(mdis.symbol_pool) ira.add_bloc(asm_block) # Instanciate a Symbolic Execution engine with default value for registers ## EAX = EAX_init, ... symbols_init = ira.arch.regs.regs_init symb = SymbolicExecutionEngine(ira, symbols_init) # Emulate one IR basic block ## Emulation of several basic blocks can be done through .emul_ir_blocks cur_addr = symb.emul_ir_block(START_ADDR) # Modified elements print 'Modified registers:' symb.dump_id() print 'Modified memory (should be empty):' symb.dump_mem() # Check final status eax, ebx = ira.arch.regs.EAX, ira.arch.regs.EBX final_state = symb.as_assignblock() assert final_state[eax] == symbols_init[ebx]
def test_ClassDef(self): from miasm2.expression.expression import ExprInt, ExprId, ExprMem, \ ExprCompose, ExprAff from miasm2.arch.x86.sem import ir_x86_32 from miasm2.ir.symbexec import SymbolicExecutionEngine from miasm2.ir.ir import AssignBlock addrX = ExprInt(-1, 32) addr0 = ExprInt(0, 32) addr1 = ExprInt(1, 32) addr8 = ExprInt(8, 32) addr9 = ExprInt(9, 32) addr20 = ExprInt(20, 32) addr40 = ExprInt(40, 32) addr50 = ExprInt(50, 32) mem0 = ExprMem(addr0) mem1 = ExprMem(addr1, 8) mem8 = ExprMem(addr8) mem9 = ExprMem(addr9) mem20 = ExprMem(addr20) mem40v = ExprMem(addr40, 8) mem40w = ExprMem(addr40, 16) mem50v = ExprMem(addr50, 8) mem50w = ExprMem(addr50, 16) id_x = ExprId('x') id_y = ExprId('y', 8) id_a = ExprId('a') id_eax = ExprId('eax_init') e = SymbolicExecutionEngine(ir_x86_32(), {mem0: id_x, mem1: id_y, mem9: id_x, mem40w: id_x[:16], mem50v: id_y, id_a: addr0, id_eax: addr0}) self.assertEqual(e.find_mem_by_addr(addr0), mem0) self.assertEqual(e.find_mem_by_addr(addrX), None) self.assertEqual(e.eval_expr(ExprMem(addr1 - addr1)), id_x) self.assertEqual(e.eval_expr(ExprMem(addr1, 8)), id_y) self.assertEqual(e.eval_expr(ExprMem(addr1 + addr1)), ExprCompose( id_x[16:32], ExprMem(ExprInt(4, 32), 16))) self.assertEqual(e.eval_expr(mem8), ExprCompose( id_x[0:24], ExprMem(ExprInt(11, 32), 8))) self.assertEqual(e.eval_expr(mem40v), id_x[:8]) self.assertEqual(e.eval_expr(mem50w), ExprCompose( id_y, ExprMem(ExprInt(51, 32), 8))) self.assertEqual(e.eval_expr(mem20), mem20) e.func_read = lambda x: x self.assertEqual(e.eval_expr(mem20), mem20) self.assertEqual(set(e.modified()), set(e.symbols)) self.assertRaises( KeyError, e.symbols.__getitem__, ExprMem(ExprInt(100, 32))) self.assertEqual(e.apply_expr(id_eax), addr0) self.assertEqual(e.apply_expr(ExprAff(id_eax, addr9)), addr9) self.assertEqual(e.apply_expr(id_eax), addr9) # apply_change / eval_ir / apply_expr ## x = a (with a = 0x0) assignblk = AssignBlock({id_x:id_a}) e.eval_ir(assignblk) self.assertEqual(e.apply_expr(id_x), addr0) ## x = a (without replacing 'a' with 0x0) e.apply_change(id_x, id_a) self.assertEqual(e.apply_expr(id_x), id_a) ## x = a (with a = 0x0) self.assertEqual(e.apply_expr(assignblk.dst2ExprAff(id_x)), addr0) self.assertEqual(e.apply_expr(id_x), addr0) # state self.assertEqual(e.as_assignblock().get_r(), set([id_x, id_y]))
line = machine.mn.fromstring("MOV EAX, EBX", 32) asm = machine.mn.asm(line)[0] # Get back block bin_stream = bin_stream_str(asm) mdis = machine.dis_engine(bin_stream) asm_block = mdis.dis_bloc(START_ADDR) # Translate ASM -> IR ira = machine.ira(mdis.symbol_pool) ira.add_bloc(asm_block) # Instanciate a Symbolic Execution engine with default value for registers ## EAX = EAX_init, ... symbols_init = ira.arch.regs.regs_init symb = SymbolicExecutionEngine(ira, symbols_init) # Emulate one IR basic block ## Emulation of several basic blocks can be done through .emul_ir_blocks cur_addr = symb.emul_ir_block(START_ADDR) # Modified elements print 'Modified registers:' symb.dump_id() print 'Modified memory (should be empty):' symb.dump_mem() # Check final status eax, ebx = ira.arch.regs.EAX, ira.arch.regs.EBX assert symb.symbols[eax] == symbols_init[ebx] assert eax in symb.modified()
if __name__ == '__main__': translator_smt2 = Translator.to_language("smt2") data = open(args[0]).read() bs = bin_stream_str(data) mdis = dis_engine(bs) addr = int(options.address, 16) ir_arch = machine.ir(mdis.loc_db) ircfg = ir_arch.new_ircfg() symbexec = SymbolicExecutionEngine(ir_arch) asmcfg, loc_db = parse_asm.parse_txt(machine.mn, 32, ''' init: PUSH argv PUSH argc PUSH ret_addr ''', loc_db=mdis.loc_db) argc_lbl = loc_db.get_name_location('argc') argv_lbl = loc_db.get_name_location('argv') ret_addr_lbl = loc_db.get_name_location('ret_addr') init_lbl = loc_db.get_name_location('init')
def test_ClassDef(self): from miasm2.expression.expression import ExprInt, ExprId, ExprMem, \ ExprCompose, ExprAff from miasm2.arch.x86.sem import ir_x86_32 from miasm2.ir.symbexec import SymbolicExecutionEngine from miasm2.ir.ir import AssignBlock 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) sb = SymbolicExecutionEngine(ir_x86_32(), { 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)) ## Func read def custom_func_read(mem): if mem == ExprMem(ExprInt(0x1000, 32), 32): return id_x return mem sb.func_read = custom_func_read ## 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.dst2ExprAff(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(ExprAff(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 sb.symbols.iteritems(): 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 sb.symbols.iteritems(): 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 sb.symbols.iteritems(): if dst == ExprMem(ExprInt(0xFFFFFFFE, 32), 32) and src == id_e[16:48]: found = True assert found sb_empty = SymbolicExecutionEngine(ir_x86_32(), {}) sb_empty.dump() # Test memory full print 'full' arch_addr8 = ir_x86_32() # 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 = sb_addr8.symbols.items() 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 = sb_addr8.symbols.items() 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 sb_addr8.symbols.keys() == [ExprMem(ExprInt(0x5, 5), 256)]