summaryrefslogtreecommitdiff
path: root/python/__init__.py
diff options
context:
space:
mode:
Diffstat (limited to 'python/__init__.py')
-rw-r--r--python/__init__.py1549
1 files changed, 1320 insertions, 229 deletions
diff --git a/python/__init__.py b/python/__init__.py
index b88c5beb..26c8fb5d 100644
--- a/python/__init__.py
+++ b/python/__init__.py
@@ -19,7 +19,15 @@
# IN THE SOFTWARE.
import _binaryninjacore as core
-import ctypes, traceback, json, struct, threading, code, sys
+import abc
+import ctypes
+import traceback
+import json
+import struct
+import threading
+import code
+import sys
+import copy
_plugin_init = False
def _init_plugins():
@@ -31,11 +39,11 @@ def _init_plugins():
if not core.BNIsLicenseValidated():
raise RuntimeError, "License is not valid. Please supply a valid license."
-class DataBuffer:
- def __init__(self, contents = "", handle = None):
+class DataBuffer(object):
+ def __init__(self, contents="", handle=None):
if handle is not None:
self.handle = core.handle_of_type(handle, core.BNDataBuffer)
- elif (type(contents) is int) or (type(contents) is long):
+ elif isinstance(contents, int) or isinstance(contents, long):
self.handle = core.BNCreateDataBuffer(None, contents)
elif isinstance(contents, DataBuffer):
self.handle = core.BNDuplicateDataBuffer(contents.handle)
@@ -123,7 +131,7 @@ class DataBuffer:
return core.BNDataBufferToEscapedString(self.handle)
def unescape(self):
- return DataBuffer(handle = core.BNDecodeEscapedString(str(self)))
+ return DataBuffer(handle=core.BNDecodeEscapedString(str(self)))
def base64_encode(self):
return core.BNDataBufferToBase64(self.handle)
@@ -174,7 +182,35 @@ class NavigationHandler(object):
log_error(traceback.format_exc())
return False
+class _AssociatedDataStore(dict):
+ _defaults = {}
+
+ @classmethod
+ def set_default(cls, name, value):
+ cls._defaults[name] = value
+
+ def __getattr__(self, name):
+ if name in self.__dict__:
+ return self.__dict__[name]
+ if name not in self:
+ if name in self.__class__._defaults:
+ result = copy.copy(self.__class__._defaults[name])
+ self[name] = result
+ return result
+ return self.__getitem__(name)
+
+ def __setattr__(self, name, value):
+ self.__setitem__(name, value)
+
+ def __delattr__(self, name):
+ self.__delitem__(name)
+
+class _FileMetadataAssociatedDataStore(_AssociatedDataStore):
+ _defaults = {}
+
class FileMetadata(object):
+ _associated_data = {}
+
"""
``class FileMetadata`` represents the file being analyzed by Binary Ninja. It is responsible for opening,
closing, creating the database (.bndb) files, and is used to keep track of undoable actions.
@@ -193,13 +229,23 @@ class FileMetadata(object):
self.handle = core.BNCreateFileMetadata()
if filename is not None:
core.BNSetFilename(self.handle, str(filename))
- self.__dict__['navigation'] = None
+ self.nav = None
def __del__(self):
if self.navigation is not None:
core.BNSetFileMetadataNavigationHandler(self.handle, None)
core.BNFreeFileMetadata(self.handle)
+ @classmethod
+ def _unregister(cls, f):
+ handle = ctypes.cast(f, ctypes.c_void_p)
+ if handle.value in cls._associated_data:
+ del cls._associated_data[handle.value]
+
+ @classmethod
+ def set_default_data(cls, name, value):
+ _FileMetadataAssociatedDataStore.set_default(name, value)
+
@property
def filename(self):
"""The name of the file (read/write)"""
@@ -268,6 +314,26 @@ class FileMetadata(object):
else:
core.BNMarkFileModified(self.handle)
+ @property
+ def navigation(self):
+ return self.nav
+
+ @navigation.setter
+ def navigation(self, value):
+ value._register(self.handle)
+ self.nav = value
+
+ @property
+ def data(self):
+ """Dictionary object where plugins can store arbitrary data associated with the file"""
+ handle = ctypes.cast(self.handle, ctypes.c_void_p)
+ if handle.value not in FileMetadata._associated_data:
+ obj = _FileMetadataAssociatedDataStore()
+ FileMetadata._associated_data[handle.value] = obj
+ return obj
+ else:
+ return FileMetadata._associated_data[handle.value]
+
def close(self):
"""
Closes the underlying file handle. It is recommended that this is done in a
@@ -372,18 +438,32 @@ class FileMetadata(object):
def navigate(self, view, offset):
return core.BNNavigate(self.handle, str(view), offset)
- def create_database(self, filename):
-
- return core.BNCreateDatabase(self.raw.handle, str(filename))
+ def create_database(self, filename, progress_func = None):
+ if progress_func is None:
+ return core.BNCreateDatabase(self.raw.handle, str(filename))
+ else:
+ return core.BNCreateDatabaseWithProgress(self.raw.handle, str(filename), None,
+ ctypes.CFUNCTYPE(None, ctypes.c_void_p, ctypes.c_ulonglong, ctypes.c_ulonglong)(
+ lambda ctxt, cur, total: progress_func(cur, total)))
- def open_existing_database(self, filename):
- view = core.BNOpenExistingDatabase(self.handle, str(filename))
+ def open_existing_database(self, filename, progress_func = None):
+ if progress_func is None:
+ view = core.BNOpenExistingDatabase(self.handle, str(filename))
+ else:
+ view = core.BNOpenExistingDatabaseWithProgress(self.handle, str(filename), None,
+ ctypes.CFUNCTYPE(None, ctypes.c_void_p, ctypes.c_ulonglong, ctypes.c_ulonglong)(
+ lambda ctxt, cur, total: progress_func(cur, total)))
if view is None:
return None
return BinaryView(self, handle = view)
- def save_auto_snapshot(self):
- return core.BNSaveAutoSnapshot(self.raw.handle)
+ def save_auto_snapshot(self, progress_func = None):
+ if progress_func is None:
+ return core.BNSaveAutoSnapshot(self.raw.handle)
+ else:
+ return core.BNSaveAutoSnapshotWithProgress(self.raw.handle, None,
+ ctypes.CFUNCTYPE(None, ctypes.c_void_p, ctypes.c_ulonglong, ctypes.c_ulonglong)(
+ lambda ctxt, cur, total: progress_func(cur, total)))
def get_view_of_type(self, name):
view = core.BNGetFileViewOfType(self.handle, str(name))
@@ -397,14 +477,10 @@ class FileMetadata(object):
return BinaryView(self, handle = view)
def __setattr__(self, name, value):
- if name == "navigation":
- value._register(self.handle)
- self.__dict__["navigation"] = value
- else:
- try:
- object.__setattr__(self,name,value)
- except AttributeError:
- raise AttributeError, "attribute '%s' is read only" % name
+ try:
+ object.__setattr__(self,name,value)
+ except AttributeError:
+ raise AttributeError, "attribute '%s' is read only" % name
class FileAccessor:
def __init__(self):
@@ -512,7 +588,7 @@ class UndoAction:
raise TypeError, "undo action type not registered"
action_type = self.__class__.action_type
if isinstance(action_type, str):
- self._cb.type = BNActionType_by_name[action_type]
+ self._cb.type = core.BNActionType_by_name[action_type]
else:
self._cb.type = action_type
self._cb.context = 0
@@ -569,7 +645,7 @@ class UndoAction:
log_error(traceback.format_exc())
return "null"
-class StringReference:
+class StringReference(object):
def __init__(self, string_type, start, length):
self.type = string_type
self.start = start
@@ -578,7 +654,7 @@ class StringReference:
def __repr__(self):
return "<%s: %#x, len %#x>" % (self.type, self.start, self.length)
-class BinaryDataNotificationCallbacks:
+class BinaryDataNotificationCallbacks(object):
def __init__(self, view, notify):
self.view = view
self.notify = notify
@@ -605,7 +681,7 @@ class BinaryDataNotificationCallbacks:
def _data_written(self, ctxt, view, offset, length):
try:
self.notify.data_written(self.view, offset, length)
- except:
+ except OSError:
log_error(traceback.format_exc())
def _data_inserted(self, ctxt, view, offset, length):
@@ -709,7 +785,7 @@ class _BinaryViewTypeMetaclass(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
@@ -770,7 +846,7 @@ class BinaryViewType(object):
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
@@ -817,8 +893,8 @@ class LinearDisassemblyPosition(object):
"""
``class LinearDisassemblyPosition`` is a helper object containing the position of the current Linear Disassembly.
- .. note:: This object should not be instantiated directly. Rather call :py:method:`get_linear_disassembly_position_at` \
- which instantiates this object.
+ .. note:: This object should not be instantiated directly. Rather call \
+ :py:method:`get_linear_disassembly_position_at` which instantiates this object.
"""
def __init__(self, func, block, addr):
self.function = func
@@ -848,6 +924,9 @@ class DataVariable(object):
def __repr__(self):
return "<var 0x%x: %s>" % (self.address, str(self.type))
+class _BinaryViewAssociatedDataStore(_AssociatedDataStore):
+ _defaults = {}
+
class BinaryView(object):
"""
``class BinaryView`` implements a view on binary data, and presents a queryable interface of a binary file. One key
@@ -889,9 +968,11 @@ class BinaryView(object):
externally. Additionanlly, methods which begin with ``perform_`` should not be called either and are
used explicitly for subclassing the BinaryView.
- Another important note is the ``*_user_*()`` methods. These methods are reserved for `undo-able` actions, and thus
- under most circumstances shouldn't be called by plugins, rather methods with the same name without ``_user_`` should
- be used (e.g. ``remove_function()`` rather than ``remove_user_function()``)
+ .. 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
@@ -899,6 +980,7 @@ class BinaryView(object):
_registered_cb = None
registered_view_type = None
next_address = 0
+ _associated_data = {}
def __init__(self, file_metadata = None, handle = None):
if handle is not None:
@@ -940,7 +1022,7 @@ class BinaryView(object):
self.file = file_metadata
self.handle = core.BNCreateCustomBinaryView(self.__class__.name, file_metadata.handle, self._cb)
self.notifications = {}
- self.next_address = self.entry_point
+ self.next_address = None # Do NOT try to access view before init() is called, use placeholder
@classmethod
def register(cls):
@@ -1007,6 +1089,16 @@ class BinaryView(object):
result = BinaryView(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_data(cls, name, value):
+ _BinaryViewAssociatedDataStore.set_default(name, value)
+
def __del__(self):
for i in self.notifications.values():
i._unregister()
@@ -1218,6 +1310,17 @@ class BinaryView(object):
core.BNFreeTypeList(type_list, count.value)
return result
+ @property
+ def 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))
@@ -1476,12 +1579,27 @@ class BinaryView(object):
"""
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()
+ @abc.abstractmethod
+ def perform_save(self, accessor):
+ raise NotImplementedError
+
+ @abc.abstractmethod
+ def perform_get_address_size(self):
+ raise NotImplementedError
+
+ @abc.abstractmethod
+ def perform_get_length(self):
+ raise NotImplementedError
+
+ @abc.abstractmethod
def perform_read(self, addr, length):
"""
``perform_read`` implements a mapping between a virtual address and an absolute file offset, reading
@@ -1496,8 +1614,9 @@ class BinaryView(object):
:return: length bytes read from addr, should return empty string on error
:rtype: int
"""
- return ""
+ raise NotImplementedError
+ @abc.abstractmethod
def perform_write(self, addr, data):
"""
``perform_write`` implements a mapping between a virtual address and an absolute file offset, writing
@@ -1512,8 +1631,9 @@ class BinaryView(object):
:return: length of data written, should return 0 on error
:rtype: int
"""
- return 0
+ raise NotImplementedError
+ @abc.abstractmethod
def perform_insert(self, addr, data):
"""
``perform_insert`` implements a mapping between a virtual address and an absolute file offset, inserting
@@ -1528,8 +1648,9 @@ class BinaryView(object):
:return: length of data inserted, should return 0 on error
:rtype: int
"""
- return 0
+ raise NotImplementedError
+ @abc.abstractmethod
def perform_remove(self, addr, length):
"""
``perform_remove`` implements a mapping between a virtual address and an absolute file offset, removing
@@ -1544,8 +1665,9 @@ class BinaryView(object):
:return: length of data removed, should return 0 on error
:rtype: int
"""
- return 0
+ raise NotImplementedError
+ @abc.abstractmethod
def perform_get_modification(self, addr):
"""
``perform_get_modification`` implements query to the whether the virtual address ``addr`` is modified.
@@ -1559,6 +1681,7 @@ class BinaryView(object):
"""
return core.Original
+ @abc.abstractmethod
def perform_is_valid_offset(self, addr):
"""
``perform_is_valid_offset`` implements a check if an virtual address ``addr`` is valid.
@@ -1574,6 +1697,7 @@ class BinaryView(object):
data = self.read(addr, 1)
return (data is not None) and (len(data) == 1)
+ @abc.abstractmethod
def perform_is_offset_readable(self, offset):
"""
``perform_is_offset_readable`` implements a check if an virtual address is readable.
@@ -1588,6 +1712,7 @@ class BinaryView(object):
"""
return self.is_valid_offset(offset)
+ @abc.abstractmethod
def perform_is_offset_writable(self, addr):
"""
``perform_is_offset_writable`` implements a check if a virtual address ``addr`` is writable.
@@ -1602,6 +1727,7 @@ class BinaryView(object):
"""
return self.is_valid_offset(addr)
+ @abc.abstractmethod
def perform_is_offset_executable(self, addr):
"""
``perform_is_offset_writable`` implements a check if a virtual address ``addr`` is executable.
@@ -1616,6 +1742,7 @@ class BinaryView(object):
"""
return self.is_valid_offset(addr)
+ @abc.abstractmethod
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
@@ -1632,6 +1759,7 @@ class BinaryView(object):
return self.perform_get_start()
return addr
+ @abc.abstractmethod
def perform_get_start(self):
"""
``perform_get_start`` implements a query for the first readable, writable, or executable virtual address in
@@ -1645,6 +1773,7 @@ class BinaryView(object):
"""
return 0
+ @abc.abstractmethod
def perform_get_entry_point(self):
"""
``perform_get_entry_point`` implements a query for the initial entry point for code execution.
@@ -1657,6 +1786,7 @@ class BinaryView(object):
"""
return 0
+ @abc.abstractmethod
def perform_is_executable(self):
"""
``perform_is_executable`` implements a check which returns true if the BinaryView is executable.
@@ -1667,13 +1797,14 @@ class BinaryView(object):
:return: true if the current BinaryView is executable, false if it is not executable or on error
:rtype: bool
"""
- return False
+ raise NotImplementedError
+ @abc.abstractmethod
def perform_get_default_endianness(self):
"""
``perform_get_default_endianness`` implements a check which returns true if the BinaryView is executable.
- .. note:: This method **must** be implemented for custom BinaryViews that are not LittleEndian.
+ .. note:: This method **may** be implemented for custom BinaryViews that are not LittleEndian.
.. warning:: This method **must not** be called directly.
:return: either ``core.LittleEndian`` or ``core.BigEndian``
@@ -1681,26 +1812,28 @@ class BinaryView(object):
"""
return core.LittleEndian
- def create_database(self, filename):
+ 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)
+ return self.file.create_database(filename, progress_func)
- def save_auto_snapshot(self):
+ 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()
+ return self.file.save_auto_snapshot(progress_func)
def get_view_of_type(self, name):
"""
@@ -1900,7 +2033,7 @@ class BinaryView(object):
if length is None:
return core.BNGetModification(self.handle, addr)
data = (core.BNModificationStatus * length)()
- length = core.BNGetModificationArray(self.handle, addr, data, length);
+ length = core.BNGetModificationArray(self.handle, addr, data, length)
return data[0:length]
def is_valid_offset(self, addr):
@@ -1915,7 +2048,7 @@ class BinaryView(object):
def is_offset_readable(self, addr):
"""
- ``is_valid_offset`` checks if an virtual address ``addr`` is valid for reading.
+ ``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
@@ -1925,7 +2058,7 @@ class BinaryView(object):
def is_offset_writable(self, addr):
"""
- ``is_valid_offset`` checks if an virtual address ``addr`` is valid for writing.
+ ``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
@@ -1935,7 +2068,7 @@ class BinaryView(object):
def is_offset_executable(self, addr):
"""
- ``is_valid_offset`` checks if an virtual address ``addr`` is valid for executing.
+ ``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
@@ -2232,6 +2365,22 @@ class BinaryView(object):
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(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:
@@ -3213,6 +3362,31 @@ class BinaryView(object):
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 __setattr__(self, name, value):
try:
object.__setattr__(self,name,value)
@@ -3839,7 +4013,7 @@ class Type(object):
@property
def type_class(self):
"""Type class (read-only)"""
- return BNTypeClass_names[core.BNGetTypeClass(self.handle)]
+ return core.BNTypeClass_names[core.BNGetTypeClass(self.handle)]
@property
def width(self):
@@ -3969,8 +4143,12 @@ class Type(object):
return Type(core.BNCreateFloatType(width))
@classmethod
- def structure_type(self, s):
- return Type(core.BNCreateStructureType(s.handle))
+ 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):
@@ -3991,7 +4169,7 @@ class Type(object):
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].name = ""
param_buf[i].type = params[i].handle
else:
param_buf[i].name = params[i][1]
@@ -4007,7 +4185,32 @@ class Type(object):
except AttributeError:
raise AttributeError, "attribute '%s' is read only" % name
-class StructureMember:
+
+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 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
@@ -4031,7 +4234,12 @@ class Structure(object):
@property
def name(self):
- return core.BNGetStructureName(self.handle)
+ count = ctypes.c_ulonglong()
+ nameList = core.BNGetStructureName(self.handle, count)
+ result = []
+ for i in xrange(count.value):
+ result.append(nameList[i])
+ return get_qualified_name(result)
@name.setter
def name(self, value):
@@ -4095,7 +4303,7 @@ class Structure(object):
def remove(self, i):
core.BNRemoveStructureMember(self.handle, i)
-class EnumerationMember:
+class EnumerationMember(object):
def __init__(self, name, value, default):
self.name = name
self.value = value
@@ -4150,7 +4358,7 @@ class Enumeration(object):
else:
core.BNAddEnumerationMemberWithValue(self.handle, name, value)
-class LookupTableEntry:
+class LookupTableEntry(object):
def __init__(self, from_values, to_value):
self.from_values = from_values
self.to_value = to_value
@@ -4158,19 +4366,19 @@ class LookupTableEntry:
def __repr__(self):
return "[%s] -> %#x" % (', '.join(["%#x" % i for i in self.from_values]), self.to_value)
-class RegisterValue:
+class RegisterValue(object):
def __init__(self, arch, value):
self.type = value.state
- if value.state == EntryValue:
+ if value.state == core.EntryValue:
self.reg = arch.get_reg_name(value.reg)
- elif value.state == OffsetFromEntryValue:
+ elif value.state == core.OffsetFromEntryValue:
self.reg = arch.get_reg_name(value.reg)
self.offset = value.value
- elif value.state == ConstantValue:
+ elif value.state == core.ConstantValue:
self.value = value.value
- elif value.state == StackFrameOffset:
+ elif value.state == core.StackFrameOffset:
self.offset = value.value
- elif value.state == SignedRangeValue:
+ elif value.state == core.SignedRangeValue:
self.offset = value.value
self.start = value.rangeStart
self.end = value.rangeEnd
@@ -4179,12 +4387,12 @@ class RegisterValue:
self.start |= ~((1 << 63) - 1)
if self.end & (1 << 63):
self.end |= ~((1 << 63) - 1)
- elif value.state == UnsignedRangeValue:
+ elif value.state == core.UnsignedRangeValue:
self.offset = value.value
self.start = value.rangeStart
self.end = value.rangeEnd
self.step = value.rangeStep
- elif value.state == LookupTableValue:
+ elif value.state == core.LookupTableValue:
self.table = []
self.mapping = {}
for i in xrange(0, value.rangeEnd):
@@ -4193,29 +4401,29 @@ class RegisterValue:
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 == OffsetFromUndeterminedValue:
+ elif value.state == core.OffsetFromUndeterminedValue:
self.offset = value.value
def __repr__(self):
- if self.type == EntryValue:
+ if self.type == core.EntryValue:
return "<entry %s>" % self.reg
- if self.type == OffsetFromEntryValue:
+ if self.type == core.OffsetFromEntryValue:
return "<entry %s + %#x>" % (self.reg, self.offset)
- if self.type == ConstantValue:
+ if self.type == core.ConstantValue:
return "<const %#x>" % self.value
- if self.type == StackFrameOffset:
+ if self.type == core.StackFrameOffset:
return "<stack frame offset %#x>" % self.offset
- if (self.type == SignedRangeValue) or (self.type == UnsignedRangeValue):
+ if (self.type == core.SignedRangeValue) or (self.type == core.UnsignedRangeValue):
if self.step == 1:
return "<range: %#x to %#x>" % (self.start, self.end)
return "<range: %#x to %#x, step %#x>" % (self.start, self.end, self.step)
- if self.type == LookupTableValue:
+ if self.type == core.LookupTableValue:
return "<table: %s>" % ', '.join([repr(i) for i in self.table])
- if self.type == OffsetFromUndeterminedValue:
+ if self.type == core.OffsetFromUndeterminedValue:
return "<undetermined with offset %#x>" % self.offset
return "<undetermined>"
-class StackVariable:
+class StackVariable(object):
def __init__(self, ofs, name, t):
self.offset = ofs
self.name = name
@@ -4246,6 +4454,16 @@ class StackVariableReference:
return "<operand %d ref to %s%+#x>" % (self.source_operand, self.name, self.referenced_offset)
return "<operand %d ref to %s>" % (self.source_operand, self.name)
+class ConstantReference:
+ def __init__(self, val, size):
+ self.value = val
+ self.size = size
+
+ def __repr__(self):
+ if self.size == 0:
+ return "<constant %#x>" % self.value
+ return "<constant %#x size %d>" % (self.value, self.size)
+
class IndirectBranchInfo:
def __init__(self, source_arch, source_addr, dest_arch, dest_addr, auto_defined):
self.source_arch = source_arch
@@ -4257,14 +4475,119 @@ class IndirectBranchInfo:
def __repr__(self):
return "<branch %s:%#x -> %s:%#x>" % (self.source_arch.name, self.source_addr, self.dest_arch.name, self.dest_addr)
+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.CustomHighlightColor
+ self.red = red
+ self.green = green
+ self.blue = blue
+ elif (mix_color is not None) and (mix is not None):
+ self.style = core.MixedHighlightColor
+ if color is None:
+ self.color = core.NoHighlightColor
+ else:
+ self.color = color
+ self.mix_color = mix_color
+ self.mix = mix
+ else:
+ self.style = core.StandardHighlightColor
+ if color is None:
+ self.color = core.NoHighlightColor
+ else:
+ self.color = color
+ self.alpha = alpha
+
+ def _standard_color_to_str(self, color):
+ if color == core.NoHighlightColor:
+ return "none"
+ if color == core.BlueHighlightColor:
+ return "blue"
+ if color == core.GreenHighlightColor:
+ return "green"
+ if color == core.CyanHighlightColor:
+ return "cyan"
+ if color == core.RedHighlightColor:
+ return "red"
+ if color == core.MagentaHighlightColor:
+ return "magenta"
+ if color == core.YellowHighlightColor:
+ return "yellow"
+ if color == core.OrangeHighlightColor:
+ return "orange"
+ if color == core.WhiteHighlightColor:
+ return "white"
+ if color == core.BlackHighlightColor:
+ return "black"
+ return "%d" % color
+
+ def __repr__(self):
+ if self.style == core.StandardHighlightColor:
+ if self.alpha == 255:
+ return "<color: %s>" % self._standard_color_to_str(self.color)
+ return "<color: %s, alpha %d>" % (self._standard_color_to_str(self.color), self.alpha)
+ if self.style == core.MixedHighlightColor:
+ if self.alpha == 255:
+ return "<color: mix %s to %s factor %d>" % (self._standard_color_to_str(self.color),
+ self._standard_color_to_str(self.mix_color), self.mix)
+ return "<color: mix %s to %s factor %d, alpha %d>" % (self._standard_color_to_str(self.color),
+ self._standard_color_to_str(self.mix_color), self.mix, self.alpha)
+ if self.style == core.CustomHighlightColor:
+ if self.alpha == 255:
+ return "<color: #%.2x%.2x%.2x>" % (self.red, self.green, self.blue)
+ return "<color: #%.2x%.2x%.2x, alpha %d>" % (self.red, self.green, self.blue, self.alpha)
+ return "<color>"
+
+ def _get_core_struct(self):
+ result = core.BNHighlightColor()
+ result.style = self.style
+ result.color = core.NoHighlightColor
+ result.mix_color = core.NoHighlightColor
+ result.mix = 0
+ result.r = 0
+ result.g = 0
+ result.b = 0
+ result.alpha = self.alpha
+
+ if self.style == core.StandardHighlightColor:
+ result.color = self.color
+ elif self.style == core.MixedHighlightColor:
+ result.color = self.color
+ result.mixColor = self.mix_color
+ result.mix = self.mix
+ elif self.style == core.CustomHighlightColor:
+ result.r = self.red
+ result.g = self.green
+ result.b = self.blue
+
+ return result
+
+class _FunctionAssociatedDataStore(_AssociatedDataStore):
+ _defaults = {}
+
class Function(object):
+ _associated_data = {}
+
def __init__(self, view, handle):
self._view = view
self.handle = core.handle_of_type(handle, core.BNFunction)
+ self._advanced_analysis_requests = 0
def __del__(self):
+ if self._advanced_analysis_requests > 0:
+ core.BNReleaseAdvancedFunctionAnalysisDataMultiple(self.handle, self._advanced_analysis_requests)
core.BNFreeFunction(self.handle)
+ @classmethod
+ def _unregister(cls, func):
+ handle = ctypes.cast(func, ctypes.c_void_p)
+ if handle.value in cls._associated_data:
+ del cls._associated_data[handle.value]
+
+ @classmethod
+ def set_default_data(cls, name, value):
+ _FunctionAssociatedDataStore.set_default(name, value)
+
@property
def name(self):
"""Symbol name for the function"""
@@ -4276,7 +4599,7 @@ class Function(object):
if self.symbol is not None:
self.view.undefine_user_symbol(self.symbol)
else:
- symbol = Symbol(FunctionSymbol,self.start,value)
+ symbol = Symbol(core.FunctionSymbol,self.start,value)
self.view.define_user_symbol(symbol)
@property
@@ -4321,6 +4644,11 @@ class Function(object):
return core.BNHasExplicitlyDefinedType(self.handle)
@property
+ def needs_update(self):
+ """Whether the function has analysis that needs to be updated (read-only)"""
+ return core.BNIsFunctionUpdateNeeded(self.handle)
+
+ @property
def basic_blocks(self):
"""List of basic blocks (read-only)"""
count = ctypes.c_ulonglong()
@@ -4343,26 +4671,14 @@ class Function(object):
return result
@property
- def indirect_branches(self):
- count = ctypes.c_ulonglong()
- branches = core.BNGetIndirectBranches(self.handle, count)
- result = []
- for i in xrange(0, count.value):
- result.append(IndirectBranchInfo(Architecture(branches[i].sourceArch), branches[i].sourceAddr, Architecture(branches[i].destArch), branches[i].destAddr, branches[i].autoDefined))
- core.BNFreeIndirectBranchList(branches)
- return result
-
- @property
def low_level_il(self):
"""Function low level IL (read-only)"""
- return LowLevelILFunction(self.arch, core.BNNewLowLevelILFunctionReference(
- core.BNGetFunctionLowLevelIL(self.handle)), self)
+ return LowLevelILFunction(self.arch, core.BNGetFunctionLowLevelIL(self.handle), self)
@property
def lifted_il(self):
"""Function lifted IL (read-only)"""
- return LowLevelILFunction(self.arch, core.BNNewLowLevelILFunctionReference(
- core.BNGetFunctionLiftedIL(self.handle)), self)
+ return LowLevelILFunction(self.arch, core.BNGetFunctionLiftedIL(self.handle), self)
@property
def function_type(self):
@@ -4396,6 +4712,17 @@ class Function(object):
core.BNFreeIndirectBranchList(branches)
return result
+ @property
+ def data(self):
+ """Dictionary object where plugins can store arbitrary data associated with the function"""
+ handle = ctypes.cast(self.handle, ctypes.c_void_p)
+ if handle.value not in Function._associated_data:
+ obj = _FunctionAssociatedDataStore()
+ Function._associated_data[handle.value] = obj
+ return obj
+ else:
+ return Function._associated_data[handle.value]
+
def __iter__(self):
count = ctypes.c_ulonglong()
blocks = core.BNGetFunctionBasicBlockList(self.handle, count)
@@ -4539,6 +4866,15 @@ class Function(object):
core.BNFreeStackVariableReferenceList(refs, count.value)
return result
+ def get_constants_referenced_by(self, arch, addr):
+ count = ctypes.c_ulonglong()
+ refs = core.BNGetConstantsReferencedByInstruction(self.handle, arch.handle, addr, count)
+ result = []
+ for i in xrange(0, count.value):
+ result.append(ConstantReference(refs[i].value, refs[i].size))
+ core.BNFreeConstantReferenceList(refs)
+ return result
+
def get_lifted_il_at(self, arch, addr):
return core.BNGetLiftedILForInstruction(self.handle, arch.handle, addr)
@@ -4645,7 +4981,76 @@ class Function(object):
display_type = core.BNIntegerDisplayType_by_name[display_type]
core.BNSetIntegerConstantDisplayType(self.handle, arch.handle, instr_addr, value, operand, display_type)
-class BasicBlockEdge:
+ def reanalyze(self):
+ """
+ ``reanalyze`` causes this functions to be reanalyzed. This function does not wait for the analysis to finish.
+
+ :rtype: None
+ """
+ core.BNReanalyzeFunction(self.handle)
+
+ def request_advanced_analysis_data(self):
+ core.BNRequestAdvancedFunctionAnalysisData(self.handle)
+ self._advanced_analysis_requests += 1
+
+ def release_advanced_analysis_data(self):
+ core.BNReleaseAdvancedFunctionAnalysisData(self.handle)
+ self._advanced_analysis_requests -= 1
+
+ def get_basic_block_at(self, arch, addr):
+ block = core.BNGetFunctionBasicBlockAtAddress(self.handle, arch.handle, addr)
+ if not block:
+ return None
+ return BasicBlock(self._view, handle = block)
+
+ def get_instr_highlight(self, arch, addr):
+ color = core.BNGetInstructionHighlight(self.handle, arch.handle, addr)
+ if color.style == core.StandardHighlightColor:
+ return HighlightColor(color = color.color, alpha = color.alpha)
+ elif color.style == core.MixedHighlightColor:
+ return HighlightColor(color = color.color, mix_color = color.mixColor, mix = color.mix, alpha = color.alpha)
+ elif color.style == core.CustomHighlightColor:
+ return HighlightColor(red = color.r, green = color.g, blue = color.b, alpha = color.alpha)
+ return HighlightColor(color = core.NoHighlightColor)
+
+ def set_auto_instr_highlight(self, arch, addr, color):
+ if not isinstance(color, HighlightColor):
+ color = HighlightColor(color = color)
+ core.BNSetAutoInstructionHighlight(self.handle, arch.handle, addr, color._get_core_struct())
+
+ def set_user_instr_highlight(self, arch, addr, color):
+ if not isinstance(color, HighlightColor):
+ color = HighlightColor(color = color)
+ core.BNSetUserInstructionHighlight(self.handle, arch.handle, addr, color._get_core_struct())
+
+class AdvancedFunctionAnalysisDataRequestor(object):
+ def __init__(self, func = None):
+ self._function = func
+ if self._function is not None:
+ self._function.request_advanced_analysis_data()
+
+ def __del__(self):
+ if self._function is not None:
+ self._function.release_advanced_analysis_data()
+
+ @property
+ def function(self):
+ return self._function
+
+ @function.setter
+ def function(self, func):
+ if self._function is not None:
+ self._function.release_advanced_analysis_data()
+ self._function = func
+ if self._function is not None:
+ self._function.request_advanced_analysis_data()
+
+ def close(self):
+ if self._function is not None:
+ self._function.release_advanced_analysis_data()
+ self._function = None
+
+class BasicBlockEdge(object):
def __init__(self, branch_type, target, arch):
self.type = core.BNBranchType_names[branch_type]
if self.type != "UnresolvedBranch":
@@ -4730,6 +5135,22 @@ class BasicBlock(object):
def disassembly_text(self):
return self.get_disassembly_text()
+ @property
+ def highlight(self):
+ """Highlight color for basic block"""
+ color = core.BNGetBasicBlockHighlight(self.handle)
+ if color.style == core.StandardHighlightColor:
+ return HighlightColor(color = color.color, alpha = color.alpha)
+ elif color.style == core.MixedHighlightColor:
+ return HighlightColor(color = color.color, mix_color = color.mixColor, mix = color.mix, alpha = color.alpha)
+ elif color.style == core.CustomHighlightColor:
+ return HighlightColor(red = color.r, green = color.g, blue = color.b, alpha = color.alpha)
+ return HighlightColor(color = core.NoHighlightColor)
+
+ @highlight.setter
+ def highlight(self, value):
+ self.set_user_highlight(value)
+
def __setattr__(self, name, value):
try:
object.__setattr__(self,name,value)
@@ -4784,6 +5205,16 @@ class BasicBlock(object):
core.BNFreeDisassemblyTextLines(lines, count.value)
return result
+ def set_auto_highlight(self, color):
+ if not isinstance(color, HighlightColor):
+ color = HighlightColor(color = color)
+ core.BNSetAutoBasicBlockHighlight(self.handle, color._get_core_struct())
+
+ def set_user_highlight(self, color):
+ if not isinstance(color, HighlightColor):
+ color = HighlightColor(color = color)
+ core.BNSetUserBasicBlockHighlight(self.handle, color._get_core_struct())
+
class LowLevelILBasicBlock(BasicBlock):
def __init__(self, view, handle, owner):
super(LowLevelILBasicBlock, self).__init__(view, handle)
@@ -4793,7 +5224,7 @@ class LowLevelILBasicBlock(BasicBlock):
for idx in xrange(self.start, self.end):
yield self.il_function[idx]
-class DisassemblyTextLine:
+class DisassemblyTextLine(object):
def __init__(self, addr, tokens):
self.address = addr
self.tokens = tokens
@@ -4827,6 +5258,19 @@ class FunctionGraphBlock(object):
core.BNFreeFunctionGraphBlock(self.handle)
@property
+ def basic_block(self):
+ """Basic block associated with this part of the funciton graph (read-only)"""
+ block = core.BNGetFunctionGraphBasicBlock(self.handle)
+ func = core.BNGetBasicBlockFunction(block)
+ if func is None:
+ core.BNFreeBasicBlock(block)
+ block = None
+ else:
+ block = BasicBlock(BinaryView(None, handle = core.BNGetFunctionData(func)), block)
+ core.BNFreeFunction(func)
+ return block
+
+ @property
def arch(self):
"""Function graph block architecture (read-only)"""
arch = core.BNGetFunctionGraphBlockArchitecture(self.handle)
@@ -4962,12 +5406,12 @@ class DisassemblySettings(object):
def is_option_set(self, option):
if isinstance(option, str):
- option = core.BNDisassemblyOption_by_name(option)
+ option = core.BNDisassemblyOption_by_name[option]
return core.BNIsDisassemblySettingsOptionSet(self.handle, option)
def set_option(self, option, state = True):
if isinstance(option, str):
- option = core.BNDisassemblyOption_by_name(option)
+ option = core.BNDisassemblyOption_by_name[option]
core.BNSetDisassemblySettingsOption(self.handle, option, state)
class FunctionGraph(object):
@@ -5111,7 +5555,7 @@ class FunctionGraph(object):
option = core.BNDisassemblyOption_by_name(option)
core.BNSetFunctionGraphOption(self.handle, option, state)
-class RegisterInfo:
+class RegisterInfo(object):
def __init__(self, full_width_reg, size, offset = 0, extend = core.NoExtend, index = None):
self.full_width_reg = full_width_reg
self.offset = offset
@@ -5128,7 +5572,7 @@ class RegisterInfo:
extend = ""
return "<reg: size %d, offset %d in %s%s>" % (self.size, self.offset, self.full_width_reg, extend)
-class InstructionBranch:
+class InstructionBranch(object):
def __init__(self, branch_type, target = 0, arch = None):
self.type = branch_type
self.target = target
@@ -5142,7 +5586,7 @@ class InstructionBranch:
return "<%s: %s@%#x>" % (branch_type, self.arch.name, self.target)
return "<%s: %#x>" % (branch_type, self.target)
-class InstructionInfo:
+class InstructionInfo(object):
def __init__(self):
self.length = 0
self.branch_delay = False
@@ -5157,7 +5601,7 @@ class InstructionInfo:
branch_delay = ", delay slot"
return "<instr: %d bytes%s, %s>" % (self.length, branch_delay, repr(self.branches))
-class InstructionTextToken:
+class InstructionTextToken(object):
"""
``class InstructionTextToken`` is used to tell the core about the various components in the disassembly views.
@@ -5254,7 +5698,7 @@ class _ArchitectureMetaClass(type):
class Architecture(object):
"""
- ``class Architecture`` is the parent class for all CPU architectures. Subclasses of Architecture implemnt assembly,
+ ``class Architecture`` is the parent class for all CPU architectures. Subclasses of Architecture implement assembly,
disassembly, IL lifting, and patching.
``class Architecture`` has a ``__metaclass__`` with the additional methods ``register``, and supports
@@ -5354,7 +5798,7 @@ class Architecture(object):
self._flags_required_for_flag_condition = {}
self.__dict__["flags_required_for_flag_condition"] = {}
- for cond in core.BNLowLevelILFlagCondition_names.keys():
+ for cond in core.BNLowLevelILFlagCondition_names:
count = ctypes.c_ulonglong()
flags = core.BNGetArchitectureFlagsRequiredForFlagCondition(self.handle, cond, count)
flag_indexes = []
@@ -5441,7 +5885,7 @@ class Architecture(object):
self._regs_by_index = {}
self.__dict__["regs"] = self.__class__.regs
reg_index = 0
- for reg in self.regs.keys():
+ for reg in self.regs:
info = self.regs[reg]
if reg not in self._all_regs:
self._all_regs[reg] = reg_index
@@ -5478,7 +5922,7 @@ class Architecture(object):
self._flag_roles = {}
self.__dict__["flag_roles"] = self.__class__.flag_roles
- for flag in self.__class__.flag_roles.keys():
+ for flag in self.__class__.flag_roles:
role = self.__class__.flag_roles[flag]
if isinstance(role, str):
role = core.BNFlagRole_by_name[role]
@@ -5486,7 +5930,7 @@ class Architecture(object):
self._flags_required_for_flag_condition = {}
self.__dict__["flags_required_for_flag_condition"] = self.__class__.flags_required_for_flag_condition
- for cond in self.__class__.flags_required_for_flag_condition.keys():
+ for cond in self.__class__.flags_required_for_flag_condition:
flags = []
for flag in self.__class__.flags_required_for_flag_condition[cond]:
flags.append(self._flags[flag])
@@ -5494,7 +5938,7 @@ class Architecture(object):
self._flags_written_by_flag_write_type = {}
self.__dict__["flags_written_by_flag_write_type"] = self.__class__.flags_written_by_flag_write_type
- for write_type in self.__class__.flags_written_by_flag_write_type.keys():
+ for write_type in self.__class__.flags_written_by_flag_write_type:
flags = []
for flag in self.__class__.flags_written_by_flag_write_type[write_type]:
flags.append(self._flags[flag])
@@ -5604,7 +6048,7 @@ class Architecture(object):
else:
result[0].branchArch[i] = info.branches[i].arch.handle
return True
- except:
+ except (KeyError, OSError):
log_error(traceback.format_exc())
return False
@@ -5621,7 +6065,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 = BNInstructionTextTokenType_by_name[tokens[i].type]
+ token_buf[i].type = core.BNInstructionTextTokenType_by_name[tokens[i].type]
else:
token_buf[i].type = tokens[i].type
token_buf[i].text = tokens[i].text
@@ -5632,7 +6076,7 @@ class Architecture(object):
ptr = ctypes.cast(token_buf, ctypes.c_void_p)
self._pending_token_lists[ptr.value] = (ptr.value, token_buf)
return True
- except:
+ except (KeyError, OSError):
log_error(traceback.format_exc())
return False
@@ -5642,7 +6086,7 @@ class Architecture(object):
if buf.value not in self._pending_token_lists:
raise ValueError, "freeing token list that wasn't allocated"
del self._pending_token_lists[buf.value]
- except:
+ except KeyError:
log_error(traceback.format_exc())
def _get_instruction_low_level_il(self, ctxt, data, addr, length, il):
@@ -5655,7 +6099,7 @@ class Architecture(object):
return False
length[0] = result
return True
- except:
+ except OSError:
log_error(traceback.format_exc())
return False
@@ -5664,7 +6108,7 @@ class Architecture(object):
if reg in self._regs_by_index:
return core.BNAllocString(self._regs_by_index[reg])
return core.BNAllocString("")
- except:
+ except (KeyError, OSError):
log_error(traceback.format_exc())
return core.BNAllocString("")
@@ -5673,7 +6117,7 @@ class Architecture(object):
if flag in self._flags_by_index:
return core.BNAllocString(self._flags_by_index[flag])
return core.BNAllocString("")
- except:
+ except (KeyError, OSError):
log_error(traceback.format_exc())
return core.BNAllocString("")
@@ -5682,7 +6126,7 @@ class Architecture(object):
if write_type in self._flag_write_types_by_index:
return core.BNAllocString(self._flag_write_types_by_index[write_type])
return core.BNAllocString("")
- except:
+ except (KeyError, OSError):
log_error(traceback.format_exc())
return core.BNAllocString("")
@@ -5696,7 +6140,7 @@ class Architecture(object):
result = ctypes.cast(reg_buf, ctypes.c_void_p)
self._pending_reg_lists[result.value] = (result, reg_buf)
return result.value
- except:
+ except KeyError:
log_error(traceback.format_exc())
count[0] = 0
return None
@@ -5711,7 +6155,7 @@ class Architecture(object):
result = ctypes.cast(reg_buf, ctypes.c_void_p)
self._pending_reg_lists[result.value] = (result, reg_buf)
return result.value
- except:
+ except KeyError:
log_error(traceback.format_exc())
count[0] = 0
return None
@@ -5726,7 +6170,7 @@ class Architecture(object):
result = ctypes.cast(flag_buf, ctypes.c_void_p)
self._pending_reg_lists[result.value] = (result, flag_buf)
return result.value
- except:
+ except KeyError:
log_error(traceback.format_exc())
count[0] = 0
return None
@@ -5741,7 +6185,7 @@ class Architecture(object):
result = ctypes.cast(type_buf, ctypes.c_void_p)
self._pending_reg_lists[result.value] = (result, type_buf)
return result.value
- except:
+ except KeyError:
log_error(traceback.format_exc())
count[0] = 0
return None
@@ -5751,7 +6195,7 @@ class Architecture(object):
if flag in self._flag_roles:
return self._flag_roles[flag]
return core.SpecialFlagRole
- except:
+ except KeyError:
log_error(traceback.format_exc())
return None
@@ -5768,7 +6212,7 @@ class Architecture(object):
result = ctypes.cast(flag_buf, ctypes.c_void_p)
self._pending_reg_lists[result.value] = (result, flag_buf)
return result.value
- except:
+ except KeyError:
log_error(traceback.format_exc())
count[0] = 0
return None
@@ -5786,7 +6230,7 @@ class Architecture(object):
result = ctypes.cast(flag_buf, ctypes.c_void_p)
self._pending_reg_lists[result.value] = (result, flag_buf)
return result.value
- except:
+ except (KeyError, OSError):
log_error(traceback.format_exc())
count[0] = 0
return None
@@ -5807,7 +6251,7 @@ class Architecture(object):
operand_list.append(("reg", self._regs_by_index[operands[i].reg]))
return self.perform_get_flag_write_low_level_il(op, size, write_type_name, flag_name, operand_list,
LowLevelILFunction(self, core.BNNewLowLevelILFunctionReference(il))).index
- except:
+ except (KeyError, OSError):
log_error(traceback.format_exc())
return False
@@ -5815,7 +6259,7 @@ class Architecture(object):
try:
return self.perform_get_flag_condition_low_level_il(cond,
LowLevelILFunction(self, core.BNNewLowLevelILFunctionReference(il))).index
- except:
+ except OSError:
log_error(traceback.format_exc())
return 0
@@ -5825,7 +6269,7 @@ class Architecture(object):
if buf.value not in self._pending_reg_lists:
raise ValueError, "freeing register list that wasn't allocated"
del self._pending_reg_lists[buf.value]
- except:
+ except (ValueError, KeyError):
log_error(traceback.format_exc())
def _get_register_info(self, ctxt, reg, result):
@@ -5844,7 +6288,7 @@ class Architecture(object):
result[0].extend = core.BNImplicitRegisterExtend_by_name[info.extend]
else:
result[0].extend = info.extend
- except:
+ except KeyError:
log_error(traceback.format_exc())
result[0].fullWidthRegister = 0
result[0].offset = 0
@@ -5854,7 +6298,7 @@ class Architecture(object):
def _get_stack_pointer_register(self, ctxt):
try:
return self._all_regs[self.__class__.stack_pointer]
- except:
+ except KeyError:
log_error(traceback.format_exc())
return 0
@@ -5863,7 +6307,7 @@ class Architecture(object):
if self.__class__.link_reg is None:
return 0xffffffff
return self._all_regs[self.__class__.link_reg]
- except:
+ except KeyError:
log_error(traceback.format_exc())
return 0
@@ -5992,16 +6436,17 @@ class Architecture(object):
log_error(traceback.format_exc())
return False
+ @abc.abstractmethod
def perform_get_instruction_info(self, data, addr):
"""
``perform_get_instruction_info`` implements a method which interpretes the bytes passed in ``data`` as an
:py:Class:`InstructionInfo` object. The InstructionInfo object should have the length of the current instruction.
If the instruction is a branch instruction the method should add a branch of the proper type:
- ===================== =================================================
+ ===================== ===================================================
BranchType Description
- ===================== =================================================
- UnconditionalBranch Branch will alwasy be taken
+ ===================== ===================================================
+ UnconditionalBranch Branch will always be taken
FalseBranch False branch condition
TrueBranch True branch condition
CallDestination Branch is a call instruction (Branch with Link)
@@ -6009,15 +6454,16 @@ class Architecture(object):
SystemCall System call instruction
IndirectBranch Branch destination is a memory address or register
UnresolvedBranch Call instruction that isn't
- ===================== ==================================================
+ ===================== ===================================================
:param str data: bytes to decode
:param int addr: virtual address of the byte to be decoded
:return: a :py:class:`InstructionInfo` object containing the length and branche types for the given instruction
:rtype: InstructionInfo
"""
- return None
+ raise NotImplementedError
+ @abc.abstractmethod
def perform_get_instruction_text(self, data, addr):
"""
``perform_get_instruction_text`` implements a method which interpretes the bytes passed in ``data`` as a
@@ -6028,8 +6474,9 @@ class Architecture(object):
:return: a tuple of list(InstructionTextToken) and length of instruction decoded
:rtype: tuple(list(InstructionTextToken), int)
"""
- return None, None
+ raise NotImplementedError
+ @abc.abstractmethod
def perform_get_instruction_low_level_il(self, data, addr, il):
"""
``perform_get_instruction_low_level_il`` implements a method to interpret the bytes passed in ``data`` to
@@ -6042,8 +6489,9 @@ class Architecture(object):
:param LowLevelILFunction il: LowLevelILFunction object to append LowLevelILExpr objects to
:rtype: None
"""
- return None
+ raise NotImplementedError
+ @abc.abstractmethod
def perform_get_flag_write_low_level_il(self, op, size, write_type, flag, operands, il):
"""
.. note:: Architecture subclasses should implement this method.
@@ -6059,6 +6507,7 @@ class Architecture(object):
"""
return il.unimplemented()
+ @abc.abstractmethod
def perform_get_flag_condition_low_level_il(self, cond, il):
"""
.. note:: Architecture subclasses should implement this method.
@@ -6070,6 +6519,7 @@ class Architecture(object):
"""
return il.unimplemented()
+ @abc.abstractmethod
def perform_assemble(self, code, addr):
"""
``perform_assemble`` implements a method to convert the string of assembly instructions ``code`` loaded at
@@ -6088,6 +6538,7 @@ class Architecture(object):
"""
return None, "Architecture does not implement an assembler.\n"
+ @abc.abstractmethod
def perform_is_never_branch_patch_available(self, data, addr):
"""
``perform_is_never_branch_patch_available`` implements a check to determine if the instruction represented by
@@ -6103,6 +6554,7 @@ class Architecture(object):
"""
return False
+ @abc.abstractmethod
def perform_is_always_branch_patch_available(self, data, addr):
"""
``perform_is_always_branch_patch_available`` implements a check to determine if the instruction represented by
@@ -6118,6 +6570,7 @@ class Architecture(object):
"""
return False
+ @abc.abstractmethod
def perform_is_invert_branch_patch_available(self, data, addr):
"""
``perform_is_invert_branch_patch_available`` implements a check to determine if the instruction represented by
@@ -6132,6 +6585,7 @@ class Architecture(object):
"""
return False
+ @abc.abstractmethod
def perform_is_skip_and_return_zero_patch_available(self, data, addr):
"""
``perform_is_skip_and_return_zero_patch_available`` implements a check to determine if the instruction represented by
@@ -6149,6 +6603,7 @@ class Architecture(object):
"""
return False
+ @abc.abstractmethod
def perform_is_skip_and_return_value_patch_available(self, data, addr):
"""
``perform_is_skip_and_return_value_patch_available`` implements a check to determine if the instruction represented by
@@ -6166,6 +6621,7 @@ class Architecture(object):
"""
return False
+ @abc.abstractmethod
def perform_convert_to_nop(self, data, addr):
"""
``perform_convert_to_nop`` implements a method which returns a nop sequence of len(data) bytes long.
@@ -6180,6 +6636,7 @@ class Architecture(object):
"""
return None
+ @abc.abstractmethod
def perform_always_branch(self, data, addr):
"""
``perform_always_branch`` implements a method which converts the branch represented by the bytes in ``data`` to
@@ -6195,6 +6652,7 @@ class Architecture(object):
"""
return None
+ @abc.abstractmethod
def perform_invert_branch(self, data, addr):
"""
``perform_invert_branch`` implements a method which inverts the branch represented by the bytes in ``data`` to
@@ -6210,6 +6668,7 @@ class Architecture(object):
"""
return None
+ @abc.abstractmethod
def perform_skip_and_return_value(self, data, addr, value):
"""
``perform_skip_and_return_value`` implements a method which converts a *call-like* instruction represented by
@@ -6751,6 +7210,7 @@ class Architecture(object):
variables[parse.variables[i].name] = Type(core.BNNewTypeReference(parse.variables[i].type))
for i in xrange(0, parse.functionCount):
functions[parse.functions[i].name] = Type(core.BNNewTypeReference(parse.functions[i].type))
+ BNFreeTypeParserResult(parse)
return (TypeParserResult(types, variables, functions), error_str)
def parse_types_from_source_file(self, filename, include_dirs = []):
@@ -6791,6 +7251,7 @@ class Architecture(object):
variables[parse.variables[i].name] = Type(core.BNNewTypeReference(parse.variables[i].type))
for i in xrange(0, parse.functionCount):
functions[parse.functions[i].name] = Type(core.BNNewTypeReference(parse.functions[i].type))
+ BNFreeTypeParserResult(parse)
return (TypeParserResult(types, variables, functions), error_str)
def register_calling_convention(self, cc):
@@ -6802,7 +7263,7 @@ class Architecture(object):
"""
core.BNRegisterCallingConvention(self.handle, cc.handle)
-class ReferenceSource:
+class ReferenceSource(object):
def __init__(self, func, arch, addr):
self.function = func
self.arch = arch
@@ -6814,7 +7275,7 @@ class ReferenceSource:
else:
return "<ref: %#x>" % self.address
-class LowLevelILLabel:
+class LowLevelILLabel(object):
def __init__(self, handle = None):
if handle is None:
self.handle = (core.BNLowLevelILLabel * 1)()
@@ -6830,73 +7291,73 @@ class LowLevelILInstruction(object):
"""
ILOperations = {
- core.LLIL_NOP: [],
- core.LLIL_SET_REG: [("dest", "reg"), ("src", "expr")],
+ core.LLIL_NOP: [],
+ core.LLIL_SET_REG: [("dest", "reg"), ("src", "expr")],
core.LLIL_SET_REG_SPLIT: [("hi", "reg"), ("lo", "reg"), ("src", "expr")],
- core.LLIL_SET_FLAG: [("dest", "flag"), ("src", "expr")],
- core.LLIL_LOAD: [("src", "expr")],
- core.LLIL_STORE: [("dest", "expr"), ("src", "expr")],
- core.LLIL_PUSH: [("src", "expr")],
- core.LLIL_POP: [],
- core.LLIL_REG: [("src", "reg")],
- core.LLIL_CONST: [("value", "int")],
- core.LLIL_FLAG: [("src", "flag")],
- core.LLIL_FLAG_BIT: [("src", "flag"), ("bit", "int")],
- core.LLIL_ADD: [("left", "expr"), ("right", "expr")],
- core.LLIL_ADC: [("left", "expr"), ("right", "expr")],
- core.LLIL_SUB: [("left", "expr"), ("right", "expr")],
- core.LLIL_SBB: [("left", "expr"), ("right", "expr")],
- core.LLIL_AND: [("left", "expr"), ("right", "expr")],
- core.LLIL_OR: [("left", "expr"), ("right", "expr")],
- core.LLIL_XOR: [("left", "expr"), ("right", "expr")],
- core.LLIL_LSL: [("left", "expr"), ("right", "expr")],
- core.LLIL_LSR: [("left", "expr"), ("right", "expr")],
- core.LLIL_ASR: [("left", "expr"), ("right", "expr")],
- core.LLIL_ROL: [("left", "expr"), ("right", "expr")],
- core.LLIL_RLC: [("left", "expr"), ("right", "expr")],
- core.LLIL_ROR: [("left", "expr"), ("right", "expr")],
- core.LLIL_RRC: [("left", "expr"), ("right", "expr")],
- core.LLIL_MUL: [("left", "expr"), ("right", "expr")],
- core.LLIL_MULU_DP: [("left", "expr"), ("right", "expr")],
- core.LLIL_MULS_DP: [("left", "expr"), ("right", "expr")],
- core.LLIL_DIVU: [("left", "expr"), ("right", "expr")],
- core.LLIL_DIVU_DP: [("hi", "expr"), ("lo", "expr"), ("right", "expr")],
- core.LLIL_DIVS: [("left", "expr"), ("right", "expr")],
- core.LLIL_DIVS_DP: [("hi", "expr"), ("lo", "expr"), ("right", "expr")],
- core.LLIL_MODU: [("left", "expr"), ("right", "expr")],
- core.LLIL_MODU_DP: [("hi", "expr"), ("lo", "expr"), ("right", "expr")],
- core.LLIL_MODS: [("left", "expr"), ("right", "expr")],
- core.LLIL_MODS_DP: [("hi", "expr"), ("lo", "expr"), ("right", "expr")],
- core.LLIL_NEG: [("src", "expr")],
- core.LLIL_NOT: [("src", "expr")],
- core.LLIL_SX: [("src", "expr")],
- core.LLIL_ZX: [("src", "expr")],
- core.LLIL_JUMP: [("dest", "expr")],
- core.LLIL_JUMP_TO: [("dest", "expr"), ("targets", "int_list")],
- core.LLIL_CALL: [("dest", "expr")],
- core.LLIL_RET: [("dest", "expr")],
- core.LLIL_NORET: [],
- core.LLIL_IF: [("condition", "expr"), ("true", "int"), ("false", "int")],
- core.LLIL_GOTO: [("dest", "int")],
- core.LLIL_FLAG_COND: [("condition", "cond")],
- core.LLIL_CMP_E: [("left", "expr"), ("right", "expr")],
- core.LLIL_CMP_NE: [("left", "expr"), ("right", "expr")],
- core.LLIL_CMP_SLT: [("left", "expr"), ("right", "expr")],
- core.LLIL_CMP_ULT: [("left", "expr"), ("right", "expr")],
- core.LLIL_CMP_SLE: [("left", "expr"), ("right", "expr")],
- core.LLIL_CMP_ULE: [("left", "expr"), ("right", "expr")],
- core.LLIL_CMP_SGE: [("left", "expr"), ("right", "expr")],
- core.LLIL_CMP_UGE: [("left", "expr"), ("right", "expr")],
- core.LLIL_CMP_SGT: [("left", "expr"), ("right", "expr")],
- core.LLIL_CMP_UGT: [("left", "expr"), ("right", "expr")],
- core.LLIL_TEST_BIT: [("left", "expr"), ("right", "expr")],
- core.LLIL_BOOL_TO_INT: [("src", "expr")],
- core.LLIL_SYSCALL: [],
- core.LLIL_BP: [],
- core.LLIL_TRAP: [("value", "int")],
- core.LLIL_UNDEF: [],
- core.LLIL_UNIMPL: [],
- core.LLIL_UNIMPL_MEM: [("src", "expr")]
+ core.LLIL_SET_FLAG: [("dest", "flag"), ("src", "expr")],
+ core.LLIL_LOAD: [("src", "expr")],
+ core.LLIL_STORE: [("dest", "expr"), ("src", "expr")],
+ core.LLIL_PUSH: [("src", "expr")],
+ core.LLIL_POP: [],
+ core.LLIL_REG: [("src", "reg")],
+ core.LLIL_CONST: [("value", "int")],
+ core.LLIL_FLAG: [("src", "flag")],
+ core.LLIL_FLAG_BIT: [("src", "flag"), ("bit", "int")],
+ core.LLIL_ADD: [("left", "expr"), ("right", "expr")],
+ core.LLIL_ADC: [("left", "expr"), ("right", "expr")],
+ core.LLIL_SUB: [("left", "expr"), ("right", "expr")],
+ core.LLIL_SBB: [("left", "expr"), ("right", "expr")],
+ core.LLIL_AND: [("left", "expr"), ("right", "expr")],
+ core.LLIL_OR: [("left", "expr"), ("right", "expr")],
+ core.LLIL_XOR: [("left", "expr"), ("right", "expr")],
+ core.LLIL_LSL: [("left", "expr"), ("right", "expr")],
+ core.LLIL_LSR: [("left", "expr"), ("right", "expr")],
+ core.LLIL_ASR: [("left", "expr"), ("right", "expr")],
+ core.LLIL_ROL: [("left", "expr"), ("right", "expr")],
+ core.LLIL_RLC: [("left", "expr"), ("right", "expr")],
+ core.LLIL_ROR: [("left", "expr"), ("right", "expr")],
+ core.LLIL_RRC: [("left", "expr"), ("right", "expr")],
+ core.LLIL_MUL: [("left", "expr"), ("right", "expr")],
+ core.LLIL_MULU_DP: [("left", "expr"), ("right", "expr")],
+ core.LLIL_MULS_DP: [("left", "expr"), ("right", "expr")],
+ core.LLIL_DIVU: [("left", "expr"), ("right", "expr")],
+ core.LLIL_DIVU_DP: [("hi", "expr"), ("lo", "expr"), ("right", "expr")],
+ core.LLIL_DIVS: [("left", "expr"), ("right", "expr")],
+ core.LLIL_DIVS_DP: [("hi", "expr"), ("lo", "expr"), ("right", "expr")],
+ core.LLIL_MODU: [("left", "expr"), ("right", "expr")],
+ core.LLIL_MODU_DP: [("hi", "expr"), ("lo", "expr"), ("right", "expr")],
+ core.LLIL_MODS: [("left", "expr"), ("right", "expr")],
+ core.LLIL_MODS_DP: [("hi", "expr"), ("lo", "expr"), ("right", "expr")],
+ core.LLIL_NEG: [("src", "expr")],
+ core.LLIL_NOT: [("src", "expr")],
+ core.LLIL_SX: [("src", "expr")],
+ core.LLIL_ZX: [("src", "expr")],
+ core.LLIL_JUMP: [("dest", "expr")],
+ core.LLIL_JUMP_TO: [("dest", "expr"), ("targets", "int_list")],
+ core.LLIL_CALL: [("dest", "expr")],
+ core.LLIL_RET: [("dest", "expr")],
+ core.LLIL_NORET: [],
+ core.LLIL_IF: [("condition", "expr"), ("true", "int"), ("false", "int")],
+ core.LLIL_GOTO: [("dest", "int")],
+ core.LLIL_FLAG_COND: [("condition", "cond")],
+ core.LLIL_CMP_E: [("left", "expr"), ("right", "expr")],
+ core.LLIL_CMP_NE: [("left", "expr"), ("right", "expr")],
+ core.LLIL_CMP_SLT: [("left", "expr"), ("right", "expr")],
+ core.LLIL_CMP_ULT: [("left", "expr"), ("right", "expr")],
+ core.LLIL_CMP_SLE: [("left", "expr"), ("right", "expr")],
+ core.LLIL_CMP_ULE: [("left", "expr"), ("right", "expr")],
+ core.LLIL_CMP_SGE: [("left", "expr"), ("right", "expr")],
+ core.LLIL_CMP_UGE: [("left", "expr"), ("right", "expr")],
+ core.LLIL_CMP_SGT: [("left", "expr"), ("right", "expr")],
+ core.LLIL_CMP_UGT: [("left", "expr"), ("right", "expr")],
+ core.LLIL_TEST_BIT: [("left", "expr"), ("right", "expr")],
+ core.LLIL_BOOL_TO_INT: [("src", "expr")],
+ core.LLIL_SYSCALL: [],
+ core.LLIL_BP: [],
+ core.LLIL_TRAP: [("value", "int")],
+ core.LLIL_UNDEF: [],
+ core.LLIL_UNIMPL: [],
+ core.LLIL_UNIMPL_MEM: [("src", "expr")]
}
def __init__(self, func, expr_index, instr_index = None):
@@ -6984,7 +7445,7 @@ class LowLevelILInstruction(object):
except AttributeError:
raise AttributeError, "attribute '%s' is read only" % name
-class LowLevelILExpr:
+class LowLevelILExpr(object):
"""
``class LowLevelILExpr`` hold the index of IL Expressions.
@@ -7028,7 +7489,10 @@ class LowLevelILFunction(object):
if handle is not None:
self.handle = core.handle_of_type(handle, core.BNLowLevelILFunction)
else:
- self.handle = core.BNCreateLowLevelILFunction(arch.handle)
+ func_handle = None
+ if self.source_function is not None:
+ func_handle = self.source_function.handle
+ self.handle = core.BNCreateLowLevelILFunction(arch.handle, func_handle)
def __del__(self):
core.BNFreeLowLevelILFunction(self.handle)
@@ -7084,13 +7548,12 @@ class LowLevelILFunction(object):
raise IndexError, "index out of range"
return LowLevelILInstruction(self, core.BNGetLowLevelILIndexForInstruction(self.handle, i), i)
- def __setitem__(self, i):
+ def __setitem__(self, i, j):
raise IndexError, "instruction modification not implemented"
def __iter__(self):
count = ctypes.c_ulonglong()
blocks = core.BNGetLowLevelILBasicBlockList(self.handle, count)
- result = []
view = None
if self.source_function is not None:
view = self.source_function.view
@@ -7112,7 +7575,7 @@ class LowLevelILFunction(object):
def expr(self, operation, a = 0, b = 0, c = 0, d = 0, size = 0, flags = None):
if isinstance(operation, str):
- operation = BNLowLevelILOperation_by_name[operation]
+ operation = core.BNLowLevelILOperation_by_name[operation]
if isinstance(flags, str):
flags = self.arch.get_flag_write_type_by_name(flags)
elif flags is None:
@@ -7727,7 +8190,7 @@ class LowLevelILFunction(object):
:rtype: LowLevelILExpr
"""
if isinstance(cond, str):
- cond = BNLowLevelILFlagCondition_by_name[cond]
+ cond = core.BNLowLevelILFlagCondition_by_name[cond]
return self.expr(core.LLIL_FLAG_COND, cond)
def compare_equal(self, size, a, b):
@@ -7962,7 +8425,7 @@ class LowLevelILFunction(object):
:return: the label list expression
:rtype: LowLevelILExpr
"""
- label_list = (ctypes.POINTER(BNLowLevelILLabel) * len(labels))()
+ label_list = (ctypes.POINTER(core.BNLowLevelILLabel) * len(labels))()
for i in xrange(len(labels)):
label_list[i] = labels[i].handle
return LowLevelILExpr(core.BNLowLevelILAddLabelList(self.handle, label_list, len(labels)))
@@ -7992,17 +8455,13 @@ class LowLevelILFunction(object):
core.BNLowLevelILSetExprSourceOperand(self.handle, expr.index, n)
return expr
- def finalize(self, func = None):
+ def finalize(self):
"""
- ``finalize`` ends the provided LowLevelILLabel.
+ ``finalize`` ends the function and computes the list of basic blocks.
- :param LowLevelILFunction func: optional function to end
:rtype: None
"""
- if func is None:
- core.BNFinalizeLowLevelILFunction(self.handle, None)
- else:
- core.BNFinalizeLowLevelILFunction(self.handle, func.handle)
+ core.BNFinalizeLowLevelILFunction(self.handle)
def add_label_for_address(self, arch, addr):
"""
@@ -8032,7 +8491,7 @@ class LowLevelILFunction(object):
return None
return LowLevelILLabel(label)
-class TypeParserResult:
+class TypeParserResult(object):
def __init__(self, types, variables, functions):
self.types = types
self.variables = variables
@@ -8090,7 +8549,7 @@ class _TransformMetaClass(type):
cls._registered_cb = xform._cb
xform.handle = core.BNRegisterTransformType(cls.transform_type, cls.name, cls.long_name, cls.group, xform._cb)
-class TransformParameter:
+class TransformParameter(object):
def __init__(self, name, long_name = None, fixed_length = 0):
self.name = name
if long_name is None:
@@ -8199,11 +8658,13 @@ class Transform:
log_error(traceback.format_exc())
return False
+ @abc.abstractmethod
def perform_decode(self, data, params):
if self.type == "InvertingTransform":
- return perform_encode(data, params)
+ return self.perform_encode(data, params)
return None
+ @abc.abstractmethod
def perform_encode(self, data, params):
return None
@@ -8235,7 +8696,7 @@ class Transform:
return None
return str(output_buf)
-class FunctionRecognizer:
+class FunctionRecognizer(object):
_instance = None
def __init__(self):
@@ -8334,7 +8795,7 @@ class _UpdateChannelMetaClass(type):
raise KeyError, "'%s' is not a valid channel" % str(name)
return result
-class UpdateProgressCallback:
+class UpdateProgressCallback(object):
def __init__(self, func):
self.cb = ctypes.CFUNCTYPE(ctypes.c_bool, ctypes.c_void_p, ctypes.c_ulonglong, ctypes.c_ulonglong)(self.callback)
self.func = func
@@ -8422,7 +8883,7 @@ class UpdateChannel(object):
raise IOError, error_str
return core.BNUpdateResult_names[result]
-class UpdateVersion:
+class UpdateVersion(object):
def __init__(self, channel, ver, notes, t):
self.channel = channel
self.version = ver
@@ -8445,7 +8906,7 @@ class UpdateVersion:
raise IOError, error_str
return core.BNUpdateResult_names[result]
-class PluginCommandContext:
+class PluginCommandContext(object):
def __init__(self, view):
self.view = view
self.address = 0
@@ -8658,7 +9119,7 @@ class PluginCommand:
def __repr__(self):
return "<PluginCommand: %s>" % self.name
-class CallingConvention:
+class CallingConvention(object):
name = None
caller_saved_regs = []
int_arg_regs = []
@@ -9178,26 +9639,33 @@ class ScriptingInstance(object):
except:
log_error(traceback.format_exc())
+ @abc.abstractmethod
def perform_destroy_instance(self):
- pass
+ raise NotImplementedError
+ @abc.abstractmethod
def perform_execute_script_input(self, text):
return core.InvalidScriptInput
+ @abc.abstractmethod
def perform_set_current_binary_view(self, view):
- pass
+ raise NotImplementedError
+ @abc.abstractmethod
def perform_set_current_function(self, func):
- pass
+ raise NotImplementedError
+ @abc.abstractmethod
def perform_set_current_basic_block(self, block):
- pass
+ raise NotImplementedError
+ @abc.abstractmethod
def perform_set_current_address(self, addr):
- pass
+ raise NotImplementedError
+ @abc.abstractmethod
def perform_set_current_selection(self, begin, end):
- pass
+ raise NotImplementedError
@property
def input_ready_state(self):
@@ -9484,6 +9952,15 @@ class PythonScriptingInstance(ScriptingInstance):
self.locals["current_selection"] = (self.active_selection_begin, self.active_selection_end)
self.interpreter.runsource(code)
+
+ if self.locals["here"] != self.active_addr:
+ if not self.active_view.file.navigate(self.active_view.file.view, self.locals["here"]):
+ sys.stderr.write("Address 0x%x is not valid for the current view\n" % self.locals["here"])
+ elif self.locals["current_address"] != self.active_addr:
+ if not self.active_view.file.navigate(self.active_view.file.view, self.locals["current_address"]):
+ sys.stderr.write("Address 0x%x is not valid for the current view\n" % self.locals["current_address"])
+ except:
+ traceback.print_exc()
finally:
PythonScriptingInstance._interpreter.value = None
self.instance.input_ready_state = core.ReadyForScriptExecution
@@ -9512,9 +9989,11 @@ class PythonScriptingInstance(ScriptingInstance):
self.queued_input = ""
self.input_ready_state = core.ReadyForScriptExecution
+ @abc.abstractmethod
def perform_destroy_instance(self):
self.interpreter.end()
+ @abc.abstractmethod
def perform_execute_script_input(self, text):
if self.input_ready_state == core.NotReadyForInput:
return core.InvalidScriptInput
@@ -9539,18 +10018,23 @@ class PythonScriptingInstance(ScriptingInstance):
self.interpreter.execute(text)
return core.SuccessfulScriptExecution
+ @abc.abstractmethod
def perform_set_current_binary_view(self, view):
self.interpreter.current_view = view
+ @abc.abstractmethod
def perform_set_current_function(self, func):
self.interpreter.current_func = func
+ @abc.abstractmethod
def perform_set_current_basic_block(self, block):
self.interpreter.current_block = block
+ @abc.abstractmethod
def perform_set_current_address(self, addr):
self.interpreter.current_addr = addr
+ @abc.abstractmethod
def perform_set_current_selection(self, begin, end):
self.interpreter.current_selection_begin = begin
self.interpreter.current_selection_end = end
@@ -9597,6 +10081,508 @@ class MainThreadActionHandler(object):
def add_action(self, action):
pass
+class _BackgroundTaskMetaclass(type):
+ @property
+ def list(self):
+ """List all running background tasks (read-only)"""
+ count = ctypes.c_ulonglong()
+ tasks = core.BNGetRunningBackgroundTasks(count)
+ result = []
+ for i in xrange(0, count.value):
+ result.append(BackgroundTask(core.BNNewBackgroundTaskReference(tasks[i])))
+ core.BNFreeBackgroundTaskList(tasks)
+ return result
+
+ def __iter__(self):
+ _init_plugins()
+ count = ctypes.c_ulonglong()
+ tasks = core.BNGetRunningBackgroundTasks(count)
+ try:
+ for i in xrange(0, count.value):
+ yield BackgroundTask(core.BNNewBackgroundTaskReference(tasks[i]))
+ finally:
+ core.BNFreeBackgroundTaskList(tasks)
+
+class BackgroundTask(object):
+ __metaclass__ = _BackgroundTaskMetaclass
+
+ def __init__(self, initial_progress_text = "", can_cancel = False, handle = None):
+ if handle is None:
+ self.handle = core.BNBeginBackgroundTask(initial_progress_text, can_cancel)
+ else:
+ self.handle = handle
+
+ def __del__(self):
+ core.BNFreeBackgroundTask(self.handle)
+
+ @property
+ def progress(self):
+ """Text description of the progress of the background task (displayed in status bar of the UI)"""
+ return core.BNGetBackgroundTaskProgressText(self.handle)
+
+ @progress.setter
+ def progress(self, value):
+ core.BNSetBackgroundTaskProgressText(self.handle, str(value))
+
+ @property
+ def can_cancel(self):
+ """Whether the task can be cancelled (read-only)"""
+ return core.BNCanCancelBackgroundTask(self.handle)
+
+ @property
+ def finished(self):
+ """Whether the task has finished"""
+ return core.BNIsBackgroundTaskFinished(self.handle)
+
+ @finished.setter
+ def finished(self, value):
+ if value:
+ self.finish()
+
+ def finish(self):
+ core.BNFinishBackgroundTask(self.handle)
+
+ @property
+ def cancelled(self):
+ """Whether the task has been cancelled"""
+ return core.BNIsBackgroundTaskCancelled(self.handle)
+
+ @cancelled.setter
+ def cancelled(self, value):
+ if value:
+ self.cancel()
+
+ def cancel(self):
+ core.BNCancelBackgroundTask(self.handle)
+
+class BackgroundTaskThread(BackgroundTask):
+ def __init__(self, initial_progress_text = "", can_cancel = False):
+ class _Thread(threading.Thread):
+ def __init__(self, task):
+ threading.Thread.__init__(self)
+ self.task = task
+
+ def run(self):
+ self.task.run()
+ self.task.finish()
+ self.task = None
+
+ BackgroundTask.__init__(self, initial_progress_text, can_cancel)
+ self.thread = _Thread(self)
+
+ def run(self):
+ pass
+
+ def start(self):
+ self.thread.start()
+
+ def join(self):
+ self.thread.join()
+
+class LabelField(object):
+ def __init__(self, text):
+ self.text = text
+
+ def _fill_core_struct(self, value):
+ value.type = core.LabelFormField
+ value.prompt = self.text
+
+ def _fill_core_result(self, value):
+ pass
+
+ def _get_result(self, value):
+ pass
+
+class SeparatorField(object):
+ def _fill_core_struct(self, value):
+ value.type = core.SeparatorFormField
+
+ def _fill_core_result(self, value):
+ pass
+
+ def _get_result(self, value):
+ pass
+
+class TextLineField(object):
+ def __init__(self, prompt):
+ self.prompt = prompt
+ self.result = None
+
+ def _fill_core_struct(self, value):
+ value.type = core.TextLineFormField
+ value.prompt = self.prompt
+
+ def _fill_core_result(self, value):
+ value.stringResult = core.BNAllocString(str(self.result))
+
+ def _get_result(self, value):
+ self.result = value.stringResult
+
+class MultilineTextField(object):
+ def __init__(self, prompt):
+ self.prompt = prompt
+ self.result = None
+
+ def _fill_core_struct(self, value):
+ value.type = core.MultilineTextFormField
+ value.prompt = self.prompt
+
+ def _fill_core_result(self, value):
+ value.stringResult = core.BNAllocString(str(self.result))
+
+ def _get_result(self, value):
+ self.result = value.stringResult
+
+class IntegerField(object):
+ def __init__(self, prompt):
+ self.prompt = prompt
+ self.result = None
+
+ def _fill_core_struct(self, value):
+ value.type = core.IntegerFormField
+ value.prompt = self.prompt
+
+ def _fill_core_result(self, value):
+ value.intResult = self.result
+
+ def _get_result(self, value):
+ self.result = value.intResult
+
+class AddressField(object):
+ def __init__(self, prompt, view = None, current_address = 0):
+ self.prompt = prompt
+ self.view = view
+ self.current_address = current_address
+ self.result = None
+
+ def _fill_core_struct(self, value):
+ value.type = core.AddressFormField
+ value.prompt = self.prompt
+ value.view = None
+ if self.view is not None:
+ value.view = self.view.handle
+ value.currentAddress = self.current_address
+
+ def _fill_core_result(self, value):
+ value.addressResult = self.result
+
+ def _get_result(self, value):
+ self.result = value.addressResult
+
+class ChoiceField(object):
+ def __init__(self, prompt, choices):
+ self.prompt = prompt
+ self.choices = choices
+ self.result = None
+
+ def _fill_core_struct(self, value):
+ value.type = core.ChoiceFormField
+ value.prompt = self.prompt
+ choice_buf = (ctypes.c_char_p * len(self.choices))()
+ for i in xrange(0, len(self.choices)):
+ choice_buf[i] = str(self.choices[i])
+ value.choices = choice_buf
+ value.count = len(self.choices)
+
+ def _fill_core_result(self, value):
+ value.indexResult = self.result
+
+ def _get_result(self, value):
+ self.result = value.indexResult
+
+class OpenFileNameField(object):
+ def __init__(self, prompt, ext = ""):
+ self.prompt = prompt
+ self.ext = ext
+ self.result = None
+
+ def _fill_core_struct(self, value):
+ value.type = core.OpenFileNameFormField
+ value.prompt = self.prompt
+ value.ext = self.ext
+
+ def _fill_core_result(self, value):
+ value.stringResult = core.BNAllocString(str(self.result))
+
+ def _get_result(self, value):
+ self.result = value.stringResult
+
+class SaveFileNameField(object):
+ def __init__(self, prompt, ext = "", default_name = ""):
+ self.prompt = prompt
+ self.ext = ext
+ self.default_name = default_name
+ self.result = None
+
+ def _fill_core_struct(self, value):
+ value.type = core.SaveFileNameFormField
+ value.prompt = self.prompt
+ value.ext = self.ext
+ value.defaultName = self.default_name
+
+ def _fill_core_result(self, value):
+ value.stringResult = core.BNAllocString(str(self.result))
+
+ def _get_result(self, value):
+ self.result = value.stringResult
+
+class DirectoryNameField(object):
+ def __init__(self, prompt, default_name = ""):
+ self.prompt = prompt
+ self.default_name = default_name
+ self.result = None
+
+ def _fill_core_struct(self, value):
+ value.type = core.DirectoryNameField
+ value.prompt = self.prompt
+ value.defaultName = self.default_name
+
+ def _fill_core_result(self, value):
+ value.stringResult = core.BNAllocString(str(self.result))
+
+ def _get_result(self, value):
+ self.result = value.stringResult
+
+class InteractionHandler(object):
+ _interaction_handler = None
+
+ def __init__(self):
+ self._cb = core.BNInteractionHandlerCallbacks()
+ self._cb.context = 0
+ self._cb.showPlainTextReport = self._cb.showPlainTextReport.__class__(self._show_plain_text_report)
+ self._cb.showMarkdownReport = self._cb.showMarkdownReport.__class__(self._show_markdown_report)
+ self._cb.showHTMLReport = self._cb.showHTMLReport.__class__(self._show_html_report)
+ self._cb.getTextLineInput = self._cb.getTextLineInput.__class__(self._get_text_line_input)
+ self._cb.getIntegerInput = self._cb.getIntegerInput.__class__(self._get_int_input)
+ self._cb.getAddressInput = self._cb.getAddressInput.__class__(self._get_address_input)
+ self._cb.getChoiceInput = self._cb.getChoiceInput.__class__(self._get_choice_input)
+ self._cb.getOpenFileNameInput = self._cb.getOpenFileNameInput.__class__(self._get_open_filename_input)
+ self._cb.getSaveFileNameInput = self._cb.getSaveFileNameInput.__class__(self._get_save_filename_input)
+ self._cb.getDirectoryNameInput = self._cb.getDirectoryNameInput.__class__(self._get_directory_name_input)
+ self._cb.getFormInput = self._cb.getFormInput.__class__(self._get_form_input)
+ self._cb.showMessageBox = self._cb.showMessageBox.__class__(self._show_message_box)
+
+ def register(self):
+ self.__class__._interaction_handler = self
+ core.BNRegisterInteractionHandler(self._cb)
+
+ def _show_plain_text_report(self, ctxt, view, title, contents):
+ try:
+ if view:
+ view = BinaryView(None, handle = core.BNNewViewReference(view))
+ else:
+ view = None
+ self.show_plain_text_report(view, title, contents)
+ except:
+ log_error(traceback.format_exc())
+
+ def _show_markdown_report(self, ctxt, view, title, contents, plaintext):
+ try:
+ if view:
+ view = BinaryView(None, handle = core.BNNewViewReference(view))
+ else:
+ view = None
+ self.show_markdown_report(view, title, contents, plaintext)
+ except:
+ log_error(traceback.format_exc())
+
+ def _show_html_report(self, ctxt, view, title, contents, plaintext):
+ try:
+ if view:
+ view = BinaryView(None, handle = core.BNNewViewReference(view))
+ else:
+ view = None
+ self.show_html_report(view, title, contents, plaintext)
+ except:
+ log_error(traceback.format_exc())
+
+ def _get_text_line_input(self, ctxt, result, prompt, title):
+ try:
+ value = self.get_text_line_input(prompt, title)
+ if value is None:
+ return False
+ result[0] = core.BNAllocString(str(value))
+ return True
+ except:
+ log_error(traceback.format_exc())
+
+ def _get_int_input(self, ctxt, result, prompt, title):
+ try:
+ value = self.get_int_input(prompt, title)
+ if value is None:
+ return False
+ result[0] = value
+ return True
+ except:
+ log_error(traceback.format_exc())
+
+ def _get_address_input(self, ctxt, result, prompt, title, view, current_address):
+ try:
+ if view:
+ view = BinaryView(None, handle = core.BNNewViewReference(view))
+ else:
+ view = None
+ value = self.get_address_input(prompt, title, view, current_address)
+ if value is None:
+ return False
+ result[0] = value
+ return True
+ except:
+ log_error(traceback.format_exc())
+
+ def _get_choice_input(self, ctxt, result, prompt, title, choice_buf, count):
+ try:
+ choices = []
+ for i in xrange(0, count):
+ choices.append(choice_buf[i])
+ value = self.get_choice_input(prompt, title, choices)
+ if value is None:
+ return False
+ result[0] = value
+ return True
+ except:
+ log_error(traceback.format_exc())
+
+ def _get_open_filename_input(self, ctxt, result, prompt, ext):
+ try:
+ value = self.get_open_filename_input(prompt, ext)
+ if value is None:
+ return False
+ result[0] = core.BNAllocString(str(value))
+ return True
+ except:
+ log_error(traceback.format_exc())
+
+ def _get_save_filename_input(self, ctxt, result, prompt, ext, default_name):
+ try:
+ value = self.get_save_filename_input(prompt, ext, default_name)
+ if value is None:
+ return False
+ result[0] = core.BNAllocString(str(value))
+ return True
+ except:
+ log_error(traceback.format_exc())
+
+ def _get_directory_name_input(self, ctxt, result, prompt, default_name):
+ try:
+ value = self.get_directory_name_input(prompt, default_name)
+ if value is None:
+ return False
+ result[0] = core.BNAllocString(str(value))
+ return True
+ except:
+ log_error(traceback.format_exc())
+
+ def _get_form_input(self, ctxt, fields, count, title):
+ try:
+ field_objs = []
+ for i in xrange(0, count):
+ if fields[i].type == core.LabelFormField:
+ field_objs.append(LabelField(fields[i].prompt))
+ elif fields[i].type == core.SeparatorFormField:
+ field_objs.append(SeparatorField())
+ elif fields[i].type == core.TextLineFormField:
+ field_objs.append(TextLineField(fields[i].prompt))
+ elif fields[i].type == core.MultilineTextFormField:
+ field_objs.append(MultilineTextField(fields[i].prompt))
+ elif fields[i].type == core.IntegerFormField:
+ field_objs.append(IntegerField(fields[i].prompt))
+ elif fields[i].type == core.AddressFormField:
+ view = None
+ if fields[i].view:
+ view = BinaryView(None, handle = core.BNNewViewReference(fields[i].view))
+ field_objs.append(AddressField(fields[i].prompt, view, fields[i].currentAddress))
+ elif fields[i].type == core.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.OpenFileNameFormField:
+ field_objs.append(OpenFileNameField(fields[i].prompt, fields[i].ext))
+ elif fields[i].type == core.SaveFileNameFormField:
+ field_objs.append(SaveFileNameField(fields[i].prompt, fields[i].ext, fields[i].defaultName))
+ elif fields[i].type == core.DirectoryNameField:
+ field_objs.append(DirectoryNameField(fields[i].prompt, fields[i].defaultName))
+ else:
+ field_objs.append(LabelField(fields[i].prompt))
+ if not self.get_form_input(field_objs, title):
+ return False
+ for i in xrange(0, count):
+ field_objs[i]._fill_core_result(fields[i])
+ return True
+ except:
+ log_error(traceback.format_exc())
+
+ def _show_message_box(self, ctxt, title, text, buttons, icon):
+ try:
+ return self.show_message_box(title, text, buttons, icon)
+ except:
+ log_error(traceback.format_exc())
+
+ def show_plain_text_report(self, view, title, contents):
+ pass
+
+ def show_markdown_report(self, view, title, contents, plaintext):
+ self.show_html_report(view, title, markdown_to_html(contents), plaintext)
+
+ def show_html_report(self, view, title, contents, plaintext):
+ if len(plaintext) != 0:
+ self.show_plain_text_report(view, title, plaintext)
+
+ def get_text_line_input(self, prompt, title):
+ return None
+
+ def get_int_input(self, prompt, title):
+ while True:
+ text = self.get_text_line_input(prompt, title)
+ if len(text) == 0:
+ return False
+ try:
+ return int(text)
+ except:
+ continue
+
+ def get_address_input(self, prompt, title, view, current_address):
+ return get_int_input(prompt, title)
+
+ def get_choice_input(self, prompt, title, choices):
+ return None
+
+ def get_open_filename_input(self, prompt, ext):
+ return get_text_line_input(prompt, "Open File")
+
+ def get_save_filename_input(self, prompt, ext, default_name):
+ return get_text_line_input(title, "Save File")
+
+ def get_directory_name_input(self, prompt, default_name):
+ return get_text_line_input(title, "Select Directory")
+
+ def get_form_input(self, fields, title):
+ return False
+
+ def show_message_box(self, title, text, buttons, icon):
+ return core.CancelButton
+
+class _DestructionCallbackHandler:
+ def __init__(self):
+ self._cb = core.BNObjectDestructionCallbacks()
+ self._cb.context = 0
+ self._cb.destructBinaryView = self._cb.destructBinaryView.__class__(self.destruct_binary_view)
+ self._cb.destructFileMetadata = self._cb.destructFileMetadata.__class__(self.destruct_file_metadata)
+ self._cb.destructFunction = self._cb.destructFunction.__class__(self.destruct_function)
+ core.BNRegisterObjectDestructionCallbacks(self._cb)
+
+ def destruct_binary_view(self, ctxt, view):
+ BinaryView._unregister(view)
+
+ def destruct_file_metadata(self, ctxt, f):
+ FileMetadata._unregister(f)
+
+ def destruct_function(self, ctxt, func):
+ Function._unregister(func)
+
+_destruct_callbacks = _DestructionCallbackHandler()
+
def LLIL_TEMP(n):
return n | 0x80000000
@@ -9851,15 +10837,17 @@ def demangle_ms(arch, mangled_name):
if core.BNDemangleMS(arch.handle, mangled_name, ctypes.byref(handle), ctypes.byref(outName), ctypes.byref(outSize)):
for i in xrange(outSize.value):
names.append(outName[i])
+ #core.BNFreeDemangledName(outName.value, outSize.value)
return (Type(handle), names)
- return (None, mangledName)
+ return (None, mangled_name)
+
_output_to_log = False
def redirect_output_to_log():
global _output_to_log
_output_to_log = True
-class _MainThreadActionContext:
+class _ThreadActionContext(object):
_actions = []
def __init__(self, func):
@@ -9882,16 +10870,119 @@ class _MainThreadActionContext:
self.__class__._actions.remove(self)
def execute_on_main_thread(func):
- action = _MainThreadActionContext(func)
+ action = _ThreadActionContext(func)
obj = core.BNExecuteOnMainThread(0, action.callback)
if obj:
return MainThreadAction(obj)
return None
def execute_on_main_thread_and_wait(func):
- action = _MainThreadActionContext(func)
+ action = _ThreadActionContext(func)
core.BNExecuteOnMainThreadAndWait(0, action.callback)
+def worker_enqueue(func):
+ action = _ThreadActionContext(func)
+ core.BNWorkerEnqueue(0, action.callback)
+
+def worker_priority_enqueue(func):
+ action = _ThreadActionContext(func)
+ core.BNWorkerPriorityEnqueue(0, action.callback)
+
+def worker_interactive_enqueue(func):
+ action = _ThreadActionContext(func)
+ core.BNWorkerInteractiveEnqueue(0, action.callback)
+
+def get_worker_thread_count():
+ return core.BNGetWorkerThreadCount()
+
+def set_worker_thread_count(count):
+ core.BNSetWorkerThreadCount(count)
+
+def markdown_to_html(contents):
+ return core.BNMarkdownToHTML(contents)
+
+def show_plain_text_report(title, contents):
+ core.BNShowPlainTextReport(None, title, contents)
+
+def show_markdown_report(title, contents, plaintext = ""):
+ core.BNShowMarkdownReport(None, title, contents, plaintext)
+
+def show_html_report(title, contents, plaintext = ""):
+ core.BNShowHTMLReport(None, title, contents, plaintext)
+
+def get_text_line_input(prompt, title):
+ value = ctypes.c_char_p()
+ if not core.BNGetTextLineInput(value, prompt, title):
+ return None
+ result = value.value
+ core.BNFreeString(ctypes.cast(value, ctypes.POINTER(ctypes.c_byte)))
+ return result
+
+def get_int_input(prompt, title):
+ value = ctypes.c_longlong()
+ if not core.BNGetIntegerInput(value, prompt, title):
+ return None
+ return value.value
+
+def get_address_input(prompt, title):
+ value = ctypes.c_ulonglong()
+ if not core.BNGetAddressInput(value, prompt, title, None, 0):
+ return None
+ return value.value
+
+def get_choice_input(prompt, title, choices):
+ choice_buf = (ctypes.c_char_p * len(choices))()
+ for i in xrange(0, len(choices)):
+ choice_buf[i] = str(choices[i])
+ value = ctypes.c_ulonglong()
+ if not core.BNGetChoiceInput(value, prompt, title, choice_buf, len(choices)):
+ return None
+ return value.value
+
+def get_open_filename_input(prompt, ext = ""):
+ value = ctypes.c_char_p()
+ if not core.BNGetOpenFileNameInput(value, prompt, ext):
+ return None
+ result = value.value
+ core.BNFreeString(ctypes.cast(value, ctypes.POINTER(ctypes.c_byte)))
+ return result
+
+def get_save_filename_input(prompt, ext = "", default_name = ""):
+ value = ctypes.c_char_p()
+ if not core.BNGetSaveFileNameInput(value, prompt, ext, default_name):
+ return None
+ result = value.value
+ core.BNFreeString(ctypes.cast(value, ctypes.POINTER(ctypes.c_byte)))
+ return result
+
+def get_directory_name_input(prompt, default_name = ""):
+ value = ctypes.c_char_p()
+ if not core.BNGetDirectoryNameInput(value, prompt, default_name):
+ return None
+ result = value.value
+ core.BNFreeString(ctypes.cast(value, ctypes.POINTER(ctypes.c_byte)))
+ return result
+
+def get_form_input(fields, title):
+ value = (core.BNFormInputField * len(fields))()
+ for i in xrange(0, len(fields)):
+ if isinstance(fields[i], str):
+ LabelField(fields[i])._fill_core_struct(value[i])
+ elif fields[i] is None:
+ SeparatorField()._fill_core_struct(value[i])
+ else:
+ fields[i]._fill_core_struct(value[i])
+ if not core.BNGetFormInput(value, len(fields), title):
+ return False
+ for i in xrange(0, len(fields)):
+ if not (isinstance(fields[i], str) or (fields[i] is None)):
+ fields[i]._get_result(value[i])
+ core.BNFreeFormInputResults(value, len(fields))
+ return True
+
+def show_message_box(title, text, buttons = core.OKButtonSet, icon = core.InformationIcon):
+ return core.BNShowMessageBox(title, text, buttons, icon)
+
bundled_plugin_path = core.BNGetBundledPluginDirectory()
user_plugin_path = core.BNGetUserPluginDirectory()