diff options
Diffstat (limited to 'python')
| -rw-r--r-- | python/architecture.py | 6 | ||||
| -rw-r--r-- | python/basicblock.py | 47 | ||||
| -rw-r--r-- | python/binaryview.py | 153 | ||||
| -rw-r--r-- | python/examples/jump_table.py | 2 | ||||
| -rw-r--r-- | python/examples/print_syscalls.py | 2 | ||||
| -rw-r--r-- | python/filemetadata.py | 8 | ||||
| -rw-r--r-- | python/function.py | 162 | ||||
| -rw-r--r-- | python/scriptingprovider.py | 43 |
8 files changed, 330 insertions, 93 deletions
diff --git a/python/architecture.py b/python/architecture.py index 0cdba6e5..5162e58a 100644 --- a/python/architecture.py +++ b/python/architecture.py @@ -1152,6 +1152,12 @@ class Architecture(object): core.BNFreeInstructionText(tokens, count.value) return result, length.value + def get_instruction_low_level_il_instruction(self, bv, addr): + il = lowlevelil.LowLevelILFunction(self) + data = bv.read(addr, self.max_instr_length) + self.get_instruction_low_level_il(data, addr, il) + return il[0] + def get_instruction_low_level_il(self, data, addr, il): """ ``get_instruction_low_level_il`` appends LowLevelILExpr objects for the instruction at the given virtual diff --git a/python/basicblock.py b/python/basicblock.py index 7abfdc94..d728cb8d 100644 --- a/python/basicblock.py +++ b/python/basicblock.py @@ -111,11 +111,25 @@ class BasicBlock(object): @property def disassembly_text(self): + """ + ``disassembly_text`` property which returns a list of function.DisassemblyTextLine objects for the current basic block. + :Example: + + >>> current_basic_block.disassembly_text + [<0x100000f30: _main:>, ...] + """ return self.get_disassembly_text() @property def highlight(self): - """Highlight color for basic block""" + """Gets or sets the highlight color for basic block + + :Example: + + >>> current_basic_block.highlight = core.BNHighlightStandardColor.BlueHighlightColor + >>> current_basic_block.highlight + <color: blue> + """ color = core.BNGetBasicBlockHighlight(self.handle) if color.style == core.BNHighlightColorStyle.StandardHighlightColor: return highlight.HighlightColor(color=color.color, alpha=color.alpha) @@ -162,6 +176,13 @@ class BasicBlock(object): core.BNMarkBasicBlockAsRecentlyUsed(self.handle) def get_disassembly_text(self, settings=None): + """ + ``get_disassembly_text`` returns a list of function.DisassemblyTextLine objects for the current basic block. + :Example: + + >>>current_basic_block.get_disassembly_text() + [<0x100000f30: _main:>, <0x100000f30: push rbp>, ... ] + """ settings_obj = None if settings: settings_obj = settings.handle @@ -184,11 +205,27 @@ class BasicBlock(object): return result def set_auto_highlight(self, color): - if not isinstance(color, highlight.HighlightColor): - color = highlight.HighlightColor(color=color) + """ + ``set_auto_highlight`` highlights the current BasicBlock with the supplied color. + + .warning:: Use only in analysis plugins. Do not use in regular plugins, as colors won't be saved to the database. + + :param core.BNHighlightStandardColor or highlight.HighlightColor color: Color value to use for highlighting + """ + if not isinstance(color, core.BNHighlightStandardColor) and not isinstance(color, highlight.HighlightColor): + raise ValueError("Specified color is not one of core.BNHighlightStandardColor, highlight.HighlightColor") core.BNSetAutoBasicBlockHighlight(self.handle, color._get_core_struct()) def set_user_highlight(self, color): - if not isinstance(color, highlight.HighlightColor): - color = highlight.HighlightColor(color=color) + """ + ``set_user_highlight`` highlights the current BasicBlock with the supplied color + + :param core.BNHighlightStandardColor or highlight.HighlightColor color: Color value to use for highlighting + :Example: + + >>> current_basic_block.set_user_highlight(highlight.HighlightColor(red=0xff, blue=0xff, green=0)) + >>> current_basic_block.set_user_highlight(core.BNHighlightStandardColor.BlueHighlightColor) + """ + if not isinstance(color, core.BNHighlightStandardColor) and not isinstance(color, highlight.HighlightColor): + raise ValueError("Specified color is not one of core.BNHighlightStandardColor, highlight.HighlightColor") core.BNSetUserBasicBlockHighlight(self.handle, color._get_core_struct()) diff --git a/python/binaryview.py b/python/binaryview.py index e6e0ff61..7c85cd52 100644 --- a/python/binaryview.py +++ b/python/binaryview.py @@ -275,7 +275,7 @@ class BinaryViewType(object): @property def name(self): - """Binary View name (read-only)""" + """BinaryView name (read-only)""" return core.BNGetBinaryViewTypeName(self.handle) @property @@ -303,12 +303,21 @@ class BinaryViewType(object): """ ``get_view_of_file`` returns the first available, non-Raw `BinaryView` available. - :param str filename: Path to filename + :param str filename: Path to filename or bndb :param bool update_analysis: defaults to True. Pass False to not run update_analysis_and_wait. :return: returns a BinaryView object for the given filename. :rtype: BinaryView or None """ - view = BinaryView.open(filename) + sqlite = "SQLite format 3" + if filename.endswith(".bndb"): + f = open(filename, 'r') + if f is None or f.read(len(sqlite)) != sqlite: + return None + f.close() + view = filemetadata.FileMetadata().open_existing_database(filename) + else: + view = BinaryView.open(filename) + if view is None: return None for available in view.available_view_types: @@ -1381,7 +1390,7 @@ class BinaryView(object): >>> bv.get_disassembly(0x100012f1) 'xor eax, eax' >>> bv.begin_undo_actions() - >>> bv.convert_to_nop(bv.arch, 0x100012f1) + >>> bv.convert_to_nop(0x100012f1) True >>> bv.commit_undo_actions() >>> bv.get_disassembly(0x100012f1) @@ -1406,7 +1415,7 @@ class BinaryView(object): >>> bv.get_disassembly(0x100012f1) 'xor eax, eax' >>> bv.begin_undo_actions() - >>> bv.convert_to_nop(bv.arch, 0x100012f1) + >>> bv.convert_to_nop(0x100012f1) True >>> bv.commit_undo_actions() >>> bv.get_disassembly(0x100012f1) @@ -1428,7 +1437,7 @@ class BinaryView(object): >>> bv.get_disassembly(0x100012f1) 'xor eax, eax' >>> bv.begin_undo_actions() - >>> bv.convert_to_nop(bv.arch, 0x100012f1) + >>> bv.convert_to_nop(0x100012f1) True >>> bv.commit_undo_actions() >>> bv.get_disassembly(0x100012f1) @@ -1453,7 +1462,7 @@ class BinaryView(object): >>> bv.get_disassembly(0x100012f1) 'xor eax, eax' >>> bv.begin_undo_actions() - >>> bv.convert_to_nop(bv.arch, 0x100012f1) + >>> bv.convert_to_nop(0x100012f1) True >>> bv.commit_undo_actions() >>> bv.get_disassembly(0x100012f1) @@ -1624,33 +1633,37 @@ class BinaryView(object): self.notifications[notify]._unregister() del self.notifications[notify] - def add_function(self, plat, addr): + def add_function(self, addr, plat=None): """ ``add_function`` add a new function of the given ``plat`` at the virtual address ``addr`` - :param Platform plat: Platform for the function to be added :param int addr: virtual address of the function to be added + :param Platform plat: Platform for the function to be added :rtype: None :Example: - >>> bv.add_function(bv.plat, 1) + >>> bv.add_function(1) >>> bv.functions [<func: x86_64@0x1>] """ + if plat is None: + plat = self.platform core.BNAddFunctionForAnalysis(self.handle, plat.handle, addr) - def add_entry_point(self, plat, addr): + def add_entry_point(self, addr, plat=None): """ ``add_entry_point`` adds an virtual address to start analysis from for a given plat. - :param Platform plat: Platform for the entry point analysis :param int addr: virtual address to start analysis from + :param Platform plat: Platform for the entry point analysis :rtype: None :Example: - >>> bv.add_entry_point(bv.plat, 0xdeadbeef) + >>> bv.add_entry_point(0xdeadbeef) >>> """ + if plat is None: + plat = self.platform core.BNAddEntryPointForAnalysis(self.handle, plat.handle, addr) def remove_function(self, func): @@ -1669,20 +1682,22 @@ class BinaryView(object): """ core.BNRemoveAnalysisFunction(self.handle, func.handle) - def create_user_function(self, plat, addr): + def create_user_function(self, addr, plat=None): """ ``create_user_function`` add a new *user* function of the given ``plat`` at the virtual address ``addr`` - :param Platform plat: Platform for the function to be added :param int addr: virtual address of the *user* function to be added + :param Platform plat: Platform for the function to be added :rtype: None :Example: - >>> bv.create_user_function(bv.plat, 1) + >>> bv.create_user_function(1) >>> bv.functions [<func: x86_64@0x1>] """ + if plat is None: + plat = self.platform core.BNCreateUserFunction(self.handle, plat.handle, addr) def remove_user_function(self, func): @@ -1832,20 +1847,22 @@ class BinaryView(object): return None return DataVariable(var.address, type.Type(var.type), var.autoDiscovered) - def get_function_at(self, plat, addr): + def get_function_at(self, addr, plat=None): """ ``get_function_at`` gets a binaryninja.Function object for the function at the virtual address ``addr``: - :param binaryninja.Platform plat: plat of the desired function :param int addr: virtual address of the desired function + :param Platform plat: plat of the desired function :return: returns a Function object or None for the function at the virtual address provided :rtype: Function :Example: - >>> bv.get_function_at(bv.plat, bv.entry_point) + >>> bv.get_function_at(bv.entry_point) <func: x86_64@0x100001174> >>> """ + if plat is None: + plat = self.platform func = core.BNGetAnalysisFunction(self.handle, plat.handle, addr) if func is None: return None @@ -2092,144 +2109,154 @@ class BinaryView(object): """ core.BNDefineImportedFunction(self.handle, import_addr_sym.handle, func.handle) - def is_never_branch_patch_available(self, arch, addr): + def is_never_branch_patch_available(self, addr, arch=None): """ ``is_never_branch_patch_available`` queries the architecture plugin to determine if the instruction at the instruction at ``addr`` can be made to **never branch**. The actual logic of which is implemented in the ``perform_is_never_branch_patch_available`` in the corresponding architecture. - :param Architecture arch: the architecture for the current view :param int addr: the virtual address of the instruction to be patched + :param Architecture arch: (optional) the architecture of the instructions if different from the default :return: True if the instruction can be patched, False otherwise :rtype: bool :Example: >>> bv.get_disassembly(0x100012ed) 'test eax, eax' - >>> bv.is_never_branch_patch_available(bv.arch, 0x100012ed) + >>> bv.is_never_branch_patch_available(0x100012ed) False >>> bv.get_disassembly(0x100012ef) 'jg 0x100012f5' - >>> bv.is_never_branch_patch_available(bv.arch, 0x100012ef) + >>> bv.is_never_branch_patch_available(0x100012ef) True >>> """ + if arch is None: + arch = self.arch return core.BNIsNeverBranchPatchAvailable(self.handle, arch.handle, addr) - def is_always_branch_patch_available(self, arch, addr): + def is_always_branch_patch_available(self, addr, arch=None): """ ``is_always_branch_patch_available`` queries the architecture plugin to determine if the instruction at ``addr`` can be made to **always branch**. The actual logic of which is implemented in the ``perform_is_always_branch_patch_available`` in the corresponding architecture. - :param Architecture arch: the architecture for the current view :param int addr: the virtual address of the instruction to be patched + :param Architecture arch: (optional) the architecture for the current view :return: True if the instruction can be patched, False otherwise :rtype: bool :Example: >>> bv.get_disassembly(0x100012ed) 'test eax, eax' - >>> bv.is_always_branch_patch_available(bv.arch, 0x100012ed) + >>> bv.is_always_branch_patch_available(0x100012ed) False >>> bv.get_disassembly(0x100012ef) 'jg 0x100012f5' - >>> bv.is_always_branch_patch_available(bv.arch, 0x100012ef) + >>> bv.is_always_branch_patch_available(0x100012ef) True >>> """ + if arch is None: + arch = self.arch return core.BNIsAlwaysBranchPatchAvailable(self.handle, arch.handle, addr) - def is_invert_branch_patch_available(self, arch, addr): + def is_invert_branch_patch_available(self, addr, arch=None): """ ``is_invert_branch_patch_available`` queries the architecture plugin to determine if the instruction at ``addr`` is a branch that can be inverted. The actual logic of which is implemented in the ``perform_is_invert_branch_patch_available`` in the corresponding architecture. - :param Architecture arch: the architecture for the current view :param int addr: the virtual address of the instruction to be patched + :param Architecture arch: (optional) the architecture of the instructions if different from the default :return: True if the instruction can be patched, False otherwise :rtype: bool :Example: >>> bv.get_disassembly(0x100012ed) 'test eax, eax' - >>> bv.is_invert_branch_patch_available(bv.arch, 0x100012ed) + >>> bv.is_invert_branch_patch_available(0x100012ed) False >>> bv.get_disassembly(0x100012ef) 'jg 0x100012f5' - >>> bv.is_invert_branch_patch_available(bv.arch, 0x100012ef) + >>> bv.is_invert_branch_patch_available(0x100012ef) True >>> """ + if arch is None: + arch = self.arch return core.BNIsInvertBranchPatchAvailable(self.handle, arch.handle, addr) - def is_skip_and_return_zero_patch_available(self, arch, addr): + def is_skip_and_return_zero_patch_available(self, addr, arch=None): """ ``is_skip_and_return_zero_patch_available`` queries the architecture plugin to determine if the instruction at ``addr`` is similar to an x86 "call" instruction which can be made to return zero. The actual logic of which is implemented in the ``perform_is_skip_and_return_zero_patch_available`` in the corresponding architecture. - :param Architecture arch: the architecture for the current view :param int addr: the virtual address of the instruction to be patched + :param Architecture arch: (optional) the architecture of the instructions if different from the default :return: True if the instruction can be patched, False otherwise :rtype: bool :Example: >>> bv.get_disassembly(0x100012f6) 'mov dword [0x10003020], eax' - >>> bv.is_skip_and_return_zero_patch_available(bv.arch, 0x100012f6) + >>> bv.is_skip_and_return_zero_patch_available(0x100012f6) False >>> bv.get_disassembly(0x100012fb) 'call 0x10001629' - >>> bv.is_skip_and_return_zero_patch_available(bv.arch, 0x100012fb) + >>> bv.is_skip_and_return_zero_patch_available(0x100012fb) True >>> """ + if arch is None: + arch = self.arch return core.BNIsSkipAndReturnZeroPatchAvailable(self.handle, arch.handle, addr) - def is_skip_and_return_value_patch_available(self, arch, addr): + def is_skip_and_return_value_patch_available(self, addr, arch=None): """ ``is_skip_and_return_value_patch_available`` queries the architecture plugin to determine if the instruction at ``addr`` is similar to an x86 "call" instruction which can be made to return a value. The actual logic of which is implemented in the ``perform_is_skip_and_return_value_patch_available`` in the corresponding architecture. - :param Architecture arch: the architecture for the current view :param int addr: the virtual address of the instruction to be patched + :param Architecture arch: (optional) the architecture of the instructions if different from the default :return: True if the instruction can be patched, False otherwise :rtype: bool :Example: >>> bv.get_disassembly(0x100012f6) 'mov dword [0x10003020], eax' - >>> bv.is_skip_and_return_value_patch_available(bv.arch, 0x100012f6) + >>> bv.is_skip_and_return_value_patch_available(0x100012f6) False >>> bv.get_disassembly(0x100012fb) 'call 0x10001629' - >>> bv.is_skip_and_return_value_patch_available(bv.arch, 0x100012fb) + >>> bv.is_skip_and_return_value_patch_available(0x100012fb) True >>> """ + if arch is None: + arch = self.arch return core.BNIsSkipAndReturnValuePatchAvailable(self.handle, arch.handle, addr) - def convert_to_nop(self, arch, addr): + def convert_to_nop(self, addr, arch=None): """ ``convert_to_nop`` converts the instruction at virtual address ``addr`` to a nop of the provided architecture. .. note:: This API performs a binary patch, analysis may need to be updated afterward. Additionally the binary\ file must be saved in order to preserve the changes made. - :param Architecture arch: architecture of the current BinaryView :param int addr: virtual address of the instruction to conver to nops + :param Architecture arch: (optional) the architecture of the instructions if different from the default :return: True on success, False on falure. :rtype: bool :Example: >>> bv.get_disassembly(0x100012fb) 'call 0x10001629' - >>> bv.convert_to_nop(bv.arch, 0x100012fb) + >>> bv.convert_to_nop(0x100012fb) True >>> #The above 'call' instruction is 5 bytes, a nop in x86 is 1 byte, >>> # thus 5 nops are used: @@ -2246,9 +2273,11 @@ class BinaryView(object): >>> bv.get_next_disassembly() 'mov byte [ebp-0x1c], al' """ + if arch is None: + arch = self.arch return core.BNConvertToNop(self.handle, arch.handle, addr) - def always_branch(self, arch, addr): + def always_branch(self, addr, arch=None): """ ``always_branch`` convert the instruction of architecture ``arch`` at the virtual address ``addr`` to an unconditional branch. @@ -2256,23 +2285,25 @@ class BinaryView(object): .. note:: This API performs a binary patch, analysis may need to be updated afterward. Additionally the binary\ file must be saved in order to preserve the changes made. - :param Architecture arch: architecture of the current binary view :param int addr: virtual address of the instruction to be modified + :param Architecture arch: (optional) the architecture of the instructions if different from the default :return: True on success, False on falure. :rtype: bool :Example: >>> bv.get_disassembly(0x100012ef) 'jg 0x100012f5' - >>> bv.always_branch(bv.arch, 0x100012ef) + >>> bv.always_branch(0x100012ef) True >>> bv.get_disassembly(0x100012ef) 'jmp 0x100012f5' >>> """ + if arch is None: + arch = self.arch return core.BNAlwaysBranch(self.handle, arch.handle, addr) - def never_branch(self, arch, addr): + def never_branch(self, addr, arch=None): """ ``never_branch`` convert the branch instruction of architecture ``arch`` at the virtual address ``addr`` to a fall through. @@ -2280,23 +2311,25 @@ class BinaryView(object): .. note:: This API performs a binary patch, analysis may need to be updated afterward. Additionally the binary\ file must be saved in order to preserve the changes made. - :param Architecture arch: architecture of the current binary view :param int addr: virtual address of the instruction to be modified + :param Architecture arch: (optional) the architecture of the instructions if different from the default :return: True on success, False on falure. :rtype: bool :Example: >>> bv.get_disassembly(0x1000130e) 'jne 0x10001317' - >>> bv.never_branch(bv.arch, 0x1000130e) + >>> bv.never_branch(0x1000130e) True >>> bv.get_disassembly(0x1000130e) 'nop' >>> """ + if arch is None: + arch = self.arch return core.BNConvertToNop(self.handle, arch.handle, addr) - def invert_branch(self, arch, addr): + def invert_branch(self, addr, arch=None): """ ``invert_branch`` convert the branch instruction of architecture ``arch`` at the virtual address ``addr`` to the inverse branch. @@ -2304,63 +2337,69 @@ class BinaryView(object): .. note:: This API performs a binary patch, analysis may need to be updated afterward. Additionally the binary file must be saved in order to preserve the changes made. - :param Architecture arch: architecture of the current binary view :param int addr: virtual address of the instruction to be modified + :param Architecture arch: (optional) the architecture of the instructions if different from the default :return: True on success, False on falure. :rtype: bool :Example: >>> bv.get_disassembly(0x1000130e) 'je 0x10001317' - >>> bv.invert_branch(bv.arch, 0x1000130e) + >>> bv.invert_branch(0x1000130e) True >>> >>> bv.get_disassembly(0x1000130e) 'jne 0x10001317' >>> """ + if arch is None: + arch = self.arch return core.BNInvertBranch(self.handle, arch.handle, addr) - def skip_and_return_value(self, arch, addr, value): + def skip_and_return_value(self, addr, value, arch=None): """ ``skip_and_return_value`` convert the ``call`` instruction of architecture ``arch`` at the virtual address ``addr`` to the equivilent of returning a value. - :param Architecture arch: architecture of the current binary view :param int addr: virtual address of the instruction to be modified :param int value: value to make the instruction *return* + :param Architecture arch: (optional) the architecture of the instructions if different from the default :return: True on success, False on falure. :rtype: bool :Example: >>> bv.get_disassembly(0x1000132a) 'call 0x1000134a' - >>> bv.skip_and_return_value(bv.arch, 0x1000132a, 42) + >>> bv.skip_and_return_value(0x1000132a, 42) True >>> #The return value from x86 functions is stored in eax thus: >>> bv.get_disassembly(0x1000132a) 'mov eax, 0x2a' >>> """ + if arch is None: + arch = self.arch return core.BNSkipAndReturnValue(self.handle, arch.handle, addr, value) - def get_instruction_length(self, arch, addr): + def get_instruction_length(self, addr, arch=None): """ ``get_instruction_length`` returns the number of bytes in the instruction of Architecture ``arch`` at the virtual address ``addr`` - :param Architecture arch: architecture of the current binary view :param int addr: virtual address of the instruction query + :param Architecture arch: (optional) the architecture of the instructions if different from the default :return: Number of bytes in instruction :rtype: int :Example: >>> bv.get_disassembly(0x100012f1) 'xor eax, eax' - >>> bv.get_instruction_length(bv.arch, 0x100012f1) + >>> bv.get_instruction_length(0x100012f1) 2L >>> """ + if arch is None: + arch = self.arch return core.BNGetInstructionLength(self.handle, arch.handle, addr) def notify_data_written(self, offset, length): diff --git a/python/examples/jump_table.py b/python/examples/jump_table.py index 23531de0..0fd0dbab 100644 --- a/python/examples/jump_table.py +++ b/python/examples/jump_table.py @@ -77,7 +77,7 @@ def find_jump_table(bv, addr): i += 1 # Set the indirect branch targets on the jump instruction to be the list of targets discovered - func.set_user_indirect_branches(arch, jump_addr, branches) + func.set_user_indirect_branches(jump_addr, branches) # Create a plugin command so that the user can right click on an instruction referencing a jump table and # invoke the command diff --git a/python/examples/print_syscalls.py b/python/examples/print_syscalls.py index c3b47a8d..003b388e 100644 --- a/python/examples/print_syscalls.py +++ b/python/examples/print_syscalls.py @@ -43,7 +43,7 @@ def print_syscalls(bv): syscalls = (il for il in chain.from_iterable(func.low_level_il) if il.operation == core.BNLowLevelILOperation.LLIL_SYSCALL) for il in syscalls: - value = func.get_reg_value_at(bv.arch, il.address, register).value + value = func.get_reg_value_at(il.address, register).value print("System call address: {:#x} - {:d}".format(il.address, value)) diff --git a/python/filemetadata.py b/python/filemetadata.py index 846c9f94..f6593405 100644 --- a/python/filemetadata.py +++ b/python/filemetadata.py @@ -208,7 +208,7 @@ class FileMetadata(object): >>> bv.get_disassembly(0x100012f1) 'xor eax, eax' >>> bv.begin_undo_actions() - >>> bv.convert_to_nop(bv.arch, 0x100012f1) + >>> bv.convert_to_nop(0x100012f1) True >>> bv.commit_undo_actions() >>> bv.get_disassembly(0x100012f1) @@ -230,7 +230,7 @@ class FileMetadata(object): >>> bv.get_disassembly(0x100012f1) 'xor eax, eax' >>> bv.begin_undo_actions() - >>> bv.convert_to_nop(bv.arch, 0x100012f1) + >>> bv.convert_to_nop(0x100012f1) True >>> bv.commit_undo_actions() >>> bv.get_disassembly(0x100012f1) @@ -252,7 +252,7 @@ class FileMetadata(object): >>> bv.get_disassembly(0x100012f1) 'xor eax, eax' >>> bv.begin_undo_actions() - >>> bv.convert_to_nop(bv.arch, 0x100012f1) + >>> bv.convert_to_nop(0x100012f1) True >>> bv.commit_undo_actions() >>> bv.get_disassembly(0x100012f1) @@ -277,7 +277,7 @@ class FileMetadata(object): >>> bv.get_disassembly(0x100012f1) 'xor eax, eax' >>> bv.begin_undo_actions() - >>> bv.convert_to_nop(bv.arch, 0x100012f1) + >>> bv.convert_to_nop(0x100012f1) True >>> bv.commit_undo_actions() >>> bv.get_disassembly(0x100012f1) diff --git a/python/function.py b/python/function.py index 2910d283..7253f264 100644 --- a/python/function.py +++ b/python/function.py @@ -286,7 +286,7 @@ class Function(object): @property def function_type(self): - """Function type""" + """Function type object""" return bntype.Type(core.BNGetFunctionType(self.handle)) @function_type.setter @@ -358,10 +358,26 @@ class Function(object): def set_comment(self, addr, comment): core.BNSetCommentForAddress(self.handle, addr, comment) - def get_low_level_il_at(self, arch, addr): + def get_low_level_il_at(self, addr, arch=None): + """ + ``get_low_level_il_at`` gets the LowLevelIL instruction address corresponding to the given virtual address + + :param int addr: virtual address of the function to be queried + :param Architecture arch: (optional) Architecture for the given function + :rtype: int + :Example: + + >>> func = bv.functions[0] + >>> func.get_low_level_il_at(func.start) + 0L + """ + if arch is None: + arch = self.arch return core.BNGetLowLevelILForInstruction(self.handle, arch.handle, addr) - def get_low_level_il_exits_at(self, arch, addr): + def get_low_level_il_exits_at(self, addr, arch=None): + if arch is None: + arch = self.arch count = ctypes.c_ulonglong() exits = core.BNGetLowLevelILExitsForInstruction(self.handle, arch.handle, addr, count) result = [] @@ -370,7 +386,21 @@ class Function(object): core.BNFreeLowLevelILInstructionList(exits) return result - def get_reg_value_at(self, arch, addr, reg): + def get_reg_value_at(self, addr, reg, arch=None): + """ + ``get_reg_value_at`` gets the value the provided string register address corresponding to the given virtual address + + :param int addr: virtual address of the instruction to query + :param str reg: string value of native register to query + :param Architecture arch: (optional) Architecture for the given function + :rtype: function.RegisterValue + :Example: + + >>> func.get_reg_value_at(0x400dbe, 'rdi') + <const 0x2> + """ + if arch is None: + arch = self.arch if isinstance(reg, str): reg = arch.regs[reg].index value = core.BNGetRegisterValueAtInstruction(self.handle, arch.handle, addr, reg) @@ -378,7 +408,21 @@ class Function(object): core.BNFreeRegisterValue(value) return result - def get_reg_value_after(self, arch, addr, reg): + def get_reg_value_after(self, addr, reg, arch=None): + """ + ``get_reg_value_after`` gets the value instruction address corresponding to the given virtual address + + :param int addr: virtual address of the instruction to query + :param str reg: string value of native register to query + :param Architecture arch: (optional) Architecture for the given function + :rtype: function.RegisterValue + :Example: + + >>> func.get_reg_value_after(0x400dbe, 'rdi') + <undetermined> + """ + if arch is None: + arch = self.arch if isinstance(reg, str): reg = arch.regs[reg].index value = core.BNGetRegisterValueAfterInstruction(self.handle, arch.handle, addr, reg) @@ -386,11 +430,25 @@ class Function(object): core.BNFreeRegisterValue(value) return result - def get_reg_value_at_low_level_il_instruction(self, i, reg): + def get_reg_value_at_low_level_il_instruction(self, i, reg, arch=None): + """ + ``get_reg_value_at_low_level_il_instruction`` returns the value of the specified register ``reg`` at the il address + i + + :param int i: il address of instruction to query + :param Architecture arch: (optional) Architecture for the given function + :rtype: function.RegisterValue + :Example: + + >>> func.get_reg_value_at_low_level_il_instruction(15, 'rdi') + <const 0x2> + """ + if arch is None: + arch = self.arch if isinstance(reg, str): reg = self.arch.regs[reg].index value = core.BNGetRegisterValueAtLowLevelILInstruction(self.handle, i, reg) - result = RegisterValue(self.arch, value) + result = RegisterValue(arch, value) core.BNFreeRegisterValue(value) return result @@ -402,13 +460,35 @@ class Function(object): core.BNFreeRegisterValue(value) return result - def get_stack_contents_at(self, arch, addr, offset, size): + def get_stack_contents_at(self, addr, offset, size, arch=None): + """ + ``get_stack_contents_at`` returns the RegisterValue for the item on the stack in the current function at the + given virtual address ``addr``, stack offset ``offset`` and size of ``size``. Optionally specifying the architecture. + + :param int addr: virtual address of the instruction to query + :param int offset: stack offset base of stack + :param int size: size of memory to query + :param Architecture arch: (optional) Architecture for the given function + :rtype: function.RegisterValue + + .. note:: Stack base is zero on entry into the function unless the architecture places the return address on the + stack as in (x86/x86_64) where the stack base will start at address_size + + :Example: + + >>> func.get_stack_contents_at(0x400fad, -16, 4) + <range: 0x8 to 0xffffffff> + """ + if arch is None: + arch = self.arch value = core.BNGetStackContentsAtInstruction(self.handle, arch.handle, addr, offset, size) result = RegisterValue(arch, value) core.BNFreeRegisterValue(value) return result - def get_stack_contents_after(self, arch, addr, offset, size): + def get_stack_contents_after(self, addr, offset, size, arch=None): + if arch is None: + arch = self.arch value = core.BNGetStackContentsAfterInstruction(self.handle, arch.handle, addr, offset, size) result = RegisterValue(arch, value) core.BNFreeRegisterValue(value) @@ -426,7 +506,9 @@ class Function(object): core.BNFreeRegisterValue(value) return result - def get_parameter_at(self, arch, addr, func_type, i): + def get_parameter_at(self, addr, func_type, i, arch=None): + if arch is None: + arch = self.arch if func_type is not None: func_type = func_type.handle value = core.BNGetParameterValueAtInstruction(self.handle, arch.handle, addr, func_type, i) @@ -442,7 +524,9 @@ class Function(object): core.BNFreeRegisterValue(value) return result - def get_regs_read_by(self, arch, addr): + def get_regs_read_by(self, addr, arch=None): + if arch is None: + arch = self.arch count = ctypes.c_ulonglong() regs = core.BNGetRegistersReadByInstruction(self.handle, arch.handle, addr, count) result = [] @@ -451,7 +535,9 @@ class Function(object): core.BNFreeRegisterList(regs) return result - def get_regs_written_by(self, arch, addr): + def get_regs_written_by(self, addr, arch=None): + if arch is None: + arch = self.arch count = ctypes.c_ulonglong() regs = core.BNGetRegistersWrittenByInstruction(self.handle, arch.handle, addr, count) result = [] @@ -460,7 +546,9 @@ class Function(object): core.BNFreeRegisterList(regs) return result - def get_stack_vars_referenced_by(self, arch, addr): + def get_stack_vars_referenced_by(self, addr, arch=None): + if arch is None: + arch = self.arch count = ctypes.c_ulonglong() refs = core.BNGetStackVariablesReferencedByInstruction(self.handle, arch.handle, addr, count) result = [] @@ -470,7 +558,9 @@ class Function(object): core.BNFreeStackVariableReferenceList(refs, count.value) return result - def get_constants_referenced_by(self, arch, addr): + def get_constants_referenced_by(self, addr, arch=None): + if arch is None: + arch = self.arch count = ctypes.c_ulonglong() refs = core.BNGetConstantsReferencedByInstruction(self.handle, arch.handle, addr, count) result = [] @@ -479,7 +569,9 @@ class Function(object): core.BNFreeConstantReferenceList(refs) return result - def get_lifted_il_at(self, arch, addr): + def get_lifted_il_at(self, addr, arch=None): + if arch is None: + arch = self.arch return core.BNGetLiftedILForInstruction(self.handle, arch.handle, addr) def get_lifted_il_flag_uses_for_definition(self, i, flag): @@ -531,21 +623,27 @@ class Function(object): def apply_auto_discovered_type(self, func_type): core.BNApplyAutoDiscoveredFunctionType(self.handle, func_type.handle) - def set_auto_indirect_branches(self, source_arch, source, branches): + def set_auto_indirect_branches(self, source, branches, source_arch=None): + if source_arch is None: + source_arch = self.arch branch_list = (core.BNArchitectureAndAddress * len(branches))() for i in xrange(len(branches)): branch_list[i].arch = branches[i][0].handle branch_list[i].address = branches[i][1] core.BNSetAutoIndirectBranches(self.handle, source_arch.handle, source, branch_list, len(branches)) - def set_user_indirect_branches(self, source_arch, source, branches): + def set_user_indirect_branches(self, source, branches, source_arch=None): + if source_arch is None: + source_arch = self.arch branch_list = (core.BNArchitectureAndAddress * len(branches))() for i in xrange(len(branches)): branch_list[i].arch = branches[i][0].handle branch_list[i].address = branches[i][1] core.BNSetUserIndirectBranches(self.handle, source_arch.handle, source, branch_list, len(branches)) - def get_indirect_branches_at(self, arch, addr): + def get_indirect_branches_at(self, addr, arch=None): + if arch is None: + arch = self.arch count = ctypes.c_ulonglong() branches = core.BNGetIndirectBranchesAt(self.handle, arch.handle, addr, count) result = [] @@ -554,7 +652,9 @@ class Function(object): core.BNFreeIndirectBranchList(branches) return result - def get_block_annotations(self, arch, addr): + def get_block_annotations(self, addr, arch=None): + if arch is None: + arch = self.arch count = ctypes.c_ulonglong(0) lines = core.BNGetFunctionBlockAnnotations(self.handle, arch.handle, addr, count) result = [] @@ -577,10 +677,14 @@ class Function(object): def set_user_type(self, value): core.BNSetFunctionUserType(self.handle, value.handle) - def get_int_display_type(self, arch, instr_addr, value, operand): + def get_int_display_type(self, instr_addr, value, operand, arch=None): + if arch is None: + arch = self.arch return core.BNGetIntegerConstantDisplayType(self.handle, arch.handle, instr_addr, value, operand) - def set_int_display_type(self, arch, instr_addr, value, operand, display_type): + def set_int_display_type(self, instr_addr, value, operand, display_type, arch=None): + if arch is None: + arch = self.arch if isinstance(display_type, str): display_type = core.BNIntegerDisplayType[display_type] core.BNSetIntegerConstantDisplayType(self.handle, arch.handle, instr_addr, value, operand, display_type) @@ -601,13 +705,17 @@ class Function(object): core.BNReleaseAdvancedFunctionAnalysisData(self.handle) self._advanced_analysis_requests -= 1 - def get_basic_block_at(self, arch, addr): + def get_basic_block_at(self, addr, arch=None): + if arch is None: + arch = self.arch block = core.BNGetFunctionBasicBlockAtAddress(self.handle, arch.handle, addr) if not block: return None return basicblock.BasicBlock(self._view, handle = block) - def get_instr_highlight(self, arch, addr): + def get_instr_highlight(self, addr, arch=None): + if arch is None: + arch = self.arch color = core.BNGetInstructionHighlight(self.handle, arch.handle, addr) if color.style == core.BNHighlightColorStyle.StandardHighlightColor: return highlight.HighlightColor(color = color.color, alpha = color.alpha) @@ -617,12 +725,16 @@ class Function(object): return highlight.HighlightColor(red = color.r, green = color.g, blue = color.b, alpha = color.alpha) return highlight.HighlightColor(color = core.BNHighlightStandardColor.NoHighlightColor) - def set_auto_instr_highlight(self, arch, addr, color): + def set_auto_instr_highlight(self, addr, color, arch=None): + if arch is None: + arch = self.arch if not isinstance(color, highlight.HighlightColor): color = highlight.HighlightColor(color = color) core.BNSetAutoInstructionHighlight(self.handle, arch.handle, addr, color._get_core_struct()) - def set_user_instr_highlight(self, arch, addr, color): + def set_user_instr_highlight(self, addr, color, arch=None): + if arch is None: + arch = self.arch if not isinstance(color, highlight.HighlightColor): color = highlight.HighlightColor(color = color) core.BNSetUserInstructionHighlight(self.handle, arch.handle, addr, color._get_core_struct()) diff --git a/python/scriptingprovider.py b/python/scriptingprovider.py index 3ccf9560..cbd9696d 100644 --- a/python/scriptingprovider.py +++ b/python/scriptingprovider.py @@ -334,6 +334,48 @@ class _PythonScriptingInstanceOutput(object): self.orig = orig self.is_error = is_error self.buffer = "" + self.encoding = 'UTF-8' + self.errors = None + self.isatty = False + self.mode = 'w' + self.name = 'PythonScriptingInstanceOutput' + self.newlines = None + + def close(self): + pass + + def closed(self): + return False + + def flush(self): + pass + + def next(self): + raise IOError("File not open for reading") + + def read(self): + raise IOError("File not open for reading") + + def readinto(self): + raise IOError("File not open for reading") + + def readlines(self): + raise IOError("File not open for reading") + + def seek(self): + pass + + def sofspace(self): + return 0 + + def truncate(self): + pass + + def tell(self): + return self.orig.tell() + + def writelines(self, lines): + return self.write('\n'.join(lines)) def write(self, data): global _output_to_log @@ -590,6 +632,7 @@ class PythonScriptingProvider(ScriptingProvider): name = "Python" instance_class = PythonScriptingInstance + PythonScriptingProvider().register() # Wrap stdin/stdout/stderr for Python scripting provider implementation |
