end_addr = last_addr + last_item_size if end_addr < max_addr: try: next_addr = self.ceiling_addr(end_addr) except KeyError: next_addr = max_addr if next_addr > end_addr: # there is a gap size = next_addr - end_addr if obj is None or isinstance(obj, cle.ExternObject): bytes_ = None else: try: _l.debug("Loading bytes from object %s, section %s, segmeng %s, addresss %#x.", obj, section, segment, next_addr) bytes_ = self.project.loader.memory.load(next_addr, size) except KeyError: # The address does not exist bytes_ = None self.add_obj(end_addr, Unknown(end_addr, size, bytes_=bytes_, object_=obj, segment=segment, section=section) ) addr = next_addr else: addr = max_addr from angr.analyses import AnalysesHub AnalysesHub.register_default('CFB', CFBlanket) AnalysesHub.register_default('CFBlanket', CFBlanket)
counter=n_counter)[-1] u_flags = sl.regs.flags.canonicalize(var_map=u_map, counter=u_counter)[-1] if n_flags is not u_flags and sl.se.simplify( n_flags) is not sr.se.simplify(u_flags): self._report_incongruency("Different flags!") return False return True def compare_paths(self, pl, pr): l.debug("Comparing paths...") if not self.compare_states(pl, pr): self._report_incongruency("Failed state similarity check!") return False if pr.history.block_count != pl.history.block_count: self._report_incongruency("Different weights!") return False if pl.addr != pr.addr: self._report_incongruency("Different addresses!") return False return True from ..errors import AngrIncongruencyError from angr.analyses import AnalysesHub AnalysesHub.register_default('CongruencyCheck', CongruencyCheck)
:return: None """ register_pvs = set() for node in data_graph.nodes(): if isinstance(node.variable, SimRegisterVariable) and \ node.variable.reg is not None and \ node.variable.reg < 40: register_pvs.add(node) for reg in register_pvs: # does it have a consumer? out_edges = data_graph.out_edges(reg, data=True) consumers = [] killers = [] for _, _, data in out_edges: if 'type' in data and data['type'] == 'kill': killers.append(data) else: consumers.append(data) if not consumers and killers: # we can remove the assignment! da = DeadAssignment(reg) self.dead_assignments.append(da) from angr.analyses import AnalysesHub AnalysesHub.register_default('BinaryOptimizer', BinaryOptimizer)
(src, dst) for src, dst, data in reversed_cyclic_graph.edges(data=True) if data['jumpkind'] in ('Ijk_FakeRet', 'Ijk_Exit') ] reversed_cyclic_graph.remove_edges_from(fakeret_edges) # Perform a topological sort sorted_nodes = networkx.topological_sort(graph) nodes = [ n for n in sorted_nodes if graph.in_degree(n) > 1 and n.looping_times == 0 ] # Reorder nodes based on post-dominance relations nodes = sorted( nodes, key=cmp_to_key(lambda n1, n2: (1 if self._post_dominate( reversed_cyclic_graph, n1, n2) else (-1 if self._post_dominate( reversed_cyclic_graph, n2, n1) else 0)))) return [(n.addr, n.looping_times) for n in nodes] from angr.analyses import AnalysesHub AnalysesHub.register_default('Veritesting', Veritesting) from ..errors import SimValueError, SimSolverModeError, SimError from ..sim_options import BYPASS_VERITESTING_EXCEPTIONS from claripy import ClaripyError
size=node.size, opt_level=0 # disable the optimization in order to have # instruction-level analysis results ) output_states = successors.all_successors state.concrete_states = [ state for state in output_states if not state.ip.symbolic ] self._outstates[node.addr] = state self._node_iterations[node] += 1 return True, state def _intra_analysis(self): pass def _post_analysis(self): # TODO: only re-assign variable names to those that are newly changed self.variable_manager.initialize_variable_names() for addr, state in self._outstates.items(): self.variable_manager[self.function.addr].set_live_variables(addr, state.register_region, state.stack_region ) from angr.analyses import AnalysesHub AnalysesHub.register_default('VariableRecovery', VariableRecovery)
# This is for testing successors = graph.graph.successors(node) else: # Real CFGNode! successors = graph.model.get_successors(node) return successors def _pd_post_process(self, cfg): """ Take care of those loop headers/tails where we manually broke their connection to the next BBL """ loop_back_edges = self._cfg.get_loop_back_edges() for b1, b2 in loop_back_edges: # The edge between b1 and b2 is manually broken # The post dominator of b1 should be b2 (or not?) successors = list(self._pd_graph_successors(cfg, b1)) if len(successors) == 0: if b2 in self._post_dom: self._post_dom.add_edge(b1, b2) else: _l.debug("%s is not in post dominator dict.", b2) from angr.analyses import AnalysesHub AnalysesHub.register_default('CDG', CDG)
Search for the last branching exit, just like # if (t12) { PUT(184) = 0xBADF00D:I64; exit-Boring } and then taint the temp variable inside if predicate """ cmp_stmt_id = None cmp_tmp_id = None all_statements = len(statements) statements = reversed(statements) for stmt_rev_idx, stmt in enumerate(statements): stmt_idx = all_statements - stmt_rev_idx - 1 actions = stmt.actions # Ugly implementation here has_code_action = False for a in actions: if isinstance(a, SimActionExit): has_code_action = True break if has_code_action: readtmp_action = next(filter(lambda r: r.type == 'tmp' and r.action == 'read', actions), None) if readtmp_action is not None: cmp_tmp_id = readtmp_action.tmp cmp_stmt_id = stmt_idx break else: raise AngrBackwardSlicingError("ReadTempAction is not found. Please report to Fish.") return cmp_stmt_id, cmp_tmp_id from angr.analyses import AnalysesHub AnalysesHub.register_default('BackwardSlice', BackwardSlice)
n_flags = sr.regs.eflags.canonicalize(var_map=n_map, counter=n_counter)[-1] u_flags = sl.regs.eflags.canonicalize(var_map=u_map, counter=u_counter)[-1] else: n_flags = sr.regs.flags.canonicalize(var_map=n_map, counter=n_counter)[-1] u_flags = sl.regs.flags.canonicalize(var_map=u_map, counter=u_counter)[-1] if n_flags is not u_flags and sl.se.simplify(n_flags) is not sr.se.simplify(u_flags): self._report_incongruency("Different flags!") return False return True def compare_paths(self, pl, pr): l.debug("Comparing paths...") if not self.compare_states(pl, pr): self._report_incongruency("Failed state similarity check!") return False if pr.history.block_count != pl.history.block_count: self._report_incongruency("Different weights!") return False if pl.addr != pr.addr: self._report_incongruency("Different addresses!") return False return True from ..errors import AngrIncongruencyError from angr.analyses import AnalysesHub AnalysesHub.register_default('CongruencyCheck', CongruencyCheck)
entry_edges, break_edges, continue_edges, loop_body_nodes, subg, tops[:]) return me, [me] + alls def _parse_loops_from_graph(self, graph): """ Return all Loop instances that can be extracted from a graph. :param graph: The graph to analyze. :return: A list of all the Loop instances that were found in the graph. """ outtop = [] outall = [] for subg in networkx.strongly_connected_component_subgraphs(graph): if len(subg.nodes()) == 1: if len(list(subg.successors(list(subg.nodes())[0]))) == 0: continue thisloop, allloops = self._parse_loop_graph(subg, graph) if thisloop is not None: outall += allloops outtop.append(thisloop) return outtop, outall from angr.analyses import AnalysesHub AnalysesHub.register_default('LoopFinder', LoopFinder)
# def _process_block(self, state, block): # pylint:disable=no-self-use """ Scan through all statements and perform the following tasks: - Find stack pointers and the VEX temporary variable storing stack pointers - Selectively calculate VEX statements - Track memory loading and mark stack and global variables accordingly :param angr.Block block: :return: """ l.debug('Processing block %#x.', block.addr) processor = self._ail_engine if isinstance(block, ailment.Block) else self._vex_engine processor.process(state, block=block, fail_fast=self._fail_fast) # readjusting sp at the end for blocks that end in a call if block.addr in self._node_to_cc: cc = self._node_to_cc[block.addr] if cc is not None: state.processor_state.sp_adjustment += cc.sp_delta state.processor_state.sp_adjusted = True l.debug('Adjusting stack pointer at end of block %#x with offset %+#x.', block.addr, state.processor_state.sp_adjustment) from angr.analyses import AnalysesHub AnalysesHub.register_default('VariableRecoveryFast', VariableRecoveryFast)
initial_state.options.discard(options.CGC_ZERO_FILL_UNCONSTRAINED_MEMORY) initial_state.options.update({options.TRACK_REGISTER_ACTIONS, options.TRACK_MEMORY_ACTIONS, options.TRACK_JMP_ACTIONS, options.TRACK_CONSTRAINT_ACTIONS}) symbolic_stack = initial_state.se.BVS("symbolic_stack", project.arch.bits * stack_length) initial_state.memory.store(initial_state.regs.sp, symbolic_stack) if initial_state.arch.bp_offset != initial_state.arch.sp_offset: initial_state.regs.bp = initial_state.regs.sp + 20 * initial_state.arch.bytes initial_state.se._solver.timeout = 500 # only solve for half a second at most return initial_state @staticmethod def make_symbolic_state(project, reg_list, stack_length=80): """ converts an input state into a state with symbolic registers :return: the symbolic state """ input_state = Identifier.make_initial_state(project, stack_length) symbolic_state = input_state.copy() # overwrite all registers for reg in reg_list: symbolic_state.registers.store(reg, symbolic_state.se.BVS("sreg_" + reg + "-", project.arch.bits)) # restore sp symbolic_state.regs.sp = input_state.regs.sp # restore bp symbolic_state.regs.bp = input_state.regs.bp return symbolic_state from angr.analyses import AnalysesHub AnalysesHub.register_default('Identifier', Identifier)
else: return method def resolve_invoke(self, invoke_expr, method, container): # Generic method to resolve invoke # Given an invoke expression it figures out which "technique" should be applied invoke_type = str(type(invoke_expr)) cls = self.project.loader.main_object.classes[method.class_name] if 'VirtualInvokeExpr' in invoke_type: targets = self.resolve_abstract_dispatch(cls, method) elif 'DynamicInvokeExpr' in invoke_type: targets = self.resolve_abstract_dispatch(cls, method) elif 'InterfaceInvokeExpr' in invoke_type: targets = self.resolve_abstract_dispatch(cls, method) elif 'SpecialInvokeExpr' in invoke_type: t = self.resolve_special_dispatch(method, container) targets = [t] elif 'StaticInvokeExpr' in invoke_type: targets = [method] return targets from angr.analyses import AnalysesHub AnalysesHub.register_default('SootClassHierarchy', SootClassHierarchy)
elif exprs[0].tag == 'Iex_Const': dfg.add_edge(exprs[0], stmt_node) putsnodes[stmt.offset] = stmt_node elif stmt.tag == 'Ist_Exit': if exprs[0].tag == 'Iex_RdTmp': dfg.add_edge(tmpsnodes[exprs[0].tmp], stmt_node) elif stmt.tag == 'Ist_Dirty': tmpsnodes[stmt.tmp] = stmt_node elif stmt.tag == 'Ist_CAS': tmpsnodes[stmt.oldLo] = stmt_node else: for e in stmt.expressions: if e.tag == 'Iex_RdTmp': dfg.add_edge(tmpsnodes[e.tmp], stmt_node) else: dfg.add_edge(e, stmt_node) for vtx in list(dfg.nodes()): if dfg.degree(vtx) == 0: dfg.remove_node(vtx) if dfg.size() > 0: dfgs[node.addr] = dfg return dfgs from angr.analyses import AnalysesHub AnalysesHub.register_default('DFG', DFG)
opt_level=0 # disable the optimization in order to have # instruction-level analysis results ) output_states = successors.all_successors state.concrete_states = [ state for state in output_states if not state.ip.symbolic ] self._node_to_state[node.addr] = state self._node_iterations[node] += 1 return True, state def _intra_analysis(self): pass def _post_analysis(self): # TODO: only re-assign variable names to those that are newly changed self.variable_manager.initialize_variable_names() for addr, state in self._node_to_state.items(): self.variable_manager[self.function.addr].set_live_variables( addr, state.register_region, state.stack_region) from angr.analyses import AnalysesHub AnalysesHub.register_default('VariableRecovery', VariableRecovery)
r = re.compile(ins_regex) regexes.add(r) for start_, data in self.project.loader.main_object.memory.backers(): for regex in regexes: # Match them! for mo in regex.finditer(data): position = mo.start() + start_ if position % arch.instruction_alignment == 0: votes[(arch.name, arch.memory_endness)] += 1 l.debug("%s %s hits %d times", arch.name, arch.memory_endness, votes[(arch.name, arch.memory_endness)]) arch_name, endianness, hits = sorted([(k[0], k[1], v) for k, v in votes.items()], key=lambda x: x[2], reverse=True)[0] if hits < self.cookiesize * 2: # this cannot possibly be code arch_name = "DATA" endianness = "" self.arch = arch_name self.endianness = endianness # Save it as well for debugging self.votes = votes l.debug("The architecture should be %s with %s", self.arch, self.endianness) from angr.analyses import AnalysesHub AnalysesHub.register_default('BoyScout', BoyScout)
return stmt_idx if stmt_idx == DEFAULT_STATEMENT: vex_block = self.project.factory.block(block_addr).vex return len(vex_block.statements) raise AngrBackwardSlicingError('Unsupported statement ID "%s"' % stmt_idx) @staticmethod def _last_branching_statement(statements): """ Search for the last branching exit, just like # if (t12) { PUT(184) = 0xBADF00D:I64; exit-Boring } and then taint the temp variable inside if predicate """ cmp_stmt_id = None cmp_tmp_id = None total_stmts = len(statements) statements = reversed(statements) for stmt_rev_idx, stmt in enumerate(statements): if isinstance(stmt, pyvex.IRStmt.Exit): stmt_idx = total_stmts - stmt_rev_idx - 1 cmp_stmt_id = stmt_idx cmp_tmp_id = stmt.guard.tmp return cmp_stmt_id, cmp_tmp_id from angr.analyses import AnalysesHub AnalysesHub.register_default('BackwardSlice', BackwardSlice)
cs = self.project.arch.capstone_thumb else: aligned_block_addr = block.addr cs = self.project.arch.capstone if block.bytestr is None: bytestr = ''.join(self.project.loader.memory.read_bytes(aligned_block_addr, block.size)) else: bytestr = block.bytestr self.block_to_insn_addrs[block.addr] = [] for cs_insn in cs.disasm(bytestr, block.addr): if cs_insn.address in self.kb.labels: label = Label(cs_insn.address, self.kb.labels[cs_insn.address]) self.raw_result.append(label) self.raw_result_map['labels'][label.addr] = label if cs_insn.address in self.kb.comments: comment = Comment(cs_insn.address, self.kb.comments[cs_insn.address]) self.raw_result.append(comment) self.raw_result_map['comments'][comment.addr] = comment instruction = Instruction(CapstoneInsn(cs_insn), bs) self.raw_result.append(instruction) self.raw_result_map['instructions'][instruction.addr] = instruction self.block_to_insn_addrs[block.addr].append(cs_insn.address) def render(self, formatting=None): if formatting is None: formatting = {} return '\n'.join(sum((x.render(formatting) for x in self.raw_result), [])) from angr.analyses import AnalysesHub AnalysesHub.register_default('Disassembly', Disassembly)
ailment.Stmt.Call: _handle_Call, } expr_handlers = { ailment.Stmt.Call: _handle_CallExpr, } block_walker = AILBlockWalker(stmt_handlers=stmt_handlers, expr_handlers=expr_handlers) def _graph_walker_handler(node): block_walker.walk(node) AILGraphWalker(ail_graph, _graph_walker_handler, replace_nodes=False).walk() # add strings references that are not used in function calls self._process_strings(func, proxi_nodes, exclude_string_refs=string_refs) # add it to the graph graph.add_node(func_proxi_node) for pn in proxi_nodes: graph.add_edge(func_proxi_node, pn) return to_expand from angr.analyses import AnalysesHub AnalysesHub.register_default('Proximity', ProximityGraphAnalysis)
context-sensitivity, and state keeping) only exist in CFGAccurate, which is when you want to use CFGAccurate instead. """ def __init__(self, **kwargs): outdated_exception = "CFG is now an alias to CFGFast." outdated_message = "CFG is now an alias to CFGFast. Please switch to CFGAccurate if you need functionalities " \ "that only exist there. For most cases, your code should be fine by changing \"CFG(...)\" " \ "to \"CFGAccurate(...)\". Sorry for breaking your code with this giant change." cfgaccurate_params = { 'context_sensitivity_level', 'avoid_runs', 'enable_function_hints', 'call_depth', 'call_tracing_filter', 'initial_state', 'starts', 'keep_state', 'enable_advanced_backward_slicing', 'enable_symbolic_back_traversal', 'additional_edges', 'no_construct' } # Sanity check to make sure the user only wants to use CFGFast for p in cfgaccurate_params: if kwargs.get(p, None) is not None: sys.stderr.write(outdated_message + "\n") raise OutdatedError(outdated_exception) # Now initializes CFGFast :-) CFGFast.__init__(self, **kwargs) from angr.analyses import AnalysesHub AnalysesHub.register_default('CFG', CFG)
if data['jumpkind'] in ('Ijk_FakeRet', 'Ijk_Exit') ] graph.remove_edges_from(fakeret_edges) # Remove all "FakeRet" edges from cyclic_graph as well fakeret_edges = [ (src, dst) for src, dst, data in reversed_cyclic_graph.edges(data=True) if data['jumpkind'] in ('Ijk_FakeRet', 'Ijk_Exit') ] reversed_cyclic_graph.remove_edges_from(fakeret_edges) # Perform a topological sort sorted_nodes = networkx.topological_sort(graph) nodes = [ n for n in sorted_nodes if graph.in_degree(n) > 1 and n.looping_times == 0 ] # Reorder nodes based on post-dominance relations nodes = sorted(nodes, key=cmp_to_key(lambda n1, n2: ( 1 if self._post_dominate(reversed_cyclic_graph, n1, n2) else (-1 if self._post_dominate(reversed_cyclic_graph, n2, n1) else 0) ))) return [ (n.addr, n.looping_times) for n in nodes ] from angr.analyses import AnalysesHub AnalysesHub.register_default('Veritesting', Veritesting) from ..errors import SimValueError, SimSolverModeError, SimError from ..sim_options import BYPASS_VERITESTING_EXCEPTIONS from claripy import ClaripyError
# Match them! for mo in regex.finditer(data): position = mo.start() + start_ if position % arch.instruction_alignment == 0: votes[(arch.name, arch.memory_endness)] += 1 l.debug("%s %s hits %d times", arch.name, arch.memory_endness, votes[(arch.name, arch.memory_endness)]) arch_name, endianness, hits = sorted([(k[0], k[1], v) for k, v in votes.iteritems()], key=lambda x: x[2], reverse=True)[0] if hits < self.cookiesize * 2: # this cannot possibly be code arch_name = "DATA" endianness = "" self.arch = arch_name self.endianness = endianness # Save it as well for debugging self.votes = votes l.debug("The architecture should be %s with %s", self.arch, self.endianness) from angr.analyses import AnalysesHub AnalysesHub.register_default('BoyScout', BoyScout)
edges_by_line.add((f, t)) # Render block edges, to a reference buffer for tracking and output buffer for display edge_buf = ['' for _ in buf] ref_buf = ['' for _ in buf] edge_col = col('edge') for f, t in sorted(edges_by_line, key=lambda e: abs(e[0] - e[1])): add_edge_to_buffer(edge_buf, ref_buf, f, t, lambda s: ansi_color(s, edge_col), ascii_only=ascii_only) add_edge_to_buffer(ref_buf, ref_buf, f, t, ascii_only=ascii_only) max_edge_depth = max(map(len, ref_buf)) # Justify edge and combine with disassembly for i, line in enumerate(buf): buf[i] = ' ' * (max_edge_depth - len(ref_buf[i])) + edge_buf[i] + line return '\n'.join(buf) from angr.analyses import AnalysesHub AnalysesHub.register_default('Disassembly', Disassembly)
:param angr.knowledge.Function function: :param networkx.MultiDiGraph data_graph: :return: None """ register_pvs = set() for node in data_graph.nodes(): if isinstance(node.variable, SimRegisterVariable) and \ node.variable.reg is not None and \ node.variable.reg < 40: register_pvs.add(node) for reg in register_pvs: # does it have a consumer? out_edges = data_graph.out_edges(reg, data=True) consumers = [ ] killers = [ ] for _, _, data in out_edges: if 'type' in data and data['type'] == 'kill': killers.append(data) else: consumers.append(data) if not consumers and killers: # we can remove the assignment! da = DeadAssignment(reg) self.dead_assignments.append(da) from angr.analyses import AnalysesHub AnalysesHub.register_default('BinaryOptimizer', BinaryOptimizer)
# there is a gap size = next_addr - end_addr if obj is None or isinstance(obj, cle.ExternObject): bytes_ = None else: try: _l.debug( "Loading bytes from object %s, section %s, segmeng %s, addresss %#x.", obj, section, segment, next_addr) bytes_ = self.project.loader.memory.load( next_addr, size) except KeyError: # The address does not exist bytes_ = None self.add_obj( end_addr, Unknown(end_addr, size, bytes_=bytes_, object_=obj, segment=segment, section=section)) addr = next_addr else: addr = max_addr from angr.analyses import AnalysesHub AnalysesHub.register_default('CFB', CFBlanket) AnalysesHub.register_default('CFBlanket', CFBlanket)
initial_state.memory.store(initial_state.regs.sp, symbolic_stack) if initial_state.arch.bp_offset != initial_state.arch.sp_offset: initial_state.regs.bp = initial_state.regs.sp + 20 * initial_state.arch.bytes initial_state.solver._solver.timeout = 500 # only solve for half a second at most return initial_state @staticmethod def make_symbolic_state(project, reg_list, stack_length=80): """ converts an input state into a state with symbolic registers :return: the symbolic state """ input_state = Identifier.make_initial_state(project, stack_length) symbolic_state = input_state.copy() # overwrite all registers for reg in reg_list: symbolic_state.registers.store( reg, symbolic_state.solver.BVS("sreg_" + reg + "-", project.arch.bits)) # restore sp symbolic_state.regs.sp = input_state.regs.sp # restore bp symbolic_state.regs.bp = input_state.regs.bp return symbolic_state from angr.analyses import AnalysesHub AnalysesHub.register_default('Identifier', Identifier)
:return: """ l.debug('Processing block %#x.', block.addr) processor = self._ail_engine if isinstance( block, ailment.Block) else self._vex_engine processor.process(state, block=block, fail_fast=self._fail_fast) if self._track_sp and block.addr in self._node_to_cc: # readjusting sp at the end for blocks that end in a call cc = self._node_to_cc[block.addr] state.processor_state.sp_adjusted = False if cc is not None and cc.sp_delta is not None: state.processor_state.sp_adjustment += cc.sp_delta state.processor_state.sp_adjusted = True l.debug( 'Adjusting stack pointer at end of block %#x with offset %+#x.', block.addr, state.processor_state.sp_adjustment) else: # make a guess # of course, this will fail miserably if the function called is not cdecl if self.project.arch.call_pushes_ret: state.processor_state.sp_adjustment += self.project.arch.bytes state.processor_state.sp_adjusted = True from angr.analyses import AnalysesHub AnalysesHub.register_default('VariableRecoveryFast', VariableRecoveryFast)
raise AngrGirlScoutError('Please generate the call graph first.') f = open(filepath, "wb") for src, dst in graph.edges(): f.write("0x%x\tDirectEdge\t0x%x\n" % (src, dst)) f.close() def generate_code_cover(self): """ Generate a list of all recovered basic blocks. """ lst = [ ] for irsb_addr in self.cfg.nodes(): if irsb_addr not in self._block_size: continue irsb_size = self._block_size[irsb_addr] lst.append((irsb_addr, irsb_size)) lst = sorted(lst, key=lambda x: x[0]) return lst from angr.analyses import AnalysesHub AnalysesHub.register_default('GirlScout', GirlScout) from ..blade import Blade from ..errors import AngrGirlScoutError
# Case 2: a is a subset of the original address # Case 3: a is a superset of the original address live_defs[variable] = { code_loc } l.debug("XX CodeLoc %s kills variable %s", code_loc, variable) def _add_edge(self, s_a, s_b, **edge_labels): """ Add an edge in the graph from `s_a` to statement `s_b`, where `s_a` and `s_b` are tuples of statements of the form (irsb_addr, stmt_idx). """ # Is that edge already in the graph ? # If at least one is new, then we are not redoing the same path again if (s_a, s_b) not in self.graph.edges(): self.graph.add_edge(s_a, s_b, **edge_labels) self._new = True l.info("New edge: %s --> %s", s_a, s_b) def get_all_nodes(self, simrun_addr, stmt_idx): """ Get all DDG nodes matching the given basic block address and statement index. """ nodes=[] for n in self.graph.nodes(): if n.simrun_addr == simrun_addr and n.stmt_idx == stmt_idx: nodes.add(n) return nodes from angr.analyses import AnalysesHub AnalysesHub.register_default('VSA_DDG', VSA_DDG)
todo = [addr] while todo: addr = todo.pop(0) seen.add(addr) irsb = self.project.factory.block(addr, opt_level=0).vex if irsb.jumpkind == 'Ijk_Ret': # got it! for stmt in reversed(irsb.statements): if stmt.tag == 'Ist_IMark': l.error("VERY strange return instruction at %#x...", addr) break if stmt.tag == 'Ist_WrTmp': if stmt.data.tag == 'Iex_Binop': if stmt.data.op.startswith('Iop_Add'): return stmt.data.args[ 1].con.value - self.project.arch.bytes elif irsb.jumpkind == 'Ijk_Call': if addr + irsb.size not in seen: todo.append(addr + irsb.size) else: todo.extend(irsb.constant_jump_targets - seen) return None from angr.analyses import AnalysesHub AnalysesHub.register_default('CalleeCleanupFinder', CalleeCleanupFinder)
lambda g: entry_node in g.nodes(), networkx.weakly_connected_component_subgraphs(subg))) me = Loop(entry_node, entry_edges, break_edges, continue_edges, loop_body_nodes, subg, tops[:]) return me, [me] + alls def _parse_loops_from_graph(self, graph): """ Return all Loop instances that can be extracted from a graph. :param graph: The graph to analyze. :return: A list of all the Loop instances that were found in the graph. """ outtop = [] outall = [] for subg in networkx.strongly_connected_component_subgraphs(graph): if len(subg.nodes()) == 1: if len(list(subg.successors(list(subg.nodes())[0]))) == 0: continue thisloop, allloops = self._parse_loop_graph(subg, graph) if thisloop is not None: outall += allloops outtop.append(thisloop) return outtop, outall from angr.analyses import AnalysesHub AnalysesHub.register_default('LoopFinder', LoopFinder)
self.results = {} try: lib = SIM_LIBRARIES[library] except KeyError: raise AngrValueError("No such library %s" % library) if binary is None: binary = self.project.loader.main_object for func in binary.symbols: if not func.is_function: continue if self.project.is_hooked(func.rebased_addr): l.debug("Skipping %s at %#x, already hooked", func.name, func.rebased_addr) continue if lib.has_implementation(func.name): proc = lib.get(func.name, self.project.arch) self.results[func.rebased_addr] = proc if self.project.is_hooked(func.rebased_addr): l.debug("Skipping %s at %#x, already hooked", func.name, func.rebased_addr) else: self.project.hook(func.rebased_addr, proc) l.info("Hooked %s at %#x", func.name, func.rebased_addr) else: l.debug("Failed to hook %s at %#x", func.name, func.rebased_addr) from angr.analyses import AnalysesHub AnalysesHub.register_default('StaticHooker', StaticHooker)
self.project.hook(addr, SIM_PROCEDURES['stubs']['ReturnUnconstrained'](cc=cc, display_name=name, library_name=libname, is_stub=True)) def analyze(self, addr): seen = set() todo = [addr] while todo: addr = todo.pop(0) seen.add(addr) irsb = self.project.factory.block(addr, opt_level=0).vex if irsb.jumpkind == 'Ijk_Ret': # got it! for stmt in reversed(irsb.statements): if stmt.tag == 'Ist_IMark': l.error("VERY strange return instruction at %#x...", addr) break if stmt.tag == 'Ist_WrTmp': if stmt.data.tag == 'Iex_Binop': if stmt.data.op.startswith('Iop_Add'): return stmt.data.args[1].con.value - self.project.arch.bytes elif irsb.jumpkind == 'Ijk_Call': if addr + irsb.size not in seen: todo.append(addr + irsb.size) else: todo.extend(irsb.constant_jump_targets - seen) return None from angr.analyses import AnalysesHub AnalysesHub.register_default('CalleeCleanupFinder', CalleeCleanupFinder)
self.results = {} try: lib = SIM_LIBRARIES[library] except KeyError: raise AngrValueError("No such library %s" % library) if binary is None: binary = self.project.loader.main_object for func in binary._symbol_cache.values(): if not func.is_function: continue if self.project.is_hooked(func.rebased_addr): l.debug("Skipping %s at %#x, already hooked", func.name, func.rebased_addr) continue if lib.has_implementation(func.name): proc = lib.get(func.name, self.project.arch) self.results[func.rebased_addr] = proc if self.project.is_hooked(func.rebased_addr): l.debug("Skipping %s at %#x, already hooked", func.name, func.rebased_addr) else: self.project.hook(func.rebased_addr, proc) l.info("Hooked %s at %#x", func.name, func.rebased_addr) else: l.debug("Failed to hook %s at %#x", func.name, func.rebased_addr) from angr.analyses import AnalysesHub AnalysesHub.register_default('StaticHooker', StaticHooker)
# This is for testing successors = graph.graph.successors(node) else: # Real CFGNode! successors = graph.get_successors(node) return successors def _pd_post_process(self, cfg): """ Take care of those loop headers/tails where we manually broke their connection to the next BBL """ loop_back_edges = self._cfg.get_loop_back_edges() for b1, b2 in loop_back_edges: # The edge between b1 and b2 is manually broken # The post dominator of b1 should be b2 (or not?) successors = list(self._pd_graph_successors(cfg, b1)) if len(successors) == 0: if b2 in self._post_dom: self._post_dom.add_edge(b1, b2) else: _l.debug("%s is not in post dominator dict.", b2) from angr.analyses import AnalysesHub AnalysesHub.register_default('CDG', CDG)
f = open(filepath, "wb") for src, dst in graph.edges(): f.write("0x%x\tDirectEdge\t0x%x\n" % (src, dst)) f.close() def generate_code_cover(self): """ Generate a list of all recovered basic blocks. """ lst = [] for irsb_addr in self.cfg.nodes(): if irsb_addr not in self._block_size: continue irsb_size = self._block_size[irsb_addr] lst.append((irsb_addr, irsb_size)) lst = sorted(lst, key=lambda x: x[0]) return lst from angr.analyses import AnalysesHub AnalysesHub.register_default('GirlScout', GirlScout) from ..blade import Blade from ..errors import AngrGirlScoutError
live_defs[variable] = {code_loc} l.debug("XX CodeLoc %s kills variable %s", code_loc, variable) def _add_edge(self, s_a, s_b, **edge_labels): """ Add an edge in the graph from `s_a` to statement `s_b`, where `s_a` and `s_b` are tuples of statements of the form (irsb_addr, stmt_idx). """ # Is that edge already in the graph ? # If at least one is new, then we are not redoing the same path again if (s_a, s_b) not in self.graph.edges(): self.graph.add_edge(s_a, s_b, **edge_labels) self._new = True l.info("New edge: %s --> %s", s_a, s_b) def get_all_nodes(self, simrun_addr, stmt_idx): """ Get all DDG nodes matching the given basic block address and statement index. """ nodes = [] for n in self.graph.nodes(): if n.simrun_addr == simrun_addr and n.stmt_idx == stmt_idx: nodes.add(n) return nodes from angr.analyses import AnalysesHub AnalysesHub.register_default('VSA_DDG', VSA_DDG)
- In the near future, this wrapper class will be removed completely, and CFG will be a simple alias to CFGFast. We expect most interfaces are the same between CFGFast and CFGAccurate. Apparently some functionalities (like context-sensitivity, and state keeping) only exist in CFGAccurate, which is when you want to use CFGAccurate instead. """ def __init__(self, **kwargs): outdated_exception = "CFG is now an alias to CFGFast." outdated_message = "CFG is now an alias to CFGFast. Please switch to CFGAccurate if you need functionalities " \ "that only exist there. For most cases, your code should be fine by changing \"CFG(...)\" " \ "to \"CFGAccurate(...)\". Sorry for breaking your code with this giant change." cfgaccurate_params = {'context_sensitivity_level', 'avoid_runs', 'enable_function_hints', 'call_depth', 'call_tracing_filter', 'initial_state', 'starts', 'keep_state', 'enable_advanced_backward_slicing', 'enable_symbolic_back_traversal', 'additional_edges', 'no_construct' } # Sanity check to make sure the user only wants to use CFGFast for p in cfgaccurate_params: if kwargs.get(p, None) is not None: sys.stderr.write(outdated_message + "\n") raise OutdatedError(outdated_exception) # Now initializes CFGFast :-) CFGFast.__init__(self, **kwargs) from angr.analyses import AnalysesHub AnalysesHub.register_default('CFG', CFG)