diff options
Diffstat (limited to 'python/__init__.py')
| -rw-r--r-- | python/__init__.py | 798 |
1 files changed, 700 insertions, 98 deletions
diff --git a/python/__init__.py b/python/__init__.py index 1cf07b7c..7e97db3e 100644 --- a/python/__init__.py +++ b/python/__init__.py @@ -809,6 +809,7 @@ class BinaryView(object): _registered = False _registered_cb = None registered_view_type = None + next_address = 0 def __init__(self, file_metadata = None, handle = None): if handle is not None: @@ -850,6 +851,7 @@ class BinaryView(object): self.file = file_metadata self.handle = core.BNCreateCustomBinaryView(self.__class__.name, file_metadata.handle, self._cb) self.notifications = {} + self.next_address = self.entry_point @classmethod def register(cls): @@ -1341,24 +1343,73 @@ class BinaryView(object): def init(self): return True + def get_disassembly(self, addr, arch=None): + """ + ``get_disassembly`` simple helper function for printing disassembly of a given address + + :param int addr: virtual address of instruction + :param Architecture arch: optional Architecture of instruction to decode + :return: a str representation of the instruction at virtual address ``addr`` or None + :rtype: str or None + :Example: + + >>> bv.get_disassembly(bv.entry_point) + 'push ebp' + >>> + """ + if arch is None: + arch = self.arch + txt, size = arch.get_instruction_text(self.read(addr, self.arch.max_instr_length), addr) + self.next_address = addr + size + if txt is None: + return None + return ''.join(str(a) for a in txt).strip() + + def get_next_disassembly(self, arch=None): + """ + ``get_next_disassembly`` simple helper function for printing disassembly of the next instruction. + The internal state of the instruction to be printed is stored in the ``next_address`` attribute + + :param int addr: virtual address of instruction + :return: a str representation of the instruction at virtual address ``addr`` or None + :rtype: str or None + :Example: + + >>> bv.get_next_disassembly() + 'push ebp' + >>> bv.get_next_disassembly() + 'mov ebp, esp' + >>> #Now reset the starting point back to the entry point + >>> bv.next_address = bv.entry_point + >>> bv.get_next_disassembly() + 'push ebp' + >>> + """ + if arch is None: + arch = self.arch + txt, size = arch.get_instruction_text(self.read(self.next_address, self.arch.max_instr_length), self.next_address) + self.next_address += size + if txt is None: + return None + return ''.join(str(a) for a in txt).strip() + def perform_read(self, addr, length): """ - ``perform_read`` implements a mapping between a rebased (virtual) address and an absolute file offset, reading + ``perform_read`` implements a mapping between a virtual address and an absolute file offset, reading ``length`` bytes from the rebased address ``addr``. This method must be overridden by custom BinaryViews if they have segments or the virtual address is different from the physical address. This method **must not** be called directly. - :param int addr: a virtual address to attempt to read from - :param int length: the number of bytes to be read - - :return: length bytes read from addr, should return empty string on error - :type: int + :param int addr: a virtual address to attempt to read from + :param int length: the number of bytes to be read + :return: length bytes read from addr, should return empty string on error + :rtype: int """ return "" def perform_write(self, addr, data): """ - ``perform_write`` implements a mapping between a rebased (virtual) address and an absolute file offset, writing + ``perform_write`` implements a mapping between a virtual address and an absolute file offset, writing the bytes ``data`` to rebased address ``addr``. This method must be overridden by custom BinaryViews if they have segments or the virtual address is different from the physical address. This method **must not** be called directly. @@ -1372,31 +1423,29 @@ class BinaryView(object): def perform_insert(self, addr, data): """ - ``perform_insert`` implements a mapping between a rebased (virtual) address and an absolute file offset, inserting + ``perform_insert`` implements a mapping between a virtual address and an absolute file offset, inserting the bytes ``data`` to rebased address ``addr``. This method must be overridden by custom BinaryViews if they have segments or the virtual address is different from the physical address. This method **must not** be called. :param int addr: a virtual address :param str data: the data to be inserted - - :return: length of data inserted, should return 0 on error - :rtype: int + :return: length of data inserted, should return 0 on error + :rtype: int """ return 0 def perform_remove(self, addr, length): """ - ``perform_remove`` implements a mapping between a rebased (virtual) address and an absolute file offset, removing + ``perform_remove`` implements a mapping between a virtual address and an absolute file offset, removing ``length`` bytes from the rebased address ``addr``. This method must be overridden by custom BinaryViews if they have segments or the virtual address is different from the physical address. This method **must not** be called directly. :param int addr: a virtual address :param str data: the data to be removed - - :return: length of data removed, should return 0 on error - :rtype: int + :return: length of data removed, should return 0 on error + :rtype: int """ return 0 @@ -1406,9 +1455,8 @@ class BinaryView(object): method **must not** be called. :param int addr: a virtual address to be checked - :return: One of the following: Original = 0, Changed = 1, Inserted = 2 - :rtype: int + :rtype: BNModificationStatus """ return core.Original @@ -1419,25 +1467,23 @@ class BinaryView(object): **must not** be called. :param int addr: a virtual address to be checked - - :return: true if the virtual address is valid, false if the virtual address is invalid or error - :rtype: boolean + :return: true if the virtual address is valid, false if the virtual address is invalid or error + :rtype: bool """ data = self.read(addr, 1) return (data is not None) and (len(data) == 1) - def perform_is_offset_readable(self, addr): + def perform_is_offset_readable(self, offset): """ ``perform_is_offset_readable`` implements a check if an virtual address is readable. This method **must** be implemented for custom BinaryViews whose virtual addresses differ from physical file offsets, or if memory protections exist.This method **must not** be called. - :param int addr: a virtual address to be checked - - :return: true if the virtual address is readable, false if the virtual address is not readable or error - :rtype: boolean + :param int offset: a virtual address to be checked + :return: true if the virtual address is readable, false if the virtual address is not readable or error + :rtype: bool """ - return self.is_valid_offset(addr) + return self.is_valid_offset(offset) def perform_is_offset_writable(self, addr): """ @@ -1446,9 +1492,8 @@ class BinaryView(object): if memory protections exist. This method **must not** be called. :param int addr: a virtual address to be checked - - :return: true if the virtual address is writable, false if the virtual address is not writable or error - :rtype: boolean + :return: true if the virtual address is writable, false if the virtual address is not writable or error + :rtype: bool """ return self.is_valid_offset(addr) @@ -1459,9 +1504,8 @@ class BinaryView(object): or if memory protections exist. This method **must not** be called. :param int addr: a virtual address to be checked - - :return: true if the virtual address is executable, false if the virtual address is not executable or error - :rtype: int + :return: true if the virtual address is executable, false if the virtual address is not executable or error + :rtype: int """ return self.is_valid_offset(addr) @@ -1471,9 +1515,8 @@ class BinaryView(object): memory address. This method **must not** be called. :param int addr: a virtual address to start checking from. - - :return: the next readable, writable, or executable virtual memory address - :rtype: int + :return: the next readable, writable, or executable virtual memory address + :rtype: int """ if addr < self.perform_get_start(): return self.perform_get_start() @@ -1484,8 +1527,8 @@ class BinaryView(object): ``perform_get_start`` implements a query for the first readable, writable, or executable virtual address in the BinaryView. This method **must not** be called. - :return: returns the first virtual address in the BinaryView. - :rtype: int + :return: returns the first virtual address in the BinaryView. + :rtype: int """ return 0 @@ -1494,8 +1537,8 @@ class BinaryView(object): ``perform_get_entry_point`` implements a query for the initial entry point for code execution. This method **should** be implmented for custom BinaryViews that are executable. This method **must not** be called. - :return: the virtual address of the entry point - :rtype: int + :return: the virtual address of the entry point + :rtype: int """ return 0 @@ -1505,8 +1548,8 @@ class BinaryView(object): This method **must** be implemented for custom BinaryViews that are executable. This method **must not** be called. - :return: true if the current BinaryView is executable, false if it is not executable or on error - :rtype: boolean + :return: true if the current BinaryView is executable, false if it is not executable or on error + :rtype: bool """ return False @@ -1516,8 +1559,8 @@ class BinaryView(object): This method **must** be implemented for custom BinaryViews that are not LittleEndian. This method **must not** be called. - :return: either ``core.LittleEndian`` or ``core.BigEndian`` - :type: int + :return: either ``core.LittleEndian`` or ``core.BigEndian`` + :rtype: BNEndianness """ return core.LittleEndian @@ -1527,9 +1570,8 @@ class BinaryView(object): **must not** be called. :param str filename: path and filename to write the bndb to, this string `should` have ".bndb" appended to it. - - :return: true on success, false on failure - :rtype: boolean + :return: true on success, false on failure + :rtype: bool """ return self.file.create_database(filename) @@ -1563,13 +1605,14 @@ class BinaryView(object): :param int addr: virtual address to read from. :param int length: number of bytes to read. - - return (str): at most ``length`` bytes from the virtual address ``addr``, empty string on error or no data.:: + :return: at most ``length`` bytes from the virtual address ``addr``, empty string on error or no data. + :rtype: str + :Example: >>> #Opening a x86_64 Mach-O binary >>> bv = BinaryViewType['Raw'].open("/bin/ls") >>> bv.read(0,4) - '\xcf\xfa\xed\xfe' + \'\\xcf\\xfa\\xed\\xfe\' """ buf = DataBuffer(handle = core.BNReadViewBuffer(self.handle, addr, length)) return str(buf) @@ -1580,9 +1623,12 @@ class BinaryView(object): :param int addr: virtual address to write to. :param str data: data to be written at addr. + :return: number of bytes written to virtual address ``addr`` + :rtype: int + :Example: - return (int): number of bytes written to virtual address ``addr``:: - + >>> bv.read(0,4) + 'BBBB' >>> bv.write(0, "AAAA") 4L >>> bv.read(0,4) @@ -1597,8 +1643,9 @@ class BinaryView(object): :param int addr: virtual address to write to. :param str data: data to be inserted at addr. - - return (int): number of bytes inserted to virtual address ``addr``:: + :return: number of bytes inserted to virtual address ``addr`` + :rtype: int + :Example: >>> bv.insert(0,"BBBB") 4L @@ -1614,9 +1661,12 @@ class BinaryView(object): :param int addr: virtual address to remove from. :param int length: number of bytes to remove. + :return: number of bytes removed from virtual address ``addr`` + :rtype: int + :Example: - return (int): number of bytes removed from virtual address ``addr``:: - + >>> bv.read(0,8) + 'BBBBAAAA' >>> bv.remove(0,4) 4L >>> bv.read(0,4) @@ -1624,30 +1674,69 @@ class BinaryView(object): """ return core.BNRemoveViewData(self.handle, addr, length) - def get_modification(self, offset, length = None): + def get_modification(self, addr, length = None): + """ + ``get_modification`` returns the modified bytes of up to ``length`` bytes from virtual address ``addr``, or if + ``length`` is None returns the core.BNModificationStatus. + + :param int addr: virtual address to get modification from + :param int length: optional length of modification + :return: Either core.BNModificationStatus of the byte at ``addr``, or string of modified bytes at ``addr`` + :rtype: core.BNModificationStatus or str + """ if length is None: - return core.BNGetModification(self.handle, offset) + return core.BNGetModification(self.handle, addr) data = (core.BNModificationStatus * length)() - length = core.BNGetModificationArray(self.handle, offset, data, length); + length = core.BNGetModificationArray(self.handle, addr, data, length); return data[0:length] - def is_valid_offset(self, offset): - return core.BNIsValidOffset(self.handle, offset) + def is_valid_offset(self, addr): + """ + ``is_valid_offset`` checks if an virtual address ``addr`` is valid . - def is_offset_readable(self, offset): - return core.BNIsOffsetReadable(self.handle, offset) + :param int addr: a virtual address to be checked + :return: true if the virtual address is valid, false if the virtual address is invalid or error + :rtype: bool + """ + return core.BNIsValidOffset(self.handle, addr) - def is_offset_writable(self, offset): - return core.BNIsOffsetWritable(self.handle, offset) + def is_offset_readable(self, addr): + """ + ``is_valid_offset`` checks if an virtual address ``addr`` is valid for reading. - def is_offset_executable(self, offset): - return core.BNIsOffsetExecutable(self.handle, offset) + :param int addr: a virtual address to be checked + :return: true if the virtual address is valid for reading, false if the virtual address is invalid or error + :rtype: bool + """ + return core.BNIsOffsetReadable(self.handle, addr) + + def is_offset_writable(self, addr): + """ + ``is_valid_offset`` checks if an virtual address ``addr`` is valid for writing. + + :param int addr: a virtual address to be checked + :return: true if the virtual address is valid for writing, false if the virtual address is invalid or error + :rtype: bool + """ + return core.BNIsOffsetWritable(self.handle, addr) + + def is_offset_executable(self, addr): + """ + ``is_valid_offset`` checks if an virtual address ``addr`` is valid for executing. + + :param int addr: a virtual address to be checked + :return: true if the virtual address is valid for executing, false if the virtual address is invalid or error + :rtype: bool + """ + return core.BNIsOffsetExecutable(self.handle, addr) def save(self, dest): """ - ``save`` saves the original file to the provided destination ``dest`` along with any modifications. + ``save`` saves the original binary file to the provided destination ``dest`` along with any modifications. :param str dest: destination path and filename of file to be written + :return: boolean True on success, False on failure + :rtype: bool """ if isinstance(dest, FileAccessor): return core.BNSaveToFile(self.handle, dest._cb) @@ -1665,29 +1754,43 @@ class BinaryView(object): def add_function(self, platform, addr): """ - ``add_function`` adds a new function of the given ``platform`` at the virtual address ``addr`` + ``add_function`` add a new function of the given ``platform`` at the virtual address ``addr`` - :param binaryninja.Platform platform: platform for the function to be added + :param Platform platform: Platform for the function to be added :param int addr: virtual address of the function to be added - - :return: None :: + :return: Nothing + :rtype: None + :Example: >>> bv.add_function(bv.platform, bv.entry_point + 1) >>> bv.functions [<func: x86_64@0x1>] + """ core.BNAddFunctionForAnalysis(self.handle, platform.handle, addr) def add_entry_point(self, platform, addr): + """ + ``add_entry_point`` adds an virtual address to start analysis from for a given platform. + + :param Platform platform: Platform for the entry point analysis + :param int addr: virtual address to start analysis from + :return: Nothing + :rtype: None + :Example: + >>> bv.add_entry_point(bv.platform, 0xdeadbeef) + >>> + """ core.BNAddEntryPointForAnalysis(self.handle, platform.handle, addr) def remove_function(self, func): """ ``remove_function`` removes the function ``func`` from the list of functions - func (binaryninja.Function): a binaryninja.Function object. - - :return: None :: + :param Function func: a Function object. + :return: Nothing + :rtype: None + :Example: >>> bv.functions [<func: x86_64@0x1>] @@ -1710,7 +1813,8 @@ class BinaryView(object): ``update_analysis_and_wait()``. An analysis update **must** be run after changes are made which could change analysis results such as adding functions. - :return: None + :return: Nothing + :rtype: None """ core.BNUpdateAnalysis(self.handle) @@ -1721,7 +1825,8 @@ class BinaryView(object): ``update_analysis()`` or ``update_analysis_and_wait()``. An analysis update **must** be run after changes are made which could change analysis results such as adding functions. - :return: None + :return: Nothing + :rtype: None """ class WaitEvent: def __init__(self): @@ -1749,37 +1854,55 @@ class BinaryView(object): """ ``abort_analysis`` will abort the currently running analysis. - :return: None + :return: Nothing + :rtype: None """ core.BNAbortAnalysis(self.handle) def define_data_var(self, addr, var_type): """ - ``define_data_var`` defines a data variable ``var_type`` at the virtual address ``addr``. + ``define_data_var`` defines a non-user data variable ``var_type`` at the virtual address ``addr``. :param int addr: virtual address to define the given data variable :param binaryninja.Type var_type: type to be defined at the given virtual address + :return Nothing + :rtype: None + :Example: - :return None :: - - >>> bv.define_data_var(bv.entry_point, bv.parse_type_string("int foo")[0]) >>> t = bv.parse_type_string("int foo") >>> t (<type: int32_t>, 'foo') >>> bv.define_data_var(bv.entry_point, t[0]) + >>> """ core.BNDefineDataVariable(self.handle, addr, var_type.handle) def define_user_data_var(self, addr, var_type): + """ + ``define_data_var`` defines a user data variable ``var_type`` at the virtual address ``addr``. + + :param int addr: virtual address to define the given data variable + :param binaryninja.Type var_type: type to be defined at the given virtual address + :return Nothing + :rtype: None + :Example: + + >>> t = bv.parse_type_string("int foo") + >>> t + (<type: int32_t>, 'foo') + >>> bv.define_user_data_var(bv.entry_point, t[0]) + >>> + """ core.BNDefineUserDataVariable(self.handle, addr, var_type.handle) def undefine_data_var(self, addr): """ - ``undefine_data_var`` removes the data variable at the virtual address ``addr``. + ``undefine_data_var`` removes the non-user data variable at the virtual address ``addr``. :param int addr: virtual address to define the data variable to be removed - - :return: None :: + :return: Nothing + :rtype: None + :Example: >>> bv.undefine_data_var(bv.entry_point) >>> @@ -1787,6 +1910,17 @@ class BinaryView(object): core.BNUndefineDataVariable(self.handle, addr) def undefine_user_data_var(self, addr): + """ + ``undefine_data_var`` removes the user data variable at the virtual address ``addr``. + + :param int addr: virtual address to define the data variable to be removed + :return: Nothing + :rtype: None + :Example: + + >>> bv.undefine_user_data_var(bv.entry_point) + >>> + """ core.BNUndefineUserDataVariable(self.handle, addr) def get_data_var_at(self, addr): @@ -1794,15 +1928,15 @@ class BinaryView(object): ``get_data_var_at`` returns the data type at a given virtual address. :param int addr: virtual address to get the data type from - - :return: returns the DataVariable at the given virtual address, None on error.:: + :return: returns the DataVariable at the given virtual address, None on error. + :rtype: DataVariable + :Example: >>> t = bv.parse_type_string("int foo") >>> bv.define_data_var(bv.entry_point, t[0]) >>> bv.get_data_var_at(bv.entry_point) <var 0x100001174: int32_t> - :rtype: binaryninja.DataVariable """ var = core.BNDataVariable() if not core.BNGetDataVariableAtAddress(self.handle, addr, var): @@ -1815,14 +1949,13 @@ class BinaryView(object): :param binaryninja.Platform platform: platform of the desired function :param int addr: virtual address of the desired function - - :return: returns a Function object or None for the function at the virtual address provided :: + :return: returns a Function object or None for the function at the virtual address provided + :rtype: Function + :Example: >>> bv.get_function_at(bv.platform, bv.entry_point) <func: x86_64@0x100001174> >>> - - :rtype: binaryninja.Function """ func = core.BNGetAnalysisFunction(self.handle, platform.handle, addr) if func is None: @@ -1837,9 +1970,8 @@ class BinaryView(object): platforms. :param int addr: virtual address of the desired Function object list. - - :return: a list of binaryninja.Function objects defined at the provided virtual address - :rtype: list + :return: a list of binaryninja.Function objects defined at the provided virtual address + :rtype: list(Function) """ count = ctypes.c_ulonglong(0) funcs = core.BNGetAnalysisFunctionsForAddress(self.handle, addr, count) @@ -1857,7 +1989,11 @@ class BinaryView(object): def get_basic_blocks_at(self, addr): """ - ``get_basic_blocks_at`` returns the binaryninja.BasicBlock + ``get_basic_blocks_at`` get a list of :py:Class:`BasicBlock` objects which exist at the provided virtual address. + + :param int addr: virtual address of BasicBlock desired + :return: a list of :py:Class:`BasicBlock` objects + :rtype: list(BasicBlock) """ count = ctypes.c_ulonglong(0) blocks = core.BNGetBasicBlocksForAddress(self.handle, addr, count) @@ -1895,18 +2031,54 @@ class BinaryView(object): return result def get_symbol_at(self, addr): + """ + ``get_symbol_at`` returns the Symbol at the provided virtual address. + + :param int addr: virtual address to query for symbol + :return: Symbol for the given virtual address + :rtype: Symbol + :Example: + + >>> bv.get_symbol_at(bv.entry_point) + <FunctionSymbol: "_start" @ 0x100001174> + >>> + """ sym = core.BNGetSymbolByAddress(self.handle, addr) if sym is None: return None return Symbol(None, None, None, handle = sym) def get_symbol_by_raw_name(self, name): + """ + ``get_symbol_by_raw_name`` retrieves a Symbol object for the given a raw (mangled) name. + + :param str name: raw (mangled) name of Symbol to be retrieved + :return: Symbol object corresponding to the provided raw name + :rtype: Symbol + :Example: + + >>> bv.get_symbol_by_raw_name('?testf@Foobar@@SA?AW4foo@1@W421@@Z') + <FunctionSymbol: "public: static enum Foobar::foo __cdecl Foobar::testf(enum Foobar::foo)" @ 0x10001100> + >>> + """ sym = core.BNGetSymbolByRawName(self.handle, name) if sym is None: return None return Symbol(None, None, None, handle = sym) def get_symbols_by_name(self, name): + """ + ``get_symbols_by_name`` retrieves a list of Symbol objects for the given symbol name. + + :param str name: name of Symbol object to be retrieved + :return: Symbol object corresponding to the provided name + :rtype: Symbol + :Example: + + >>> bv.get_symbols_by_name('?testf@Foobar@@SA?AW4foo@1@W421@@Z') + [<FunctionSymbol: "public: static enum Foobar::foo __cdecl Foobar::testf(enum Foobar::foo)" @ 0x10001100>] + >>> + """ count = ctypes.c_ulonglong(0) syms = core.BNGetSymbolsByName(self.handle, name, count) result = [] @@ -1916,6 +2088,19 @@ class BinaryView(object): return result def get_symbols(self, start = None, length = None): + """ + ``get_symbols`` retrieves the list of all Symbol objects in the optionally provided range. + + :param int start: optional start virtual address + :param int length: optional length + :return: list of all Symbol objects, or those Symbol objects in the range of ``start``-``start+length`` + :rtype: list(Symbol) + :Example: + + >>> bv.get_symbols(0x1000200c, 1) + [<ImportAddressSymbol: "KERNEL32!IsProcessorFeaturePresent@IAT" @ 0x1000200c>] + >>> + """ count = ctypes.c_ulonglong(0) if start is None: syms = core.BNGetSymbols(self.handle, count) @@ -1928,6 +2113,21 @@ class BinaryView(object): return result def get_symbols_of_type(self, sym_type, start = None, length = None): + """ + ``get_symbols_of_type`` retrieves a list of all Symbol objects of the provided symbol type in the optionally + provided range. + + :param SymbolType sym_type: A Symbol type: :py:Class:`Symbol`. + :param int start: optional start virtual address + :param int length: optional length + :return: list of all Symbol objects of type sym_type, or those Symbol objects in the range of ``start``-``start+length`` + :rtype: list(Symbol) + :Example: + + >>> bv.get_symbols_of_type(core.ImportAddressSymbol, 0x10002028, 1) + [<ImportAddressSymbol: "KERNEL32!GetCurrentThreadId@IAT" @ 0x10002028>] + >>> + """ if isinstance(sym_type, str): sym_type = core.BNSymbolType_by_name[sym_type] count = ctypes.c_ulonglong(0) @@ -1942,51 +2142,319 @@ class BinaryView(object): return result def define_auto_symbol(self, sym): + """ + ``define_auto_symbol`` adds a symbol to the internal list of automatically discovered Symbol objects. + + :param Symbol sym: the symbol to define + :return: Nothing + :rtype: None + """ core.BNDefineAutoSymbol(self.handle, sym.handle) def undefine_auto_symbol(self, sym): + """ + ``undefine_auto_symbol`` removes a symbol from the internal list of automatically discovered Symbol objects. + + :param Symbol sym: the symbol to undefine + :return: Nothing + :rtype: None + """ core.BNUndefineAutoSymbol(self.handle, sym.handle) def define_user_symbol(self, sym): + """ + ``define_user_symbol`` adds a symbol to the internal list of user added Symbol objects. + + :param Symbol sym: the symbol to define + :return: Nothing + :rtype: None + """ core.BNDefineUserSymbol(self.handle, sym.handle) def undefine_user_symbol(self, sym): + """ + ``undefine_user_symbol`` removes a symbol from the internal list of user added Symbol objects. + + :param Symbol sym: the symbol to undefine + :return: Nothing + :rtype: None + """ core.BNUndefineUserSymbol(self.handle, sym.handle) def define_imported_function(self, import_addr_sym, func): + """ + ``define_imported_function`` + """ core.BNDefineImportedFunction(self.handle, import_addr_sym.handle, func.handle) def is_never_branch_patch_available(self, arch, addr): + """ + ``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 + :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) + False + >>> bv.get_disassembly(0x100012ef) + 'jg 0x100012f5' + >>> bv.is_never_branch_patch_available(bv.arch, 0x100012ef) + True + >>> + """ return core.BNIsNeverBranchPatchAvailable(self.handle, arch.handle, addr) def is_always_branch_patch_available(self, arch, addr): + """ + ``is_always_branch_patch_available`` queries the architecture plugin to determine if the instruction at 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 + :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) + False + >>> bv.get_disassembly(0x100012ef) + 'jg 0x100012f5' + >>> bv.is_always_branch_patch_available(bv.arch, 0x100012ef) + True + >>> + """ return core.BNIsAlwaysBranchPatchAvailable(self.handle, arch.handle, addr) def is_invert_branch_patch_available(self, arch, addr): + """ + ``is_invert_branch_patch_available`` queries the architecture plugin to determine if the instruction at 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 + :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) + False + >>> bv.get_disassembly(0x100012ef) + 'jg 0x100012f5' + >>> bv.is_invert_branch_patch_available(bv.arch, 0x100012ef) + True + >>> + """ return core.BNIsInvertBranchPatchAvailable(self.handle, arch.handle, addr) def is_skip_and_return_zero_patch_available(self, arch, addr): + """ + ``is_skip_and_return_zero_patch_available`` queries the architecture plugin to determine if the instruction at 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 + :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) + False + >>> bv.get_disassembly(0x100012fb) + 'call 0x10001629' + >>> bv.is_skip_and_return_zero_patch_available(bv.arch, 0x100012fb) + True + >>> + """ return core.BNIsSkipAndReturnZeroPatchAvailable(self.handle, arch.handle, addr) def is_skip_and_return_value_patch_available(self, arch, addr): + """ + ``is_skip_and_return_value_patch_available`` queries the architecture plugin to determine if the instruction at 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 + :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) + False + >>> bv.get_disassembly(0x100012fb) + 'call 0x10001629' + >>> bv.is_skip_and_return_value_patch_available(bv.arch, 0x100012fb) + True + >>> + """ return core.BNIsSkipAndReturnValuePatchAvailable(self.handle, arch.handle, addr) def convert_to_nop(self, arch, addr): + """ + ``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 + :return: True on success, False on falure. + :rtype: bool + :Example: + + >>> bv.get_disassembly(0x100012fb) + 'call 0x10001629' + >>> bv.convert_to_nop(bv.arch, 0x100012fb) + True + >>> #The above 'call' instruction is 5 bytes, a nop in x86 is 1 byte, thus 5 nops are used: + >>> bv.get_disassembly(0x100012fb) + 'nop' + >>> bv.get_next_disassembly() + 'nop' + >>> bv.get_next_disassembly() + 'nop' + >>> bv.get_next_disassembly() + 'nop' + >>> bv.get_next_disassembly() + 'nop' + >>> bv.get_next_disassembly() + 'mov byte [ebp-0x1c], al' + """ return core.BNConvertToNop(self.handle, arch.handle, addr) def always_branch(self, arch, addr): + """ + ``always_branch`` convert the instruction of architecture ``arch`` at the virtual address ``addr`` to an + unconditional branch. + + .. 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 + :return: True on success, False on falure. + :rtype: bool + :Example: + + >>> bv.get_disassembly(0x100012ef) + 'jg 0x100012f5' + >>> bv.always_branch(bv.arch, 0x100012ef) + True + >>> bv.get_disassembly(0x100012ef) + 'jmp 0x100012f5' + >>> + """ return core.BNAlwaysBranch(self.handle, arch.handle, addr) def never_branch(self, arch, addr): + """ + ``always_branch`` convert the branch instruction of architecture ``arch`` at the virtual address ``addr`` to + a fall through. + + .. 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 + :return: True on success, False on falure. + :rtype: bool + :Example: + + >>> bv.get_disassembly(0x1000130e) + 'jne 0x10001317' + >>> bv.never_branch(bv.arch, 0x1000130e) + True + >>> bv.get_disassembly(0x1000130e) + 'nop' + >>> + """ return core.BNConvertToNop(self.handle, arch.handle, addr) def invert_branch(self, arch, addr): + """ + ``invert_branch`` convert the branch instruction of architecture ``arch`` at the virtual address ``addr`` to the + inverse branch. + + .. 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 + :return: True on success, False on falure. + :rtype: bool + :Example: + + >>> bv.get_disassembly(0x1000130e) + 'je 0x10001317' + >>> bv.invert_branch(bv.arch, 0x1000130e) + True + >>> + >>> bv.get_disassembly(0x1000130e) + 'jne 0x10001317' + >>> + """ return core.BNInvertBranch(self.handle, arch.handle, addr) def skip_and_return_value(self, arch, addr, value): + """ + ``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* + :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) + True + >>> #The return value from x86 functions is stored in eax thus: + >>> bv.get_disassembly(0x1000132a) + 'mov eax, 0x2a' + >>> + """ return core.BNSkipAndReturnValue(self.handle, arch.handle, addr, value) def get_instruction_length(self, arch, addr): + """ + ``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 + :return: Number of bytes in instruction + :rtype: int + :Example: + + >>> bv.get_disassembly(0x100012f1) + 'xor eax, eax' + >>> bv.get_instruction_length(bv.arch, 0x100012f1) + 2L + >>> + """ return core.BNGetInstructionLength(self.handle, arch.handle, addr) def notify_data_written(self, offset, length): @@ -1999,6 +2467,20 @@ class BinaryView(object): core.BNNotifyDataRemoved(self.handle, offset, length) def get_strings(self, start = None, length = None): + """ + ``get_strings`` returns a list of strings defined in the binary in the optional virtual address range: + ``start-(start+length)`` + + :param int start: optional virtual address to start the string list from, defaults to start of the binary + :param int length: optional length range to return strings from, defaults to length of the binary + :return: a list of all strings or a list of strings defined between ``start`` and ``start+length`` + :rtype: list(str()) + :Example: + + >>> bv.get_strings(0x1000004d, 1) + [<AsciiString: 0x1000004d, len 0x2c>] + >>> + """ count = ctypes.c_ulonglong(0) if start is None: strings = core.BNGetStrings(self.handle, count) @@ -2108,7 +2590,24 @@ class BinaryView(object): return self._get_linear_disassembly_lines(core.BNGetNextLinearDisassemblyLines, pos, settings) def get_linear_disassembly(self, settings): - """Gets an iterator for all lines in the linear disassembly of the view for the given disassembly settings""" + """ + ``get_linear_disassembly`` gets an iterator for all lines in the linear disassembly of the view for the given + disassembly settings. **Note:** linear_disassembly doesn't just return disassembly it will return a single line + from the linear view, and thus will contain both hex dump and disassembly. + + :param DisassemblySettings settings: :py:Class:`DisassemblySettings` instance specifying the desired output formatting. + :return: An iterator containing formatted dissassembly lines. + :rtype: LinearDisassemblyIterator + :Example: + + >>> settings = DisassemblySettings() + >>> lines = bv.get_linear_disassembly(settings) + >>> for line in lines: + ... print line + ... break + ... + cf fa ed fe 07 00 00 01 ........ + """ class LinearDisassemblyIterator(object): def __init__(self, view, settings): self.view = view @@ -2126,6 +2625,18 @@ class BinaryView(object): return iter(LinearDisassemblyIterator(self, settings)) def parse_type_string(self, text): + """ + ``parse_type_string`` converts `C-style` string into a :py:Class:`Type`. + + :param str text: `C-style` string of type to create + :return: A tuple of a :py:Class:`Type` and string type name + :rtype: tuple(Type, str) + :Example: + + >>> bv.parse_type_string("int foo") + (<type: int32_t>, 'foo') + >>> + """ result = core.BNNameAndType() errors = ctypes.c_char_p() if not core.BNParseTypeString(self.handle, text, result, errors): @@ -2138,24 +2649,102 @@ class BinaryView(object): return type_obj, name def get_type_by_name(self, name): + """ + ``get_type_by_name`` returns the defined type whose name corresponds with the provided ``name`` + + :param str name: Type name to lookup + :return: A :py:Class:`Type` or None if the type does not exist + :rtype: Type or None + :Example: + + >>> type, name = bv.parse_type_string("int foo") + >>> bv.define_type(name, type) + >>> bv.get_type_by_name(name) + <type: int32_t> + >>> + """ obj = core.BNGetAnalysisTypeByName(self.handle, name) if not obj: return None return Type(obj) def is_type_auto_defined(self, name): + #TODO: Documentation return core.BNIsAnalysisTypeAutoDefined(self.handle, name) def define_type(self, name, type_obj): + """ + ``define_type`` registers a :py:Class:`Type` ``type_obj`` of the given ``name`` in the global list of types for + the current :py:Class:`BinaryView`. + + :param str name: Name of the type to be registered + :param Type type_obj: Type object to be registered + :return: Nothing + :rtype: None + :Example: + + >>> type, name = bv.parse_type_string("int foo") + >>> bv.define_type(name, type) + >>> bv.get_type_by_name(name) + <type: int32_t> + """ core.BNDefineAnalysisType(self.handle, name, type_obj.handle) def define_user_type(self, name, type_obj): + """ + ``define_user_type`` registers a :py:Class:`Type` ``type_obj`` of the given ``name`` in the global list of user + types for the current :py:Class:`BinaryView`. + + :param str name: Name of the user type to be registered + :param Type type_obj: Type object to be registered + :return: Nothing + :rtype: None + :Example: + + >>> type, name = bv.parse_type_string("int foo") + >>> bv.define_user_type(name, type) + >>> bv.get_type_by_name(name) + <type: int32_t> + """ core.BNDefineUserAnalysisType(self.handle, name, type_obj.handle) def undefine_type(self, name): + """ + ``undefine_type`` removes a :py:Class:`Type` from the global list of types for the current :py:Class:`BinaryView` + + :param str name: Name of type to be undefined + :return: Nothing + :rtype: None + :Example: + + >>> type, name = bv.parse_type_string("int foo") + >>> bv.define_type(name, type) + >>> bv.get_type_by_name(name) + <type: int32_t> + >>> bv.undefine_type(name) + >>> bv.get_type_by_name(name) + >>> + """ core.BNUndefineAnalysisType(self.handle, name) def undefine_user_type(self, name): + """ + ``undefine_user_type`` removes a :py:Class:`Type` from the global list of user types for the current + :py:Class:`BinaryView` + + :param str name: Name of user type to be undefined + :return: Nothing + :rtype: None + :Example: + + >>> type, name = bv.parse_type_string("int foo") + >>> bv.define_type(name, type) + >>> bv.get_type_by_name(name) + <type: int32_t> + >>> bv.undefine_type(name) + >>> bv.get_type_by_name(name) + >>> + """ core.BNUndefineUserAnalysisType(self.handle, name) def find_next_data(self, start, data, flags = 0): @@ -2357,6 +2946,19 @@ class BinaryWriter: core.BNSeekBinaryWriterRelative(self.handle, offset) class Symbol(object): + """ + Symbols are defined as one of the following types: + + =========================== ============================================================== + SymbolType Description + =========================== ============================================================== + FunctionSymbol Symbol for Function that exists in the current binary + ImportAddressSymbol Symbol defined in the Import Address Table + ImportedFunctionSymbol Symbol for Function that is not defined in the current binary + DataSymbol Symbol for Data in the current binary + ImportedDataSymbol Symbol for Data that is not defined in the current binary + =========================== ============================================================== + """ def __init__(self, sym_type, addr, short_name, full_name = None, raw_name = None, handle = None): if handle is not None: self.handle = core.handle_of_type(handle, core.BNSymbol) @@ -4059,8 +4661,8 @@ class Architecture(object): return Platform(self, pl) def __setattr__(self, name, value): - if ((name == "name") or (name == "endianness") or (name == "address_size") or (name == "default_int_size") or - (name == "regs")): + if ((name == "name") or (name == "endianness") or (name == "address_size") or + (name == "default_int_size") or (name == "regs") or (name == "get_max_instruction_length")): raise AttributeError, "attribute '%s' is read only" % name else: try: |
