def __repr__(self): if self.type == BranchType.UnresolvedBranch: return "<%s>" % BranchType(self.type).name elif self.target.arch: return "<%s: %s@%#x>" % (BranchType(self.type).name, self.target.arch.name, self.target.start) else: return "<%s: %#x>" % (BranchType(self.type).name, self.target.start)
def __init__(self, branch_type, source, target, points, back_edge, style): self.type = BranchType(branch_type) self.source = source self.target = target self.points = points self.back_edge = back_edge self.style = style
def incoming_edges(self): """List of basic block incoming edges (read-only)""" count = ctypes.c_ulonglong(0) edges = core.BNGetBasicBlockIncomingEdges(self.handle, count) result = [] for i in range(0, count.value): branch_type = BranchType(edges[i].type) if edges[i].target: target = self._create_instance(self.view, core.BNNewBasicBlockReference(edges[i].target)) else: target = None result.append(BasicBlockEdge(branch_type, target, self, edges[i].backEdge)) core.BNFreeBasicBlockEdgeList(edges, count.value) return result
def incoming_edges(self): """Flow graph block list of incoming edges (read-only)""" count = ctypes.c_ulonglong() edges = core.BNGetFlowGraphNodeIncomingEdges(self.handle, count) result = [] for i in range(0, count.value): branch_type = BranchType(edges[i].type) target = edges[i].target if target: target = FlowGraphNode(self._graph, core.BNNewFlowGraphNodeReference(target)) points = [] for j in range(0, edges[i].pointCount): points.append((edges[i].points[j].x, edges[i].points[j].y)) result.append(FlowGraphEdge(branch_type, self, target, points, edges[i].backEdge)) core.BNFreeFlowGraphNodeEdgeList(edges, count.value) return result
def render_svg(function, origname): graph = function.create_graph() graph.layout_and_wait() heightconst = 15 ratio = 0.48 widthconst = heightconst * ratio output = '''<html> <head> <style type="text/css"> @import url(https://fonts.googleapis.com/css?family=Source+Code+Pro); body { background-color: rgb(42, 42, 42); color: rgb(220, 220, 220); font-family: "Source Code Pro", "Lucida Console", "Consolas", monospace; } a, a:visited { color: rgb(200, 200, 200); font-weight: bold; } svg { background-color: rgb(42, 42, 42); display: block; margin: 0 auto; } .basicblock { stroke: rgb(224, 224, 224); } .edge { fill: none; stroke-width: 1px; } .back_edge { fill: none; stroke-width: 2px; } .UnconditionalBranch, .IndirectBranch { stroke: rgb(128, 198, 233); color: rgb(128, 198, 233); } .FalseBranch { stroke: rgb(222, 143, 151); color: rgb(222, 143, 151); } .TrueBranch { stroke: rgb(162, 217, 175); color: rgb(162, 217, 175); } .arrow { stroke-width: 1; fill: currentColor; } text { font-family: "Source Code Pro", "Lucida Console", "Consolas", monospace; font-size: 9pt; fill: rgb(224, 224, 224); } .CodeSymbolToken { fill: rgb(128, 198, 223); } .DataSymbolToken { fill: rgb(142, 230, 237); } .TextToken, .InstructionToken, .BeginMemoryOperandToken, .EndMemoryOperandToken { fill: rgb(224, 224, 224); } .PossibleAddressToken, .IntegerToken { fill: rgb(162, 217, 175); } .RegisterToken { fill: rgb(237, 223, 179); } .AnnotationToken { fill: rgb(218, 196, 209); } .ImportToken { fill: rgb(237, 189, 129); } .StackVariableToken { fill: rgb(193, 220, 199); } </style> <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.2/jquery.min.js"></script> </head> ''' output += '''<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="{width}" height="{height}"> <defs> <marker id="arrow-TrueBranch" class="arrow TrueBranch" viewBox="0 0 10 10" refX="10" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"> <path d="M 0 0 L 10 5 L 0 10 z" /> </marker> <marker id="arrow-FalseBranch" class="arrow FalseBranch" viewBox="0 0 10 10" refX="10" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"> <path d="M 0 0 L 10 5 L 0 10 z" /> </marker> <marker id="arrow-UnconditionalBranch" class="arrow UnconditionalBranch" viewBox="0 0 10 10" refX="10" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"> <path d="M 0 0 L 10 5 L 0 10 z" /> </marker> <marker id="arrow-IndirectBranch" class="arrow IndirectBranch" viewBox="0 0 10 10" refX="10" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"> <path d="M 0 0 L 10 5 L 0 10 z" /> </marker> </defs> '''.format(width=graph.width * widthconst + 20, height=graph.height * heightconst + 20) output += ''' <g id="functiongraph0" class="functiongraph"> <title>Function Graph 0</title> ''' edges = '' for i, block in enumerate(graph.blocks): # Calculate basic block location and coordinates x = ((block.x) * widthconst) y = ((block.y) * heightconst) width = ((block.width) * widthconst) height = ((block.height) * heightconst) # Render block output += ' <g id="basicblock{i}">\n'.format(i=i) output += ' <title>Basic Block {i}</title>\n'.format(i=i) rgb = colors['none'] try: bb = block.basic_block color_code = bb.highlight.color color_str = bb.highlight._standard_color_to_str(color_code) if color_str in colors: rgb = colors[color_str] except: pass output += ' <rect class="basicblock" x="{x}" y="{y}" fill-opacity="0.4" height="{height}" width="{width}" fill="rgb({r},{g},{b})"/>\n'.format( x=x, y=y, width=width + 16, height=height + 12, r=rgb[0], g=rgb[1], b=rgb[2]) # Render instructions, unfortunately tspans don't allow copying/pasting more # than one line at a time, need SVG 1.2 textarea tags for that it looks like output += ' <text x="{x}" y="{y}">\n'.format(x=x, y=y + (i + 1) * heightconst) for i, line in enumerate(block.lines): output += ' <tspan id="instr-{address}" x="{x}" y="{y}">'.format( x=x + 6, y=y + 6 + (i + 0.7) * heightconst, address=hex(line.address)[:-1]) hover = instruction_data_flow(function, line.address) output += '<title>{hover}</title>'.format(hover=hover) for token in line.tokens: # TODO: add hover for hex, function, and reg tokens output += '<tspan class="{tokentype}">{text}</tspan>'.format( text=escape(token.text), tokentype=InstructionTextTokenType(token.type).name) output += '</tspan>\n' output += ' </text>\n' output += ' </g>\n' # Edges are rendered in a seperate chunk so they have priority over the # basic blocks or else they'd render below them for edge in block.outgoing_edges: points = "" x, y = edge.points[0] points += str( x * widthconst) + "," + str(y * heightconst + 12) + " " for x, y in edge.points[1:-1]: points += str(x * widthconst) + "," + str( y * heightconst) + " " x, y = edge.points[-1] points += str( x * widthconst) + "," + str(y * heightconst + 0) + " " if edge.back_edge: edges += ' <polyline class="back_edge {type}" points="{points}" marker-end="url(#arrow-{type})"/>\n'.format( type=BranchType(edge.type).name, points=points) else: edges += ' <polyline class="edge {type}" points="{points}" marker-end="url(#arrow-{type})"/>\n'.format( type=BranchType(edge.type).name, points=points) output += ' ' + edges + '\n' output += ' </g>\n' output += '</svg>' output += '<p>This CFG generated by <a href="https://binary.ninja/">Binary Ninja</a> from {filename} on {timestring}.</p>'.format( filename=origname, timestring=time.strftime("%c")) output += '</html>' return output