def graph_connect (dbg, buff_addr, size, realloc=False): global count, graph count += 1 eip = dbg.context.Eip allocator = pgraph.node(eip) allocated = pgraph.node(buff_addr) allocator.label = "%08x" % eip allocated.label = "%d" % size allocated.size = size allocator.color = 0xFFAC59 if realloc: allocated.color = 0x46FF46 else: allocated.color = 0x59ACFF graph.add_node(allocator) graph.add_node(allocated) edge = pgraph.edge(allocator.id, allocated.id) edge.label = "%d" % count graph.add_edge(edge)
def graph_connect(dbg, buff_addr, size, realloc=False): global count, graph count += 1 eip = dbg.context.Eip allocator = pgraph.node(eip) allocated = pgraph.node(buff_addr) allocator.label = "%08x" % eip allocated.label = "%d" % size allocated.size = size allocator.color = 0xFFAC59 if realloc: allocated.color = 0x46FF46 else: allocated.color = 0x59ACFF graph.add_node(allocator) graph.add_node(allocated) edge = pgraph.edge(allocator.id, allocated.id) edge.label = "%d" % count graph.add_edge(edge)
def __init_basic_blocks__(self): ''' Enumerate the basic block boundaries for the current function and store them in a graph structure. ''' import copy self.chunks = self.__init_collect_function_chunks__() contained_heads = sum([[ea for ea in Heads(chunk_start, chunk_end)] for (chunk_start, chunk_end) in self.chunks], list()) blocks = [] edges = [] for (chunk_start, chunk_end) in self.chunks: curr_start = chunk_start # enumerate the nodes. for ea in Heads(chunk_start, chunk_end): # ignore data heads. if not isCode(GetFlags(ea)): curr_start = NextNotTail(ea) continue next_ea = NextNotTail(ea) branches_to_next = self._branches_to(next_ea) branches_from = self._branches_from(ea) is_retn = idaapi.is_ret_insn(ea) if is_retn or not isCode(GetFlags(next_ea)): blocks.append((curr_start, ea)) curr_start = next_ea #this will be handled if still not code elif len(branches_from) > 0: blocks.append((curr_start, ea)) curr_start = next_ea for branch in branches_from: if branch not in contained_heads: continue if len(branches_from) == 1: color = 0x0000FF elif branch == next_ea: color = 0xFF0000 else: color = 0x00FF00 edges.append((curr_start, branch, color)) elif len(branches_to_next) > 0: blocks.append((curr_start, ea)) curr_start = next_ea # draw an "implicit" branch. edges.append((ea, next_ea, 0x0000FF)) basicBlocks = [basic_block(bs,be,self.depth, self.analysis, self)\ for (bs,be) in blocks] map(self.add_node, basicBlocks) for (src, dst, color) in edges: edge = pgraph.edge(src, dst) edge.color = color self.add_edge(edge)
def __init_basic_blocks__ (self): ''' Enumerate the basic block boundaries for the current function and store them in a graph structure. ''' import copy self.chunks = self.__init_collect_function_chunks__() contained_heads = sum([[ea for ea in Heads(chunk_start, chunk_end)] for (chunk_start, chunk_end) in self.chunks],list()) blocks = [] edges = [] for (chunk_start, chunk_end) in self.chunks: curr_start = chunk_start # enumerate the nodes. for ea in Heads(chunk_start, chunk_end): # ignore data heads. if not isCode(GetFlags(ea)): curr_start = NextNotTail(ea) continue next_ea = NextNotTail(ea) branches_to_next = self._branches_to(next_ea) branches_from = self._branches_from(ea) is_retn = idaapi.is_ret_insn(ea) if is_retn or not isCode(GetFlags(next_ea)): blocks.append((curr_start,ea)) curr_start = next_ea #this will be handled if still not code elif len(branches_from) > 0: blocks.append((curr_start,ea)) curr_start = next_ea for branch in branches_from: if branch not in contained_heads: continue if len(branches_from) == 1: color = 0x0000FF elif branch == next_ea: color = 0xFF0000 else: color = 0x00FF00 edges.append((curr_start, branch, color)) elif len(branches_to_next)> 0: blocks.append((curr_start,ea)) curr_start = next_ea # draw an "implicit" branch. edges.append((ea, next_ea, 0x0000FF)) basicBlocks = [basic_block(bs,be,self.depth, self.analysis, self)\ for (bs,be) in blocks] map(self.add_node,basicBlocks) for (src, dst, color) in edges: edge = pgraph.edge(src, dst) edge.color = color self.add_edge(edge)
def __init_enumerate_imports__ (self): ''' Enumerate and add nodes / edges for each import within the module. This routine will pass through the entire module structure. ''' for func in self.nodes.values(): for bb in func.nodes.values(): for instruction in bb.instructions.values(): if instruction.refs_api: (address, api) = instruction.refs_api node = function(address, module=self) node.color = 0xB4B4DA self.add_node(node) edge = pgraph.edge(func.ea_start, address) self.add_edge(edge)
def __init_enumerate_imports__(self): ''' Enumerate and add nodes / edges for each import within the module. This routine will pass through the entire module structure. ''' for func in self.nodes.values(): for bb in func.nodes.values(): for instruction in bb.instructions.values(): if instruction.refs_api: (address, api) = instruction.refs_api node = function(address, module=self) node.color = 0xB4B4DA self.add_node(node) edge = pgraph.edge(func.ea_start, address) self.add_edge(edge)
print "[%d] %s" % (len(crashes), synopsis) print "\t", for crash in crashes: if graph: last = crash_node.id for entry in crash.stack_unwind: address = long(entry.split(":")[1], 16) n = graph.find_node("id", address) if not n: n = pgraph.node(address) n.count = 1 n.label = "[%d] %s" % (n.count, entry) graph.add_node(n) else: n.count += 1 n.label = "[%d] %s" % (n.count, entry) edge = pgraph.edge(n.id, last) graph.add_edge(edge) last = n.id print "%s," % crash.extra, print "\n" if graph: fh = open("%s.udg" % graph_name, "w+") fh.write(graph.render_graph_udraw()) fh.close()
def __init__ (self, name="", signature=None, depth=DEPTH_FULL, analysis=ANALYSIS_NONE): ''' Analysis of an IDA database requires the instantiation of this class and will handle, depending on the requested depth, the analysis of all functions, basic blocks, instructions and more specifically which analysis techniques to apply. For the full list of ananylsis options see defines.py. Specifying ANALYSIS_IMPORTS will require an extra one-time scan through the entire structure to propogate functions (nodes) and cross references (edges) for each reference API call. Specifying ANALYSIS_RPC will require an extra one-time scan through the entire IDA database and will propogate additional function level attributes. The signature attribute was added for use in the PaiMei process stalker module, for ensuring that a loaded DLL is equivalent to the PIDA file with matching name. Setting breakpoints in a non-matching module is obviously no good. @see: defines.py @type name: String @param name: (Optional) Module name @type signature: String @param signature: (Optional) Unique file signature to associate with module @type depth: Integer @param depth: (Optional, Def=DEPTH_FULL) How deep to analyze the module @type analysis: Integer @param analysis: (Optional, Def=ANALYSIS_NONE) Which extra analysis options to enable ''' # run the parent classes initialization routine first. super(module, self).__init__(name) self.name = name self.base = MinEA() - 0x1000 # XXX - cheap hack self.depth = depth self.analysis = analysis self.signature = signature self.ext = {} self.log = True # convenience alias. self.functions = self.nodes # enumerate and add the functions within the module. if self.log: print "Analyzing functions..." for ea in Functions(MinEA(), MaxEA()): func = function(ea, self.depth, self.analysis, self) func.shape = "ellipse" self.add_node(func) # enumerate and add nodes for each import within the module. if self.depth & DEPTH_INSTRUCTIONS and self.analysis & ANALYSIS_IMPORTS: if self.log: print"Enumerating imports..." self.__init_enumerate_imports__() # enumerate and propogate attributes for any discovered RPC interfaces. if self.analysis & ANALYSIS_RPC: if self.log: print "Enumerating RPC interfaces..." self.__init_enumerate_rpc__() # enumerate and add the intramodular cross references. if self.log: print "Enumerating intramodular cross references..." for func in self.nodes.values(): xrefs = list(CodeRefsTo(func.ea_start, 0)) xrefs.extend(list(DataRefsTo(func.ea_start))) for ref in xrefs: from_func = get_func(ref) if from_func: # GHETTO - add the actual source EA to the function. if not self.nodes[from_func.startEA].outbound_eas.has_key(ref): self.nodes[from_func.startEA].outbound_eas[ref] = [] self.nodes[from_func.startEA].outbound_eas[ref].append(func.ea_start) edge = pgraph.edge(from_func.startEA, func.ea_start) self.add_edge(edge)
def __init__(self, name="", signature=None, depth=DEPTH_FULL, analysis=ANALYSIS_NONE): ''' Analysis of an IDA database requires the instantiation of this class and will handle, depending on the requested depth, the analysis of all functions, basic blocks, instructions and more specifically which analysis techniques to apply. For the full list of ananylsis options see defines.py. Specifying ANALYSIS_IMPORTS will require an extra one-time scan through the entire structure to propogate functions (nodes) and cross references (edges) for each reference API call. Specifying ANALYSIS_RPC will require an extra one-time scan through the entire IDA database and will propogate additional function level attributes. The signature attribute was added for use in the PaiMei process stalker module, for ensuring that a loaded DLL is equivalent to the PIDA file with matching name. Setting breakpoints in a non-matching module is obviously no good. @see: defines.py @type name: String @param name: (Optional) Module name @type signature: String @param signature: (Optional) Unique file signature to associate with module @type depth: Integer @param depth: (Optional, Def=DEPTH_FULL) How deep to analyze the module @type analysis: Integer @param analysis: (Optional, Def=ANALYSIS_NONE) Which extra analysis options to enable ''' # run the parent classes initialization routine first. super(module, self).__init__(name) self.name = name self.base = MinEA() - 0x1000 # XXX - cheap hack self.depth = depth self.analysis = analysis self.signature = signature self.ext = {} self.log = True # convenience alias. self.functions = self.nodes # enumerate and add the functions within the module. if self.log: print "Analyzing functions..." for ea in Functions(MinEA(), MaxEA()): func = function(ea, self.depth, self.analysis, self) func.shape = "ellipse" self.add_node(func) # enumerate and add nodes for each import within the module. if self.depth & DEPTH_INSTRUCTIONS and self.analysis & ANALYSIS_IMPORTS: if self.log: print "Enumerating imports..." self.__init_enumerate_imports__() # enumerate and propogate attributes for any discovered RPC interfaces. if self.analysis & ANALYSIS_RPC: if self.log: print "Enumerating RPC interfaces..." self.__init_enumerate_rpc__() # enumerate and add the intramodular cross references. if self.log: print "Enumerating intramodular cross references..." for func in self.nodes.values(): xrefs = list(CodeRefsTo(func.ea_start, 0)) xrefs.extend(list(DataRefsTo(func.ea_start))) for ref in xrefs: from_func = get_func(ref) if from_func: # GHETTO - add the actual source EA to the function. if not self.nodes[from_func.startEA].outbound_eas.has_key( ref): self.nodes[from_func.startEA].outbound_eas[ref] = [] self.nodes[from_func.startEA].outbound_eas[ref].append( func.ea_start) edge = pgraph.edge(from_func.startEA, func.ea_start) self.add_edge(edge)
print "[%d] %s" % (len(crashes), synopsis) print "\t", for crash in crashes: if graph: last = crash_node.id for entry in crash.stack_unwind: address = long(entry.split(":")[1], 16) n = graph.find_node("id", address) if not n: n = pgraph.node(address) n.count = 1 n.label = "[%d] %s" % (n.count, entry) graph.add_node(n) else: n.count += 1 n.label = "[%d] %s" % (n.count, entry) edge = pgraph.edge(n.id, last) graph.add_edge(edge) last = n.id print "%d," % crash.extra, print "\n" if graph: fh = open("%s.udg" % graph_name, "w+") fh.write(graph.render_graph_udraw()) fh.close()