From 5e4cca1f1796bec109adacdb049d9e34c17656eb Mon Sep 17 00:00:00 2001 From: plafosse Date: Fri, 28 Oct 2016 20:16:37 -0400 Subject: Refactor python api into separate files and add Enumeration support. Also fixed bugs found with pyflakes --- python/binaryview.py | 3515 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 3515 insertions(+) create mode 100644 python/binaryview.py (limited to 'python/binaryview.py') diff --git a/python/binaryview.py b/python/binaryview.py new file mode 100644 index 00000000..76def834 --- /dev/null +++ b/python/binaryview.py @@ -0,0 +1,3515 @@ +# Copyright (c) 2015-2016 Vector 35 LLC +# +# 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 +# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +# sell copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +# IN THE SOFTWARE. + +import struct +import traceback +import ctypes +import abc +import threading + +# Binary Ninja components +import _binaryninjacore as core +import function +import startup +import architecture +import platform +import associateddatastore +import fileaccessor +import filemetadata +import log +import databuffer +import basicblock +import bntype +import lineardisassembly + + +class BinaryDataNotification: + def data_written(self, view, offset, length): + pass + + def data_inserted(self, view, offset, length): + pass + + def data_removed(self, view, offset, length): + pass + + def function_added(self, view, func): + pass + + def function_removed(self, view, func): + pass + + def function_updated(self, view, func): + pass + + def data_var_added(self, view, var): + pass + + def data_var_removed(self, view, var): + pass + + def data_var_updated(self, view, var): + pass + + def string_found(self, view, string_type, offset, length): + pass + + def string_removed(self, view, string_type, offset, length): + pass + + +class StringReference(object): + def __init__(self, string_type, start, length): + self.type = string_type + self.start = start + self.length = length + + def __repr__(self): + return "<%s: %#x, len %#x>" % (self.type, self.start, self.length) + + +class AnalysisCompletionEvent(object): + def __init__(self, view, callback): + self.view = view + self.callback = callback + self._cb = ctypes.CFUNCTYPE(None, ctypes.c_void_p)(self._notify) + self.handle = core.BNAddAnalysisCompletionEvent(self.view.handle, None, self._cb) + + def __del__(self): + core.BNFreeAnalysisCompletionEvent(self.handle) + + def _notify(self, ctxt): + try: + self.callback() + except: + log.log_error(traceback.format_exc()) + + def _empty_callback(self): + pass + + def cancel(self): + self.callback = self._empty_callback + core.BNCancelAnalysisCompletionEvent(self.handle) + + +class AnalysisProgress(object): + def __init__(self, state, count, total): + self.state = state + self.count = count + self.total = total + + def __str__(self): + if self.state == core.BNAnalysisState.DisassembleState: + return "Disassembling (%d/%d)" % (self.count, self.total) + if self.state == core.BNAnalysisState.AnalyzeState: + return "Analyzing (%d/%d)" % (self.count, self.total) + return "Idle" + + def __repr__(self): + return "" % str(self) + + +class DataVariable(object): + def __init__(self, addr, var_type, auto_discovered): + self.address = addr + self.type = var_type + self.auto_discovered = auto_discovered + + def __repr__(self): + return "" % (self.address, str(self.type)) + + +class BinaryDataNotificationCallbacks(object): + def __init__(self, view, notify): + self.view = view + self.notify = notify + self._cb = core.BNBinaryDataNotification() + self._cb.context = 0 + self._cb.dataWritten = self._cb.dataWritten.__class__(self._data_written) + self._cb.dataInserted = self._cb.dataInserted.__class__(self._data_inserted) + self._cb.dataRemoved = self._cb.dataRemoved.__class__(self._data_removed) + self._cb.functionAdded = self._cb.functionAdded.__class__(self._function_added) + self._cb.functionRemoved = self._cb.functionRemoved.__class__(self._function_removed) + self._cb.functionUpdated = self._cb.functionUpdated.__class__(self._function_updated) + self._cb.dataVariableAdded = self._cb.dataVariableAdded.__class__(self._data_var_added) + self._cb.dataVariableRemoved = self._cb.dataVariableRemoved.__class__(self._data_var_removed) + self._cb.dataVariableUpdated = self._cb.dataVariableUpdated.__class__(self._data_var_updated) + self._cb.stringFound = self._cb.stringFound.__class__(self._string_found) + self._cb.stringRemoved = self._cb.stringRemoved.__class__(self._string_removed) + + def _register(self): + core.BNRegisterDataNotification(self.view.handle, self._cb) + + def _unregister(self): + core.BNUnregisterDataNotification(self.view.handle, self._cb) + + def _data_written(self, ctxt, view, offset, length): + try: + self.notify.data_written(self.view, offset, length) + except OSError: + log.log_error(traceback.format_exc()) + + def _data_inserted(self, ctxt, view, offset, length): + try: + self.notify.data_inserted(self.view, offset, length) + except: + log.log_error(traceback.format_exc()) + + def _data_removed(self, ctxt, view, offset, length): + try: + self.notify.data_removed(self.view, offset, length) + except: + log.log_error(traceback.format_exc()) + + def _function_added(self, ctxt, view, func): + try: + self.notify.function_added(self.view, function.Function(self.view, core.BNNewFunctionReference(func))) + except: + log.log_error(traceback.format_exc()) + + def _function_removed(self, ctxt, view, func): + try: + self.notify.function_removed(self.view, function.Function(self.view, core.BNNewFunctionReference(func))) + except: + log.log_error(traceback.format_exc()) + + def _function_updated(self, ctxt, view, func): + try: + self.notify.function_updated(self.view, function.Function(self.view, core.BNNewFunctionReference(func))) + except: + log.log_error(traceback.format_exc()) + + def _data_var_added(self, ctxt, view, var): + try: + address = var.address + var_type = bntype.Type(core.BNNewTypeReference(var.type)) + auto_discovered = var.autoDiscovered + self.notify.data_var_added(self.view, DataVariable(address, var_type, auto_discovered)) + except: + log.log_error(traceback.format_exc()) + + def _data_var_removed(self, ctxt, view, var): + try: + address = var.address + var_type = bntype.Type(core.BNNewTypeReference(var.type)) + auto_discovered = var.autoDiscovered + self.notify.data_var_removed(self.view, DataVariable(address, var_type, auto_discovered)) + except: + log.log_error(traceback.format_exc()) + + def _data_var_updated(self, ctxt, view, var): + try: + address = var.address + var_type = bntype.Type(core.BNNewTypeReference(var.type)) + auto_discovered = var.autoDiscovered + self.notify.data_var_updated(self.view, DataVariable(address, var_type, auto_discovered)) + except: + log.log_error(traceback.format_exc()) + + def _string_found(self, ctxt, view, string_type, offset, length): + try: + self.notify.string_found(self.view, core.BNStringType(string_type), offset, length) + except: + log.log_error(traceback.format_exc()) + + def _string_removed(self, ctxt, view, string_type, offset, length): + try: + self.notify.string_removed(self.view, core.BNStringType(string_type), offset, length) + except: + log.log_error(traceback.format_exc()) + + +class _BinaryViewTypeMetaclass(type): + @property + def list(self): + """List all BinaryView types (read-only)""" + startup._init_plugins() + count = ctypes.c_ulonglong() + types = core.BNGetBinaryViewTypes(count) + result = [] + for i in xrange(0, count.value): + result.append(BinaryViewType(types[i])) + core.BNFreeBinaryViewTypeList(types) + return result + + def __iter__(self): + startup._init_plugins() + count = ctypes.c_ulonglong() + types = core.BNGetBinaryViewTypes(count) + try: + for i in xrange(0, count.value): + yield BinaryViewType(types[i]) + finally: + core.BNFreeBinaryViewTypeList(types) + + def __getitem__(self, value): + startup._init_plugins() + view_type = core.BNGetBinaryViewTypeByName(str(value)) + if view_type is None: + raise KeyError("'%s' is not a valid view type" % str(value)) + return BinaryViewType(view_type) + + def __setattr__(self, name, value): + try: + type.__setattr__(self, name, value) + except AttributeError: + raise AttributeError("attribute '%s' is read only" % name) + + +class BinaryViewType(object): + __metaclass__ = _BinaryViewTypeMetaclass + + def __init__(self, handle): + self.handle = core.handle_of_type(handle, core.BNBinaryViewType) + + @property + def name(self): + """Binary View name (read-only)""" + return core.BNGetBinaryViewTypeName(self.handle) + + @property + def long_name(self): + """BinaryView long name (read-only)""" + return core.BNGetBinaryViewTypeLongName(self.handle) + + def __repr__(self): + return "" % self.name + + def create(self, data): + view = core.BNCreateBinaryViewOfType(self.handle, data.handle) + if view is None: + return None + return BinaryView(file_metadata=data.file, handle=view) + + def open(self, src, file_metadata=None): + data = BinaryView.open(src, file_metadata) + if data is None: + return None + return self.create(data) + + def is_valid_for_data(self, data): + return core.BNIsBinaryViewTypeValidForData(self.handle, data.handle) + + def register_arch(self, ident, endian, arch): + core.BNRegisterArchitectureForViewType(self.handle, ident, endian, arch.handle) + + def get_arch(self, ident, endian): + arch = core.BNGetArchitectureForViewType(self.handle, ident, endian) + if arch is None: + return None + return architecture.Architecture(arch) + + def register_platform(self, ident, arch, plat): + core.BNRegisterPlatformForViewType(self.handle, ident, arch.handle, plat.handle) + + def register_default_platform(self, arch, plat): + core.BNRegisterDefaultPlatformForViewType(self.handle, arch.handle, plat.handle) + + def get_platform(self, ident, arch): + plat = core.BNGetPlatformForViewType(self.handle, ident, arch.handle) + if plat is None: + return None + return platform.Platform(None, plat) + + def __setattr__(self, name, value): + try: + object.__setattr__(self, name, value) + except AttributeError: + raise AttributeError("attribute '%s' is read only" % name) + + +class Segment(object): + def __init__(self, start, length, data_offset, data_length, flags): + self.start = start + self.length = length + self.data_offset = data_offset + self.data_length = data_length + self.flags = flags + + @property + def end(self): + return self.start + self.length + + def __len__(self): + return self.length + + def __repr__(self): + return "" % (self.start, self.end, + "r" if (self.flags & core.BNSegmentFlag.SegmentReadable) != 0 else "-", + "w" if (self.flags & core.BNSegmentFlag.SegmentWritable) != 0 else "-", + "x" if (self.flags & core.BNSegmentFlag.SegmentExecutable) != 0 else "-") + + +class Section(object): + def __init__(self, name, section_type, start, length, linked_section, info_section, info_data, align, entry_size): + self.name = name + self.type = section_type + self.start = start + self.length = length + self.linked_section = linked_section + self.info_section = info_section + self.info_data = info_data + self.align = align + self.entry_size = entry_size + + @property + def end(self): + return self.start + self.length + + def __len__(self): + return self.length + + def __repr__(self): + return "
" % (self.name, self.start, self.end) + + +class AddressRange(object): + def __init__(self, start, end): + self.start = start + self.end = end + + @property + def length(self): + return self.end - self.start + + def __len__(self): + return self.end - self.start + + def __repr__(self): + return "<%#x-%#x>" % (self.start, self.end) + + +class _BinaryViewAssociatedDataStore(associateddatastore._AssociatedDataStore): + _defaults = {} + + +class BinaryView(object): + """ + ``class BinaryView`` implements a view on binary data, and presents a queryable interface of a binary file. One key + job of BinaryView is file format parsing which allows Binary Ninja to read, write, insert, remove portions + of the file given a virtual address. For the purposes of this documentation we define a virtual address as the + memory address that the various pieces of the physical file will be loaded at. + + A binary file does not have to have just one BinaryView, thus much of the interface to manipulate disassembly exists + within or is accessed through a BinaryView. All files are guaranteed to have at least the ``Raw`` BinaryView. The + ``Raw`` BinaryView is simply a hex editor, but is helpful for manipulating binary files via their absolute addresses. + + BinaryViews are plugins and thus registered with Binary Ninja at startup, and thus should **never** be instantiated + directly as this is already done. The list of available BinaryViews can be seen in the BinaryViewType class which + provides an iterator and map of the various installed BinaryViews:: + + >>> list(BinaryViewType) + [, , , ] + >>> BinaryViewType['ELF'] + + + To open a file with a given BinaryView the following code can be used:: + + >>> bv = BinaryViewType['Mach-O'].open("/bin/ls") + >>> bv + + + `By convention in the rest of this document we will use bv to mean an open BinaryView of an executable file.` + When a BinaryView is open on an executable view, analysis does not automatically run, this can be done by running + the ``update_analysis_and_wait()`` method which disassembles the executable and returns when all disassembly is + finished:: + + >>> bv.update_analysis_and_wait() + >>> + + Since BinaryNinja's analysis is multi-threaded (depending on version) this can also be done in the background by + using the ``update_analysis()`` method instead. + + By standard python convention methods which start with '_' should be considered private and should not be called + externally. Additionanlly, methods which begin with ``perform_`` should not be called either and are + used explicitly for subclassing the BinaryView. + + .. note:: An important note on the ``*_user_*()`` methods. Binary Ninja makes a distinction between edits \ + performed by the user and actions performed by auto analysis. Auto analysis actions that can quickly be recalculated \ + are not saved to the database. Auto analysis actions that take a long time and all user edits are stored in the \ + database (e.g. ``remove_user_function()`` rather than ``remove_function()``). Thus use ``_user_`` methods if saving \ + to the database is desired. + """ + name = None + long_name = None + _registered = False + _registered_cb = None + registered_view_type = None + next_address = 0 + _associated_data = {} + + def __init__(self, file_metadata=None, parent_view=None, handle=None): + if handle is not None: + self.handle = core.handle_of_type(handle, core.BNBinaryView) + if file_metadata is None: + self.file = filemetadata.FileMetadata(handle=core.BNGetFileForView(handle)) + else: + self.file = file_metadata + elif self.__class__ is BinaryView: + startup._init_plugins() + if file_metadata is None: + file_metadata = filemetadata.FileMetadata() + self.handle = core.BNCreateBinaryDataView(file_metadata.handle) + self.file = filemetadata.FileMetadata(handle=core.BNNewFileReference(file_metadata)) + else: + startup._init_plugins() + if not self.__class__._registered: + raise TypeError("view type not registered") + self._cb = core.BNCustomBinaryView() + self._cb.context = 0 + self._cb.init = self._cb.init.__class__(self._init) + self._cb.read = self._cb.read.__class__(self._read) + self._cb.write = self._cb.write.__class__(self._write) + self._cb.insert = self._cb.insert.__class__(self._insert) + self._cb.remove = self._cb.remove.__class__(self._remove) + self._cb.getModification = self._cb.getModification.__class__(self._get_modification) + self._cb.isValidOffset = self._cb.isValidOffset.__class__(self._is_valid_offset) + self._cb.isOffsetReadable = self._cb.isOffsetReadable.__class__(self._is_offset_readable) + self._cb.isOffsetWritable = self._cb.isOffsetWritable.__class__(self._is_offset_writable) + self._cb.isOffsetExecutable = self._cb.isOffsetExecutable.__class__(self._is_offset_executable) + self._cb.getNextValidOffset = self._cb.getNextValidOffset.__class__(self._get_next_valid_offset) + self._cb.getStart = self._cb.getStart.__class__(self._get_start) + self._cb.getLength = self._cb.getLength.__class__(self._get_length) + self._cb.getEntryPoint = self._cb.getEntryPoint.__class__(self._get_entry_point) + self._cb.isExecutable = self._cb.isExecutable.__class__(self._is_executable) + self._cb.getDefaultEndianness = self._cb.getDefaultEndianness.__class__(self._get_default_endianness) + self._cb.getAddressSize = self._cb.getAddressSize.__class__(self._get_address_size) + self._cb.save = self._cb.save.__class__(self._save) + self.file = file_metadata + if parent_view is not None: + parent_view = parent_view.handle + self.handle = core.BNCreateCustomBinaryView(self.__class__.name, file_metadata.handle, parent_view, self._cb) + self.notifications = {} + self.next_address = None # Do NOT try to access view before init() is called, use placeholder + + @classmethod + def register(cls): + startup._init_plugins() + if cls.name is None: + raise ValueError("view 'name' not defined") + if cls.long_name is None: + cls.long_name = cls.name + cls._registered_cb = core.BNCustomBinaryViewType() + cls._registered_cb.context = 0 + cls._registered_cb.create = cls._registered_cb.create.__class__(cls._create) + cls._registered_cb.isValidForData = cls._registered_cb.isValidForData.__class__(cls._is_valid_for_data) + cls.registered_view_type = BinaryViewType(core.BNRegisterBinaryViewType(cls.name, cls.long_name, cls._registered_cb)) + cls._registered = True + + @classmethod + def _create(cls, ctxt, data): + try: + file_metadata = filemetadata.FileMetadata(handle=core.BNGetFileForView(data)) + view = cls(BinaryView(file_metadata=file_metadata, handle=core.BNNewViewReference(data))) + if view is None: + return None + return ctypes.cast(core.BNNewViewReference(view.handle), ctypes.c_void_p).value + except: + log.log_error(traceback.format_exc()) + return None + + @classmethod + def _is_valid_for_data(cls, ctxt, data): + try: + return cls.is_valid_for_data(BinaryView(handle=core.BNNewViewReference(data))) + except: + log.log_error(traceback.format_exc()) + return False + + @classmethod + def open(cls, src, file_metadata=None): + startup._init_plugins() + if isinstance(src, fileaccessor.FileAccessor): + if file_metadata is None: + file_metadata = filemetadata.FileMetadata() + view = core.BNCreateBinaryDataViewFromFile(file_metadata.handle, src._cb) + else: + if file_metadata is None: + file_metadata = filemetadata.FileMetadata(str(src)) + view = core.BNCreateBinaryDataViewFromFilename(file_metadata.handle, str(src)) + if view is None: + return None + result = BinaryView(file_metadata=file_metadata, handle=view) + return result + + @classmethod + def new(cls, data=None, file_metadata=None): + startup._init_plugins() + if file_metadata is None: + file_metadata = filemetadata.FileMetadata() + if data is None: + view = core.BNCreateBinaryDataView(file_metadata.handle) + else: + buf = databuffer.DataBuffer(data) + view = core.BNCreateBinaryDataViewFromBuffer(file_metadata.handle, buf.handle) + if view is None: + return None + result = BinaryView(file_metadata=file_metadata, handle=view) + return result + + @classmethod + def _unregister(cls, view): + handle = ctypes.cast(view, ctypes.c_void_p) + if handle.value in cls._associated_data: + del cls._associated_data[handle.value] + + @classmethod + def set_default_session_data(cls, name, value): + _BinaryViewAssociatedDataStore.set_default(name, value) + + def __del__(self): + for i in self.notifications.values(): + i._unregister() + core.BNFreeBinaryView(self.handle) + + def __iter__(self): + count = ctypes.c_ulonglong(0) + funcs = core.BNGetAnalysisFunctionList(self.handle, count) + try: + for i in xrange(0, count.value): + yield function.Function(self, core.BNNewFunctionReference(funcs[i])) + finally: + core.BNFreeFunctionList(funcs, count.value) + + @property + def parent_view(self): + """View that contains the raw data used by this view (read-only)""" + result = core.BNGetParentView(self.handle) + if result is None: + return None + return BinaryView(handle=result) + + @property + def modified(self): + """boolean modification state of the BinaryView (read/write)""" + return self.file.modified + + @modified.setter + def modified(self, value): + self.file.modified = value + + @property + def analysis_changed(self): + """boolean analysis state changed of the currently running analysis (read-only)""" + return self.file.analysis_changed + + @property + def has_database(self): + """boolean has a database been written to disk (read-only)""" + return self.file.has_database + + @property + def view(self): + return self.file.view + + @view.setter + def view(self, value): + self.file.view = value + + @property + def offset(self): + return self.file.offset + + @offset.setter + def offset(self, value): + self.file.offset = value + + @property + def start(self): + """Start offset of the binary (read-only)""" + return core.BNGetStartOffset(self.handle) + + @property + def end(self): + """End offset of the binary (read-only)""" + return core.BNGetEndOffset(self.handle) + + @property + def entry_point(self): + """Entry point of the binary (read-only)""" + return core.BNGetEntryPoint(self.handle) + + @property + def arch(self): + """The architecture associated with the current BinaryView (read/write)""" + arch = core.BNGetDefaultArchitecture(self.handle) + if arch is None: + return None + return architecture.Architecture(handle=arch) + + @arch.setter + def arch(self, value): + if value is None: + core.BNSetDefaultArchitecture(self.handle, None) + else: + core.BNSetDefaultArchitecture(self.handle, value.handle) + + @property + def platform(self): + """The platform associated with the current BinaryView (read/write)""" + plat = core.BNGetDefaultPlatform(self.handle) + if plat is None: + return None + return platform.Platform(self.arch, handle=plat) + + @platform.setter + def platform(self, value): + if value is None: + core.BNSetDefaultPlatform(self.handle, None) + else: + core.BNSetDefaultPlatform(self.handle, value.handle) + + @property + def endianness(self): + """Endianness of the binary (read-only)""" + return core.BNGetDefaultEndianness(self.handle) + + @property + def address_size(self): + """Address size of the binary (read-only)""" + return core.BNGetViewAddressSize(self.handle) + + @property + def executable(self): + """Whether the binary is an executable (read-only)""" + return core.BNIsExecutableView(self.handle) + + @property + def functions(self): + """List of functions (read-only)""" + count = ctypes.c_ulonglong(0) + funcs = core.BNGetAnalysisFunctionList(self.handle, count) + result = [] + for i in xrange(0, count.value): + result.append(function.Function(self, core.BNNewFunctionReference(funcs[i]))) + core.BNFreeFunctionList(funcs, count.value) + return result + + @property + def has_functions(self): + """Boolean whether the binary has functions (read-only)""" + return core.BNHasFunctions(self.handle) + + @property + def entry_function(self): + """Entry function (read-only)""" + func = core.BNGetAnalysisEntryPoint(self.handle) + if func is None: + return None + return function.Function(self, func) + + @property + def symbols(self): + """Dict of symbols (read-only)""" + count = ctypes.c_ulonglong(0) + syms = core.BNGetSymbols(self.handle, count) + result = {} + for i in xrange(0, count.value): + sym = function.Symbol(None, None, None, handle=core.BNNewSymbolReference(syms[i])) + result[sym.raw_name] = sym + core.BNFreeSymbolList(syms, count.value) + return result + + @property + def view_type(self): + """View type (read-only)""" + return core.BNGetViewType(self.handle) + + @property + def available_view_types(self): + """Available view types (read-only)""" + count = ctypes.c_ulonglong(0) + types = core.BNGetBinaryViewTypesForData(self.handle, count) + result = [] + for i in xrange(0, count.value): + result.append(BinaryViewType(types[i])) + core.BNFreeBinaryViewTypeList(types) + return result + + @property + def strings(self): + """List of strings (read-only)""" + return self.get_strings() + + @property + def saved(self): + """boolean state of whether or not the file has been saved (read/write)""" + return self.file.saved + + @saved.setter + def saved(self, value): + self.file.saved = value + + @property + def analysis_progress(self): + """Status of current analysis (read-only)""" + result = core.BNGetAnalysisProgress(self.handle) + return AnalysisProgress(result.state, result.count, result.total) + + @property + def linear_disassembly(self): + """Iterator for all lines in the linear disassembly of the view""" + return self.get_linear_disassembly(None) + + @property + def data_vars(self): + """List of data variables (read-only)""" + count = ctypes.c_ulonglong(0) + var_list = core.BNGetDataVariables(self.handle, count) + result = {} + for i in xrange(0, count.value): + addr = var_list[i].address + var_type = bntype.Type(core.BNNewTypeReference(var_list[i].type)) + auto_discovered = var_list[i].autoDiscovered + result[addr] = DataVariable(addr, var_type, auto_discovered) + core.BNFreeDataVariables(var_list, count.value) + return result + + @property + def types(self): + """List of defined types (read-only)""" + count = ctypes.c_ulonglong(0) + type_list = core.BNGetAnalysisTypeList(self.handle, count) + result = {} + for i in xrange(0, count.value): + result[type_list[i].name] = bntype.Type(core.BNNewTypeReference(type_list[i].type)) + core.BNFreeTypeList(type_list, count.value) + return result + + @property + def segments(self): + """List of segments (read-only)""" + count = ctypes.c_ulonglong(0) + segment_list = core.BNGetSegments(self.handle, count) + result = [] + for i in xrange(0, count.value): + result.append(Segment(segment_list[i].start, segment_list[i].length, + segment_list[i].dataOffset, segment_list[i].dataLength, segment_list[i].flags)) + core.BNFreeSegmentList(segment_list) + return result + + @property + def sections(self): + """List of sections (read-only)""" + count = ctypes.c_ulonglong(0) + section_list = core.BNGetSections(self.handle, count) + result = {} + for i in xrange(0, count.value): + result[section_list[i].name] = Section(section_list[i].name, section_list[i].type, section_list[i].start, + section_list[i].length, section_list[i].linkedSection, section_list[i].infoSection, + section_list[i].infoData, section_list[i].align, section_list[i].entrySize) + core.BNFreeSectionList(section_list, count.value) + return result + + @property + def allocated_ranges(self): + """List of valid address ranges for this view (read-only)""" + count = ctypes.c_ulonglong(0) + range_list = core.BNGetAllocatedRanges(self.handle, count) + result = [] + for i in xrange(0, count.value): + result.append(AddressRange(range_list[i].start, range_list[i].end)) + core.BNFreeAddressRanges(range_list) + return result + + @property + def session_data(self): + """Dictionary object where plugins can store arbitrary data associated with the view""" + handle = ctypes.cast(self.handle, ctypes.c_void_p) + if handle.value not in BinaryView._associated_data: + obj = _BinaryViewAssociatedDataStore() + BinaryView._associated_data[handle.value] = obj + return obj + else: + return BinaryView._associated_data[handle.value] + + def __len__(self): + return int(core.BNGetViewLength(self.handle)) + + def __getitem__(self, i): + if isinstance(i, tuple): + result = "" + for s in i: + result += self.__getitem__(s) + return result + elif isinstance(i, slice): + if i.step is not None: + raise IndexError("step not implemented") + i = i.indices(self.end) + start = i[0] + stop = i[1] + if stop <= start: + return "" + return str(self.read(start, stop - start)) + elif i < 0: + if i >= -len(self): + value = str(self.read(int(len(self) + i), 1)) + if len(value) == 0: + return IndexError("index not readable") + return value + raise IndexError("index out of range") + elif (i >= self.start) and (i < self.end): + value = str(self.read(int(i), 1)) + if len(value) == 0: + return IndexError("index not readable") + return value + else: + raise IndexError("index out of range") + + def __setitem__(self, i, value): + if isinstance(i, slice): + if i.step is not None: + raise IndexError("step not supported on assignment") + i = i.indices(self.end) + start = i[0] + stop = i[1] + if stop < start: + stop = start + if len(value) != (stop - start): + self.remove(start, stop - start) + self.insert(start, value) + else: + self.write(start, value) + elif i < 0: + if i >= -len(self): + if len(value) != 1: + raise ValueError("expected single byte for assignment") + if self.write(int(len(self) + i), value) != 1: + raise IndexError("index not writable") + else: + raise IndexError("index out of range") + elif (i >= self.start) and (i < self.end): + if len(value) != 1: + raise ValueError("expected single byte for assignment") + if self.write(int(i), value) != 1: + raise IndexError("index not writable") + else: + raise IndexError("index out of range") + + def __repr__(self): + start = self.start + length = len(self) + if start != 0: + size = "start %#x, len %#x" % (start, length) + else: + size = "len %#x" % length + filename = self.file.filename + if len(filename) > 0: + return "" % (filename, size) + return "" % (size) + + def _init(self, ctxt): + try: + return self.init() + except: + log.log_error(traceback.format_exc()) + return False + + def _read(self, ctxt, dest, offset, length): + try: + data = self.perform_read(offset, length) + if data is None: + return 0 + if len(data) > length: + data = data[0:length] + ctypes.memmove(dest, str(data), len(data)) + return len(data) + except: + log.log_error(traceback.format_exc()) + return 0 + + def _write(self, ctxt, offset, src, length): + try: + data = ctypes.create_string_buffer(length) + ctypes.memmove(data, src, length) + return self.perform_write(offset, data.raw) + except: + log.log_error(traceback.format_exc()) + return 0 + + def _insert(self, ctxt, offset, src, length): + try: + data = ctypes.create_string_buffer(length) + ctypes.memmove(data, src, length) + return self.perform_insert(offset, data.raw) + except: + log.log_error(traceback.format_exc()) + return 0 + + def _remove(self, ctxt, offset, length): + try: + return self.perform_remove(offset, length) + except: + log.log_error(traceback.format_exc()) + return 0 + + def _get_modification(self, ctxt, offset): + try: + return self.perform_get_modification(offset) + except: + log.log_error(traceback.format_exc()) + return core.BNModificationStatus.Original + + def _is_valid_offset(self, ctxt, offset): + try: + return self.perform_is_valid_offset(offset) + except: + log.log_error(traceback.format_exc()) + return False + + def _is_offset_readable(self, ctxt, offset): + try: + return self.perform_is_offset_readable(offset) + except: + log.log_error(traceback.format_exc()) + return False + + def _is_offset_writable(self, ctxt, offset): + try: + return self.perform_is_offset_writable(offset) + except: + log.log_error(traceback.format_exc()) + return False + + def _is_offset_executable(self, ctxt, offset): + try: + return self.perform_is_offset_executable(offset) + except: + log.log_error(traceback.format_exc()) + return False + + def _get_next_valid_offset(self, ctxt, offset): + try: + return self.perform_get_next_valid_offset(offset) + except: + log.log_error(traceback.format_exc()) + return offset + + def _get_start(self, ctxt): + try: + return self.perform_get_start() + except: + log.log_error(traceback.format_exc()) + return 0 + + def _get_length(self, ctxt): + try: + return self.perform_get_length() + except: + log.log_error(traceback.format_exc()) + return 0 + + def _get_entry_point(self, ctxt): + try: + return self.perform_get_entry_point() + except: + log.log_error(traceback.format_exc()) + return 0 + + def _is_executable(self, ctxt): + try: + return self.perform_is_executable() + except: + log.log_error(traceback.format_exc()) + return False + + def _get_default_endianness(self, ctxt): + try: + return self.perform_get_default_endianness() + except: + log.log_error(traceback.format_exc()) + return core.BNEndianness.LittleEndian + + def _get_address_size(self, ctxt): + try: + return self.perform_get_address_size() + except: + log.log_error(traceback.format_exc()) + return 8 + + def _save(self, ctxt, file_accessor): + try: + return self.perform_save(fileaccessor.CoreFileAccessor(file_accessor)) + except: + log.log_error(traceback.format_exc()) + return False + + 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, ``self.arch`` is used if this parameter is None + :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 Architecture arch: optional Architecture, ``self.arch`` is used if this parameter is None + :return: a str representation of the instruction at virtual address ``self.next_address`` + :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 + if self.next_address is None: + self.next_address = self.entry_point + 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_save(self, accessor): + if self.parent_view is not None: + return self.parent_view.save(accessor) + return False + + @abc.abstractmethod + def perform_get_address_size(self): + raise NotImplementedError + + def perform_get_length(self): + """ + ``perform_get_length`` implements a query for the size of the virtual address range used by + the BinaryView. + + .. note:: This method **may** be overridden by custom BinaryViews. Use ``add_auto_segment`` to provide + data without overriding this method. + .. warning:: This method **must not** be called directly. + + :return: returns the size of the virtual address range used by the BinaryView. + :rtype: int + """ + return 0 + + def perform_read(self, addr, length): + """ + ``perform_read`` implements a mapping between a virtual address and an absolute file offset, reading + ``length`` bytes from the rebased address ``addr``. + + .. note:: This method **may** be overridden by custom BinaryViews. Use ``add_auto_segment`` to provide + data without overriding this method. + .. warning:: 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 + :rtype: str + """ + return "" + + def perform_write(self, addr, data): + """ + ``perform_write`` implements a mapping between a virtual address and an absolute file offset, writing + the bytes ``data`` to rebased address ``addr``. + + .. note:: This method **may** be overridden by custom BinaryViews. Use ``add_auto_segment`` to provide + data without overriding this method. + .. warning:: This method **must not** be called directly. + + :param int addr: a virtual address + :param str data: the data to be written + :return: length of data written, should return 0 on error + :rtype: int + """ + return 0 + + def perform_insert(self, addr, data): + """ + ``perform_insert`` implements a mapping between a virtual address and an absolute file offset, inserting + the bytes ``data`` to rebased address ``addr``. + + .. note:: This method **may** be overridden by custom BinaryViews. If not overridden, inserting is disallowed + .. warning:: This method **must not** be called directly. + + :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 0 + + def perform_remove(self, addr, length): + """ + ``perform_remove`` implements a mapping between a virtual address and an absolute file offset, removing + ``length`` bytes from the rebased address ``addr``. + + .. note:: This method **may** be overridden by custom BinaryViews. If not overridden, removing data is disallowed + .. warning:: 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 0 + + def perform_get_modification(self, addr): + """ + ``perform_get_modification`` implements query to the whether the virtual address ``addr`` is modified. + + .. note:: This method **may** be overridden by custom BinaryViews. Use ``add_auto_segment`` to provide + data without overriding this method. + .. warning:: This method **must not** be called directly. + + :param int addr: a virtual address to be checked + :return: One of the following: Original = 0, Changed = 1, Inserted = 2 + :rtype: BNModificationStatus + """ + return core.BNModificationStatus.Original + + def perform_is_valid_offset(self, addr): + """ + ``perform_is_valid_offset`` implements a check if an virtual address ``addr`` is valid. + + .. note:: This method **may** be overridden by custom BinaryViews. Use ``add_auto_segment`` to provide + data without overriding this method. + .. warning:: This method **must not** be called directly. + + :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 + """ + data = self.read(addr, 1) + return (data is not None) and (len(data) == 1) + + def perform_is_offset_readable(self, offset): + """ + ``perform_is_offset_readable`` implements a check if an virtual address is readable. + + .. note:: This method **may** be overridden by custom BinaryViews. Use ``add_auto_segment`` to provide + data without overriding this method. + .. warning:: This method **must not** be called directly. + + :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(offset) + + def perform_is_offset_writable(self, addr): + """ + ``perform_is_offset_writable`` implements a check if a virtual address ``addr`` is writable. + + .. note:: This method **may** be overridden by custom BinaryViews. Use ``add_auto_segment`` to provide + data without overriding this method. + .. warning:: This method **must not** be called directly. + + :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: bool + """ + return self.is_valid_offset(addr) + + def perform_is_offset_executable(self, addr): + """ + ``perform_is_offset_writable`` implements a check if a virtual address ``addr`` is executable. + + .. note:: This method **may** be overridden by custom BinaryViews. Use ``add_auto_segment`` to provide + data without overriding this method. + .. warning:: This method **must not** be called directly. + + :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 self.is_valid_offset(addr) + + def perform_get_next_valid_offset(self, addr): + """ + ``perform_get_next_valid_offset`` implements a query for the next valid readable, writable, or executable virtual + memory address. + + .. note:: This method **may** be overridden by custom BinaryViews. Use ``add_auto_segment`` to provide + data without overriding this method. + .. warning:: This method **must not** be called directly. + + :param int addr: a virtual address to start checking from. + :return: the next readable, writable, or executable virtual memory address + :rtype: int + """ + if addr < self.perform_get_start(): + return self.perform_get_start() + return addr + + def perform_get_start(self): + """ + ``perform_get_start`` implements a query for the first readable, writable, or executable virtual address in + the BinaryView. + + .. note:: This method **may** be overridden by custom BinaryViews. Use ``add_auto_segment`` to provide + data without overriding this method. + .. warning:: This method **must not** be called directly. + + :return: returns the first virtual address in the BinaryView. + :rtype: int + """ + return 0 + + def perform_get_entry_point(self): + """ + ``perform_get_entry_point`` implements a query for the initial entry point for code execution. + + .. note:: This method **should** be implmented for custom BinaryViews that are executable. + .. warning:: This method **must not** be called directly. + + :return: the virtual address of the entry point + :rtype: int + """ + return 0 + + def perform_is_executable(self): + """ + ``perform_is_executable`` implements a check which returns true if the BinaryView is executable. + + .. note:: This method **must** be implemented for custom BinaryViews that are executable. + .. warning:: This method **must not** be called directly. + + :return: true if the current BinaryView is executable, false if it is not executable or on error + :rtype: bool + """ + return False + + def perform_get_default_endianness(self): + """ + ``perform_get_default_endianness`` implements a check which returns true if the BinaryView is executable. + + .. note:: This method **may** be implemented for custom BinaryViews that are not LittleEndian. + .. warning:: This method **must not** be called directly. + + :return: either ``core.BNEndianness.LittleEndian`` or ``core.BNEndianness.BigEndian`` + :rtype: BNEndianness + """ + return core.BNEndianness.LittleEndian + + def create_database(self, filename, progress_func=None): + """ + ``perform_get_database`` writes the current database (.bndb) file out to the specified file. + + :param str filename: path and filename to write the bndb to, this string `should` have ".bndb" appended to it. + :param callable() progress_func: optional function to be called with the current progress and total count. + :return: true on success, false on failure + :rtype: bool + """ + return self.file.create_database(filename, progress_func) + + def save_auto_snapshot(self, progress_func=None): + """ + ``save_auto_snapshot`` saves the current database to the already created file. + + .. note:: :py:method:`create_database` should have been called prior to executing this method + + :param callable() progress_func: optional function to be called with the current progress and total count. + :return: True if it successfully saved the snapshot, False otherwise + :rtype: bool + """ + return self.file.save_auto_snapshot(progress_func) + + def get_view_of_type(self, name): + """ + ``get_view_of_type`` returns the BinaryView associated with the provided name if it exists. + + :param str name: Name of the view to be retrieved + :return: BinaryView object assocated with the provided name or None on failure + :rtype: BinaryView or None + """ + return self.file.get_view_of_type(name) + + def begin_undo_actions(self): + """ + ``begin_undo_actions`` start recording actions taken so the can be undone at some point. + + :rtype: None + :Example: + + >>> bv.get_disassembly(0x100012f1) + 'xor eax, eax' + >>> bv.begin_undo_actions() + >>> bv.convert_to_nop(bv.arch, 0x100012f1) + True + >>> bv.commit_undo_actions() + >>> bv.get_disassembly(0x100012f1) + 'nop' + >>> bv.undo() + >>> bv.get_disassembly(0x100012f1) + 'xor eax, eax' + >>> + """ + self.file.begin_undo_actions() + + def add_undo_action(self, action): + core.BNAddUndoAction(self.handle, action.__class__.name, action._cb) + + def commit_undo_actions(self): + """ + ``commit_undo_actions`` commit the actions taken since the last commit to the undo database. + + :rtype: None + :Example: + + >>> bv.get_disassembly(0x100012f1) + 'xor eax, eax' + >>> bv.begin_undo_actions() + >>> bv.convert_to_nop(bv.arch, 0x100012f1) + True + >>> bv.commit_undo_actions() + >>> bv.get_disassembly(0x100012f1) + 'nop' + >>> bv.undo() + >>> bv.get_disassembly(0x100012f1) + 'xor eax, eax' + >>> + """ + self.file.commit_undo_actions() + + def undo(self): + """ + ``undo`` undo the last commited action in the undo database. + + :rtype: None + :Example: + + >>> bv.get_disassembly(0x100012f1) + 'xor eax, eax' + >>> bv.begin_undo_actions() + >>> bv.convert_to_nop(bv.arch, 0x100012f1) + True + >>> bv.commit_undo_actions() + >>> bv.get_disassembly(0x100012f1) + 'nop' + >>> bv.undo() + >>> bv.get_disassembly(0x100012f1) + 'xor eax, eax' + >>> bv.redo() + >>> bv.get_disassembly(0x100012f1) + 'nop' + >>> + """ + self.file.undo() + + def redo(self): + """ + ``redo`` redo the last commited action in the undo database. + + :rtype: None + :Example: + + >>> bv.get_disassembly(0x100012f1) + 'xor eax, eax' + >>> bv.begin_undo_actions() + >>> bv.convert_to_nop(bv.arch, 0x100012f1) + True + >>> bv.commit_undo_actions() + >>> bv.get_disassembly(0x100012f1) + 'nop' + >>> bv.undo() + >>> bv.get_disassembly(0x100012f1) + 'xor eax, eax' + >>> bv.redo() + >>> bv.get_disassembly(0x100012f1) + 'nop' + >>> + """ + self.file.redo() + + def navigate(self, view, offset): + self.file.navigate(view, offset) + + def read(self, addr, length): + """ + ``read`` returns the data reads at most ``length`` bytes from virtual address ``addr``. + + :param int addr: virtual address to read from. + :param int length: number of bytes to read. + :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\' + """ + buf = databuffer.DataBuffer(handle=core.BNReadViewBuffer(self.handle, addr, length)) + return str(buf) + + def write(self, addr, data): + """ + ``write`` writes the bytes in ``data`` to the virtual address ``addr``. + + :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: + + >>> bv.read(0,4) + 'BBBB' + >>> bv.write(0, "AAAA") + 4L + >>> bv.read(0,4) + 'AAAA' + """ + buf = databuffer.DataBuffer(data) + return core.BNWriteViewBuffer(self.handle, addr, buf.handle) + + def insert(self, addr, data): + """ + ``insert`` inserts the bytes in ``data`` to the virtual address ``addr``. + + :param int addr: virtual address to write to. + :param str data: data to be inserted at addr. + :return: number of bytes inserted to virtual address ``addr`` + :rtype: int + :Example: + + >>> bv.insert(0,"BBBB") + 4L + >>> bv.read(0,8) + 'BBBBAAAA' + """ + buf = databuffer.DataBuffer(data) + return core.BNInsertViewBuffer(self.handle, addr, buf.handle) + + def remove(self, addr, length): + """ + ``remove`` removes at most ``length`` bytes from virtual address ``addr``. + + :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: + + >>> bv.read(0,8) + 'BBBBAAAA' + >>> bv.remove(0,4) + 4L + >>> bv.read(0,4) + 'AAAA' + """ + return core.BNRemoveViewData(self.handle, addr, length) + + 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, addr) + data = (core.BNModificationStatus * length)() + length = core.BNGetModificationArray(self.handle, addr, data, length) + return data[0:length] + + def is_valid_offset(self, addr): + """ + ``is_valid_offset`` checks if an virtual address ``addr`` is valid . + + :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_readable(self, addr): + """ + ``is_offset_readable`` checks if an virtual address ``addr`` is valid for reading. + + :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_offset_writable`` 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_offset_executable`` 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 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.FileAccessor): + return core.BNSaveToFile(self.handle, dest._cb) + return core.BNSaveToFilename(self.handle, str(dest)) + + def register_notification(self, notify): + cb = BinaryDataNotificationCallbacks(self, notify) + cb._register() + self.notifications[notify] = cb + + def unregister_notification(self, notify): + if notify in self.notifications: + self.notifications[notify]._unregister() + del self.notifications[notify] + + def add_function(self, plat, addr): + """ + ``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 + :rtype: None + :Example: + + >>> bv.add_function(bv.plat, 1) + >>> bv.functions + [] + + """ + core.BNAddFunctionForAnalysis(self.handle, plat.handle, addr) + + def add_entry_point(self, plat, addr): + """ + ``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 + :rtype: None + :Example: + >>> bv.add_entry_point(bv.plat, 0xdeadbeef) + >>> + """ + core.BNAddEntryPointForAnalysis(self.handle, plat.handle, addr) + + def remove_function(self, func): + """ + ``remove_function`` removes the function ``func`` from the list of functions + + :param Function func: a Function object. + :rtype: None + :Example: + + >>> bv.functions + [] + >>> bv.remove_function(bv.functions[0]) + >>> bv.functions + [] + """ + core.BNRemoveAnalysisFunction(self.handle, func.handle) + + def create_user_function(self, plat, addr): + """ + ``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 + :rtype: None + :Example: + + >>> bv.create_user_function(bv.plat, 1) + >>> bv.functions + [] + + """ + core.BNCreateUserFunction(self.handle, plat.handle, addr) + + def remove_user_function(self, func): + """ + ``remove_user_function`` removes the *user* function ``func`` from the list of functions + + :param Function func: a Function object. + :rtype: None + :Example: + + >>> bv.functions + [] + >>> bv.remove_user_function(bv.functions[0]) + >>> bv.functions + [] + """ + core.BNRemoveUserFunction(self.handle, func.handle) + + def update_analysis(self): + """ + ``update_analysis`` asynchronously starts the analysis running and returns immediately. Analysis of BinaryViews + does not occur automatically, the user must start analysis by calling either ``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. + + :rtype: None + """ + core.BNUpdateAnalysis(self.handle) + + def update_analysis_and_wait(self): + """ + ``update_analysis_and_wait`` blocking call to update the analysis, this call returns when the analysis is + complete. Analysis of BinaryViews does not occur automatically, the user must start analysis by calling either + ``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. + + :rtype: None + """ + class WaitEvent: + def __init__(self): + self.cond = threading.Condition() + self.done = False + + def complete(self): + self.cond.acquire() + self.done = True + self.cond.notify() + self.cond.release() + + def wait(self): + self.cond.acquire() + while not self.done: + self.cond.wait() + self.cond.release() + + wait = WaitEvent() + # TODO: figure out if we actually need this 'event' variable, likely we do + event = AnalysisCompletionEvent(self, lambda: wait.complete()) + core.BNUpdateAnalysis(self.handle) + wait.wait() + + def abort_analysis(self): + """ + ``abort_analysis`` will abort the currently running analysis. + + :rtype: None + """ + core.BNAbortAnalysis(self.handle) + + def define_data_var(self, addr, var_type): + """ + ``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 Type var_type: type to be defined at the given virtual address + :rtype: None + :Example: + + >>> t = bv.parse_type_string("int foo") + >>> 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 + :rtype: None + :Example: + + >>> t = bv.parse_type_string("int foo") + >>> 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 non-user data variable at the virtual address ``addr``. + + :param int addr: virtual address to define the data variable to be removed + :rtype: None + :Example: + + >>> bv.undefine_data_var(bv.entry_point) + >>> + """ + 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 + :rtype: None + :Example: + + >>> bv.undefine_user_data_var(bv.entry_point) + >>> + """ + core.BNUndefineUserDataVariable(self.handle, addr) + + def get_data_var_at(self, addr): + """ + ``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. + :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 = core.BNDataVariable() + if not core.BNGetDataVariableAtAddress(self.handle, addr, var): + return None + return DataVariable(var.address, type.Type(var.type), var.autoDiscovered) + + def get_function_at(self, plat, addr): + """ + ``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 + :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) + + >>> + """ + func = core.BNGetAnalysisFunction(self.handle, plat.handle, addr) + if func is None: + return None + return function.Function(self, func) + + def get_functions_at(self, addr): + """ + ``get_functions_at`` get a list of binaryninja.Function objects (one for each valid plat) at the given + virtual address. Binary Ninja does not limit the number of platforms in a given file thus there may be multiple + functions defined from different architectures at the same location. This API allows you to query all of valid + 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(Function) + """ + count = ctypes.c_ulonglong(0) + funcs = core.BNGetAnalysisFunctionsForAddress(self.handle, addr, count) + result = [] + for i in xrange(0, count.value): + result.append(function.Function(self, core.BNNewFunctionReference(funcs[i]))) + core.BNFreeFunctionList(funcs, count.value) + return result + + def get_recent_function_at(self, addr): + func = core.BNGetRecentAnalysisFunctionForAddress(self.handle, addr) + if func is None: + return None + return function.Function(self, func) + + def get_basic_blocks_at(self, addr): + """ + ``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) + result = [] + for i in xrange(0, count.value): + result.append(basicblock.BasicBlock(self, core.BNNewBasicBlockReference(blocks[i]))) + core.BNFreeBasicBlockList(blocks, count.value) + return result + + def get_basic_blocks_starting_at(self, addr): + """ + ``get_basic_blocks_at`` get a list of :py:Class:`BasicBlock` objects which start 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.BNGetBasicBlocksStartingAtAddress(self.handle, addr, count) + result = [] + for i in xrange(0, count.value): + result.append(basicblock.BasicBlock(self, core.BNNewBasicBlockReference(blocks[i]))) + core.BNFreeBasicBlockList(blocks, count.value) + return result + + def get_recent_basic_block_at(self, addr): + block = core.BNGetRecentBasicBlockForAddress(self.handle, addr) + if block is None: + return None + return basicblock.BasicBlock(self, block) + + def get_code_refs(self, addr, length=None): + count = ctypes.c_ulonglong(0) + if length is None: + refs = core.BNGetCodeReferences(self.handle, addr, count) + else: + refs = core.BNGetCodeReferencesInRange(self.handle, addr, length, count) + result = [] + for i in xrange(0, count.value): + if refs[i].func: + func = function.Function(self, core.BNNewFunctionReference(refs[i].func)) + else: + func = None + if refs[i].arch: + arch = architecture.Architecture(refs[i].arch) + else: + arch = None + addr = refs[i].addr + result.append(architecture.ReferenceSource(func, arch, addr)) + core.BNFreeCodeReferences(refs, count.value) + 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) + + >>> + """ + sym = core.BNGetSymbolByAddress(self.handle, addr) + if sym is None: + return None + return bntype.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') + + >>> + """ + sym = core.BNGetSymbolByRawName(self.handle, name) + if sym is None: + return None + return bntype.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') + [] + >>> + """ + count = ctypes.c_ulonglong(0) + syms = core.BNGetSymbolsByName(self.handle, name, count) + result = [] + for i in xrange(0, count.value): + result.append(bntype.Symbol(None, None, None, handle = core.BNNewSymbolReference(syms[i]))) + core.BNFreeSymbolList(syms, count.value) + 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) + [] + >>> + """ + count = ctypes.c_ulonglong(0) + if start is None: + syms = core.BNGetSymbols(self.handle, count) + else: + syms = core.BNGetSymbolsInRange(self.handle, start, length, count) + result = [] + for i in xrange(0, count.value): + result.append(bntype.Symbol(None, None, None, handle = core.BNNewSymbolReference(syms[i]))) + core.BNFreeSymbolList(syms, count.value) + 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.BNSymbolType.ImportAddressSymbol, 0x10002028, 1) + [] + >>> + """ + if isinstance(sym_type, str): + sym_type = core.BNSymbolType[sym_type] + count = ctypes.c_ulonglong(0) + if start is None: + syms = core.BNGetSymbolsOfType(self.handle, sym_type, count) + else: + syms = core.BNGetSymbolsOfTypeInRange(self.handle, sym_type, start, length, count) + result = [] + for i in xrange(0, count.value): + result.append(bntype.Symbol(None, None, None, handle = core.BNNewSymbolReference(syms[i]))) + core.BNFreeSymbolList(syms, count.value) + 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 + :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 + :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 + :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 + :rtype: None + """ + core.BNUndefineUserSymbol(self.handle, sym.handle) + + def define_imported_function(self, import_addr_sym, func): + """ + ``define_imported_function`` defines an imported Function ``func`` with a ImportedFunctionSymbol type. + + :param Symbol import_addr_sym: A Symbol object with type ImportedFunctionSymbol + :param Function func: A Function object to define as an imported function + :rtype: None + """ + 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 ``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 ``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 ``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 ``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): + """ + ``never_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): + core.BNNotifyDataWritten(self.handle, offset, length) + + def notify_data_inserted(self, offset, length): + core.BNNotifyDataInserted(self.handle, offset, length) + + def notify_data_removed(self, offset, length): + 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) + [] + >>> + """ + count = ctypes.c_ulonglong(0) + if start is None: + strings = core.BNGetStrings(self.handle, count) + else: + strings = core.BNGetStringsInRange(self.handle, start, length, count) + result = [] + for i in xrange(0, count.value): + result.append(StringReference(core.BNStringType(strings[i].type), strings[i].start, strings[i].length)) + core.BNFreeStringReferenceList(strings) + return result + + def add_analysis_completion_event(self, callback): + """ + ``add_analysis_completion_event`` sets up a call back function to be called when analysis has been completed. + This is helpful when using asynchronously analysis. + + :param callable() callback: A function to be called with no parameters when analysis has completed. + :return: An initialized AnalysisCompletionEvent object. + :rtype: AnalysisCompletionEvent + :Example: + + >>> def completionEvent(): + ... print "done" + ... + >>> bv.add_analysis_completion_event(completionEvent) + + >>> bv.update_analysis() + done + >>> + """ + return AnalysisCompletionEvent(self, callback) + + def get_next_function_start_after(self, addr): + """ + ``get_next_function_start_after`` returns the virtual address of the Function that occurs after the virtual address + ``addr`` + + :param int addr: the virtual address to start looking from. + :return: the virtual address of the next Function + :rtype: int + :Example: + + >>> bv.get_next_function_start_after(bv.entry_point) + 268441061L + >>> hex(bv.get_next_function_start_after(bv.entry_point)) + '0x100015e5L' + >>> hex(bv.get_next_function_start_after(0x100015e5)) + '0x10001629L' + >>> hex(bv.get_next_function_start_after(0x10001629)) + '0x1000165eL' + >>> + """ + return core.BNGetNextFunctionStartAfterAddress(self.handle, addr) + + def get_next_basic_block_start_after(self, addr): + """ + ``get_next_basic_block_start_after`` returns the virtual address of the BasicBlock that occurs after the virtual + address ``addr`` + + :param int addr: the virtual address to start looking from. + :return: the virtual address of the next BasicBlock + :rtype: int + :Example: + + >>> hex(bv.get_next_basic_block_start_after(bv.entry_point)) + '0x100014a8L' + >>> hex(bv.get_next_basic_block_start_after(0x100014a8)) + '0x100014adL' + >>> + """ + return core.BNGetNextBasicBlockStartAfterAddress(self.handle, addr) + + def get_next_data_after(self, addr): + """ + ``get_next_data_after`` retrieves the virtual address of the next non-code byte. + + :param int addr: the virtual address to start looking from. + :return: the virtual address of the next data byte which is data, not code + :rtype: int + :Example: + + >>> hex(bv.get_next_data_after(0x10000000)) + '0x10000001L' + """ + return core.BNGetNextDataAfterAddress(self.handle, addr) + + def get_next_data_var_after(self, addr): + """ + ``get_next_data_var_after`` retrieves the next virtual address of the next :py:Class:`DataVariable` + + :param int addr: the virtual address to start looking from. + :return: the virtual address of the next :py:Class:`DataVariable` + :rtype: int + :Example: + + >>> hex(bv.get_next_data_var_after(0x10000000)) + '0x1000003cL' + >>> bv.get_data_var_at(0x1000003c) + + >>> + """ + return core.BNGetNextDataVariableAfterAddress(self.handle, addr) + + def get_previous_function_start_before(self, addr): + """ + ``get_previous_function_start_before`` returns the virtual address of the Function that occurs prior to the + virtual address provided + + :param int addr: the virtual address to start looking from. + :return: the virtual address of the previous Function + :rtype: int + :Example: + + >>> hex(bv.entry_point) + '0x1000149fL' + >>> hex(bv.get_next_function_start_after(bv.entry_point)) + '0x100015e5L' + >>> hex(bv.get_previous_function_start_before(0x100015e5)) + '0x1000149fL' + >>> + """ + return core.BNGetPreviousFunctionStartBeforeAddress(self.handle, addr) + + def get_previous_basic_block_start_before(self, addr): + """ + ``get_previous_basic_block_start_before`` returns the virtual address of the BasicBlock that occurs prior to the + provided virtual address + + :param int addr: the virtual address to start looking from. + :return: the virtual address of the previous BasicBlock + :rtype: int + :Example: + + >>> hex(bv.entry_point) + '0x1000149fL' + >>> hex(bv.get_next_basic_block_start_after(bv.entry_point)) + '0x100014a8L' + >>> hex(bv.get_previous_basic_block_start_before(0x100014a8)) + '0x1000149fL' + >>> + """ + return core.BNGetPreviousBasicBlockStartBeforeAddress(self.handle, addr) + + def get_previous_basic_block_end_before(self, addr): + """ + ``get_previous_basic_block_end_before`` + + :param int addr: the virtual address to start looking from. + :return: the virtual address of the previous BasicBlock end + :rtype: int + :Example: + >>> hex(bv.entry_point) + '0x1000149fL' + >>> hex(bv.get_next_basic_block_start_after(bv.entry_point)) + '0x100014a8L' + >>> hex(bv.get_previous_basic_block_end_before(0x100014a8)) + '0x100014a8L' + """ + return core.BNGetPreviousBasicBlockEndBeforeAddress(self.handle, addr) + + def get_previous_data_before(self, addr): + """ + ``get_previous_data_before`` + + :param int addr: the virtual address to start looking from. + :return: the virtual address of the previous data (non-code) byte + :rtype: int + :Example: + + >>> hex(bv.get_previous_data_before(0x1000001)) + '0x1000000L' + >>> + """ + return core.BNGetPreviousDataBeforeAddress(self.handle, addr) + + def get_previous_data_var_before(self, addr): + """ + ``get_previous_data_var_before`` + + :param int addr: the virtual address to start looking from. + :return: the virtual address of the previous :py:Class:`DataVariable` + :rtype: int + :Example: + + >>> hex(bv.get_previous_data_var_before(0x1000003c)) + '0x10000000L' + >>> bv.get_data_var_at(0x10000000) + + >>> + """ + return core.BNGetPreviousDataVariableBeforeAddress(self.handle, addr) + + def get_linear_disassembly_position_at(self, addr, settings): + """ + ``get_linear_disassembly_position_at`` instantiates a :py:class:`LinearDisassemblyPosition` object for use in + :py:method:`get_previous_linear_disassembly_lines` or :py:method:`get_next_linear_disassembly_lines`. + + :param int addr: virtual address of linear disassembly position + :param DisassemblySettings settings: an instantiated :py:class:`DisassemblySettings` object + :return: An instantied :py:class:`LinearDisassemblyPosition` object for the provided virtual address + :rtype: LinearDisassemblyPosition + :Example: + + >>> settings = DisassemblySettings() + >>> pos = bv.get_linear_disassembly_position_at(0x1000149f, settings) + >>> lines = bv.get_previous_linear_disassembly_lines(pos, settings) + >>> lines + [<0x1000149a: pop esi>, <0x1000149b: pop ebp>, + <0x1000149c: retn 0xc>, <0x1000149f: >] + """ + if settings is not None: + settings = settings.handle + pos = core.BNGetLinearDisassemblyPositionForAddress(self.handle, addr, settings) + func = None + block = None + if pos.function: + func = function.Function(self, pos.function) + if pos.block: + block = basicblock.BasicBlock(self, pos.block) + return lineardisassembly.LinearDisassemblyPosition(func, block, pos.address) + + def _get_linear_disassembly_lines(self, api, pos, settings): + pos_obj = core.BNLinearDisassemblyPosition() + pos_obj.function = None + pos_obj.block = None + pos_obj.address = pos.address + if pos.function is not None: + pos_obj.function = core.BNNewFunctionReference(pos.function.handle) + if pos.block is not None: + pos_obj.block = core.BNNewBasicBlockReference(pos.block.handle) + + if settings is not None: + settings = settings.handle + + count = ctypes.c_ulonglong(0) + lines = api(self.handle, pos_obj, settings, count) + + result = [] + for i in xrange(0, count.value): + func = None + block = None + if lines[i].function: + func = function.Function(self, core.BNNewFunctionReference(lines[i].function)) + if lines[i].block: + block = basicblock.BasicBlock(self, core.BNNewBasicBlockReference(lines[i].block)) + addr = lines[i].contents.addr + tokens = [] + for j in xrange(0, lines[i].contents.count): + token_type = core.BNInstructionTextTokenType(lines[i].contents.tokens[j].type) + text = lines[i].contents.tokens[j].text + value = lines[i].contents.tokens[j].value + size = lines[i].contents.tokens[j].size + operand = lines[i].contents.tokens[j].operand + tokens.append(function.InstructionTextToken(token_type, text, value, size, operand)) + contents = function.DisassemblyTextLine(addr, tokens) + result.append(lineardisassembly.LinearDisassemblyLine(lines[i].type, func, block, lines[i].lineOffset, contents)) + + func = None + block = None + if pos_obj.function: + func = function.Function(self, pos_obj.function) + if pos_obj.block: + block = basicblock.BasicBlock(self, pos_obj.block) + pos.function = func + pos.block = block + pos.address = pos_obj.address + + core.BNFreeLinearDisassemblyLines(lines, count.value) + return result + + def get_previous_linear_disassembly_lines(self, pos, settings): + """ + ``get_previous_linear_disassembly_lines`` retrieves a list of :py:class:`LinearDisassemblyLine` objects for the + previous disassembly lines, and updates the LinearDisassemblyPosition passed in. This function can be called + repeatedly to get more lines of linear disassembly. + + :param LinearDisassemblyPosition pos: Position to start retrieving linear disassembly lines from + :param DisassemblySettings settings: DisassemblySettings display settings for the linear disassembly + :return: a list of :py:class:`LinearDisassemblyLine` objects for the previous lines. + :Example: + + >>> settings = DisassemblySettings() + >>> pos = bv.get_linear_disassembly_position_at(0x1000149a, settings) + >>> bv.get_previous_linear_disassembly_lines(pos, settings) + [<0x10001488: push dword [ebp+0x10 {arg_c}]>, ... , <0x1000149a: >] + >>> bv.get_previous_linear_disassembly_lines(pos, settings) + [<0x10001483: xor eax, eax {0x0}>, ... , <0x10001488: >] + """ + return self._get_linear_disassembly_lines(core.BNGetPreviousLinearDisassemblyLines, pos, settings) + + def get_next_linear_disassembly_lines(self, pos, settings): + """ + ``get_next_linear_disassembly_lines`` retrieves a list of :py:class:`LinearDisassemblyLine` objects for the + next disassembly lines, and updates the LinearDisassemblyPosition passed in. This function can be called + repeatedly to get more lines of linear disassembly. + + :param LinearDisassemblyPosition pos: Position to start retrieving linear disassembly lines from + :param DisassemblySettings settings: DisassemblySettings display settings for the linear disassembly + :return: a list of :py:class:`LinearDisassemblyLine` objects for the next lines. + :Example: + + >>> settings = DisassemblySettings() + >>> pos = bv.get_linear_disassembly_position_at(0x10001483, settings) + >>> bv.get_next_linear_disassembly_lines(pos, settings) + [<0x10001483: xor eax, eax {0x0}>, <0x10001485: inc eax {0x1}>, ... , <0x10001488: >] + >>> bv.get_next_linear_disassembly_lines(pos, settings) + [<0x10001488: push dword [ebp+0x10 {arg_c}]>, ... , <0x1000149a: >] + >>> + """ + return self._get_linear_disassembly_lines(core.BNGetNextLinearDisassemblyLines, pos, settings) + + def get_linear_disassembly(self, 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 data views, and disassembly. + + :param DisassemblySettings settings: 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 + self.settings = settings + + def __iter__(self): + pos = self.view.get_linear_disassembly_position_at(self.view.start, self.settings) + while True: + lines = self.view.get_next_linear_disassembly_lines(pos, self.settings) + if len(lines) == 0: + break + for line in lines: + yield line + + 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") + (, 'foo') + >>> + """ + result = core.BNNameAndType() + errors = ctypes.c_char_p() + if not core.BNParseTypeString(self.handle, text, result, errors): + error_str = errors.value + core.BNFreeString(ctypes.cast(errors, ctypes.POINTER(ctypes.c_byte))) + raise SyntaxError(error_str) + type_obj = bntype.Type(core.BNNewTypeReference(result.type)) + name = result.name + core.BNFreeNameAndType(result) + 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) + + >>> + """ + obj = core.BNGetAnalysisTypeByName(self.handle, name) + if not obj: + return None + return bntype.Type(obj) + + def is_type_auto_defined(self, name): + """ + ``is_type_auto_defined`` queries the user type list of name. If name is not in the *user* type list then the name + is considered an *auto* type. + + :param str name: Name of type to query + :return: True if the type is not a *user* type. False if the type is a *user* type. + :Example: + >>> bv.is_type_auto_defined("foo") + True + >>> bv.define_user_type("foo", bv.parse_type_string("struct {int x,y;}")[0]) + >>> bv.is_type_auto_defined("foo") + False + >>> + """ + 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 + :rtype: None + :Example: + + >>> type, name = bv.parse_type_string("int foo") + >>> bv.define_type(name, type) + >>> bv.get_type_by_name(name) + + """ + 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 + :rtype: None + :Example: + + >>> type, name = bv.parse_type_string("int foo") + >>> bv.define_user_type(name, type) + >>> bv.get_type_by_name(name) + + """ + 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 + :rtype: None + :Example: + + >>> type, name = bv.parse_type_string("int foo") + >>> bv.define_type(name, type) + >>> bv.get_type_by_name(name) + + >>> 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 + :rtype: None + :Example: + + >>> type, name = bv.parse_type_string("int foo") + >>> bv.define_type(name, type) + >>> bv.get_type_by_name(name) + + >>> bv.undefine_type(name) + >>> bv.get_type_by_name(name) + >>> + """ + core.BNUndefineUserAnalysisType(self.handle, name) + + def find_next_data(self, start, data, flags = 0): + """ + ``find_next_data`` searchs for the bytes in data starting at the virtual address ``start`` either, case-sensitive, + or case-insensitive. + + :param int start: virtual address to start searching from. + :param str data: bytes to search for + :param FindFlags flags: case-sensitivity flag, one of the following: + + ==================== ====================== + FindFlags Description + ==================== ====================== + NoFindFlags Case-sensitive find + FindCaseInsensitive Case-insensitive find + ==================== ====================== + """ + buf = databuffer.DataBuffer(str(data)) + result = ctypes.c_ulonglong() + if not core.BNFindNextData(self.handle, start, buf.handle, result, flags): + return None + return result.value + + def reanalyze(self): + """ + ``reanalyze`` causes all functions to be reanalyzed. This function does not wait for the analysis to finish. + + :rtype: None + """ + core.BNReanalyzeAllFunctions(self.handle) + + def show_plain_text_report(self, title, contents): + core.BNShowPlainTextReport(self.handle, title, contents) + + def show_markdown_report(self, title, contents, plaintext = ""): + core.BNShowMarkdownReport(self.handle, title, contents, plaintext) + + def show_html_report(self, title, contents, plaintext = ""): + core.BNShowHTMLReport(self.handle, title, contents, plaintext) + + def get_address_input(self, prompt, title, current_address = None): + if current_address is None: + current_address = self.file.offset + value = ctypes.c_ulonglong() + if not core.BNGetAddressInput(value, prompt, title, self.handle, current_address): + return None + return value.value + + def add_auto_segment(self, start, length, data_offset, data_length, flags): + core.BNAddAutoSegment(self.handle, start, length, data_offset, data_length, flags) + + def remove_auto_segment(self, start, length): + core.BNRemoveAutoSegment(self.handle, start, length) + + def add_user_segment(self, start, length, data_offset, data_length, flags): + core.BNAddUserSegment(self.handle, start, length, data_offset, data_length, flags) + + def remove_user_segment(self, start, length): + core.BNRemoveUserSegment(self.handle, start, length) + + def get_segment_at(self, addr): + segment = core.BNSegment() + if not core.BNGetSegmentAt(self.handle, addr, segment): + return None + result = Segment(segment.start, segment.length, segment.dataOffset, segment.dataLength, + segment.flags) + return result + + def add_auto_section(self, name, start, length, type = "", align = 1, entry_size = 1, linked_section = "", + info_section = "", info_data = 0): + core.BNAddAutoSection(self.handle, name, start, length, type, align, entry_size, linked_section, + info_section, info_data) + + def remove_auto_section(self, name): + core.BNRemoveAutoSection(self.handle, name) + + def add_user_section(self, name, start, length, type = "", align = 1, entry_size = 1, linked_section = "", + info_section = "", info_data = 0): + core.BNAddUserSection(self.handle, name, start, length, type, align, entry_size, linked_section, + info_section, info_data) + + def remove_user_section(self, name): + core.BNRemoveUserSection(self.handle, name) + + def get_sections_at(self, addr): + count = ctypes.c_ulonglong(0) + section_list = core.BNGetSectionsAt(self.handle, addr, count) + result = [] + for i in xrange(0, count.value): + result.append(Section(section_list[i].name, section_list[i].type, section_list[i].start, + section_list[i].length, section_list[i].linkedSection, section_list[i].infoSection, + section_list[i].infoData, section_list[i].align, section_list[i].entrySize)) + core.BNFreeSectionList(section_list, count.value) + return result + + def get_section_by_name(self, name): + section = core.BNSection() + if not core.BNGetSectionByName(self.handle, name, section): + return None + result = Section(section.name, section.type, section.start, section.length, section.linkedSection, + section.infoSection, section.infoData, section.align, section.entrySize) + core.BNFreeSection(section) + return result + + def get_unique_section_names(self, name_list): + incoming_names = (ctypes.c_char_p * len(name_list))() + for i in xrange(0, len(name_list)): + incoming_names[i] = name_list[i] + outgoing_names = core.BNGetUniqueSectionNames(self.handle, incoming_names, len(name_list)) + result = [] + for i in xrange(0, len(name_list)): + result.append(str(outgoing_names[i])) + core.BNFreeStringList(outgoing_names, len(name_list)) + return result + + def __setattr__(self, name, value): + try: + object.__setattr__(self, name, value) + except AttributeError: + raise AttributeError("attribute '%s' is read only" % name) + + +class BinaryReader(object): + """ + ``class BinaryReader`` is a convenience class for reading binary data. + + BinaryReader can be instantiated as follows and the rest of the document will start from this context :: + + >>> from binaryninja import * + >>> bv = BinaryViewType['Mach-O'].open("/bin/ls") + >>> br = BinaryReader(bv) + >>> hex(br.read32()) + '0xfeedfacfL' + >>> + + Or using the optional endian parameter :: + + >>> from binaryninja import * + >>> br = BinaryReader(bv, core.BNEndianness.BigEndian) + >>> hex(br.read32()) + '0xcffaedfeL' + >>> + """ + def __init__(self, view, endian = None): + self.handle = core.BNCreateBinaryReader(view.handle) + if endian is None: + core.BNSetBinaryReaderEndianness(self.handle, view.endianness) + else: + core.BNSetBinaryReaderEndianness(self.handle, endian) + + def __del__(self): + core.BNFreeBinaryReader(self.handle) + + @property + def endianness(self): + """ + The Endianness to read data. (read/write) + + :getter: returns the endianness of the reader + :setter: sets the endianness of the reader (BigEndian or LittleEndian) + :type: Endianness + """ + return core.BNGetBinaryReaderEndianness(self.handle) + + @endianness.setter + def endianness(self, value): + core.BNSetBinaryReaderEndianness(self.handle, value) + + @property + def offset(self): + """ + The current read offset (read/write). + + :getter: returns the current internal offset + :setter: sets the internal offset + :type: int + """ + return core.BNGetReaderPosition(self.handle) + + @offset.setter + def offset(self, value): + core.BNSeekBinaryReader(self.handle, value) + + @property + def eof(self): + """ + Is end of file (read-only) + + :getter: returns boolean, true if end of file, false otherwise + :type: bool + """ + return core.BNIsEndOfFile(self.handle) + + def read(self, length): + """ + ``read`` returns ``length`` bytes read from the current offset, adding ``length`` to offset. + + :param int length: number of bytes to read. + :return: ``length`` bytes from current offset + :rtype: str, or None on failure + :Example: + + >>> br.read(8) + '\\xcf\\xfa\\xed\\xfe\\x07\\x00\\x00\\x01' + >>> + """ + dest = ctypes.create_string_buffer(length) + if not core.BNReadData(self.handle, dest, length): + return None + return dest.raw + + def read8(self): + """ + ``read8`` returns a one byte integer from offet incrementing the offset. + + :return: byte at offset. + :rtype: int, or None on failure + :Example: + + >>> br.seek(0x100000000) + >>> br.read8() + 207 + >>> + """ + result = ctypes.c_ubyte() + if not core.BNRead8(self.handle, result): + return None + return result.value + + def read16(self): + """ + ``read16`` returns a two byte integer from offet incrementing the offset by two, using specified endianness. + + :return: a two byte integer at offset. + :rtype: int, or None on failure + :Example: + + >>> br.seek(0x100000000) + >>> hex(br.read16()) + '0xfacf' + >>> + """ + result = ctypes.c_ushort() + if not core.BNRead16(self.handle, result): + return None + return result.value + + def read32(self): + """ + ``read32`` returns a four byte integer from offet incrementing the offset by four, using specified endianness. + + :return: a four byte integer at offset. + :rtype: int, or None on failure + :Example: + + >>> br.seek(0x100000000) + >>> hex(br.read32()) + '0xfeedfacfL' + >>> + """ + result = ctypes.c_uint() + if not core.BNRead32(self.handle, result): + return None + return result.value + + def read64(self): + """ + ``read64`` returns an eight byte integer from offet incrementing the offset by eight, using specified endianness. + + :return: an eight byte integer at offset. + :rtype: int, or None on failure + :Example: + + >>> br.seek(0x100000000) + >>> hex(br.read64()) + '0x1000007feedfacfL' + >>> + """ + result = ctypes.c_ulonglong() + if not core.BNRead64(self.handle, result): + return None + return result.value + + def read16le(self): + """ + ``read16le`` returns a two byte little endian integer from offet incrementing the offset by two. + + :return: a two byte integer at offset. + :rtype: int, or None on failure + :Exmaple: + + >>> br.seek(0x100000000) + >>> hex(br.read16le()) + '0xfacf' + >>> + """ + result = self.read(2) + if (result is None) or (len(result) != 2): + return None + return struct.unpack(">> br.seek(0x100000000) + >>> hex(br.read32le()) + '0xfeedfacf' + >>> + """ + result = self.read(4) + if (result is None) or (len(result) != 4): + return None + return struct.unpack(">> br.seek(0x100000000) + >>> hex(br.read64le()) + '0x1000007feedfacf' + >>> + """ + result = self.read(8) + if (result is None) or (len(result) != 8): + return None + return struct.unpack(">> br.seek(0x100000000) + >>> hex(br.read16be()) + '0xcffa' + >>> + """ + result = self.read(2) + if (result is None) or (len(result) != 2): + return None + return struct.unpack(">H", result)[0] + + def read32be(self): + """ + ``read32be`` returns a four byte big endian integer from offet incrementing the offset by four. + + :return: a four byte integer at offset. + :rtype: int, or None on failure + :Example: + + >>> br.seek(0x100000000) + >>> hex(br.read32be()) + '0xcffaedfe' + >>> + """ + result = self.read(4) + if (result is None) or (len(result) != 4): + return None + return struct.unpack(">I", result)[0] + + def read64be(self): + """ + ``read64be`` returns an eight byte big endian integer from offet incrementing the offset by eight. + + :return: a eight byte integer at offset. + :rtype: int, or None on failure + :Example: + + >>> br.seek(0x100000000) + >>> hex(br.read64be()) + '0xcffaedfe07000001L' + """ + result = self.read(8) + if (result is None) or (len(result) != 8): + return None + return struct.unpack(">Q", result)[0] + + def seek(self, offset): + """ + ``seek`` update internal offset to ``offset``. + + :param int offset: offset to set the internal offset to + :rtype: None + :Example: + + >>> hex(br.offset) + '0x100000008L' + >>> br.seek(0x100000000) + >>> hex(br.offset) + '0x100000000L' + >>> + """ + core.BNSeekBinaryReader(self.handle, offset) + + def seek_relative(self, offset): + """ + ``seek_relative`` updates the internal offset by ``offset``. + + :param int offset: offset to add to the internal offset + :rtype: None + :Example: + + >>> hex(br.offset) + '0x100000008L' + >>> br.seek_relative(-8) + >>> hex(br.offset) + '0x100000000L' + >>> + """ + core.BNSeekBinaryReaderRelative(self.handle, offset) + + def __setattr__(self, name, value): + try: + object.__setattr__(self, name, value) + except AttributeError: + raise AttributeError("attribute '%s' is read only" % name) + + +class BinaryWriter(object): + """ + ``class BinaryWriter`` is a convenience class for writing binary data. + + BinaryWriter can be instantiated as follows and the rest of the document will start from this context :: + + >>> from binaryninja import * + >>> bv = BinaryViewType['Mach-O'].open("/bin/ls") + >>> br = BinaryReader(bv) + >>> bw = BinaryWriter(bv) + >>> + + Or using the optional endian parameter :: + + >>> from binaryninja import * + >>> br = BinaryReader(bv, core.BNEndianness.BigEndian) + >>> bw = BinaryWriter(bv, core.BNEndianness.BigEndian) + >>> + """ + def __init__(self, view, endian = None): + self.handle = core.BNCreateBinaryWriter(view.handle) + if endian is None: + core.BNSetBinaryWriterEndianness(self.handle, view.endianness) + else: + core.BNSetBinaryWriterEndianness(self.handle, endian) + + def __del__(self): + core.BNFreeBinaryWriter(self.handle) + + @property + def endianness(self): + """ + The Endianness to written data. (read/write) + + :getter: returns the endianness of the reader + :setter: sets the endianness of the reader (BigEndian or LittleEndian) + :type: Endianness + """ + return core.BNGetBinaryWriterEndianness(self.handle) + + @endianness.setter + def endianness(self, value): + core.BNSetBinaryWriterEndianness(self.handle, value) + + @property + def offset(self): + """ + The current write offset (read/write). + + :getter: returns the current internal offset + :setter: sets the internal offset + :type: int + """ + return core.BNGetWriterPosition(self.handle) + + @offset.setter + def offset(self, value): + core.BNSeekBinaryWriter(self.handle, value) + + def write(self, value): + """ + ``write`` writes ``len(value)`` bytes to the internal offset, without regard to endianness. + + :param str value: bytes to be written at current offset + :return: boolean True on success, False on failure. + :rtype: bool + :Example: + + >>> bw.write("AAAA") + True + >>> br.read(4) + 'AAAA' + >>> + """ + value = str(value) + buf = ctypes.create_string_buffer(len(value)) + ctypes.memmove(buf, value, len(value)) + return core.BNWriteData(self.handle, buf, len(value)) + + def write8(self, value): + """ + ``write8`` lowest order byte from the integer ``value`` to the current offset. + + :param str value: bytes to be written at current offset + :return: boolean + :rtype: int + :Example: + + >>> bw.write8(0x42) + True + >>> br.read(1) + 'B' + >>> + """ + return core.BNWrite8(self.handle, value) + + def write16(self, value): + """ + ```` writes the lowest order two bytes from the integer ``value`` to the current offset, using internal endianness. + + :param int value: integer value to write. + :return: boolean True on success, False on failure. + :rtype: bool + """ + return core.BNWrite16(self.handle, value) + + def write32(self, value): + """ + ```` writes the lowest order four bytes from the integer ``value`` to the current offset, using internal endianness. + + :param int value: integer value to write. + :return: boolean True on success, False on failure. + :rtype: bool + """ + return core.BNWrite32(self.handle, value) + + def write64(self, value): + """ + ```` writes the lowest order eight bytes from the integer ``value`` to the current offset, using internal endianness. + + :param int value: integer value to write. + :return: boolean True on success, False on failure. + :rtype: bool + """ + return core.BNWrite64(self.handle, value) + + def write16le(self, value): + """ + ``write16le`` writes the lowest order two bytes from the little endian integer ``value`` to the current offset. + + :param int value: integer value to write. + :return: boolean True on success, False on failure. + :rtype: bool + """ + value = struct.pack("H", value) + return self.write(value) + + def write32be(self, value): + """ + ``write32be`` writes the lowest order four bytes from the big endian integer ``value`` to the current offset. + + :param int value: integer value to write. + :return: boolean True on success, False on failure. + :rtype: bool + """ + value = struct.pack(">I", value) + return self.write(value) + + def write64be(self, value): + """ + ``write64be`` writes the lowest order eight bytes from the big endian integer ``value`` to the current offset. + + :param int value: integer value to write. + :return: boolean True on success, False on failure. + :rtype: bool + """ + value = struct.pack(">Q", value) + return self.write(value) + + def seek(self, offset): + """ + ``seek`` update internal offset to ``offset``. + + :param int offset: offset to set the internal offset to + :rtype: None + :Example: + + >>> hex(bw.offset) + '0x100000008L' + >>> bw.seek(0x100000000) + >>> hex(br.offset) + '0x100000000L' + >>> + """ + core.BNSeekBinaryWriter(self.handle, offset) + + def seek_relative(self, offset): + """ + ``seek_relative`` updates the internal offset by ``offset``. + + :param int offset: offset to add to the internal offset + :rtype: None + :Example: + + >>> hex(bw.offset) + '0x100000008L' + >>> bw.seek_relative(-8) + >>> hex(br.offset) + '0x100000000L' + >>> + """ + core.BNSeekBinaryWriterRelative(self.handle, offset) -- cgit v1.3.1 From a6842fc4209ed0bc160222ee61b2e6d9741dc9ef Mon Sep 17 00:00:00 2001 From: plafosse Date: Mon, 31 Oct 2016 16:06:34 -0400 Subject: Refactoring and other improvements of the python api --- python/__init__.py | 55 ++- python/architecture.py | 6 + python/binaryview.py | 35 +- python/enum/LICENSE | 32 ++ python/enum/README | 3 + python/enum/__init__.py | 837 ++++++++++++++++++++++++++++++++ python/examples/bin_info.py | 66 ++- python/examples/instruction_iterator.py | 28 +- python/platform.py | 9 + 9 files changed, 994 insertions(+), 77 deletions(-) create mode 100644 python/enum/LICENSE create mode 100644 python/enum/README create mode 100644 python/enum/__init__.py (limited to 'python/binaryview.py') diff --git a/python/__init__.py b/python/__init__.py index 402c8526..f38395c8 100644 --- a/python/__init__.py +++ b/python/__init__.py @@ -19,31 +19,38 @@ # IN THE SOFTWARE. -# Binary Ninja components -import _binaryninjacore as core -from databuffer import * -from filemetadata import * -from fileaccessor import * -from binaryview import * -from transform import * -from architecture import * -from basicblock import * -from function import * -from log import * -from lowlevelil import * -from bntype import * -from functionrecognizer import * -from update import * -from plugin import * -from callingconvention import * -from platform import * -from demangle import * -from mainthread import * -from interaction import * -from lineardisassembly import * -from undoaction import * -from highlight import * +import sys + +# Binary Ninja components +try: + import _binaryninjacore as core + from databuffer import * + from filemetadata import * + from fileaccessor import * + from binaryview import * + from transform import * + from architecture import * + from basicblock import * + from function import * + from log import * + from lowlevelil import * + from bntype import * + from functionrecognizer import * + from update import * + from plugin import * + from callingconvention import * + from platform import * + from demangle import * + from mainthread import * + from interaction import * + from lineardisassembly import * + from undoaction import * + from highlight import * +except: + x = open("/Users/peterl/path", "w") + x.write(str(sys.exc_info())) + x.close() class _DestructionCallbackHandler(object): def __init__(self): diff --git a/python/architecture.py b/python/architecture.py index a8aa391b..0cdba6e5 100644 --- a/python/architecture.py +++ b/python/architecture.py @@ -1084,6 +1084,12 @@ class Architecture(object): """ return None + def get_associated_arch_by_address(self, addr): + new_addr = ctypes.c_ulonglong() + new_addr.value = addr + result = core.BNGetAssociatedArchitectureByAddress(self.handle, new_addr) + return Architecture(handle = result), new_addr.value + def get_instruction_info(self, data, addr): """ ``get_instruction_info`` returns an InstructionInfo object for the instruction at the given virtual address diff --git a/python/binaryview.py b/python/binaryview.py index 76def834..e6e0ff61 100644 --- a/python/binaryview.py +++ b/python/binaryview.py @@ -266,12 +266,6 @@ class _BinaryViewTypeMetaclass(type): raise KeyError("'%s' is not a valid view type" % str(value)) return BinaryViewType(view_type) - def __setattr__(self, name, value): - try: - type.__setattr__(self, name, value) - except AttributeError: - raise AttributeError("attribute '%s' is read only" % name) - class BinaryViewType(object): __metaclass__ = _BinaryViewTypeMetaclass @@ -304,6 +298,27 @@ class BinaryViewType(object): return None return self.create(data) + @classmethod + def get_view_of_file(cls, filename, update_analysis=True): + """ + ``get_view_of_file`` returns the first available, non-Raw `BinaryView` available. + + :param str filename: Path to filename + :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) + if view is None: + return None + for available in view.available_view_types: + if available.name != "Raw": + bv = cls[available.name].open(filename) + if update_analysis: + bv.update_analysis_and_wait() + return bv + return None + def is_valid_for_data(self, data): return core.BNIsBinaryViewTypeValidForData(self.handle, data.handle) @@ -328,12 +343,6 @@ class BinaryViewType(object): return None return platform.Platform(None, plat) - def __setattr__(self, name, value): - try: - object.__setattr__(self, name, value) - except AttributeError: - raise AttributeError("attribute '%s' is read only" % name) - class Segment(object): def __init__(self, start, length, data_offset, data_length, flags): @@ -467,7 +476,7 @@ class BinaryView(object): if file_metadata is None: file_metadata = filemetadata.FileMetadata() self.handle = core.BNCreateBinaryDataView(file_metadata.handle) - self.file = filemetadata.FileMetadata(handle=core.BNNewFileReference(file_metadata)) + self.file = filemetadata.FileMetadata(handle=core.BNNewFileReference(file_metadata.handle)) else: startup._init_plugins() if not self.__class__._registered: diff --git a/python/enum/LICENSE b/python/enum/LICENSE new file mode 100644 index 00000000..9003b885 --- /dev/null +++ b/python/enum/LICENSE @@ -0,0 +1,32 @@ +Copyright (c) 2013, Ethan Furman. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + + Redistributions of source code must retain the above + copyright notice, this list of conditions and the + following disclaimer. + + Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials + provided with the distribution. + + Neither the name Ethan Furman nor the names of any + contributors may be used to endorse or promote products + derived from this software without specific prior written + permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. diff --git a/python/enum/README b/python/enum/README new file mode 100644 index 00000000..aa2333d8 --- /dev/null +++ b/python/enum/README @@ -0,0 +1,3 @@ +enum34 is the new Python stdlib enum module available in Python 3.4 +backported for previous versions of Python from 2.4 to 3.3. +tested on 2.6, 2.7, and 3.3+ diff --git a/python/enum/__init__.py b/python/enum/__init__.py new file mode 100644 index 00000000..d6ffb3a4 --- /dev/null +++ b/python/enum/__init__.py @@ -0,0 +1,837 @@ +"""Python Enumerations""" + +import sys as _sys + +__all__ = ['Enum', 'IntEnum', 'unique'] + +version = 1, 1, 6 + +pyver = float('%s.%s' % _sys.version_info[:2]) + +try: + any +except NameError: + def any(iterable): + for element in iterable: + if element: + return True + return False + +try: + from collections import OrderedDict +except ImportError: + OrderedDict = None + +try: + basestring +except NameError: + # In Python 2 basestring is the ancestor of both str and unicode + # in Python 3 it's just str, but was missing in 3.1 + basestring = str + +try: + unicode +except NameError: + # In Python 3 unicode no longer exists (it's just str) + unicode = str + +class _RouteClassAttributeToGetattr(object): + """Route attribute access on a class to __getattr__. + + This is a descriptor, used to define attributes that act differently when + accessed through an instance and through a class. Instance access remains + normal, but access to an attribute through a class will be routed to the + class's __getattr__ method; this is done by raising AttributeError. + + """ + def __init__(self, fget=None): + self.fget = fget + + def __get__(self, instance, ownerclass=None): + if instance is None: + raise AttributeError() + return self.fget(instance) + + def __set__(self, instance, value): + raise AttributeError("can't set attribute") + + def __delete__(self, instance): + raise AttributeError("can't delete attribute") + + +def _is_descriptor(obj): + """Returns True if obj is a descriptor, False otherwise.""" + return ( + hasattr(obj, '__get__') or + hasattr(obj, '__set__') or + hasattr(obj, '__delete__')) + + +def _is_dunder(name): + """Returns True if a __dunder__ name, False otherwise.""" + return (name[:2] == name[-2:] == '__' and + name[2:3] != '_' and + name[-3:-2] != '_' and + len(name) > 4) + + +def _is_sunder(name): + """Returns True if a _sunder_ name, False otherwise.""" + return (name[0] == name[-1] == '_' and + name[1:2] != '_' and + name[-2:-1] != '_' and + len(name) > 2) + + +def _make_class_unpicklable(cls): + """Make the given class un-picklable.""" + def _break_on_call_reduce(self, protocol=None): + raise TypeError('%r cannot be pickled' % self) + cls.__reduce_ex__ = _break_on_call_reduce + cls.__module__ = '' + + +class _EnumDict(dict): + """Track enum member order and ensure member names are not reused. + + EnumMeta will use the names found in self._member_names as the + enumeration member names. + + """ + def __init__(self): + super(_EnumDict, self).__init__() + self._member_names = [] + + def __setitem__(self, key, value): + """Changes anything not dundered or not a descriptor. + + If a descriptor is added with the same name as an enum member, the name + is removed from _member_names (this may leave a hole in the numerical + sequence of values). + + If an enum member name is used twice, an error is raised; duplicate + values are not checked for. + + Single underscore (sunder) names are reserved. + + Note: in 3.x __order__ is simply discarded as a not necessary piece + leftover from 2.x + + """ + if pyver >= 3.0 and key in ('_order_', '__order__'): + return + elif key == '__order__': + key = '_order_' + if _is_sunder(key): + if key != '_order_': + raise ValueError('_names_ are reserved for future Enum use') + elif _is_dunder(key): + pass + elif key in self._member_names: + # descriptor overwriting an enum? + raise TypeError('Attempted to reuse key: %r' % key) + elif not _is_descriptor(value): + if key in self: + # enum overwriting a descriptor? + raise TypeError('Key already defined as: %r' % self[key]) + self._member_names.append(key) + super(_EnumDict, self).__setitem__(key, value) + + +# Dummy value for Enum as EnumMeta explicity checks for it, but of course until +# EnumMeta finishes running the first time the Enum class doesn't exist. This +# is also why there are checks in EnumMeta like `if Enum is not None` +Enum = None + + +class EnumMeta(type): + """Metaclass for Enum""" + @classmethod + def __prepare__(metacls, cls, bases): + return _EnumDict() + + def __new__(metacls, cls, bases, classdict): + # an Enum class is final once enumeration items have been defined; it + # cannot be mixed with other types (int, float, etc.) if it has an + # inherited __new__ unless a new __new__ is defined (or the resulting + # class will fail). + if type(classdict) is dict: + original_dict = classdict + classdict = _EnumDict() + for k, v in original_dict.items(): + classdict[k] = v + + member_type, first_enum = metacls._get_mixins_(bases) + __new__, save_new, use_args = metacls._find_new_(classdict, member_type, + first_enum) + # save enum items into separate mapping so they don't get baked into + # the new class + members = dict((k, classdict[k]) for k in classdict._member_names) + for name in classdict._member_names: + del classdict[name] + + # py2 support for definition order + _order_ = classdict.get('_order_') + if _order_ is None: + if pyver < 3.0: + try: + _order_ = [name for (name, value) in sorted(members.items(), key=lambda item: item[1])] + except TypeError: + _order_ = [name for name in sorted(members.keys())] + else: + _order_ = classdict._member_names + else: + del classdict['_order_'] + if pyver < 3.0: + _order_ = _order_.replace(',', ' ').split() + aliases = [name for name in members if name not in _order_] + _order_ += aliases + + # check for illegal enum names (any others?) + invalid_names = set(members) & set(['mro']) + if invalid_names: + raise ValueError('Invalid enum member name(s): %s' % ( + ', '.join(invalid_names), )) + + # save attributes from super classes so we know if we can take + # the shortcut of storing members in the class dict + base_attributes = set([a for b in bases for a in b.__dict__]) + # create our new Enum type + enum_class = super(EnumMeta, metacls).__new__(metacls, cls, bases, classdict) + enum_class._member_names_ = [] # names in random order + if OrderedDict is not None: + enum_class._member_map_ = OrderedDict() + else: + enum_class._member_map_ = {} # name->value map + enum_class._member_type_ = member_type + + # Reverse value->name map for hashable values. + enum_class._value2member_map_ = {} + + # instantiate them, checking for duplicates as we go + # we instantiate first instead of checking for duplicates first in case + # a custom __new__ is doing something funky with the values -- such as + # auto-numbering ;) + if __new__ is None: + __new__ = enum_class.__new__ + for member_name in _order_: + value = members[member_name] + if not isinstance(value, tuple): + args = (value, ) + else: + args = value + if member_type is tuple: # special case for tuple enums + args = (args, ) # wrap it one more time + if not use_args or not args: + enum_member = __new__(enum_class) + if not hasattr(enum_member, '_value_'): + enum_member._value_ = value + else: + enum_member = __new__(enum_class, *args) + if not hasattr(enum_member, '_value_'): + enum_member._value_ = member_type(*args) + value = enum_member._value_ + enum_member._name_ = member_name + enum_member.__objclass__ = enum_class + enum_member.__init__(*args) + # If another member with the same value was already defined, the + # new member becomes an alias to the existing one. + for name, canonical_member in enum_class._member_map_.items(): + if canonical_member.value == enum_member._value_: + enum_member = canonical_member + break + else: + # Aliases don't appear in member names (only in __members__). + enum_class._member_names_.append(member_name) + # performance boost for any member that would not shadow + # a DynamicClassAttribute (aka _RouteClassAttributeToGetattr) + if member_name not in base_attributes: + setattr(enum_class, member_name, enum_member) + # now add to _member_map_ + enum_class._member_map_[member_name] = enum_member + try: + # This may fail if value is not hashable. We can't add the value + # to the map, and by-value lookups for this value will be + # linear. + enum_class._value2member_map_[value] = enum_member + except TypeError: + pass + + + # If a custom type is mixed into the Enum, and it does not know how + # to pickle itself, pickle.dumps will succeed but pickle.loads will + # fail. Rather than have the error show up later and possibly far + # from the source, sabotage the pickle protocol for this class so + # that pickle.dumps also fails. + # + # However, if the new class implements its own __reduce_ex__, do not + # sabotage -- it's on them to make sure it works correctly. We use + # __reduce_ex__ instead of any of the others as it is preferred by + # pickle over __reduce__, and it handles all pickle protocols. + unpicklable = False + if '__reduce_ex__' not in classdict: + if member_type is not object: + methods = ('__getnewargs_ex__', '__getnewargs__', + '__reduce_ex__', '__reduce__') + if not any(m in member_type.__dict__ for m in methods): + _make_class_unpicklable(enum_class) + unpicklable = True + + + # double check that repr and friends are not the mixin's or various + # things break (such as pickle) + for name in ('__repr__', '__str__', '__format__', '__reduce_ex__'): + class_method = getattr(enum_class, name) + obj_method = getattr(member_type, name, None) + enum_method = getattr(first_enum, name, None) + if name not in classdict and class_method is not enum_method: + if name == '__reduce_ex__' and unpicklable: + continue + setattr(enum_class, name, enum_method) + + # method resolution and int's are not playing nice + # Python's less than 2.6 use __cmp__ + + if pyver < 2.6: + + if issubclass(enum_class, int): + setattr(enum_class, '__cmp__', getattr(int, '__cmp__')) + + elif pyver < 3.0: + + if issubclass(enum_class, int): + for method in ( + '__le__', + '__lt__', + '__gt__', + '__ge__', + '__eq__', + '__ne__', + '__hash__', + ): + setattr(enum_class, method, getattr(int, method)) + + # replace any other __new__ with our own (as long as Enum is not None, + # anyway) -- again, this is to support pickle + if Enum is not None: + # if the user defined their own __new__, save it before it gets + # clobbered in case they subclass later + if save_new: + setattr(enum_class, '__member_new__', enum_class.__dict__['__new__']) + setattr(enum_class, '__new__', Enum.__dict__['__new__']) + return enum_class + + def __bool__(cls): + """ + classes/types should always be True. + """ + return True + + def __call__(cls, value, names=None, module=None, type=None, start=1): + """Either returns an existing member, or creates a new enum class. + + This method is used both when an enum class is given a value to match + to an enumeration member (i.e. Color(3)) and for the functional API + (i.e. Color = Enum('Color', names='red green blue')). + + When used for the functional API: `module`, if set, will be stored in + the new class' __module__ attribute; `type`, if set, will be mixed in + as the first base class. + + Note: if `module` is not set this routine will attempt to discover the + calling module by walking the frame stack; if this is unsuccessful + the resulting class will not be pickleable. + + """ + if names is None: # simple value lookup + return cls.__new__(cls, value) + # otherwise, functional API: we're creating a new Enum type + return cls._create_(value, names, module=module, type=type, start=start) + + def __contains__(cls, member): + return isinstance(member, cls) and member.name in cls._member_map_ + + def __delattr__(cls, attr): + # nicer error message when someone tries to delete an attribute + # (see issue19025). + if attr in cls._member_map_: + raise AttributeError( + "%s: cannot delete Enum member." % cls.__name__) + super(EnumMeta, cls).__delattr__(attr) + + def __dir__(self): + return (['__class__', '__doc__', '__members__', '__module__'] + + self._member_names_) + + @property + def __members__(cls): + """Returns a mapping of member name->value. + + This mapping lists all enum members, including aliases. Note that this + is a copy of the internal mapping. + + """ + return cls._member_map_.copy() + + def __getattr__(cls, name): + """Return the enum member matching `name` + + We use __getattr__ instead of descriptors or inserting into the enum + class' __dict__ in order to support `name` and `value` being both + properties for enum members (which live in the class' __dict__) and + enum members themselves. + + """ + if _is_dunder(name): + raise AttributeError(name) + try: + return cls._member_map_[name] + except KeyError: + raise AttributeError(name) + + def __getitem__(cls, name): + return cls._member_map_[name] + + def __iter__(cls): + return (cls._member_map_[name] for name in cls._member_names_) + + def __reversed__(cls): + return (cls._member_map_[name] for name in reversed(cls._member_names_)) + + def __len__(cls): + return len(cls._member_names_) + + __nonzero__ = __bool__ + + def __repr__(cls): + return "" % cls.__name__ + + def __setattr__(cls, name, value): + """Block attempts to reassign Enum members. + + A simple assignment to the class namespace only changes one of the + several possible ways to get an Enum member from the Enum class, + resulting in an inconsistent Enumeration. + + """ + member_map = cls.__dict__.get('_member_map_', {}) + if name in member_map: + raise AttributeError('Cannot reassign members.') + super(EnumMeta, cls).__setattr__(name, value) + + def _create_(cls, class_name, names=None, module=None, type=None, start=1): + """Convenience method to create a new Enum class. + + `names` can be: + + * A string containing member names, separated either with spaces or + commas. Values are auto-numbered from 1. + * An iterable of member names. Values are auto-numbered from 1. + * An iterable of (member name, value) pairs. + * A mapping of member name -> value. + + """ + if pyver < 3.0: + # if class_name is unicode, attempt a conversion to ASCII + if isinstance(class_name, unicode): + try: + class_name = class_name.encode('ascii') + except UnicodeEncodeError: + raise TypeError('%r is not representable in ASCII' % class_name) + metacls = cls.__class__ + if type is None: + bases = (cls, ) + else: + bases = (type, cls) + classdict = metacls.__prepare__(class_name, bases) + _order_ = [] + + # special processing needed for names? + if isinstance(names, basestring): + names = names.replace(',', ' ').split() + if isinstance(names, (tuple, list)) and isinstance(names[0], basestring): + names = [(e, i+start) for (i, e) in enumerate(names)] + + # Here, names is either an iterable of (name, value) or a mapping. + item = None # in case names is empty + for item in names: + if isinstance(item, basestring): + member_name, member_value = item, names[item] + else: + member_name, member_value = item + classdict[member_name] = member_value + _order_.append(member_name) + # only set _order_ in classdict if name/value was not from a mapping + if not isinstance(item, basestring): + classdict['_order_'] = ' '.join(_order_) + enum_class = metacls.__new__(metacls, class_name, bases, classdict) + + # TODO: replace the frame hack if a blessed way to know the calling + # module is ever developed + if module is None: + try: + module = _sys._getframe(2).f_globals['__name__'] + except (AttributeError, ValueError): + pass + if module is None: + _make_class_unpicklable(enum_class) + else: + enum_class.__module__ = module + + return enum_class + + @staticmethod + def _get_mixins_(bases): + """Returns the type for creating enum members, and the first inherited + enum class. + + bases: the tuple of bases that was given to __new__ + + """ + if not bases or Enum is None: + return object, Enum + + + # double check that we are not subclassing a class with existing + # enumeration members; while we're at it, see if any other data + # type has been mixed in so we can use the correct __new__ + member_type = first_enum = None + for base in bases: + if (base is not Enum and + issubclass(base, Enum) and + base._member_names_): + raise TypeError("Cannot extend enumerations") + # base is now the last base in bases + if not issubclass(base, Enum): + raise TypeError("new enumerations must be created as " + "`ClassName([mixin_type,] enum_type)`") + + # get correct mix-in type (either mix-in type of Enum subclass, or + # first base if last base is Enum) + if not issubclass(bases[0], Enum): + member_type = bases[0] # first data type + first_enum = bases[-1] # enum type + else: + for base in bases[0].__mro__: + # most common: (IntEnum, int, Enum, object) + # possible: (, , + # , , + # ) + if issubclass(base, Enum): + if first_enum is None: + first_enum = base + else: + if member_type is None: + member_type = base + + return member_type, first_enum + + if pyver < 3.0: + @staticmethod + def _find_new_(classdict, member_type, first_enum): + """Returns the __new__ to be used for creating the enum members. + + classdict: the class dictionary given to __new__ + member_type: the data type whose __new__ will be used by default + first_enum: enumeration to check for an overriding __new__ + + """ + # now find the correct __new__, checking to see of one was defined + # by the user; also check earlier enum classes in case a __new__ was + # saved as __member_new__ + __new__ = classdict.get('__new__', None) + if __new__: + return None, True, True # __new__, save_new, use_args + + N__new__ = getattr(None, '__new__') + O__new__ = getattr(object, '__new__') + if Enum is None: + E__new__ = N__new__ + else: + E__new__ = Enum.__dict__['__new__'] + # check all possibles for __member_new__ before falling back to + # __new__ + for method in ('__member_new__', '__new__'): + for possible in (member_type, first_enum): + try: + target = possible.__dict__[method] + except (AttributeError, KeyError): + target = getattr(possible, method, None) + if target not in [ + None, + N__new__, + O__new__, + E__new__, + ]: + if method == '__member_new__': + classdict['__new__'] = target + return None, False, True + if isinstance(target, staticmethod): + target = target.__get__(member_type) + __new__ = target + break + if __new__ is not None: + break + else: + __new__ = object.__new__ + + # if a non-object.__new__ is used then whatever value/tuple was + # assigned to the enum member name will be passed to __new__ and to the + # new enum member's __init__ + if __new__ is object.__new__: + use_args = False + else: + use_args = True + + return __new__, False, use_args + else: + @staticmethod + def _find_new_(classdict, member_type, first_enum): + """Returns the __new__ to be used for creating the enum members. + + classdict: the class dictionary given to __new__ + member_type: the data type whose __new__ will be used by default + first_enum: enumeration to check for an overriding __new__ + + """ + # now find the correct __new__, checking to see of one was defined + # by the user; also check earlier enum classes in case a __new__ was + # saved as __member_new__ + __new__ = classdict.get('__new__', None) + + # should __new__ be saved as __member_new__ later? + save_new = __new__ is not None + + if __new__ is None: + # check all possibles for __member_new__ before falling back to + # __new__ + for method in ('__member_new__', '__new__'): + for possible in (member_type, first_enum): + target = getattr(possible, method, None) + if target not in ( + None, + None.__new__, + object.__new__, + Enum.__new__, + ): + __new__ = target + break + if __new__ is not None: + break + else: + __new__ = object.__new__ + + # if a non-object.__new__ is used then whatever value/tuple was + # assigned to the enum member name will be passed to __new__ and to the + # new enum member's __init__ + if __new__ is object.__new__: + use_args = False + else: + use_args = True + + return __new__, save_new, use_args + + +######################################################## +# In order to support Python 2 and 3 with a single +# codebase we have to create the Enum methods separately +# and then use the `type(name, bases, dict)` method to +# create the class. +######################################################## +temp_enum_dict = {} +temp_enum_dict['__doc__'] = "Generic enumeration.\n\n Derive from this class to define new enumerations.\n\n" + +def __new__(cls, value): + # all enum instances are actually created during class construction + # without calling this method; this method is called by the metaclass' + # __call__ (i.e. Color(3) ), and by pickle + if type(value) is cls: + # For lookups like Color(Color.red) + value = value.value + #return value + # by-value search for a matching enum member + # see if it's in the reverse mapping (for hashable values) + try: + if value in cls._value2member_map_: + return cls._value2member_map_[value] + except TypeError: + # not there, now do long search -- O(n) behavior + for member in cls._member_map_.values(): + if member.value == value: + return member + raise ValueError("%s is not a valid %s" % (value, cls.__name__)) +temp_enum_dict['__new__'] = __new__ +del __new__ + +def __repr__(self): + return "<%s.%s: %r>" % ( + self.__class__.__name__, self._name_, self._value_) +temp_enum_dict['__repr__'] = __repr__ +del __repr__ + +def __str__(self): + return "%s.%s" % (self.__class__.__name__, self._name_) +temp_enum_dict['__str__'] = __str__ +del __str__ + +if pyver >= 3.0: + def __dir__(self): + added_behavior = [ + m + for cls in self.__class__.mro() + for m in cls.__dict__ + if m[0] != '_' and m not in self._member_map_ + ] + return (['__class__', '__doc__', '__module__', ] + added_behavior) + temp_enum_dict['__dir__'] = __dir__ + del __dir__ + +def __format__(self, format_spec): + # mixed-in Enums should use the mixed-in type's __format__, otherwise + # we can get strange results with the Enum name showing up instead of + # the value + + # pure Enum branch + if self._member_type_ is object: + cls = str + val = str(self) + # mix-in branch + else: + cls = self._member_type_ + val = self.value + return cls.__format__(val, format_spec) +temp_enum_dict['__format__'] = __format__ +del __format__ + + +#################################### +# Python's less than 2.6 use __cmp__ + +if pyver < 2.6: + + def __cmp__(self, other): + if type(other) is self.__class__: + if self is other: + return 0 + return -1 + return NotImplemented + raise TypeError("unorderable types: %s() and %s()" % (self.__class__.__name__, other.__class__.__name__)) + temp_enum_dict['__cmp__'] = __cmp__ + del __cmp__ + +else: + + def __le__(self, other): + raise TypeError("unorderable types: %s() <= %s()" % (self.__class__.__name__, other.__class__.__name__)) + temp_enum_dict['__le__'] = __le__ + del __le__ + + def __lt__(self, other): + raise TypeError("unorderable types: %s() < %s()" % (self.__class__.__name__, other.__class__.__name__)) + temp_enum_dict['__lt__'] = __lt__ + del __lt__ + + def __ge__(self, other): + raise TypeError("unorderable types: %s() >= %s()" % (self.__class__.__name__, other.__class__.__name__)) + temp_enum_dict['__ge__'] = __ge__ + del __ge__ + + def __gt__(self, other): + raise TypeError("unorderable types: %s() > %s()" % (self.__class__.__name__, other.__class__.__name__)) + temp_enum_dict['__gt__'] = __gt__ + del __gt__ + + +def __eq__(self, other): + if type(other) is self.__class__: + return self is other + return NotImplemented +temp_enum_dict['__eq__'] = __eq__ +del __eq__ + +def __ne__(self, other): + if type(other) is self.__class__: + return self is not other + return NotImplemented +temp_enum_dict['__ne__'] = __ne__ +del __ne__ + +def __hash__(self): + return hash(self._name_) +temp_enum_dict['__hash__'] = __hash__ +del __hash__ + +def __reduce_ex__(self, proto): + return self.__class__, (self._value_, ) +temp_enum_dict['__reduce_ex__'] = __reduce_ex__ +del __reduce_ex__ + +# _RouteClassAttributeToGetattr is used to provide access to the `name` +# and `value` properties of enum members while keeping some measure of +# protection from modification, while still allowing for an enumeration +# to have members named `name` and `value`. This works because enumeration +# members are not set directly on the enum class -- __getattr__ is +# used to look them up. + +@_RouteClassAttributeToGetattr +def name(self): + return self._name_ +temp_enum_dict['name'] = name +del name + +@_RouteClassAttributeToGetattr +def value(self): + return self._value_ +temp_enum_dict['value'] = value +del value + +@classmethod +def _convert(cls, name, module, filter, source=None): + """ + Create a new Enum subclass that replaces a collection of global constants + """ + # convert all constants from source (or module) that pass filter() to + # a new Enum called name, and export the enum and its members back to + # module; + # also, replace the __reduce_ex__ method so unpickling works in + # previous Python versions + module_globals = vars(_sys.modules[module]) + if source: + source = vars(source) + else: + source = module_globals + members = dict((name, value) for name, value in source.items() if filter(name)) + cls = cls(name, members, module=module) + cls.__reduce_ex__ = _reduce_ex_by_name + module_globals.update(cls.__members__) + module_globals[name] = cls + return cls +temp_enum_dict['_convert'] = _convert +del _convert + +Enum = EnumMeta('Enum', (object, ), temp_enum_dict) +del temp_enum_dict + +# Enum has now been created +########################### + +class IntEnum(int, Enum): + """Enum where members are also (and must be) ints""" + +def _reduce_ex_by_name(self, proto): + return self.name + +def unique(enumeration): + """Class decorator that ensures only unique members exist in an enumeration.""" + duplicates = [] + for name, member in enumeration.__members__.items(): + if name != member.name: + duplicates.append((name, member.name)) + if duplicates: + duplicate_names = ', '.join( + ["%s -> %s" % (alias, name) for (alias, name) in duplicates] + ) + raise ValueError('duplicate names found in %r: %s' % + (enumeration, duplicate_names) + ) + return enumeration diff --git a/python/examples/bin_info.py b/python/examples/bin_info.py index a472495a..c574a530 100644 --- a/python/examples/bin_info.py +++ b/python/examples/bin_info.py @@ -20,37 +20,51 @@ # IN THE SOFTWARE. import sys -import binaryninja +import binaryninja.log as log +import binaryninja.binaryview as view +import binaryninja.interaction as interaction +from binaryninja.plugin import PluginCommand -if sys.platform.lower().startswith("linux"): - bintype = "ELF" -elif sys.platform.lower() == "darwin": - bintype = "Mach-O" -else: - raise Exception("%s is not supported on this plugin" % sys.platform) -if len(sys.argv) > 1: - target = sys.argv[1] -else: - target = "/bin/ls" +def bininfo(bv): + if bv is None: + filename = "" + if len(sys.argv) > 1: + filename = sys.argv[1] + else: + filename = interaction.get_open_filename_input("Filename:") + if filename is None: + log.log_warn("No file specified") + sys.exit(1) -bv = binaryninja.BinaryViewType[bintype].open(target) -bv.update_analysis_and_wait() + bv = view.BinaryViewType.get_view_of_file(filename) + log.redirect_output_to_log() + log.log_to_stdout(True) -log.log_info("-------- %s --------" % target) -log.log_info("START: 0x%x" % bv.start) -log.log_info("ENTRY: 0x%x" % bv.entry_point) -log.log_info("ARCH: %s" % bv.arch.name) -log.log_info("\n-------- Function List --------") + contents = "## %s ##\n" % bv.file.filename + contents += "- START: 0x%x\n\n" % bv.start + contents += "- ENTRY: 0x%x\n\n" % bv.entry_point + contents += "- ARCH: %s\n\n" % bv.arch.name + contents += "### First 10 Functions ###\n" -for func in bv.functions: - log.log_info(func.symbol.name) + contents += "| Start | Name |\n" + contents += "|------:|:-------|\n" + for i in xrange(min(10, len(bv.functions))): + contents += "| 0x%x | %s |\n" % (bv.functions[i].start, bv.functions[i].symbol.full_name) + contents += "### First 10 Strings ###\n" + contents += "| Start | Length | String |\n" + contents += "|------:|-------:|:-------|\n" + for i in xrange(min(10, len(bv.strings))): + start = bv.strings[i].start + length = bv.strings[i].length + string = bv.read(start, length) + contents += "| 0x%x |%d | %s |\n" % (start, length, string) -log.log_info("\n-------- First 10 strings --------") + interaction.show_markdown_report("Binary Info Report", contents) -for i in xrange(10): - start = bv.strings[i].start - length = bv.strings[i].length - string = bv.read(start, length) - log.log_info("0x%x (%d):\t%s" % (start, length, string)) + +if __name__ == "__main__": + bininfo(None) +else: + PluginCommand.register("Binary Info", "Display basic info about the binary", bininfo) diff --git a/python/examples/instruction_iterator.py b/python/examples/instruction_iterator.py index 6c9d9653..47717aa0 100644 --- a/python/examples/instruction_iterator.py +++ b/python/examples/instruction_iterator.py @@ -20,7 +20,7 @@ # IN THE SOFTWARE. import sys -import binaryninja +import binaryninja as binja if sys.platform.lower().startswith("linux"): @@ -35,30 +35,30 @@ if len(sys.argv) > 1: else: target = "/bin/ls" -bv = binaryninja.BinaryViewType[bintype].open(target) +bv = binja.BinaryViewType[bintype].open(target) bv.update_analysis_and_wait() - -print "-------- %s --------" % target -print "START: 0x%x" % bv.start -print "ENTRY: 0x%x" % bv.entry_point -print "ARCH: %s" % bv.arch.name -print "\n-------- Function List --------" +binja.log_to_stdout(True) +binja.log_info("-------- %s --------" % target) +binja.log_info("START: 0x%x" % bv.start) +binja.log_info("ENTRY: 0x%x" % bv.entry_point) +binja.log_info("ARCH: %s" % bv.arch.name) +binja.log_info("\n-------- Function List --------") """ print all the functions, their basic blocks, and their il instructions """ for func in bv.functions: - print repr(func) + binja.log_info(repr(func)) for block in func.low_level_il: - print "\t{0}".format(block) + binja.log_info("\t{0}".format(block)) for insn in block: - print "\t\t{0}".format(insn) + binja.log_info("\t\t{0}".format(insn)) """ print all the functions, their basic blocks, and their mc instructions """ for func in bv.functions: - print repr(func) + binja.log_info(repr(func)) for block in func: - print "\t{0}".format(block) + binja.log_info("\t{0}".format(block)) for insn in block: - print "\t\t{0}".format(insn) + binja.log_info("\t\t{0}".format(insn)) diff --git a/python/platform.py b/python/platform.py index d69c38d1..6c3eefea 100644 --- a/python/platform.py +++ b/python/platform.py @@ -241,3 +241,12 @@ class Platform(object): :rtype: None """ core.BNRegisterPlatformCallingConvention(self.handle, cc.handle) + + def get_related_platform(self, arch): + result = core.BNGetRelatedPlatform(self.handle, arch.handle) + if not result: + return None + return Platform(None, handle = result) + + def add_related_platform(self, arch, platform): + core.BNAddRelatedPlatform(self.handle, arch.handle, platform.handle) -- cgit v1.3.1 From 842aba557f24ca9ab63f05cec6aa0c0efebd51b4 Mon Sep 17 00:00:00 2001 From: Peter LaFosse Date: Mon, 2 Jan 2017 15:19:47 -0500 Subject: Making platform and architecture optional parameters where possible --- python/architecture.py | 6 ++ python/basicblock.py | 47 +++++++++-- python/binaryview.py | 153 +++++++++++++++++++++-------------- python/examples/jump_table.py | 2 +- python/examples/print_syscalls.py | 2 +- python/filemetadata.py | 8 +- python/function.py | 162 ++++++++++++++++++++++++++++++++------ python/scriptingprovider.py | 43 ++++++++++ 8 files changed, 330 insertions(+), 93 deletions(-) (limited to 'python/binaryview.py') 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 = 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 [] """ + 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 [] """ + 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) >>> """ + 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') + + """ + 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') + + """ + 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') + + """ + 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) + + """ + 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 -- cgit v1.3.1 From 2421d9a6e6e86ff3f37056a68454b7437fb60860 Mon Sep 17 00:00:00 2001 From: Peter LaFosse Date: Mon, 2 Jan 2017 16:15:07 -0500 Subject: Manual merging with dev --- api-docs/source/conf.py | 8 +- binaryninjaapi.h | 2 + binaryninjacore.h | 3 + binaryview.cpp | 7 ++ docs/.s3_website.yaml | 3 + docs/getting-started.md | 1 + docs/guide/troubleshooting.md | 22 +++- platform.cpp | 9 ++ python/binaryview.py | 29 ++++- python/bntype.py | 18 +-- python/examples/nsf.py | 138 ++++++++++++++++++++++ python/lowlevelil.py | 267 +++++++++++++++++++++--------------------- 12 files changed, 354 insertions(+), 153 deletions(-) create mode 100644 docs/.s3_website.yaml create mode 100644 python/examples/nsf.py (limited to 'python/binaryview.py') diff --git a/api-docs/source/conf.py b/api-docs/source/conf.py index 42bcfb87..15e06045 100644 --- a/api-docs/source/conf.py +++ b/api-docs/source/conf.py @@ -121,7 +121,7 @@ exclude_patterns = [] # If true, the current module name will be prepended to all description # unit titles (such as .. function::). # -# add_module_names = True +add_module_names = True # If true, sectionauthor and moduleauthor directives will be shown in the # output. They are ignored by default. @@ -211,7 +211,7 @@ html_static_path = ['_static'] # If false, no module index is generated. # -# html_domain_indices = True +html_domain_indices = True # If false, no index is generated. # @@ -219,11 +219,11 @@ html_static_path = ['_static'] # If true, the index is split into individual pages for each letter. # -# html_split_index = False +html_split_index = False # If true, links to the reST sources are added to the pages. # -# html_show_sourcelink = True +html_show_sourcelink = True # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. # diff --git a/binaryninjaapi.h b/binaryninjaapi.h index 6311271c..a918fc42 100644 --- a/binaryninjaapi.h +++ b/binaryninjaapi.h @@ -926,6 +926,7 @@ namespace BinaryNinja std::vector> GetSymbolsOfType(BNSymbolType type, uint64_t start, uint64_t len); void DefineAutoSymbol(Ref sym); + void DefineAutoSymbolAndVariableOrFunction(Ref platform, Ref sym, Ref type); void UndefineAutoSymbol(Ref sym); void DefineUserSymbol(Ref sym); @@ -2243,6 +2244,7 @@ namespace BinaryNinja Ref GetRelatedPlatform(Architecture* arch); void AddRelatedPlatform(Architecture* arch, Platform* platform); + Ref GetAssociatedPlatformByAddress(uint64_t& addr); }; class ScriptingOutputListener diff --git a/binaryninjacore.h b/binaryninjacore.h index ea81c388..b2ed7cd3 100644 --- a/binaryninjacore.h +++ b/binaryninjacore.h @@ -1877,6 +1877,8 @@ extern "C" BINARYNINJACOREAPI void BNDefineUserSymbol(BNBinaryView* view, BNSymbol* sym); BINARYNINJACOREAPI void BNUndefineUserSymbol(BNBinaryView* view, BNSymbol* sym); BINARYNINJACOREAPI void BNDefineImportedFunction(BNBinaryView* view, BNSymbol* importAddressSym, BNFunction* func); + BINARYNINJACOREAPI void BNDefineAutoSymbolAndVariableOrFunction(BNBinaryView* view, BNPlatform* platform, + BNSymbol* sym, BNType* type); BINARYNINJACOREAPI BNSymbol* BNImportedFunctionFromImportAddressSymbol(BNSymbol* sym, uint64_t addr); @@ -2135,6 +2137,7 @@ extern "C" BINARYNINJACOREAPI BNPlatform* BNGetRelatedPlatform(BNPlatform* platform, BNArchitecture* arch); BINARYNINJACOREAPI void BNAddRelatedPlatform(BNPlatform* platform, BNArchitecture* arch, BNPlatform* related); + BINARYNINJACOREAPI BNPlatform* BNGetAssociatedPlatformByAddress(BNPlatform* platform, uint64_t* addr); //Demangler BINARYNINJACOREAPI bool BNDemangleMS(BNArchitecture* arch, diff --git a/binaryview.cpp b/binaryview.cpp index ff19de18..cc6667c5 100644 --- a/binaryview.cpp +++ b/binaryview.cpp @@ -1156,6 +1156,13 @@ void BinaryView::DefineAutoSymbol(Ref sym) } +void BinaryView::DefineAutoSymbolAndVariableOrFunction(Ref platform, Ref sym, Ref type) +{ + BNDefineAutoSymbolAndVariableOrFunction(m_object, platform ? platform->GetObject() : nullptr, sym->GetObject(), + type ? type->GetObject() : nullptr); +} + + void BinaryView::UndefineAutoSymbol(Ref sym) { BNUndefineAutoSymbol(m_object, sym->GetObject()); diff --git a/docs/.s3_website.yaml b/docs/.s3_website.yaml new file mode 100644 index 00000000..02c4a996 --- /dev/null +++ b/docs/.s3_website.yaml @@ -0,0 +1,3 @@ +s3_bucket: docs.binary.ninja +site: ../site +s3_reduced_redundancy: True diff --git a/docs/getting-started.md b/docs/getting-started.md index 82c833a5..c78aa737 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -62,6 +62,7 @@ Switching views happens multiple ways. In some instances, it's automatic (clicki - `;` : Adds a comment - `i` : Switches between disassembly and low-level il in graph view - `y` : Change type + - `a` : Change the data type to an ASCII string - [1248] : Change type directly to a data variable of the indicated widths - `d` : Switches between data variables of various widths - `r` : Change the data type to single ASCII character diff --git a/docs/guide/troubleshooting.md b/docs/guide/troubleshooting.md index 68a4d328..a74ecb68 100644 --- a/docs/guide/troubleshooting.md +++ b/docs/guide/troubleshooting.md @@ -9,22 +9,36 @@ ## License Problems -- If experiencing problems with Windows UAC permissions during an update, the easiest fix is to completely un-install and re-download the latest installer. Preferences are saved outside the installation folder and are preserved, though you might want to remove your [license](/getting-started/index.html#license). +- If experiencing problems with Windows UAC permissions during an update, the easiest fix is to completely un-install and [recover][recover] the latest installer and license. Preferences are saved outside the installation folder and are preserved, though you might want to remove your [license](/getting-started/index.html#license). - If you need to change the email address on your license, contact [support]. -## Arch Linux +## Linux -Arch Linux is not an officially supported operating system, but many of our users have run it, and there are a few pitfalls to watch out for. +Given the diversity of Linux distributions, some work-arounds are required to run Binary Ninja on platforms that are not [officially supported][faq]. + +### Arch Linux - Install python2 from the [official repositories][archrepo] - Install the [libcurl-compat] library from AUR, and run Binary Ninja via `LD_PRELOAD=libcurl.so.3 ~/binaryninja/binaryninja` +### KDE + +To run Binary Ninja in a KDE based environment, set the `QT_PLUGIN_PATH` to the `QT` sub-folder: + +``` +cd ~/binaryninja +QT_PLUGIN_PATH=./qt ./binaryninja +``` + + ## API - - If the GUI launches but the license file is not valid, check that you're using the right version of Python. Only a 64-bit Python 2.7 is supported at this time. + - If the GUI launches but the license file is not valid when launched from the command-line, check that you're using the right version of Python. Only a 64-bit Python 2.7 is supported at this time. Additionally, the [personal][purchase] edition does not support headless operation. [known issues]: https://github.com/Vector35/binaryninja-api/issues?q=is%3Aissue [libcurl-compat]: https://aur.archlinux.org/packages/libcurl-compat/ [archrepo]: https://wiki.archlinux.org/index.php/Official_repositories [recover]: https://binary.ninja/recover.html [support]: https://binary.ninja/support.html +[faq]: https://binary.ninja/faq.html +[purchase]: https://binary.ninja/purchase.html diff --git a/platform.cpp b/platform.cpp index 9b4053db..7a6571cc 100644 --- a/platform.cpp +++ b/platform.cpp @@ -244,3 +244,12 @@ void Platform::AddRelatedPlatform(Architecture* arch, Platform* platform) { BNAddRelatedPlatform(m_object, arch->GetObject(), platform->GetObject()); } + + +Ref Platform::GetAssociatedPlatformByAddress(uint64_t& addr) +{ + BNPlatform* platform = BNGetAssociatedPlatformByAddress(m_object, &addr); + if (!platform) + return nullptr; + return new Platform(platform); +} diff --git a/python/binaryview.py b/python/binaryview.py index 7c85cd52..b4be159c 100644 --- a/python/binaryview.py +++ b/python/binaryview.py @@ -590,6 +590,16 @@ class BinaryView(object): @classmethod def set_default_session_data(cls, name, value): + """ + ```set_default_session_data``` saves a variable to the BinaryView. + :param name: name of the variable to be saved + :param value: value of the variable to be saved + + :Example: + >>> BinaryView.set_default_session_data("variable_name", "value") + >>> bv.session_data.variable_name + 'value' + """ _BinaryViewAssociatedDataStore.set_default(name, value) def __del__(self): @@ -1932,6 +1942,19 @@ class BinaryView(object): return basicblock.BasicBlock(self, block) def get_code_refs(self, addr, length=None): + """ + ``get_code_refs`` returns a list of ReferenceSource objects (xrefs or cross-references) that point to the provided virtual address. + + :param int addr: virtual address to query for references + :return: List of References for the given virtual address + :rtype: list(ReferenceSource) + :Example: + + >>> bv.get_code_refs(here) + [] + >>> + + """ count = ctypes.c_ulonglong(0) if length is None: refs = core.BNGetCodeReferences(self.handle, addr, count) @@ -3434,7 +3457,7 @@ class BinaryWriter(object): def write16(self, value): """ - ```` writes the lowest order two bytes from the integer ``value`` to the current offset, using internal endianness. + ``write16`` writes the lowest order two bytes from the integer ``value`` to the current offset, using internal endianness. :param int value: integer value to write. :return: boolean True on success, False on failure. @@ -3444,7 +3467,7 @@ class BinaryWriter(object): def write32(self, value): """ - ```` writes the lowest order four bytes from the integer ``value`` to the current offset, using internal endianness. + ``write32`` writes the lowest order four bytes from the integer ``value`` to the current offset, using internal endianness. :param int value: integer value to write. :return: boolean True on success, False on failure. @@ -3454,7 +3477,7 @@ class BinaryWriter(object): def write64(self, value): """ - ```` writes the lowest order eight bytes from the integer ``value`` to the current offset, using internal endianness. + ``write64`` writes the lowest order eight bytes from the integer ``value`` to the current offset, using internal endianness. :param int value: integer value to write. :return: boolean True on success, False on failure. diff --git a/python/bntype.py b/python/bntype.py index 9f070168..1822c5df 100644 --- a/python/bntype.py +++ b/python/bntype.py @@ -235,8 +235,8 @@ class Type(object): return Type(core.BNCreateBoolType()) @classmethod - def int(self, width, sign = True): - return Type(core.BNCreateIntegerType(width, sign)) + def int(self, width, sign = True, altname=""): + return Type(core.BNCreateIntegerType(width, sign, altname)) @classmethod def float(self, width): @@ -251,13 +251,13 @@ class Type(object): return Type(core.BNCreateUnknownType(unknown_type.handle)) @classmethod - def enumeration_type(self, arch, e, width = None): + def enumeration_type(self, arch, e, width=None): if width is None: width = arch.default_int_size return Type(core.BNCreateEnumerationType(e.handle, width)) @classmethod - def pointer(self, arch, t, const = False): + def pointer(self, arch, t, const=False): return Type(core.BNCreatePointerType(arch.handle, t.handle, const)) @classmethod @@ -265,7 +265,7 @@ class Type(object): return Type(core.BNCreateArrayType(t.handle, count)) @classmethod - def function(self, ret, params, calling_convention = None, variable_arguments = False): + def function(self, ret, params, calling_convention=None, variable_arguments=False): param_buf = (core.BNNameAndType * len(params))() for i in xrange(0, len(params)): if isinstance(params[i], Type): @@ -287,7 +287,7 @@ class Type(object): class UnknownType(object): - def __init__(self, handle = None): + def __init__(self, handle=None): if handle is None: self.handle = core.BNCreateUnknownType() else: @@ -324,7 +324,7 @@ class StructureMember(object): class Structure(object): - def __init__(self, handle = None): + def __init__(self, handle=None): if handle is None: self.handle = core.BNCreateStructure() else: @@ -416,7 +416,7 @@ class EnumerationMember(object): class Enumeration(object): - def __init__(self, handle = None): + def __init__(self, handle=None): if handle is None: self.handle = core.BNCreateEnumeration() else: @@ -472,7 +472,7 @@ class TypeParserResult(object): return "{types: %s, variables: %s, functions: %s}" % (self.types, self.variables, self.functions) -def preprocess_source(source, filename = None, include_dirs = []): +def preprocess_source(source, filename=None, include_dirs=[]): """ ``preprocess_source`` run the C preprocessor on the given source or source filename. diff --git a/python/examples/nsf.py b/python/examples/nsf.py new file mode 100644 index 00000000..9d4ebd5c --- /dev/null +++ b/python/examples/nsf.py @@ -0,0 +1,138 @@ +# Copyright (c) 2015-2016 Vector 35 LLC +# +# 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 +# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +# sell copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +# IN THE SOFTWARE. +# +# +# Simple NSF file loader, primarily for analyzing: +# https://scarybeastsecurity.blogspot.com/2016/11/0day-exploit-compromising-linux-desktop.html +# + +from binaryninja import * +import struct +import traceback +import os + +class NSFView(BinaryView): + name = "NSF" + long_name = "Nintendo Sound Format" + + def __init__(self, data): + BinaryView.__init__(self, parent_view = data, file_metadata = data.file) + + @classmethod + def is_valid_for_data(self, data): + hdr = data.read(0, 128) + if len(hdr) < 128: + return False + if hdr[0:5] != "NESM\x1a": + return False + song_count = struct.unpack("B", hdr[6])[0] + if song_count < 1: + log_info("Appears to be an NSF, but no songs.") + return False + return True + + def init(self): + try: + hdr = self.parent_view.read(0, 128) + self.version = struct.unpack("B", hdr[5])[0] + self.song_count = struct.unpack("B", hdr[6])[0] + self.starting_song = struct.unpack("B", hdr[7])[0] + self.load_address = struct.unpack("{}(a, b)`` :rtype: LowLevelILExpr """ - return self.expr(core.BNLowLevelILOperation.LLIL_ADD, a.index, b.index, size = size, flags = flags) + return self.expr(core.BNLowLevelILOperation.LLIL_ADD, a.index, b.index, size=size, flags=flags) - def add_carry(self, size, a, b, flags = None): + def add_carry(self, size, a, b, flags=None): """ ``add_carry`` adds with carry expression ``a`` to expression ``b`` potentially setting flags ``flags`` and returning an expression of ``size`` bytes. @@ -518,9 +518,9 @@ class LowLevelILFunction(object): :return: The expression ``adc.{}(a, b)`` :rtype: LowLevelILExpr """ - return self.expr(core.BNLowLevelILOperation.LLIL_ADC, a.index, b.index, size = size, flags = flags) + return self.expr(core.BNLowLevelILOperation.LLIL_ADC, a.index, b.index, size=size, flags=flags) - def sub(self, size, a, b, flags = None): + def sub(self, size, a, b, flags=None): """ ``sub`` subtracts expression ``b`` from expression ``a`` potentially setting flags ``flags`` and returning an expression of ``size`` bytes. @@ -532,9 +532,9 @@ class LowLevelILFunction(object): :return: The expression ``sub.{}(a, b)`` :rtype: LowLevelILExpr """ - return self.expr(core.BNLowLevelILOperation.LLIL_SUB, a.index, b.index, size = size, flags = flags) + return self.expr(core.BNLowLevelILOperation.LLIL_SUB, a.index, b.index, size=size, flags=flags) - def sub_borrow(self, size, a, b, flags = None): + def sub_borrow(self, size, a, b, flags=None): """ ``sub_borrow`` subtracts with borrow expression ``b`` from expression ``a`` potentially setting flags ``flags`` and returning an expression of ``size`` bytes. @@ -546,9 +546,9 @@ class LowLevelILFunction(object): :return: The expression ``sbc.{}(a, b)`` :rtype: LowLevelILExpr """ - return self.expr(core.BNLowLevelILOperation.LLIL_SBB, a.index, b.index, size = size, flags = flags) + return self.expr(core.BNLowLevelILOperation.LLIL_SBB, a.index, b.index, size=size, flags=flags) - def and_expr(self, size, a, b, flags = None): + def and_expr(self, size, a, b, flags=None): """ ``and_expr`` bitwise and's expression ``a`` and expression ``b`` potentially setting flags ``flags`` and returning an expression of ``size`` bytes. @@ -560,9 +560,9 @@ class LowLevelILFunction(object): :return: The expression ``and.{}(a, b)`` :rtype: LowLevelILExpr """ - return self.expr(core.BNLowLevelILOperation.LLIL_AND, a.index, b.index, size = size, flags = flags) + return self.expr(core.BNLowLevelILOperation.LLIL_AND, a.index, b.index, size=size, flags=flags) - def or_expr(self, size, a, b, flags = None): + def or_expr(self, size, a, b, flags=None): """ ``or_expr`` bitwise or's expression ``a`` and expression ``b`` potentially setting flags ``flags`` and returning an expression of ``size`` bytes. @@ -574,9 +574,9 @@ class LowLevelILFunction(object): :return: The expression ``or.{}(a, b)`` :rtype: LowLevelILExpr """ - return self.expr(core.BNLowLevelILOperation.LLIL_OR, a.index, b.index, size = size, flags = flags) + return self.expr(core.BNLowLevelILOperation.LLIL_OR, a.index, b.index, size=size, flags=flags) - def xor_expr(self, size, a, b, flags = None): + def xor_expr(self, size, a, b, flags=None): """ ``xor_expr`` xor's expression ``a`` with expression ``b`` potentially setting flags ``flags`` and returning an expression of ``size`` bytes. @@ -588,9 +588,9 @@ class LowLevelILFunction(object): :return: The expression ``xor.{}(a, b)`` :rtype: LowLevelILExpr """ - return self.expr(core.BNLowLevelILOperation.LLIL_XOR, a.index, b.index, size = size, flags = flags) + return self.expr(core.BNLowLevelILOperation.LLIL_XOR, a.index, b.index, size=size, flags=flags) - def shift_left(self, size, a, b, flags = None): + def shift_left(self, size, a, b, flags=None): """ ``shift_left`` subtracts with borrow expression ``b`` from expression ``a`` potentially setting flags ``flags`` and returning an expression of ``size`` bytes. @@ -602,9 +602,9 @@ class LowLevelILFunction(object): :return: The expression ``lsl.{}(a, b)`` :rtype: LowLevelILExpr """ - return self.expr(core.BNLowLevelILOperation.LLIL_LSL, a.index, b.index, size = size, flags = flags) + return self.expr(core.BNLowLevelILOperation.LLIL_LSL, a.index, b.index, size=size, flags=flags) - def logical_shift_right(self, size, a, b, flags = None): + def logical_shift_right(self, size, a, b, flags=None): """ ``logical_shift_right`` shifts logically right expression ``a`` by expression ``b`` potentially setting flags ``flags``and returning an expression of ``size`` bytes. @@ -616,9 +616,9 @@ class LowLevelILFunction(object): :return: The expression ``lsr.{}(a, b)`` :rtype: LowLevelILExpr """ - return self.expr(core.BNLowLevelILOperation.LLIL_LSR, a.index, b.index, size = size, flags = flags) + return self.expr(core.BNLowLevelILOperation.LLIL_LSR, a.index, b.index, size=size, flags=flags) - def arith_shift_right(self, size, a, b, flags = None): + def arith_shift_right(self, size, a, b, flags=None): """ ``arith_shift_right`` shifts arithmatic right expression ``a`` by expression ``b`` potentially setting flags ``flags`` and returning an expression of ``size`` bytes. @@ -630,9 +630,9 @@ class LowLevelILFunction(object): :return: The expression ``asr.{}(a, b)`` :rtype: LowLevelILExpr """ - return self.expr(core.BNLowLevelILOperation.LLIL_ASR, a.index, b.index, size = size, flags = flags) + return self.expr(core.BNLowLevelILOperation.LLIL_ASR, a.index, b.index, size=size, flags=flags) - def rotate_left(self, size, a, b, flags = None): + def rotate_left(self, size, a, b, flags=None): """ ``rotate_left`` bitwise rotates left expression ``a`` by expression ``b`` potentially setting flags ``flags`` and returning an expression of ``size`` bytes. @@ -644,9 +644,9 @@ class LowLevelILFunction(object): :return: The expression ``rol.{}(a, b)`` :rtype: LowLevelILExpr """ - return self.expr(core.BNLowLevelILOperation.LLIL_ROL, a.index, b.index, size = size, flags = flags) + return self.expr(core.BNLowLevelILOperation.LLIL_ROL, a.index, b.index, size=size, flags=flags) - def rotate_left_carry(self, size, a, b, flags = None): + def rotate_left_carry(self, size, a, b, flags=None): """ ``rotate_left_carry`` bitwise rotates left with carry expression ``a`` by expression ``b`` potentially setting flags ``flags`` and returning an expression of ``size`` bytes. @@ -658,9 +658,9 @@ class LowLevelILFunction(object): :return: The expression ``rcl.{}(a, b)`` :rtype: LowLevelILExpr """ - return self.expr(core.LLIL_RLC, a.index, b.index, size = size, flags = flags) + return self.expr(core.LLIL_RLC, a.index, b.index, size=size, flags=flags) - def rotate_right(self, size, a, b, flags = None): + def rotate_right(self, size, a, b, flags=None): """ ``rotate_right`` bitwise rotates right expression ``a`` by expression ``b`` potentially setting flags ``flags`` and returning an expression of ``size`` bytes. @@ -672,9 +672,9 @@ class LowLevelILFunction(object): :return: The expression ``ror.{}(a, b)`` :rtype: LowLevelILExpr """ - return self.expr(core.BNLowLevelILOperation.LLIL_ROR, a.index, b.index, size = size, flags = flags) + return self.expr(core.BNLowLevelILOperation.LLIL_ROR, a.index, b.index, size=size, flags=flags) - def rotate_right_carry(self, size, a, b, flags = None): + def rotate_right_carry(self, size, a, b, flags=None): """ ``rotate_right_carry`` bitwise rotates right with carry expression ``a`` by expression ``b`` potentially setting flags ``flags`` and returning an expression of ``size`` bytes. @@ -686,9 +686,9 @@ class LowLevelILFunction(object): :return: The expression ``rcr.{}(a, b)`` :rtype: LowLevelILExpr """ - return self.expr(core.BNLowLevelILOperation.LLIL_RRC, a.index, b.index, size = size, flags = flags) + return self.expr(core.BNLowLevelILOperation.LLIL_RRC, a.index, b.index, size=size, flags=flags) - def mult(self, size, a, b, flags = None): + def mult(self, size, a, b, flags=None): """ ``mult`` multiplies expression ``a`` by expression ``b`` potentially setting flags ``flags`` and returning an expression of ``size`` bytes. @@ -700,9 +700,9 @@ class LowLevelILFunction(object): :return: The expression ``sbc.{}(a, b)`` :rtype: LowLevelILExpr """ - return self.expr(core.BNLowLevelILOperation.LLIL_MUL, a.index, b.index, size = size, flags = flags) + return self.expr(core.BNLowLevelILOperation.LLIL_MUL, a.index, b.index, size=size, flags=flags) - def mult_double_prec_signed(self, size, a, b, flags = None): + def mult_double_prec_signed(self, size, a, b, flags=None): """ ``mult_double_prec_signed`` multiplies signed with double precision expression ``a`` by expression ``b`` potentially setting flags ``flags`` and returning an expression of ``size`` bytes. @@ -714,9 +714,9 @@ class LowLevelILFunction(object): :return: The expression ``muls.dp.{}(a, b)`` :rtype: LowLevelILExpr """ - return self.expr(core.BNLowLevelILOperation.LLIL_MULS_DP, a.index, b.index, size = size, flags = flags) + return self.expr(core.BNLowLevelILOperation.LLIL_MULS_DP, a.index, b.index, size=size, flags=flags) - def mult_double_prec_unsigned(self, size, a, b, flags = None): + def mult_double_prec_unsigned(self, size, a, b, flags=None): """ ``mult_double_prec_unsigned`` multiplies unsigned with double precision expression ``a`` by expression ``b`` potentially setting flags ``flags`` and returning an expression of ``size`` bytes. @@ -728,9 +728,9 @@ class LowLevelILFunction(object): :return: The expression ``muls.dp.{}(a, b)`` :rtype: LowLevelILExpr """ - return self.expr(core.BNLowLevelILOperation.LLIL_MULU_DP, a.index, b.index, size = size, flags = flags) + return self.expr(core.BNLowLevelILOperation.LLIL_MULU_DP, a.index, b.index, size=size, flags=flags) - def div_signed(self, size, a, b, flags = None): + def div_signed(self, size, a, b, flags=None): """ ``div_signed`` signed divide expression ``a`` by expression ``b`` potentially setting flags ``flags`` and returning an expression of ``size`` bytes. @@ -742,9 +742,9 @@ class LowLevelILFunction(object): :return: The expression ``divs.{}(a, b)`` :rtype: LowLevelILExpr """ - return self.expr(core.BNLowLevelILOperation.LLIL_DIVS, a.index, b.index, size = size, flags = flags) + return self.expr(core.BNLowLevelILOperation.LLIL_DIVS, a.index, b.index, size=size, flags=flags) - def div_double_prec_signed(self, size, hi, lo, b, flags = None): + def div_double_prec_signed(self, size, hi, lo, b, flags=None): """ ``div_double_prec_signed`` signed double precision divide using expression ``hi`` and expression ``lo`` as a single double precision register by expression ``b`` potentially setting flags ``flags`` and returning an @@ -758,9 +758,9 @@ class LowLevelILFunction(object): :return: The expression ``divs.dp.{}(hi:lo, b)`` :rtype: LowLevelILExpr """ - return self.expr(core.BNLowLevelILOperation.LLIL_DIVS_DP, hi.index, lo.index, b.index, size = size, flags = flags) + return self.expr(core.BNLowLevelILOperation.LLIL_DIVS_DP, hi.index, lo.index, b.index, size=size, flags=flags) - def div_unsigned(self, size, a, b, flags = None): + def div_unsigned(self, size, a, b, flags=None): """ ``div_unsigned`` unsigned divide expression ``a`` by expression ``b`` potentially setting flags ``flags`` and returning an expression of ``size`` bytes. @@ -772,9 +772,9 @@ class LowLevelILFunction(object): :return: The expression ``divs.{}(a, b)`` :rtype: LowLevelILExpr """ - return self.expr(core.BNLowLevelILOperation.LLIL_DIVS, a.index, b.index, size = size, flags = flags) + return self.expr(core.BNLowLevelILOperation.LLIL_DIVS, a.index, b.index, size=size, flags=flags) - def div_double_prec_unsigned(self, size, hi, lo, b, flags = None): + def div_double_prec_unsigned(self, size, hi, lo, b, flags=None): """ ``div_double_prec_unsigned`` unsigned double precision divide using expression ``hi`` and expression ``lo`` as a single double precision register by expression ``b`` potentially setting flags ``flags`` and returning an @@ -788,9 +788,9 @@ class LowLevelILFunction(object): :return: The expression ``divs.dp.{}(hi:lo, b)`` :rtype: LowLevelILExpr """ - return self.expr(core.BNLowLevelILOperation.LLIL_DIVS_DP, hi.index, lo.index, b.index, size = size, flags = flags) + return self.expr(core.BNLowLevelILOperation.LLIL_DIVS_DP, hi.index, lo.index, b.index, size=size, flags=flags) - def mod_signed(self, size, a, b, flags = None): + def mod_signed(self, size, a, b, flags=None): """ ``mod_signed`` signed modulus expression ``a`` by expression ``b`` potentially setting flags ``flags`` and returning an expression of ``size`` bytes. @@ -802,9 +802,9 @@ class LowLevelILFunction(object): :return: The expression ``mods.{}(a, b)`` :rtype: LowLevelILExpr """ - return self.expr(core.BNLowLevelILOperation.LLIL_MODS, a.index, b.index, size = size, flags = flags) + return self.expr(core.BNLowLevelILOperation.LLIL_MODS, a.index, b.index, size=size, flags=flags) - def mod_double_prec_signed(self, size, hi, lo, b, flags = None): + def mod_double_prec_signed(self, size, hi, lo, b, flags=None): """ ``mod_double_prec_signed`` signed double precision modulus using expression ``hi`` and expression ``lo`` as a single double precision register by expression ``b`` potentially setting flags ``flags`` and returning an expression @@ -818,9 +818,9 @@ class LowLevelILFunction(object): :return: The expression ``mods.dp.{}(hi:lo, b)`` :rtype: LowLevelILExpr """ - return self.expr(core.BNLowLevelILOperation.LLIL_MODS_DP, hi.index, lo.index, b.index, size = size, flags = flags) + return self.expr(core.BNLowLevelILOperation.LLIL_MODS_DP, hi.index, lo.index, b.index, size=size, flags=flags) - def mod_unsigned(self, size, a, b, flags = None): + def mod_unsigned(self, size, a, b, flags=None): """ ``mod_unsigned`` unsigned modulus expression ``a`` by expression ``b`` potentially setting flags ``flags`` and returning an expression of ``size`` bytes. @@ -832,9 +832,9 @@ class LowLevelILFunction(object): :return: The expression ``modu.{}(a, b)`` :rtype: LowLevelILExpr """ - return self.expr(core.BNLowLevelILOperation.LLIL_MODS, a.index, b.index, size = size, flags = flags) + return self.expr(core.BNLowLevelILOperation.LLIL_MODS, a.index, b.index, size=size, flags=flags) - def mod_double_prec_unsigned(self, size, hi, lo, b, flags = None): + def mod_double_prec_unsigned(self, size, hi, lo, b, flags=None): """ ``mod_double_prec_unsigned`` unsigned double precision modulus using expression ``hi`` and expression ``lo`` as a single double precision register by expression ``b`` potentially setting flags ``flags`` and returning an @@ -848,9 +848,9 @@ class LowLevelILFunction(object): :return: The expression ``modu.dp.{}(hi:lo, b)`` :rtype: LowLevelILExpr """ - return self.expr(core.BNLowLevelILOperation.LLIL_MODS_DP, hi.index, lo.index, b.index, size = size, flags = flags) + return self.expr(core.BNLowLevelILOperation.LLIL_MODS_DP, hi.index, lo.index, b.index, size=size, flags=flags) - def neg_expr(self, size, value, flags = None): + def neg_expr(self, size, value, flags=None): """ ``neg_expr`` two's complement sign negation of expression ``value`` of size ``size`` potentially setting flags @@ -860,9 +860,9 @@ class LowLevelILFunction(object): :return: The expression ``neg.{}(value)`` :rtype: LowLevelILExpr """ - return self.expr(core.BNLowLevelILOperation.LLIL_NEG, value.index, size = size, flags = flags) + return self.expr(core.BNLowLevelILOperation.LLIL_NEG, value.index, size=size, flags=flags) - def not_expr(self, size, value, flags = None): + def not_expr(self, size, value, flags=None): """ ``not_expr`` bitwise inverse of expression ``value`` of size ``size`` potentially setting flags @@ -872,29 +872,30 @@ class LowLevelILFunction(object): :return: The expression ``not.{}(value)`` :rtype: LowLevelILExpr """ - return self.expr(core.BNLowLevelILOperation.LLIL_NOT, value.index, size = size, flags = flags) + return self.expr(core.BNLowLevelILOperation.LLIL_NOT, value.index, size=size, flags=flags) - def sign_extend(self, size, value): + def sign_extend(self, size, value, flags=None): """ ``sign_extend`` two's complement sign-extends the expression in ``value`` to ``size`` bytes :param int size: the size of the result in bytes - :param LowLevelILExpr value: the expression to sign extend + :param LowLevelILExpr value: the expression to sign extn + :param str flags: optional, flags to set :return: The expression ``sx.(value)`` :rtype: LowLevelILExpr """ - return self.expr(core.BNLowLevelILOperation.LLIL_SX, value.index, size = size) + return self.expr(core.BNLowLevelILOperation.LLIL_SX, value.index, size=size, flags=flags) def zero_extend(self, size, value): """ - ``sign_extend`` zero-extends the expression in ``value`` to ``size`` bytes + ``zero_extend`` zero-extends the expression in ``value`` to ``size`` bytes :param int size: the size of the result in bytes :param LowLevelILExpr value: the expression to zero extend :return: The expression ``sx.(value)`` :rtype: LowLevelILExpr """ - return self.expr(core.BNLowLevelILOperation.LLIL_ZX, value.index, size = size) + return self.expr(core.BNLowLevelILOperation.LLIL_ZX, value.index, size=size) def jump(self, dest): """ -- cgit v1.3.1 From 4761ea9c83104b872d8d49fcde45f17d17e7872d Mon Sep 17 00:00:00 2001 From: Peter LaFosse Date: Thu, 5 Jan 2017 09:14:31 -0500 Subject: Modifying how enumerations are exposed and used, and a bunch of cleanup of existing plugins --- python/__init__.py | 51 ++-- python/architecture.py | 54 ++-- python/basicblock.py | 33 +-- python/binaryview.py | 92 ++++--- python/bntype.py | 505 ----------------------------------- python/demangle.py | 6 +- python/examples/angr_plugin.py | 25 +- python/examples/bin_info.py | 15 +- python/examples/breakpoint.py | 28 +- python/examples/export_svg.py | 84 +++--- python/examples/jump_table.py | 8 +- python/examples/nds.py | 225 ++++++++-------- python/examples/nes.py | 430 +++++++++++++++--------------- python/examples/nsf.py | 86 +++--- python/examples/print_syscalls.py | 55 ++-- python/examples/version_switcher.py | 15 +- python/function.py | 98 +++---- python/generator.cpp | 88 ++++--- python/highlight.py | 47 ++-- python/interaction.py | 45 ++-- python/log.py | 10 +- python/lowlevelil.py | 275 ++++++++++---------- python/platform.py | 33 ++- python/plugin.py | 19 +- python/scriptingprovider.py | 35 +-- python/startup.py | 4 - python/transform.py | 7 +- python/types.py | 506 ++++++++++++++++++++++++++++++++++++ python/undoaction.py | 3 +- python/update.py | 5 +- 30 files changed, 1497 insertions(+), 1390 deletions(-) delete mode 100644 python/bntype.py create mode 100644 python/types.py (limited to 'python/binaryview.py') diff --git a/python/__init__.py b/python/__init__.py index 2a1139f9..a1ea02f5 100644 --- a/python/__init__.py +++ b/python/__init__.py @@ -18,30 +18,37 @@ # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS # IN THE SOFTWARE. + # Binary Ninja components import _binaryninjacore as core -from databuffer import * -from filemetadata import * -from fileaccessor import * -from binaryview import * -from transform import * -from architecture import * -from basicblock import * -from function import * -from log import * -from lowlevelil import * -from bntype import * -from functionrecognizer import * -from update import * -from plugin import * -from callingconvention import * -from platform import * -from demangle import * -from mainthread import * -from interaction import * -from lineardisassembly import * -from undoaction import * -from highlight import * +from .enums import * +from .databuffer import * +from .filemetadata import * +from .fileaccessor import * +from .binaryview import * +from .transform import * +from .architecture import * +from .basicblock import * +from .function import * +from .log import * +from .lowlevelil import * +from .types import * +from .functionrecognizer import * +from .update import * +from .plugin import * +from .callingconvention import * +from .platform import * +from .demangle import * +from .mainthread import * +from .interaction import * +from .lineardisassembly import * +from .undoaction import * +from .highlight import * +from .scriptingprovider import * + + +def shutdown(): + core.BNShutdown() class _DestructionCallbackHandler(object): diff --git a/python/architecture.py b/python/architecture.py index 5162e58a..5d42ec35 100644 --- a/python/architecture.py +++ b/python/architecture.py @@ -24,8 +24,8 @@ import abc # Binary Ninja components import _binaryninjacore as core -from _binaryninjacore import BNEndianness - +from enums import (Endianness, ImplicitRegisterExtend, BranchType, + InstructionTextTokenType, LowLevelILFlagCondition, FlagRole) import startup import function import lowlevelil @@ -33,7 +33,7 @@ import callingconvention import platform import log import databuffer -import bntype +import types class _ArchitectureMetaClass(type): @@ -108,7 +108,7 @@ class Architecture(object): >>> arch = Architecture['x86'] """ name = None - endianness = BNEndianness.LittleEndian + endianness = Endianness.LittleEndian address_size = 8 default_int_size = 4 max_instr_length = 16 @@ -128,7 +128,7 @@ class Architecture(object): if handle is not None: self.handle = core.handle_of_type(handle, core.BNArchitecture) self.__dict__["name"] = core.BNGetArchitectureName(self.handle) - self.__dict__["endianness"] = core.BNEndianness(core.BNGetArchitectureEndianness(self.handle)).name + self.__dict__["endianness"] = Endianness(core.BNGetArchitectureEndianness(self.handle)).name self.__dict__["address_size"] = core.BNGetArchitectureAddressSize(self.handle) self.__dict__["default_int_size"] = core.BNGetArchitectureDefaultIntegerSize(self.handle) self.__dict__["max_instr_length"] = core.BNGetArchitectureMaxInstructionLength(self.handle) @@ -146,7 +146,7 @@ class Architecture(object): info = core.BNGetArchitectureRegisterInfo(self.handle, regs[i]) full_width_reg = core.BNGetArchitectureRegisterName(self.handle, info.fullWidthRegister) self.regs[name] = function.RegisterInfo(full_width_reg, info.size, info.offset, - core.BNImplicitRegisterExtend(info.extend).name, regs[i]) + ImplicitRegisterExtend(info.extend).name, regs[i]) core.BNFreeRegisterList(regs) count = ctypes.c_ulonglong() @@ -182,7 +182,7 @@ class Architecture(object): self._flags_required_for_flag_condition = {} self.__dict__["flags_required_for_flag_condition"] = {} - for cond in core.BNLowLevelILFlagCondition: + for cond in LowLevelILFlagCondition: count = ctypes.c_ulonglong() flags = core.BNGetArchitectureFlagsRequiredForFlagCondition(self.handle, cond, count) flag_indexes = [] @@ -311,7 +311,7 @@ class Architecture(object): for flag in self.__class__.flag_roles: role = self.__class__.flag_roles[flag] if isinstance(role, str): - role = core.BNFlagRole[role] + role = FlagRole[role] self._flag_roles[self._flags[flag]] = role self._flags_required_for_flag_condition = {} @@ -383,7 +383,7 @@ class Architecture(object): return self.__class__.endianness except: log.log_error(traceback.format_exc()) - return core.BNEndianness.LittleEndian + return Endianness.LittleEndian def _get_address_size(self, ctxt): try: @@ -434,7 +434,7 @@ class Architecture(object): result[0].branchCount = len(info.branches) for i in xrange(0, len(info.branches)): if isinstance(info.branches[i].type, str): - result[0].branchType[i] = core.BNBranchType[info.branches[i].type] + result[0].branchType[i] = BranchType[info.branches[i].type] else: result[0].branchType[i] = info.branches[i].type result[0].branchTarget[i] = info.branches[i].target @@ -460,7 +460,7 @@ class Architecture(object): token_buf = (core.BNInstructionTextToken * len(tokens))() for i in xrange(0, len(tokens)): if isinstance(tokens[i].type, str): - token_buf[i].type = core.BNInstructionTextTokenType[tokens[i].type] + token_buf[i].type = InstructionTextTokenType[tokens[i].type] else: token_buf[i].type = tokens[i].type token_buf[i].text = tokens[i].text @@ -589,7 +589,7 @@ class Architecture(object): try: if flag in self._flag_roles: return self._flag_roles[flag] - return core.BNFlagRole.SpecialFlagRole + return FlagRole.SpecialFlagRole except KeyError: log.log_error(traceback.format_exc()) return None @@ -673,14 +673,14 @@ class Architecture(object): result[0].fullWidthRegister = 0 result[0].offset = 0 result[0].size = 0 - result[0].extend = core.BNImplicitRegisterExtend.NoExtend + result[0].extend = ImplicitRegisterExtend.NoExtend return info = self.__class__.regs[self._regs_by_index[reg]] result[0].fullWidthRegister = self._all_regs[info.full_width_reg] result[0].offset = info.offset result[0].size = info.size if isinstance(info.extend, str): - result[0].extend = core.BNImplicitRegisterExtend[info.extend] + result[0].extend = ImplicitRegisterExtend[info.extend] else: result[0].extend = info.extend except KeyError: @@ -688,7 +688,7 @@ class Architecture(object): result[0].fullWidthRegister = 0 result[0].offset = 0 result[0].size = 0 - result[0].extend = core.BNImplicitRegisterExtend.NoExtend + result[0].extend = ImplicitRegisterExtend.NoExtend def _get_stack_pointer_register(self, ctxt): try: @@ -1113,7 +1113,7 @@ class Architecture(object): result.length = info.length result.branch_delay = info.branchDelay for i in xrange(0, info.branchCount): - branch_type = core.BNBranchType(info.branchType[i]).name + branch_type = BranchType(info.branchType[i]).name target = info.branchTarget[i] if info.branchArch[i]: arch = Architecture(info.branchArch[i]) @@ -1143,7 +1143,7 @@ class Architecture(object): return None, 0 result = [] for i in xrange(0, count.value): - token_type = core.BNInstructionTextTokenType(tokens[i].type).name + token_type = InstructionTextTokenType(tokens[i].type).name text = tokens[i].text value = tokens[i].value size = tokens[i].size @@ -1611,17 +1611,17 @@ class Architecture(object): core.BNFreeString(ctypes.cast(errors, ctypes.POINTER(ctypes.c_byte))) if not result: return (None, error_str) - types = {} + type_dict = {} variables = {} functions = {} for i in xrange(0, parse.typeCount): - types[parse.types[i].name] = bntype.Type(core.BNNewTypeReference(parse.types[i].type)) + types[parse.types[i].name] = types.Type(core.BNNewTypeReference(parse.types[i].type)) for i in xrange(0, parse.variableCount): - variables[parse.variables[i].name] = bntype.Type(core.BNNewTypeReference(parse.variables[i].type)) + variables[parse.variables[i].name] = types.Type(core.BNNewTypeReference(parse.variables[i].type)) for i in xrange(0, parse.functionCount): - functions[parse.functions[i].name] = bntype.Type(core.BNNewTypeReference(parse.functions[i].type)) + functions[parse.functions[i].name] = types.Type(core.BNNewTypeReference(parse.functions[i].type)) core.BNFreeTypeParserResult(parse) - return (bntype.TypeParserResult(types, variables, functions), error_str) + return (types.TypeParserResult(type_dict, variables, functions), error_str) def parse_types_from_source_file(self, filename, include_dirs=[]): """ @@ -1652,17 +1652,17 @@ class Architecture(object): core.BNFreeString(ctypes.cast(errors, ctypes.POINTER(ctypes.c_byte))) if not result: return (None, error_str) - types = {} + type_dict = {} variables = {} functions = {} for i in xrange(0, parse.typeCount): - types[parse.types[i].name] = bntype.Type(core.BNNewTypeReference(parse.types[i].type)) + type_dict[parse.types[i].name] = types.Type(core.BNNewTypeReference(parse.types[i].type)) for i in xrange(0, parse.variableCount): - variables[parse.variables[i].name] = bntype.Type(core.BNNewTypeReference(parse.variables[i].type)) + variables[parse.variables[i].name] = types.Type(core.BNNewTypeReference(parse.variables[i].type)) for i in xrange(0, parse.functionCount): - functions[parse.functions[i].name] = bntype.Type(core.BNNewTypeReference(parse.functions[i].type)) + functions[parse.functions[i].name] = types.Type(core.BNNewTypeReference(parse.functions[i].type)) core.BNFreeTypeParserResult(parse) - return (bntype.TypeParserResult(types, variables, functions), error_str) + return (types.TypeParserResult(type_dict, variables, functions), error_str) def register_calling_convention(self, cc): """ diff --git a/python/basicblock.py b/python/basicblock.py index d728cb8d..ae9889fc 100644 --- a/python/basicblock.py +++ b/python/basicblock.py @@ -22,6 +22,7 @@ import ctypes # Binary Ninja components import _binaryninjacore as core +from enums import BranchType, HighlightColorStyle, HighlightStandardColor, InstructionTextTokenType import architecture import highlight import function @@ -30,13 +31,13 @@ import function class BasicBlockEdge(object): def __init__(self, branch_type, target, arch): self.type = branch_type - if self.type != core.BNBranchType.UnresolvedBranch: + if self.type != BranchType.UnresolvedBranch: self.target = target self.arch = arch def __repr__(self): - if self.type == core.BNBranchType.UnresolvedBranch: - return "<%s>" % core.BNBranchType(self.type).name + if self.type == BranchType.UnresolvedBranch: + return "<%s>" % BranchType(self.type).name elif self.arch: return "<%s: %s@%#x>" % (self.type, self.arch.name, self.target) else: @@ -126,18 +127,18 @@ class BasicBlock(object): :Example: - >>> current_basic_block.highlight = core.BNHighlightStandardColor.BlueHighlightColor + >>> current_basic_block.highlight = HighlightStandardColor.BlueHighlightColor >>> current_basic_block.highlight """ color = core.BNGetBasicBlockHighlight(self.handle) - if color.style == core.BNHighlightColorStyle.StandardHighlightColor: + if color.style == HighlightColorStyle.StandardHighlightColor: return highlight.HighlightColor(color=color.color, alpha=color.alpha) - elif color.style == core.BNHighlightColorStyle.MixedHighlightColor: + elif color.style == HighlightColorStyle.MixedHighlightColor: return highlight.HighlightColor(color=color.color, mix_color=color.mixColor, mix=color.mix, alpha=color.alpha) - elif color.style == core.BNHighlightColorStyle.CustomHighlightColor: + elif color.style == HighlightColorStyle.CustomHighlightColor: return highlight.HighlightColor(red=color.r, green=color.g, blue=color.b, alpha=color.alpha) - return highlight.HighlightColor(color=core.BNHighlightStandardColor.NoHighlightColor) + return highlight.HighlightColor(color=HighlightStandardColor.NoHighlightColor) @highlight.setter def highlight(self, value): @@ -194,7 +195,7 @@ class BasicBlock(object): addr = lines[i].addr tokens = [] for j in xrange(0, lines[i].count): - token_type = core.BNInstructionTextTokenType(lines[i].tokens[j].type) + token_type = InstructionTextTokenType(lines[i].tokens[j].type) text = lines[i].tokens[j].text value = lines[i].tokens[j].value size = lines[i].tokens[j].size @@ -210,22 +211,22 @@ class BasicBlock(object): .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 + :param HighlightStandardColor 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") + if not isinstance(color, HighlightStandardColor) and not isinstance(color, highlight.HighlightColor): + raise ValueError("Specified color is not one of HighlightStandardColor, highlight.HighlightColor") core.BNSetAutoBasicBlockHighlight(self.handle, color._get_core_struct()) def set_user_highlight(self, 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 + :param HighlightStandardColor 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) + >>> current_basic_block.set_user_highlight(HighlightStandardColor.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") + if not isinstance(color, HighlightStandardColor) and not isinstance(color, highlight.HighlightColor): + raise ValueError("Specified color is not one of HighlightStandardColor, highlight.HighlightColor") core.BNSetUserBasicBlockHighlight(self.handle, color._get_core_struct()) diff --git a/python/binaryview.py b/python/binaryview.py index b4be159c..41702dc8 100644 --- a/python/binaryview.py +++ b/python/binaryview.py @@ -26,6 +26,7 @@ import threading # Binary Ninja components import _binaryninjacore as core +from enums import AnalysisState, SymbolType, InstructionTextTokenType, Endianness, ModificationStatus, StringType, SegmentFlag import function import startup import architecture @@ -36,7 +37,7 @@ import filemetadata import log import databuffer import basicblock -import bntype +import types import lineardisassembly @@ -116,9 +117,9 @@ class AnalysisProgress(object): self.total = total def __str__(self): - if self.state == core.BNAnalysisState.DisassembleState: + if self.state == AnalysisState.DisassembleState: return "Disassembling (%d/%d)" % (self.count, self.total) - if self.state == core.BNAnalysisState.AnalyzeState: + if self.state == AnalysisState.AnalyzeState: return "Analyzing (%d/%d)" % (self.count, self.total) return "Idle" @@ -199,7 +200,7 @@ class BinaryDataNotificationCallbacks(object): def _data_var_added(self, ctxt, view, var): try: address = var.address - var_type = bntype.Type(core.BNNewTypeReference(var.type)) + var_type = types.Type(core.BNNewTypeReference(var.type)) auto_discovered = var.autoDiscovered self.notify.data_var_added(self.view, DataVariable(address, var_type, auto_discovered)) except: @@ -208,7 +209,7 @@ class BinaryDataNotificationCallbacks(object): def _data_var_removed(self, ctxt, view, var): try: address = var.address - var_type = bntype.Type(core.BNNewTypeReference(var.type)) + var_type = types.Type(core.BNNewTypeReference(var.type)) auto_discovered = var.autoDiscovered self.notify.data_var_removed(self.view, DataVariable(address, var_type, auto_discovered)) except: @@ -217,7 +218,7 @@ class BinaryDataNotificationCallbacks(object): def _data_var_updated(self, ctxt, view, var): try: address = var.address - var_type = bntype.Type(core.BNNewTypeReference(var.type)) + var_type = types.Type(core.BNNewTypeReference(var.type)) auto_discovered = var.autoDiscovered self.notify.data_var_updated(self.view, DataVariable(address, var_type, auto_discovered)) except: @@ -225,13 +226,13 @@ class BinaryDataNotificationCallbacks(object): def _string_found(self, ctxt, view, string_type, offset, length): try: - self.notify.string_found(self.view, core.BNStringType(string_type), offset, length) + self.notify.string_found(self.view, StringType(string_type), offset, length) except: log.log_error(traceback.format_exc()) def _string_removed(self, ctxt, view, string_type, offset, length): try: - self.notify.string_removed(self.view, core.BNStringType(string_type), offset, length) + self.notify.string_removed(self.view, StringType(string_type), offset, length) except: log.log_error(traceback.format_exc()) @@ -370,9 +371,9 @@ class Segment(object): def __repr__(self): return "" % (self.start, self.end, - "r" if (self.flags & core.BNSegmentFlag.SegmentReadable) != 0 else "-", - "w" if (self.flags & core.BNSegmentFlag.SegmentWritable) != 0 else "-", - "x" if (self.flags & core.BNSegmentFlag.SegmentExecutable) != 0 else "-") + "r" if (self.flags & SegmentFlag.SegmentReadable) != 0 else "-", + "w" if (self.flags & SegmentFlag.SegmentWritable) != 0 else "-", + "x" if (self.flags & SegmentFlag.SegmentExecutable) != 0 else "-") class Section(object): @@ -804,7 +805,7 @@ class BinaryView(object): result = {} for i in xrange(0, count.value): addr = var_list[i].address - var_type = bntype.Type(core.BNNewTypeReference(var_list[i].type)) + var_type = types.Type(core.BNNewTypeReference(var_list[i].type)) auto_discovered = var_list[i].autoDiscovered result[addr] = DataVariable(addr, var_type, auto_discovered) core.BNFreeDataVariables(var_list, count.value) @@ -817,7 +818,7 @@ class BinaryView(object): type_list = core.BNGetAnalysisTypeList(self.handle, count) result = {} for i in xrange(0, count.value): - result[type_list[i].name] = bntype.Type(core.BNNewTypeReference(type_list[i].type)) + result[type_list[i].name] = types.Type(core.BNNewTypeReference(type_list[i].type)) core.BNFreeTypeList(type_list, count.value) return result @@ -993,7 +994,7 @@ class BinaryView(object): return self.perform_get_modification(offset) except: log.log_error(traceback.format_exc()) - return core.BNModificationStatus.Original + return ModificationStatus.Original def _is_valid_offset(self, ctxt, offset): try: @@ -1063,7 +1064,7 @@ class BinaryView(object): return self.perform_get_default_endianness() except: log.log_error(traceback.format_exc()) - return core.BNEndianness.LittleEndian + return Endianness.LittleEndian def _get_address_size(self, ctxt): try: @@ -1229,9 +1230,9 @@ class BinaryView(object): :param int addr: a virtual address to be checked :return: One of the following: Original = 0, Changed = 1, Inserted = 2 - :rtype: BNModificationStatus + :rtype: ModificationStatus """ - return core.BNModificationStatus.Original + return ModificationStatus.Original def perform_is_valid_offset(self, addr): """ @@ -1352,10 +1353,10 @@ class BinaryView(object): .. note:: This method **may** be implemented for custom BinaryViews that are not LittleEndian. .. warning:: This method **must not** be called directly. - :return: either ``core.BNEndianness.LittleEndian`` or ``core.BNEndianness.BigEndian`` - :rtype: BNEndianness + :return: either ``Endianness.LittleEndian`` or ``Endianness.BigEndian`` + :rtype: Endianness """ - return core.BNEndianness.LittleEndian + return Endianness.LittleEndian def create_database(self, filename, progress_func=None): """ @@ -1568,16 +1569,16 @@ class BinaryView(object): 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. + ``length`` is None returns the ModificationStatus. :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 + :return: Either ModificationStatus of the byte at ``addr``, or string of modified bytes at ``addr`` + :rtype: ModificationStatus or str """ if length is None: return core.BNGetModification(self.handle, addr) - data = (core.BNModificationStatus * length)() + data = (ModificationStatus * length)() length = core.BNGetModificationArray(self.handle, addr, data, length) return data[0:length] @@ -1991,7 +1992,7 @@ class BinaryView(object): sym = core.BNGetSymbolByAddress(self.handle, addr) if sym is None: return None - return bntype.Symbol(None, None, None, handle = sym) + return types.Symbol(None, None, None, handle = sym) def get_symbol_by_raw_name(self, name): """ @@ -2009,7 +2010,7 @@ class BinaryView(object): sym = core.BNGetSymbolByRawName(self.handle, name) if sym is None: return None - return bntype.Symbol(None, None, None, handle = sym) + return types.Symbol(None, None, None, handle = sym) def get_symbols_by_name(self, name): """ @@ -2028,7 +2029,7 @@ class BinaryView(object): syms = core.BNGetSymbolsByName(self.handle, name, count) result = [] for i in xrange(0, count.value): - result.append(bntype.Symbol(None, None, None, handle = core.BNNewSymbolReference(syms[i]))) + result.append(types.Symbol(None, None, None, handle = core.BNNewSymbolReference(syms[i]))) core.BNFreeSymbolList(syms, count.value) return result @@ -2053,7 +2054,7 @@ class BinaryView(object): syms = core.BNGetSymbolsInRange(self.handle, start, length, count) result = [] for i in xrange(0, count.value): - result.append(bntype.Symbol(None, None, None, handle = core.BNNewSymbolReference(syms[i]))) + result.append(types.Symbol(None, None, None, handle = core.BNNewSymbolReference(syms[i]))) core.BNFreeSymbolList(syms, count.value) return result @@ -2069,12 +2070,12 @@ class BinaryView(object): :rtype: list(Symbol) :Example: - >>> bv.get_symbols_of_type(core.BNSymbolType.ImportAddressSymbol, 0x10002028, 1) + >>> bv.get_symbols_of_type(SymbolType.ImportAddressSymbol, 0x10002028, 1) [] >>> """ if isinstance(sym_type, str): - sym_type = core.BNSymbolType[sym_type] + sym_type = SymbolType[sym_type] count = ctypes.c_ulonglong(0) if start is None: syms = core.BNGetSymbolsOfType(self.handle, sym_type, count) @@ -2082,7 +2083,7 @@ class BinaryView(object): syms = core.BNGetSymbolsOfTypeInRange(self.handle, sym_type, start, length, count) result = [] for i in xrange(0, count.value): - result.append(bntype.Symbol(None, None, None, handle = core.BNNewSymbolReference(syms[i]))) + result.append(types.Symbol(None, None, None, handle = core.BNNewSymbolReference(syms[i]))) core.BNFreeSymbolList(syms, count.value) return result @@ -2095,6 +2096,21 @@ class BinaryView(object): """ core.BNDefineAutoSymbol(self.handle, sym.handle) + def define_auto_symbol_and_var_or_function(self, sym, sym_type, platform = None): + """ + ``define_auto_symbol`` adds a symbol to the internal list of automatically discovered Symbol objects. + + :param Symbol sym: the symbol to define + :rtype: None + """ + if platform is None: + platform = self.platform + if platform is not None: + platform = platform.handle + if sym_type is not None: + sym_type = sym_type.handle + core.BNDefineAutoSymbolAndVariableOrFunction(self.handle, platform, sym.handle, sym_type) + def undefine_auto_symbol(self, sym): """ ``undefine_auto_symbol`` removes a symbol from the internal list of automatically discovered Symbol objects. @@ -2456,7 +2472,7 @@ class BinaryView(object): strings = core.BNGetStringsInRange(self.handle, start, length, count) result = [] for i in xrange(0, count.value): - result.append(StringReference(core.BNStringType(strings[i].type), strings[i].start, strings[i].length)) + result.append(StringReference(StringType(strings[i].type), strings[i].start, strings[i].length)) core.BNFreeStringReferenceList(strings) return result @@ -2697,7 +2713,7 @@ class BinaryView(object): addr = lines[i].contents.addr tokens = [] for j in xrange(0, lines[i].contents.count): - token_type = core.BNInstructionTextTokenType(lines[i].contents.tokens[j].type) + token_type = InstructionTextTokenType(lines[i].contents.tokens[j].type) text = lines[i].contents.tokens[j].text value = lines[i].contents.tokens[j].value size = lines[i].contents.tokens[j].size @@ -2816,7 +2832,7 @@ class BinaryView(object): error_str = errors.value core.BNFreeString(ctypes.cast(errors, ctypes.POINTER(ctypes.c_byte))) raise SyntaxError(error_str) - type_obj = bntype.Type(core.BNNewTypeReference(result.type)) + type_obj = types.Type(core.BNNewTypeReference(result.type)) name = result.name core.BNFreeNameAndType(result) return type_obj, name @@ -2839,7 +2855,7 @@ class BinaryView(object): obj = core.BNGetAnalysisTypeByName(self.handle, name) if not obj: return None - return bntype.Type(obj) + return types.Type(obj) def is_type_auto_defined(self, name): """ @@ -3066,7 +3082,7 @@ class BinaryReader(object): Or using the optional endian parameter :: >>> from binaryninja import * - >>> br = BinaryReader(bv, core.BNEndianness.BigEndian) + >>> br = BinaryReader(bv, Endianness.BigEndian) >>> hex(br.read32()) '0xcffaedfeL' >>> @@ -3374,8 +3390,8 @@ class BinaryWriter(object): Or using the optional endian parameter :: >>> from binaryninja import * - >>> br = BinaryReader(bv, core.BNEndianness.BigEndian) - >>> bw = BinaryWriter(bv, core.BNEndianness.BigEndian) + >>> br = BinaryReader(bv, Endianness.BigEndian) + >>> bw = BinaryWriter(bv, Endianness.BigEndian) >>> """ def __init__(self, view, endian = None): diff --git a/python/bntype.py b/python/bntype.py deleted file mode 100644 index 1822c5df..00000000 --- a/python/bntype.py +++ /dev/null @@ -1,505 +0,0 @@ -# Copyright (c) 2015-2016 Vector 35 LLC -# -# 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 -# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -# sell copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -# IN THE SOFTWARE. - -import ctypes - -# Binary Ninja components -import _binaryninjacore as core -import callingconvention -import demangle - - -class Symbol(object): - """ - Symbols are defined as one of the following types: - - =========================== ============================================================== - BNSymbolType 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) - else: - if isinstance(sym_type, str): - sym_type = core.BNSymbolType[sym_type] - if full_name is None: - full_name = short_name - if raw_name is None: - raw_name = full_name - self.handle = core.BNCreateSymbol(sym_type, short_name, full_name, raw_name, addr) - - def __del__(self): - core.BNFreeSymbol(self.handle) - - @property - def type(self): - """Symbol type (read-only)""" - return core.BNSymbolType(core.BNGetSymbolType(self.handle)) - - @property - def name(self): - """Symbol name (read-only)""" - return core.BNGetSymbolRawName(self.handle) - - @property - def short_name(self): - """Symbol short name (read-only)""" - return core.BNGetSymbolShortName(self.handle) - - @property - def full_name(self): - """Symbol full name (read-only)""" - return core.BNGetSymbolFullName(self.handle) - - @property - def raw_name(self): - """Symbol raw name (read-only)""" - return core.BNGetSymbolRawName(self.handle) - - @property - def address(self): - """Symbol address (read-only)""" - return core.BNGetSymbolAddress(self.handle) - - @property - def auto(self): - return core.BNIsSymbolAutoDefined(self.handle) - - @auto.setter - def auto(self, value): - core.BNSetSymbolAutoDefined(self.handle, value) - - def __repr__(self): - return "<%s: \"%s\" @ %#x>" % (self.type, self.full_name, self.address) - - def __setattr__(self, name, value): - try: - object.__setattr__(self, name, value) - except AttributeError: - raise AttributeError("attribute '%s' is read only" % name) - - -class Type(object): - def __init__(self, handle): - self.handle = handle - - def __del__(self): - core.BNFreeType(self.handle) - - @property - def type_class(self): - """Type class (read-only)""" - return core.BNTypeClass(core.BNGetTypeClass(self.handle)) - - @property - def width(self): - """Type width (read-only)""" - return core.BNGetTypeWidth(self.handle) - - @property - def alignment(self): - """Type alignment (read-only)""" - return core.BNGetTypeAlignment(self.handle) - - @property - def signed(self): - """Wether type is signed (read-only)""" - return core.BNIsTypeSigned(self.handle) - - @property - def const(self): - """Whether type is const (read-only)""" - return core.BNIsTypeConst(self.handle) - - @property - def modified(self): - """Whether type is modified (read-only)""" - return core.BNIsTypeFloatingPoint(self.handle) - - @property - def target(self): - """Target (read-only)""" - result = core.BNGetChildType(self.handle) - if result is None: - return None - return Type(result) - - @property - def element_type(self): - """Target (read-only)""" - result = core.BNGetChildType(self.handle) - if result is None: - return None - return Type(result) - - @property - def return_value(self): - """Return value (read-only)""" - result = core.BNGetChildType(self.handle) - if result is None: - return None - return Type(result) - - @property - def calling_convention(self): - """Calling convention (read-only)""" - result = core.BNGetTypeCallingConvention(self.handle) - if result is None: - return None - return callingconvention.CallingConvention(None, result) - - @property - def parameters(self): - """Type parameters list (read-only)""" - count = ctypes.c_ulonglong() - params = core.BNGetTypeParameters(self.handle, count) - result = [] - for i in xrange(0, count.value): - result.append((Type(core.BNNewTypeReference(params[i].type)), params[i].name)) - core.BNFreeTypeParameterList(params, count.value) - return result - - @property - def has_variable_arguments(self): - """Whether type has variable arguments (read-only)""" - return core.BNTypeHasVariableArguments(self.handle) - - @property - def can_return(self): - """Whether type can return (read-only)""" - return core.BNFunctionTypeCanReturn(self.handle) - - @property - def structure(self): - """Structure of the type (read-only)""" - result = core.BNGetTypeStructure(self.handle) - if result is None: - return None - return Structure(result) - - @property - def enumeration(self): - """Type enumeration (read-only)""" - result = core.BNGetTypeEnumeration(self.handle) - if result is None: - return None - return Enumeration(result) - - @property - def count(self): - """Type count (read-only)""" - return core.BNGetTypeElementCount(self.handle) - - def __str__(self): - return core.BNGetTypeString(self.handle) - - def __repr__(self): - return "" % str(self) - - def get_string_before_name(self): - return core.BNGetTypeStringBeforeName(self.handle) - - def get_string_after_name(self): - return core.BNGetTypeStringAfterName(self.handle) - - @classmethod - def void(cls): - return Type(core.BNCreateVoidType()) - - @classmethod - def bool(self): - return Type(core.BNCreateBoolType()) - - @classmethod - def int(self, width, sign = True, altname=""): - return Type(core.BNCreateIntegerType(width, sign, altname)) - - @classmethod - def float(self, width): - return Type(core.BNCreateFloatType(width)) - - @classmethod - def structure_type(self, structure_type): - return Type(core.BNCreateStructureType(structure_type.handle)) - - @classmethod - def unknown_type(self, unknown_type): - return Type(core.BNCreateUnknownType(unknown_type.handle)) - - @classmethod - def enumeration_type(self, arch, e, width=None): - if width is None: - width = arch.default_int_size - return Type(core.BNCreateEnumerationType(e.handle, width)) - - @classmethod - def pointer(self, arch, t, const=False): - return Type(core.BNCreatePointerType(arch.handle, t.handle, const)) - - @classmethod - def array(self, t, count): - return Type(core.BNCreateArrayType(t.handle, count)) - - @classmethod - def function(self, ret, params, calling_convention=None, variable_arguments=False): - param_buf = (core.BNNameAndType * len(params))() - for i in xrange(0, len(params)): - if isinstance(params[i], Type): - param_buf[i].name = "" - param_buf[i].type = params[i].handle - else: - param_buf[i].name = params[i][1] - param_buf[i].type = params[i][0] - if calling_convention is not None: - calling_convention = calling_convention.handle - return Type(core.BNCreateFunctionType(ret.handle, calling_convention, param_buf, len(params), - variable_arguments)) - - def __setattr__(self, name, value): - try: - object.__setattr__(self, name, value) - except AttributeError: - raise AttributeError("attribute '%s' is read only" % name) - - -class UnknownType(object): - def __init__(self, handle=None): - if handle is None: - self.handle = core.BNCreateUnknownType() - else: - self.handle = handle - - def __del__(self): - core.BNFreeUnknownType(self.handle) - - @property - def name(self): - count = ctypes.c_ulonglong() - nameList = core.BNGetUnknownTypeName(self.handle, count) - result = [] - for i in xrange(count.value): - result.append(nameList[i]) - return demangle.get_qualified_name(result) - - @name.setter - def name(self, value): - core.BNSetUnknownTypeName(self.handle, value) - - -class StructureMember(object): - def __init__(self, t, name, offset): - self.type = t - self.name = name - self.offset = offset - - def __repr__(self): - if len(self.name) == 0: - return "" % (str(self.type), self.offset) - return "<%s %s%s, offset %#x>" % (self.type.get_string_before_name(), self.name, - self.type.get_string_after_name(), self.offset) - - -class Structure(object): - def __init__(self, handle=None): - if handle is None: - self.handle = core.BNCreateStructure() - else: - self.handle = handle - - def __del__(self): - core.BNFreeStructure(self.handle) - - @property - def name(self): - count = ctypes.c_ulonglong() - nameList = core.BNGetStructureName(self.handle, count) - result = [] - for i in xrange(count.value): - result.append(nameList[i]) - return demangle.get_qualified_name(result) - - @name.setter - def name(self, value): - core.BNSetStructureName(self.handle, value) - - @property - def members(self): - """Structure member list (read-only)""" - count = ctypes.c_ulonglong() - members = core.BNGetStructureMembers(self.handle, count) - result = [] - for i in xrange(0, count.value): - result.append(StructureMember(Type(core.BNNewTypeReference(members[i].type)), - members[i].name, members[i].offset)) - core.BNFreeStructureMemberList(members, count.value) - return result - - @property - def width(self): - """Structure width (read-only)""" - return core.BNGetStructureWidth(self.handle) - - @property - def alignment(self): - """Structure alignment (read-only)""" - return core.BNGetStructureAlignment(self.handle) - - @property - def packed(self): - return core.BNIsStructurePacked(self.handle) - - @packed.setter - def packed(self, value): - core.BNSetStructurePacked(self.handle, value) - - @property - def union(self): - return core.BNIsStructureUnion(self.handle) - - @union.setter - def union(self, value): - core.BNSetStructureUnion(self.handle, value) - - def __setattr__(self, name, value): - try: - object.__setattr__(self, name, value) - except AttributeError: - raise AttributeError("attribute '%s' is read only" % name) - - def __repr__(self): - if len(self.name) > 0: - return "" % self.name - return "" % self.width - - def append(self, t, name = ""): - core.BNAddStructureMember(self.handle, t.handle, name) - - def insert(self, offset, t, name = ""): - core.BNAddStructureMemberAtOffset(self.handle, t.handle, name, offset) - - def remove(self, i): - core.BNRemoveStructureMember(self.handle, i) - - -class EnumerationMember(object): - def __init__(self, name, value, default): - self.name = name - self.value = value - self.default = default - - def __repr__(self): - return "<%s = %#x>" % (self.name, self.value) - - -class Enumeration(object): - def __init__(self, handle=None): - if handle is None: - self.handle = core.BNCreateEnumeration() - else: - self.handle = handle - - def __del__(self): - core.BNFreeEnumeration(self.handle) - - @property - def name(self): - return core.BNGetEnumerationName(self.handle) - - @name.setter - def name(self, value): - core.BNSetEnumerationName(self.handle, value) - - @property - def members(self): - """Enumeration member list (read-only)""" - count = ctypes.c_ulonglong() - members = core.BNGetEnumerationMembers(self.handle, count) - result = [] - for i in xrange(0, count.value): - result.append(EnumerationMember(members[i].name, members[i].value, members[i].isDefault)) - core.BNFreeEnumerationMemberList(members, count.value) - return result - - def __setattr__(self, name, value): - try: - object.__setattr__(self, name, value) - except AttributeError: - raise AttributeError("attribute '%s' is read only" % name) - - def __repr__(self): - if len(self.name) > 0: - return "" % self.name - return "" % repr(self.members) - - def append(self, name, value = None): - if value is None: - core.BNAddEnumerationMember(self.handle, name) - else: - core.BNAddEnumerationMemberWithValue(self.handle, name, value) - - -class TypeParserResult(object): - def __init__(self, types, variables, functions): - self.types = types - self.variables = variables - self.functions = functions - - def __repr__(self): - return "{types: %s, variables: %s, functions: %s}" % (self.types, self.variables, self.functions) - - -def preprocess_source(source, filename=None, include_dirs=[]): - """ - ``preprocess_source`` run the C preprocessor on the given source or source filename. - - :param str source: source to preprocess - :param str filename: optional filename to preprocess - :param list(str) include_dirs: list of string directorires to use as include directories. - :return: returns a tuple of (preprocessed_source, error_string) - :rtype: tuple(str,str) - :Example: - - >>> source = "#define TEN 10\\nint x[TEN];\\n" - >>> preprocess_source(source) - ('#line 1 "input"\\n\\n#line 2 "input"\\n int x [ 10 ] ;\\n', '') - >>> - """ - if filename is None: - filename = "input" - dir_buf = (ctypes.c_char_p * len(include_dirs))() - for i in xrange(0, len(include_dirs)): - dir_buf[i] = str(include_dirs[i]) - output = ctypes.c_char_p() - errors = ctypes.c_char_p() - result = core.BNPreprocessSource(source, filename, output, errors, dir_buf, len(include_dirs)) - output_str = output.value - error_str = errors.value - core.BNFreeString(ctypes.cast(output, ctypes.POINTER(ctypes.c_byte))) - core.BNFreeString(ctypes.cast(errors, ctypes.POINTER(ctypes.c_byte))) - if result: - return (output_str, error_str) - return (None, error_str) diff --git a/python/demangle.py b/python/demangle.py index 75c63f40..520cfbaf 100644 --- a/python/demangle.py +++ b/python/demangle.py @@ -22,7 +22,7 @@ import ctypes # Binary Ninja components import _binaryninjacore as core -import bntype +import types def get_qualified_name(names): @@ -64,7 +64,7 @@ def demangle_ms(arch, mangled_name): for i in xrange(outSize.value): names.append(outName[i]) core.BNFreeDemangledName(outName.value, outSize.value) - return (bntype.Type(handle), names) + return (types.Type(handle), names) return (None, mangled_name) @@ -79,5 +79,5 @@ def demangle_gnu3(arch, mangled_name): core.BNFreeDemangledName(outName.value, outSize.value) if not handle: return (None, names) - return (bntype.Type(handle), names) + return (types.Type(handle), names) return (None, mangled_name) diff --git a/python/examples/angr_plugin.py b/python/examples/angr_plugin.py index 852eff65..9c91d970 100644 --- a/python/examples/angr_plugin.py +++ b/python/examples/angr_plugin.py @@ -30,14 +30,20 @@ # virtual environment. A later update may allow for a manual override to link to the required version # of Python. -__name__ = "__console__" # angr looks for this, it won't load from within a UI without it -import angr -from binaryninja import * - import tempfile import logging import os +__name__ = "__console__" # angr looks for this, it won't load from within a UI without it + +import angr +# For the lazy instead you can just import everything 'from binaryninja import *'' +from binaryninja.binaryview import BinaryView +from binaryninja.plugin import BackgroundTaskThread, PluginCommand +from binaryninja.interaction import show_plain_text_report, show_message_box +from binaryninja.highlight import HighlightColor +from binaryninja.enums import HighlightStandardColor, MessageBoxButtonSet + # Disable warning logs as they show up as errors in the UI logging.disable(logging.WARNING) @@ -109,8 +115,8 @@ 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(core.BNHighlightStandardColor.GreenHighlightColor, alpha = 128)) - block.function.set_auto_instr_highlight(block.arch, addr, core.BNHighlightStandardColor.GreenHighlightColor) + block.set_auto_highlight(HighlightColor(HighlightStandardColor.GreenHighlightColor, alpha = 128)) + block.function.set_auto_instr_highlight(block.arch, addr, HighlightStandardColor.GreenHighlightColor) # Add the instruction to the list associated with the current view bv.session_data.angr_find.add(addr) @@ -120,8 +126,8 @@ 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(core.BNHighlightStandardColor.RedHighlightColor, alpha = 128)) - block.function.set_auto_instr_highlight(block.arch, addr, core.BNHighlightStandardColor.RedHighlightColor) + block.set_auto_highlight(HighlightColor(HighlightStandardColor.RedHighlightColor, alpha = 128)) + block.function.set_auto_instr_highlight(block.arch, addr, HighlightStandardColor.RedHighlightColor) # Add the instruction to the list associated with the current view bv.session_data.angr_avoid.add(addr) @@ -131,13 +137,14 @@ 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.", core.BNMessageBoxButtonSet.OKButtonSet, core.BNMessageBoxButtonSet.ErrorIcon) + "continue.", MessageBoxButtonSet.OKButtonSet, MessageBoxButtonSet.ErrorIcon) return # Start a solver thread for the path associated with the view s = Solver(bv.session_data.angr_find, bv.session_data.angr_avoid, bv) s.start() + # 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) diff --git a/python/examples/bin_info.py b/python/examples/bin_info.py index c574a530..4c4ab8fd 100644 --- a/python/examples/bin_info.py +++ b/python/examples/bin_info.py @@ -21,12 +21,12 @@ import sys import binaryninja.log as log -import binaryninja.binaryview as view +from binaryninja.binaryview import BinaryViewType import binaryninja.interaction as interaction from binaryninja.plugin import PluginCommand -def bininfo(bv): +def get_bininfo(bv): if bv is None: filename = "" if len(sys.argv) > 1: @@ -37,7 +37,7 @@ def bininfo(bv): log.log_warn("No file specified") sys.exit(1) - bv = view.BinaryViewType.get_view_of_file(filename) + bv = BinaryViewType.get_view_of_file(filename) log.redirect_output_to_log() log.log_to_stdout(True) @@ -60,11 +60,14 @@ def bininfo(bv): length = bv.strings[i].length string = bv.read(start, length) contents += "| 0x%x |%d | %s |\n" % (start, length, string) + return contents - interaction.show_markdown_report("Binary Info Report", contents) + +def display_bininfo(bv): + interaction.show_markdown_report("Binary Info Report", get_bininfo(bv)) if __name__ == "__main__": - bininfo(None) + print get_bininfo(None) else: - PluginCommand.register("Binary Info", "Display basic info about the binary", bininfo) + PluginCommand.register("Binary Info", "Display basic info about the binary", display_bininfo) diff --git a/python/examples/breakpoint.py b/python/examples/breakpoint.py index 2426e6a1..e694329b 100644 --- a/python/examples/breakpoint.py +++ b/python/examples/breakpoint.py @@ -18,7 +18,11 @@ # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS # IN THE SOFTWARE. -from binaryninja import * + +from binaryninja.plugin import PluginCommand +from binaryninja.log import log_error +from binaryninja.architecture import Architecture + def write_breakpoint(view, start, length): """Sample function to show registering a plugin menu item for a range of bytes. Also possible: @@ -26,11 +30,21 @@ def write_breakpoint(view, start, length): register_for_address register_for_function """ - if view.arch.name.startswith("x86"): - view.write(start, "\xcc" * length) - elif view.arch.name == "armv7": - view.write(start, "\x7a\x00\x20\xe1" * (length/4)) - else: - log_error("No support for breakpoint on %s" % view.arch.name) + 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) + return + bkpt, err = Architecture[view.arch.name].assemble(bkpt_str[view.arch.name]) + if bkpt is None: + log_error(err) + return + view.write(start, bkpt * length / len(bkpt)) + PluginCommand.register_for_range("Convert to breakpoint", "Fill region with breakpoint instructions.", write_breakpoint) diff --git a/python/examples/export_svg.py b/python/examples/export_svg.py index 5a4d2982..bab00f5d 100755 --- a/python/examples/export_svg.py +++ b/python/examples/export_svg.py @@ -1,11 +1,14 @@ -from binaryninja import * +# from binaryninja import * import os import webbrowser try: - from urllib import pathname2url # Python 2.x + from urllib import pathname2url # Python 2.x except: - from urllib.request import pathname2url # Python 3.x + from urllib.request import pathname2url # Python 3.x +from binaryninja.interaction import get_save_filename_input, show_message_box +from binaryninja.enums import MessageBoxButtonSet +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]} @@ -17,40 +20,46 @@ escape_table = { ' ': " " } -def escape(string): - string=string.decode('utf-8').encode('ascii','xmlcharrefreplace') #handle extended unicode - return ''.join(escape_table.get(i,i) for i in string) #still escape the basics -def save_svg(bv,function): - address = hex(function.start).replace('L','') +def escape(toescape): + toescape = toescape.decode('utf-8').encode('ascii', 'xmlcharrefreplace') # handle extended unicode + return ''.join(escape_table.get(i, i) for i in toescape) # still escape the basics + + +def save_svg(bv, function): + address = hex(function.start).replace('L', '') path = os.path.dirname(bv.file.filename) origname = os.path.basename(bv.file.filename) - filename = os.path.join(path,'binaryninja-{filename}-{function}.html'.format(filename=origname,function=address)) + filename = os.path.join(path, 'binaryninja-{filename}-{function}.html'.format(filename=origname, function=address)) outputfile = get_save_filename_input('File name for export_svg', 'HTML files (*.html)', filename) if outputfile is None: return content = render_svg(function) - output = open(outputfile,'w') + output = open(outputfile, 'w') output.write(content) output.close() - if show_message_box("Open SVG", "Would you like to view the exported SVG?", buttons = core.YesNoButtonSet, icon = core.QuestionIcon) == core.YesButton: + result = show_message_box("Open SVG", "Would you like to view the exported SVG?", + buttons = MessageBoxButtonSet.YesNoButtonSet, icon = MessageBoxButtonSet.QuestionIcon) + if result == MessageBoxButtonSet.YesButton: url = 'file:{}'.format(pathname2url(outputfile)) webbrowser.open(url) -def instruction_data_flow(function,address): + +def instruction_data_flow(function, address): ''' TODO: Extract data flow information ''' - length = function.view.get_instruction_length(function.arch,address) + length = function.view.get_instruction_length(function.arch, address) bytes = function.view.read(address, length) hex = bytes.encode('hex') - padded = ' '.join([hex[i:i+2] for i in range(0, len(hex), 2)]) + padded = ' '.join([hex[i:i + 2] for i in range(0, len(hex), 2)]) return 'Opcode: {bytes}'.format(bytes=padded) + def render_svg(function): graph = function.create_graph() graph.layout_and_wait() heightconst = 15 ratio = 0.48 - widthconst = heightconst*ratio + widthconst = heightconst * ratio output = ''' @@ -135,63 +144,64 @@ def render_svg(function): - '''.format(width=graph.width*widthconst + 20, height=graph.height*heightconst + 20) + '''.format(width=graph.width * widthconst + 20, height=graph.height * heightconst + 20) output += ''' Function Graph 0 ''' edges = '' - for i,block in enumerate(graph.blocks): + for i, block in enumerate(graph.blocks): - #Calculate basic block location and coordinates + # Calculate basic block location and coordinates x = ((block.x) * widthconst) y = ((block.y) * heightconst) width = ((block.width) * widthconst) height = ((block.height) * heightconst) - #Render block + # Render block output += ' \n'.format(i=i) output += ' Basic Block {i}\n'.format(i=i) - rgb=colors['none'] + rgb = colors['none'] try: bb = block.basic_block color_code = bb.highlight.color color_str = bb.highlight._standard_color_to_str(color_code) if color_str in colors: - rgb=colors[color_str] + rgb = colors[color_str] except: pass - output += ' \n'.format(x=x,y=y,width=width + 16,height=height + 12,r=rgb[0],g=rgb[1],b=rgb[2]) + output += ' \n'.format(x=x, y=y, width=width + 16, height=height + 12, r=rgb[0], g=rgb[1], b=rgb[2]) - #Render instructions, unfortunately tspans don't allow copying/pasting more - #than one line at a time, need SVG 1.2 textarea tags for that it looks like + # Render instructions, unfortunately tspans don't allow copying/pasting more + # than one line at a time, need SVG 1.2 textarea tags for that it looks like - output += ' \n'.format(x=x,y=y + (i + 1) * heightconst) - for i,line in enumerate(block.lines): - output += ' '.format(x=x + 6,y=y + 6 + (i + 0.7) * heightconst,address=hex(line.address)[:-1]) + output += ' \n'.format(x=x, y=y + (i + 1) * heightconst) + for i, line in enumerate(block.lines): + output += ' '.format(x=x + 6, y=y + 6 + (i + 0.7) * heightconst, address=hex(line.address)[:-1]) hover = instruction_data_flow(function, line.address) output += '{hover}'.format(hover=hover) for token in line.tokens: # TODO: add hover for hex, function, and reg tokens - output+='{text}'.format(text=escape(token.text),tokentype=token.type) + output += '{text}'.format(text=escape(token.text), tokentype=token.type) output += '\n' output += ' \n' output += ' \n' - #Edges are rendered in a seperate chunk so they have priority over the - #basic blocks or else they'd render below them + # Edges are rendered in a seperate chunk so they have priority over the + # basic blocks or else they'd render below them for edge in block.outgoing_edges: points = "" - x,y = edge.points[0] - points += str(x*widthconst)+","+str(y*heightconst + 12) + " " - for x,y in edge.points[1:-1]: - points += str(x*widthconst)+","+str(y*heightconst) + " " - x,y = edge.points[-1] - points += str(x*widthconst)+","+str(y*heightconst + 0) + " " - edges += ' \n'.format(type=edge.type,points=points) + x, y = edge.points[0] + points += str(x * widthconst) + "," + str(y * heightconst + 12) + " " + for x, y in edge.points[1:-1]: + points += str(x * widthconst) + "," + str(y * heightconst) + " " + x, y = edge.points[-1] + points += str(x * widthconst) + "," + str(y * heightconst + 0) + " " + edges += ' \n'.format(type=edge.type, points=points) output += ' ' + edges + '\n' output += ' \n' output += '' return output + PluginCommand.register_for_function("Export to SVG", "Exports an SVG of the current function", save_svg) diff --git a/python/examples/jump_table.py b/python/examples/jump_table.py index 0fd0dbab..f24eea12 100644 --- a/python/examples/jump_table.py +++ b/python/examples/jump_table.py @@ -20,7 +20,8 @@ # This plugin will attempt to resolve simple jump tables (an array of code pointers) and add the destinations # as indirect branch targets so that the flow graph reflects the jump table's control flow. -import binaryninja +from binaryninja.plugin import PluginCommand +from binaryninja.enum import InstructionTextTokenType import struct @@ -49,7 +50,7 @@ def find_jump_table(bv, addr): # Collect the branch targets for any tables referenced by the clicked instruction branches = [] for token in tokens: - if token.type == core.BNInstructionTextTokenType.PossibleAddressToken: # Table addresses will be a "possible address" token + if token.type == InstructionTextTokenType.PossibleAddressToken: # Table addresses will be a "possible address" token tbl = token.value print "Found possible table at 0x%x" % tbl i = 0 @@ -79,6 +80,7 @@ def find_jump_table(bv, addr): # Set the indirect branch targets on the jump instruction to be the list of targets discovered 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 -binaryninja.PluginCommand.register_for_address("Process jump table", "Look for jump table destinations", find_jump_table) +PluginCommand.register_for_address("Process jump table", "Look for jump table destinations", find_jump_table) diff --git a/python/examples/nds.py b/python/examples/nds.py index 302bbc0d..ff137b4b 100644 --- a/python/examples/nds.py +++ b/python/examples/nds.py @@ -1,108 +1,117 @@ -# Copyright (c) 2015-2016 Vector 35 LLC -# -# 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 -# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -# sell copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -# IN THE SOFTWARE. - -from binaryninja import * -import struct -import traceback -import os - -def crc16(data): - crc = 0xffff - for ch in data: - crc ^= ord(ch) - for bit in xrange(0, 8): - if (crc & 1) == 1: - crc = (crc >> 1) ^ 0xa001 - else: - crc >>= 1 - return crc - -class DSView(BinaryView): - def __init__(self, data): - BinaryView.__init__(self, file_metadata = data.file, parent_view = data) - self.raw = data - - @classmethod - def is_valid_for_data(self, data): - hdr = data.read(0, 0x160) - if len(hdr) < 0x160: - return False - if struct.unpack("> 1) ^ 0xa001 + else: + crc >>= 1 + return crc + + +class DSView(BinaryView): + def __init__(self, data): + BinaryView.__init__(self, file_metadata = data.file, parent_view = data) + self.raw = data + + @classmethod + def is_valid_for_data(self, data): + hdr = data.read(0, 0x160) + if len(hdr) < 0x160: + return False + if struct.unpack("= 0x8000: self.add_function(Architecture['6502'].standalone_platform, addr) @@ -611,6 +618,7 @@ class NESView(BinaryView): def perform_get_entry_point(self): return struct.unpack("'.format(sys.argv[0])) - return -1 - - target = sys.argv[1] - - bv = BinaryView.open(target) - view_type = next(bvt for bvt in bv.available_view_types if bvt.name != 'Raw') - if not view_type: - print('Error: Unable to get any other view type besides Raw') - return -1 - - bv = bv.file.get_view_of_type(view_type.name) - bv.update_analysis_and_wait() - - print_syscalls(bv) + for func in bv.functions: + syscalls = (il for il in chain.from_iterable(func.low_level_il) + if il.operation == LowLevelILOperation.LLIL_SYSCALL) + for il in syscalls: + value = func.get_reg_value_at(il.address, register).value + print("System call address: {:#x} - {:d}".format(il.address, value)) if __name__ == "__main__": - sys.exit(main()) + if len(sys.argv) != 2: + print('Usage: {} '.format(sys.argv[0])) + else: + print_syscalls(sys.argv[1]) diff --git a/python/examples/version_switcher.py b/python/examples/version_switcher.py index e8f8814d..bc4f576c 100644 --- a/python/examples/version_switcher.py +++ b/python/examples/version_switcher.py @@ -27,10 +27,11 @@ chandefault = binaryninja.UpdateChannel.list[0].name channel = None versions = [] + def load_channel(newchannel): global channel global versions - if (channel != None and newchannel == channel.name): + if (channel is None and newchannel == channel.name): print "Same channel, not updating." else: try: @@ -42,6 +43,7 @@ def load_channel(newchannel): print "%s is not a valid channel name. Defaulting to " % chandefault channel = binaryninja.UpdateChannel[chandefault] + def select(version): done = False date = datetime.datetime.fromtimestamp(version.time).strftime('%c') @@ -74,34 +76,37 @@ def select(version): print "binaryninja.core_version %s" % binaryninja.core_version print "Updating..." print version.update() - #forward updating won't work without reloading + # forward updating won't work without reloading sys.exit() else: print "Invalid selection" + def list_channels(): done = False print "\tSelect channel:\n" while not done: channel_list = binaryninja.UpdateChannel.list for index, item in enumerate(channel_list): - print "\t%d)\t%s" % (index+1, item.name) - print "\t%d)\t%s" % (len(channel_list)+1, "Main Menu") + print "\t%d)\t%s" % (index + 1, item.name) + print "\t%d)\t%s" % (len(channel_list) + 1, "Main Menu") selection = raw_input('Choice: ') if selection.isdigit(): selection = int(selection) else: selection = 0 - if (selection <= 0 or selection > len(channel_list)+1): + if (selection <= 0 or selection > len(channel_list) + 1): print "%s is an invalid choice." % selection else: done = True if (selection != len(channel_list) + 1): load_channel(channel_list[selection - 1].name) + def toggle_updates(): binaryninja.set_auto_updates_enabled(not binaryninja.are_auto_updates_enabled()) + def main(): global channel done = False diff --git a/python/function.py b/python/function.py index 16357c3f..e3c79312 100644 --- a/python/function.py +++ b/python/function.py @@ -24,10 +24,12 @@ import ctypes # Binary Ninja components import _binaryninjacore as core +from enums import (FunctionGraphType, BranchType, SymbolType, InstructionTextTokenType, + HighlightStandardColor, RegisterValueType, ImplicitRegisterExtend, DisassemblyOption, IntegerDisplayType) import architecture import highlight import associateddatastore -import bntype +import types import basicblock import lowlevelil import binaryview @@ -46,16 +48,16 @@ class LookupTableEntry(object): class RegisterValue(object): def __init__(self, arch, value): self.type = value.state - if value.state == core.BNRegisterValueType.EntryValue: + if value.state == RegisterValueType.EntryValue: self.reg = arch.get_reg_name(value.reg) - elif value.state == core.BNRegisterValueType.OffsetFromEntryValue: + elif value.state == RegisterValueType.OffsetFromEntryValue: self.reg = arch.get_reg_name(value.reg) self.offset = value.value - elif value.state == core.BNRegisterValueType.ConstantValue: + elif value.state == RegisterValueType.ConstantValue: self.value = value.value - elif value.state == core.BNRegisterValueType.StackFrameOffset: + elif value.state == RegisterValueType.StackFrameOffset: self.offset = value.value - elif value.state == core.BNRegisterValueType.SignedRangeValue: + elif value.state == RegisterValueType.SignedRangeValue: self.offset = value.value self.start = value.rangeStart self.end = value.rangeEnd @@ -64,12 +66,12 @@ class RegisterValue(object): self.start |= ~((1 << 63) - 1) if self.end & (1 << 63): self.end |= ~((1 << 63) - 1) - elif value.state == core.BNRegisterValueType.UnsignedRangeValue: + elif value.state == RegisterValueType.UnsignedRangeValue: self.offset = value.value self.start = value.rangeStart self.end = value.rangeEnd self.step = value.rangeStep - elif value.state == core.BNRegisterValueType.LookupTableValue: + elif value.state == RegisterValueType.LookupTableValue: self.table = [] self.mapping = {} for i in xrange(0, value.rangeEnd): @@ -78,25 +80,25 @@ class RegisterValue(object): from_list.append(value.table[i].fromValues[j]) self.mapping[value.table[i].fromValues[j]] = value.table[i].toValue self.table.append(LookupTableEntry(from_list, value.table[i].toValue)) - elif value.state == core.BNRegisterValueType.OffsetFromUndeterminedValue: + elif value.state == RegisterValueType.OffsetFromUndeterminedValue: self.offset = value.value def __repr__(self): - if self.type == core.BNRegisterValueType.EntryValue: + if self.type == RegisterValueType.EntryValue: return "" % self.reg - if self.type == core.BNRegisterValueType.OffsetFromEntryValue: + if self.type == RegisterValueType.OffsetFromEntryValue: return "" % (self.reg, self.offset) - if self.type == core.BNRegisterValueType.ConstantValue: + if self.type == RegisterValueType.ConstantValue: return "" % self.value - if self.type == core.BNRegisterValueType.StackFrameOffset: + if self.type == RegisterValueType.StackFrameOffset: return "" % self.offset - if (self.type == core.BNRegisterValueType.SignedRangeValue) or (self.type == core.BNRegisterValueType.UnsignedRangeValue): + if (self.type == RegisterValueType.SignedRangeValue) or (self.type == RegisterValueType.UnsignedRangeValue): if self.step == 1: return "" % (self.start, self.end) return "" % (self.start, self.end, self.step) - if self.type == core.BNRegisterValueType.LookupTableValue: + if self.type == RegisterValueType.LookupTableValue: return "" % ', '.join([repr(i) for i in self.table]) - if self.type == core.BNRegisterValueType.OffsetFromUndeterminedValue: + if self.type == RegisterValueType.OffsetFromUndeterminedValue: return "" % self.offset return "" @@ -195,7 +197,7 @@ class Function(object): if self.symbol is not None: self.view.undefine_user_symbol(self.symbol) else: - symbol = bntype.Symbol(core.BNSymbolType.FunctionSymbol, self.start, value) + symbol = types.Symbol(SymbolType.FunctionSymbol, self.start, value) self.view.define_user_symbol(symbol) @property @@ -230,7 +232,7 @@ class Function(object): sym = core.BNGetFunctionSymbol(self.handle) if sym is None: return None - return bntype.Symbol(None, None, None, handle = sym) + return types.Symbol(None, None, None, handle = sym) @property def auto(self): @@ -287,7 +289,7 @@ class Function(object): @property def function_type(self): """Function type object""" - return bntype.Type(core.BNGetFunctionType(self.handle)) + return types.Type(core.BNGetFunctionType(self.handle)) @function_type.setter def function_type(self, value): @@ -300,7 +302,7 @@ class Function(object): v = core.BNGetStackLayout(self.handle, count) result = [] for i in xrange(0, count.value): - result.append(StackVariable(v[i].offset, v[i].name, bntype.Type(handle = core.BNNewTypeReference(v[i].type)))) + result.append(StackVariable(v[i].offset, v[i].name, types.Type(handle = core.BNNewTypeReference(v[i].type)))) result.sort(key = lambda x: x.offset) core.BNFreeStackLayout(v, count.value) return result @@ -553,7 +555,7 @@ class Function(object): refs = core.BNGetStackVariablesReferencedByInstruction(self.handle, arch.handle, addr, count) result = [] for i in xrange(0, count.value): - result.append(StackVariableReference(refs[i].sourceOperand, bntype.Type(core.BNNewTypeReference(refs[i].type)), + result.append(StackVariableReference(refs[i].sourceOperand, types.Type(core.BNNewTypeReference(refs[i].type)), refs[i].name, refs[i].startingOffset, refs[i].referencedOffset)) core.BNFreeStackVariableReferenceList(refs, count.value) return result @@ -661,7 +663,7 @@ class Function(object): for i in xrange(0, count.value): tokens = [] for j in xrange(0, lines[i].count): - token_type = core.BNInstructionTextTokenType(lines[i].tokens[j].type) + token_type = InstructionTextTokenType(lines[i].tokens[j].type) text = lines[i].tokens[j].text value = lines[i].tokens[j].value size = lines[i].tokens[j].size @@ -688,13 +690,13 @@ class Function(object): :param int instr_addr: :param int value: :param int operand: - :param BNIntegerDisplayTypeEnum display_type: + :param IntegerDisplayTypeEnum display_type: :param Architecture arch: (optional) """ if arch is None: arch = self.arch if isinstance(display_type, str): - display_type = core.BNIntegerDisplayType[display_type] + display_type = IntegerDisplayType[display_type] core.BNSetIntegerConstantDisplayType(self.handle, arch.handle, instr_addr, value, operand, display_type) def reanalyze(self): @@ -741,13 +743,13 @@ class Function(object): if arch is None: arch = self.arch color = core.BNGetInstructionHighlight(self.handle, arch.handle, addr) - if color.style == core.BNHighlightColorStyle.StandardHighlightColor: + if color.style == HighlightColorStyle.StandardHighlightColor: return highlight.HighlightColor(color = color.color, alpha = color.alpha) - elif color.style == core.BNHighlightColorStyle.MixedHighlightColor: + elif color.style == HighlightColorStyle.MixedHighlightColor: return highlight.HighlightColor(color = color.color, mix_color = color.mixColor, mix = color.mix, alpha = color.alpha) - elif color.style == core.BNHighlightColorStyle.CustomHighlightColor: + elif color.style == HighlightColorStyle.CustomHighlightColor: return highlight.HighlightColor(red = color.r, green = color.g, blue = color.b, alpha = color.alpha) - return highlight.HighlightColor(color = core.BNHighlightStandardColor.NoHighlightColor) + return highlight.HighlightColor(color = HighlightStandardColor.NoHighlightColor) def set_auto_instr_highlight(self, addr, color, arch=None): """ @@ -756,7 +758,7 @@ class Function(object): .warning:: Use only in analysis plugins. Do not use in regular plugins, as colors won't be saved to the database. :param int addr: virtual address of the instruction to be highlighted - :param core.BNHighlightStandardColor or highlight.HighlightColor color: Color value to use for highlighting + :param HighlightStandardColor or highlight.HighlightColor color: Color value to use for highlighting :param Architecture arch: (optional) Architecture of the instruction if different from self.arch """ if arch is None: @@ -770,17 +772,17 @@ class Function(object): ``set_user_instr_highlight`` highlights the instruction at the specified address with the supplied color :param int addr: virtual address of the instruction to be highlighted - :param core.BNHighlightStandardColor or highlight.HighlightColor color: Color value to use for highlighting + :param HighlightStandardColor or highlight.HighlightColor color: Color value to use for highlighting :param Architecture arch: (optional) Architecture of the instruction if different from self.arch :Example: - >>> current_function.set_user_instr_highlight(here, core.BNHighlightStandardColor.BlueHighlightColor) + >>> current_function.set_user_instr_highlight(here, HighlightStandardColor.BlueHighlightColor) >>> current_function.set_user_instr_highlight(here, highlight.HighlightColor(red=0xff, blue=0xff, green=0)) """ if arch is None: arch = self.arch - if not isinstance(color, core.BNHighlightStandardColor) and not isinstance(color, highlight.HighlightColor): - raise ValueError("Specified color is not one of core.BNHighlightStandardColor, highlight.HighlightColor") + if not isinstance(color, HighlightStandardColor) and not isinstance(color, highlight.HighlightColor): + raise ValueError("Specified color is not one of HighlightStandardColor, highlight.HighlightColor") core.BNSetUserInstructionHighlight(self.handle, arch.handle, addr, color._get_core_struct()) @@ -908,7 +910,7 @@ class FunctionGraphBlock(object): addr = lines[i].addr tokens = [] for j in xrange(0, lines[i].count): - token_type = core.BNInstructionTextTokenType(lines[i].tokens[j].type) + token_type = InstructionTextTokenType(lines[i].tokens[j].type) text = lines[i].tokens[j].text value = lines[i].tokens[j].value size = lines[i].tokens[j].size @@ -925,7 +927,7 @@ class FunctionGraphBlock(object): edges = core.BNGetFunctionGraphBlockOutgoingEdges(self.handle, count) result = [] for i in xrange(0, count.value): - branch_type = core.BNBranchType(edges[i].type) + branch_type = BranchType(edges[i].type) target = edges[i].target arch = None if edges[i].arch is not None: @@ -958,7 +960,7 @@ class FunctionGraphBlock(object): addr = lines[i].addr tokens = [] for j in xrange(0, lines[i].count): - token_type = core.BNInstructionTextTokenType(lines[i].tokens[j].type) + token_type = InstructionTextTokenType(lines[i].tokens[j].type) text = lines[i].tokens[j].text value = lines[i].tokens[j].value size = lines[i].tokens[j].size @@ -997,12 +999,12 @@ class DisassemblySettings(object): def is_option_set(self, option): if isinstance(option, str): - option = core.BNDisassemblyOption[option] + option = DisassemblyOption[option] return core.BNIsDisassemblySettingsOptionSet(self.handle, option) def set_option(self, option, state = True): if isinstance(option, str): - option = core.BNDisassemblyOption[option] + option = DisassemblyOption[option] core.BNSetDisassemblySettingsOption(self.handle, option, state) @@ -1033,7 +1035,7 @@ class FunctionGraph(object): @property def type(self): """Function graph type (read-only)""" - return core.BNFunctionGraphType(core.BNGetFunctionGraphType(self.handle)) + return FunctionGraphType(core.BNGetFunctionGraphType(self.handle)) @property def blocks(self): @@ -1101,9 +1103,9 @@ class FunctionGraph(object): except: log.log_error(traceback.format_exc()) - def layout(self, graph_type = core.BNFunctionGraphType.NormalFunctionGraph): + def layout(self, graph_type = FunctionGraphType.NormalFunctionGraph): if isinstance(graph_type, str): - graph_type = core.BNFunctionGraphType[graph_type] + graph_type = FunctionGraphType[graph_type] core.BNStartFunctionGraphLayout(self.handle, graph_type) def _wait_complete(self): @@ -1111,7 +1113,7 @@ class FunctionGraph(object): self._wait_cond.notify() self._wait_cond.release() - def layout_and_wait(self, graph_type = core.BNFunctionGraphType.NormalFunctionGraph): + def layout_and_wait(self, graph_type=FunctionGraphType.NormalFunctionGraph): self._wait_cond = threading.Condition() self.on_complete(self._wait_complete) self.layout(graph_type) @@ -1139,17 +1141,17 @@ class FunctionGraph(object): def is_option_set(self, option): if isinstance(option, str): - option = core.BNDisassemblyOption[option] + option = DisassemblyOption[option] return core.BNIsFunctionGraphOptionSet(self.handle, option) def set_option(self, option, state = True): if isinstance(option, str): - option = core.BNDisassemblyOption[option] + option = DisassemblyOption[option] core.BNSetFunctionGraphOption(self.handle, option, state) class RegisterInfo(object): - def __init__(self, full_width_reg, size, offset = 0, extend = core.BNImplicitRegisterExtend.NoExtend, index = None): + def __init__(self, full_width_reg, size, offset=0, extend=ImplicitRegisterExtend.NoExtend, index=None): self.full_width_reg = full_width_reg self.offset = offset self.size = size @@ -1157,9 +1159,9 @@ class RegisterInfo(object): self.index = index def __repr__(self): - if self.extend == core.BNImplicitRegisterExtend.ZeroExtendToFullWidth: + if self.extend == ImplicitRegisterExtend.ZeroExtendToFullWidth: extend = ", zero extend" - elif self.extend == core.BNImplicitRegisterExtend.SignExtendToFullWidth: + elif self.extend == ImplicitRegisterExtend.SignExtendToFullWidth: extend = ", sign extend" else: extend = "" @@ -1200,7 +1202,7 @@ class InstructionTextToken(object): ``class InstructionTextToken`` is used to tell the core about the various components in the disassembly views. ========================== ============================================ - BNInstructionTextTokenType Description + InstructionTextTokenType Description ========================== ============================================ TextToken Text that doesn't fit into the other tokens InstructionToken The instruction mnemonic diff --git a/python/generator.cpp b/python/generator.cpp index 730b317c..d3725b6d 100644 --- a/python/generator.cpp +++ b/python/generator.cpp @@ -101,8 +101,13 @@ void OutputType(FILE* out, Type* type, bool isReturnType = false, bool isCallbac fprintf(out, "%s", type->GetQualifiedName(type->GetStructure()->GetName()).c_str()); break; case EnumerationTypeClass: - fprintf(out, "%sEnum", type->GetQualifiedName(type->GetEnumeration()->GetName()).c_str()); + { + string name = type->GetQualifiedName(type->GetEnumeration()->GetName()); + if (name.size() > 2 && name.substr(0, 2) == "BN") + name = name.substr(2); + fprintf(out, "%sEnum", name.c_str()); break; + } case PointerTypeClass: if (isCallback || (type->GetChildType()->GetClass() == VoidTypeClass)) { @@ -147,9 +152,9 @@ void OutputType(FILE* out, Type* type, bool isReturnType = false, bool isCallbac int main(int argc, char* argv[]) { - if (argc < 3) + if (argc < 4) { - fprintf(stderr, "Usage: generator
\n"); + fprintf(stderr, "Usage: generator
\n"); return 1; } @@ -164,23 +169,27 @@ int main(int argc, char* argv[]) return 1; FILE* out = fopen(argv[2], "w"); + FILE* enums = fopen(argv[3], "w"); - fprintf(out, "import ctypes, os, enum\n\n"); + fprintf(out, "from __future__ import absolute_import\n"); + fprintf(out, "import ctypes, os\n\n"); + fprintf(enums, "import enum"); fprintf(out, "# Load core module\n"); -#if defined(__APPLE__) - fprintf(out, "_base_path = os.path.join(os.path.dirname(__file__), \"..\", \"..\", \"..\", \"MacOS\")\n"); -#else - fprintf(out, "_base_path = os.path.join(os.path.dirname(__file__), \"..\", \"..\")\n"); -#endif - -#ifdef WIN32 - fprintf(out, "core = ctypes.CDLL(os.path.join(_base_path, \"binaryninjacore.dll\"))\n\n"); -#elif defined(__APPLE__) - fprintf(out, "core = ctypes.CDLL(os.path.join(_base_path, \"libbinaryninjacore.dylib\"))\n\n"); -#else - fprintf(out, "core = ctypes.CDLL(os.path.join(_base_path, \"libbinaryninjacore.so.1\"))\n\n"); -#endif + fprintf(out, "import platform\n"); + fprintf(out, "core = None\n"); + fprintf(out, "_base_path = None\n"); + fprintf(out, "if platform.system() == \"Darwin\":\n"); + fprintf(out, "\t_base_path = os.path.join(os.path.dirname(__file__), \"..\", \"..\", \"..\", \"MacOS\")\n"); + fprintf(out, "\tcore = ctypes.CDLL(os.path.join(_base_path, \"libbinaryninjacore.dylib\"))\n\n"); + fprintf(out, "elif platform.system() == \"Linux\":\n"); + fprintf(out, "\t_base_path = os.path.join(os.path.dirname(__file__), \"..\", \"..\")\n"); + fprintf(out, "\tcore = ctypes.CDLL(os.path.join(_base_path, \"libbinaryninjacore.so.1\"))\n\n"); + fprintf(out, "elif platform.system() == \"Windows\":\n"); + fprintf(out, "\t_base_path = os.path.join(os.path.dirname(__file__), \"..\", \"..\")\n"); + fprintf(out, "\tcore = ctypes.CDLL(os.path.join(_base_path, \"binaryninjacore.dll\"))\n"); + fprintf(out, "else:\n"); + fprintf(out, "\traise Exception(\"OS not supported\")\n\n"); // Create type objects fprintf(out, "# Type definitions\n"); @@ -189,17 +198,21 @@ int main(int argc, char* argv[]) if (i.second->GetClass() == StructureTypeClass) { fprintf(out, "class %s(ctypes.Structure):\n", i.first.c_str()); - fprintf(out, " pass\n"); + fprintf(out, "\tpass\n"); } else if (i.second->GetClass() == EnumerationTypeClass) { - fprintf(out, "%sEnum = ctypes.c_int\n", i.first.c_str()); - fprintf(out, "class %s(enum.IntEnum):\n", i.first.c_str()); + string name = i.first; + if (name.size() > 2 && name.substr(0, 2) == "BN") + name = name.substr(2); + + fprintf(out, "%sEnum = ctypes.c_int\n", name.c_str()); + + fprintf(enums, "\n\nclass %s(enum.IntEnum):\n", name.c_str()); for (auto& j : i.second->GetEnumeration()->GetMembers()) { - fprintf(out, " %s = %" PRId64 "\n", j.name.c_str(), j.value); + fprintf(enums, "\t%s = %" PRId64 "\n", j.name.c_str(), j.value); } - } else if ((i.second->GetClass() == BoolTypeClass) || (i.second->GetClass() == IntegerTypeClass) || (i.second->GetClass() == FloatTypeClass) || (i.second->GetClass() == ArrayTypeClass)) @@ -219,11 +232,11 @@ int main(int argc, char* argv[]) fprintf(out, "%s._fields_ = [\n", i.first.c_str()); for (auto& j : i.second->GetStructure()->GetMembers()) { - fprintf(out, " (\"%s\", ", j.name.c_str()); + fprintf(out, "\t\t(\"%s\", ", j.name.c_str()); OutputType(out, j.type); fprintf(out, "),\n"); } - fprintf(out, " ]\n"); + fprintf(out, "\t]\n"); } } @@ -260,7 +273,7 @@ int main(int argc, char* argv[]) fprintf(out, "%s.argtypes = [\n", funcName.c_str()); for (auto& j : i.second->GetParameters()) { - fprintf(out, " "); + fprintf(out, "\t\t"); if (i.first == "BNFreeString") { // BNFreeString expects a pointer to a string allocated by the core, so do not use @@ -274,38 +287,39 @@ int main(int argc, char* argv[]) } fprintf(out, ",\n"); } - fprintf(out, " ]\n"); + fprintf(out, "\t]\n"); } if (stringResult) { // Emit wrapper to get Python string and free native memory fprintf(out, "def %s(*args):\n", i.first.c_str()); - fprintf(out, " result = %s(*args)\n", funcName.c_str()); - fprintf(out, " string = ctypes.cast(result, ctypes.c_char_p).value\n"); - fprintf(out, " BNFreeString(result)\n"); - fprintf(out, " return string\n"); + fprintf(out, "\tresult = %s(*args)\n", funcName.c_str()); + fprintf(out, "\tstring = ctypes.cast(result, ctypes.c_char_p).value\n"); + fprintf(out, "\tBNFreeString(result)\n"); + fprintf(out, "\treturn string\n"); } else if (pointerResult) { // Emit wrapper to return None on null pointer fprintf(out, "def %s(*args):\n", i.first.c_str()); - fprintf(out, " result = %s(*args)\n", funcName.c_str()); - fprintf(out, " if not result:\n"); - fprintf(out, " return None\n"); - fprintf(out, " return result\n"); + fprintf(out, "\tresult = %s(*args)\n", funcName.c_str()); + fprintf(out, "\tif not result:\n"); + fprintf(out, "\t\treturn None\n"); + fprintf(out, "\treturn result\n"); } } fprintf(out, "\n# Helper functions\n"); fprintf(out, "def handle_of_type(value, handle_type):\n"); - fprintf(out, " if isinstance(value, ctypes.POINTER(handle_type)) or isinstance(value, ctypes.c_void_p):\n"); - fprintf(out, " return ctypes.cast(value, ctypes.POINTER(handle_type))\n"); - fprintf(out, " raise ValueError, 'expected pointer to %%s' %% str(handle_type)\n"); + fprintf(out, "\tif isinstance(value, ctypes.POINTER(handle_type)) or isinstance(value, ctypes.c_void_p):\n"); + fprintf(out, "\t\treturn ctypes.cast(value, ctypes.POINTER(handle_type))\n"); + fprintf(out, "\traise ValueError, 'expected pointer to %%s' %% str(handle_type)\n"); fprintf(out, "\n# Set path for core plugins\n"); fprintf(out, "BNSetBundledPluginDirectory(os.path.join(_base_path, \"plugins\"))\n"); fclose(out); + fclose(enums); return 0; } diff --git a/python/highlight.py b/python/highlight.py index 98735166..6af1cf95 100644 --- a/python/highlight.py +++ b/python/highlight.py @@ -21,66 +21,67 @@ # Binary Ninja components import _binaryninjacore as core +from enums import HighlightColorStyle, HighlightStandardColor class HighlightColor(object): def __init__(self, color = None, mix_color = None, mix = None, red = None, green = None, blue = None, alpha = 255): if (red is not None) and (green is not None) and (blue is not None): - self.style = core.BNHighlightColorStyle.CustomHighlightColor + self.style = HighlightColorStyle.CustomHighlightColor self.red = red self.green = green self.blue = blue elif (mix_color is not None) and (mix is not None): - self.style = core.BNHighlightColorStyle.MixedHighlightColor + self.style = HighlightColorStyle.MixedHighlightColor if color is None: - self.color = core.BNHighlightStandardColor.NoHighlightColor + self.color = HighlightStandardColor.NoHighlightColor else: self.color = color self.mix_color = mix_color self.mix = mix else: - self.style = core.BNHighlightColorStyle.StandardHighlightColor + self.style = HighlightColorStyle.StandardHighlightColor if color is None: - self.color = core.BNHighlightStandardColor.NoHighlightColor + self.color = HighlightStandardColor.NoHighlightColor else: self.color = color self.alpha = alpha def _standard_color_to_str(self, color): - if color == core.BNHighlightStandardColor.NoHighlightColor: + if color == HighlightStandardColor.NoHighlightColor: return "none" - if color == core.BNHighlightStandardColor.BlueHighlightColor: + if color == HighlightStandardColor.BlueHighlightColor: return "blue" - if color == core.BNHighlightStandardColor.GreenHighlightColor: + if color == HighlightStandardColor.GreenHighlightColor: return "green" - if color == core.BNHighlightStandardColor.CyanHighlightColor: + if color == HighlightStandardColor.CyanHighlightColor: return "cyan" - if color == core.BNHighlightStandardColor.RedHighlightColor: + if color == HighlightStandardColor.RedHighlightColor: return "red" - if color == core.BNHighlightStandardColor.MagentaHighlightColor: + if color == HighlightStandardColor.MagentaHighlightColor: return "magenta" - if color == core.BNHighlightStandardColor.YellowHighlightColor: + if color == HighlightStandardColor.YellowHighlightColor: return "yellow" - if color == core.BNHighlightStandardColor.OrangeHighlightColor: + if color == HighlightStandardColor.OrangeHighlightColor: return "orange" - if color == core.BNHighlightStandardColor.WhiteHighlightColor: + if color == HighlightStandardColor.WhiteHighlightColor: return "white" - if color == core.BNHighlightStandardColor.BlackHighlightColor: + if color == HighlightStandardColor.BlackHighlightColor: return "black" return "%d" % color def __repr__(self): - if self.style == core.BNHighlightColorStyle.StandardHighlightColor: + if self.style == HighlightColorStyle.StandardHighlightColor: if self.alpha == 255: return "" % self._standard_color_to_str(self.color) return "" % (self._standard_color_to_str(self.color), self.alpha) - if self.style == core.BNHighlightColorStyle.MixedHighlightColor: + if self.style == HighlightColorStyle.MixedHighlightColor: if self.alpha == 255: return "" % (self._standard_color_to_str(self.color), self._standard_color_to_str(self.mix_color), self.mix) return "" % (self._standard_color_to_str(self.color), self._standard_color_to_str(self.mix_color), self.mix, self.alpha) - if self.style == core.BNHighlightColorStyle.CustomHighlightColor: + if self.style == HighlightColorStyle.CustomHighlightColor: if self.alpha == 255: return "" % (self.red, self.green, self.blue) return "" % (self.red, self.green, self.blue, self.alpha) @@ -89,21 +90,21 @@ class HighlightColor(object): def _get_core_struct(self): result = core.BNHighlightColor() result.style = self.style - result.color = core.BNHighlightStandardColor.NoHighlightColor - result.mix_color = core.BNHighlightStandardColor.NoHighlightColor + result.color = HighlightStandardColor.NoHighlightColor + result.mix_color = HighlightStandardColor.NoHighlightColor result.mix = 0 result.r = 0 result.g = 0 result.b = 0 result.alpha = self.alpha - if self.style == core.BNHighlightColorStyle.StandardHighlightColor: + if self.style == HighlightColorStyle.StandardHighlightColor: result.color = self.color - elif self.style == core.BNHighlightColorStyle.MixedHighlightColor: + elif self.style == HighlightColorStyle.MixedHighlightColor: result.color = self.color result.mixColor = self.mix_color result.mix = self.mix - elif self.style == core.BNHighlightColorStyle.CustomHighlightColor: + elif self.style == HighlightColorStyle.CustomHighlightColor: result.r = self.red result.g = self.green result.b = self.blue diff --git a/python/interaction.py b/python/interaction.py index 1899b7aa..6d640d17 100644 --- a/python/interaction.py +++ b/python/interaction.py @@ -23,6 +23,7 @@ import traceback # Binary Ninja components import _binaryninjacore as core +from enums import FormInputFieldType, MessageBoxIcon, MessageBoxButtonResult import binaryview import log @@ -32,7 +33,7 @@ class LabelField(object): self.text = text def _fill_core_struct(self, value): - value.type = core.BNFormInputFieldType.LabelFormField + value.type = FormInputFieldType.LabelFormField value.prompt = self.text def _fill_core_result(self, value): @@ -44,7 +45,7 @@ class LabelField(object): class SeparatorField(object): def _fill_core_struct(self, value): - value.type = core.BNFormInputFieldType.SeparatorFormField + value.type = FormInputFieldType.SeparatorFormField def _fill_core_result(self, value): pass @@ -59,7 +60,7 @@ class TextLineField(object): self.result = None def _fill_core_struct(self, value): - value.type = core.BNFormInputFieldType.TextLineFormField + value.type = FormInputFieldType.TextLineFormField value.prompt = self.prompt def _fill_core_result(self, value): @@ -75,7 +76,7 @@ class MultilineTextField(object): self.result = None def _fill_core_struct(self, value): - value.type = core.BNFormInputFieldType.MultilineTextFormField + value.type = FormInputFieldType.MultilineTextFormField value.prompt = self.prompt def _fill_core_result(self, value): @@ -91,7 +92,7 @@ class IntegerField(object): self.result = None def _fill_core_struct(self, value): - value.type = core.BNFormInputFieldType.IntegerFormField + value.type = FormInputFieldType.IntegerFormField value.prompt = self.prompt def _fill_core_result(self, value): @@ -109,7 +110,7 @@ class AddressField(object): self.result = None def _fill_core_struct(self, value): - value.type = core.BNFormInputFieldType.AddressFormField + value.type = FormInputFieldType.AddressFormField value.prompt = self.prompt value.view = None if self.view is not None: @@ -130,7 +131,7 @@ class ChoiceField(object): self.result = None def _fill_core_struct(self, value): - value.type = core.BNFormInputFieldType.ChoiceFormField + value.type = FormInputFieldType.ChoiceFormField value.prompt = self.prompt choice_buf = (ctypes.c_char_p * len(self.choices))() for i in xrange(0, len(self.choices)): @@ -152,7 +153,7 @@ class OpenFileNameField(object): self.result = None def _fill_core_struct(self, value): - value.type = core.BNFormInputFieldType.OpenFileNameFormField + value.type = FormInputFieldType.OpenFileNameFormField value.prompt = self.prompt value.ext = self.ext @@ -171,7 +172,7 @@ class SaveFileNameField(object): self.result = None def _fill_core_struct(self, value): - value.type = core.BNFormInputFieldType.SaveFileNameFormField + value.type = FormInputFieldType.SaveFileNameFormField value.prompt = self.prompt value.ext = self.ext value.defaultName = self.default_name @@ -190,7 +191,7 @@ class DirectoryNameField(object): self.result = None def _fill_core_struct(self, value): - value.type = core.DirectoryNameField + value.type = DirectoryNameField value.prompt = self.prompt value.defaultName = self.default_name @@ -335,31 +336,31 @@ class InteractionHandler(object): try: field_objs = [] for i in xrange(0, count): - if fields[i].type == core.BNFormInputFieldType.LabelFormField: + if fields[i].type == FormInputFieldType.LabelFormField: field_objs.append(LabelField(fields[i].prompt)) - elif fields[i].type == core.BNFormInputFieldType.SeparatorFormField: + elif fields[i].type == FormInputFieldType.SeparatorFormField: field_objs.append(SeparatorField()) - elif fields[i].type == core.BNFormInputFieldType.TextLineFormField: + elif fields[i].type == FormInputFieldType.TextLineFormField: field_objs.append(TextLineField(fields[i].prompt)) - elif fields[i].type == core.BNFormInputFieldType.MultilineTextFormField: + elif fields[i].type == FormInputFieldType.MultilineTextFormField: field_objs.append(MultilineTextField(fields[i].prompt)) - elif fields[i].type == core.BNFormInputFieldType.IntegerFormField: + elif fields[i].type == FormInputFieldType.IntegerFormField: field_objs.append(IntegerField(fields[i].prompt)) - elif fields[i].type == core.BNFormInputFieldType.AddressFormField: + elif fields[i].type == FormInputFieldType.AddressFormField: view = None if fields[i].view: view = binaryview.BinaryView(handle = core.BNNewViewReference(fields[i].view)) field_objs.append(AddressField(fields[i].prompt, view, fields[i].currentAddress)) - elif fields[i].type == core.BNFormInputFieldType.ChoiceFormField: + elif fields[i].type == FormInputFieldType.ChoiceFormField: choices = [] for i in xrange(0, fields[i].count): choices.append(fields[i].choices[i]) field_objs.append(ChoiceField(fields[i].prompt, choices)) - elif fields[i].type == core.BNFormInputFieldType.OpenFileNameFormField: + elif fields[i].type == FormInputFieldType.OpenFileNameFormField: field_objs.append(OpenFileNameField(fields[i].prompt, fields[i].ext)) - elif fields[i].type == core.BNFormInputFieldType.SaveFileNameFormField: + elif fields[i].type == FormInputFieldType.SaveFileNameFormField: field_objs.append(SaveFileNameField(fields[i].prompt, fields[i].ext, fields[i].defaultName)) - elif fields[i].type == core.DirectoryNameField: + elif fields[i].type == DirectoryNameField: field_objs.append(DirectoryNameField(fields[i].prompt, fields[i].defaultName)) else: field_objs.append(LabelField(fields[i].prompt)) @@ -419,7 +420,7 @@ class InteractionHandler(object): return False def show_message_box(self, title, text, buttons, icon): - return core.BNMessageBoxButtonResult.CancelButton + return MessageBoxButtonResult.CancelButton def markdown_to_html(contents): @@ -516,5 +517,5 @@ def get_form_input(fields, title): return True -def show_message_box(title, text, buttons = core.BNMessageBoxButtonResult.OKButton, icon = core.BNMessageBoxIcon.InformationIcon): +def show_message_box(title, text, buttons = MessageBoxButtonResult.OKButton, icon = MessageBoxIcon.InformationIcon): return core.BNShowMessageBox(title, text, buttons, icon) diff --git a/python/log.py b/python/log.py index 932c739d..45adb4aa 100644 --- a/python/log.py +++ b/python/log.py @@ -57,7 +57,7 @@ def log_debug(text): :rtype: None :Example: - >>> log_to_stdout(core.BNLogLevel.DebugLog) + >>> log_to_stdout(LogLevel.DebugLog) >>> log_debug("Hotdogs!") Hotdogs! """ @@ -87,7 +87,7 @@ def log_warn(text): :rtype: None :Example: - >>> log_to_stdout(core.BNLogLevel.DebugLog) + >>> log_to_stdout(LogLevel.DebugLog) >>> log_info("Chilidogs!") Chilidogs! >>> @@ -103,7 +103,7 @@ def log_error(text): :rtype: None :Example: - >>> log_to_stdout(core.BNLogLevel.DebugLog) + >>> log_to_stdout(LogLevel.DebugLog) >>> log_error("Spanferkel!") Spanferkel! >>> @@ -119,7 +119,7 @@ def log_alert(text): :rtype: None :Example: - >>> log_to_stdout(core.BNLogLevel.DebugLog) + >>> log_to_stdout(LogLevel.DebugLog) >>> log_alert("Kielbasa!") Kielbasa! >>> @@ -136,7 +136,7 @@ def log_to_stdout(min_level): :Example: >>> log_debug("Hotdogs!") - >>> log_to_stdout(core.BNLogLevel.DebugLog) + >>> log_to_stdout(LogLevel.DebugLog) >>> log_debug("Hotdogs!") Hotdogs! >>> diff --git a/python/lowlevelil.py b/python/lowlevelil.py index 7025a7c1..4564bf13 100644 --- a/python/lowlevelil.py +++ b/python/lowlevelil.py @@ -22,6 +22,7 @@ import ctypes # Binary Ninja components import _binaryninjacore as core +from .enums import LowLevelILOperation, LowLevelILFlagCondition, InstructionTextTokenType import function import basicblock @@ -43,73 +44,73 @@ class LowLevelILInstruction(object): """ ILOperations = { - core.BNLowLevelILOperation.LLIL_NOP: [], - core.BNLowLevelILOperation.LLIL_SET_REG: [("dest", "reg"), ("src", "expr")], - core.BNLowLevelILOperation.LLIL_SET_REG_SPLIT: [("hi", "reg"), ("lo", "reg"), ("src", "expr")], - core.BNLowLevelILOperation.LLIL_SET_FLAG: [("dest", "flag"), ("src", "expr")], - core.BNLowLevelILOperation.LLIL_LOAD: [("src", "expr")], - core.BNLowLevelILOperation.LLIL_STORE: [("dest", "expr"), ("src", "expr")], - core.BNLowLevelILOperation.LLIL_PUSH: [("src", "expr")], - core.BNLowLevelILOperation.LLIL_POP: [], - core.BNLowLevelILOperation.LLIL_REG: [("src", "reg")], - core.BNLowLevelILOperation.LLIL_CONST: [("value", "int")], - core.BNLowLevelILOperation.LLIL_FLAG: [("src", "flag")], - core.BNLowLevelILOperation.LLIL_FLAG_BIT: [("src", "flag"), ("bit", "int")], - core.BNLowLevelILOperation.LLIL_ADD: [("left", "expr"), ("right", "expr")], - core.BNLowLevelILOperation.LLIL_ADC: [("left", "expr"), ("right", "expr")], - core.BNLowLevelILOperation.LLIL_SUB: [("left", "expr"), ("right", "expr")], - core.BNLowLevelILOperation.LLIL_SBB: [("left", "expr"), ("right", "expr")], - core.BNLowLevelILOperation.LLIL_AND: [("left", "expr"), ("right", "expr")], - core.BNLowLevelILOperation.LLIL_OR: [("left", "expr"), ("right", "expr")], - core.BNLowLevelILOperation.LLIL_XOR: [("left", "expr"), ("right", "expr")], - core.BNLowLevelILOperation.LLIL_LSL: [("left", "expr"), ("right", "expr")], - core.BNLowLevelILOperation.LLIL_LSR: [("left", "expr"), ("right", "expr")], - core.BNLowLevelILOperation.LLIL_ASR: [("left", "expr"), ("right", "expr")], - core.BNLowLevelILOperation.LLIL_ROL: [("left", "expr"), ("right", "expr")], - core.BNLowLevelILOperation.LLIL_RLC: [("left", "expr"), ("right", "expr")], - core.BNLowLevelILOperation.LLIL_ROR: [("left", "expr"), ("right", "expr")], - core.BNLowLevelILOperation.LLIL_RRC: [("left", "expr"), ("right", "expr")], - core.BNLowLevelILOperation.LLIL_MUL: [("left", "expr"), ("right", "expr")], - core.BNLowLevelILOperation.LLIL_MULU_DP: [("left", "expr"), ("right", "expr")], - core.BNLowLevelILOperation.LLIL_MULS_DP: [("left", "expr"), ("right", "expr")], - core.BNLowLevelILOperation.LLIL_DIVU: [("left", "expr"), ("right", "expr")], - core.BNLowLevelILOperation.LLIL_DIVU_DP: [("hi", "expr"), ("lo", "expr"), ("right", "expr")], - core.BNLowLevelILOperation.LLIL_DIVS: [("left", "expr"), ("right", "expr")], - core.BNLowLevelILOperation.LLIL_DIVS_DP: [("hi", "expr"), ("lo", "expr"), ("right", "expr")], - core.BNLowLevelILOperation.LLIL_MODU: [("left", "expr"), ("right", "expr")], - core.BNLowLevelILOperation.LLIL_MODU_DP: [("hi", "expr"), ("lo", "expr"), ("right", "expr")], - core.BNLowLevelILOperation.LLIL_MODS: [("left", "expr"), ("right", "expr")], - core.BNLowLevelILOperation.LLIL_MODS_DP: [("hi", "expr"), ("lo", "expr"), ("right", "expr")], - core.BNLowLevelILOperation.LLIL_NEG: [("src", "expr")], - core.BNLowLevelILOperation.LLIL_NOT: [("src", "expr")], - core.BNLowLevelILOperation.LLIL_SX: [("src", "expr")], - core.BNLowLevelILOperation.LLIL_ZX: [("src", "expr")], - core.BNLowLevelILOperation.LLIL_JUMP: [("dest", "expr")], - core.BNLowLevelILOperation.LLIL_JUMP_TO: [("dest", "expr"), ("targets", "int_list")], - core.BNLowLevelILOperation.LLIL_CALL: [("dest", "expr")], - core.BNLowLevelILOperation.LLIL_RET: [("dest", "expr")], - core.BNLowLevelILOperation.LLIL_NORET: [], - core.BNLowLevelILOperation.LLIL_IF: [("condition", "expr"), ("true", "int"), ("false", "int")], - core.BNLowLevelILOperation.LLIL_GOTO: [("dest", "int")], - core.BNLowLevelILOperation.LLIL_FLAG_COND: [("condition", "cond")], - core.BNLowLevelILOperation.LLIL_CMP_E: [("left", "expr"), ("right", "expr")], - core.BNLowLevelILOperation.LLIL_CMP_NE: [("left", "expr"), ("right", "expr")], - core.BNLowLevelILOperation.LLIL_CMP_SLT: [("left", "expr"), ("right", "expr")], - core.BNLowLevelILOperation.LLIL_CMP_ULT: [("left", "expr"), ("right", "expr")], - core.BNLowLevelILOperation.LLIL_CMP_SLE: [("left", "expr"), ("right", "expr")], - core.BNLowLevelILOperation.LLIL_CMP_ULE: [("left", "expr"), ("right", "expr")], - core.BNLowLevelILOperation.LLIL_CMP_SGE: [("left", "expr"), ("right", "expr")], - core.BNLowLevelILOperation.LLIL_CMP_UGE: [("left", "expr"), ("right", "expr")], - core.BNLowLevelILOperation.LLIL_CMP_SGT: [("left", "expr"), ("right", "expr")], - core.BNLowLevelILOperation.LLIL_CMP_UGT: [("left", "expr"), ("right", "expr")], - core.BNLowLevelILOperation.LLIL_TEST_BIT: [("left", "expr"), ("right", "expr")], - core.BNLowLevelILOperation.LLIL_BOOL_TO_INT: [("src", "expr")], - core.BNLowLevelILOperation.LLIL_SYSCALL: [], - core.BNLowLevelILOperation.LLIL_BP: [], - core.BNLowLevelILOperation.LLIL_TRAP: [("value", "int")], - core.BNLowLevelILOperation.LLIL_UNDEF: [], - core.BNLowLevelILOperation.LLIL_UNIMPL: [], - core.BNLowLevelILOperation.LLIL_UNIMPL_MEM: [("src", "expr")] + LowLevelILOperation.LLIL_NOP: [], + LowLevelILOperation.LLIL_SET_REG: [("dest", "reg"), ("src", "expr")], + LowLevelILOperation.LLIL_SET_REG_SPLIT: [("hi", "reg"), ("lo", "reg"), ("src", "expr")], + LowLevelILOperation.LLIL_SET_FLAG: [("dest", "flag"), ("src", "expr")], + LowLevelILOperation.LLIL_LOAD: [("src", "expr")], + LowLevelILOperation.LLIL_STORE: [("dest", "expr"), ("src", "expr")], + LowLevelILOperation.LLIL_PUSH: [("src", "expr")], + LowLevelILOperation.LLIL_POP: [], + LowLevelILOperation.LLIL_REG: [("src", "reg")], + LowLevelILOperation.LLIL_CONST: [("value", "int")], + LowLevelILOperation.LLIL_FLAG: [("src", "flag")], + LowLevelILOperation.LLIL_FLAG_BIT: [("src", "flag"), ("bit", "int")], + LowLevelILOperation.LLIL_ADD: [("left", "expr"), ("right", "expr")], + LowLevelILOperation.LLIL_ADC: [("left", "expr"), ("right", "expr")], + LowLevelILOperation.LLIL_SUB: [("left", "expr"), ("right", "expr")], + LowLevelILOperation.LLIL_SBB: [("left", "expr"), ("right", "expr")], + LowLevelILOperation.LLIL_AND: [("left", "expr"), ("right", "expr")], + LowLevelILOperation.LLIL_OR: [("left", "expr"), ("right", "expr")], + LowLevelILOperation.LLIL_XOR: [("left", "expr"), ("right", "expr")], + LowLevelILOperation.LLIL_LSL: [("left", "expr"), ("right", "expr")], + LowLevelILOperation.LLIL_LSR: [("left", "expr"), ("right", "expr")], + LowLevelILOperation.LLIL_ASR: [("left", "expr"), ("right", "expr")], + LowLevelILOperation.LLIL_ROL: [("left", "expr"), ("right", "expr")], + LowLevelILOperation.LLIL_RLC: [("left", "expr"), ("right", "expr")], + LowLevelILOperation.LLIL_ROR: [("left", "expr"), ("right", "expr")], + LowLevelILOperation.LLIL_RRC: [("left", "expr"), ("right", "expr")], + LowLevelILOperation.LLIL_MUL: [("left", "expr"), ("right", "expr")], + LowLevelILOperation.LLIL_MULU_DP: [("left", "expr"), ("right", "expr")], + LowLevelILOperation.LLIL_MULS_DP: [("left", "expr"), ("right", "expr")], + LowLevelILOperation.LLIL_DIVU: [("left", "expr"), ("right", "expr")], + LowLevelILOperation.LLIL_DIVU_DP: [("hi", "expr"), ("lo", "expr"), ("right", "expr")], + LowLevelILOperation.LLIL_DIVS: [("left", "expr"), ("right", "expr")], + LowLevelILOperation.LLIL_DIVS_DP: [("hi", "expr"), ("lo", "expr"), ("right", "expr")], + LowLevelILOperation.LLIL_MODU: [("left", "expr"), ("right", "expr")], + LowLevelILOperation.LLIL_MODU_DP: [("hi", "expr"), ("lo", "expr"), ("right", "expr")], + LowLevelILOperation.LLIL_MODS: [("left", "expr"), ("right", "expr")], + LowLevelILOperation.LLIL_MODS_DP: [("hi", "expr"), ("lo", "expr"), ("right", "expr")], + LowLevelILOperation.LLIL_NEG: [("src", "expr")], + LowLevelILOperation.LLIL_NOT: [("src", "expr")], + LowLevelILOperation.LLIL_SX: [("src", "expr")], + LowLevelILOperation.LLIL_ZX: [("src", "expr")], + LowLevelILOperation.LLIL_JUMP: [("dest", "expr")], + LowLevelILOperation.LLIL_JUMP_TO: [("dest", "expr"), ("targets", "int_list")], + LowLevelILOperation.LLIL_CALL: [("dest", "expr")], + LowLevelILOperation.LLIL_RET: [("dest", "expr")], + LowLevelILOperation.LLIL_NORET: [], + LowLevelILOperation.LLIL_IF: [("condition", "expr"), ("true", "int"), ("false", "int")], + LowLevelILOperation.LLIL_GOTO: [("dest", "int")], + LowLevelILOperation.LLIL_FLAG_COND: [("condition", "cond")], + LowLevelILOperation.LLIL_CMP_E: [("left", "expr"), ("right", "expr")], + LowLevelILOperation.LLIL_CMP_NE: [("left", "expr"), ("right", "expr")], + LowLevelILOperation.LLIL_CMP_SLT: [("left", "expr"), ("right", "expr")], + LowLevelILOperation.LLIL_CMP_ULT: [("left", "expr"), ("right", "expr")], + LowLevelILOperation.LLIL_CMP_SLE: [("left", "expr"), ("right", "expr")], + LowLevelILOperation.LLIL_CMP_ULE: [("left", "expr"), ("right", "expr")], + LowLevelILOperation.LLIL_CMP_SGE: [("left", "expr"), ("right", "expr")], + LowLevelILOperation.LLIL_CMP_UGE: [("left", "expr"), ("right", "expr")], + LowLevelILOperation.LLIL_CMP_SGT: [("left", "expr"), ("right", "expr")], + LowLevelILOperation.LLIL_CMP_UGT: [("left", "expr"), ("right", "expr")], + LowLevelILOperation.LLIL_TEST_BIT: [("left", "expr"), ("right", "expr")], + LowLevelILOperation.LLIL_BOOL_TO_INT: [("src", "expr")], + LowLevelILOperation.LLIL_SYSCALL: [], + LowLevelILOperation.LLIL_BP: [], + LowLevelILOperation.LLIL_TRAP: [("value", "int")], + LowLevelILOperation.LLIL_UNDEF: [], + LowLevelILOperation.LLIL_UNIMPL: [], + LowLevelILOperation.LLIL_UNIMPL_MEM: [("src", "expr")] } def __init__(self, func, expr_index, instr_index=None): @@ -118,7 +119,7 @@ class LowLevelILInstruction(object): self.expr_index = expr_index self.instr_index = instr_index self.operation = instr.operation - self.operation_name = core.BNLowLevelILOperation(instr.operation) + self.operation_name = LowLevelILOperation(instr.operation) self.size = instr.size self.address = instr.address self.source_operand = instr.sourceOperand @@ -144,7 +145,7 @@ class LowLevelILInstruction(object): elif operand_type == "flag": value = func.arch.get_flag_name(instr.operands[i]) elif operand_type == "cond": - value = core.BNLowLevelILFlagCondition(instr.operands[i]) + value = LowLevelILFlagCondition(instr.operands[i]) elif operand_type == "int_list": count = ctypes.c_ulonglong() operands = core.BNLowLevelILGetOperandList(func.handle, self.expr_index, i, count) @@ -182,7 +183,7 @@ class LowLevelILInstruction(object): return None result = [] for i in xrange(0, count.value): - token_type = core.BNInstructionTextTokenType(tokens[i].type) + token_type = InstructionTextTokenType(tokens[i].type) text = tokens[i].text value = tokens[i].value size = tokens[i].size @@ -329,8 +330,8 @@ class LowLevelILFunction(object): def expr(self, operation, a = 0, b = 0, c = 0, d = 0, size = 0, flags = None): if isinstance(operation, str): - operation = core.BNLowLevelILOperation[operation] - elif isinstance(operation, core.BNLowLevelILOperation): + operation = LowLevelILOperation[operation] + elif isinstance(operation, LowLevelILOperation): operation = operation.value if isinstance(flags, str): flags = self.arch.get_flag_write_type_by_name(flags) @@ -355,7 +356,7 @@ class LowLevelILFunction(object): :return: The no operation expression :rtype: LowLevelILExpr """ - return self.expr(core.BNLowLevelILOperation.LLIL_NOP) + return self.expr(LowLevelILOperation.LLIL_NOP) def set_reg(self, size, reg, value, flags = 0): """ @@ -370,7 +371,7 @@ class LowLevelILFunction(object): """ if isinstance(reg, str): reg = self.arch.regs[reg].index - return self.expr(core.BNLowLevelILOperation.LLIL_SET_REG, reg, value.index, size = size, flags = flags) + return self.expr(LowLevelILOperation.LLIL_SET_REG, reg, value.index, size = size, flags = flags) def set_reg_split(self, size, hi, lo, value, flags = 0): """ @@ -389,7 +390,7 @@ class LowLevelILFunction(object): hi = self.arch.regs[hi].index if isinstance(lo, str): lo = self.arch.regs[lo].index - return self.expr(core.BNLowLevelILOperation.LLIL_SET_REG_SPLIT, hi, lo, value.index, size = size, flags = flags) + return self.expr(LowLevelILOperation.LLIL_SET_REG_SPLIT, hi, lo, value.index, size = size, flags = flags) def set_flag(self, flag, value): """ @@ -400,7 +401,7 @@ class LowLevelILFunction(object): :return: The expression FLAG.flag = value :rtype: LowLevelILExpr """ - return self.expr(core.BNLowLevelILOperation.LLIL_SET_FLAG, self.arch.get_flag_by_name(flag), value.index) + return self.expr(LowLevelILOperation.LLIL_SET_FLAG, self.arch.get_flag_by_name(flag), value.index) def load(self, size, addr): """ @@ -411,7 +412,7 @@ class LowLevelILFunction(object): :return: The expression ``[addr].size`` :rtype: LowLevelILExpr """ - return self.expr(core.BNLowLevelILOperation.LLIL_LOAD, addr.index, size=size) + return self.expr(LowLevelILOperation.LLIL_LOAD, addr.index, size=size) def store(self, size, addr, value): """ @@ -423,7 +424,7 @@ class LowLevelILFunction(object): :return: The expression ``[addr].size = value`` :rtype: LowLevelILExpr """ - return self.expr(core.BNLowLevelILOperation.LLIL_STORE, addr.index, value.index, size=size) + return self.expr(LowLevelILOperation.LLIL_STORE, addr.index, value.index, size=size) def push(self, size, value): """ @@ -434,7 +435,7 @@ class LowLevelILFunction(object): :return: The expression push(value) :rtype: LowLevelILExpr """ - return self.expr(core.BNLowLevelILOperation.LLIL_PUSH, value.index, size=size) + return self.expr(LowLevelILOperation.LLIL_PUSH, value.index, size=size) def pop(self, size): """ @@ -444,7 +445,7 @@ class LowLevelILFunction(object): :return: The expression ``pop`` :rtype: LowLevelILExpr """ - return self.expr(core.BNLowLevelILOperation.LLIL_POP, size=size) + return self.expr(LowLevelILOperation.LLIL_POP, size=size) def reg(self, size, reg): """ @@ -457,7 +458,7 @@ class LowLevelILFunction(object): """ if isinstance(reg, str): reg = self.arch.regs[reg].index - return self.expr(core.BNLowLevelILOperation.LLIL_REG, reg, size=size) + return self.expr(LowLevelILOperation.LLIL_REG, reg, size=size) def const(self, size, value): """ @@ -468,7 +469,7 @@ class LowLevelILFunction(object): :return: A constant expression of given value and size :rtype: LowLevelILExpr """ - return self.expr(core.BNLowLevelILOperation.LLIL_CONST, value, size=size) + return self.expr(LowLevelILOperation.LLIL_CONST, value, size=size) def flag(self, reg): """ @@ -478,7 +479,7 @@ class LowLevelILFunction(object): :return: A flag expression of given flag name :rtype: LowLevelILExpr """ - return self.expr(core.BNLowLevelILOperation.LLIL_FLAG, self.arch.get_flag_by_name(reg)) + return self.expr(LowLevelILOperation.LLIL_FLAG, self.arch.get_flag_by_name(reg)) def flag_bit(self, size, reg, bit): """ @@ -490,7 +491,7 @@ class LowLevelILFunction(object): :return: A constant expression of given value and size ``FLAG.reg = bit`` :rtype: LowLevelILExpr """ - return self.expr(core.BNLowLevelILOperation.LLIL_FLAG_BIT, self.arch.get_flag_by_name(reg), bit, size=size) + return self.expr(LowLevelILOperation.LLIL_FLAG_BIT, self.arch.get_flag_by_name(reg), bit, size=size) def add(self, size, a, b, flags=None): """ @@ -504,7 +505,7 @@ class LowLevelILFunction(object): :return: The expression ``add.{}(a, b)`` :rtype: LowLevelILExpr """ - return self.expr(core.BNLowLevelILOperation.LLIL_ADD, a.index, b.index, size=size, flags=flags) + return self.expr(LowLevelILOperation.LLIL_ADD, a.index, b.index, size=size, flags=flags) def add_carry(self, size, a, b, flags=None): """ @@ -518,7 +519,7 @@ class LowLevelILFunction(object): :return: The expression ``adc.{}(a, b)`` :rtype: LowLevelILExpr """ - return self.expr(core.BNLowLevelILOperation.LLIL_ADC, a.index, b.index, size=size, flags=flags) + return self.expr(LowLevelILOperation.LLIL_ADC, a.index, b.index, size=size, flags=flags) def sub(self, size, a, b, flags=None): """ @@ -532,7 +533,7 @@ class LowLevelILFunction(object): :return: The expression ``sub.{}(a, b)`` :rtype: LowLevelILExpr """ - return self.expr(core.BNLowLevelILOperation.LLIL_SUB, a.index, b.index, size=size, flags=flags) + return self.expr(LowLevelILOperation.LLIL_SUB, a.index, b.index, size=size, flags=flags) def sub_borrow(self, size, a, b, flags=None): """ @@ -546,7 +547,7 @@ class LowLevelILFunction(object): :return: The expression ``sbc.{}(a, b)`` :rtype: LowLevelILExpr """ - return self.expr(core.BNLowLevelILOperation.LLIL_SBB, a.index, b.index, size=size, flags=flags) + return self.expr(LowLevelILOperation.LLIL_SBB, a.index, b.index, size=size, flags=flags) def and_expr(self, size, a, b, flags=None): """ @@ -560,7 +561,7 @@ class LowLevelILFunction(object): :return: The expression ``and.{}(a, b)`` :rtype: LowLevelILExpr """ - return self.expr(core.BNLowLevelILOperation.LLIL_AND, a.index, b.index, size=size, flags=flags) + return self.expr(LowLevelILOperation.LLIL_AND, a.index, b.index, size=size, flags=flags) def or_expr(self, size, a, b, flags=None): """ @@ -574,7 +575,7 @@ class LowLevelILFunction(object): :return: The expression ``or.{}(a, b)`` :rtype: LowLevelILExpr """ - return self.expr(core.BNLowLevelILOperation.LLIL_OR, a.index, b.index, size=size, flags=flags) + return self.expr(LowLevelILOperation.LLIL_OR, a.index, b.index, size=size, flags=flags) def xor_expr(self, size, a, b, flags=None): """ @@ -588,7 +589,7 @@ class LowLevelILFunction(object): :return: The expression ``xor.{}(a, b)`` :rtype: LowLevelILExpr """ - return self.expr(core.BNLowLevelILOperation.LLIL_XOR, a.index, b.index, size=size, flags=flags) + return self.expr(LowLevelILOperation.LLIL_XOR, a.index, b.index, size=size, flags=flags) def shift_left(self, size, a, b, flags=None): """ @@ -602,7 +603,7 @@ class LowLevelILFunction(object): :return: The expression ``lsl.{}(a, b)`` :rtype: LowLevelILExpr """ - return self.expr(core.BNLowLevelILOperation.LLIL_LSL, a.index, b.index, size=size, flags=flags) + return self.expr(LowLevelILOperation.LLIL_LSL, a.index, b.index, size=size, flags=flags) def logical_shift_right(self, size, a, b, flags=None): """ @@ -616,7 +617,7 @@ class LowLevelILFunction(object): :return: The expression ``lsr.{}(a, b)`` :rtype: LowLevelILExpr """ - return self.expr(core.BNLowLevelILOperation.LLIL_LSR, a.index, b.index, size=size, flags=flags) + return self.expr(LowLevelILOperation.LLIL_LSR, a.index, b.index, size=size, flags=flags) def arith_shift_right(self, size, a, b, flags=None): """ @@ -630,7 +631,7 @@ class LowLevelILFunction(object): :return: The expression ``asr.{}(a, b)`` :rtype: LowLevelILExpr """ - return self.expr(core.BNLowLevelILOperation.LLIL_ASR, a.index, b.index, size=size, flags=flags) + return self.expr(LowLevelILOperation.LLIL_ASR, a.index, b.index, size=size, flags=flags) def rotate_left(self, size, a, b, flags=None): """ @@ -644,7 +645,7 @@ class LowLevelILFunction(object): :return: The expression ``rol.{}(a, b)`` :rtype: LowLevelILExpr """ - return self.expr(core.BNLowLevelILOperation.LLIL_ROL, a.index, b.index, size=size, flags=flags) + return self.expr(LowLevelILOperation.LLIL_ROL, a.index, b.index, size=size, flags=flags) def rotate_left_carry(self, size, a, b, flags=None): """ @@ -658,7 +659,7 @@ class LowLevelILFunction(object): :return: The expression ``rcl.{}(a, b)`` :rtype: LowLevelILExpr """ - return self.expr(core.LLIL_RLC, a.index, b.index, size=size, flags=flags) + return self.expr(LowLevelILOperation.LLIL_RLC, a.index, b.index, size=size, flags=flags) def rotate_right(self, size, a, b, flags=None): """ @@ -672,7 +673,7 @@ class LowLevelILFunction(object): :return: The expression ``ror.{}(a, b)`` :rtype: LowLevelILExpr """ - return self.expr(core.BNLowLevelILOperation.LLIL_ROR, a.index, b.index, size=size, flags=flags) + return self.expr(LowLevelILOperation.LLIL_ROR, a.index, b.index, size=size, flags=flags) def rotate_right_carry(self, size, a, b, flags=None): """ @@ -686,7 +687,7 @@ class LowLevelILFunction(object): :return: The expression ``rcr.{}(a, b)`` :rtype: LowLevelILExpr """ - return self.expr(core.BNLowLevelILOperation.LLIL_RRC, a.index, b.index, size=size, flags=flags) + return self.expr(LowLevelILOperation.LLIL_RRC, a.index, b.index, size=size, flags=flags) def mult(self, size, a, b, flags=None): """ @@ -700,7 +701,7 @@ class LowLevelILFunction(object): :return: The expression ``sbc.{}(a, b)`` :rtype: LowLevelILExpr """ - return self.expr(core.BNLowLevelILOperation.LLIL_MUL, a.index, b.index, size=size, flags=flags) + return self.expr(LowLevelILOperation.LLIL_MUL, a.index, b.index, size=size, flags=flags) def mult_double_prec_signed(self, size, a, b, flags=None): """ @@ -714,7 +715,7 @@ class LowLevelILFunction(object): :return: The expression ``muls.dp.{}(a, b)`` :rtype: LowLevelILExpr """ - return self.expr(core.BNLowLevelILOperation.LLIL_MULS_DP, a.index, b.index, size=size, flags=flags) + return self.expr(LowLevelILOperation.LLIL_MULS_DP, a.index, b.index, size=size, flags=flags) def mult_double_prec_unsigned(self, size, a, b, flags=None): """ @@ -728,7 +729,7 @@ class LowLevelILFunction(object): :return: The expression ``muls.dp.{}(a, b)`` :rtype: LowLevelILExpr """ - return self.expr(core.BNLowLevelILOperation.LLIL_MULU_DP, a.index, b.index, size=size, flags=flags) + return self.expr(LowLevelILOperation.LLIL_MULU_DP, a.index, b.index, size=size, flags=flags) def div_signed(self, size, a, b, flags=None): """ @@ -742,7 +743,7 @@ class LowLevelILFunction(object): :return: The expression ``divs.{}(a, b)`` :rtype: LowLevelILExpr """ - return self.expr(core.BNLowLevelILOperation.LLIL_DIVS, a.index, b.index, size=size, flags=flags) + return self.expr(LowLevelILOperation.LLIL_DIVS, a.index, b.index, size=size, flags=flags) def div_double_prec_signed(self, size, hi, lo, b, flags=None): """ @@ -758,7 +759,7 @@ class LowLevelILFunction(object): :return: The expression ``divs.dp.{}(hi:lo, b)`` :rtype: LowLevelILExpr """ - return self.expr(core.BNLowLevelILOperation.LLIL_DIVS_DP, hi.index, lo.index, b.index, size=size, flags=flags) + return self.expr(LowLevelILOperation.LLIL_DIVS_DP, hi.index, lo.index, b.index, size=size, flags=flags) def div_unsigned(self, size, a, b, flags=None): """ @@ -772,7 +773,7 @@ class LowLevelILFunction(object): :return: The expression ``divs.{}(a, b)`` :rtype: LowLevelILExpr """ - return self.expr(core.BNLowLevelILOperation.LLIL_DIVS, a.index, b.index, size=size, flags=flags) + return self.expr(LowLevelILOperation.LLIL_DIVS, a.index, b.index, size=size, flags=flags) def div_double_prec_unsigned(self, size, hi, lo, b, flags=None): """ @@ -788,7 +789,7 @@ class LowLevelILFunction(object): :return: The expression ``divs.dp.{}(hi:lo, b)`` :rtype: LowLevelILExpr """ - return self.expr(core.BNLowLevelILOperation.LLIL_DIVS_DP, hi.index, lo.index, b.index, size=size, flags=flags) + return self.expr(LowLevelILOperation.LLIL_DIVS_DP, hi.index, lo.index, b.index, size=size, flags=flags) def mod_signed(self, size, a, b, flags=None): """ @@ -802,7 +803,7 @@ class LowLevelILFunction(object): :return: The expression ``mods.{}(a, b)`` :rtype: LowLevelILExpr """ - return self.expr(core.BNLowLevelILOperation.LLIL_MODS, a.index, b.index, size=size, flags=flags) + return self.expr(LowLevelILOperation.LLIL_MODS, a.index, b.index, size=size, flags=flags) def mod_double_prec_signed(self, size, hi, lo, b, flags=None): """ @@ -818,7 +819,7 @@ class LowLevelILFunction(object): :return: The expression ``mods.dp.{}(hi:lo, b)`` :rtype: LowLevelILExpr """ - return self.expr(core.BNLowLevelILOperation.LLIL_MODS_DP, hi.index, lo.index, b.index, size=size, flags=flags) + return self.expr(LowLevelILOperation.LLIL_MODS_DP, hi.index, lo.index, b.index, size=size, flags=flags) def mod_unsigned(self, size, a, b, flags=None): """ @@ -832,7 +833,7 @@ class LowLevelILFunction(object): :return: The expression ``modu.{}(a, b)`` :rtype: LowLevelILExpr """ - return self.expr(core.BNLowLevelILOperation.LLIL_MODS, a.index, b.index, size=size, flags=flags) + return self.expr(LowLevelILOperation.LLIL_MODS, a.index, b.index, size=size, flags=flags) def mod_double_prec_unsigned(self, size, hi, lo, b, flags=None): """ @@ -848,7 +849,7 @@ class LowLevelILFunction(object): :return: The expression ``modu.dp.{}(hi:lo, b)`` :rtype: LowLevelILExpr """ - return self.expr(core.BNLowLevelILOperation.LLIL_MODS_DP, hi.index, lo.index, b.index, size=size, flags=flags) + return self.expr(LowLevelILOperation.LLIL_MODS_DP, hi.index, lo.index, b.index, size=size, flags=flags) def neg_expr(self, size, value, flags=None): """ @@ -860,7 +861,7 @@ class LowLevelILFunction(object): :return: The expression ``neg.{}(value)`` :rtype: LowLevelILExpr """ - return self.expr(core.BNLowLevelILOperation.LLIL_NEG, value.index, size=size, flags=flags) + return self.expr(LowLevelILOperation.LLIL_NEG, value.index, size=size, flags=flags) def not_expr(self, size, value, flags=None): """ @@ -872,7 +873,7 @@ class LowLevelILFunction(object): :return: The expression ``not.{}(value)`` :rtype: LowLevelILExpr """ - return self.expr(core.BNLowLevelILOperation.LLIL_NOT, value.index, size=size, flags=flags) + return self.expr(LowLevelILOperation.LLIL_NOT, value.index, size=size, flags=flags) def sign_extend(self, size, value, flags=None): """ @@ -884,7 +885,7 @@ class LowLevelILFunction(object): :return: The expression ``sx.(value)`` :rtype: LowLevelILExpr """ - return self.expr(core.BNLowLevelILOperation.LLIL_SX, value.index, size=size, flags=flags) + return self.expr(LowLevelILOperation.LLIL_SX, value.index, size=size, flags=flags) def zero_extend(self, size, value): """ @@ -895,7 +896,7 @@ class LowLevelILFunction(object): :return: The expression ``sx.(value)`` :rtype: LowLevelILExpr """ - return self.expr(core.BNLowLevelILOperation.LLIL_ZX, value.index, size=size) + return self.expr(LowLevelILOperation.LLIL_ZX, value.index, size=size) def jump(self, dest): """ @@ -905,7 +906,7 @@ class LowLevelILFunction(object): :return: The expression ``jump(dest)`` :rtype: LowLevelILExpr """ - return self.expr(core.BNLowLevelILOperation.LLIL_JUMP, dest.index) + return self.expr(LowLevelILOperation.LLIL_JUMP, dest.index) def call(self, dest): """ @@ -916,7 +917,7 @@ class LowLevelILFunction(object): :return: The expression ``call(dest)`` :rtype: LowLevelILExpr """ - return self.expr(core.BNLowLevelILOperation.LLIL_CALL, dest.index) + return self.expr(LowLevelILOperation.LLIL_CALL, dest.index) def ret(self, dest): """ @@ -927,7 +928,7 @@ class LowLevelILFunction(object): :return: The expression ``jump(dest)`` :rtype: LowLevelILExpr """ - return self.expr(core.BNLowLevelILOperation.LLIL_RET, dest.index) + return self.expr(LowLevelILOperation.LLIL_RET, dest.index) def no_ret(self): """ @@ -936,7 +937,7 @@ class LowLevelILFunction(object): :return: The expression ``noreturn`` :rtype: LowLevelILExpr """ - return self.expr(core.BNLowLevelILOperation.LLIL_NORET) + return self.expr(LowLevelILOperation.LLIL_NORET) def flag_condition(self, cond): """ @@ -947,10 +948,10 @@ class LowLevelILFunction(object): :rtype: LowLevelILExpr """ if isinstance(cond, str): - cond = core.BNLowLevelILFlagCondition[cond] - elif isinstance(cond, core.BNLowLevelILFlagCondition): + cond = LowLevelILFlagCondition[cond] + elif isinstance(cond, LowLevelILFlagCondition): cond = cond.value - return self.expr(core.BNLowLevelILOperation.LLIL_FLAG_COND, cond) + return self.expr(LowLevelILOperation.LLIL_FLAG_COND, cond) def compare_equal(self, size, a, b): """ @@ -963,7 +964,7 @@ class LowLevelILFunction(object): :return: a comparison expression. :rtype: LowLevelILExpr """ - return self.expr(core.BNLowLevelILOperation.LLIL_CMP_E, a.index, b.index, size = size) + return self.expr(LowLevelILOperation.LLIL_CMP_E, a.index, b.index, size = size) def compare_not_equal(self, size, a, b): """ @@ -976,7 +977,7 @@ class LowLevelILFunction(object): :return: a comparison expression. :rtype: LowLevelILExpr """ - return self.expr(core.BNLowLevelILOperation.LLIL_CMP_NE, a.index, b.index, size = size) + return self.expr(LowLevelILOperation.LLIL_CMP_NE, a.index, b.index, size = size) def compare_signed_less_than(self, size, a, b): """ @@ -989,7 +990,7 @@ class LowLevelILFunction(object): :return: a comparison expression. :rtype: LowLevelILExpr """ - return self.expr(core.BNLowLevelILOperation.LLIL_CMP_SLT, a.index, b.index, size = size) + return self.expr(LowLevelILOperation.LLIL_CMP_SLT, a.index, b.index, size = size) def compare_unsigned_less_than(self, size, a, b): """ @@ -1002,7 +1003,7 @@ class LowLevelILFunction(object): :return: a comparison expression. :rtype: LowLevelILExpr """ - return self.expr(core.BNLowLevelILOperation.LLIL_CMP_ULT, a.index, b.index, size = size) + return self.expr(LowLevelILOperation.LLIL_CMP_ULT, a.index, b.index, size = size) def compare_signed_less_equal(self, size, a, b): """ @@ -1015,7 +1016,7 @@ class LowLevelILFunction(object): :return: a comparison expression. :rtype: LowLevelILExpr """ - return self.expr(core.BNLowLevelILOperation.LLIL_CMP_SLE, a.index, b.index, size = size) + return self.expr(LowLevelILOperation.LLIL_CMP_SLE, a.index, b.index, size = size) def compare_unsigned_less_equal(self, size, a, b): """ @@ -1028,7 +1029,7 @@ class LowLevelILFunction(object): :return: a comparison expression. :rtype: LowLevelILExpr """ - return self.expr(core.BNLowLevelILOperation.LLIL_CMP_ULE, a.index, b.index, size = size) + return self.expr(LowLevelILOperation.LLIL_CMP_ULE, a.index, b.index, size = size) def compare_signed_greater_equal(self, size, a, b): """ @@ -1041,7 +1042,7 @@ class LowLevelILFunction(object): :return: a comparison expression. :rtype: LowLevelILExpr """ - return self.expr(core.BNLowLevelILOperation.LLIL_CMP_SGE, a.index, b.index, size = size) + return self.expr(LowLevelILOperation.LLIL_CMP_SGE, a.index, b.index, size = size) def compare_unsigned_greater_equal(self, size, a, b): """ @@ -1054,7 +1055,7 @@ class LowLevelILFunction(object): :return: a comparison expression. :rtype: LowLevelILExpr """ - return self.expr(core.BNLowLevelILOperation.LLIL_CMP_UGE, a.index, b.index, size = size) + return self.expr(LowLevelILOperation.LLIL_CMP_UGE, a.index, b.index, size = size) def compare_signed_greater_than(self, size, a, b): """ @@ -1067,7 +1068,7 @@ class LowLevelILFunction(object): :return: a comparison expression. :rtype: LowLevelILExpr """ - return self.expr(core.BNLowLevelILOperation.LLIL_CMP_SGT, a.index, b.index, size = size) + return self.expr(LowLevelILOperation.LLIL_CMP_SGT, a.index, b.index, size = size) def compare_unsigned_greater_than(self, size, a, b): """ @@ -1080,10 +1081,10 @@ class LowLevelILFunction(object): :return: a comparison expression. :rtype: LowLevelILExpr """ - return self.expr(core.BNLowLevelILOperation.LLIL_CMP_UGT, a.index, b.index, size = size) + return self.expr(LowLevelILOperation.LLIL_CMP_UGT, a.index, b.index, size = size) def test_bit(self, size, a, b): - return self.expr(core.BNLowLevelILOperation.LLIL_TEST_BIT, a.index, b.index, size = size) + return self.expr(LowLevelILOperation.LLIL_TEST_BIT, a.index, b.index, size = size) def system_call(self): """ @@ -1092,7 +1093,7 @@ class LowLevelILFunction(object): :return: a system call expression. :rtype: LowLevelILExpr """ - return self.expr(core.BNLowLevelILOperation.LLIL_SYSCALL) + return self.expr(LowLevelILOperation.LLIL_SYSCALL) def breakpoint(self): """ @@ -1101,7 +1102,7 @@ class LowLevelILFunction(object): :return: a breakpoint expression. :rtype: LowLevelILExpr """ - return self.expr(core.BNLowLevelILOperation.LLIL_BP) + return self.expr(LowLevelILOperation.LLIL_BP) def trap(self, value): """ @@ -1111,7 +1112,7 @@ class LowLevelILFunction(object): :return: a trap expression. :rtype: LowLevelILExpr """ - return self.expr(core.BNLowLevelILOperation.LLIL_TRAP, value) + return self.expr(LowLevelILOperation.LLIL_TRAP, value) def undefined(self): """ @@ -1121,7 +1122,7 @@ class LowLevelILFunction(object): :return: the unimplemented expression. :rtype: LowLevelILExpr """ - return self.expr(core.BNLowLevelILOperation.LLIL_UNDEF) + return self.expr(LowLevelILOperation.LLIL_UNDEF) def unimplemented(self): """ @@ -1131,7 +1132,7 @@ class LowLevelILFunction(object): :return: the unimplemented expression. :rtype: LowLevelILExpr """ - return self.expr(core.BNLowLevelILOperation.LLIL_UNIMPL) + return self.expr(LowLevelILOperation.LLIL_UNIMPL) def unimplemented_memory_ref(self, size, addr): """ @@ -1142,7 +1143,7 @@ class LowLevelILFunction(object): :return: the unimplemented memory reference expression. :rtype: LowLevelILExpr """ - return self.expr(core.BNLowLevelILOperation.LLIL_UNIMPL_MEM, addr.index, size = size) + return self.expr(LowLevelILOperation.LLIL_UNIMPL_MEM, addr.index, size = size) def goto(self, label): """ diff --git a/python/platform.py b/python/platform.py index 6c3eefea..04dce587 100644 --- a/python/platform.py +++ b/python/platform.py @@ -20,10 +20,12 @@ import ctypes -#Binary Ninja components +# Binary Ninja components import _binaryninjacore as core import startup import architecture +import callingconvention + class _PlatformMetaClass(type): @property @@ -60,15 +62,15 @@ class _PlatformMetaClass(type): def __setattr__(self, name, value): try: - type.__setattr__(self,name,value) + type.__setattr__(self, name, value) except AttributeError: - raise AttributeError, "attribute '%s' is read only" % name + raise AttributeError("attribute '%s' is read only" % name) def __getitem__(cls, value): startup._init_plugins() platform = core.BNGetPlatformByName(str(value)) if platform is None: - raise KeyError, "'%s' is not a valid platform" % str(value) + raise KeyError("'%s' is not a valid platform" % str(value)) return Platform(None, platform) def get_list(cls, os = None, arch = None): @@ -86,6 +88,7 @@ class _PlatformMetaClass(type): core.BNFreePlatformList(platforms, count.value) return result + class Platform(object): """ ``class Platform`` contains all information releated to the execution environment of the binary, mainly the @@ -118,7 +121,7 @@ class Platform(object): result = core.BNGetPlatformDefaultCallingConvention(self.handle) if result is None: return None - return CallingConvention(None, result) + return callingconvention.CallingConvention(None, result) @default_calling_convention.setter def default_calling_convention(self, value): @@ -136,7 +139,7 @@ class Platform(object): result = core.BNGetPlatformCdeclCallingConvention(self.handle) if result is None: return None - return CallingConvention(None, result) + return callingconvention.CallingConvention(None, result) @cdecl_calling_convention.setter def cdecl_calling_convention(self, value): @@ -154,7 +157,7 @@ class Platform(object): result = core.BNGetPlatformStdcallCallingConvention(self.handle) if result is None: return None - return CallingConvention(None, result) + return callingconvention.CallingConvention(None, result) @stdcall_calling_convention.setter def stdcall_calling_convention(self, value): @@ -172,7 +175,7 @@ class Platform(object): result = core.BNGetPlatformFastcallCallingConvention(self.handle) if result is None: return None - return CallingConvention(None, result) + return callingconvention.CallingConvention(None, result) @fastcall_calling_convention.setter def fastcall_calling_convention(self, value): @@ -190,7 +193,7 @@ class Platform(object): result = core.BNGetPlatformSystemCallConvention(self.handle) if result is None: return None - return CallingConvention(None, result) + return callingconvention.CallingConvention(None, result) @system_call_convention.setter def system_call_convention(self, value): @@ -208,15 +211,15 @@ class Platform(object): cc = core.BNGetPlatformCallingConventions(self.handle, count) result = [] for i in xrange(0, count.value): - result.append(CallingConvention(None, core.BNNewCallingConventionReference(cc[i]))) + result.append(callingconvention.CallingConvention(None, core.BNNewCallingConventionReference(cc[i]))) core.BNFreeCallingConventionList(cc, count.value) return result def __setattr__(self, name, value): try: - object.__setattr__(self,name,value) + object.__setattr__(self, name, value) except AttributeError: - raise AttributeError, "attribute '%s' is read only" % name + raise AttributeError("attribute '%s' is read only" % name) def __repr__(self): return "" % self.name @@ -250,3 +253,9 @@ class Platform(object): def add_related_platform(self, arch, platform): core.BNAddRelatedPlatform(self.handle, arch.handle, platform.handle) + + def get_associated_platform_by_address(self, addr): + new_addr = ctypes.c_ulonglong() + new_addr.value = addr + result = core.BNGetAssociatedPlatformByAddress(self.handle, new_addr) + return Platform(None, handle = result), new_addr.value diff --git a/python/plugin.py b/python/plugin.py index b6faef7f..9a4da487 100644 --- a/python/plugin.py +++ b/python/plugin.py @@ -24,6 +24,7 @@ import threading # Binary Ninja components import _binaryninjacore as core +from enums import LowLevelILOperation import startup import filemetadata import binaryview @@ -77,7 +78,7 @@ class PluginCommand(object): ctypes.memmove(ctypes.byref(self.command), ctypes.byref(cmd), ctypes.sizeof(core.BNPluginCommand)) self.name = str(cmd.name) self.description = str(cmd.description) - self.type = core.BNPluginCommandType(cmd.type) + self.type = LowLevelILOperation(cmd.type) @classmethod def _default_action(cls, view, action): @@ -209,21 +210,21 @@ class PluginCommand(object): def is_valid(self, context): if context.view is None: return False - if self.command.type == core.BNPluginCommandType.DefaultPluginCommand: + if self.command.type == LowLevelILOperation.DefaultPluginCommand: if not self.command.defaultIsValid: return True return self.command.defaultIsValid(self.command.context, context.view.handle) - elif self.command.type == core.BNPluginCommandType.AddressPluginCommand: + elif self.command.type == LowLevelILOperation.AddressPluginCommand: if not self.command.addressIsValid: return True return self.command.addressIsValid(self.command.context, context.view.handle, context.address) - elif self.command.type == core.BNPluginCommandType.RangePluginCommand: + elif self.command.type == LowLevelILOperation.RangePluginCommand: if context.length == 0: return False if not self.command.rangeIsValid: return True return self.command.rangeIsValid(self.command.context, context.view.handle, context.address, context.length) - elif self.command.type == core.BNPluginCommandType.FunctionPluginCommand: + elif self.command.type == LowLevelILOperation.FunctionPluginCommand: if context.function is None: return False if not self.command.functionIsValid: @@ -234,13 +235,13 @@ class PluginCommand(object): def execute(self, context): if not self.is_valid(context): return - if self.command.type == core.BNPluginCommandType.DefaultPluginCommand: + if self.command.type == LowLevelILOperation.DefaultPluginCommand: self.command.defaultCommand(self.command.context, context.view.handle) - elif self.command.type == core.BNPluginCommandType.AddressPluginCommand: + elif self.command.type == LowLevelILOperation.AddressPluginCommand: self.command.addressCommand(self.command.context, context.view.handle, context.address) - elif self.command.type == core.BNPluginCommandType.RangePluginCommand: + elif self.command.type == LowLevelILOperation.RangePluginCommand: self.command.rangeCommand(self.command.context, context.view.handle, context.address, context.length) - elif self.command.type == core.BNPluginCommandType.FunctionPluginCommand: + elif self.command.type == LowLevelILOperation.FunctionPluginCommand: self.command.functionCommand(self.command.context, context.view.handle, context.function.handle) def __repr__(self): diff --git a/python/scriptingprovider.py b/python/scriptingprovider.py index 079b47cd..71402b1b 100644 --- a/python/scriptingprovider.py +++ b/python/scriptingprovider.py @@ -28,6 +28,7 @@ import sys # Binary Ninja Components import _binaryninjacore as core +from enums import ScriptingProviderExecuteResult, ScriptingProviderInputReadyState import binaryview import function import basicblock @@ -131,7 +132,7 @@ class ScriptingInstance(object): return self.perform_execute_script_input(text) except: log.log_error(traceback.format_exc()) - return core.BNScriptingProviderExecuteResult.InvalidScriptInput + return ScriptingProviderExecuteResult.InvalidScriptInput def _set_current_binary_view(self, ctxt, view): try: @@ -186,7 +187,7 @@ class ScriptingInstance(object): @abc.abstractmethod def perform_execute_script_input(self, text): - return core.BNScriptingProviderExecuteResult.InvalidScriptInput + return ScriptingProviderExecuteResult.InvalidScriptInput @abc.abstractmethod def perform_set_current_binary_view(self, view): @@ -506,7 +507,7 @@ class PythonScriptingInstance(ScriptingInstance): result = self.input self.input = "" return result - self.instance.input_ready_state = core.BNScriptingProviderInputReadyState.ReadyForScriptProgramInput + self.instance.input_ready_state = ScriptingProviderInputReadyState.ReadyForScriptProgramInput self.event.wait() self.event.clear() return "" @@ -518,7 +519,7 @@ class PythonScriptingInstance(ScriptingInstance): if self.exit: break if self.code is not None: - self.instance.input_ready_state = core.BNScriptingProviderInputReadyState.NotReadyForInput + self.instance.input_ready_state = ScriptingProviderInputReadyState.NotReadyForInput code = self.code self.code = None @@ -551,7 +552,7 @@ class PythonScriptingInstance(ScriptingInstance): traceback.print_exc() finally: PythonScriptingInstance._interpreter.value = None - self.instance.input_ready_state = core.BNScriptingProviderInputReadyState.ReadyForScriptExecution + self.instance.input_ready_state = ScriptingProviderInputReadyState.ReadyForScriptExecution def get_selected_data(self): if self.active_view is None: @@ -575,7 +576,7 @@ class PythonScriptingInstance(ScriptingInstance): self.interpreter = PythonScriptingInstance.InterpreterThread(self) self.interpreter.start() self.queued_input = "" - self.input_ready_state = core.BNScriptingProviderInputReadyState.ReadyForScriptExecution + self.input_ready_state = ScriptingProviderInputReadyState.ReadyForScriptExecution @abc.abstractmethod def perform_destroy_instance(self): @@ -583,15 +584,15 @@ class PythonScriptingInstance(ScriptingInstance): @abc.abstractmethod def perform_execute_script_input(self, text): - if self.input_ready_state == core.BNScriptingProviderInputReadyState.NotReadyForInput: - return core.BNScriptingProviderExecuteResult.InvalidScriptInput + if self.input_ready_state == ScriptingProviderInputReadyState.NotReadyForInput: + return ScriptingProviderExecuteResult.InvalidScriptInput - if self.input_ready_state == core.BNScriptingProviderInputReadyState.ReadyForScriptProgramInput: + if self.input_ready_state == ScriptingProviderInputReadyState.ReadyForScriptProgramInput: if len(text) == 0: - return core.BNScriptingProviderExecuteResult.SuccessfulScriptExecution - self.input_ready_state = core.BNScriptingProviderInputReadyState.NotReadyForInput + return ScriptingProviderExecuteResult.SuccessfulScriptExecution + self.input_ready_state = ScriptingProviderInputReadyState.NotReadyForInput self.interpreter.add_input(text) - return core.BNScriptingProviderExecuteResult.SuccessfulScriptExecution + return ScriptingProviderExecuteResult.SuccessfulScriptExecution try: result = code.compile_command(text) @@ -600,11 +601,11 @@ class PythonScriptingInstance(ScriptingInstance): if result is None: # Command is not complete, ask for more input - return core.BNScriptingProviderExecuteResult.IncompleteScriptInput + return ScriptingProviderExecuteResult.IncompleteScriptInput - self.input_ready_state = core.BNScriptingProviderInputReadyState.NotReadyForInput + self.input_ready_state = ScriptingProviderInputReadyState.NotReadyForInput self.interpreter.execute(text) - return core.BNScriptingProviderExecuteResult.SuccessfulScriptExecution + return ScriptingProviderExecuteResult.SuccessfulScriptExecution @abc.abstractmethod def perform_set_current_binary_view(self, view): @@ -635,6 +636,10 @@ class PythonScriptingProvider(ScriptingProvider): PythonScriptingProvider().register() # Wrap stdin/stdout/stderr for Python scripting provider implementation +original_stdin = sys.stdin +original_stdout = sys.stdout +original_stderr = sys.stderr + sys.stdin = _PythonScriptingInstanceInput(sys.stdin) sys.stdout = _PythonScriptingInstanceOutput(sys.stdout, False) sys.stderr = _PythonScriptingInstanceOutput(sys.stderr, True) diff --git a/python/startup.py b/python/startup.py index c9d6792e..809f185b 100644 --- a/python/startup.py +++ b/python/startup.py @@ -32,7 +32,3 @@ def _init_plugins(): core.BNInitUserPlugins() if not core.BNIsLicenseValidated(): raise RuntimeError("License is not valid. Please supply a valid license.") - - -def shutdown(): - core.BNShutdown() diff --git a/python/transform.py b/python/transform.py index 0bbffc8f..0c003738 100644 --- a/python/transform.py +++ b/python/transform.py @@ -24,6 +24,7 @@ import abc # Binary Ninja components import _binaryninjacore as core +from enums import TransformType import startup import log import databuffer @@ -109,14 +110,14 @@ class Transform(object): self._pending_param_lists = {} self.type = self.__class__.transform_type if not isinstance(self.type, str): - self.type = core.BNTransformType(self.type) + self.type = TransformType(self.type) self.name = self.__class__.name self.long_name = self.__class__.long_name self.group = self.__class__.group self.parameters = self.__class__.parameters else: self.handle = handle - self.type = core.BNTransformType(core.BNGetTransformType(self.handle)) + self.type = TransformType(core.BNGetTransformType(self.handle)) self.name = core.BNGetTransformName(self.handle) self.long_name = core.BNGetTransformLongName(self.handle) self.group = core.BNGetTransformGroup(self.handle) @@ -191,7 +192,7 @@ class Transform(object): @abc.abstractmethod def perform_decode(self, data, params): - if self.type == core.BNTransformType.InvertingTransform: + if self.type == TransformType.InvertingTransform: return self.perform_encode(data, params) return None diff --git a/python/types.py b/python/types.py new file mode 100644 index 00000000..8582e4e0 --- /dev/null +++ b/python/types.py @@ -0,0 +1,506 @@ +# Copyright (c) 2015-2016 Vector 35 LLC +# +# 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 +# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +# sell copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +# IN THE SOFTWARE. + +import ctypes + +# Binary Ninja components +import _binaryninjacore as core +from enums import SymbolType, TypeClass +import callingconvention +import demangle + + +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) + else: + if isinstance(sym_type, str): + sym_type = SymbolType[sym_type] + if full_name is None: + full_name = short_name + if raw_name is None: + raw_name = full_name + self.handle = core.BNCreateSymbol(sym_type, short_name, full_name, raw_name, addr) + + def __del__(self): + core.BNFreeSymbol(self.handle) + + @property + def type(self): + """Symbol type (read-only)""" + return SymbolType(core.BNGetSymbolType(self.handle)) + + @property + def name(self): + """Symbol name (read-only)""" + return core.BNGetSymbolRawName(self.handle) + + @property + def short_name(self): + """Symbol short name (read-only)""" + return core.BNGetSymbolShortName(self.handle) + + @property + def full_name(self): + """Symbol full name (read-only)""" + return core.BNGetSymbolFullName(self.handle) + + @property + def raw_name(self): + """Symbol raw name (read-only)""" + return core.BNGetSymbolRawName(self.handle) + + @property + def address(self): + """Symbol address (read-only)""" + return core.BNGetSymbolAddress(self.handle) + + @property + def auto(self): + return core.BNIsSymbolAutoDefined(self.handle) + + @auto.setter + def auto(self, value): + core.BNSetSymbolAutoDefined(self.handle, value) + + def __repr__(self): + return "<%s: \"%s\" @ %#x>" % (self.type, self.full_name, self.address) + + def __setattr__(self, name, value): + try: + object.__setattr__(self, name, value) + except AttributeError: + raise AttributeError("attribute '%s' is read only" % name) + + +class Type(object): + def __init__(self, handle): + self.handle = handle + + def __del__(self): + core.BNFreeType(self.handle) + + @property + def type_class(self): + """Type class (read-only)""" + return TypeClass(core.BNGetTypeClass(self.handle)) + + @property + def width(self): + """Type width (read-only)""" + return core.BNGetTypeWidth(self.handle) + + @property + def alignment(self): + """Type alignment (read-only)""" + return core.BNGetTypeAlignment(self.handle) + + @property + def signed(self): + """Wether type is signed (read-only)""" + return core.BNIsTypeSigned(self.handle) + + @property + def const(self): + """Whether type is const (read-only)""" + return core.BNIsTypeConst(self.handle) + + @property + def modified(self): + """Whether type is modified (read-only)""" + return core.BNIsTypeFloatingPoint(self.handle) + + @property + def target(self): + """Target (read-only)""" + result = core.BNGetChildType(self.handle) + if result is None: + return None + return Type(result) + + @property + def element_type(self): + """Target (read-only)""" + result = core.BNGetChildType(self.handle) + if result is None: + return None + return Type(result) + + @property + def return_value(self): + """Return value (read-only)""" + result = core.BNGetChildType(self.handle) + if result is None: + return None + return Type(result) + + @property + def calling_convention(self): + """Calling convention (read-only)""" + result = core.BNGetTypeCallingConvention(self.handle) + if result is None: + return None + return callingconvention.CallingConvention(None, result) + + @property + def parameters(self): + """Type parameters list (read-only)""" + count = ctypes.c_ulonglong() + params = core.BNGetTypeParameters(self.handle, count) + result = [] + for i in xrange(0, count.value): + result.append((Type(core.BNNewTypeReference(params[i].type)), params[i].name)) + core.BNFreeTypeParameterList(params, count.value) + return result + + @property + def has_variable_arguments(self): + """Whether type has variable arguments (read-only)""" + return core.BNTypeHasVariableArguments(self.handle) + + @property + def can_return(self): + """Whether type can return (read-only)""" + return core.BNFunctionTypeCanReturn(self.handle) + + @property + def structure(self): + """Structure of the type (read-only)""" + result = core.BNGetTypeStructure(self.handle) + if result is None: + return None + return Structure(result) + + @property + def enumeration(self): + """Type enumeration (read-only)""" + result = core.BNGetTypeEnumeration(self.handle) + if result is None: + return None + return Enumeration(result) + + @property + def count(self): + """Type count (read-only)""" + return core.BNGetTypeElementCount(self.handle) + + def __str__(self): + return core.BNGetTypeString(self.handle) + + def __repr__(self): + return "" % str(self) + + def get_string_before_name(self): + return core.BNGetTypeStringBeforeName(self.handle) + + def get_string_after_name(self): + return core.BNGetTypeStringAfterName(self.handle) + + @classmethod + def void(cls): + return Type(core.BNCreateVoidType()) + + @classmethod + def bool(self): + return Type(core.BNCreateBoolType()) + + @classmethod + def int(self, width, sign = True, altname=""): + return Type(core.BNCreateIntegerType(width, sign, altname)) + + @classmethod + def float(self, width): + return Type(core.BNCreateFloatType(width)) + + @classmethod + def structure_type(self, structure_type): + return Type(core.BNCreateStructureType(structure_type.handle)) + + @classmethod + def unknown_type(self, unknown_type): + return Type(core.BNCreateUnknownType(unknown_type.handle)) + + @classmethod + def enumeration_type(self, arch, e, width=None): + if width is None: + width = arch.default_int_size + return Type(core.BNCreateEnumerationType(e.handle, width)) + + @classmethod + def pointer(self, arch, t, const=False): + return Type(core.BNCreatePointerType(arch.handle, t.handle, const)) + + @classmethod + def array(self, t, count): + return Type(core.BNCreateArrayType(t.handle, count)) + + @classmethod + def function(self, ret, params, calling_convention=None, variable_arguments=False): + param_buf = (core.BNNameAndType * len(params))() + for i in xrange(0, len(params)): + if isinstance(params[i], Type): + param_buf[i].name = "" + param_buf[i].type = params[i].handle + else: + param_buf[i].name = params[i][1] + param_buf[i].type = params[i][0] + if calling_convention is not None: + calling_convention = calling_convention.handle + return Type(core.BNCreateFunctionType(ret.handle, calling_convention, param_buf, len(params), + variable_arguments)) + + def __setattr__(self, name, value): + try: + object.__setattr__(self, name, value) + except AttributeError: + raise AttributeError("attribute '%s' is read only" % name) + + +class UnknownType(object): + def __init__(self, handle=None): + if handle is None: + self.handle = core.BNCreateUnknownType() + else: + self.handle = handle + + def __del__(self): + core.BNFreeUnknownType(self.handle) + + @property + def name(self): + count = ctypes.c_ulonglong() + nameList = core.BNGetUnknownTypeName(self.handle, count) + result = [] + for i in xrange(count.value): + result.append(nameList[i]) + return demangle.get_qualified_name(result) + + @name.setter + def name(self, value): + core.BNSetUnknownTypeName(self.handle, value) + + +class StructureMember(object): + def __init__(self, t, name, offset): + self.type = t + self.name = name + self.offset = offset + + def __repr__(self): + if len(self.name) == 0: + return "" % (str(self.type), self.offset) + return "<%s %s%s, offset %#x>" % (self.type.get_string_before_name(), self.name, + self.type.get_string_after_name(), self.offset) + + +class Structure(object): + def __init__(self, handle=None): + if handle is None: + self.handle = core.BNCreateStructure() + else: + self.handle = handle + + def __del__(self): + core.BNFreeStructure(self.handle) + + @property + def name(self): + count = ctypes.c_ulonglong() + nameList = core.BNGetStructureName(self.handle, count) + result = [] + for i in xrange(count.value): + result.append(nameList[i]) + return demangle.get_qualified_name(result) + + @name.setter + def name(self, value): + core.BNSetStructureName(self.handle, value) + + @property + def members(self): + """Structure member list (read-only)""" + count = ctypes.c_ulonglong() + members = core.BNGetStructureMembers(self.handle, count) + result = [] + for i in xrange(0, count.value): + result.append(StructureMember(Type(core.BNNewTypeReference(members[i].type)), + members[i].name, members[i].offset)) + core.BNFreeStructureMemberList(members, count.value) + return result + + @property + def width(self): + """Structure width (read-only)""" + return core.BNGetStructureWidth(self.handle) + + @property + def alignment(self): + """Structure alignment (read-only)""" + return core.BNGetStructureAlignment(self.handle) + + @property + def packed(self): + return core.BNIsStructurePacked(self.handle) + + @packed.setter + def packed(self, value): + core.BNSetStructurePacked(self.handle, value) + + @property + def union(self): + return core.BNIsStructureUnion(self.handle) + + @union.setter + def union(self, value): + core.BNSetStructureUnion(self.handle, value) + + def __setattr__(self, name, value): + try: + object.__setattr__(self, name, value) + except AttributeError: + raise AttributeError("attribute '%s' is read only" % name) + + def __repr__(self): + if len(self.name) > 0: + return "" % self.name + return "" % self.width + + def append(self, t, name = ""): + core.BNAddStructureMember(self.handle, t.handle, name) + + def insert(self, offset, t, name = ""): + core.BNAddStructureMemberAtOffset(self.handle, t.handle, name, offset) + + def remove(self, i): + core.BNRemoveStructureMember(self.handle, i) + + +class EnumerationMember(object): + def __init__(self, name, value, default): + self.name = name + self.value = value + self.default = default + + def __repr__(self): + return "<%s = %#x>" % (self.name, self.value) + + +class Enumeration(object): + def __init__(self, handle=None): + if handle is None: + self.handle = core.BNCreateEnumeration() + else: + self.handle = handle + + def __del__(self): + core.BNFreeEnumeration(self.handle) + + @property + def name(self): + return core.BNGetEnumerationName(self.handle) + + @name.setter + def name(self, value): + core.BNSetEnumerationName(self.handle, value) + + @property + def members(self): + """Enumeration member list (read-only)""" + count = ctypes.c_ulonglong() + members = core.BNGetEnumerationMembers(self.handle, count) + result = [] + for i in xrange(0, count.value): + result.append(EnumerationMember(members[i].name, members[i].value, members[i].isDefault)) + core.BNFreeEnumerationMemberList(members, count.value) + return result + + def __setattr__(self, name, value): + try: + object.__setattr__(self, name, value) + except AttributeError: + raise AttributeError("attribute '%s' is read only" % name) + + def __repr__(self): + if len(self.name) > 0: + return "" % self.name + return "" % repr(self.members) + + def append(self, name, value = None): + if value is None: + core.BNAddEnumerationMember(self.handle, name) + else: + core.BNAddEnumerationMemberWithValue(self.handle, name, value) + + +class TypeParserResult(object): + def __init__(self, types, variables, functions): + self.types = types + self.variables = variables + self.functions = functions + + def __repr__(self): + return "{types: %s, variables: %s, functions: %s}" % (self.types, self.variables, self.functions) + + +def preprocess_source(source, filename=None, include_dirs=[]): + """ + ``preprocess_source`` run the C preprocessor on the given source or source filename. + + :param str source: source to preprocess + :param str filename: optional filename to preprocess + :param list(str) include_dirs: list of string directorires to use as include directories. + :return: returns a tuple of (preprocessed_source, error_string) + :rtype: tuple(str,str) + :Example: + + >>> source = "#define TEN 10\\nint x[TEN];\\n" + >>> preprocess_source(source) + ('#line 1 "input"\\n\\n#line 2 "input"\\n int x [ 10 ] ;\\n', '') + >>> + """ + if filename is None: + filename = "input" + dir_buf = (ctypes.c_char_p * len(include_dirs))() + for i in xrange(0, len(include_dirs)): + dir_buf[i] = str(include_dirs[i]) + output = ctypes.c_char_p() + errors = ctypes.c_char_p() + result = core.BNPreprocessSource(source, filename, output, errors, dir_buf, len(include_dirs)) + output_str = output.value + error_str = errors.value + core.BNFreeString(ctypes.cast(output, ctypes.POINTER(ctypes.c_byte))) + core.BNFreeString(ctypes.cast(errors, ctypes.POINTER(ctypes.c_byte))) + if result: + return (output_str, error_str) + return (None, error_str) diff --git a/python/undoaction.py b/python/undoaction.py index 850d37fd..9f742e00 100644 --- a/python/undoaction.py +++ b/python/undoaction.py @@ -24,6 +24,7 @@ import ctypes # Binary Ninja components import _binaryninjacore as core +from enums import ActionType import startup import log @@ -40,7 +41,7 @@ class UndoAction(object): raise TypeError("undo action type not registered") action_type = self.__class__.action_type if isinstance(action_type, str): - self._cb.type = core.BNActionType[action_type] + self._cb.type = ActionType[action_type] else: self._cb.type = action_type self._cb.context = 0 diff --git a/python/update.py b/python/update.py index 38d68683..7e2bd4ef 100644 --- a/python/update.py +++ b/python/update.py @@ -23,6 +23,7 @@ import ctypes # Binary Ninja components import _binaryninjacore as core +from enums import UpdateResult import startup import log @@ -180,7 +181,7 @@ class UpdateChannel(object): error_str = errors.value core.BNFreeString(ctypes.cast(errors, ctypes.POINTER(ctypes.c_byte))) raise IOError(error_str) - return core.BNUpdateResult(result) + return UpdateResult(result) class UpdateVersion(object): @@ -204,7 +205,7 @@ class UpdateVersion(object): error_str = errors.value core.BNFreeString(ctypes.cast(errors, ctypes.POINTER(ctypes.c_byte))) raise IOError(error_str) - return core.BNUpdateResult(result) + return UpdateResult(result) def are_auto_updates_enabled(): -- cgit v1.3.1 From 9d1cac8ee55553cdb20c36deb3b15c9219b02d9b Mon Sep 17 00:00:00 2001 From: Peter LaFosse Date: Sat, 7 Jan 2017 16:08:08 -0500 Subject: More fixes for refactor --- python/architecture.py | 2 +- python/binaryview.py | 24 +++++++++++++++--------- python/examples/angr_plugin.py | 4 ++-- python/examples/breakpoint.py | 4 ++-- python/examples/export_svg.py | 12 ++++++------ python/examples/instruction_iterator.py | 33 +++++++++++---------------------- python/examples/jump_table.py | 4 ++-- python/examples/nes.py | 13 +++++++------ python/examples/nsf.py | 5 +++-- 9 files changed, 49 insertions(+), 52 deletions(-) (limited to 'python/binaryview.py') diff --git a/python/architecture.py b/python/architecture.py index 5d42ec35..c95c71a0 100644 --- a/python/architecture.py +++ b/python/architecture.py @@ -1143,7 +1143,7 @@ class Architecture(object): return None, 0 result = [] for i in xrange(0, count.value): - token_type = InstructionTextTokenType(tokens[i].type).name + token_type = InstructionTextTokenType(tokens[i].type) text = tokens[i].text value = tokens[i].value size = tokens[i].size diff --git a/python/binaryview.py b/python/binaryview.py index 41702dc8..b19ecbd6 100644 --- a/python/binaryview.py +++ b/python/binaryview.py @@ -1099,7 +1099,7 @@ class BinaryView(object): """ if arch is None: arch = self.arch - txt, size = arch.get_instruction_text(self.read(addr, self.arch.max_instr_length), addr) + txt, size = arch.get_instruction_text(self.read(addr, arch.max_instr_length), addr) self.next_address = addr + size if txt is None: return None @@ -1129,7 +1129,7 @@ class BinaryView(object): arch = self.arch if self.next_address is None: self.next_address = self.entry_point - txt, size = arch.get_instruction_text(self.read(self.next_address, self.arch.max_instr_length), self.next_address) + txt, size = arch.get_instruction_text(self.read(self.next_address, arch.max_instr_length), self.next_address) self.next_address += size if txt is None: return None @@ -1658,6 +1658,8 @@ class BinaryView(object): [] """ + if self.platform is None: + raise Exception("Default platform not set in BinaryView") if plat is None: plat = self.platform core.BNAddFunctionForAnalysis(self.handle, plat.handle, addr) @@ -1673,6 +1675,8 @@ class BinaryView(object): >>> bv.add_entry_point(0xdeadbeef) >>> """ + if self.platform is None: + raise Exception("Default platform not set in BinaryView") if plat is None: plat = self.platform core.BNAddEntryPointForAnalysis(self.handle, plat.handle, addr) @@ -2096,20 +2100,22 @@ class BinaryView(object): """ core.BNDefineAutoSymbol(self.handle, sym.handle) - def define_auto_symbol_and_var_or_function(self, sym, sym_type, platform = None): + def define_auto_symbol_and_var_or_function(self, sym, sym_type, plat=None): """ - ``define_auto_symbol`` adds a symbol to the internal list of automatically discovered Symbol objects. + ``define_auto_symbol_and_var_or_function`` :param Symbol sym: the symbol to define + :param SymbolType sym_type: Type of symbol being defined + :param Platform plat: (optional) platform :rtype: None """ - if platform is None: - platform = self.platform - if platform is not None: - platform = platform.handle + if plat is None: + plat = self.plat + if plat is not None: + plat = plat.handle if sym_type is not None: sym_type = sym_type.handle - core.BNDefineAutoSymbolAndVariableOrFunction(self.handle, platform, sym.handle, sym_type) + core.BNDefineAutoSymbolAndVariableOrFunction(self.handle, plat, sym.handle, sym_type) def undefine_auto_symbol(self, sym): """ diff --git a/python/examples/angr_plugin.py b/python/examples/angr_plugin.py index 9c91d970..90217d65 100644 --- a/python/examples/angr_plugin.py +++ b/python/examples/angr_plugin.py @@ -116,7 +116,7 @@ def find_instr(bv, addr): blocks = bv.get_basic_blocks_at(addr) for block in blocks: block.set_auto_highlight(HighlightColor(HighlightStandardColor.GreenHighlightColor, alpha = 128)) - block.function.set_auto_instr_highlight(block.arch, addr, HighlightStandardColor.GreenHighlightColor) + block.function.set_auto_instr_highlight(addr, HighlightStandardColor.GreenHighlightColor) # Add the instruction to the list associated with the current view bv.session_data.angr_find.add(addr) @@ -127,7 +127,7 @@ def avoid_instr(bv, addr): blocks = bv.get_basic_blocks_at(addr) for block in blocks: block.set_auto_highlight(HighlightColor(HighlightStandardColor.RedHighlightColor, alpha = 128)) - block.function.set_auto_instr_highlight(block.arch, addr, HighlightStandardColor.RedHighlightColor) + block.function.set_auto_instr_highlight(addr, HighlightStandardColor.RedHighlightColor) # Add the instruction to the list associated with the current view bv.session_data.angr_avoid.add(addr) diff --git a/python/examples/breakpoint.py b/python/examples/breakpoint.py index e694329b..b1297e26 100644 --- a/python/examples/breakpoint.py +++ b/python/examples/breakpoint.py @@ -21,7 +21,6 @@ from binaryninja.plugin import PluginCommand from binaryninja.log import log_error -from binaryninja.architecture import Architecture def write_breakpoint(view, start, length): @@ -40,7 +39,8 @@ def write_breakpoint(view, start, length): if view.arch.name not in bkpt_str: log_error("Architecture %s not supported" % view.arch.name) return - bkpt, err = Architecture[view.arch.name].assemble(bkpt_str[view.arch.name]) + + bkpt, err = view.arch.assemble(bkpt_str[view.arch.name]) if bkpt is None: log_error(err) return diff --git a/python/examples/export_svg.py b/python/examples/export_svg.py index bab00f5d..89bc41a1 100755 --- a/python/examples/export_svg.py +++ b/python/examples/export_svg.py @@ -7,7 +7,7 @@ except: from urllib.request import pathname2url # Python 3.x from binaryninja.interaction import get_save_filename_input, show_message_box -from binaryninja.enums import MessageBoxButtonSet +from binaryninja.enums import MessageBoxButtonSet, MessageBoxIcon, MessageBoxButtonResult, InstructionTextTokenType, BranchType 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]} @@ -39,15 +39,15 @@ def save_svg(bv, function): output.write(content) output.close() result = show_message_box("Open SVG", "Would you like to view the exported SVG?", - buttons = MessageBoxButtonSet.YesNoButtonSet, icon = MessageBoxButtonSet.QuestionIcon) - if result == MessageBoxButtonSet.YesButton: + buttons = MessageBoxButtonSet.YesNoButtonSet, icon = MessageBoxIcon.QuestionIcon) + if result == MessageBoxButtonResult.YesButton: url = 'file:{}'.format(pathname2url(outputfile)) webbrowser.open(url) def instruction_data_flow(function, address): ''' TODO: Extract data flow information ''' - length = function.view.get_instruction_length(function.arch, address) + length = function.view.get_instruction_length(address) bytes = function.view.read(address, length) hex = bytes.encode('hex') padded = ' '.join([hex[i:i + 2] for i in range(0, len(hex), 2)]) @@ -181,7 +181,7 @@ def render_svg(function): output += '{hover}'.format(hover=hover) for token in line.tokens: # TODO: add hover for hex, function, and reg tokens - output += '{text}'.format(text=escape(token.text), tokentype=token.type) + output += '{text}'.format(text=escape(token.text), tokentype=InstructionTextTokenType(token.type).name) output += '\n' output += ' \n' output += ' \n' @@ -197,7 +197,7 @@ def render_svg(function): points += str(x * widthconst) + "," + str(y * heightconst) + " " x, y = edge.points[-1] points += str(x * widthconst) + "," + str(y * heightconst + 0) + " " - edges += ' \n'.format(type=edge.type, points=points) + edges += ' \n'.format(type=BranchType(edge.type).name, points=points) output += ' ' + edges + '\n' output += ' \n' output += '' diff --git a/python/examples/instruction_iterator.py b/python/examples/instruction_iterator.py index 47717aa0..7ff2d692 100644 --- a/python/examples/instruction_iterator.py +++ b/python/examples/instruction_iterator.py @@ -22,21 +22,10 @@ import sys import binaryninja as binja - -if sys.platform.lower().startswith("linux"): - bintype = "ELF" -elif sys.platform.lower() == "darwin": - bintype = "Mach-O" -else: - raise Exception("%s is not supported on this plugin" % sys.platform) - if len(sys.argv) > 1: target = sys.argv[1] -else: - target = "/bin/ls" -bv = binja.BinaryViewType[bintype].open(target) -bv.update_analysis_and_wait() +bv = binja.BinaryViewType.get_view_of_file(target) binja.log_to_stdout(True) binja.log_info("-------- %s --------" % target) binja.log_info("START: 0x%x" % bv.start) @@ -46,19 +35,19 @@ binja.log_info("\n-------- Function List --------") """ print all the functions, their basic blocks, and their il instructions """ for func in bv.functions: - binja.log_info(repr(func)) - for block in func.low_level_il: - binja.log_info("\t{0}".format(block)) + binja.log_info(repr(func)) + for block in func.low_level_il: + binja.log_info("\t{0}".format(block)) - for insn in block: - binja.log_info("\t\t{0}".format(insn)) + for insn in block: + binja.log_info("\t\t{0}".format(insn)) """ print all the functions, their basic blocks, and their mc instructions """ for func in bv.functions: - binja.log_info(repr(func)) - for block in func: - binja.log_info("\t{0}".format(block)) + binja.log_info(repr(func)) + for block in func: + binja.log_info("\t{0}".format(block)) - for insn in block: - binja.log_info("\t\t{0}".format(insn)) + for insn in block: + binja.log_info("\t\t{0}".format(insn)) diff --git a/python/examples/jump_table.py b/python/examples/jump_table.py index f24eea12..439e2ab6 100644 --- a/python/examples/jump_table.py +++ b/python/examples/jump_table.py @@ -21,7 +21,7 @@ # This plugin will attempt to resolve simple jump tables (an array of code pointers) and add the destinations # as indirect branch targets so that the flow graph reflects the jump table's control flow. from binaryninja.plugin import PluginCommand -from binaryninja.enum import InstructionTextTokenType +from binaryninja.enums import InstructionTextTokenType import struct @@ -50,7 +50,7 @@ def find_jump_table(bv, addr): # Collect the branch targets for any tables referenced by the clicked instruction branches = [] for token in tokens: - if token.type == InstructionTextTokenType.PossibleAddressToken: # Table addresses will be a "possible address" token + if InstructionTextTokenType(token.type) == InstructionTextTokenType.PossibleAddressToken: # Table addresses will be a "possible address" token tbl = token.value print "Found possible table at 0x%x" % tbl i = 0 diff --git a/python/examples/nes.py b/python/examples/nes.py index a1410398..4122cde0 100644 --- a/python/examples/nes.py +++ b/python/examples/nes.py @@ -24,11 +24,11 @@ import os from binaryninja.architecture import Architecture from binaryninja.lowlevelil import LowLevelILLabel, LLIL_TEMP -from binaryninja.function import RegisterInfo, InstructionInfo +from binaryninja.function import RegisterInfo, InstructionInfo, InstructionTextToken from binaryninja.binaryview import BinaryView from binaryninja.types import Symbol from binaryninja.log import log_error -from enums import (BranchType, InstructionTextToken, InstructionTextTokenType, +from binaryninja.enums import (BranchType, InstructionTextTokenType, LowLevelILOperation, LowLevelILFlagCondition, FlagRole, SegmentFlag, SymbolType) InstructionNames = [ @@ -513,6 +513,7 @@ class NESView(BinaryView): def __init__(self, data): BinaryView.__init__(self, parent_view = data, file_metadata = data.file) + self.platform = Architecture['6502'].standalone_platform @classmethod def is_valid_for_data(self, data): @@ -554,9 +555,9 @@ class NESView(BinaryView): self.define_auto_symbol(Symbol(SymbolType.FunctionSymbol, nmi, "_nmi")) self.define_auto_symbol(Symbol(SymbolType.FunctionSymbol, start, "_start")) self.define_auto_symbol(Symbol(SymbolType.FunctionSymbol, irq, "_irq")) - self.add_function(Architecture['6502'].standalone_platform, nmi) - self.add_function(Architecture['6502'].standalone_platform, irq) - self.add_entry_point(Architecture['6502'].standalone_platform, start) + self.add_function(nmi) + self.add_function(irq) + self.add_entry_point(start) # Hardware registers self.define_auto_symbol(Symbol(SymbolType.DataSymbol, 0x2000, "PPUCTRL")) @@ -605,7 +606,7 @@ class NESView(BinaryView): name = sym[1] self.define_auto_symbol(Symbol(SymbolType.FunctionSymbol, addr, name)) if addr >= 0x8000: - self.add_function(Architecture['6502'].standalone_platform, addr) + self.add_function(addr) return True except: diff --git a/python/examples/nsf.py b/python/examples/nsf.py index de775d34..b1bac3a8 100644 --- a/python/examples/nsf.py +++ b/python/examples/nsf.py @@ -39,6 +39,7 @@ class NSFView(BinaryView): def __init__(self, data): BinaryView.__init__(self, parent_view=data, file_metadata=data.file) + self.platform = Architecture["6502"].standalone_platform @classmethod def is_valid_for_data(self, data): @@ -94,8 +95,8 @@ class NSFView(BinaryView): self.define_auto_symbol(Symbol(SymbolType.FunctionSymbol, self.play_address, "_play")) self.define_auto_symbol(Symbol(SymbolType.FunctionSymbol, self.init_address, "_init")) - self.add_entry_point(Architecture['6502'].standalone_platform, self.init_address) - self.add_function(Architecture['6502'].standalone_platform, self.play_address) + self.add_entry_point(self.init_address) + self.add_function(self.play_address) # Hardware registers self.define_auto_symbol(Symbol(SymbolType.DataSymbol, 0x2000, "PPUCTRL")) -- cgit v1.3.1 From aae6c3aecdb04e8a6e33799287737a33a634418d Mon Sep 17 00:00:00 2001 From: Peter LaFosse Date: Mon, 9 Jan 2017 21:58:55 -0500 Subject: Wrapping some unwrapped enumeration values, and adding il basic block indexing --- python/architecture.py | 2 +- python/binaryview.py | 4 ++-- python/function.py | 11 ++++++----- python/lowlevelil.py | 12 ++++++++++-- 4 files changed, 19 insertions(+), 10 deletions(-) (limited to 'python/binaryview.py') diff --git a/python/architecture.py b/python/architecture.py index c95c71a0..f1440ca3 100644 --- a/python/architecture.py +++ b/python/architecture.py @@ -176,7 +176,7 @@ class Architecture(object): self._flag_roles = {} self.__dict__["flag_roles"] = {} for flag in self.__dict__["flags"]: - role = core.BNGetArchitectureFlagRole(self.handle, self._flags[flag]) + role = FlagRole(core.BNGetArchitectureFlagRole(self.handle, self._flags[flag])) self.__dict__["flag_roles"][flag] = role self._flag_roles[self._flags[flag]] = role diff --git a/python/binaryview.py b/python/binaryview.py index b19ecbd6..3467dcc3 100644 --- a/python/binaryview.py +++ b/python/binaryview.py @@ -708,7 +708,7 @@ class BinaryView(object): @property def endianness(self): """Endianness of the binary (read-only)""" - return core.BNGetDefaultEndianness(self.handle) + return Endianness(core.BNGetDefaultEndianness(self.handle)) @property def address_size(self): @@ -1577,7 +1577,7 @@ class BinaryView(object): :rtype: ModificationStatus or str """ if length is None: - return core.BNGetModification(self.handle, addr) + return ModificationStatus(core.BNGetModification(self.handle, addr)) data = (ModificationStatus * length)() length = core.BNGetModificationArray(self.handle, addr, data, length) return data[0:length] diff --git a/python/function.py b/python/function.py index e3c79312..1843dd3d 100644 --- a/python/function.py +++ b/python/function.py @@ -25,7 +25,8 @@ import ctypes # Binary Ninja components import _binaryninjacore as core from enums import (FunctionGraphType, BranchType, SymbolType, InstructionTextTokenType, - HighlightStandardColor, RegisterValueType, ImplicitRegisterExtend, DisassemblyOption, IntegerDisplayType) + HighlightStandardColor, HighlightColorStyle, RegisterValueType, ImplicitRegisterExtend, + DisassemblyOption, IntegerDisplayType) import architecture import highlight import associateddatastore @@ -47,7 +48,7 @@ class LookupTableEntry(object): class RegisterValue(object): def __init__(self, arch, value): - self.type = value.state + self.type = RegisterValueType(value.state) if value.state == RegisterValueType.EntryValue: self.reg = arch.get_reg_name(value.reg) elif value.state == RegisterValueType.OffsetFromEntryValue: @@ -682,7 +683,7 @@ class Function(object): 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) + return IntegerDisplayType(core.BNGetIntegerConstantDisplayType(self.handle, arch.handle, instr_addr, value, operand)) def set_int_display_type(self, instr_addr, value, operand, display_type, arch=None): """ @@ -831,7 +832,7 @@ class DisassemblyTextLine(object): class FunctionGraphEdge: def __init__(self, branch_type, arch, target, points): - self.type = branch_type + self.type = BranchType(branch_type) self.arch = arch self.target = target self.points = points @@ -1237,7 +1238,7 @@ class InstructionTextToken(object): """ def __init__(self, token_type, text, value = 0, size = 0, operand = 0xffffffff): - self.type = token_type + self.type = InstructionTextTokenType(token_type) self.text = text self.value = value self.size = size diff --git a/python/lowlevelil.py b/python/lowlevelil.py index 4564bf13..419e8513 100644 --- a/python/lowlevelil.py +++ b/python/lowlevelil.py @@ -118,8 +118,7 @@ class LowLevelILInstruction(object): self.function = func self.expr_index = expr_index self.instr_index = instr_index - self.operation = instr.operation - self.operation_name = LowLevelILOperation(instr.operation) + self.operation = LowLevelILOperation(instr.operation) self.size = instr.size self.address = instr.address self.source_operand = instr.sourceOperand @@ -1261,6 +1260,15 @@ class LowLevelILBasicBlock(basicblock.BasicBlock): for idx in xrange(self.start, self.end): yield self.il_function[idx] + def __getitem__(self, idx): + size = self.end - self.start + if idx > size or idx < -size: + raise IndexError("list index is out of range") + if idx >= 0: + return self.il_function[idx + self.start] + else: + return self.il_function[self.end + idx] + def LLIL_TEMP(n): return n | 0x80000000 -- cgit v1.3.1 From 1230404d0b7cd7a00fd3da7ad2aebb66d663fd08 Mon Sep 17 00:00:00 2001 From: Peter LaFosse Date: Mon, 9 Jan 2017 23:00:18 -0500 Subject: Use new style class definitions, add __init__ BinaryDataNotification --- python/binaryview.py | 7 +++++-- python/function.py | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) (limited to 'python/binaryview.py') diff --git a/python/binaryview.py b/python/binaryview.py index 3467dcc3..af7faa32 100644 --- a/python/binaryview.py +++ b/python/binaryview.py @@ -41,7 +41,10 @@ import types import lineardisassembly -class BinaryDataNotification: +class BinaryDataNotification(object): + def __init__(self): + pass + def data_written(self, view, offset, length): pass @@ -1751,7 +1754,7 @@ class BinaryView(object): :rtype: None """ - class WaitEvent: + class WaitEvent(object): def __init__(self): self.cond = threading.Condition() self.done = False diff --git a/python/function.py b/python/function.py index 1843dd3d..7d03585c 100644 --- a/python/function.py +++ b/python/function.py @@ -830,7 +830,7 @@ class DisassemblyTextLine(object): return "<%#x: %s>" % (self.address, str(self)) -class FunctionGraphEdge: +class FunctionGraphEdge(object): def __init__(self, branch_type, arch, target, points): self.type = BranchType(branch_type) self.arch = arch -- cgit v1.3.1 From bac8ff2315599fac8b49fc1c62ce63ffa946bb0d Mon Sep 17 00:00:00 2001 From: Peter LaFosse Date: Tue, 10 Jan 2017 19:17:45 -0500 Subject: Fix bv.symbols --- python/binaryview.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'python/binaryview.py') diff --git a/python/binaryview.py b/python/binaryview.py index af7faa32..aaa2cfe0 100644 --- a/python/binaryview.py +++ b/python/binaryview.py @@ -754,7 +754,7 @@ class BinaryView(object): syms = core.BNGetSymbols(self.handle, count) result = {} for i in xrange(0, count.value): - sym = function.Symbol(None, None, None, handle=core.BNNewSymbolReference(syms[i])) + sym = types.Symbol(None, None, None, handle=core.BNNewSymbolReference(syms[i])) result[sym.raw_name] = sym core.BNFreeSymbolList(syms, count.value) return result -- cgit v1.3.1 From 1f6c09e54ab53403fe0236c46f69b896713abddc Mon Sep 17 00:00:00 2001 From: Rusty Wagner Date: Mon, 16 Jan 2017 17:53:34 -0500 Subject: Fix lint issues --- python/architecture.py | 6 +++--- python/binaryview.py | 8 ++++---- python/types.py | 1 - 3 files changed, 7 insertions(+), 8 deletions(-) (limited to 'python/binaryview.py') diff --git a/python/architecture.py b/python/architecture.py index d67f00a6..32d97b09 100644 --- a/python/architecture.py +++ b/python/architecture.py @@ -364,7 +364,7 @@ class Architecture(object): def __setattr__(self, name, value): if ((name == "name") or (name == "endianness") or (name == "address_size") or - (name == "default_int_size") or (name == "regs") or (name == "get_max_instruction_length")): + (name == "default_int_size") or (name == "regs") or (name == "get_max_instruction_length")): raise AttributeError("attribute '%s' is read only" % name) else: try: @@ -1610,7 +1610,7 @@ class Architecture(object): error_str = errors.value core.BNFreeString(ctypes.cast(errors, ctypes.POINTER(ctypes.c_byte))) if not result: - raise SyntaxError, error_str + raise SyntaxError(error_str) type_dict = {} variables = {} functions = {} @@ -1654,7 +1654,7 @@ class Architecture(object): error_str = errors.value core.BNFreeString(ctypes.cast(errors, ctypes.POINTER(ctypes.c_byte))) if not result: - raise SyntaxError, error_str + raise SyntaxError(error_str) type_dict = {} variables = {} functions = {} diff --git a/python/binaryview.py b/python/binaryview.py index 34be139d..cf30d78d 100644 --- a/python/binaryview.py +++ b/python/binaryview.py @@ -250,16 +250,16 @@ class BinaryDataNotificationCallbacks(object): def _type_defined(self, ctxt, name, type_obj): try: qualified_name = types.QualifiedName._from_core_struct(name[0]) - self.notify.type_defined(self.view, qualified_name, Type(core.BNNewTypeReference(type_obj))) + self.notify.type_defined(self.view, qualified_name, types.Type(core.BNNewTypeReference(type_obj))) except: - log_error(traceback.format_exc()) + log.log_error(traceback.format_exc()) def _type_undefined(self, ctxt, name, type_obj): try: qualified_name = types.QualifiedName._from_core_struct(name[0]) - self.notify.type_undefined(self.view, qualified_name, Type(core.BNNewTypeReference(type_obj))) + self.notify.type_undefined(self.view, qualified_name, types.Type(core.BNNewTypeReference(type_obj))) except: - log_error(traceback.format_exc()) + log.log_error(traceback.format_exc()) class _BinaryViewTypeMetaclass(type): diff --git a/python/types.py b/python/types.py index 757f88aa..0470ea73 100644 --- a/python/types.py +++ b/python/types.py @@ -24,7 +24,6 @@ import ctypes import _binaryninjacore as core from enums import SymbolType, TypeClass, NamedTypeReferenceClass import callingconvention -import demangle class QualifiedName(object): -- cgit v1.3.1 From ded271158000d7fa509f513b425d95390a7f2058 Mon Sep 17 00:00:00 2001 From: Rusty Wagner Date: Tue, 17 Jan 2017 18:44:51 -0500 Subject: Add missing Python APIs --- python/architecture.py | 6 ++++- python/basicblock.py | 4 +++- python/binaryview.py | 6 +++-- python/function.py | 19 ++++++++++++---- python/lowlevelil.py | 4 +++- python/types.py | 62 +++++++++++++++++++++++++++++++++++++++++++++++++- 6 files changed, 90 insertions(+), 11 deletions(-) (limited to 'python/binaryview.py') diff --git a/python/architecture.py b/python/architecture.py index 32d97b09..ea97f605 100644 --- a/python/architecture.py +++ b/python/architecture.py @@ -467,6 +467,8 @@ class Architecture(object): token_buf[i].value = tokens[i].value token_buf[i].size = tokens[i].size token_buf[i].operand = tokens[i].operand + token_buf[i].context = tokens[i].context + token_buf[i].address = tokens[i].address result[0] = token_buf ptr = ctypes.cast(token_buf, ctypes.c_void_p) self._pending_token_lists[ptr.value] = (ptr.value, token_buf) @@ -1148,7 +1150,9 @@ class Architecture(object): value = tokens[i].value size = tokens[i].size operand = tokens[i].operand - result.append(function.InstructionTextToken(token_type, text, value, size, operand)) + context = tokens[i].context + address = tokens[i].address + result.append(function.InstructionTextToken(token_type, text, value, size, operand, context, address)) core.BNFreeInstructionText(tokens, count.value) return result, length.value diff --git a/python/basicblock.py b/python/basicblock.py index ae9889fc..ffbcd217 100644 --- a/python/basicblock.py +++ b/python/basicblock.py @@ -200,7 +200,9 @@ class BasicBlock(object): value = lines[i].tokens[j].value size = lines[i].tokens[j].size operand = lines[i].tokens[j].operand - tokens.append(function.InstructionTextToken(token_type, text, value, size, operand)) + context = lines[i].tokens[j].context + address = lines[i].tokens[j].address + tokens.append(function.InstructionTextToken(token_type, text, value, size, operand, context, address)) result.append(function.DisassemblyTextLine(addr, tokens)) core.BNFreeDisassemblyTextLines(lines, count.value) return result diff --git a/python/binaryview.py b/python/binaryview.py index cf30d78d..f8fe1fde 100644 --- a/python/binaryview.py +++ b/python/binaryview.py @@ -1886,7 +1886,7 @@ class BinaryView(object): var = core.BNDataVariable() if not core.BNGetDataVariableAtAddress(self.handle, addr, var): return None - return DataVariable(var.address, type.Type(var.type), var.autoDiscovered) + return DataVariable(var.address, types.Type(var.type), var.autoDiscovered) def get_function_at(self, addr, plat=None): """ @@ -2750,7 +2750,9 @@ class BinaryView(object): value = lines[i].contents.tokens[j].value size = lines[i].contents.tokens[j].size operand = lines[i].contents.tokens[j].operand - tokens.append(function.InstructionTextToken(token_type, text, value, size, operand)) + context = lines[i].contents.tokens[j].context + address = lines[i].contents.tokens[j].address + tokens.append(function.InstructionTextToken(token_type, text, value, size, operand, context, address)) contents = function.DisassemblyTextLine(addr, tokens) result.append(lineardisassembly.LinearDisassemblyLine(lines[i].type, func, block, lines[i].lineOffset, contents)) diff --git a/python/function.py b/python/function.py index 7d03585c..5f9f475a 100644 --- a/python/function.py +++ b/python/function.py @@ -26,7 +26,7 @@ import ctypes import _binaryninjacore as core from enums import (FunctionGraphType, BranchType, SymbolType, InstructionTextTokenType, HighlightStandardColor, HighlightColorStyle, RegisterValueType, ImplicitRegisterExtend, - DisassemblyOption, IntegerDisplayType) + DisassemblyOption, IntegerDisplayType, InstructionTextTokenContext) import architecture import highlight import associateddatastore @@ -669,7 +669,9 @@ class Function(object): value = lines[i].tokens[j].value size = lines[i].tokens[j].size operand = lines[i].tokens[j].operand - tokens.append(InstructionTextToken(token_type, text, value, size, operand)) + context = lines[i].tokens[j].context + address = lines[i].tokens[j].address + tokens.append(InstructionTextToken(token_type, text, value, size, operand, context, address)) result.append(tokens) core.BNFreeInstructionTextLines(lines, count.value) return result @@ -916,7 +918,9 @@ class FunctionGraphBlock(object): value = lines[i].tokens[j].value size = lines[i].tokens[j].size operand = lines[i].tokens[j].operand - tokens.append(InstructionTextToken(token_type, text, value, size, operand)) + context = lines[i].tokens[j].context + address = lines[i].tokens[j].address + tokens.append(InstructionTextToken(token_type, text, value, size, operand, context, address)) result.append(DisassemblyTextLine(addr, tokens)) core.BNFreeDisassemblyTextLines(lines, count.value) return result @@ -966,7 +970,9 @@ class FunctionGraphBlock(object): value = lines[i].tokens[j].value size = lines[i].tokens[j].size operand = lines[i].tokens[j].operand - tokens.append(InstructionTextToken(token_type, text, value, size, operand)) + context = lines[i].tokens[j].context + address = lines[i].tokens[j].address + tokens.append(InstructionTextToken(token_type, text, value, size, operand, context, address)) yield DisassemblyTextLine(addr, tokens) finally: core.BNFreeDisassemblyTextLines(lines, count.value) @@ -1237,12 +1243,15 @@ class InstructionTextToken(object): ========================== ============================================ """ - def __init__(self, token_type, text, value = 0, size = 0, operand = 0xffffffff): + def __init__(self, token_type, text, value = 0, size = 0, operand = 0xffffffff, + context = InstructionTextTokenContext.NoTokenContext, address = 0): self.type = InstructionTextTokenType(token_type) self.text = text self.value = value self.size = size self.operand = operand + self.context = InstructionTextTokenContext(context) + self.address = address def __str__(self): return self.text diff --git a/python/lowlevelil.py b/python/lowlevelil.py index 419e8513..29b46b65 100644 --- a/python/lowlevelil.py +++ b/python/lowlevelil.py @@ -187,7 +187,9 @@ class LowLevelILInstruction(object): value = tokens[i].value size = tokens[i].size operand = tokens[i].operand - result.append(function.InstructionTextToken(token_type, text, value, size, operand)) + context = tokens[i].context + address = tokens[i].address + result.append(function.InstructionTextToken(token_type, text, value, size, operand, context, address)) core.BNFreeInstructionText(tokens, count.value) return result diff --git a/python/types.py b/python/types.py index 0470ea73..1dd2157e 100644 --- a/python/types.py +++ b/python/types.py @@ -22,8 +22,9 @@ import ctypes # Binary Ninja components import _binaryninjacore as core -from enums import SymbolType, TypeClass, NamedTypeReferenceClass +from enums import SymbolType, TypeClass, NamedTypeReferenceClass, InstructionTextTokenType import callingconvention +import function class QualifiedName(object): @@ -317,6 +318,56 @@ class Type(object): def get_string_after_name(self): return core.BNGetTypeStringAfterName(self.handle) + @property + def tokens(self): + """Type string as a list of tokens (read-only)""" + count = ctypes.c_ulonglong() + tokens = core.BNGetTypeTokens(self.handle, count) + result = [] + for i in xrange(0, count.value): + token_type = InstructionTextTokenType(tokens[i].type) + text = tokens[i].text + value = tokens[i].value + size = tokens[i].size + operand = tokens[i].operand + context = tokens[i].context + address = tokens[i].address + result.append(function.InstructionTextToken(token_type, text, value, size, operand, context, address)) + core.BNFreeTokenList(tokens, count.value) + return result + + def get_tokens_before_name(self): + count = ctypes.c_ulonglong() + tokens = core.BNGetTypeTokensBeforeName(self.handle, count) + result = [] + for i in xrange(0, count.value): + token_type = InstructionTextTokenType(tokens[i].type) + text = tokens[i].text + value = tokens[i].value + size = tokens[i].size + operand = tokens[i].operand + context = tokens[i].context + address = tokens[i].address + result.append(function.InstructionTextToken(token_type, text, value, size, operand, context, address)) + core.BNFreeTokenList(tokens, count.value) + return result + + def get_tokens_after_name(self): + count = ctypes.c_ulonglong() + tokens = core.BNGetTypeTokensAfterName(self.handle, count) + result = [] + for i in xrange(0, count.value): + token_type = InstructionTextTokenType(tokens[i].type) + text = tokens[i].text + value = tokens[i].value + size = tokens[i].size + operand = tokens[i].operand + context = tokens[i].context + address = tokens[i].address + result.append(function.InstructionTextToken(token_type, text, value, size, operand, context, address)) + core.BNFreeTokenList(tokens, count.value) + return result + @classmethod def void(cls): return Type(core.BNCreateVoidType()) @@ -518,6 +569,9 @@ class Structure(object): def remove(self, i): core.BNRemoveStructureMember(self.handle, i) + def replace(self, i, t, name = ""): + core.BNReplaceStructureMember(self.handle, i, t.handle, name) + class EnumerationMember(object): def __init__(self, name, value, default): @@ -565,6 +619,12 @@ class Enumeration(object): else: core.BNAddEnumerationMemberWithValue(self.handle, name, value) + def remove(self, i): + core.BNRemoveEnumerationMember(self.handle, i) + + def replace(self, i, name, value): + core.BNReplaceEnumerationMember(self.handle, i, name, value) + class TypeParserResult(object): def __init__(self, types, variables, functions): -- cgit v1.3.1 From c6ed1dd374515d0e23a9d627a7dfb659c7981d16 Mon Sep 17 00:00:00 2001 From: Rusty Wagner Date: Thu, 19 Jan 2017 21:15:32 -0500 Subject: Add API to find virtual address from file offset --- binaryninjaapi.h | 1 + binaryninjacore.h | 1 + binaryview.cpp | 6 ++++++ python/binaryview.py | 6 ++++++ 4 files changed, 14 insertions(+) (limited to 'python/binaryview.py') diff --git a/binaryninjaapi.h b/binaryninjaapi.h index afbff4da..4e3f3d57 100644 --- a/binaryninjaapi.h +++ b/binaryninjaapi.h @@ -1050,6 +1050,7 @@ namespace BinaryNinja void RemoveUserSegment(uint64_t start, uint64_t length); std::vector GetSegments(); bool GetSegmentAt(uint64_t addr, Segment& result); + bool GetAddressForDataOffset(uint64_t offset, uint64_t& addr); void AddAutoSection(const std::string& name, uint64_t start, uint64_t length, const std::string& type = "", uint64_t align = 1, uint64_t entrySize = 0, const std::string& linkedSection = "", diff --git a/binaryninjacore.h b/binaryninjacore.h index 02f753cf..7d3bc14c 100644 --- a/binaryninjacore.h +++ b/binaryninjacore.h @@ -1420,6 +1420,7 @@ extern "C" BINARYNINJACOREAPI BNSegment* BNGetSegments(BNBinaryView* view, size_t* count); BINARYNINJACOREAPI void BNFreeSegmentList(BNSegment* segments); BINARYNINJACOREAPI bool BNGetSegmentAt(BNBinaryView* view, uint64_t addr, BNSegment* result); + BINARYNINJACOREAPI bool BNGetAddressForDataOffset(BNBinaryView* view, uint64_t offset, uint64_t* addr); BINARYNINJACOREAPI void BNAddAutoSection(BNBinaryView* view, const char* name, uint64_t start, uint64_t length, const char* type, uint64_t align, uint64_t entrySize, const char* linkedSection, const char* infoSection, diff --git a/binaryview.cpp b/binaryview.cpp index bef23750..cc8bb733 100644 --- a/binaryview.cpp +++ b/binaryview.cpp @@ -1645,6 +1645,12 @@ bool BinaryView::GetSegmentAt(uint64_t addr, Segment& result) } +bool BinaryView::GetAddressForDataOffset(uint64_t offset, uint64_t& addr) +{ + return BNGetAddressForDataOffset(m_object, offset, &addr); +} + + void BinaryView::AddAutoSection(const string& name, uint64_t start, uint64_t length, const string& type, uint64_t align, uint64_t entrySize, const string& linkedSection, const string& infoSection, uint64_t infoData) { diff --git a/python/binaryview.py b/python/binaryview.py index f8fe1fde..ba706fe5 100644 --- a/python/binaryview.py +++ b/python/binaryview.py @@ -3052,6 +3052,12 @@ class BinaryView(object): segment.flags) return result + def get_address_for_data_offset(self, offset): + address = ctypes.c_ulonglong() + if not core.BNGetAddressForDataOffset(self.handle, offset, address): + return None + return address.value + def add_auto_section(self, name, start, length, type = "", align = 1, entry_size = 1, linked_section = "", info_section = "", info_data = 0): core.BNAddAutoSection(self.handle, name, start, length, type, align, entry_size, linked_section, -- cgit v1.3.1 From b6636ec672069142919a9e735660d07213b93623 Mon Sep 17 00:00:00 2001 From: Josh Watson Date: Mon, 23 Jan 2017 13:51:54 -0500 Subject: BinaryView.get_view_of_file Fix (#603) * Fixed bug where BinaryView.get_view_of_file was not properly handling bndb files * Re-added a new line that somehow got removed --- python/binaryview.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'python/binaryview.py') diff --git a/python/binaryview.py b/python/binaryview.py index aaa2cfe0..476f2be6 100644 --- a/python/binaryview.py +++ b/python/binaryview.py @@ -326,7 +326,11 @@ class BinaryViewType(object): return None for available in view.available_view_types: if available.name != "Raw": - bv = cls[available.name].open(filename) + if filename.endswith(".bndb"): + bv = view.get_view_of_type(available.name) + else: + bv = cls[available.name].open(filename) + if update_analysis: bv.update_analysis_and_wait() return bv -- cgit v1.3.1 From 8df9a34dd67c852626432c84a5007be3173c33e0 Mon Sep 17 00:00:00 2001 From: Rusty Wagner Date: Mon, 6 Feb 2017 22:27:42 -0500 Subject: Add type IDs for types to track across renames --- binaryninjaapi.cpp | 9 ++++ binaryninjaapi.h | 27 +++++++++-- binaryninjacore.h | 19 ++++++-- binaryview.cpp | 54 +++++++++++++++++++--- python/__init__.py | 4 ++ python/binaryview.py | 126 ++++++++++++++++++++++++++++++++++++++++++++------- python/types.py | 63 +++++++++++++++++++++++--- type.cpp | 90 +++++++++++++++++++++++++++++++++++- 8 files changed, 354 insertions(+), 38 deletions(-) (limited to 'python/binaryview.py') diff --git a/binaryninjaapi.cpp b/binaryninjaapi.cpp index e1dab528..099f35eb 100644 --- a/binaryninjaapi.cpp +++ b/binaryninjaapi.cpp @@ -237,3 +237,12 @@ void BinaryNinja::SetWorkerThreadCount(size_t count) { BNSetWorkerThreadCount(count); } + + +string BinaryNinja::GetUniqueIdentifierString() +{ + char* str = BNGetUniqueIdentifierString(); + string result = str; + BNFreeString(str); + return result; +} diff --git a/binaryninjaapi.h b/binaryninjaapi.h index 4e3f3d57..92eeba30 100644 --- a/binaryninjaapi.h +++ b/binaryninjaapi.h @@ -409,6 +409,8 @@ namespace BinaryNinja BNMessageBoxButtonResult ShowMessageBox(const std::string& title, const std::string& text, BNMessageBoxButtonSet buttons = OKButtonSet, BNMessageBoxIcon icon = InformationIcon); + std::string GetUniqueIdentifierString(); + class QualifiedName { std::vector m_name; @@ -1027,11 +1029,15 @@ namespace BinaryNinja std::map> GetTypes(); Ref GetTypeByName(const QualifiedName& name); + Ref GetTypeById(const std::string& id); + std::string GetTypeId(const QualifiedName& name); + QualifiedName GetTypeNameById(const std::string& id); bool IsTypeAutoDefined(const QualifiedName& name); - void DefineType(const QualifiedName& name, Ref type); + QualifiedName DefineType(const std::string& id, const QualifiedName& defaultName, Ref type); void DefineUserType(const QualifiedName& name, Ref type); - void UndefineType(const QualifiedName& name); + void UndefineType(const std::string& id); void UndefineUserType(const QualifiedName& name); + void RenameType(const QualifiedName& oldName, const QualifiedName& newName); bool FindNextData(uint64_t start, const DataBuffer& data, uint64_t& result, BNFindFlag flags = NoFindFlags); @@ -1611,12 +1617,18 @@ namespace BinaryNinja static Ref StructureType(Structure* strct); static Ref NamedType(NamedTypeReference* ref, size_t width = 0, size_t align = 1); static Ref NamedType(const QualifiedName& name, Type* type); + static Ref NamedType(const std::string& id, const QualifiedName& name, Type* type); + static Ref NamedType(BinaryView* view, const QualifiedName& name); static Ref EnumerationType(Architecture* arch, Enumeration* enm, size_t width = 0, bool issigned = false); static Ref PointerType(Architecture* arch, Type* type, bool cnst = false, bool vltl = false, BNReferenceType refType = PointerReferenceType); static Ref ArrayType(Type* type, uint64_t elem); static Ref FunctionType(Type* returnValue, CallingConvention* callingConvention, const std::vector& params, bool varArg = false); + + static std::string GenerateAutoTypeId(const std::string& source, const QualifiedName& name); + static std::string GenerateAutoPlatformTypeId(const QualifiedName& name); + static std::string GenerateAutoDemangledTypeId(const QualifiedName& name); }; class NamedTypeReference: public CoreRefCountObject GenerateAutoTypeReference(BNNamedTypeReferenceClass cls, + const std::string& source, const QualifiedName& name); + static Ref GenerateAutoPlatformTypeReference(BNNamedTypeReferenceClass cls, + const QualifiedName& name); + static Ref GenerateAutoDemangledTypeReference(BNNamedTypeReferenceClass cls, + const QualifiedName& name); }; struct StructureMember diff --git a/binaryninjacore.h b/binaryninjacore.h index 7d3bc14c..b454da64 100644 --- a/binaryninjacore.h +++ b/binaryninjacore.h @@ -1234,6 +1234,8 @@ extern "C" BINARYNINJACOREAPI void BNRegisterObjectDestructionCallbacks(BNObjectDestructionCallbacks* callbacks); BINARYNINJACOREAPI void BNUnregisterObjectDestructionCallbacks(BNObjectDestructionCallbacks* callbacks); + BINARYNINJACOREAPI char* BNGetUniqueIdentifierString(void); + // Plugin initialization BINARYNINJACOREAPI void BNInitCorePlugins(void); BINARYNINJACOREAPI void BNInitUserPlugins(void); @@ -1807,11 +1809,19 @@ extern "C" BINARYNINJACOREAPI BNQualifiedNameAndType* BNGetAnalysisTypeList(BNBinaryView* view, size_t* count); BINARYNINJACOREAPI void BNFreeTypeList(BNQualifiedNameAndType* types, size_t count); BINARYNINJACOREAPI BNType* BNGetAnalysisTypeByName(BNBinaryView* view, BNQualifiedName* name); + BINARYNINJACOREAPI BNType* BNGetAnalysisTypeById(BNBinaryView* view, const char* id); + BINARYNINJACOREAPI char* BNGetAnalysisTypeId(BNBinaryView* view, BNQualifiedName* name); + BINARYNINJACOREAPI BNQualifiedName BNGetAnalysisTypeNameById(BNBinaryView* view, const char* id); BINARYNINJACOREAPI bool BNIsAnalysisTypeAutoDefined(BNBinaryView* view, BNQualifiedName* name); - BINARYNINJACOREAPI void BNDefineAnalysisType(BNBinaryView* view, BNQualifiedName* name, BNType* type); + BINARYNINJACOREAPI BNQualifiedName BNDefineAnalysisType(BNBinaryView* view, const char* id, + BNQualifiedName* defaultName, BNType* type); BINARYNINJACOREAPI void BNDefineUserAnalysisType(BNBinaryView* view, BNQualifiedName* name, BNType* type); - BINARYNINJACOREAPI void BNUndefineAnalysisType(BNBinaryView* view, BNQualifiedName* name); + BINARYNINJACOREAPI void BNUndefineAnalysisType(BNBinaryView* view, const char* id); BINARYNINJACOREAPI void BNUndefineUserAnalysisType(BNBinaryView* view, BNQualifiedName* name); + BINARYNINJACOREAPI void BNRenameAnalysisType(BNBinaryView* view, BNQualifiedName* oldName, BNQualifiedName* newName); + BINARYNINJACOREAPI char* BNGenerateAutoTypeId(const char* source, BNQualifiedName* name); + BINARYNINJACOREAPI char* BNGenerateAutoPlatformTypeId(BNQualifiedName* name); + BINARYNINJACOREAPI char* BNGenerateAutoDemangledTypeId(BNQualifiedName* name); BINARYNINJACOREAPI void BNReanalyzeAllFunctions(BNBinaryView* view); BINARYNINJACOREAPI void BNReanalyzeFunction(BNFunction* func); @@ -2006,10 +2016,13 @@ extern "C" BINARYNINJACOREAPI void BNFreeTokenList(BNInstructionTextToken* tokens, size_t count); BINARYNINJACOREAPI BNType* BNCreateNamedTypeReference(BNNamedTypeReference* nt, size_t width, size_t align); - BINARYNINJACOREAPI BNType* BNCreateNamedTypeReferenceFromType(BNQualifiedName* name, BNType* type); + BINARYNINJACOREAPI BNType* BNCreateNamedTypeReferenceFromTypeAndId(const char* id, BNQualifiedName* name, BNType* type); + BINARYNINJACOREAPI BNType* BNCreateNamedTypeReferenceFromType(BNBinaryView* view, BNQualifiedName* name); BINARYNINJACOREAPI BNNamedTypeReference* BNCreateNamedType(void); BINARYNINJACOREAPI void BNSetTypeReferenceClass(BNNamedTypeReference* nt, BNNamedTypeReferenceClass cls); BINARYNINJACOREAPI BNNamedTypeReferenceClass BNGetTypeReferenceClass(BNNamedTypeReference* nt); + BINARYNINJACOREAPI void BNSetTypeReferenceId(BNNamedTypeReference* nt, const char* id); + BINARYNINJACOREAPI char* BNGetTypeReferenceId(BNNamedTypeReference* nt); BINARYNINJACOREAPI void BNSetTypeReferenceName(BNNamedTypeReference* nt, BNQualifiedName* name); BINARYNINJACOREAPI BNQualifiedName BNGetTypeReferenceName(BNNamedTypeReference* nt); BINARYNINJACOREAPI void BNFreeQualifiedName(BNQualifiedName* name); diff --git a/binaryview.cpp b/binaryview.cpp index cc8bb733..1b1574e1 100644 --- a/binaryview.cpp +++ b/binaryview.cpp @@ -1496,6 +1496,35 @@ Ref BinaryView::GetTypeByName(const QualifiedName& name) } +Ref BinaryView::GetTypeById(const string& id) +{ + BNType* type = BNGetAnalysisTypeById(m_object, id.c_str()); + if (!type) + return nullptr; + return new Type(type); +} + + +QualifiedName BinaryView::GetTypeNameById(const string& id) +{ + BNQualifiedName name = BNGetAnalysisTypeNameById(m_object, id.c_str()); + QualifiedName result = QualifiedName::FromAPIObject(&name); + BNFreeQualifiedName(&name); + return result; +} + + +string BinaryView::GetTypeId(const QualifiedName& name) +{ + BNQualifiedName nameObj = name.GetAPIObject(); + char* id = BNGetAnalysisTypeId(m_object, &nameObj); + QualifiedName::FreeAPIObject(&nameObj); + string result = id; + BNFreeString(id); + return result; +} + + bool BinaryView::IsTypeAutoDefined(const QualifiedName& name) { BNQualifiedName nameObj = name.GetAPIObject(); @@ -1505,11 +1534,14 @@ bool BinaryView::IsTypeAutoDefined(const QualifiedName& name) } -void BinaryView::DefineType(const QualifiedName& name, Ref type) +QualifiedName BinaryView::DefineType(const string& id, const QualifiedName& defaultName, Ref type) { - BNQualifiedName nameObj = name.GetAPIObject(); - BNDefineAnalysisType(m_object, &nameObj, type->GetObject()); + BNQualifiedName nameObj = defaultName.GetAPIObject(); + BNQualifiedName regName = BNDefineAnalysisType(m_object, id.c_str(), &nameObj, type->GetObject()); QualifiedName::FreeAPIObject(&nameObj); + QualifiedName result = QualifiedName::FromAPIObject(®Name); + BNFreeQualifiedName(®Name); + return result; } @@ -1521,11 +1553,9 @@ void BinaryView::DefineUserType(const QualifiedName& name, Ref type) } -void BinaryView::UndefineType(const QualifiedName& name) +void BinaryView::UndefineType(const string& id) { - BNQualifiedName nameObj = name.GetAPIObject(); - BNUndefineAnalysisType(m_object, &nameObj); - QualifiedName::FreeAPIObject(&nameObj); + BNUndefineAnalysisType(m_object, id.c_str()); } @@ -1537,6 +1567,16 @@ void BinaryView::UndefineUserType(const QualifiedName& name) } +void BinaryView::RenameType(const QualifiedName& oldName, const QualifiedName& newName) +{ + BNQualifiedName oldNameObj = oldName.GetAPIObject(); + BNQualifiedName newNameObj = newName.GetAPIObject(); + BNRenameAnalysisType(m_object, &oldNameObj, &newNameObj); + QualifiedName::FreeAPIObject(&oldNameObj); + QualifiedName::FreeAPIObject(&newNameObj); +} + + bool BinaryView::FindNextData(uint64_t start, const DataBuffer& data, uint64_t& result, BNFindFlag flags) { return BNFindNextData(m_object, start, data.GetBufferObject(), &result, flags); diff --git a/python/__init__.py b/python/__init__.py index a1ea02f5..9b87aa47 100644 --- a/python/__init__.py +++ b/python/__init__.py @@ -51,6 +51,10 @@ def shutdown(): core.BNShutdown() +def get_unique_identifier(): + return core.BNGetUniqueIdentifierString() + + class _DestructionCallbackHandler(object): def __init__(self): self._cb = core.BNObjectDestructionCallbacks() diff --git a/python/binaryview.py b/python/binaryview.py index ba706fe5..2cdacb4c 100644 --- a/python/binaryview.py +++ b/python/binaryview.py @@ -2881,7 +2881,7 @@ class BinaryView(object): :Example: >>> type, name = bv.parse_type_string("int foo") - >>> bv.define_type(name, type) + >>> bv.define_user_type(name, type) >>> bv.get_type_by_name(name) >>> @@ -2892,6 +2892,71 @@ class BinaryView(object): return None return types.Type(obj) + def get_type_by_id(self, id): + """ + ``get_type_by_id`` returns the defined type whose unique identifier corresponds with the provided ``id`` + + :param str id: Unique identifier 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") + >>> type_id = Type.generate_auto_type_id("source", name) + >>> bv.define_type(type_id, name, type) + >>> bv.get_type_by_id(type_id) + + >>> + """ + obj = core.BNGetAnalysisTypeById(self.handle, id) + if not obj: + return None + return types.Type(obj) + + def get_type_name_by_id(self, id): + """ + ``get_type_name_by_id`` returns the defined type name whose unique identifier corresponds with the provided ``id`` + + :param str id: Unique identifier to lookup + :return: A QualifiedName or None if the type does not exist + :rtype: QualifiedName or None + :Example: + + >>> type, name = bv.parse_type_string("int foo") + >>> type_id = Type.generate_auto_type_id("source", name) + >>> bv.define_type(type_id, name, type) + 'foo' + >>> bv.get_type_name_by_id(type_id) + 'foo' + >>> + """ + name = core.BNGetAnalysisTypeNameById(self.handle, id) + result = types.QualifiedName._from_core_struct(name) + core.BNFreeQualifiedName(name) + if len(result) == 0: + return None + return result + + def get_type_id(self, name): + """ + ``get_type_id`` returns the unique indentifier of the defined type whose name corresponds with the + provided ``name`` + + :param QualifiedName name: Type name to lookup + :return: The unique identifier of the type + :rtype: str + :Example: + + >>> type, name = bv.parse_type_string("int foo") + >>> type_id = Type.generate_auto_type_id("source", name) + >>> registered_name = bv.define_type(type_id, name, type) + >>> bv.get_type_id(registered_name) == type_id + True + >>> + """ + name = types.QualifiedName(name)._get_core_struct() + return core.BNGetAnalysisTypeId(self.handle, name) + def is_type_auto_defined(self, name): """ ``is_type_auto_defined`` queries the user type list of name. If name is not in the *user* type list then the name @@ -2910,23 +2975,28 @@ class BinaryView(object): name = types.QualifiedName(name)._get_core_struct() return core.BNIsAnalysisTypeAutoDefined(self.handle, name) - def define_type(self, name, type_obj): + def define_type(self, type_id, default_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`. + the current :py:Class:`BinaryView`. This method should only be used for automatically generated types. - :param QualifiedName name: Name of the type to be registered + :param str type_id: Unique identifier for the automatically generated type + :param QualifiedName default_name: Name of the type to be registered :param Type type_obj: Type object to be registered - :rtype: None + :return: Registered name of the type. May not be the same as the requested name if the user has renamed types. + :rtype: QualifiedName :Example: >>> type, name = bv.parse_type_string("int foo") - >>> bv.define_type(name, type) - >>> bv.get_type_by_name(name) + >>> registered_name = bv.define_type(Type.generate_auto_type_id("source", name), name, type) + >>> bv.get_type_by_name(registered_name) """ - name = types.QualifiedName(name)._get_core_struct() - core.BNDefineAnalysisType(self.handle, name, type_obj.handle) + name = types.QualifiedName(default_name)._get_core_struct() + reg_name = core.BNDefineAnalysisType(self.handle, type_id, name, type_obj.handle) + result = types.QualifiedName._from_core_struct(reg_name) + core.BNFreeQualifiedName(reg_name) + return result def define_user_type(self, name, type_obj): """ @@ -2946,24 +3016,24 @@ class BinaryView(object): name = types.QualifiedName(name)._get_core_struct() core.BNDefineUserAnalysisType(self.handle, name, type_obj.handle) - def undefine_type(self, name): + def undefine_type(self, type_id): """ ``undefine_type`` removes a :py:Class:`Type` from the global list of types for the current :py:Class:`BinaryView` - :param QualifiedName name: Name of type to be undefined + :param str type_id: Unique identifier of type to be undefined :rtype: None :Example: >>> type, name = bv.parse_type_string("int foo") - >>> bv.define_type(name, type) + >>> type_id = Type.generate_auto_type_id("source", name) + >>> bv.define_type(type_id, name, type) >>> bv.get_type_by_name(name) - >>> bv.undefine_type(name) + >>> bv.undefine_type(type_id) >>> bv.get_type_by_name(name) >>> """ - name = types.QualifiedName(name)._get_core_struct() - core.BNUndefineAnalysisType(self.handle, name) + core.BNUndefineAnalysisType(self.handle, type_id) def undefine_user_type(self, name): """ @@ -2975,16 +3045,38 @@ class BinaryView(object): :Example: >>> type, name = bv.parse_type_string("int foo") - >>> bv.define_type(name, type) + >>> bv.define_user_type(name, type) >>> bv.get_type_by_name(name) - >>> bv.undefine_type(name) + >>> bv.undefine_user_type(name) >>> bv.get_type_by_name(name) >>> """ name = types.QualifiedName(name)._get_core_struct() core.BNUndefineUserAnalysisType(self.handle, name) + def rename_type(self, old_name, new_name): + """ + ``rename_type`` renames a type in the global list of types for the current :py:Class:`BinaryView` + + :param QualifiedName old_name: Existing name of type to be renamed + :param QualifiedName new_name: New name of type to be renamed + :rtype: None + :Example: + + >>> type, name = bv.parse_type_string("int foo") + >>> bv.define_user_type(name, type) + >>> bv.get_type_by_name("foo") + + >>> bv.rename_type("foo", "bar") + >>> bv.get_type_by_name("bar") + + >>> + """ + old_name = types.QualifiedName(old_name)._get_core_struct() + new_name = types.QualifiedName(new_name)._get_core_struct() + core.BNRenameAnalysisType(self.handle, old_name, new_name) + def find_next_data(self, start, data, flags = 0): """ ``find_next_data`` searchs for the bytes in data starting at the virtual address ``start`` either, case-sensitive, diff --git a/python/types.py b/python/types.py index 1dd2157e..1cc02691 100644 --- a/python/types.py +++ b/python/types.py @@ -299,7 +299,7 @@ class Type(object): result = core.BNGetTypeNamedTypeReference(self.handle) if result is None: return None - return NamedTypeReference(result) + return NamedTypeReference(handle = result) @property def count(self): @@ -392,12 +392,24 @@ class Type(object): def named_type(self, named_type, width = 0, align = 1): return Type(core.BNCreateNamedTypeReference(named_type.handle, width, align)) + @classmethod + def named_type_from_type_and_id(self, type_id, name, t): + name = QualifiedName(name)._get_core_struct() + if t is not None: + t = t.handle + return Type(core.BNCreateNamedTypeReferenceFromTypeAndId(type_id, name, t)) + @classmethod def named_type_from_type(self, name, t): name = QualifiedName(name)._get_core_struct() if t is not None: t = t.handle - return Type(core.BNCreateNamedTypeReferenceFromType(name, t)) + return Type(core.BNCreateNamedTypeReferenceFromTypeAndId("", name, t)) + + @classmethod + def named_type_from_registered_type(self, view, name): + name = QualifiedName(name)._get_core_struct() + return Type(core.BNCreateNamedTypeReferenceFromType(view.handle, name)) @classmethod def enumeration_type(self, arch, e, width=None): @@ -428,6 +440,21 @@ class Type(object): return Type(core.BNCreateFunctionType(ret.handle, calling_convention, param_buf, len(params), variable_arguments)) + @classmethod + def generate_auto_type_id(self, source, name): + name = QualifiedName(name)._get_core_struct() + return core.BNGenerateAutoTypeId(source, name) + + @classmethod + def generate_auto_platform_type_id(self, name): + name = QualifiedName(name)._get_core_struct() + return core.BNGenerateAutoTypeId(name) + + @classmethod + def generate_auto_demangled_type_id(self, name): + name = QualifiedName(name)._get_core_struct() + return core.BNGenerateAutoTypeId(name) + def __setattr__(self, name, value): try: object.__setattr__(self, name, value) @@ -436,10 +463,12 @@ class Type(object): class NamedTypeReference(object): - def __init__(self, type_class = NamedTypeReferenceClass.UnknownNamedTypeClass, name = None, handle = None): + def __init__(self, type_class = NamedTypeReferenceClass.UnknownNamedTypeClass, type_id = None, name = None, handle = None): if handle is None: self.handle = core.BNCreateNamedType() core.BNSetTypeReferenceClass(self.handle, type_class) + if type_id is not None: + core.BNSetTypeReferenceId(self.handle, type_id) if name is not None: name = QualifiedName(name)._get_core_struct() core.BNSetTypeReferenceName(self.handle, name) @@ -451,16 +480,23 @@ class NamedTypeReference(object): @property def type_class(self): - return core.BNGetTypeReferenceClass(self.handle) + return NamedTypeReferenceClass(core.BNGetTypeReferenceClass(self.handle)) @type_class.setter def type_class(self, value): core.BNSetTypeReferenceClass(self.handle, value) + @property + def type_id(self): + return core.BNGetTypeReferenceId(self.handle) + + @type_id.setter + def type_id(self, value): + core.BNSetTypeReferenceId(self.handle, value) + @property def name(self): - count = ctypes.c_ulonglong() - name = core.BNGetTypeReferenceName(self.handle, count) + name = core.BNGetTypeReferenceName(self.handle) result = QualifiedName._from_core_struct(name) core.BNFreeQualifiedName(name) return result @@ -481,6 +517,21 @@ class NamedTypeReference(object): return "" % str(self.name) return "" % str(self.name) + @classmethod + def generate_auto_type_ref(self, type_class, source, name): + type_id = Type.generate_auto_type_id(source, name) + return NamedTypeReference(type_class, type_id, name) + + @classmethod + def generate_auto_platform_type_ref(self, type_class, source, name): + type_id = Type.generate_auto_platform_type_id(source, name) + return NamedTypeReference(type_class, type_id, name) + + @classmethod + def generate_auto_demangled_type_ref(self, type_class, source, name): + type_id = Type.generate_auto_demangled_type_id(source, name) + return NamedTypeReference(type_class, type_id, name) + class StructureMember(object): def __init__(self, t, name, offset): diff --git a/type.cpp b/type.cpp index e71077e6..dd1fb8d6 100644 --- a/type.cpp +++ b/type.cpp @@ -511,9 +511,25 @@ Ref Type::NamedType(NamedTypeReference* ref, size_t width, size_t align) Ref Type::NamedType(const QualifiedName& name, Type* type) +{ + return NamedType("", name, type); +} + + +Ref Type::NamedType(const string& id, const QualifiedName& name, Type* type) { BNQualifiedName nameObj = name.GetAPIObject(); - Type* result = new Type(BNCreateNamedTypeReferenceFromType(&nameObj, type ? type->GetObject() : nullptr)); + Type* result = new Type(BNCreateNamedTypeReferenceFromTypeAndId(id.c_str(), &nameObj, + type ? type->GetObject() : nullptr)); + QualifiedName::FreeAPIObject(&nameObj); + return result; +} + + +Ref Type::NamedType(BinaryView* view, const QualifiedName& name) +{ + BNQualifiedName nameObj = name.GetAPIObject(); + Type* result = new Type(BNCreateNamedTypeReferenceFromType(view->GetObject(), &nameObj)); QualifiedName::FreeAPIObject(&nameObj); return result; } @@ -561,16 +577,47 @@ void Type::SetFunctionCanReturn(bool canReturn) } +string Type::GenerateAutoTypeId(const string& source, const QualifiedName& name) +{ + BNQualifiedName nameObj = name.GetAPIObject(); + string result = BNGenerateAutoTypeId(source.c_str(), &nameObj); + QualifiedName::FreeAPIObject(&nameObj); + return result; +} + + +string Type::GenerateAutoPlatformTypeId(const QualifiedName& name) +{ + BNQualifiedName nameObj = name.GetAPIObject(); + string result = BNGenerateAutoPlatformTypeId(&nameObj); + QualifiedName::FreeAPIObject(&nameObj); + return result; +} + + +string Type::GenerateAutoDemangledTypeId(const QualifiedName& name) +{ + BNQualifiedName nameObj = name.GetAPIObject(); + string result = BNGenerateAutoDemangledTypeId(&nameObj); + QualifiedName::FreeAPIObject(&nameObj); + return result; +} + + NamedTypeReference::NamedTypeReference(BNNamedTypeReference* nt) { m_object = nt; } -NamedTypeReference::NamedTypeReference(BNNamedTypeReferenceClass cls, const QualifiedName& names) +NamedTypeReference::NamedTypeReference(BNNamedTypeReferenceClass cls, const string& id, const QualifiedName& names) { m_object = BNCreateNamedType(); BNSetTypeReferenceClass(m_object, cls); + if (id.size() != 0) + { + BNSetTypeReferenceId(m_object, id.c_str()); + } if (names.size() != 0) { BNQualifiedName nameObj = names.GetAPIObject(); @@ -592,6 +639,21 @@ BNNamedTypeReferenceClass NamedTypeReference::GetTypeClass() const } +string NamedTypeReference::GetTypeId() const +{ + char* str = BNGetTypeReferenceId(m_object); + string result = str; + BNFreeString(str); + return result; +} + + +void NamedTypeReference::SetTypeId(const string& id) +{ + BNSetTypeReferenceId(m_object, id.c_str()); +} + + void NamedTypeReference::SetName(const QualifiedName& names) { BNQualifiedName nameObj = names.GetAPIObject(); @@ -609,6 +671,30 @@ QualifiedName NamedTypeReference::GetName() const } +Ref NamedTypeReference::GenerateAutoTypeReference(BNNamedTypeReferenceClass cls, + const string& source, const QualifiedName& name) +{ + string id = Type::GenerateAutoTypeId(source, name); + return new NamedTypeReference(cls, id, name); +} + + +Ref NamedTypeReference::GenerateAutoPlatformTypeReference(BNNamedTypeReferenceClass cls, + const QualifiedName& name) +{ + string id = Type::GenerateAutoPlatformTypeId(name); + return new NamedTypeReference(cls, id, name); +} + + +Ref NamedTypeReference::GenerateAutoDemangledTypeReference(BNNamedTypeReferenceClass cls, + const QualifiedName& name) +{ + string id = Type::GenerateAutoDemangledTypeId(name); + return new NamedTypeReference(cls, id, name); +} + + Structure::Structure() { m_object = BNCreateStructure(); -- cgit v1.3.1 From 898ec98d9858ddec7fb431ba304d996cec12ff68 Mon Sep 17 00:00:00 2001 From: Rusty Wagner Date: Thu, 9 Feb 2017 19:06:07 -0500 Subject: APIs for handling platform types --- architecture.cpp | 9 +++++---- binaryninjaapi.h | 17 ++++++++++++----- binaryninjacore.h | 16 ++++++++++------ binaryview.cpp | 6 ++++++ platform.cpp | 28 ++++++++++++++++++++++++++++ python/architecture.py | 12 ++++++++---- python/binaryview.py | 16 ++++++++++++++++ python/platform.py | 12 ++++++++++++ python/types.py | 18 ++++++------------ type.cpp | 26 +++++++++++--------------- 10 files changed, 114 insertions(+), 46 deletions(-) (limited to 'python/binaryview.py') diff --git a/architecture.cpp b/architecture.cpp index 0e25fa85..d72e7f42 100644 --- a/architecture.cpp +++ b/architecture.cpp @@ -747,7 +747,8 @@ void Architecture::SetBinaryViewTypeConstant(const string& type, const string& n bool Architecture::ParseTypesFromSource(const string& source, const string& fileName, map>& types, map>& variables, - map>& functions, string& errors, const vector& includeDirs) + map>& functions, string& errors, const vector& includeDirs, + const string& autoTypeSource) { BNTypeParserResult result; char* errorStr; @@ -761,7 +762,7 @@ bool Architecture::ParseTypesFromSource(const string& source, const string& file functions.clear(); bool ok = BNParseTypesFromSource(m_object, source.c_str(), fileName.c_str(), &result, - &errorStr, includeDirList, includeDirs.size()); + &errorStr, includeDirList, includeDirs.size(), autoTypeSource.c_str()); errors = errorStr; BNFreeString(errorStr); if (!ok) @@ -789,7 +790,7 @@ bool Architecture::ParseTypesFromSource(const string& source, const string& file bool Architecture::ParseTypesFromSourceFile(const string& fileName, map>& types, map>& variables, map>& functions, - string& errors, const vector& includeDirs) + string& errors, const vector& includeDirs, const string& autoTypeSource) { BNTypeParserResult result; char* errorStr; @@ -803,7 +804,7 @@ bool Architecture::ParseTypesFromSourceFile(const string& fileName, map>& types, std::map>& variables, std::map>& functions, std::string& errors, - const std::vector& includeDirs = std::vector()); + const std::vector& includeDirs = std::vector(), + const std::string& autoTypeSource = ""); bool ParseTypesFromSourceFile(const std::string& fileName, std::map>& types, std::map>& variables, std::map>& functions, std::string& errors, - const std::vector& includeDirs = std::vector()); + const std::vector& includeDirs = std::vector(), + const std::string& autoTypeSource = ""); void RegisterCallingConvention(CallingConvention* cc); std::vector> GetCallingConventions(); @@ -1627,8 +1631,8 @@ namespace BinaryNinja const std::vector& params, bool varArg = false); static std::string GenerateAutoTypeId(const std::string& source, const QualifiedName& name); - static std::string GenerateAutoPlatformTypeId(const QualifiedName& name); static std::string GenerateAutoDemangledTypeId(const QualifiedName& name); + static std::string GetAutoDemangledTypeIdSource(); }; class NamedTypeReference: public CoreRefCountObject GenerateAutoTypeReference(BNNamedTypeReferenceClass cls, const std::string& source, const QualifiedName& name); - static Ref GenerateAutoPlatformTypeReference(BNNamedTypeReferenceClass cls, - const QualifiedName& name); static Ref GenerateAutoDemangledTypeReference(BNNamedTypeReferenceClass cls, const QualifiedName& name); }; @@ -2339,6 +2341,11 @@ namespace BinaryNinja Ref GetRelatedPlatform(Architecture* arch); void AddRelatedPlatform(Architecture* arch, Platform* platform); Ref GetAssociatedPlatformByAddress(uint64_t& addr); + + std::string GenerateAutoPlatformTypeId(const QualifiedName& name); + Ref GenerateAutoPlatformTypeReference(BNNamedTypeReferenceClass cls, + const QualifiedName& name); + std::string GetAutoPlatformTypeIdSource(); }; class ScriptingOutputListener diff --git a/binaryninjacore.h b/binaryninjacore.h index b454da64..4b810002 100644 --- a/binaryninjacore.h +++ b/binaryninjacore.h @@ -1820,8 +1820,12 @@ extern "C" BINARYNINJACOREAPI void BNUndefineUserAnalysisType(BNBinaryView* view, BNQualifiedName* name); BINARYNINJACOREAPI void BNRenameAnalysisType(BNBinaryView* view, BNQualifiedName* oldName, BNQualifiedName* newName); BINARYNINJACOREAPI char* BNGenerateAutoTypeId(const char* source, BNQualifiedName* name); - BINARYNINJACOREAPI char* BNGenerateAutoPlatformTypeId(BNQualifiedName* name); + BINARYNINJACOREAPI char* BNGenerateAutoPlatformTypeId(BNPlatform* platform, BNQualifiedName* name); BINARYNINJACOREAPI char* BNGenerateAutoDemangledTypeId(BNQualifiedName* name); + BINARYNINJACOREAPI char* BNGetAutoPlatformTypeIdSource(BNPlatform* platform); + BINARYNINJACOREAPI char* BNGetAutoDemangledTypeIdSource(void); + + BINARYNINJACOREAPI void BNRegisterPlatformTypes(BNBinaryView* view, BNPlatform* platform); BINARYNINJACOREAPI void BNReanalyzeAllFunctions(BNBinaryView* view); BINARYNINJACOREAPI void BNReanalyzeFunction(BNFunction* func); @@ -2063,13 +2067,13 @@ extern "C" // Source code processing BINARYNINJACOREAPI bool BNPreprocessSource(const char* source, const char* fileName, char** output, char** errors, - const char** includeDirs, size_t includeDirCount); + const char** includeDirs, size_t includeDirCount); BINARYNINJACOREAPI bool BNParseTypesFromSource(BNArchitecture* arch, const char* source, const char* fileName, - BNTypeParserResult* result, char** errors, - const char** includeDirs, size_t includeDirCount); + BNTypeParserResult* result, char** errors, const char** includeDirs, size_t includeDirCount, + const char* autoTypeSource); BINARYNINJACOREAPI bool BNParseTypesFromSourceFile(BNArchitecture* arch, const char* fileName, - BNTypeParserResult* result, char** errors, - const char** includeDirs, size_t includeDirCount); + BNTypeParserResult* result, char** errors, const char** includeDirs, size_t includeDirCount, + const char* autoTypeSource); BINARYNINJACOREAPI void BNFreeTypeParserResult(BNTypeParserResult* result); // Updates diff --git a/binaryview.cpp b/binaryview.cpp index 1b1574e1..8edbc2bf 100644 --- a/binaryview.cpp +++ b/binaryview.cpp @@ -1577,6 +1577,12 @@ void BinaryView::RenameType(const QualifiedName& oldName, const QualifiedName& n } +void BinaryView::RegisterPlatformTypes(Platform* platform) +{ + BNRegisterPlatformTypes(m_object, platform->GetObject()); +} + + bool BinaryView::FindNextData(uint64_t start, const DataBuffer& data, uint64_t& result, BNFindFlag flags) { return BNFindNextData(m_object, start, data.GetBufferObject(), &result, flags); diff --git a/platform.cpp b/platform.cpp index 7a6571cc..3bf4c0a4 100644 --- a/platform.cpp +++ b/platform.cpp @@ -253,3 +253,31 @@ Ref Platform::GetAssociatedPlatformByAddress(uint64_t& addr) return nullptr; return new Platform(platform); } + + +string Platform::GenerateAutoPlatformTypeId(const QualifiedName& name) +{ + BNQualifiedName nameObj = name.GetAPIObject(); + char* str = BNGenerateAutoPlatformTypeId(m_object, &nameObj); + string result = str; + QualifiedName::FreeAPIObject(&nameObj); + BNFreeString(str); + return result; +} + + +Ref Platform::GenerateAutoPlatformTypeReference(BNNamedTypeReferenceClass cls, + const QualifiedName& name) +{ + string id = GenerateAutoPlatformTypeId(name); + return new NamedTypeReference(cls, id, name); +} + + +string Platform::GetAutoPlatformTypeIdSource() +{ + char* str = BNGetAutoPlatformTypeIdSource(m_object); + string result = str; + BNFreeString(str); + return result; +} diff --git a/python/architecture.py b/python/architecture.py index ea97f605..4cd0c597 100644 --- a/python/architecture.py +++ b/python/architecture.py @@ -1585,7 +1585,7 @@ class Architecture(object): """ core.BNSetBinaryViewTypeArchitectureConstant(self.handle, type_name, const_name, value) - def parse_types_from_source(self, source, filename=None, include_dirs=[]): + def parse_types_from_source(self, source, filename=None, include_dirs=[], auto_type_source=None): """ ``parse_types_from_source`` parses the source string and any needed headers searching for them in the optional list of directories provided in ``include_dirs``. @@ -1593,6 +1593,7 @@ class Architecture(object): :param str source: source string to be parsed :param str filename: optional source filename :param list(str) include_dirs: optional list of string filename include directories + :param str auto_type_source: optional source of types if used for automatically generated types :return: py:class:`TypeParserResult` (a SyntaxError is thrown on parse error) :rtype: TypeParserResult :Example: @@ -1610,7 +1611,8 @@ class Architecture(object): dir_buf[i] = str(include_dirs[i]) parse = core.BNTypeParserResult() errors = ctypes.c_char_p() - result = core.BNParseTypesFromSource(self.handle, source, filename, parse, errors, dir_buf, len(include_dirs)) + result = core.BNParseTypesFromSource(self.handle, source, filename, parse, errors, dir_buf, + len(include_dirs), auto_type_source) error_str = errors.value core.BNFreeString(ctypes.cast(errors, ctypes.POINTER(ctypes.c_byte))) if not result: @@ -1630,13 +1632,14 @@ class Architecture(object): core.BNFreeTypeParserResult(parse) return types.TypeParserResult(type_dict, variables, functions) - def parse_types_from_source_file(self, filename, include_dirs=[]): + def parse_types_from_source_file(self, filename, include_dirs=[], auto_type_source=None): """ ``parse_types_from_source_file`` parses the source file ``filename`` and any needed headers searching for them in the optional list of directories provided in ``include_dirs``. :param str filename: filename of file to be parsed :param list(str) include_dirs: optional list of string filename include directories + :param str auto_type_source: optional source of types if used for automatically generated types :return: py:class:`TypeParserResult` (a SyntaxError is thrown on parse error) :rtype: TypeParserResult :Example: @@ -1654,7 +1657,8 @@ class Architecture(object): dir_buf[i] = str(include_dirs[i]) parse = core.BNTypeParserResult() errors = ctypes.c_char_p() - result = core.BNParseTypesFromSourceFile(self.handle, filename, parse, errors, dir_buf, len(include_dirs)) + result = core.BNParseTypesFromSourceFile(self.handle, filename, parse, errors, dir_buf, + len(include_dirs), auto_type_source) error_str = errors.value core.BNFreeString(ctypes.cast(errors, ctypes.POINTER(ctypes.c_byte))) if not result: diff --git a/python/binaryview.py b/python/binaryview.py index 2cdacb4c..caa5d780 100644 --- a/python/binaryview.py +++ b/python/binaryview.py @@ -3077,6 +3077,22 @@ class BinaryView(object): new_name = types.QualifiedName(new_name)._get_core_struct() core.BNRenameAnalysisType(self.handle, old_name, new_name) + def register_platform_types(self, platform): + """ + ``register_platform_types`` ensures that the platform-specific types for a :py:Class:`Platform` are available + for the current :py:Class:`BinaryView`. This is automatically performed when adding a new function or setting + the default platform. + + :param Platform platform: Platform containing types to be registered + :rtype: None + :Example: + + >>> platform = Platform["linux-x86"] + >>> bv.register_platform_types(platform) + >>> + """ + core.BNRegisterPlatformTypes(self.handle, platform.handle) + def find_next_data(self, start, data, flags = 0): """ ``find_next_data`` searchs for the bytes in data starting at the virtual address ``start`` either, case-sensitive, diff --git a/python/platform.py b/python/platform.py index 04dce587..5d90997d 100644 --- a/python/platform.py +++ b/python/platform.py @@ -25,6 +25,7 @@ import _binaryninjacore as core import startup import architecture import callingconvention +import types class _PlatformMetaClass(type): @@ -259,3 +260,14 @@ class Platform(object): new_addr.value = addr result = core.BNGetAssociatedPlatformByAddress(self.handle, new_addr) return Platform(None, handle = result), new_addr.value + + def generate_auto_platform_type_id(self, name): + name = types.QualifiedName(name)._get_core_struct() + return core.BNGenerateAutoPlatformTypeId(self.handle, name) + + def generate_auto_platform_type_ref(self, type_class, name): + type_id = self.generate_auto_platform_type_id(name) + return types.NamedTypeReference(type_class, type_id, name) + + def get_auto_platform_type_id_source(self): + return core.BNGetAutoPlatformTypeIdSource(self.handle) diff --git a/python/types.py b/python/types.py index 1cc02691..f66625f8 100644 --- a/python/types.py +++ b/python/types.py @@ -446,14 +446,13 @@ class Type(object): return core.BNGenerateAutoTypeId(source, name) @classmethod - def generate_auto_platform_type_id(self, name): + def generate_auto_demangled_type_id(self, name): name = QualifiedName(name)._get_core_struct() - return core.BNGenerateAutoTypeId(name) + return core.BNGenerateAutoDemangledTypeId(name) @classmethod - def generate_auto_demangled_type_id(self, name): - name = QualifiedName(name)._get_core_struct() - return core.BNGenerateAutoTypeId(name) + def get_auto_demanged_type_id_source(self): + return core.BNGetAutoDemangledTypeIdSource() def __setattr__(self, name, value): try: @@ -523,13 +522,8 @@ class NamedTypeReference(object): return NamedTypeReference(type_class, type_id, name) @classmethod - def generate_auto_platform_type_ref(self, type_class, source, name): - type_id = Type.generate_auto_platform_type_id(source, name) - return NamedTypeReference(type_class, type_id, name) - - @classmethod - def generate_auto_demangled_type_ref(self, type_class, source, name): - type_id = Type.generate_auto_demangled_type_id(source, name) + def generate_auto_demangled_type_ref(self, type_class, name): + type_id = Type.generate_auto_demangled_type_id(name) return NamedTypeReference(type_class, type_id, name) diff --git a/type.cpp b/type.cpp index dd1fb8d6..66138001 100644 --- a/type.cpp +++ b/type.cpp @@ -580,26 +580,30 @@ void Type::SetFunctionCanReturn(bool canReturn) string Type::GenerateAutoTypeId(const string& source, const QualifiedName& name) { BNQualifiedName nameObj = name.GetAPIObject(); - string result = BNGenerateAutoTypeId(source.c_str(), &nameObj); + char* str = BNGenerateAutoTypeId(source.c_str(), &nameObj); + string result = str; QualifiedName::FreeAPIObject(&nameObj); + BNFreeString(str); return result; } -string Type::GenerateAutoPlatformTypeId(const QualifiedName& name) +string Type::GenerateAutoDemangledTypeId(const QualifiedName& name) { BNQualifiedName nameObj = name.GetAPIObject(); - string result = BNGenerateAutoPlatformTypeId(&nameObj); + char* str = BNGenerateAutoDemangledTypeId(&nameObj); + string result = str; QualifiedName::FreeAPIObject(&nameObj); + BNFreeString(str); return result; } -string Type::GenerateAutoDemangledTypeId(const QualifiedName& name) +string Type::GetAutoDemangledTypeIdSource() { - BNQualifiedName nameObj = name.GetAPIObject(); - string result = BNGenerateAutoDemangledTypeId(&nameObj); - QualifiedName::FreeAPIObject(&nameObj); + char* str = BNGetAutoDemangledTypeIdSource(); + string result = str; + BNFreeString(str); return result; } @@ -679,14 +683,6 @@ Ref NamedTypeReference::GenerateAutoTypeReference(BNNamedTyp } -Ref NamedTypeReference::GenerateAutoPlatformTypeReference(BNNamedTypeReferenceClass cls, - const QualifiedName& name) -{ - string id = Type::GenerateAutoPlatformTypeId(name); - return new NamedTypeReference(cls, id, name); -} - - Ref NamedTypeReference::GenerateAutoDemangledTypeReference(BNNamedTypeReferenceClass cls, const QualifiedName& name) { -- cgit v1.3.1 From f8687791c32688a78b5e6667b2af9689816e41af Mon Sep 17 00:00:00 2001 From: Rusty Wagner Date: Fri, 10 Feb 2017 16:37:32 -0500 Subject: Merge in pull requests that never made it into dev --- python/architecture.py | 4 ++-- python/binaryview.py | 2 +- python/types.py | 14 ++++++++++++++ 3 files changed, 17 insertions(+), 3 deletions(-) (limited to 'python/binaryview.py') diff --git a/python/architecture.py b/python/architecture.py index f1440ca3..3e899d68 100644 --- a/python/architecture.py +++ b/python/architecture.py @@ -1160,8 +1160,8 @@ class Architecture(object): 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 - address ``addr`` with data ``data``. + ``get_instruction_low_level_il`` appends LowLevelILExpr objects to ``il`` for the instruction at the given + virtual address ``addr`` with data ``data``. :param str data: max_instruction_length bytes from the binary at virtual address ``addr`` :param int addr: virtual address of bytes in ``data`` diff --git a/python/binaryview.py b/python/binaryview.py index 476f2be6..c021024f 100644 --- a/python/binaryview.py +++ b/python/binaryview.py @@ -1933,7 +1933,7 @@ class BinaryView(object): def get_basic_blocks_starting_at(self, addr): """ - ``get_basic_blocks_at`` get a list of :py:Class:`BasicBlock` objects which start at the provided virtual address. + ``get_basic_blocks_starting_at`` get a list of :py:Class:`BasicBlock` objects which start at the provided virtual address. :param int addr: virtual address of BasicBlock desired :return: a list of :py:Class:`BasicBlock` objects diff --git a/python/types.py b/python/types.py index 8582e4e0..62a441cd 100644 --- a/python/types.py +++ b/python/types.py @@ -237,6 +237,12 @@ class Type(object): @classmethod def int(self, width, sign = True, altname=""): + """ + ``int`` class method for creating an int Type. + + :param int width: width of the integer in bytes + :param bool sign: optional variable representing signedness + """ return Type(core.BNCreateIntegerType(width, sign, altname)) @classmethod @@ -267,6 +273,14 @@ class Type(object): @classmethod def function(self, ret, params, calling_convention=None, variable_arguments=False): + """ + ``function`` class method for creating an function Type. + + :param Type ret: width of the integer in bytes + :param list(Type) params: list of parameter Types + :param CallingConvention calling_convention: optional argument for function calling convention + :param bool variable_arguments: optional argument for functions that have a variable number of arguments + """ param_buf = (core.BNNameAndType * len(params))() for i in xrange(0, len(params)): if isinstance(params[i], Type): -- cgit v1.3.1 From 57c08987ee10af0b52d5c3fd44739a3935f9efa7 Mon Sep 17 00:00:00 2001 From: Rusty Wagner Date: Thu, 16 Feb 2017 19:12:43 -0500 Subject: Basic blocks have incoming and outgoing edges with basic block references, use core object identity for equality --- basicblock.cpp | 30 +++++++++++++++++++++--- binaryninjaapi.h | 42 ++++++++++++++++++++++++++++++---- binaryninjacore.h | 7 +++--- python/architecture.py | 10 ++++++++ python/basicblock.py | 56 +++++++++++++++++++++++++++++++++------------ python/binaryview.py | 40 ++++++++++++++++++++++++++++++++ python/callingconvention.py | 10 ++++++++ python/filemetadata.py | 10 ++++++++ python/function.py | 30 ++++++++++++++++++++++++ python/lowlevelil.py | 10 ++++++++ python/platform.py | 10 ++++++++ python/transform.py | 10 ++++++++ python/types.py | 50 ++++++++++++++++++++++++++++++++++++++++ 13 files changed, 291 insertions(+), 24 deletions(-) (limited to 'python/binaryview.py') diff --git a/basicblock.cpp b/basicblock.cpp index 4edcc568..153a7768 100644 --- a/basicblock.cpp +++ b/basicblock.cpp @@ -108,6 +108,12 @@ uint64_t BasicBlock::GetLength() const } +size_t BasicBlock::GetIndex() const +{ + return BNGetBasicBlockIndex(m_object); +} + + vector BasicBlock::GetOutgoingEdges() const { size_t count; @@ -118,12 +124,30 @@ vector BasicBlock::GetOutgoingEdges() const { BasicBlockEdge edge; edge.type = array[i].type; - edge.target = array[i].target; - edge.arch = array[i].arch ? new CoreArchitecture(array[i].arch) : nullptr; + edge.target = array[i].target ? new BasicBlock(BNNewBasicBlockReference(array[i].target)) : nullptr; + result.push_back(edge); + } + + BNFreeBasicBlockEdgeList(array, count); + return result; +} + + +vector BasicBlock::GetIncomingEdges() const +{ + size_t count; + BNBasicBlockEdge* array = BNGetBasicBlockIncomingEdges(m_object, &count); + + vector result; + for (size_t i = 0; i < count; i++) + { + BasicBlockEdge edge; + edge.type = array[i].type; + edge.target = array[i].target ? new BasicBlock(BNNewBasicBlockReference(array[i].target)) : nullptr; result.push_back(edge); } - BNFreeBasicBlockOutgoingEdgeList(array); + BNFreeBasicBlockEdgeList(array, count); return result; } diff --git a/binaryninjaapi.h b/binaryninjaapi.h index 370a9ae2..7004501c 100644 --- a/binaryninjaapi.h +++ b/binaryninjaapi.h @@ -51,6 +51,8 @@ namespace BinaryNinja RefCountObject(): m_refs(0) {} virtual ~RefCountObject() {} + RefCountObject* GetObject() { return this; } + void AddRef() { #ifdef WIN32 @@ -101,7 +103,7 @@ namespace BinaryNinja CoreRefCountObject(): m_refs(0), m_object(nullptr) {} virtual ~CoreRefCountObject() {} - T* GetObject() { return m_object; } + T* GetObject() const { return m_object; } void AddRef() { @@ -158,7 +160,7 @@ namespace BinaryNinja StaticCoreRefCountObject(): m_refs(0), m_object(nullptr) {} virtual ~StaticCoreRefCountObject() {} - T* GetObject() { return m_object; } + T* GetObject() const { return m_object; } void AddRef() { @@ -246,6 +248,36 @@ namespace BinaryNinja return m_obj == NULL; } + bool operator==(const T* obj) const + { + return m_obj->GetObject() == obj->GetObject(); + } + + bool operator==(const Ref& obj) const + { + return m_obj->GetObject() == obj.m_obj->GetObject(); + } + + bool operator!=(const T* obj) const + { + return m_obj->GetObject() != obj->GetObject(); + } + + bool operator!=(const Ref& obj) const + { + return m_obj->GetObject() != obj.m_obj->GetObject(); + } + + bool operator<(const T* obj) const + { + return m_obj->GetObject() < obj->GetObject(); + } + + bool operator<(const Ref& obj) const + { + return m_obj->GetObject() < obj.m_obj->GetObject(); + } + T* GetPtr() const { return m_obj; @@ -1728,8 +1760,7 @@ namespace BinaryNinja struct BasicBlockEdge { BNBranchType type; - uint64_t target; - Ref arch; + Ref target; }; class BasicBlock: public CoreRefCountObject @@ -1744,7 +1775,10 @@ namespace BinaryNinja uint64_t GetEnd() const; uint64_t GetLength() const; + size_t GetIndex() const; + std::vector GetOutgoingEdges() const; + std::vector GetIncomingEdges() const; bool HasUndeterminedOutgoingEdges() const; void MarkRecentUse(); diff --git a/binaryninjacore.h b/binaryninjacore.h index b8531742..2d22bb3f 100644 --- a/binaryninjacore.h +++ b/binaryninjacore.h @@ -793,8 +793,7 @@ extern "C" struct BNBasicBlockEdge { BNBranchType type; - uint64_t target; - BNArchitecture* arch; + BNBasicBlock* target; }; struct BNPoint @@ -1726,8 +1725,10 @@ extern "C" BINARYNINJACOREAPI uint64_t BNGetBasicBlockEnd(BNBasicBlock* block); BINARYNINJACOREAPI uint64_t BNGetBasicBlockLength(BNBasicBlock* block); BINARYNINJACOREAPI BNBasicBlockEdge* BNGetBasicBlockOutgoingEdges(BNBasicBlock* block, size_t* count); - BINARYNINJACOREAPI void BNFreeBasicBlockOutgoingEdgeList(BNBasicBlockEdge* edges); + BINARYNINJACOREAPI BNBasicBlockEdge* BNGetBasicBlockIncomingEdges(BNBasicBlock* block, size_t* count); + BINARYNINJACOREAPI void BNFreeBasicBlockEdgeList(BNBasicBlockEdge* edges, size_t count); BINARYNINJACOREAPI bool BNBasicBlockHasUndeterminedOutgoingEdges(BNBasicBlock* block); + BINARYNINJACOREAPI size_t BNGetBasicBlockIndex(BNBasicBlock* block); BINARYNINJACOREAPI BNDisassemblyTextLine* BNGetBasicBlockDisassemblyText(BNBasicBlock* block, BNDisassemblySettings* settings, size_t* count); diff --git a/python/architecture.py b/python/architecture.py index 5bafe949..39e5e72d 100644 --- a/python/architecture.py +++ b/python/architecture.py @@ -333,6 +333,16 @@ class Architecture(object): self._pending_reg_lists = {} self._pending_token_lists = {} + def __eq__(self, value): + if not isinstance(value, Architecture): + return False + return ctypes.addressof(self.handle.contents) == ctypes.addressof(value.handle.contents) + + def __ne__(self, value): + if not isinstance(value, Architecture): + return True + return ctypes.addressof(self.handle.contents) != ctypes.addressof(value.handle.contents) + @property def full_width_regs(self): """List of full width register strings (read-only)""" diff --git a/python/basicblock.py b/python/basicblock.py index f6dbd60d..ebacb311 100644 --- a/python/basicblock.py +++ b/python/basicblock.py @@ -29,19 +29,17 @@ import function class BasicBlockEdge(object): - def __init__(self, branch_type, target, arch): + def __init__(self, branch_type, target): self.type = branch_type - if self.type != BranchType.UnresolvedBranch: - self.target = target - self.arch = arch + self.target = target def __repr__(self): if self.type == BranchType.UnresolvedBranch: return "<%s>" % BranchType(self.type).name - elif self.arch: - return "<%s: %s@%#x>" % (self.type, self.arch.name, self.target) + elif self.target.arch: + return "<%s: %s@%#x>" % (BranchType(self.type).name, self.target.arch.name, self.target.start) else: - return "<%s: %#x>" % (self.type, self.target) + return "<%s: %#x>" % (BranchType(self.type).name, self.target.start) class BasicBlock(object): @@ -52,6 +50,16 @@ class BasicBlock(object): def __del__(self): core.BNFreeBasicBlock(self.handle) + def __eq__(self, value): + if not isinstance(value, BasicBlock): + return False + return ctypes.addressof(self.handle.contents) == ctypes.addressof(value.handle.contents) + + def __ne__(self, value): + if not isinstance(value, BasicBlock): + return True + return ctypes.addressof(self.handle.contents) != ctypes.addressof(value.handle.contents) + @property def function(self): """Basic block function (read-only)""" @@ -83,6 +91,11 @@ class BasicBlock(object): """Basic block length (read-only)""" return core.BNGetBasicBlockLength(self.handle) + @property + def index(self): + """Basic block index in list of blocks for the function (read-only)""" + return core.BNGetBasicBlockIndex(self.handle) + @property def outgoing_edges(self): """List of basic block outgoing edges (read-only)""" @@ -90,14 +103,29 @@ class BasicBlock(object): edges = core.BNGetBasicBlockOutgoingEdges(self.handle, count) result = [] for i in xrange(0, count.value): - branch_type = edges[i].type - target = edges[i].target - if edges[i].arch: - arch = architecture.Architecture(edges[i].arch) + branch_type = BranchType(edges[i].type) + if edges[i].target: + target = BasicBlock(self.view, core.BNNewBasicBlockReference(edges[i].target)) + else: + target = None + result.append(BasicBlockEdge(branch_type, target)) + core.BNFreeBasicBlockEdgeList(edges, count.value) + return result + + @property + def incoming_edges(self): + """List of basic block incoming edges (read-only)""" + count = ctypes.c_ulonglong(0) + edges = core.BNGetBasicBlockIncomingEdges(self.handle, count) + result = [] + for i in xrange(0, count.value): + branch_type = BranchType(edges[i].type) + if edges[i].target: + target = BasicBlock(self.view, core.BNNewBasicBlockReference(edges[i].target)) else: - arch = None - result.append(BasicBlockEdge(branch_type, target, arch)) - core.BNFreeBasicBlockOutgoingEdgeList(edges) + target = None + result.append(BasicBlockEdge(branch_type, target)) + core.BNFreeBasicBlockEdgeList(edges, count.value) return result @property diff --git a/python/binaryview.py b/python/binaryview.py index 9753b653..dd37be69 100644 --- a/python/binaryview.py +++ b/python/binaryview.py @@ -299,6 +299,16 @@ class BinaryViewType(object): def __init__(self, handle): self.handle = core.handle_of_type(handle, core.BNBinaryViewType) + def __eq__(self, value): + if not isinstance(value, BinaryViewType): + return False + return ctypes.addressof(self.handle.contents) == ctypes.addressof(value.handle.contents) + + def __ne__(self, value): + if not isinstance(value, BinaryViewType): + return True + return ctypes.addressof(self.handle.contents) != ctypes.addressof(value.handle.contents) + @property def name(self): """BinaryView name (read-only)""" @@ -547,6 +557,16 @@ class BinaryView(object): self.notifications = {} self.next_address = None # Do NOT try to access view before init() is called, use placeholder + def __eq__(self, value): + if not isinstance(value, BinaryView): + return False + return ctypes.addressof(self.handle.contents) == ctypes.addressof(value.handle.contents) + + def __ne__(self, value): + if not isinstance(value, BinaryView): + return True + return ctypes.addressof(self.handle.contents) != ctypes.addressof(value.handle.contents) + @classmethod def register(cls): startup._init_plugins() @@ -3255,6 +3275,16 @@ class BinaryReader(object): def __del__(self): core.BNFreeBinaryReader(self.handle) + def __eq__(self, value): + if not isinstance(value, BinaryReader): + return False + return ctypes.addressof(self.handle.contents) == ctypes.addressof(value.handle.contents) + + def __ne__(self, value): + if not isinstance(value, BinaryReader): + return True + return ctypes.addressof(self.handle.contents) != ctypes.addressof(value.handle.contents) + @property def endianness(self): """ @@ -3562,6 +3592,16 @@ class BinaryWriter(object): def __del__(self): core.BNFreeBinaryWriter(self.handle) + def __eq__(self, value): + if not isinstance(value, BinaryWriter): + return False + return ctypes.addressof(self.handle.contents) == ctypes.addressof(value.handle.contents) + + def __ne__(self, value): + if not isinstance(value, BinaryWriter): + return True + return ctypes.addressof(self.handle.contents) != ctypes.addressof(value.handle.contents) + @property def endianness(self): """ diff --git a/python/callingconvention.py b/python/callingconvention.py index 5f4adeab..04ba711f 100644 --- a/python/callingconvention.py +++ b/python/callingconvention.py @@ -112,6 +112,16 @@ class CallingConvention(object): def __del__(self): core.BNFreeCallingConvention(self.handle) + def __eq__(self, value): + if not isinstance(value, CallingConvention): + return False + return ctypes.addressof(self.handle.contents) == ctypes.addressof(value.handle.contents) + + def __ne__(self, value): + if not isinstance(value, CallingConvention): + return True + return ctypes.addressof(self.handle.contents) != ctypes.addressof(value.handle.contents) + def _get_caller_saved_regs(self, ctxt, count): try: regs = self.__class__.caller_saved_regs diff --git a/python/filemetadata.py b/python/filemetadata.py index f6593405..b489d5bb 100644 --- a/python/filemetadata.py +++ b/python/filemetadata.py @@ -93,6 +93,16 @@ class FileMetadata(object): core.BNSetFileMetadataNavigationHandler(self.handle, None) core.BNFreeFileMetadata(self.handle) + def __eq__(self, value): + if not isinstance(value, FileMetadata): + return False + return ctypes.addressof(self.handle.contents) == ctypes.addressof(value.handle.contents) + + def __ne__(self, value): + if not isinstance(value, FileMetadata): + return True + return ctypes.addressof(self.handle.contents) != ctypes.addressof(value.handle.contents) + @classmethod def _unregister(cls, f): handle = ctypes.cast(f, ctypes.c_void_p) diff --git a/python/function.py b/python/function.py index 3aeb8e22..4cdd6cc9 100644 --- a/python/function.py +++ b/python/function.py @@ -177,6 +177,16 @@ class Function(object): core.BNReleaseAdvancedFunctionAnalysisDataMultiple(self.handle, self._advanced_analysis_requests) core.BNFreeFunction(self.handle) + def __eq__(self, value): + if not isinstance(value, Function): + return False + return ctypes.addressof(self.handle.contents) == ctypes.addressof(value.handle.contents) + + def __ne__(self, value): + if not isinstance(value, Function): + return True + return ctypes.addressof(self.handle.contents) != ctypes.addressof(value.handle.contents) + @classmethod def _unregister(cls, func): handle = ctypes.cast(func, ctypes.c_void_p) @@ -856,6 +866,16 @@ class FunctionGraphBlock(object): def __del__(self): core.BNFreeFunctionGraphBlock(self.handle) + def __eq__(self, value): + if not isinstance(value, FunctionGraphBlock): + return False + return ctypes.addressof(self.handle.contents) == ctypes.addressof(value.handle.contents) + + def __ne__(self, value): + if not isinstance(value, FunctionGraphBlock): + return True + return ctypes.addressof(self.handle.contents) != ctypes.addressof(value.handle.contents) + @property def basic_block(self): """Basic block associated with this part of the function graph (read-only)""" @@ -1030,6 +1050,16 @@ class FunctionGraph(object): self.abort() core.BNFreeFunctionGraph(self.handle) + def __eq__(self, value): + if not isinstance(value, FunctionGraph): + return False + return ctypes.addressof(self.handle.contents) == ctypes.addressof(value.handle.contents) + + def __ne__(self, value): + if not isinstance(value, FunctionGraph): + return True + return ctypes.addressof(self.handle.contents) != ctypes.addressof(value.handle.contents) + @property def function(self): """Function for a function graph (read-only)""" diff --git a/python/lowlevelil.py b/python/lowlevelil.py index 29b46b65..c80fcd0d 100644 --- a/python/lowlevelil.py +++ b/python/lowlevelil.py @@ -253,6 +253,16 @@ class LowLevelILFunction(object): def __del__(self): core.BNFreeLowLevelILFunction(self.handle) + def __eq__(self, value): + if not isinstance(value, LowLevelILFunction): + return False + return ctypes.addressof(self.handle.contents) == ctypes.addressof(value.handle.contents) + + def __ne__(self, value): + if not isinstance(value, LowLevelILFunction): + return True + return ctypes.addressof(self.handle.contents) != ctypes.addressof(value.handle.contents) + @property def current_address(self): """Current IL Address (read/write)""" diff --git a/python/platform.py b/python/platform.py index ccc80476..139b7d5e 100644 --- a/python/platform.py +++ b/python/platform.py @@ -110,6 +110,16 @@ class Platform(object): def __del__(self): core.BNFreePlatform(self.handle) + def __eq__(self, value): + if not isinstance(value, Platform): + return False + return ctypes.addressof(self.handle.contents) == ctypes.addressof(value.handle.contents) + + def __ne__(self, value): + if not isinstance(value, Platform): + return True + return ctypes.addressof(self.handle.contents) != ctypes.addressof(value.handle.contents) + @property def default_calling_convention(self): """ diff --git a/python/transform.py b/python/transform.py index 0c003738..40382c69 100644 --- a/python/transform.py +++ b/python/transform.py @@ -131,6 +131,16 @@ class Transform(object): def __repr__(self): return "" % self.name + def __eq__(self, value): + if not isinstance(value, Transform): + return False + return ctypes.addressof(self.handle.contents) == ctypes.addressof(value.handle.contents) + + def __ne__(self, value): + if not isinstance(value, Transform): + return True + return ctypes.addressof(self.handle.contents) != ctypes.addressof(value.handle.contents) + def _get_parameters(self, ctxt, count): try: count[0] = len(self.parameters) diff --git a/python/types.py b/python/types.py index 43aaa66f..ebaa36fc 100644 --- a/python/types.py +++ b/python/types.py @@ -139,6 +139,16 @@ class Symbol(object): def __del__(self): core.BNFreeSymbol(self.handle) + def __eq__(self, value): + if not isinstance(value, Symbol): + return False + return ctypes.addressof(self.handle.contents) == ctypes.addressof(value.handle.contents) + + def __ne__(self, value): + if not isinstance(value, Symbol): + return True + return ctypes.addressof(self.handle.contents) != ctypes.addressof(value.handle.contents) + @property def type(self): """Symbol type (read-only)""" @@ -194,6 +204,16 @@ class Type(object): def __del__(self): core.BNFreeType(self.handle) + def __eq__(self, value): + if not isinstance(value, Type): + return False + return ctypes.addressof(self.handle.contents) == ctypes.addressof(value.handle.contents) + + def __ne__(self, value): + if not isinstance(value, Type): + return True + return ctypes.addressof(self.handle.contents) != ctypes.addressof(value.handle.contents) + @property def type_class(self): """Type class (read-only)""" @@ -491,6 +511,16 @@ class NamedTypeReference(object): def __del__(self): core.BNFreeNamedTypeReference(self.handle) + def __eq__(self, value): + if not isinstance(value, NamedTypeReference): + return False + return ctypes.addressof(self.handle.contents) == ctypes.addressof(value.handle.contents) + + def __ne__(self, value): + if not isinstance(value, NamedTypeReference): + return True + return ctypes.addressof(self.handle.contents) != ctypes.addressof(value.handle.contents) + @property def type_class(self): return NamedTypeReferenceClass(core.BNGetTypeReferenceClass(self.handle)) @@ -564,6 +594,16 @@ class Structure(object): def __del__(self): core.BNFreeStructure(self.handle) + def __eq__(self, value): + if not isinstance(value, Structure): + return False + return ctypes.addressof(self.handle.contents) == ctypes.addressof(value.handle.contents) + + def __ne__(self, value): + if not isinstance(value, Structure): + return True + return ctypes.addressof(self.handle.contents) != ctypes.addressof(value.handle.contents) + @property def members(self): """Structure member list (read-only)""" @@ -652,6 +692,16 @@ class Enumeration(object): def __del__(self): core.BNFreeEnumeration(self.handle) + def __eq__(self, value): + if not isinstance(value, Enumeration): + return False + return ctypes.addressof(self.handle.contents) == ctypes.addressof(value.handle.contents) + + def __ne__(self, value): + if not isinstance(value, Enumeration): + return True + return ctypes.addressof(self.handle.contents) != ctypes.addressof(value.handle.contents) + @property def members(self): """Enumeration member list (read-only)""" -- cgit v1.3.1