def findDep(self, item): arg = item.args[self.lastClickIndex] address = item.address + item.instr.l func = item.func if func.ircfg is None: func.ira = BinaryAnalysis.iraType(func.cfg.loc_db) func.ircfg = func.ira.new_ircfg_from_asmcfg(func.cfg) func.defUse = DiGraphDefUse(ReachingDefinitions(func.ircfg)) indexReg = eval('BinaryAnalysis.machine.mn.regs.regs' + str(arg.size).zfill(2) + '_expr').index(arg) arg = eval('BinaryAnalysis.machine.mn.regs.regs' + str(BinaryAnalysis.disasmEngine.attrib).zfill(2) + '_expr')[ indexReg] elements = set() elements.add(arg) depgraph = DependencyGraph(func.ircfg, implicit=False, apply_simp=True, follow_call=False, follow_mem=True) currentLockey = next(iter(func.ircfg.getby_offset(address))) assignblkIndex = 0 currentBlock = func.ircfg.get_block(currentLockey) for assignblkIndex, assignblk in enumerate(currentBlock): if assignblk.instr.offset == address: break outputLog = '' for solNum, sol in enumerate(depgraph.get(currentBlock.loc_key, elements, assignblkIndex, set())): results = sol.emul(func.ira, ctx={}) outputLog += 'Solution %d:\n' % solNum for k, v in viewitems(results): outputLog += str(k) + ' = ' + str(v) + '\n' path = ' -> '.join(BinaryAnalysis.locDB.pretty_str(h) for h in sol.history[::-1]) outputLog += path + '\n\n' self.log.emit(outputLog)
def get_funcs_arg0(ctx, ira, ircfg, lbl_head): """Compute DependencyGraph on the func @lbl_head""" g_dep = DependencyGraph(ircfg, follow_call=False) element = ira.arch.regs.RSI for loc_key, index in find_call(ircfg): irb = ircfg.get_block(loc_key) instr = irb[index].instr print('Analysing references from:', hex(instr.offset), instr) g_list = g_dep.get(irb.loc_key, set([element]), index, set([lbl_head])) for dep in g_list: emul_result = dep.emul(ira, ctx) value = emul_result[element] yield value
def _insert_flat_block(self, source_flat_block, symb_exec, flat_block_to_loc_key): """ Copies source_flat_block and sets its successors according to flat_block_to_loc_key :param flat_block_to_loc_key: dictionary mapping flat_blocks to respective loc_keys :param symb_exec: instance of current symbolic execution engine :param source_flat_block: flat_block to be inserted :return: dictionary mapping old successor loc_keys to the new ones """ # we're not using redirect_successors after copying to avoid executing the same loops multiple times source_block = self.asmcfg.loc_key_to_block( source_flat_block.block_loc_key) tobe_processed = {} new_flat_blocks = set() new_block_loc_key = flat_block_to_loc_key[source_flat_block] if self.out_asmcfg.loc_key_to_block(new_block_loc_key) is not None: raise Exception("Target loc_key is already associated to a block") new_block = AsmBlock(new_block_loc_key) # copy instructions for ln in source_block.lines: tmp_ln = instruction_x86(ln.name, ln.mode, [i.copy() for i in ln.args], ln.additional_info) tmp_ln.b = ln.b tmp_ln.l = ln.l tmp_ln.offset = ln.offset new_block.addline(tmp_ln) constraints = source_block.bto # try to simplify the destination if it's a primary flattening block if not self.flat_loops[source_block.loc_key].is_default: logger.debug("current block is a part of primary loc_keys") simplified_target = symb_exec.eval_expr(self.ircfg.IRDst) if isinstance(simplified_target, ExprInt): simplified_target = self.asmcfg.loc_db.get_offset_location( int(simplified_target)) elif isinstance(simplified_target, ExprLoc): simplified_target = simplified_target.loc_key else: # there's probably a(n) (series of) unknown instruction(s) causing an implicit conditional assignment # such as CMOV or SBB->AND->ADD, prepend comparison + cond jump if it happens to be common, or add it to # ExtendedAsmCFG.extended_discovery and split flow on the final instruction # it's also possible that it's not related to any cff loop at all addr = self.asmcfg.loc_db.get_location_offset( source_flat_block.block_loc_key) addr = hex(addr) if addr else addr logger.warning( "Couldn't simplify loc_key %s at %s, continuing" % (str(source_flat_block.block_loc_key), addr)) logger.warning("the simplified target is %s of instance %s" % (simplified_target, type(simplified_target))) simplified_target = None if simplified_target: constraints = {AsmConstraintTo(simplified_target)} mode = self.asmcfg.mode # remove redundant comparison dp = DependencyGraph(self.ircfg, True) block_loc_key = source_block.loc_key res = next( dp.get(block_loc_key, {self.ircfg.IRDst}, None, {block_loc_key})) for depnode in res.relevant_nodes: ind = depnode.line_nb ind -= (len(self.ircfg.blocks[block_loc_key]) - len(new_block.lines)) if new_block.lines[ind].name == "CMP": new_block.lines.pop(ind) new_block.lines[-1] = create_jump_instruction( mode, ExprLoc(simplified_target, mode)) # copy constraints new_bto = set() for constraint in constraints: if not self.asmcfg.loc_key_to_block(constraint.loc_key): logger.debug("Skipping bad constraint %s" % constraint.loc_key) continue flat_block = self.flat_loops.get_block(constraint.loc_key, symb_exec, source_flat_block) if flat_block not in flat_block_to_loc_key: new_flat_blocks.add(flat_block) new_loc_key = self.out_asmcfg.loc_db.add_location() tobe_processed[constraint.loc_key] = (new_loc_key, flat_block) flat_block_to_loc_key[flat_block] = new_loc_key else: new_loc_key = flat_block_to_loc_key[flat_block] new_bto.add(AsmConstraint(new_loc_key, constraint.c_t)) new_block.bto = new_bto new_block.alignment = source_block.alignment # change jmp targets if new_block.lines: for ind, arg in enumerate(list(new_block.lines[-1].args)): if isinstance(arg, ExprLoc): if not self.asmcfg.loc_key_to_block(arg.loc_key): logger.debug("Skipping bad constraint %s" % arg.loc_key) continue new_target, flat_block = tobe_processed.get( arg.loc_key, (None, None)) if not new_target: flat_block = self.flat_loops.get_block( arg.loc_key, symb_exec, source_flat_block) new_target = flat_block_to_loc_key.get(flat_block) # None in case of irrelevant calls logger.debug("new target: %s" % new_target) if new_target: new_block.lines[-1].args[ind] = ExprLoc( new_target, arg.size) self.out_asmcfg.add_block(new_block) return new_flat_blocks
# StdCall example for i in range(4): e_mem = ExprMem( ExprId("ESP_init", 32) + ExprInt(4 * (i + 1), 32), 32) init_ctx[e_mem] = ExprId("arg%d" % i, 32) # Disassemble the targeted function asmcfg = mdis.dis_multiblock(int(args.func_addr, 0)) # Generate IR ircfg = ir_arch.new_ircfg_from_asmcfg(asmcfg) # Get the instance dg = DependencyGraph(ircfg, implicit=args.implicit, apply_simp=not args.do_not_simplify, follow_mem=not args.unfollow_mem, follow_call=not args.unfollow_call) # Build information target_addr = int(args.target_addr, 0) current_loc_key = next(iter(ircfg.getby_offset(target_addr))) assignblk_index = 0 current_block = ircfg.get_block(current_loc_key) for assignblk_index, assignblk in enumerate(current_block): if assignblk.instr.offset == target_addr: break # Enumerate solutions json_solutions = [] for sol_nb, sol in enumerate(
(G16_IRA, G16_INPUT), (G17_IRA, G17_INPUT), ]): # Extract test elements print("[+] Test", test_nb + 1) ircfg, (depnodes, heads) = test open("graph_%02d.dot" % (test_nb + 1), "w").write(ircfg.dot()) open("graph_%02d.dot" % (test_nb + 1), "w").write(bloc2graph(ircfg)) # Different options suffix_key_list = ["", "_nosimp", "_nomem", "_nocall", "_implicit"] # Test classes for g_ind, g_dep in enumerate([DependencyGraph(ircfg), DependencyGraph(ircfg, apply_simp=False), DependencyGraph(ircfg, follow_mem=False), DependencyGraph( ircfg, follow_mem=False, follow_call=False ), # DependencyGraph(ircfg, implicit=True), ]): # if g_ind == 4: # TODO: Implicit specifications # continue print(" - Class %s - %s" % (g_dep.__class__.__name__, suffix_key_list[g_ind])) # Select the correct result key mode_suffix = suffix_key_list[g_ind]
if arch == "x86_32": # StdCall example for i in range(4): e_mem = ExprMem(ExprId("ESP_init", 32) + ExprInt(4 * (i + 1), 32), 32) init_ctx[e_mem] = ExprId("arg%d" % i, 32) # Disassemble the targeted function asmcfg = mdis.dis_multiblock(int(args.func_addr, 0)) # Generate IR ircfg = ir_arch.new_ircfg_from_asmcfg(asmcfg) # Get the instance dg = DependencyGraph( ircfg, implicit=args.implicit, apply_simp=not args.do_not_simplify, follow_mem=not args.unfollow_mem, follow_call=not args.unfollow_call ) # Build information target_addr = int(args.target_addr, 0) current_loc_key = next(iter(ircfg.getby_offset(target_addr))) assignblk_index = 0 current_block = ircfg.get_block(current_loc_key) for assignblk_index, assignblk in enumerate(current_block): if assignblk.instr.offset == target_addr: break # Enumerate solutions json_solutions = [] for sol_nb, sol in enumerate(dg.get(current_block.loc_key, elements, assignblk_index, set())):
def _mark_branch_conditions(self, ctx=None): """ For any cjmp in CFG tries to find all solutions for []IP symbol :return: """ ir_loc: LocKey ir_block: IRBlock for ir_loc, ir_block in self._ir_cfg.blocks.items(): # check for detect current location that is head or tail of natural loop loc_addr = self._ir_cfg.loc_db.get_location_offset(ir_loc) is_head, _ = self._is_loop_head(ir_loc) is_tail, _ = self._is_loop_tail(ir_loc) if not ir_block.dst.is_cond() or is_head or is_tail: continue dg = DependencyGraph(self._ir_cfg) dst_solutions = set() solutions_log = [] for sol in dg.get(ir_loc, [self.ip], ir_block.assignblks[-1].instr.offset, set()): try: solutions = sol.emul(self._ir_arch, ctx=ctx) except NotImplementedError as ex: log(f"Unsupported expression in location - {ir_loc}", code='!') solutions_log.append((ir_loc, ir_block, None)) dst_solutions = set() break ip_expr = solutions.get(self.ip) solutions_log.append((ir_loc, ir_block, ip_expr)) if not ip_expr.is_int() and not ip_expr.is_loc( ) and not is_static_expr(ip_expr): dst_solutions = set() known_dst = self._flow_patches_map.get(loc_addr, None) if known_dst: del self._flow_patches_map[loc_addr] break if not ip_expr.is_int() and not ip_expr.is_loc(): log(f"Static ip expressions unsupported now [{ip_expr}]") # invlidate dst_solutions dst_solutions = set() known_dst = self._flow_patches_map.get(loc_addr, None) if known_dst: del self._flow_patches_map[loc_addr] break dst_solutions.update([ip_expr]) if self._verbose_log: vl_pad = 24 for ir_loc, ir_block, ip_expr in solutions_log: print(f"{'-' * vl_pad}") print(f"{ir_loc} - {hex(loc_addr)if loc_addr else 'None'}") for assign_block in ir_block.assignblks: for dst, src in assign_block.iteritems(): print(f"{dst} = {src}") print(f"{'-' * vl_pad}") print(f"Solution: {ip_expr}") if len(dst_solutions) != 1: continue static_dst = dst_solutions.pop() static_addr = simple_unwrap_expr(static_dst, self._ir_cfg.loc_db) if static_addr == -1: log(f"Oops ... {static_dst}. Fail resolve dst by a simple approach", code='!') continue known_dst = self._flow_patches_map.get(loc_addr, None) if known_dst is None: self._flow_patches_map[loc_addr] = static_addr elif self._flow_patches_map[loc_addr] != static_addr: # We found in another path different static solution, not opaque jmp del self._flow_patches_map[loc_addr] if self._verbose_log: for l, d in self._flow_patches_map.items(): print(f"{hex(l)} -> {hex(d)}")
def depgraph(self): value = self.cMethod.value return DependencyGraph(self.ircfg, implicit=value & 4, follow_mem=value & 1, follow_call=value & 2)