From 6812c973c9fa9b4ad642ab81856c05f87bd6fcc4 Mon Sep 17 00:00:00 2001 From: KyleMiles Date: Thu, 27 Jan 2022 22:43:28 -0500 Subject: Format All Files --- python/examples/angr_plugin.py | 27 +- python/examples/arch_hook.py | 17 +- python/examples/asm_to_llil_view.py | 15 +- python/examples/breakpoint.py | 8 +- python/examples/cli_dis.py | 5 +- python/examples/cli_lift.py | 21 +- python/examples/debug_info.py | 157 +++++---- python/examples/export_svg.py | 343 ++++++++++--------- python/examples/helloglobalarea.py | 2 + python/examples/hellopane.py | 7 +- python/examples/hellosidebar.py | 3 + python/examples/instruction_iterator.py | 3 - python/examples/jump_table.py | 6 +- python/examples/linear_mlil.py | 47 ++- python/examples/mappedview.py | 27 +- python/examples/nds.py | 146 ++++---- python/examples/nes.py | 552 +++++++++++++++++------------- python/examples/notification_callbacks.py | 2 + python/examples/nsf.py | 9 +- python/examples/pe_stat.py | 7 +- python/examples/print_syscalls.py | 4 +- python/examples/typelib_create.py | 29 +- python/examples/typelib_dump.py | 197 +++++------ python/examples/ui_notifications.py | 102 +++--- 24 files changed, 944 insertions(+), 792 deletions(-) (limited to 'python/examples') diff --git a/python/examples/angr_plugin.py b/python/examples/angr_plugin.py index 940aff8b..5f2eeba0 100644 --- a/python/examples/angr_plugin.py +++ b/python/examples/angr_plugin.py @@ -18,7 +18,6 @@ # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS # IN THE SOFTWARE. - # This plugin assumes angr is already installed and available on the system. See the angr documentation # for information about installing angr. It should be installed using the virtualenv method. # @@ -72,7 +71,7 @@ class Solver(BackgroundTaskThread): def run(self): # Create an angr project and an explorer with the user's settings p = angr.Project(self.binary.name) - e = p.surveyors.Explorer(find = self.find, avoid = self.avoid) + e = p.surveyors.Explorer(find=self.find, avoid=self.avoid) # Solve loop while not e.done: @@ -98,7 +97,7 @@ class Solver(BackgroundTaskThread): text_report = "Found %d path%s.\n\n" % (len(e.found), "s" if len(e.found) != 1 else "") i = 1 for f in e.found: - text_report += "Path %d\n" % i + "=" * 10 + "\n" + text_report += "Path %d\n"%i + "="*10 + "\n" text_report += "stdin:\n" + escaped_output(f.state.posix.dumps(0)) + "\n\n" text_report += "stdout:\n" + escaped_output(f.state.posix.dumps(1)) + "\n\n" text_report += "stderr:\n" + escaped_output(f.state.posix.dumps(2)) + "\n\n" @@ -115,7 +114,7 @@ def find_instr(bv, addr): # Highlight the instruction in green blocks = bv.get_basic_blocks_at(addr) for block in blocks: - block.set_auto_highlight(HighlightColor(HighlightStandardColor.GreenHighlightColor, alpha = 128)) + block.set_auto_highlight(HighlightColor(HighlightStandardColor.GreenHighlightColor, alpha=128)) block.function.set_auto_instr_highlight(addr, HighlightStandardColor.GreenHighlightColor) # Add the instruction to the list associated with the current view @@ -126,7 +125,7 @@ def avoid_instr(bv, addr): # Highlight the instruction in red blocks = bv.get_basic_blocks_at(addr) for block in blocks: - block.set_auto_highlight(HighlightColor(HighlightStandardColor.RedHighlightColor, alpha = 128)) + block.set_auto_highlight(HighlightColor(HighlightStandardColor.RedHighlightColor, alpha=128)) block.function.set_auto_instr_highlight(addr, HighlightStandardColor.RedHighlightColor) # Add the instruction to the list associated with the current view @@ -135,9 +134,11 @@ def avoid_instr(bv, addr): def solve(bv): if len(bv.session_data.angr_find) == 0: - show_message_box("Angr Solve", "You have not specified a goal instruction.\n\n" + - "Please right click on the goal instruction and select \"Find Path to This Instruction\" to " + - "continue.", MessageBoxButtonSet.OKButtonSet, MessageBoxIcon.ErrorIcon) + show_message_box( + "Angr Solve", "You have not specified a goal instruction.\n\n" + + "Please right click on the goal instruction and select \"Find Path to This Instruction\" to " + "continue.", + MessageBoxButtonSet.OKButtonSet, MessageBoxIcon.ErrorIcon + ) return # Start a solver thread for the path associated with the view @@ -146,8 +147,10 @@ def solve(bv): # Register commands for the user to interact with the plugin -PluginCommand.register_for_address("Find Path to This Instruction", - "When solving, find a path that gets to this instruction", find_instr) -PluginCommand.register_for_address("Avoid This Instruction", - "When solving, avoid paths that reach this instruction", avoid_instr) +PluginCommand.register_for_address( + "Find Path to This Instruction", "When solving, find a path that gets to this instruction", find_instr +) +PluginCommand.register_for_address( + "Avoid This Instruction", "When solving, avoid paths that reach this instruction", avoid_instr +) PluginCommand.register("Solve With Angr", "Attempt to solve for a path that satisfies the constraints given", solve) diff --git a/python/examples/arch_hook.py b/python/examples/arch_hook.py index 452bd2b6..a6e280cc 100644 --- a/python/examples/arch_hook.py +++ b/python/examples/arch_hook.py @@ -1,16 +1,17 @@ from binaryninja.architecture import Architecture, ArchitectureHook + class X86ReturnHook(ArchitectureHook): - def get_instruction_text(self, data, addr): - # Call the original implementation's method by calling the superclass - result, length = super(X86ReturnHook, self).get_instruction_text(data, addr) + def get_instruction_text(self, data, addr): + # Call the original implementation's method by calling the superclass + result, length = super(X86ReturnHook, self).get_instruction_text(data, addr) + + # Patch the name of the 'retn' instruction to 'ret' + if len(result) > 0 and result[0].text == 'retn': + result[0].text = 'ret' - # Patch the name of the 'retn' instruction to 'ret' - if len(result) > 0 and result[0].text == 'retn': - result[0].text = 'ret' + return result, length - return result, length # Install the hook by constructing it with the desired architecture to hook, then registering it X86ReturnHook(Architecture['x86']).register() - diff --git a/python/examples/asm_to_llil_view.py b/python/examples/asm_to_llil_view.py index 18c77547..3b7fb374 100644 --- a/python/examples/asm_to_llil_view.py +++ b/python/examples/asm_to_llil_view.py @@ -1,5 +1,5 @@ # Copyright (c) 2019-2022 Vector 35 Inc -# +# # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to # deal in the Software without restriction, including without limitation the @@ -103,13 +103,18 @@ class DisassemblyAndLowLevelILGraph(FlowGraph): for line in lines: if line.il_instruction is None: # For assembly lines, show address - line.tokens.insert(0, InstructionTextToken(InstructionTextTokenType.AddressDisplayToken, - "%.8x" % line.address, line.address)) + line.tokens.insert( + 0, InstructionTextToken(InstructionTextTokenType.AddressDisplayToken, "%.8x" % line.address, line.address) + ) line.tokens.insert(1, InstructionTextToken(InstructionTextTokenType.TextToken, " ")) else: # For IL lines, show IL instruction index - line.tokens.insert(0, InstructionTextToken(InstructionTextTokenType.AnnotationToken, - "%8s" % ("[%d]" % line.il_instruction.instr_index))) + line.tokens.insert( + 0, + InstructionTextToken( + InstructionTextTokenType.AnnotationToken, "%8s" % ("[%d]" % line.il_instruction.instr_index) + ) + ) line.tokens.insert(1, InstructionTextToken(InstructionTextTokenType.AnnotationToken, " => ")) nodes[block.start].lines = lines diff --git a/python/examples/breakpoint.py b/python/examples/breakpoint.py index ab2ccfa5..20ff2b6b 100644 --- a/python/examples/breakpoint.py +++ b/python/examples/breakpoint.py @@ -18,7 +18,6 @@ # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS # IN THE SOFTWARE. - from binaryninja.plugin import PluginCommand from binaryninja.log import log_error @@ -29,12 +28,7 @@ def write_breakpoint(view, start, length): register_for_address register_for_function """ - bkpt_str = { - "x86": "int3", - "x86_64": "int3", - "armv7": "bkpt", - "aarch64": "brk #0", - "mips32": "break"} + bkpt_str = {"x86": "int3", "x86_64": "int3", "armv7": "bkpt", "aarch64": "brk #0", "mips32": "break"} if view.arch.name not in bkpt_str: log_error("Architecture %s not supported" % view.arch.name) diff --git a/python/examples/cli_dis.py b/python/examples/cli_dis.py index 8f863db3..cbd4b8f1 100755 --- a/python/examples/cli_dis.py +++ b/python/examples/cli_dis.py @@ -55,12 +55,12 @@ archName = sys.argv[1] bytesList = sys.argv[2:] # parse byte arguments -data = b''.join(list(map(lambda x: int(x,16).to_bytes(1,'big'), bytesList))) +data = b''.join(list(map(lambda x: int(x, 16).to_bytes(1, 'big'), bytesList))) # disassemble arch = binaryninja.Architecture[archName] toksAndLen = arch.get_instruction_text(data, 0) -if not toksAndLen or toksAndLen[1]==0: +if not toksAndLen or toksAndLen[1] == 0: print('disassembly failed') sys.exit(-1) @@ -68,4 +68,3 @@ if not toksAndLen or toksAndLen[1]==0: toks = toksAndLen[0] strs = map(lambda x: x.text, toks) print(GREEN, ''.join(strs), NORMAL) - diff --git a/python/examples/cli_lift.py b/python/examples/cli_lift.py index b335a5e4..946f8c3a 100755 --- a/python/examples/cli_lift.py +++ b/python/examples/cli_lift.py @@ -34,16 +34,18 @@ from binaryninja import lowlevelil RED = '\x1B[31m' NORMAL = '\x1B[0m' + def traverse_IL(il, indent): if isinstance(il, lowlevelil.LowLevelILInstruction): print('\t'*indent + il.operation.name) for o in il.operands: - traverse_IL(o, indent+1) + traverse_IL(o, indent + 1) else: print('\t'*indent + str(il)) + if __name__ == '__main__': if not sys.argv[2:]: @@ -63,7 +65,7 @@ if __name__ == '__main__': bytesList = sys.argv[2:] # parse byte arguments - data = b''.join(list(map(lambda x: int(x,16).to_bytes(1,'big'), bytesList))) + data = b''.join(list(map(lambda x: int(x, 16).to_bytes(1, 'big'), bytesList))) plat = binaryninja.Platform[platName] bv = binaryview.BinaryView.new(data) @@ -71,13 +73,13 @@ if __name__ == '__main__': bv.add_function(0, plat=plat) -# print('print all the functions, their basic blocks, and their mc instructions') -# for func in bv.functions: -# print(repr(func)) -# for block in func: -# print("\t{0}".format(block)) -# for insn in block: -# print("\t\t{0}".format(insn)) + # print('print all the functions, their basic blocks, and their mc instructions') + # for func in bv.functions: + # print(repr(func)) + # for block in func: + # print("\t{0}".format(block)) + # for insn in block: + # print("\t\t{0}".format(insn)) print(RED) for func in bv.functions: @@ -87,4 +89,3 @@ if __name__ == '__main__': for insn in block: traverse_IL(insn, 0) print(NORMAL) - diff --git a/python/examples/debug_info.py b/python/examples/debug_info.py index 8f379544..28175ba1 100755 --- a/python/examples/debug_info.py +++ b/python/examples/debug_info.py @@ -29,7 +29,6 @@ # bv.apply_debug_info(debug_info) # ``` - # The rest of this file serves as a test and example of implementing debug info parsers, and the resultant debug info. # # All that is required is to provide functions similar to "is_valid" and "parse_info" below, and call @@ -98,50 +97,56 @@ # } # ``` - import binaryninja as bn import os - filename = os.path.join(os.path.dirname(os.path.abspath(__file__)), "test_debug_info") - # Some setup code not just for informative printing - print = print if __name__ != "__main__": - print = bn.log_error + print = bn.log_error -def pretty_print_add_data_variable(debug_info: bn.debuginfo.DebugInfo, address: int, t: bn.types.Type, name: str = None) -> None: - print(f" Adding data variable of type `{t}` at {hex(address)} : {debug_info.add_data_variable(address, t, name)}") +def pretty_print_add_data_variable( + debug_info: bn.debuginfo.DebugInfo, address: int, t: bn.types.Type, name: str = None +) -> None: + print(f" Adding data variable of type `{t}` at {hex(address)} : {debug_info.add_data_variable(address, t, name)}") -def pretty_print_add_function(debug_info: bn.debuginfo.DebugInfo, address: int, short_name: str = None, full_name: str = None, raw_name: str = None, return_type = None, parameters = None) -> None: - function_info = bn.debuginfo.DebugFunctionInfo(address, short_name, full_name, raw_name, return_type, parameters) - if parameters is not None: - print(f" Adding function `{return_type} {short_name}({', '.join(f'{t} {name}' for name, t in parameters)})` at {hex(address)} : {debug_info.add_function(function_info)}") - else: - print(f" Adding function `{return_type} {short_name}()` at {hex(address)} : {debug_info.add_function(function_info)}") +def pretty_print_add_function( + debug_info: bn.debuginfo.DebugInfo, address: int, short_name: str = None, full_name: str = None, raw_name: str = None, + return_type=None, parameters=None +) -> None: + function_info = bn.debuginfo.DebugFunctionInfo(address, short_name, full_name, raw_name, return_type, parameters) + if parameters is not None: + print( + f" Adding function `{return_type} {short_name}({', '.join(f'{t} {name}' for name, t in parameters)})` at {hex(address)} : {debug_info.add_function(function_info)}" + ) + else: + print( + f" Adding function `{return_type} {short_name}()` at {hex(address)} : {debug_info.add_function(function_info)}" + ) # The beginning of the actual debug info plugin def is_valid(bv: bn.binaryview.BinaryView): - sym = bv.get_symbol_by_raw_name("__elf_interp") - if sym is None: - return False - else: - var = bv.get_data_var_at(sym.address) - return b"test_debug_info_parsing" == bv.read(sym.address, var.type.width-1) + sym = bv.get_symbol_by_raw_name("__elf_interp") + if sym is None: + return False + else: + var = bv.get_data_var_at(sym.address) + return b"test_debug_info_parsing" == bv.read(sym.address, var.type.width - 1) def parse_info(debug_info: bn.debuginfo.DebugInfo, bv: bn.binaryview.BinaryView): - print("Adding types") - types = [] - for name, t in bv.parse_types_from_string(""" + print("Adding types") + types = [] + for name, t in bv.parse_types_from_string( + """ struct test_type_1 { int a; char b[4]; @@ -153,62 +158,81 @@ def parse_info(debug_info: bn.debuginfo.DebugInfo, bv: bn.binaryview.BinaryView) struct test_type_1 a; struct test_type_1* b; struct test_type_2* c; - };""").types.items(): - print(f" Adding type \"{name}\" `{t}` : {debug_info.add_type(str(name), t)}") - types.append(t) - - print("Adding data variables") - pretty_print_add_data_variable(debug_info, 0x4030, types[0], "test_var_1") - pretty_print_add_data_variable(debug_info, 0x4010, bn.types.Type.int(4, True), "test_var_2") - # Names are optional - pretty_print_add_data_variable(debug_info, 0x4014, bn.types.Type.int(4, True)) - - t = bn.types.Type.int(4, True) - t.const = True - pretty_print_add_data_variable(debug_info, 0x2004, t, "test_var_3") - - print("Adding functions") - char_star = bv.parse_type_string("char*")[0] - pretty_print_add_function(debug_info, 0x1129, "no_return_type_no_parameters", None, None, bn.types.Type.void(), None) - pretty_print_add_function(debug_info, 0x1134, "used_parameter", None, None, bn.types.Type.bool(), [("value", bn.types.Type.bool())]) - pretty_print_add_function(debug_info, 0x1155, "unused_parameters", None, None, bn.types.Type.int(4, True), [("value_1", bn.types.Type.bool()), ("value_2", bn.types.Type.int(4, True)), ("value_3", char_star)]) - pretty_print_add_function(debug_info, 0x1170, "used_and_unused_parameters_1", None, None, bn.types.Type.int(4, True), [("value_1", bn.types.Type.int(4, True)), ("value_2", bn.types.Type.int(4, True)), ("value_3", char_star), ("value_4", bn.types.Type.bool())]) - pretty_print_add_function(debug_info, 0x1191, "used_and_unused_parameters_2", None, None, bn.types.Type.int(1, False), [("value_1", bn.types.Type.bool()), ("value_2", bn.types.Type.int(1, False)), ("value_3", char_star), ("value_4", bn.types.Type.int(1, False)), ("value_5", bn.types.Type.char())]) - pretty_print_add_function(debug_info, 0x11c0, "local_parameters", None, None, bn.types.Type.void(), [("value_1", bn.types.Type.bool()), ("value_2", bn.types.Type.int(1, False)), ("value_3", char_star), ("value_4", bn.types.Type.int(1, False)), ("value_5", bn.types.Type.char())]) + };""" + ).types.items(): + print(f" Adding type \"{name}\" `{t}` : {debug_info.add_type(str(name), t)}") + types.append(t) + + print("Adding data variables") + pretty_print_add_data_variable(debug_info, 0x4030, types[0], "test_var_1") + pretty_print_add_data_variable(debug_info, 0x4010, bn.types.Type.int(4, True), "test_var_2") + # Names are optional + pretty_print_add_data_variable(debug_info, 0x4014, bn.types.Type.int(4, True)) + + t = bn.types.Type.int(4, True) + t.const = True + pretty_print_add_data_variable(debug_info, 0x2004, t, "test_var_3") + + print("Adding functions") + char_star = bv.parse_type_string("char*")[0] + pretty_print_add_function(debug_info, 0x1129, "no_return_type_no_parameters", None, None, bn.types.Type.void(), None) + pretty_print_add_function( + debug_info, 0x1134, "used_parameter", None, None, bn.types.Type.bool(), [("value", bn.types.Type.bool())] + ) + pretty_print_add_function( + debug_info, 0x1155, "unused_parameters", None, None, bn.types.Type.int(4, True), + [("value_1", bn.types.Type.bool()), ("value_2", bn.types.Type.int(4, True)), ("value_3", char_star)] + ) + pretty_print_add_function( + debug_info, 0x1170, "used_and_unused_parameters_1", None, None, bn.types.Type.int(4, True), + [("value_1", bn.types.Type.int(4, True)), ("value_2", bn.types.Type.int(4, True)), ("value_3", char_star), + ("value_4", bn.types.Type.bool())] + ) + pretty_print_add_function( + debug_info, 0x1191, "used_and_unused_parameters_2", None, None, bn.types.Type.int(1, False), + [("value_1", bn.types.Type.bool()), ("value_2", bn.types.Type.int(1, False)), ("value_3", char_star), + ("value_4", bn.types.Type.int(1, False)), ("value_5", bn.types.Type.char())] + ) + pretty_print_add_function( + debug_info, 0x11c0, "local_parameters", None, None, bn.types.Type.void(), [("value_1", bn.types.Type.bool()), + ("value_2", bn.types.Type.int(1, False)), + ("value_3", char_star), + ("value_4", bn.types.Type.int(1, False)), + ("value_5", bn.types.Type.char())] + ) parser = bn.debuginfo.DebugInfoParser.register("test debug info parser", is_valid, parse_info) print(f"Registered parser: {parser.name}") - # The above is all that is needed for a DebugInfo plugin # The below serves to test the correctness of (the Python bindings' implementation of) debug info parsers' functionality. - bn.debuginfo.DebugInfoParser.register("dummy extra debug parser 1", lambda bv: False, lambda di, bv: None) -bn.debuginfo.DebugInfoParser.register("dummy extra debug parser 2", lambda bv: bv.view_type != "Raw", lambda di, bv: None) +bn.debuginfo.DebugInfoParser.register( + "dummy extra debug parser 2", lambda bv: bv.view_type != "Raw", lambda di, bv: None +) # Test fetching parser list and fetching by name print(f"Availible parsers: {len(list(bn.debuginfo.DebugInfoParser))}") for p in bn.debuginfo.DebugInfoParser: - if p == parser: - print(f" {bn.debuginfo.DebugInfoParser[p.name].name} (the one we just registered)") - else: - print(f" {bn.debuginfo.DebugInfoParser[p.name].name}") + if p == parser: + print(f" {bn.debuginfo.DebugInfoParser[p.name].name} (the one we just registered)") + else: + print(f" {bn.debuginfo.DebugInfoParser[p.name].name}") # Test calling our `is_valid` callback bv = bn.open_view(filename, options={"analysis.experimental.parseDebugInfo": False}) if parser.is_valid_for_view(bv): - print("Parser is valid") + print("Parser is valid") else: - print("Parser is NOT valid!") - quit() - + print("Parser is NOT valid!") + quit() # Test getting list of valid parsers, and DebugInfoParser's repr print("") for p in bn.debuginfo.DebugInfoParser.get_parsers_for_view(bv): - print(f"`{p.name}` is valid for `{bv}`") + print(f"`{p.name}` is valid for `{bv}`") print("") # Test calling our `parse_info` callback @@ -219,32 +243,31 @@ print("\nEach of the following pairs of prints should be the same\n") print("All types:") for name, t in debug_info.types: - print(f" \"{name}\": `{t}`") + print(f" \"{name}\": `{t}`") print("Types from parser:") for name, t in debug_info.types_from_parser(parser.name): - print(f" \"{name}\": `{t}`") + print(f" \"{name}\": `{t}`") print("") print("All functions:") for func in debug_info.functions: - print(f" {func}") + print(f" {func}") print("Functions from parser:") for func in debug_info.functions_from_parser(parser.name): - print(f" {func}") + print(f" {func}") print("") print("All data variables:") for data_var in debug_info.data_variables: - print(f" {data_var}") + print(f" {data_var}") print("Data variables from parser:") for data_var in debug_info.data_variables_from_parser(parser.name): - print(f" {data_var}") - + print(f" {data_var}") print("Appling debug info!") bv.apply_debug_info(debug_info) @@ -254,16 +277,16 @@ bv.update_analysis_and_wait() print("") print("Types:") for name, t in debug_info.types: - print(f" {bv.get_type_by_name(name)}") + print(f" {bv.get_type_by_name(name)}") print("") print("Functions:") for func in debug_info.functions: - print(f" {bv.get_function_at(func.address)}") + print(f" {bv.get_function_at(func.address)}") print("") print("Data variables:") for data_var in debug_info.data_variables: - print(f" {bv.get_data_var_at(data_var.address)}") + print(f" {bv.get_data_var_at(data_var.address)}") diff --git a/python/examples/export_svg.py b/python/examples/export_svg.py index c96873e1..8166b27a 100755 --- a/python/examples/export_svg.py +++ b/python/examples/export_svg.py @@ -12,119 +12,126 @@ from binaryninja.enums import MessageBoxButtonSet, MessageBoxIcon, MessageBoxBut 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 = { - "'": "'", - ">": ">", - "<": "<", - '"': """, - ' ': " " +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 - if sys.version_info[0] == 3: - return ''.join(escape_table.get(chr(i), chr(i)) for i in toescape) - else: - return ''.join(escape_table.get(i, i) for i in toescape) + # handle extended unicode + toescape = toescape.encode('ascii', 'xmlcharrefreplace') + # still escape the basics + if sys.version_info[0] == 3: + return ''.join(escape_table.get(chr(i), chr(i)) for i in toescape) + else: + return ''.join(escape_table.get(i, 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' + 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) + 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"]) + 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)) + 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) - if sys.version_info[0] == 3: - hex = func_bytes.hex() - else: - hex = func_bytes.encode('hex') - padded = ' '.join([hex[i:i + 2] for i in range(0, len(hex), 2)]) - return 'Opcode: {bytes}'.format(bytes=padded) + # TODO: Extract data flow information + length = function.view.get_instruction_length(address) + func_bytes = function.view.read(address, length) + if sys.version_info[0] == 3: + hex = func_bytes.hex() + else: + hex = func_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, 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 + 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 = '''