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)