# from binaryninja import * import os import webbrowser import time import sys from pathlib import Path from urllib.request import pathname2url from binaryninja.interaction import get_save_filename_input, show_message_box, TextLineField, ChoiceField, SaveFileNameField, get_form_input from binaryninja.settings import Settings from binaryninja.enums import MessageBoxButtonSet, MessageBoxIcon, MessageBoxButtonResult, InstructionTextTokenType, BranchType, DisassemblyOption, FunctionGraphType from binaryninja.function import DisassemblySettings from binaryninja.plugin import PluginCommand colors = { 'green': [162, 217, 175], 'red': [222, 143, 151], 'blue': [128, 198, 233], 'cyan': [142, 230, 237], 'lightCyan': [176, 221, 228], 'orange': [237, 189, 129], 'yellow': [237, 223, 179], 'magenta': [218, 196, 209], 'none': [74, 74, 74], 'disabled': [144, 144, 144] } escape_table = {"'": "'", ">": ">", "<": "<", '"': """, ' ': " "} def escape(toescape): # handle extended unicode toescape = toescape.encode('ascii', 'xmlcharrefreplace') # still escape the basics return ''.join(escape_table.get(chr(i), chr(i)) for i in toescape) def save_svg(bv, function): sym = bv.get_symbol_at(function.start) if sym: offset = sym.name else: offset = "%x" % function.start path = Path(os.path.dirname(bv.file.filename)) origname = os.path.basename(bv.file.filename) filename = path / f'binaryninja-{origname}-{offset}.html' functionChoice = TextLineField("Blank to accept default") # TODO: implement linear disassembly settings and output modeChoices = ["Graph"] modeChoiceField = ChoiceField("Mode", modeChoices) if Settings().get_bool('ui.debugMode'): formChoices = [ "Assembly", "Lifted IL", "LLIL", "LLIL SSA", "Mapped Medium", "Mapped Medium SSA", "MLIL", "MLIL SSA", "HLIL", "HLIL SSA" ] formChoiceField = ChoiceField("Form", formChoices) else: formChoices = ["Assembly", "LLIL", "MLIL", "HLIL"] formChoiceField = ChoiceField("Form", formChoices) showOpcodes = ChoiceField("Show Opcodes", ["Yes", "No"]) showAddresses = ChoiceField("Show Addresses", ["Yes", "No"]) saveFileChoices = SaveFileNameField("Output file", 'HTML files (*.html)', str(filename)) if not get_form_input([ f'Current Function: {offset}', functionChoice, formChoiceField, modeChoiceField, showOpcodes, showAddresses, saveFileChoices ], "SVG Export") or saveFileChoices.result is None: return if saveFileChoices.result == '': outputfile = filename else: outputfile = saveFileChoices.result content = render_svg( function, offset, modeChoices[modeChoiceField.result], formChoices[formChoiceField.result], showOpcodes.result == 0, showAddresses.result == 0, origname ) output = open(outputfile, 'w') output.write(content) output.close() result = show_message_box( "Open SVG", "Would you like to view the exported SVG?", buttons=MessageBoxButtonSet.YesNoButtonSet, icon=MessageBoxIcon.QuestionIcon ) if result == MessageBoxButtonResult.YesButton: # might need more testing, latest py3 on windows seems.... broken with these APIs relative to other platforms if sys.platform == 'win32': webbrowser.open(outputfile) else: webbrowser.open('file://' + str(outputfile)) def instruction_data_flow(function, address): # TODO: Extract data flow information length = function.view.get_instruction_length(address) func_bytes = function.view.read(address, length) hex = func_bytes.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, offset, mode, form, showOpcodes, showAddresses, origname): settings = DisassemblySettings() if showOpcodes: settings.set_option(DisassemblyOption.ShowOpcode, True) if showAddresses: settings.set_option(DisassemblyOption.ShowAddress, True) if form == "LLIL": graph_type = FunctionGraphType.LowLevelILFunctionGraph elif form == "LLIL SSA": graph_type = FunctionGraphType.LowLevelILSSAFormFunctionGraph elif form == "Lifted IL": graph_type = FunctionGraphType.LiftedILFunctionGraph elif form == "Mapped Medium": graph_type = FunctionGraphType.MappedMediumLevelILFunctionGraph elif form == "Mapped Medium SSA": graph_type = FunctionGraphType.MappedMediumLevelILSSAFormFunctionGraph elif form == "MLIL": graph_type = FunctionGraphType.MediumLevelILFunctionGraph elif form == "MLIL SSA": graph_type = FunctionGraphType.MediumLevelILSSAFormFunctionGraph elif form == "HLIL": graph_type = FunctionGraphType.HighLevelILFunctionGraph elif form == "HLIL SSA": graph_type = FunctionGraphType.HighLevelILSSAFormFunctionGraph else: graph_type = FunctionGraphType.NormalFunctionGraph graph = function.create_graph(graph_type=graph_type, settings=settings) graph.layout_and_wait() heightconst = 15 ratio = 0.48 widthconst = heightconst * ratio output = '''
''' output += '''' output += 'This CFG generated by Binary Ninja from {filename} on {timestring} showing {function} as {form}.
'.format( filename=origname, timestring=time.strftime("%c"), function=offset, form=form ) output += '' return output PluginCommand.register_for_function("Export to SVG", "Exports an SVG of the current function", save_svg)