from binaryninja import * import os 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 def render_svg(function): graph = function.create_graph() graph.layout_and_wait() heightconst = 15 ratio = 0.54 widthconst = int(heightconst*ratio) output = ''' '''.format(width=graph.width*widthconst, height=graph.height*heightconst) output += ''' Function Graph 0 ''' edges = '' for i,block in enumerate(graph.blocks): #Calculate basic block location and coordinates x = int((block.x) * widthconst) y = int((block.y) * heightconst) width = int((block.width) * widthconst) height = int((block.height) * heightconst) #Render block output += ' \n' output += ' Basic Block {i}\n' output += ' \n'.format(i=i,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 output += ' \n'.format(x=x,y=y + (i + 1) * heightconst) for i,line in enumerate(block.lines): output += ' '.format(x=x,y=y + (i + 0.7) * heightconst,address=hex(line.address)[:-1]) for token in line.tokens: output+='{text}'.format(text=token.text,tokentype=token.type) output += ' \n' output += ' \n' output += ' \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 = "" for x,y in edge.points: points += str(x*widthconst)+","+str(y*heightconst) + " " edges += ' \n'.format(type=edge.type,points=points) output += ' ' + edges + '\n' output += ' \n' output += '' return output PluginCommand.register_for_function("Export to SVG", "Exports an SVG to your home folder for the given function", save_svg)