from binaryninja import * import os,sys escape_table = { "'": "'", ">": ">", "<": "<", '"': """, ' ': " " } def escape(string): string=string.decode('utf-8').encode('ascii','xmlcharrefreplace') #handle extended unicode return ''.join(escape_table.get(i,i) for i in string) #still escape the basics def save_svg(bv,function): filename = os.path.basename(bv.file.filename) address = hex(function.start).replace('L','') outputfile = os.path.join(os.path.expanduser('~'), 'binaryninja-{filename}-{function}.html'.format(filename=filename,function=address)) 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() graph.layout_and_wait() heightconst = 15 ratio = 0.48 widthconst = heightconst*ratio output = ''' ''' 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 = ((block.x) * widthconst) y = ((block.y) * heightconst) width = ((block.width) * widthconst) height = ((block.height) * heightconst) #Render block output += ' \n'.format(i=i) output += ' Basic Block {i}\n'.format(i=i) output += ' \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 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]) hover = instruction_data_flow(function, line.address) output += '{hover}'.format(hover=hover) for token in line.tokens: # TODO: add hover for hex, function, and reg tokens output+='{text}'.format(text=escape(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 of the current function to your home folder.", save_svg)