diff options
Diffstat (limited to 'python')
| -rwxr-xr-x | python/examples/export-svg.py | 108 |
1 files changed, 78 insertions, 30 deletions
diff --git a/python/examples/export-svg.py b/python/examples/export-svg.py index e00b651f..ad3a3dd7 100755 --- a/python/examples/export-svg.py +++ b/python/examples/export-svg.py @@ -1,16 +1,34 @@ from binaryninja import * -import os +import os,sys + +escape_table = { + "&": "&", + "'": "'", + ">": ">", + "<": "<", + '"': """, + ' ': " ", +} + +def escape(string): + return ''.join(escape_table.get(i,i) for i in string) def save_svg(bv,function): filename = bv.file.filename.split(os.sep)[-1] - outputfile = os.environ['HOME'] + os.sep + 'binaryninja-{filename}-{function}.svg'.format(filename=filename,function=function.symbol.name) - try: - output = open(outputfile,'w') - output.write(render_svg(function)) - output.close() - except: - print "Unexpected error:", sys.exc_info()[0] - raise + outputfile = os.path.join(os.path.expanduser('~'), 'binaryninja-{filename}-{function}.html'.format(filename=filename,function=function.symbol.name)) + content = render_svg(function) + output = open(outputfile,'w') + output.write(content) + output.close() + #os.system('open %s' % outputfile) + +def instruction_data_flow(function,address): + ''' TODO: Extract data flow information ''' + length = function.view.get_instruction_length(function.arch,address) + bytes = function.view.read(address, length) + hex = bytes.encode('hex') + padded = ' '.join([hex[i:i+2] for i in range(0, len(hex), 2)]) + return 'Opcode: {bytes}'.format(bytes=padded) def render_svg(function): graph = function.create_graph() @@ -19,44 +37,71 @@ def render_svg(function): ratio = 0.54 widthconst = int(heightconst*ratio) - output = '''<?xml version="1.0" standalone="no"?> - <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> - <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="{width}" height="{height}" viewBox="0 0 {width} {height}"> + output = '''<html><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="{width}" height="{height}"> <defs> <style type="text/css"><![CDATA[ @import url(https://fonts.googleapis.com/css?family=Source+Code+Pro); + svg {{ + background-color: rgb(42, 42, 42); + }} + .basicblock {{ + fill: rgb(74, 74, 74); + stroke: rgb(224, 224, 224); + }} .edge {{ fill: none; - stroke-width: 3 + stroke-width: 2px; }} .UnconditionalBranch {{ - stroke: blue; - color: blue; + stroke: rgb(128, 198, 233); + color: rgb(128, 198, 233); }} .FalseBranch {{ - stroke: red; - color: red; + stroke: rgb(222, 143, 151); + color: rgb(222, 143, 151); }} .TrueBranch {{ - stroke: green; - color: green; + stroke: rgb(162, 217, 175); + color: rgb(162, 217, 175); }} .arrow {{ - stroke-width: 3; + stroke-width: 1; fill: currentColor; }} text {{ font-family: 'Source Code Pro'; font-size: 9pt; + fill: rgb(224, 224, 224); + }} + .CodeSymbolToken {{ + fill: rgb(128, 198, 223); + }} + .TextToken {{ + fill: rgb(224, 224, 224); + }} + .PossibleAddressToken {{ + fill: rgb(162, 217, 175); + }} + .RegisterToken {{ + fill: rgb(237, 223, 179); + }} + .InstructionToken {{ + fill: rgb(224, 224, 224); + }} + .AnnotationToken {{ + fill: rgb(218, 196, 209); + }} + .ImportToken {{ + fill: rgb(237, 189, 129); }} ]]></style> - <marker id="arrow-TrueBranch" class="arrow TrueBranch" viewBox="0 0 10 10" refX="11" refY="5" markerUnits="strokeWidth" markerWidth="4" markerHeight="3" orient="auto"> + <marker id="arrow-TrueBranch" class="arrow TrueBranch" viewBox="0 0 10 10" refX="10" refY="5" markerUnits="strokeWidth" markerWidth="4" markerHeight="3" 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="11" refY="5" markerUnits="strokeWidth" markerWidth="4" markerHeight="3" orient="auto"> + <marker id="arrow-FalseBranch" class="arrow FalseBranch" viewBox="0 0 10 10" refX="10" refY="5" markerUnits="strokeWidth" markerWidth="4" markerHeight="3" 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="11" refY="5" markerUnits="strokeWidth" markerWidth="4" markerHeight="3" orient="auto"> + <marker id="arrow-UnconditionalBranch" class="arrow UnconditionalBranch" viewBox="0 0 10 10" refX="10" refY="5" markerUnits="strokeWidth" markerWidth="4" markerHeight="3" orient="auto"> <path d="M 0 0 L 10 5 L 0 10 z" /> </marker> </defs> @@ -74,9 +119,9 @@ def render_svg(function): height = int((block.height) * heightconst) #Render block - output += ' <g id="basicblock{i}" class="basicblock">\n' - output += ' <title>Basic Block {i}</title>\n' - output += ' <rect style="fill:grey;stroke:black;" x="{x}" y="{y}" height="{height}" width="{width}"/>\n'.format(i=i,x=x,y=y,width=width,height=height) + output += ' <g id="basicblock{i}">\n'.format(i=i) + output += ' <title>Basic Block {i}</title>\n'.format(i=i) + output += ' <rect class="basicblock" x="{x}" y="{y}" height="{height}" width="{width}"/>\n'.format(x=x,y=y,width=width,height=height) #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 @@ -84,9 +129,12 @@ def render_svg(function): 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="{address}" x="{x}" y="{y}">'.format(x=x,y=y + (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: - output+='<tspan class="{tokentype}">{text}</tspan>'.format(text=token.text,tokentype=token.type) - output += ' </tspan>\n' + # TODO: add hover for hex, function, and reg tokens + output+='<tspan class="{tokentype}">{text}</tspan>'.format(text=escape(token.text),tokentype=token.type) + output += '</tspan>\n' output += ' </text>\n' output += ' </g>\n' @@ -100,7 +148,7 @@ def render_svg(function): edges += ' <polyline class="edge {type}" points="{points}" marker-end="url(#arrow-{type})"/>\n'.format(type=edge.type,points=points) output += ' ' + edges + '\n' output += ' </g>\n' - output += '</svg>' + output += '</svg></html>' return output -PluginCommand.register_for_function("Export to SVG", "Exports an SVG to your home folder for the given function", save_svg) +PluginCommand.register_for_function("Export to SVG", "Exports an SVG of the current function to your home folder.", save_svg) |
