summaryrefslogtreecommitdiff
path: root/python
diff options
context:
space:
mode:
Diffstat (limited to 'python')
-rw-r--r--python/__init__.py4652
-rw-r--r--python/examples/nes.py661
-rw-r--r--python/generator.cpp302
3 files changed, 5615 insertions, 0 deletions
diff --git a/python/__init__.py b/python/__init__.py
new file mode 100644
index 00000000..432118fa
--- /dev/null
+++ b/python/__init__.py
@@ -0,0 +1,4652 @@
+import _binaryninjacore as core
+import ctypes, traceback, json, struct, threading
+
+_plugin_init = False
+def _init_plugins():
+ global _plugin_init
+ if not _plugin_init:
+ _plugin_init = True
+ core.BNInitCorePlugins()
+ core.BNInitUserPlugins()
+
+class DataBuffer:
+ 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):
+ self.handle = core.BNCreateDataBuffer(None, contents)
+ elif isinstance(contents, DataBuffer):
+ self.handle = core.BNDuplicateDataBuffer(contents.handle)
+ else:
+ self.handle = core.BNCreateDataBuffer(contents, len(contents))
+
+ def __del__(self):
+ core.BNFreeDataBuffer(self.handle)
+
+ def __len__(self):
+ return int(core.BNGetDataBufferLength(self.handle))
+
+ def __getitem__(self, i):
+ if isinstance(i, tuple):
+ result = ""
+ source = str(self)
+ for s in i:
+ result += source[s]
+ return result
+ elif isinstance(i, slice):
+ if i.step is not None:
+ i = i.indices(len(self))
+ start = i[0]
+ stop = i[1]
+ if stop <= start:
+ return ""
+ buf = ctypes.create_string_buffer(stop - start)
+ ctypes.memmove(buf, core.BNGetDataBufferContentsAt(self.handle, start), stop - start)
+ return buf.raw
+ else:
+ return str(self)[i]
+ elif i < 0:
+ if i >= -len(self):
+ return chr(core.BNGetDataBufferByte(self.handle, int(len(self) + i)))
+ raise IndexError, "index out of range"
+ elif i < len(self):
+ return chr(core.BNGetDataBufferByte(self.handle, int(i)))
+ 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(len(self))
+ start = i[0]
+ stop = i[1]
+ if stop < start:
+ stop = start
+ if len(value) != (stop - start):
+ data = str(self)
+ data = data[0:start] + value + data[stop:]
+ core.BNSetDataBufferContents(self.handle, data, len(data))
+ else:
+ value = str(value)
+ buf = ctypes.create_string_buffer(value)
+ ctypes.memmove(core.BNGetDataBufferContentsAt(self.handle, start), buf, len(value))
+ elif i < 0:
+ if i >= -len(self):
+ if len(value) != 1:
+ raise ValueError, "expected single byte for assignment"
+ value = str(value)
+ buf = ctypes.create_string_buffer(alue)
+ ctypes.memmove(core.BNGetDataBufferContentsAt(self.handle, int(len(self) + i)), buf, 1)
+ else:
+ raise IndexError, "index out of range"
+ elif i < len(self):
+ if len(value) != 1:
+ raise ValueError, "expected single byte for assignment"
+ value = str(value)
+ buf = ctypes.create_string_buffer(value)
+ ctypes.memmove(core.BNGetDataBufferContentsAt(self.handle, int(i)), buf, 1)
+ else:
+ raise IndexError, "index out of range"
+
+ def __str__(self):
+ buf = ctypes.create_string_buffer(len(self))
+ ctypes.memmove(buf, core.BNGetDataBufferContents(self.handle), len(self))
+ return buf.raw
+
+ def __repr__(self):
+ return repr(str(self))
+
+ def escape(self):
+ return core.BNDataBufferToEscapedString(self.handle)
+
+ def unescape(self):
+ return DataBuffer(handle = core.BNDecodeEscapedString(str(self)))
+
+ def base64_encode(self):
+ return core.BNDataBufferToBase64(self.handle)
+
+ def base64_decode(self):
+ return DataBuffer(handle = core.BNDecodeBase64(str(self)))
+
+ def zlib_compress(self):
+ buf = core.BNZlibCompress(self.handle)
+ if buf is None:
+ return None
+ return DataBuffer(handle = buf)
+
+ def zlib_decompress(self):
+ buf = core.BNZlibDecompress(self.handle)
+ if buf is None:
+ return None
+ return DataBuffer(handle = buf)
+
+class NavigationHandler:
+ def _register(self, handle):
+ self._cb = core.BNNavigationHandler()
+ self._cb.context = 0
+ self._cb.getCurrentView = self._cb.getCurrentView.__class__(self._get_current_view)
+ self._cb.getCurrentOffset = self._cb.getCurrentOffset.__class__(self._get_current_offset)
+ self._cb.navigate = self._cb.navigate.__class__(self._navigate)
+ core.BNSetFileMetadataNavigationHandler(handle, self._cb)
+
+ def _get_current_view(self, ctxt):
+ try:
+ view = self.get_current_view()
+ except:
+ log_error(traceback.format_exc())
+ view = ""
+ return core.BNAllocString(view)
+
+ def _get_current_offset(self, ctxt):
+ try:
+ return self.get_current_offset()
+ except:
+ log_error(traceback.format_exc())
+ return 0
+
+ def _navigate(self, ctxt, view, offset):
+ try:
+ return self.navigate(view, offset)
+ except:
+ log_error(traceback.format_exc())
+ return False
+
+class FileMetadata:
+ def __init__(self, filename = None, handle = None):
+ if handle is not None:
+ self.handle = core.handle_of_type(handle, core.BNFileMetadata)
+ else:
+ _init_plugins()
+ self.handle = core.BNCreateFileMetadata()
+ if filename is not None:
+ core.BNSetFilename(self.handle, str(filename))
+ self.__dict__['navigation'] = None
+
+ def __del__(self):
+ if self.navigation is not None:
+ core.BNSetFileMetadataNavigationHandler(self.handle, None)
+ core.BNFreeFileMetadata(self.handle)
+
+ def __getattr__(self, name):
+ if name == "filename":
+ return core.BNGetFilename(self.handle)
+ elif name == "modified":
+ return core.BNIsFileModified(self.handle)
+ elif name == "analysis_changed":
+ return core.BNIsAnalysisChanged(self.handle)
+ elif name == "has_database":
+ return core.BNIsBackedByDatabase(self.handle)
+ elif name == "view":
+ return core.BNGetCurrentView(self.handle)
+ elif name == "offset":
+ return core.BNGetCurrentOffset(self.handle)
+ elif name == "raw":
+ view = core.BNGetFileViewOfType(self.handle, "Raw")
+ if view is None:
+ return None
+ return BinaryView(self, handle = view)
+ raise AttributeError, "no attribute '%s'" % name
+
+ def __setattr__(self, name, value):
+ if name == "filename":
+ core.BNSetFilename(self.handle, str(value))
+ elif name == "navigation":
+ value._register(self.handle)
+ self.__dict__[name] = value
+ elif name == "modified":
+ if value:
+ core.BNMarkFileModified(self.handle)
+ else:
+ core.BNMarkFileSaved(self.handle)
+ elif name == "saved":
+ if value:
+ core.BNMarkFileSaved(self.handle)
+ else:
+ core.BNMarkFileModified(self.handle)
+ elif name == "view":
+ core.BNNavigate(self.handle, str(value), core.BNGetCurrentOffset(self.handle))
+ elif name == "offset":
+ core.BNNavigate(self.handle, core.BNGetCurrentView(self.handle), value)
+ elif (name == "analysis_changed") or (name == "has_database"):
+ raise AttributeError, "attribute '%s' is read only" % name
+ else:
+ self.__dict__[name] = value
+
+ def __dir__(self):
+ return dir(self.__class__) + ["filename", "modified", "analysis_changed", "has_database", "view", "offset"]
+
+ def close(self):
+ core.BNCloseFile(self.handle)
+
+ def begin_undo_actions(self):
+ core.BNBeginUndoActions(self.handle)
+
+ def commit_undo_actions(self):
+ core.BNCommitUndoActions(self.handle)
+
+ def undo(self):
+ core.BNUndo(self.handle)
+
+ def redo(self):
+ core.BNRedo(self.handle)
+
+ 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 open_existing_database(self, filename):
+ view = core.BNOpenExistingDatabase(self.handle, str(filename))
+ if view is None:
+ return None
+ return BinaryView(self, handle = view)
+
+ def save_auto_snapshot(self):
+ return core.BNSaveAutoSnapshot(self.raw.handle)
+
+ def get_view_of_type(self, name):
+ view = core.BNGetFileViewOfType(self.handle, str(name))
+ if view is None:
+ view_type = core.BNGetBinaryViewTypeByName(str(name))
+ if view_type is None:
+ return None
+ view = core.BNCreateBinaryViewOfType(view_type, self.raw.handle)
+ if view is None:
+ return None
+ return BinaryView(self, handle = view)
+
+class FileAccessor:
+ def __init__(self):
+ self._cb = core.BNFileAccessor()
+ self._cb.context = 0
+ self._cb.getLength = self._cb.getLength.__class__(self._get_length)
+ self._cb.read = self._cb.read.__class__(self._read)
+ self._cb.write = self._cb.write.__class__(self._write)
+
+ def __len__(self):
+ return self.get_length()
+
+ def _get_length(self, ctxt):
+ try:
+ return self.get_length()
+ except:
+ log_error(traceback.format_exc())
+ return 0
+
+ def _read(self, ctxt, dest, offset, length):
+ try:
+ data = self.read(offset, length)
+ if data is None:
+ return 0
+ if len(data) > length:
+ data = data[0:length]
+ ctypes.memmove(dest, data, len(data))
+ return len(data)
+ except:
+ 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.write(offset, data.raw)
+ except:
+ log_error(traceback.format_exc())
+ return 0
+
+class CoreFileAccessor(FileAccessor):
+ def __init__(self, accessor):
+ self._cb.context = accessor.context
+ self._cb.getLength = accessor.getLength
+ self._cb.read = accessor.read
+ self._cb.write = accessor.write
+
+ def get_length(self):
+ return self._cb.getLength(self._cb.context)
+
+ def read(self, offset, length):
+ data = ctypes.create_string_buffer(length)
+ length = self._cb.read(self._cb.context, data, offset, length)
+ return data.raw[0:length]
+
+ def write(self, offset, value):
+ value = str(value)
+ data = ctypes.create_string_buffer(value)
+ return self._cb.write(self._cb.context, offset, data, len(value))
+
+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 string_found(self, view, string_type, offset, length):
+ pass
+
+ def string_removed(self, view, string_type, offset, length):
+ pass
+
+class UndoAction:
+ name = None
+ action_type = None
+ _registered = False
+ _registered_cb = None
+
+ def __init__(self, view):
+ self._cb = core.BNUndoAction()
+ if not self.__class__._registered:
+ 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]
+ else:
+ self._cb.type = action_type
+ self._cb.context = 0
+ self._cb.undo = self._cb.undo.__class__(self._undo)
+ self._cb.redo = self._cb.redo.__class__(self._redo)
+ self._cb.serialize = self._cb.serialize.__class__(self._serialize)
+ self.view = view
+
+ @classmethod
+ def register(cls):
+ _init_plugins()
+ if cls.name is None:
+ raise ValueError, "undo action 'name' not defined"
+ if cls.action_type is None:
+ raise ValueError, "undo action 'action_type' not defined"
+ cb_type = ctypes.CFUNCTYPE(ctypes.c_bool, ctypes.c_void_p, ctypes.c_char_p, ctypes.POINTER(core.BNUndoAction))
+ cls._registered_cb = cb_type(cls._deserialize)
+ core.BNRegisterUndoActionType(cls.name, 0, cls._registered_cb)
+ cls._registered = True
+
+ @classmethod
+ def _deserialize(cls, ctxt, data, result):
+ try:
+ action = cls.deserialize(json.loads(data))
+ if action is None:
+ return False
+ result.context = action._cb.context
+ result.undo = action._cb.undo
+ result.redo = action._cb.redo
+ result.serialize = action._cb.serialize
+ return True
+ except:
+ log_error(traceback.format_exc())
+ return False
+
+ def _undo(self, ctxt, view):
+ try:
+ self.undo()
+ except:
+ log_error(traceback.format_exc())
+ return False
+
+ def _redo(self, ctxt, view):
+ try:
+ self.redo()
+ except:
+ log_error(traceback.format_exc())
+ return False
+
+ def _serialize(self, ctxt):
+ try:
+ return json.dumps(self.serialize())
+ except:
+ log_error(traceback.format_exc())
+ return "null"
+
+class StringReference:
+ def __init__(self, string_type, start, length):
+ self.type = string_type
+ self.start = start
+ self.length = length
+
+ def __repr__(self):
+ return "<%s: 0x%x, len 0x%x>" % (self.type, self.start, self.length)
+
+class BinaryDataNotificationCallbacks:
+ 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.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:
+ log_error(traceback.format_exc())
+
+ def _data_inserted(self, ctxt, view, offset, length):
+ try:
+ self.notify.data_inserted(self.view, offset, length)
+ except:
+ log_error(traceback.format_exc())
+
+ def _data_removed(self, ctxt, view, offset, length):
+ try:
+ self.notify.data_removed(self.view, offset, length)
+ except:
+ log_error(traceback.format_exc())
+
+ def _function_added(self, ctxt, view, func):
+ try:
+ self.notify.function_added(self.view, Function(self.view, core.BNNewFunctionReference(func)))
+ except:
+ log_error(traceback.format_exc())
+
+ def _function_removed(self, ctxt, view, func):
+ try:
+ self.notify.function_removed(self.view, Function(self.view, core.BNNewFunctionReference(func)))
+ except:
+ log_error(traceback.format_exc())
+
+ def _function_updated(self, ctxt, view, func):
+ try:
+ self.notify.function_updated(self.view, Function(self.view, core.BNNewFunctionReference(func)))
+ except:
+ log_error(traceback.format_exc())
+
+ def _string_found(self, ctxt, view, string_type, offset, length):
+ try:
+ self.notify.string_found(self.view, core.BNStringType_names[string_type], offset, length)
+ except:
+ log_error(traceback.format_exc())
+
+ def _string_removed(self, ctxt, view, string_type, offset, length):
+ try:
+ self.notify.string_removed(self.view, core.BNStringType_names[string_type], offset, length)
+ except:
+ log_error(traceback.format_exc())
+
+class _BinaryViewTypeMetaclass(type):
+ def __getattr__(cls, name):
+ if name == "list":
+ _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
+ raise AttributeError, "no attribute '%s'" % name
+
+ def __setattr__(self, name, value):
+ if name == "list":
+ raise AttributeError, "attribute '%s' is read only" % name
+ else:
+ self.__dict__[name] = value
+
+ def __dir__(self):
+ return dir(self.__class__) + ["list"]
+
+ def __getitem__(self, value):
+ _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)
+
+class BinaryViewType:
+ __metaclass__ = _BinaryViewTypeMetaclass
+
+ def __init__(self, handle):
+ self.handle = core.handle_of_type(handle, core.BNBinaryViewType)
+
+ def __getattr__(self, name):
+ if name == "name":
+ return core.BNGetBinaryViewTypeName(self.handle)
+ elif name == "long_name":
+ return core.BNGetBinaryViewTypeLongName(self.handle)
+ raise AttributeError, "no attribute '%s'" % name
+
+ def __setattr__(self, name, value):
+ if (name == "name") or (name == "long_name"):
+ raise AttributeError, "attribute '%s' is read only" % name
+ else:
+ self.__dict__[name] = value
+
+ def __dir__(self):
+ return dir(self.__class__) + ["name","long_name"]
+
+ def __repr__(self):
+ return "<view type: '%s'>" % self.name
+
+ def create(self, data):
+ view = core.BNCreateBinaryViewOfType(self.handle, data.handle)
+ if view is None:
+ return None
+ return BinaryView(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, arch):
+ core.BNRegisterArchitectureForViewType(self.handle, ident, arch.handle)
+
+ def get_arch(self, ident):
+ arch = core.BNGetArchitectureForViewType(self.handle, ident)
+ if arch is None:
+ return None
+ return Architecture(arch)
+
+ def register_platform(self, ident, arch, platform):
+ core.BNRegisterPlatformForViewType(self.handle, ident, arch.handle, platform.handle)
+
+ def register_default_platform(self, arch, platform):
+ core.BNRegisterDefaultPlatformForViewType(self.handle, arch.handle, platform.handle)
+
+ def get_platform(self, ident, arch):
+ platform = core.BNGetPlatformForViewType(self.handle, ident, arch.handle)
+ if platform is None:
+ return None
+ return Platform(None, platform)
+
+class BinaryView:
+ name = None
+ long_name = None
+ _registered = False
+ _registered_cb = None
+ view_type = None
+
+ def __init__(self, file_metadata = 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(handle = core.BNGetFileForView(handle))
+ else:
+ self.file = file_metadata
+ elif self.__class__ is BinaryView:
+ _init_plugins()
+ if file_metadata is None:
+ file_metadata = FileMetadata()
+ self.handle = core.BNCreateBinaryDataView(file_metadata.handle)
+ self.file = FileMetadata(handle = core.BNNewFileReference(file_metadata))
+ else:
+ _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
+ self.handle = core.BNCreateCustomBinaryView(self.__class__.name, file_metadata.handle, self._cb)
+ self.notifications = {}
+
+ @classmethod
+ def register(cls):
+ _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.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(handle = core.BNGetFileForView(data))
+ view = cls(BinaryView(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_error(traceback.format_exc())
+ return None
+
+ @classmethod
+ def _is_valid_for_data(cls, ctxt, data):
+ try:
+ return cls.is_valid_for_data(BinaryView(None, handle = core.BNNewViewReference(data)))
+ except:
+ log_error(traceback.format_exc())
+ return False
+
+ @classmethod
+ def open(cls, src, file_metadata = None):
+ _init_plugins()
+ if isinstance(src, FileAccessor):
+ if file_metadata is None:
+ file_metadata = FileMetadata()
+ view = core.BNCreateBinaryDataViewFromFile(file_metadata.handle, src._cb)
+ else:
+ if file_metadata is None:
+ file_metadata = FileMetadata(str(src))
+ view = core.BNCreateBinaryDataViewFromFilename(file_metadata.handle, str(src))
+ if view is None:
+ return None
+ result = BinaryView(file_metadata, handle = view)
+ return result
+
+ @classmethod
+ def new(cls, data = None, file_metadata = None):
+ _init_plugins()
+ if file_metadata is None:
+ file_metadata = FileMetadata()
+ if data is None:
+ view = core.BNCreateBinaryDataView(file_metadata.handle)
+ else:
+ buf = DataBuffer(data)
+ view = core.BNCreateBinaryDataViewFromBuffer(file_metadata.handle, buf.handle)
+ if view is None:
+ return None
+ result = BinaryView(file_metadata, handle = view)
+ return result
+
+ def __del__(self):
+ for i in self.notifications.values():
+ i._unregister()
+ core.BNFreeBinaryView(self.handle)
+
+ def __getattr__(self, name):
+ if name == "modified":
+ return self.file.modified
+ elif name == "analysis_changed":
+ return self.file.analysis_changed
+ elif name == "has_database":
+ return self.file.has_database
+ elif name == "view":
+ return self.file.view
+ elif name == "offset":
+ return self.file.offset
+ elif name == "start":
+ return core.BNGetStartOffset(self.handle)
+ elif name == "end":
+ return core.BNGetEndOffset(self.handle)
+ elif name == "entry_point":
+ return core.BNGetEntryPoint(self.handle)
+ elif name == "arch":
+ arch = core.BNGetDefaultArchitecture(self.handle)
+ if arch is None:
+ return None
+ return Architecture(handle = arch)
+ elif name == "platform":
+ platform = core.BNGetDefaultPlatform(self.handle)
+ if platform is None:
+ return None
+ return Platform(self.arch, handle = platform)
+ elif name == "endianness":
+ return core.BNGetDefaultEndianness(self.handle)
+ elif name == "address_size":
+ return core.BNGetViewAddressSize(self.handle)
+ elif name == "executable":
+ return core.BNIsExecutableView(self.handle)
+ elif name == "functions":
+ count = ctypes.c_ulonglong(0)
+ funcs = core.BNGetAnalysisFunctionList(self.handle, count)
+ result = []
+ for i in xrange(0, count.value):
+ result.append(Function(self, core.BNNewFunctionReference(funcs[i])))
+ core.BNFreeFunctionList(funcs, count.value)
+ return result
+ elif name == "has_functions":
+ return core.BNHasFunctions(self.handle)
+ elif name == "entry_function":
+ func = core.BNGetAnalysisEntryPoint(self.handle)
+ if func is None:
+ return None
+ return Function(self, func)
+ elif name == "symbols":
+ count = ctypes.c_ulonglong(0)
+ syms = core.BNGetSymbols(self.handle, count)
+ result = {}
+ for i in xrange(0, count.value):
+ sym = Symbol(None, None, None, handle = core.BNNewSymbolReference(syms[i]))
+ result[sym.raw_name] = sym
+ core.BNFreeSymbolList(syms, count.value)
+ return result
+ elif name == "type":
+ return core.BNGetViewType(self.handle)
+ elif name == "available_types":
+ 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
+ elif name == "strings":
+ return self.get_strings()
+ raise AttributeError, "no attribute '%s'" % name
+
+ def __setattr__(self, name, value):
+ if name == "modified":
+ self.file.modified = value
+ elif name == "saved":
+ self.file.saved = value
+ elif name == "view":
+ self.file.view = value
+ elif name == "offset":
+ self.file.offset = value
+ elif name == "arch":
+ if value is None:
+ core.BNSetDefaultArchitecture(self.handle, None)
+ else:
+ core.BNSetDefaultArchitecture(self.handle, value.handle)
+ elif name == "platform":
+ if value is None:
+ core.BNSetDefaultPlatform(self.handle, None)
+ else:
+ core.BNSetDefaultPlatform(self.handle, value.handle)
+ elif ((name == "analysis_changed") or (name == "has_database") or (name == "start") or (name == "end") or
+ (name == "entry_point") or (name == "endianness") or (name == "address_size") or
+ (name == "executable") or (name == "functions") or (name == "has_functions") or
+ (name == "entry_function") or (name == "symbols") or (name == "type") or (name == "available_types") or
+ (name == "strings")):
+ raise AttributeError, "attribute '%s' is read only" % name
+ else:
+ self.__dict__[name] = value
+
+ def __dir__(self):
+ return dir(self.__class__) + ["modified", "analysis_changed", "has_database", "view", "offset", "start", "end", "entry_point", "arch", "platform", "endianness", "address_size", "executable", "functions", "has_functions", "entry_function", "symbols", "type", "available_types", "strings"]
+
+ 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 0x%x, len 0x%x" % (start, length)
+ else:
+ size = "len 0x%x" % length
+ filename = self.file.filename
+ if len(filename) > 0:
+ return "<%s view: '%s', %s>" % (self.type, filename, size)
+ return "<%s view: %s>" % (self.type, size)
+
+ def _init(self, ctxt):
+ try:
+ return self.init()
+ except:
+ 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_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_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_error(traceback.format_exc())
+ return 0
+
+ def _remove(self, ctxt, offset, length):
+ try:
+ return self.perform_remove(offset, length)
+ except:
+ log_error(traceback.format_exc())
+ return 0
+
+ def _get_modification(self, ctxt, offset):
+ try:
+ return self.perform_get_modification(offset)
+ except:
+ log_error(traceback.format_exc())
+ return core.Original
+
+ def _is_valid_offset(self, ctxt, offset):
+ try:
+ return self.perform_is_valid_offset(offset)
+ except:
+ log_error(traceback.format_exc())
+ return False
+
+ def _is_offset_readable(self, ctxt, offset):
+ try:
+ return self.perform_is_offset_readable(offset)
+ except:
+ log_error(traceback.format_exc())
+ return False
+
+ def _is_offset_writable(self, ctxt, offset):
+ try:
+ return self.perform_is_offset_writable(offset)
+ except:
+ log_error(traceback.format_exc())
+ return False
+
+ def _is_offset_executable(self, ctxt, offset):
+ try:
+ return self.perform_is_offset_executable(offset)
+ except:
+ 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_error(traceback.format_exc())
+ return offset
+
+ def _get_start(self, ctxt):
+ try:
+ return self.perform_get_start()
+ except:
+ log_error(traceback.format_exc())
+ return 0
+
+ def _get_length(self, ctxt):
+ try:
+ return self.perform_get_length()
+ except:
+ log_error(traceback.format_exc())
+ return 0
+
+ def _get_entry_point(self, ctxt):
+ try:
+ return self.perform_get_entry_point()
+ except:
+ log_error(traceback.format_exc())
+ return 0
+
+ def _is_executable(self, ctxt):
+ try:
+ return self.perform_is_executable()
+ except:
+ log_error(traceback.format_exc())
+ return False
+
+ def _get_default_endianness(self, ctxt):
+ try:
+ return self.perform_get_default_endianness()
+ except:
+ log_error(traceback.format_exc())
+ return core.LittleEndian
+
+ def _get_address_size(self, ctxt):
+ try:
+ return self.perform_get_address_size()
+ except:
+ log_error(traceback.format_exc())
+ return 8
+
+ def _save(self, ctxt, file_accessor):
+ try:
+ return self.perform_save(CoreFileAccessor(file_accessor))
+ except:
+ log_error(traceback.format_exc())
+ return False
+
+ def init(self):
+ return True
+
+ def perform_write(self, offset, data):
+ return 0
+
+ def perform_insert(self, offset, data):
+ return 0
+
+ def perform_remove(self, offset, length):
+ return 0
+
+ def perform_get_modification(self, offset):
+ return core.Original
+
+ def perform_is_valid_offset(self, offset):
+ data = self.read(offset, 1)
+ return (data is not None) and (len(data) == 1)
+
+ def perform_is_offset_readable(self, offset):
+ return self.is_valid_offset(offset)
+
+ def perform_is_offset_writable(self, offset):
+ return self.is_valid_offset(offset)
+
+ def perform_is_offset_executable(self, offset):
+ return self.is_valid_offset(offset)
+
+ def perform_get_next_valid_offset(self, offset):
+ if offset < self.perform_get_start():
+ return self.perform_get_start()
+ return offset
+
+ def perform_get_start(self):
+ return 0
+
+ def perform_get_entry_point(self):
+ return 0
+
+ def perform_is_executable(self):
+ return False
+
+ def perform_get_default_endianness(self):
+ return core.LittleEndian
+
+ def create_database(self, filename):
+ return self.file.create_database(filename)
+
+ def save_auto_snapshot(self):
+ return self.file.save_auto_snapshot()
+
+ def get_view_of_type(self, name):
+ return self.file.get_view_of_type(name)
+
+ def begin_undo_actions(self):
+ 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):
+ self.file.commit_undo_actions()
+
+ def undo(self):
+ self.file.undo()
+
+ def redo(self):
+ self.file.redo()
+
+ def navigate(self, view, offset):
+ self.file.navigate(view, offset)
+
+ def read(self, offset, length):
+ buf = DataBuffer(handle = core.BNReadViewBuffer(self.handle, offset, length))
+ return str(buf)
+
+ def write(self, offset, data):
+ buf = DataBuffer(data)
+ return core.BNWriteViewBuffer(self.handle, offset, buf.handle)
+
+ def insert(self, offset, data):
+ buf = DataBuffer(data)
+ return core.BNInsertViewBuffer(self.handle, offset, buf.handle)
+
+ def remove(self, offset, length):
+ return core.BNRemoveViewData(self.handle, offset, length)
+
+ def get_modification(self, offset, length = None):
+ if length is None:
+ return core.BNGetModification(self.handle, offset)
+ data = (core.BNModificationStatus * length)()
+ length = core.BNGetModificationArray(self.handle, offset, data, length);
+ return data[0:length]
+
+ def is_valid_offset(self, offset):
+ return core.BNIsValidOffset(self.handle, offset)
+
+ def is_offset_readable(self, offset):
+ return core.BNIsOffsetReadable(self.handle, offset)
+
+ def is_offset_writable(self, offset):
+ return core.BNIsOffsetWritable(self.handle, offset)
+
+ def is_offset_executable(self, offset):
+ return core.BNIsOffsetExecutable(self.handle, offset)
+
+ def save(self, dest):
+ if isinstance(dest, 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, platform, addr):
+ core.BNAddFunctionForAnalysis(self.handle, platform.handle, addr)
+
+ def add_entry_point(self, platform, addr):
+ core.BNAddEntryPointForAnalysis(self.handle, platform.handle, addr)
+
+ def remove_function(self, func):
+ core.BNRemoveAnalysisFunction(self.handle, func.handle)
+
+ def create_user_function(self, arch, addr):
+ core.BNCreateUserFunction(self.handle, arch.handle, addr)
+
+ def update_analysis(self):
+ core.BNUpdateAnalysis(self.handle)
+
+ def abort_analysis(self):
+ core.BNAbortAnalysis(self.handle)
+
+ def get_function_at(self, arch, addr):
+ func = core.BNGetAnalysisFunction(self.handle, arch.handle, addr)
+ if func is None:
+ return None
+ return Function(self, func)
+
+ def get_functions_at(self, addr):
+ count = ctypes.c_ulonglong(0)
+ funcs = core.BNGetAnalysisFunctionsForAddress(self.handle, addr, count)
+ result = []
+ for i in xrange(0, count.value):
+ result.append(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(self, func)
+
+ def get_basic_blocks_at(self, addr):
+ count = ctypes.c_ulonglong(0)
+ blocks = core.BNGetBasicBlocksForAddress(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:
+ return None
+ return 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(self, core.BNNewFunctionReference(refs[i].func))
+ else:
+ func = None
+ if refs[i].arch:
+ arch = Architecture(refs[i].arch)
+ else:
+ arch = None
+ addr = refs[i].addr
+ result.append(ReferenceSource(func, arch, addr))
+ core.BNFreeCodeReferences(refs, count.value)
+ return result
+
+ def get_symbol_at(self, addr):
+ sym = core.BNGetSymbolByAddress(self.handle, addr)
+ if sym is None:
+ return None
+ return Symbol(None, None, None, handle = sym)
+
+ def get_symbol_by_raw_name(self, name):
+ sym = core.BNGetSymbolByRawName(self.handle, name)
+ if sym is None:
+ return None
+ return Symbol(None, None, None, handle = sym)
+
+ def get_symbols_by_name(self, name):
+ count = ctypes.c_ulonglong(0)
+ syms = core.BNGetSymbolsByName(self.handle, name, count)
+ result = []
+ for i in xrange(0, count.value):
+ result.append(Symbol(None, None, None, handle = core.BNNewSymbolReference(syms[i])))
+ core.BNFreeSymbolList(syms, count.value)
+ return result
+
+ def get_symbols(self, start = None, length = None):
+ 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(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):
+ if isinstance(sym_type, str):
+ sym_type = core.BNSymbolType_by_name[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(Symbol(None, None, None, handle = core.BNNewSymbolReference(syms[i])))
+ core.BNFreeSymbolList(syms, count.value)
+ return result
+
+ def define_auto_symbol(self, sym):
+ core.BNDefineAutoSymbol(self.handle, sym.handle)
+
+ def undefine_auto_symbol(self, sym):
+ core.BNUndefineAutoSymbol(self.handle, sym.handle)
+
+ def define_user_symbol(self, sym):
+ core.BNDefineUserSymbol(self.handle, sym.handle)
+
+ def undefine_user_symbol(self, sym):
+ core.BNUndefineUserSymbol(self.handle, sym.handle)
+
+ def define_imported_function(self, import_addr_sym, func):
+ core.BNDefineImportedFunction(self.handle, import_addr_sym.handle, func.handle)
+
+ def is_never_branch_patch_available(self, arch, addr):
+ return core.BNIsNeverBranchPatchAvailable(self.handle, arch.handle, addr)
+
+ def is_always_branch_patch_available(self, arch, addr):
+ return core.BNIsAlwaysBranchPatchAvailable(self.handle, arch.handle, addr)
+
+ def is_invert_branch_patch_available(self, arch, addr):
+ return core.BNIsInvertBranchPatchAvailable(self.handle, arch.handle, addr)
+
+ def is_skip_and_return_zero_patch_available(self, arch, addr):
+ return core.BNIsSkipAndReturnZeroPatchAvailable(self.handle, arch.handle, addr)
+
+ def is_skip_and_return_value_patch_available(self, arch, addr):
+ return core.BNIsSkipAndReturnValuePatchAvailable(self.handle, arch.handle, addr)
+
+ def convert_to_nop(self, arch, addr):
+ return core.BNConvertToNop(self.handle, arch.handle, addr)
+
+ def always_branch(self, arch, addr):
+ return core.BNAlwaysBranch(self.handle, arch.handle, addr)
+
+ def never_branch(self, arch, addr):
+ return core.BNConvertToNop(self.handle, arch.handle, addr)
+
+ def invert_branch(self, arch, addr):
+ return core.BNInvertBranch(self.handle, arch.handle, addr)
+
+ def skip_and_return_value(self, arch, addr, value):
+ return core.BNSkipAndReturnValue(self.handle, arch.handle, addr, value)
+
+ def get_instruction_length(self, arch, addr):
+ 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):
+ 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_names[strings[i].type], strings[i].start, strings[i].length))
+ core.BNFreeStringList(strings)
+ return result
+
+class BinaryReader:
+ def __init__(self, data, endian = None):
+ self.handle = core.BNCreateBinaryReader(data.handle)
+ if endian is None:
+ core.BNSetBinaryReaderEndianness(self.handle, data.endianness)
+ else:
+ core.BNSetBinaryReaderEndianness(self.handle, endian)
+
+ def __del__(self):
+ core.BNFreeBinaryReader(self.handle)
+
+ def __getattr__(self, name):
+ if name == "endianness":
+ return core.BNGetBinaryReaderEndianness(self.handle)
+ elif name == "offset":
+ return core.BNGetReaderPosition(self.handle)
+ elif name == "eof":
+ return core.BNIsEndOfFile(self.handle)
+ raise AttributeError, "no attribute '%s'" % name
+
+ def __setattr__(self, name, value):
+ if (name == "eof"):
+ raise AttributeError, "attribute '%s' is read only" % name
+ elif name == "endianness":
+ core.BNSetBinaryReaderEndianness(self.handle, value)
+ elif name == "offset":
+ core.BNSeekBinaryReader(self.handle, value)
+ else:
+ self.__dict__[name] = value
+
+ def __dir__(self):
+ return dir(self.__class__) + ["endianness","offset", "eof"]
+
+ def read(self, length):
+ dest = ctypes.create_string_buffer(length)
+ if not core.BNReadData(self.handle, dest, length):
+ return None
+ return dest.raw
+
+ def read8(self):
+ result = ctypes.c_ubyte()
+ if not core.BNRead8(self.handle, result):
+ return None
+ return result.value
+
+ def read16(self):
+ result = ctypes.c_ushort()
+ if not core.BNRead16(self.handle, result):
+ return None
+ return result.value
+
+ def read32(self):
+ result = ctypes.c_uint()
+ if not core.BNRead32(self.handle, result):
+ return None
+ return result.value
+
+ def read64(self):
+ result = ctypes.c_ulonglong()
+ if not core.BNRead64(self.handle, result):
+ return None
+ return result.value
+
+ def read16le(self):
+ result = self.read(2)
+ if (result is None) or (len(result) != 2):
+ return None
+ return struct.unpack("<H", result)[0]
+
+ def read32le(self):
+ result = self.read(4)
+ if (result is None) or (len(result) != 4):
+ return None
+ return struct.unpack("<I", result)[0]
+
+ def read64le(self):
+ result = self.read(8)
+ if (result is None) or (len(result) != 8):
+ return None
+ return struct.unpack("<Q", result)[0]
+
+ def read16be(self):
+ result = self.read(2)
+ if (result is None) or (len(result) != 2):
+ return None
+ return struct.unpack(">H", result)[0]
+
+ def read32be(self):
+ result = self.read(4)
+ if (result is None) or (len(result) != 4):
+ return None
+ return struct.unpack(">I", result)[0]
+
+ def read64be(self):
+ result = self.read(8)
+ if (result is None) or (len(result) != 8):
+ return None
+ return struct.unpack(">Q", result)[0]
+
+ def seek(self, offset):
+ core.BNSeekBinaryReader(self.handle, offset)
+
+ def seek_relative(self, offset):
+ core.BNSeekBinaryReaderRelative(self.handle, offset)
+
+class BinaryWriter:
+ def __init__(self, data, endian = None):
+ self.handle = core.BNCreateBinaryWriter(data.handle)
+ if endian is None:
+ core.BNSetBinaryWriterEndianness(self.handle, data.endianness)
+ else:
+ core.BNSetBinaryWriterEndianness(self.handle, endian)
+
+ def __del__(self):
+ core.BNFreeBinaryWriter(self.handle)
+
+ def __getattr__(self, name):
+ if name == "endianness":
+ return core.BNGetBinaryWriterEndianness(self.handle)
+ elif name == "offset":
+ return core.BNGetWriterPosition(self.handle)
+ raise AttributeError, "no attribute '%s'" % name
+
+ def __setattr__(self, name, value):
+ if name == "endianness":
+ core.BNSetBinaryWriterEndianness(self.handle, value)
+ elif name == "offset":
+ core.BNSeekBinaryWriter(self.handle, value)
+ else:
+ self.__dict__[name] = value
+
+ def __dir__(self):
+ return dir(self.__class__) + ["endianness","offset"]
+
+ def write(self, value):
+ 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):
+ return core.BNWrite8(self.handle, value)
+
+ def write16(self, value):
+ return core.BNWrite16(self.handle, value)
+
+ def write32(self, value):
+ return core.BNWrite32(self.handle, value)
+
+ def write64(self, value):
+ return core.BNWrite64(self.handle, value)
+
+ def write16le(self, value):
+ value = struct.pack("<H", value)
+ return self.write(value)
+
+ def write32le(self, value):
+ value = struct.pack("<I", value)
+ return self.write(value)
+
+ def write64le(self, value):
+ value = struct.pack("<Q", value)
+ return self.write(value)
+
+ def write16be(self, value):
+ value = struct.pack(">H", value)
+ return self.write(value)
+
+ def write32be(self, value):
+ value = struct.pack(">I", value)
+ return self.write(value)
+
+ def write64be(self, value):
+ value = struct.pack(">Q", value)
+ return self.write(value)
+
+ def seek(self, offset):
+ core.BNSeekBinaryWriter(self.handle, offset)
+
+ def seek_relative(self, offset):
+ core.BNSeekBinaryWriterRelative(self.handle, offset)
+
+class Symbol:
+ 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_by_name[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)
+
+ def __getattr__(self, name):
+ if name == "type":
+ return core.BNSymbolType_names[core.BNGetSymbolType(self.handle)]
+ elif name == "name":
+ return core.BNGetSymbolRawName(self.handle)
+ elif name == "short_name":
+ return core.BNGetSymbolShortName(self.handle)
+ elif name == "full_name":
+ return core.BNGetSymbolFullName(self.handle)
+ elif name == "raw_name":
+ return core.BNGetSymbolRawName(self.handle)
+ elif name == "address":
+ return core.BNGetSymbolAddress(self.handle)
+ elif name == "auto":
+ return core.BNIsSymbolAutoDefined(self.handle)
+ raise AttributeError, "no attribute '%s'" % name
+
+ def __setattr__(self, name, value):
+ if ((name == "type") or (name == "name") or (name == "short_name") or (name == "full_name") or
+ (name == "raw_name") or (name == "address")):
+ raise AttributeError, "attribute '%s' is read only" % name
+ elif name == "auto":
+ core.BNSetSymbolAutoDefined(self.handle, value)
+ else:
+ self.__dict__[name] = value
+
+ def __dir__(self):
+ return dir(self.__class__) + ["type","name", "short_name", "full_name", "raw_name", "address", "auto"]
+
+ def __repr__(self):
+ return "<%s: \"%s\" @ 0x%x>" % (self.type, self.full_name, self.address)
+
+class Type:
+ def __init__(self, handle):
+ self.handle = handle
+
+ def __del__(self):
+ core.BNFreeType(self.handle)
+
+ def __getattr__(self, name):
+ if name == "type_class":
+ return BNTypeClass_names[core.BNGetTypeClass(self.handle)]
+ elif name == "width":
+ return core.BNGetTypeWidth(self.handle)
+ elif name == "alignment":
+ return core.BNGetTypeAlignment(self.handle)
+ elif name == "signed":
+ return core.BNIsTypeSigned(self.handle)
+ elif name == "const":
+ return core.BNIsTypeConst(self.handle)
+ elif name == "float":
+ return core.BNIsTypeFloatingPoint(self.handle)
+ elif (name == "target") or (name == "element_type") or (name == "return_value"):
+ result = core.BNGetChildType(self.handle)
+ if result is None:
+ return None
+ return Type(result)
+ elif name == "calling_convention":
+ result = core.BNGetTypeCallingConvention(self.handle)
+ if result is None:
+ return None
+ return CallingConvention(None, result)
+ elif name == "parameters":
+ 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
+ elif name == "has_variable_arguments":
+ return core.BNTypeHasVariableArguments(self.handle)
+ elif name == "can_return":
+ return core.BNFunctionTypeCanReturn(self.handle)
+ elif name == "structure":
+ result = core.BNGetTypeStructure(self.handle)
+ if result is None:
+ return None
+ return Structure(result)
+ elif name == "enumeration":
+ result = core.BNGetTypeEnumeration(self.handle)
+ if result is None:
+ return None
+ return Enumeration(result)
+ elif name == "count":
+ return core.BNGetTypeElementCount(self.handle)
+ raise AttributeError, "no attribute '%s'" % name
+
+ def __setattr__(self, name, value):
+ if ((name == "type_class") or (name == "width") or (name == "alignment") or (name == "signed") or
+ (name == "const") or (name == "float") or (name == "target") or (name == "element_type") or
+ (name == "return_value") or (name == "parameters") or (name == "has_variable_arguments") or
+ (name == "can_return") or (name == "structure") or (name == "enumeration") or (name == "count")):
+ raise AttributeError, "attribute '%s' is read only" % name
+ else:
+ self.__dict__[name] = value
+
+ def __dir__(self):
+ return dir(self.__class__) + ["type_class", "width", "alignment", "signed", "const", "float", "target", "element_type", "return_value", "calling_convention", "parameters", "has_variable_arguments", "can_return", "structure", "enumeration", "count"]
+
+ def __str__(self):
+ return core.BNGetTypeString(self.handle)
+
+ def __repr__(self):
+ return "<type: %s>" % 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):
+ return Type(core.BNCreateIntegerType(width, sign))
+
+ @classmethod
+ def float(self, width):
+ return Type(core.BNCreateFloatType(width))
+
+ @classmethod
+ def structure_type(self, s):
+ return Type(core.BNCreateStructureType(s.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))
+
+class StructureMember:
+ def __init__(self, t, name, offset):
+ self.type = t
+ self.name = name
+ self.offset = offset
+
+ def __repr__(self):
+ if len(name) == 0:
+ return "<member: %s, offset 0x%x>" % (str(self.type), self.offset)
+ return "<%s %s%s, offset 0x%x>" % (self.type.get_string_before_name(), self.name,
+ self.type.get_string_after_name(), self.offset)
+
+class Structure:
+ def __init__(self, handle = None):
+ if handle is None:
+ self.handle = core.BNCreateStructure()
+ else:
+ self.handle = handle
+
+ def __del__(self):
+ core.BNFreeStructure(self.handle)
+
+ def __getattr__(self, name):
+ if name == "name":
+ return core.BNGetStructureName(self.handle)
+ elif name == "members":
+ 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
+ elif name == "width":
+ return core.BNGetStructureWidth(self.handle)
+ elif name == "alignment":
+ return core.BNGetStructureAlignment(self.handle)
+ elif name == "packed":
+ return core.BNIsStructurePacked(self.handle)
+ elif name == "union":
+ return core.BNIsStructureUnion(self.handle)
+ raise AttributeError, "no attribute '%s'" % name
+
+ def __setattr__(self, name, value):
+ if (name == "members") or (name == "width") or (name == "alignment"):
+ raise AttributeError, "attribute '%s' is read only" % name
+ elif name == "name":
+ core.BNSetStructureName(self.handle, value)
+ elif name == "packed":
+ core.BNSetStructurePacked(self.handle, value)
+ elif name == "union":
+ core.BNSetStructureUnion(self.handle, value)
+ else:
+ self.__dict__[name] = value
+
+ def __dir__(self):
+ return dir(self.__class__) + ["name","members", "width", "alignment", "packed", "union"]
+
+ def __repr__(self):
+ if len(self.name) > 0:
+ return "<struct: %s>" % self.name
+ return "<struct: size 0x%x>" % 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:
+ def __init__(self, name, value, default):
+ self.name = name
+ self.value = value
+ self.default = default
+
+ def __repr__(self):
+ return "<%s = 0x%x>" % (self.name, self.value)
+
+class Enumeration:
+ def __init__(self, handle = None):
+ if handle is None:
+ self.handle = core.BNCreateEnumeration()
+ else:
+ self.handle = handle
+
+ def __del__(self):
+ core.BNFreeEnumeration(self.handle)
+
+ def __getattr__(self, name):
+ if name == "name":
+ return core.BNGetEnumerationName(self.handle)
+ elif name == "members":
+ 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
+ raise AttributeError, "no attribute '%s'" % name
+
+ def __setattr__(self, name, value):
+ if name == "members":
+ raise AttributeError, "attribute '%s' is read only" % name
+ elif name == "name":
+ core.BNSetEnumerationName(self.handle, value)
+ else:
+ self.__dict__[name] = value
+
+ def __dir__(self):
+ return dir(self.__class__) + ["name", "members"]
+
+ def __repr__(self):
+ if len(self.name) > 0:
+ return "<enum: %s>" % self.name
+ return "<enum: %s>" % 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 RegisterValue:
+ def __init__(self, arch, value_type, reg, value):
+ self.type = core.BNRegisterValueType_names[value_type]
+ if value_type == EntryValue:
+ self.reg = arch.get_reg_name(reg)
+ elif value_type == OffsetFromEntryValue:
+ self.reg = arch.get_reg_name(reg)
+ self.offset = value
+ elif value_type == ConstantValue:
+ self.value = value
+ elif value_type == StackFrameOffset:
+ self.offset = value
+
+ def __repr__(self):
+ if self.type == "EntryValue":
+ return "<entry %s>" % self.reg
+ if self.type == "OffsetFromEntryValue":
+ return "<entry %s + 0x%x>" % (self.reg, self.offset)
+ if self.type == "ConstantValue":
+ return "<const 0x%x>" % self.value
+ if self.type == "StackFrameOffset":
+ return "<stack frame offset 0x%x>" % self.offset
+ return "<undetermined>"
+
+class StackVariable:
+ def __init__(self, ofs, name, t):
+ self.offset = ofs
+ self.name = name
+ self.type = t
+
+ def __repr__(self):
+ return "<var@%x: %s %s>" % (self.offset, self.type, self.name)
+
+ def __str__(self):
+ return self.name
+
+class StackVariableReference:
+ def __init__(self, src_operand, t, name, start_ofs, ref_ofs):
+ self.source_operand = src_operand
+ self.type = t
+ self.name = name
+ self.starting_offset = start_ofs
+ self.referenced_offset = ref_ofs
+ if self.source_operand == 0xffffffff:
+ self.source_operand = None
+
+ def __repr__(self):
+ if self.source_operand is None:
+ if self.referenced_offset != self.starting_offset:
+ return "<ref to %s%+x>" % (self.name, self.referenced_offset - self.starting_offset)
+ return "<ref to %s>" % self.name
+ if self.referenced_offset != self.starting_offset:
+ 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 Function:
+ def __init__(self, view, handle):
+ self._view = view
+ self.handle = core.handle_of_type(handle, core.BNFunction)
+
+ def __del__(self):
+ core.BNFreeFunction(self.handle)
+
+ def __getattr__(self, name):
+ if name == "view":
+ return self._view
+ elif name == "arch":
+ arch = core.BNGetFunctionArchitecture(self.handle)
+ if arch is None:
+ return None
+ return Architecture(arch)
+ elif name == "start":
+ return core.BNGetFunctionStart(self.handle)
+ elif name == "symbol":
+ sym = core.BNGetFunctionSymbol(self.handle)
+ if sym is None:
+ return None
+ return Symbol(None, None, None, handle = sym)
+ elif name == "auto":
+ return core.BNWasFunctionAutomaticallyDiscovered(self.handle)
+ elif name == "can_return":
+ return core.BNCanFunctionReturn(self.handle)
+ elif name == "explicitly_defined_type":
+ return core.BNHasExplicitlyDefinedType(self.handle)
+ elif name == "basic_blocks":
+ count = ctypes.c_ulonglong()
+ blocks = core.BNGetFunctionBasicBlockList(self.handle, count)
+ result = []
+ for i in xrange(0, count.value):
+ result.append(BasicBlock(self._view, core.BNNewBasicBlockReference(blocks[i])))
+ core.BNFreeBasicBlockList(blocks, count.value)
+ return result
+ elif name == "comments":
+ count = ctypes.c_ulonglong()
+ addrs = core.BNGetCommentedAddresses(self.handle, count)
+ result = {}
+ for i in xrange(0, count.value):
+ result[addrs[i]] = self.get_comment_at(addrs[i])
+ core.BNFreeAddressList(addrs)
+ return result
+ elif name == "low_level_il":
+ return LowLevelILFunction(self.arch, core.BNNewLowLevelILFunctionReference(
+ core.BNGetFunctionLowLevelIL(self.handle)))
+ elif name == "low_level_il_basic_blocks":
+ count = ctypes.c_ulonglong()
+ blocks = core.BNGetFunctionLowLevelILBasicBlockList(self.handle, count)
+ result = []
+ for i in xrange(0, count.value):
+ result.append(BasicBlock(self._view, core.BNNewBasicBlockReference(blocks[i])))
+ core.BNFreeBasicBlockList(blocks, count.value)
+ return result
+ elif name == "type":
+ return Type(core.BNGetFunctionType(self.handle))
+ elif name == "stack_layout":
+ count = ctypes.c_ulonglong()
+ v = core.BNGetStackLayout(self.handle, count)
+ result = []
+ for i in xrange(0, count.value):
+ result.append(StackVariable(v[i].offset, v[i].name, Type(handle = core.BNNewTypeReference(v[i].type))))
+ result.sort(key = lambda x: x.offset)
+ core.BNFreeStackLayout(v, count.value)
+ return result
+ raise AttributeError, "no attribute '%s'" % name
+
+ def __setattr__(self, name, value):
+ if ((name == "view") or (name == "arch") or (name == "start") or (name == "symbol") or (name == "auto") or
+ (name == "can_return") or (name == "basic_blocks") or (name == "comments") or (name == "low_level_il") or
+ (name == "low_level_il_basic_blocks") or (name == "type") or (name == "explicitly_defined_type") or
+ (name == "stack_layout")):
+ raise AttributeError, "attribute '%s' is read only" % name
+ else:
+ self.__dict__[name] = value
+
+ def __dir__(self):
+ return dir(self.__class__) + ["view", "arch", "start", "symbol", "auto", "can_return", "explicitly_defined_type", "basic_blocks", "comments", "low_level_il", "low_level_il_basic_blocks", "type", "stack_layout"]
+
+ def __repr__(self):
+ arch = self.arch
+ if arch:
+ return "<func: %s@0x%x>" % (arch.name, self.start)
+ else:
+ return "<func: 0x%x>" % self.start
+
+ def mark_recent_use(self):
+ core.BNMarkFunctionAsRecentlyUsed(self.handle)
+
+ def get_comment_at(self, addr):
+ return core.BNGetCommentForAddress(self.handle, addr)
+
+ def set_comment(self, addr, comment):
+ core.BNSetCommentForAddress(self.handle, addr, comment)
+
+ def get_low_level_il_at(self, arch, addr):
+ return core.BNGetLowLevelILForInstruction(self.handle, arch.handle, addr)
+
+ def get_low_level_il_exits_at(self, arch, addr):
+ count = ctypes.c_ulonglong()
+ exits = core.BNGetLowLevelILExitsForInstruction(self.handle, arch.handle, addr, count)
+ result = []
+ for i in xrange(0, count.value):
+ result.append(exits[i])
+ core.BNFreeLowLevelILInstructionList(exits)
+ return result
+
+ def get_reg_value_at(self, arch, addr, reg):
+ if isinstance(reg, str):
+ reg = arch.regs[reg].index
+ value = core.BNGetRegisterValueAtInstruction(self.handle, arch.handle, addr, reg)
+ return RegisterValue(arch, value.state, value.reg, value.value)
+
+ def get_reg_value_after(self, arch, addr, reg):
+ if isinstance(reg, str):
+ reg = arch.regs[reg].index
+ value = core.BNGetRegisterValueAfterInstruction(self.handle, arch.handle, addr, reg)
+ return RegisterValue(arch, value.state, value.reg, value.value)
+
+ def get_reg_value_at_low_level_il_instruction(self, i, reg):
+ if isinstance(reg, str):
+ reg = self.arch.regs[reg].index
+ value = core.BNGetRegisterValueAtInstruction(self.handle, self.arch.handle, i, reg)
+ return RegisterValue(self.arch, value.state, value.reg, value.value)
+
+ def get_reg_value_after_low_level_il_instruction(self, i, reg):
+ if isinstance(reg, str):
+ reg = self.arch.regs[reg].index
+ value = core.BNGetRegisterValueAfterInstruction(self.handle, self.arch.handle, i, reg)
+ return RegisterValue(self.arch, value.state, value.reg, value.value)
+
+ def get_regs_read_by(self, arch, addr):
+ count = ctypes.c_ulonglong()
+ regs = core.BNGetRegistersReadByInstruction(self.handle, arch.handle, addr, count)
+ result = []
+ for i in xrange(0, count.value):
+ result.append(arch.get_reg_name(regs[i]))
+ core.BNFreeRegisterList(regs)
+ return result
+
+ def get_regs_written_by(self, arch, addr):
+ count = ctypes.c_ulonglong()
+ regs = core.BNGetRegistersWrittenByInstruction(self.handle, arch.handle, addr, count)
+ result = []
+ for i in xrange(0, count.value):
+ result.append(arch.get_reg_name(regs[i]))
+ core.BNFreeRegisterList(regs)
+ return result
+
+ def get_stack_vars_referenced_by(self, arch, addr):
+ count = ctypes.c_ulonglong()
+ refs = core.BNGetStackVariablesReferencedByInstruction(self.handle, arch.handle, addr, count)
+ result = []
+ for i in xrange(0, count.value):
+ result.append(StackVariableReference(refs[i].sourceOperand, Type(core.BNNewTypeReference(refs[i].type)),
+ refs[i].name, refs[i].startingOffset, refs[i].referencedOffset))
+ core.BNFreeStackVariableReferenceList(refs, count.value)
+ return result
+
+ def create_graph(self):
+ return FunctionGraph(self._view, core.BNCreateFunctionGraph(self.handle))
+
+ def apply_imported_types(self, sym):
+ core.BNApplyImportedTypes(self.handle, sym.handle)
+
+ def apply_auto_discovered_type(self, func_type):
+ core.BNApplyAutoDiscoveredFunctionType(self.handle, func_type.handle)
+
+class BasicBlockEdge:
+ def __init__(self, branch_type, target, arch):
+ self.type = core.BNBranchType_names[branch_type]
+ if self.type != "UnresolvedBranch":
+ self.target = target
+ self.arch = arch
+
+ def __repr__(self):
+ if self.type == "UnresolvedBranch":
+ return "<%s>" % self.type
+ elif self.arch:
+ return "<%s: %s@0x%x>" % (self.type, self.arch.name, self.target)
+ else:
+ return "<%s: 0x%x>" % (self.type, self.target)
+
+class BasicBlock:
+ def __init__(self, view, handle):
+ self.view = view
+ self.handle = core.handle_of_type(handle, core.BNBasicBlock)
+
+ def __del__(self):
+ core.BNFreeBasicBlock(self.handle)
+
+ def __getattr__(self, name):
+ if name == "function":
+ func = core.BNGetBasicBlockFunction(self.handle)
+ if func is None:
+ return None
+ return Function(self.view, func)
+ elif name == "arch":
+ arch = core.BNGetBasicBlockArchitecture(self.handle)
+ if arch is None:
+ return None
+ return Architecture(arch)
+ elif name == "start":
+ return core.BNGetBasicBlockStart(self.handle)
+ elif name == "end":
+ return core.BNGetBasicBlockEnd(self.handle)
+ elif name == "outgoing_edges":
+ count = ctypes.c_ulonglong(0)
+ 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(edges[i].arch)
+ else:
+ arch = None
+ result.append(BasicBlockEdge(branch_type, target, arch))
+ core.BNFreeBasicBlockOutgoingEdgeList(edges)
+ return result
+ elif name == "has_undetermined_outgoing_edges":
+ return core.BNBasicBlockHasUndeterminedOutgoingEdges(self.handle)
+ raise AttributeError, "no attribute '%s'" % name
+
+ def __setattr__(self, name, value):
+ if ((name == "function") or (name == "arch") or (name == "start") or (name == "end") or
+ (name == "outgoing_edges") or (name == "has_undetermined_outgoing_edges")):
+ raise AttributeError, "attribute '%s' is read only" % name
+ else:
+ self.__dict__[name] = value
+
+ def __dir__(self):
+ return dir(self.__class__) + ["function", "arch", "start", "end", "outgoing_edges", "has_undetermined_outgoing_edges"]
+
+ def __len__(self):
+ return int(core.BNGetBasicBlockLength(self.handle))
+
+ def __repr__(self):
+ arch = self.arch
+ if arch:
+ return "<block: %s@0x%x-0x%x>" % (arch.name, self.start, self.end)
+ else:
+ return "<block: 0x%x-0x%x>" % (self.start, self.end)
+
+ def mark_recent_use():
+ core.BNMarkBasicBlockAsRecentlyUsed(self.handle)
+
+class FunctionGraphTextLine:
+ def __init__(self, addr, tokens):
+ self.address = addr
+ self.tokens = tokens
+
+ def __str__(self):
+ result = ""
+ for token in self.tokens:
+ result += token.text
+ return result
+
+ def __repr__(self):
+ result = "<0x%x: %s>" % (self.address, str(self))
+
+class FunctionGraphEdge:
+ def __init__(self, branch_type, arch, target, points):
+ self.type = branch_type
+ self.arch = arch
+ self.target = target
+ self.points = points
+
+ def __repr__(self):
+ if self.arch:
+ return "<%s: %s@0x%x>" % (self.type, self.arch.name, self.target)
+ return "<%s: 0x%x>" % (self.type, self.target)
+
+class FunctionGraphBlock:
+ def __init__(self, handle):
+ self.handle = handle
+
+ def __del__(self):
+ core.BNFreeFunctionGraphBlock(self.handle)
+
+ def __getattr__(self, name):
+ if name == "arch":
+ arch = core.BNGetFunctionGraphBlockArchitecture(self.handle)
+ if arch is None:
+ return None
+ return Architecture(arch)
+ elif name == "start":
+ return core.BNGetFunctionGraphBlockStart(self.handle)
+ elif name == "end":
+ return core.BNGetFunctionGraphBlockEnd(self.handle)
+ elif name == "x":
+ return core.BNGetFunctionGraphBlockX(self.handle)
+ elif name == "y":
+ return core.BNGetFunctionGraphBlockY(self.handle)
+ elif name == "width":
+ return core.BNGetFunctionGraphBlockWidth(self.handle)
+ elif name == "height":
+ return core.BNGetFunctionGraphBlockHeight(self.handle)
+ elif name == "lines":
+ count = ctypes.c_ulonglong()
+ lines = core.BNGetFunctionGraphBlockLines(self.handle, count)
+ result = []
+ for i in xrange(0, count.value):
+ addr = lines[i].addr
+ tokens = []
+ for j in xrange(0, lines[i].count):
+ token_type = core.BNInstructionTextTokenType_names[lines[i].tokens[j].type]
+ text = lines[i].tokens[j].text
+ value = lines[i].tokens[j].value
+ tokens.append(InstructionTextToken(token_type, text, value))
+ result.append(FunctionGraphTextLine(addr, tokens))
+ core.BNFreeFunctionGraphBlockLines(lines, count.value)
+ return result
+ elif name == "outgoing_edges":
+ count = ctypes.c_ulonglong()
+ edges = core.BNGetFunctionGraphBlockOutgoingEdges(self.handle, count)
+ result = []
+ for i in xrange(0, count.value):
+ branch_type = core.BNBranchType_names[edges[i].type]
+ target = edges[i].target
+ arch = None
+ if edges[i].arch is not None:
+ arch = Architecture(edges[i].arch)
+ points = []
+ for j in xrange(0, edges[i].pointCount):
+ points.append((edges[i].points[j].x, edges[i].points[j].y))
+ result.append(FunctionGraphEdge(branch_type, arch, target, points))
+ core.BNFreeFunctionGraphBlockOutgoingEdgeList(edges, count.value)
+ return result
+ raise AttributeError, "no attribute '%s'" % name
+
+ def __setattr__(self, name, value):
+ if ((name == "arch") or (name == "start") or (name == "end") or (name == "x") or (name == "y") or
+ (name == "width") or (name == "height") or (name == "lines") or (name == "outgoing_edges")):
+ raise AttributeError, "attribute '%s' is read only" % name
+ else:
+ self.__dict__[name] = value
+
+ def __dir__(self):
+ return dir(self.__class__) + ["arch", "start", "end", "x", "y", "width", "height", "lines", "outgoing_edges"]
+
+ def __repr__(self):
+ arch = self.arch
+ if arch:
+ return "<graph block: %s@0x%x-0x%x>" % (arch.name, self.start, self.end)
+ else:
+ return "<graph block: 0x%x-0x%x>" % (self.start, self.end)
+
+class FunctionGraph:
+ def __init__(self, view, handle):
+ self.view = view
+ self.handle = handle
+ self._on_complete = None
+ self._cb = ctypes.CFUNCTYPE(None, ctypes.c_void_p)(self._complete)
+
+ def __del__(self):
+ self.abort()
+ core.BNFreeFunctionGraph(self.handle)
+
+ def __getattr__(self, name):
+ if name == "function":
+ func = core.BNGetFunctionForFunctionGraph(self.handle)
+ if func is None:
+ return None
+ return Function(self.view, func)
+ elif name == "horizontal_block_margin":
+ return core.BNGetHorizontalFunctionGraphBlockMargin(self.handle)
+ elif name == "vertical_block_margin":
+ return core.BNGetVerticalFunctionGraphBlockMargin(self.handle)
+ elif name == "max_symbol_width":
+ return core.BNGetFunctionGraphMaximumSymbolWidth(self.handle)
+ elif name == "complete":
+ return core.BNIsFunctionGraphLayoutComplete(self.handle)
+ elif name == "type":
+ return core.BNFunctionGraphType_names[core.BNGetFunctionGraphType(self.handle)]
+ elif name == "blocks":
+ count = ctypes.c_ulonglong()
+ blocks = core.BNGetFunctionGraphBlocks(self.handle, count)
+ result = []
+ for i in xrange(0, count.value):
+ result.append(FunctionGraphBlock(core.BNNewFunctionGraphBlockReference(blocks[i])))
+ core.BNFreeFunctionGraphBlockList(blocks, count.value)
+ return result
+ elif name == "width":
+ return core.BNGetFunctionGraphWidth(self.handle)
+ elif name == "height":
+ return core.BNGetFunctionGraphHeight(self.handle)
+ raise AttributeError, "no attribute '%s'" % name
+
+ def __setattr__(self, name, value):
+ if ((name == "function") or (name == "complete") or (name == "type") or (name == "blocks") or
+ (name == "width") or (name == "height")):
+ raise AttributeError, "attribute '%s' is read only" % name
+ elif name == "horizontal_block_margin":
+ core.BNSetFunctionGraphBlockMargins(self.handle, value, self.vertical_block_margin)
+ elif name == "vertical_block_margin":
+ core.BNSetFunctionGraphBlockMargins(self.handle, self.horizontal_block_margin, value)
+ elif name == "max_symbol_width":
+ core.BNSetFunctionGraphMaximumSymbolWidth(self.handle, value)
+ else:
+ self.__dict__[name] = value
+
+ def __dir__(self):
+ return dir(self.__class__) + ["function", "horizontal_block_margin", "vertical_block_margin", "max_symbol_width", "complete", "type", "blocks", "width", "height"]
+
+ def __repr__(self):
+ return "<graph of %s>" % repr(self.function)
+
+ def _complete(self, ctxt):
+ try:
+ if self._on_complete is not None:
+ self._on_complete()
+ except:
+ log_error(traceback.format_exc())
+
+ def layout(self, graph_type = core.NormalFunctionGraph):
+ if isinstance(graph_type, str):
+ graph_type = core.BNFunctionGraphType_by_name[graph_type]
+ core.BNStartFunctionGraphLayout(self.handle, graph_type)
+
+ def _wait_complete(self):
+ self._wait_cond.acquire()
+ self._wait_cond.notify()
+ self._wait_cond.release()
+
+ def layout_and_wait(self, graph_type = core.NormalFunctionGraph):
+ self._wait_cond = threading.Condition()
+ self.on_complete(self._wait_complete)
+ self.layout(graph_type)
+
+ self._wait_cond.acquire()
+ while not self.complete:
+ self._wait_cond.wait()
+ self._wait_cond.release()
+
+ def on_complete(self, callback):
+ self._on_complete = callback
+ core.BNSetFunctionGraphCompleteCallback(self.handle, None, self._cb)
+
+ def abort(self):
+ core.BNAbortFunctionGraph(self.handle)
+
+ def get_blocks_in_region(self, left, top, right, bottom):
+ count = ctypes.c_ulonglong()
+ blocks = core.BNGetFunctionGraphBlocksInRegion(self.handle, left, top, right, bottom, count)
+ result = []
+ for i in xrange(0, count.value):
+ result.append(FunctionGraphBlock(core.BNNewFunctionGraphBlockReference(blocks[i])))
+ core.BNFreeFunctionGraphBlockList(blocks, count.value)
+ return result
+
+ def is_option_set(self, option):
+ if isinstance(option, str):
+ option = core.BNFunctionGraphOption_by_name(option)
+ return core.BNIsFunctionGraphOptionSet(self.handle, option)
+
+ def set_option(self, option, state = True):
+ if isinstance(option, str):
+ option = core.BNFunctionGraphOption_by_name(option)
+ core.BNSetFunctionGraphOption(self.handle, option, state)
+
+class RegisterInfo:
+ def __init__(self, full_width_reg, size, offset = 0, extend = core.NoExtend, index = None):
+ self.full_width_reg = full_width_reg
+ self.offset = offset
+ self.size = size
+ self.extend = extend
+ self.index = index
+
+ def __repr__(self):
+ if (self.extend == core.ZeroExtendToFullWidth) or (self.extend == "ZeroExtendToFullWidth"):
+ extend = ", zero extend"
+ elif (self.extend == core.SignExtendToFullWidth) or (self.extend == "SignExtendToFullWidth"):
+ extend = ", sign extend"
+ else:
+ extend = ""
+ return "<reg: size %d, offset %d in %s%s>" % (self.size, self.offset, self.full_width_reg, extend)
+
+class InstructionBranch:
+ def __init__(self, branch_type, target = 0, arch = None):
+ self.type = branch_type
+ self.target = target
+ self.arch = arch
+
+ def __repr__(self):
+ branch_type = self.type
+ if not isinstance(branch_type, str):
+ branch_type = core.BNBranchType_names[branch_type]
+ if self.arch is not None:
+ return "<%s: %s@0x%x>" % (branch_type, self.arch.name, self.target)
+ return "<%s: 0x%x>" % (branch_type, self.target)
+
+class InstructionInfo:
+ def __init__(self):
+ self.length = 0
+ self.branch_delay = False
+ self.branches = []
+
+ def add_branch(self, branch_type, target = 0, arch = None):
+ self.branches.append(InstructionBranch(branch_type, target, arch))
+
+ def __repr__(self):
+ branch_delay = ""
+ if self.branch_delay:
+ branch_delay = ", delay slot"
+ return "<instr: %d bytes%s, %s>" % (self.length, branch_delay, repr(self.branches))
+
+class InstructionTextToken:
+ def __init__(self, token_type, text, value = 0):
+ self.type = token_type
+ self.text = text
+ self.value = value
+
+ def __str__(self):
+ return self.text
+
+ def __repr__(self):
+ return repr(self.text)
+
+class _ArchitectureMetaClass(type):
+ def __getattr__(cls, name):
+ if name == "list":
+ _init_plugins()
+ count = ctypes.c_ulonglong()
+ archs = core.BNGetArchitectureList(count)
+ result = []
+ for i in xrange(0, count.value):
+ result.append(Architecture(archs[i]))
+ core.BNFreeArchitectureList(archs)
+ return result
+ raise AttributeError, "no attribute '%s'" % name
+
+ def __setattr__(cls, name, value):
+ if (name == "list"):
+ raise AttributeError, "attribute '%s' is read only" % name
+ else:
+ type.__setattr__(cls, name, value)
+
+ def __dir__(self):
+ return dir(self.__class__) + ["list"]
+
+ def __getitem__(cls, name):
+ _init_plugins()
+ arch = core.BNGetArchitectureByName(name)
+ if arch is None:
+ raise KeyError, "'%s' is not a valid architecture" % str(name)
+ return Architecture(arch)
+
+ def register(cls):
+ _init_plugins()
+ if cls.name is None:
+ raise ValueError, "architecture 'name' is not defined"
+ arch = cls()
+ cls._registered_cb = arch._cb
+ arch.handle = core.BNRegisterArchitecture(cls.name, arch._cb)
+
+class Architecture:
+ name = None
+ endianness = core.LittleEndian
+ address_size = 8
+ default_int_size = 4
+ regs = {}
+ stack_pointer = None
+ link_reg = None
+ flags = []
+ flag_write_types = []
+ __metaclass__ = _ArchitectureMetaClass
+
+ def __init__(self, handle = None):
+ 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_names[core.BNGetArchitectureEndianness(self.handle)]
+ self.__dict__["address_size"] = core.BNGetArchitectureAddressSize(self.handle)
+ self.__dict__["default_int_size"] = core.BNGetArchitectureDefaultIntegerSize(self.handle)
+ self.__dict__["stack_pointer"] = core.BNGetArchitectureRegisterName(self.handle,
+ core.BNGetArchitectureStackPointerRegister(self.handle))
+ self.__dict__["link_reg"] = core.BNGetArchitectureRegisterName(self.handle,
+ core.BNGetArchitectureLinkRegister(self.handle))
+
+ count = ctypes.c_ulonglong()
+ regs = core.BNGetAllArchitectureRegisters(self.handle, count)
+ self.__dict__["regs"] = {}
+ for i in xrange(0, count.value):
+ name = core.BNGetArchitectureRegisterName(self.handle, regs[i])
+ info = core.BNGetArchitectureRegisterInfo(self.handle, regs[i])
+ full_width_reg = core.BNGetArchitectureRegisterName(self.handle, info.fullWidthRegister)
+ self.regs[name] = RegisterInfo(full_width_reg, info.size, info.offset,
+ core.BNImplicitRegisterExtend_names[info.extend], regs[i])
+ core.BNFreeRegisterList(regs)
+
+ count = ctypes.c_ulonglong()
+ flags = core.BNGetAllArchitectureFlags(self.handle, count)
+ self._flags = {}
+ self._flags_by_index = {}
+ self.__dict__["flags"] = []
+ for i in xrange(0, count.value):
+ name = core.BNGetArchitectureFlagName(self.handle, flags[i])
+ self._flags[name] = flags[i]
+ self._flags_by_index[flags[i]] = name
+ self.flags.append(name)
+ core.BNFreeRegisterList(flags)
+
+ count = ctypes.c_ulonglong()
+ types = core.BNGetAllArchitectureFlagWriteTypes(self.handle, count)
+ self._flag_write_types = {}
+ self._flag_write_types_by_index = {}
+ self.__dict__["flag_write_types"] = []
+ for i in xrange(0, count.value):
+ name = core.BNGetArchitectureFlagWriteTypeName(self.handle, types[i])
+ self._flag_write_types[name] = types[i]
+ self._flag_write_types_by_index[types[i]] = name
+ self.flag_write_types.append(name)
+ core.BNFreeRegisterList(types)
+ else:
+ _init_plugins()
+ self._cb = core.BNCustomArchitecture()
+ self._cb.context = 0
+ self._cb.init = self._cb.init.__class__(self._init)
+ self._cb.getEndianness = self._cb.getEndianness.__class__(self._get_endianness)
+ self._cb.getAddressSize = self._cb.getAddressSize.__class__(self._get_address_size)
+ self._cb.getDefaultIntegerSize = self._cb.getDefaultIntegerSize.__class__(self._get_default_integer_size)
+ self._cb.getInstructionInfo = self._cb.getInstructionInfo.__class__(self._get_instruction_info)
+ self._cb.getInstructionText = self._cb.getInstructionText.__class__(self._get_instruction_text)
+ self._cb.freeInstructionText = self._cb.freeInstructionText.__class__(self._free_instruction_text)
+ self._cb.getInstructionLowLevelIL = self._cb.getInstructionLowLevelIL.__class__(
+ self._get_instruction_low_level_il)
+ self._cb.getRegisterName = self._cb.getRegisterName.__class__(self._get_register_name)
+ self._cb.getFlagName = self._cb.getFlagName.__class__(self._get_flag_name)
+ self._cb.getFlagWriteTypeName = self._cb.getFlagWriteTypeName.__class__(self._get_flag_write_type_name)
+ self._cb.getFullWidthRegisters = self._cb.getFullWidthRegisters.__class__(self._get_full_width_registers)
+ self._cb.getAllRegisters = self._cb.getAllRegisters.__class__(self._get_all_registers)
+ self._cb.getAllFlags = self._cb.getAllRegisters.__class__(self._get_all_flags)
+ self._cb.getAllFlagWriteTypes = self._cb.getAllRegisters.__class__(self._get_all_flag_write_types)
+ self._cb.freeRegisterList = self._cb.freeRegisterList.__class__(self._free_register_list)
+ self._cb.getRegisterInfo = self._cb.getRegisterInfo.__class__(self._get_register_info)
+ self._cb.getStackPointerRegister = self._cb.getStackPointerRegister.__class__(
+ self._get_stack_pointer_register)
+ self._cb.getLinkRegister = self._cb.getLinkRegister.__class__(self._get_link_register)
+ self._cb.assemble = self._cb.assemble.__class__(self._assemble)
+ self._cb.isNeverBranchPatchAvailable = self._cb.isNeverBranchPatchAvailable.__class__(
+ self._is_never_branch_patch_available)
+ self._cb.isAlwaysBranchPatchAvailable = self._cb.isAlwaysBranchPatchAvailable.__class__(
+ self._is_always_branch_patch_available)
+ self._cb.isInvertBranchPatchAvailable = self._cb.isInvertBranchPatchAvailable.__class__(
+ self._is_invert_branch_patch_available)
+ self._cb.isSkipAndReturnZeroPatchAvailable = self._cb.isSkipAndReturnZeroPatchAvailable.__class__(
+ self._is_skip_and_return_zero_patch_available)
+ self._cb.isSkipAndReturnValuePatchAvailable = self._cb.isSkipAndReturnValuePatchAvailable.__class__(
+ self._is_skip_and_return_value_patch_available)
+ self._cb.convertToNop = self._cb.convertToNop.__class__(self._convert_to_nop)
+ self._cb.alwaysBranch = self._cb.alwaysBranch.__class__(self._always_branch)
+ self._cb.invertBranch = self._cb.invertBranch.__class__(self._invert_branch)
+ self._cb.skipAndReturnValue = self._cb.skipAndReturnValue.__class__(self._skip_and_return_value)
+
+ self._all_regs = {}
+ self._full_width_regs = {}
+ self._regs_by_index = {}
+ self.__dict__["regs"] = self.__class__.regs
+ reg_index = 0
+ for reg in self.regs.keys():
+ info = self.regs[reg]
+ if reg not in self._all_regs:
+ self._all_regs[reg] = reg_index
+ self._regs_by_index[reg_index] = reg
+ self.regs[reg].index = reg_index
+ reg_index += 1
+ if info.full_width_reg not in self._all_regs:
+ self._all_regs[info.full_width_reg] = reg_index
+ self._regs_by_index[reg_index] = info.full_width_reg
+ self.regs[info.full_width_reg].index = reg_index
+ reg_index += 1
+ if info.full_width_reg not in self._full_width_regs:
+ self._full_width_regs[info.full_width_reg] = self._all_regs[info.full_width_reg]
+
+ self._flags = {}
+ self._flags_by_index = {}
+ self.__dict__["flags"] = self.__class__.flags
+ flag_index = 0
+ for flag in self.__class__.flags:
+ if flag not in self._flags:
+ self._flags[flag] = flag_index
+ self._flags_by_index[flag_index] = flag
+ flag_index += 1
+
+ self._flag_write_types = {}
+ self._flag_write_types_by_index = {}
+ self.__dict__["flag_write_types"] = self.__class__.flag_write_types
+ write_type_index = 0
+ for write_type in self.__class__.flag_write_types:
+ if write_type not in self._flag_write_types:
+ self._flag_write_types[write_type] = write_type_index
+ self._flag_write_types_by_index[write_type_index] = write_type
+ write_type_index += 1
+
+ self._pending_reg_lists = {}
+ self._pending_token_lists = {}
+
+
+ def __getattr__(self, name):
+ if name == "full_width_regs":
+ count = ctypes.c_ulonglong()
+ regs = core.BNGetFullWidthArchitectureRegisters(self.handle, count)
+ result = []
+ for i in xrange(0, count.value):
+ result.append(core.BNGetArchitectureRegisterName(self.handle, regs[i]))
+ core.BNFreeRegisterList(regs)
+ return result
+ elif name == "calling_conventions":
+ count = ctypes.c_ulonglong()
+ cc = core.BNGetArchitectureCallingConventions(self.handle, count)
+ result = {}
+ for i in xrange(0, count.value):
+ obj = CallingConvention(None, core.BNNewCallingConventionReference(cc[i]))
+ result[obj.name] = obj
+ core.BNFreeCallingConventionList(cc, count)
+ return result
+ elif name == "standalone_platform":
+ pl = core.BNGetArchitectureStandalonePlatform(self.handle)
+ return Platform(self, pl)
+
+ raise AttributeError, "no attribute '%s'" % name
+
+ 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 == "full_width_regs") or (name == "calling_conventions")):
+ raise AttributeError, "attribute '%s' is read only" % name
+ else:
+ self.__dict__[name] = value
+
+ def __dir__(self):
+ return dir(self.__class__) + ["full_width_regs","calling_conventions"]
+
+ def __repr__(self):
+ return "<arch: %s>" % self.name
+
+ def _init(self, ctxt, handle):
+ self.handle = handle
+
+ def _get_endianness(self, ctxt):
+ try:
+ return self.__class__.endianness
+ except:
+ log_error(traceback.format_exc())
+ return core.LittleEndian
+
+ def _get_address_size(self, ctxt):
+ try:
+ return self.__class__.address_size
+ except:
+ log_error(traceback.format_exc())
+ return 8
+
+ def _get_default_integer_size(self, ctxt):
+ try:
+ return self.__class__.default_int_size
+ except:
+ log_error(traceback.format_exc())
+ return 4
+
+ def _get_instruction_info(self, ctxt, data, addr, max_len, result):
+ try:
+ buf = ctypes.create_string_buffer(max_len)
+ ctypes.memmove(buf, data, max_len)
+ info = self.perform_get_instruction_info(buf.raw, addr)
+ if info is None:
+ return False
+ result[0].length = info.length
+ result[0].branchDelay = info.branch_delay
+ 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_by_name[info.branches[i].type]
+ else:
+ result[0].branchType[i] = info.branches[i].type
+ result[0].branchTarget[i] = info.branches[i].target
+ if info.branches[i].arch is None:
+ result[0].branchArch[i] = None
+ else:
+ result[0].branchArch[i] = info.branches[i].arch.handle
+ return True
+ except:
+ log_error(traceback.format_exc())
+ return False
+
+ def _get_instruction_text(self, ctxt, data, addr, length, result, count):
+ try:
+ buf = ctypes.create_string_buffer(length[0])
+ ctypes.memmove(buf, data, length[0])
+ info = self.perform_get_instruction_text(buf.raw, addr)
+ if info is None:
+ return False
+ tokens = info[0]
+ length[0] = info[1]
+ count[0] = len(tokens)
+ 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]
+ else:
+ token_buf[i].type = tokens[i].type
+ token_buf[i].text = tokens[i].text
+ token_buf[i].value = tokens[i].value
+ result[0] = token_buf
+ ptr = ctypes.cast(token_buf, ctypes.c_void_p)
+ self._pending_token_lists[ptr.value] = (ptr.value, token_buf)
+ return True
+ except:
+ log_error(traceback.format_exc())
+ return False
+
+ def _free_instruction_text(self, tokens, count):
+ try:
+ buf = ctypes.cast(tokens, ctypes.c_void_p)
+ 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:
+ log_error(traceback.format_exc())
+
+ def _get_instruction_low_level_il(self, ctxt, data, addr, length, il):
+ try:
+ buf = ctypes.create_string_buffer(length[0])
+ ctypes.memmove(buf, data, length[0])
+ result = self.perform_get_instruction_low_level_il(buf.raw, addr,
+ LowLevelILFunction(self, core.BNNewLowLevelILFunctionReference(il)))
+ if result is None:
+ return False
+ length[0] = result
+ return True
+ except:
+ log_error(traceback.format_exc())
+ return False
+
+ def _get_register_name(self, ctxt, reg):
+ try:
+ if reg in self._regs_by_index:
+ return core.BNAllocString(self._regs_by_index[reg])
+ return core.BNAllocString("")
+ except:
+ log_error(traceback.format_exc())
+ return core.BNAllocString("")
+
+ def _get_flag_name(self, ctxt, flag):
+ try:
+ if flag in self._flags_by_index:
+ return core.BNAllocString(self._flags_by_index[flag])
+ return core.BNAllocString("")
+ except:
+ log_error(traceback.format_exc())
+ return core.BNAllocString("")
+
+ def _get_flag_write_type_name(self, ctxt, write_type):
+ try:
+ 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:
+ log_error(traceback.format_exc())
+ return core.BNAllocString("")
+
+ def _get_full_width_registers(self, ctxt, count):
+ try:
+ regs = self._full_width_regs.values()
+ count[0] = len(regs)
+ reg_buf = (ctypes.c_uint * len(regs))()
+ for i in xrange(0, len(regs)):
+ reg_buf[i] = regs[i]
+ result = ctypes.cast(reg_buf, ctypes.c_void_p)
+ self._pending_reg_lists[result.value] = (result, reg_buf)
+ return result.value
+ except:
+ log_error(traceback.format_exc())
+ count[0] = 0
+ return None
+
+ def _get_all_registers(self, ctxt, count):
+ try:
+ regs = self._regs_by_index.keys()
+ count[0] = len(regs)
+ reg_buf = (ctypes.c_uint * len(regs))()
+ for i in xrange(0, len(regs)):
+ reg_buf[i] = regs[i]
+ result = ctypes.cast(reg_buf, ctypes.c_void_p)
+ self._pending_reg_lists[result.value] = (result, reg_buf)
+ return result.value
+ except:
+ log_error(traceback.format_exc())
+ count[0] = 0
+ return None
+
+ def _get_all_flags(self, ctxt, count):
+ try:
+ flags = self._flags_by_index.keys()
+ count[0] = len(flags)
+ flag_buf = (ctypes.c_uint * len(flags))()
+ for i in xrange(0, len(flags)):
+ flag_buf[i] = flags[i]
+ result = ctypes.cast(flag_buf, ctypes.c_void_p)
+ self._pending_reg_lists[result.value] = (result, flag_buf)
+ return result.value
+ except:
+ log_error(traceback.format_exc())
+ count[0] = 0
+ return None
+
+ def _get_all_flag_write_types(self, ctxt, count):
+ try:
+ types = self._flag_write_types_by_index.keys()
+ count[0] = len(types)
+ type_buf = (ctypes.c_uint * len(types))()
+ for i in xrange(0, len(types)):
+ type_buf[i] = types[i]
+ result = ctypes.cast(type_buf, ctypes.c_void_p)
+ self._pending_reg_lists[result.value] = (result, type_buf)
+ return result.value
+ except:
+ log_error(traceback.format_exc())
+ count[0] = 0
+ return None
+
+ def _free_register_list(self, ctxt, regs):
+ try:
+ buf = ctypes.cast(regs, ctypes.c_void_p)
+ 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:
+ log_error(traceback.format_exc())
+
+ def _get_register_info(self, ctxt, reg, result):
+ try:
+ if reg not in self._regs_by_index:
+ result[0].fullWidthRegister = 0
+ result[0].offset = 0
+ result[0].size = 0
+ result[0].extend = core.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_by_name[info.extend]
+ else:
+ result[0].extend = info.extend
+ except:
+ log_error(traceback.format_exc())
+ result[0].fullWidthRegister = 0
+ result[0].offset = 0
+ result[0].size = 0
+ result[0].extend = core.NoExtend
+
+ def _get_stack_pointer_register(self, ctxt):
+ try:
+ return self._all_regs[self.__class__.stack_pointer]
+ except:
+ log_error(traceback.format_exc())
+ return 0
+
+ def _get_link_register(self, ctxt):
+ try:
+ if self.__class__.link_reg is None:
+ return 0xffffffff
+ return self._all_regs[self.__class__.link_reg]
+ except:
+ log_error(traceback.format_exc())
+ return 0
+
+ def _assemble(self, ctxt, code, addr, result, errors):
+ try:
+ data, error_str = self.perform_assemble(code, addr)
+ errors[0] = core.BNAllocString(str(error_str))
+ if data is None:
+ return False
+ data = str(data)
+ buf = ctypes.create_string_buffer(len(data))
+ ctypes.memmove(buf, data, len(data))
+ core.BNSetDataBufferContents(result, buf, len(data))
+ return True
+ except:
+ log_error(traceback.format_exc())
+ errors[0] = core.BNAllocString("Unhandled exception during assembly.\n")
+ return False
+
+ def _is_never_branch_patch_available(self, ctxt, data, addr, length):
+ try:
+ buf = ctypes.create_string_buffer(length)
+ ctypes.memmove(buf, data, length)
+ return self.perform_is_never_branch_patch_available(buf.raw, addr)
+ except:
+ log_error(traceback.format_exc())
+ return False
+
+ def _is_always_branch_patch_available(self, ctxt, data, addr, length):
+ try:
+ buf = ctypes.create_string_buffer(length)
+ ctypes.memmove(buf, data, length)
+ return self.perform_is_always_branch_patch_available(buf.raw, addr)
+ except:
+ log_error(traceback.format_exc())
+ return False
+
+ def _is_invert_branch_patch_available(self, ctxt, data, addr, length):
+ try:
+ buf = ctypes.create_string_buffer(length)
+ ctypes.memmove(buf, data, length)
+ return self.perform_is_invert_branch_patch_available(buf.raw, addr)
+ except:
+ log_error(traceback.format_exc())
+ return False
+
+ def _is_skip_and_return_zero_patch_available(self, ctxt, data, addr, length):
+ try:
+ buf = ctypes.create_string_buffer(length)
+ ctypes.memmove(buf, data, length)
+ return self.perform_is_skip_and_return_zero_patch_available(buf.raw, addr)
+ except:
+ log_error(traceback.format_exc())
+ return False
+
+ def _is_skip_and_return_value_patch_available(self, ctxt, data, addr, length):
+ try:
+ buf = ctypes.create_string_buffer(length)
+ ctypes.memmove(buf, data, length)
+ return self.perform_is_skip_and_return_value_patch_available(buf.raw, addr)
+ except:
+ log_error(traceback.format_exc())
+ return False
+
+ def _convert_to_nop(self, ctxt, data, addr, length):
+ try:
+ buf = ctypes.create_string_buffer(length)
+ ctypes.memmove(buf, data, length)
+ result = self.perform_convert_to_nop(buf.raw, addr)
+ if result is None:
+ return False
+ result = str(result)
+ if len(result) > length:
+ result = result[0:length]
+ ctypes.memmove(data, result, len(result))
+ return True
+ except:
+ log_error(traceback.format_exc())
+ return False
+
+ def _always_branch(self, ctxt, data, addr, length):
+ try:
+ buf = ctypes.create_string_buffer(length)
+ ctypes.memmove(buf, data, length)
+ result = self.perform_always_branch(buf.raw, addr)
+ if result is None:
+ return False
+ result = str(result)
+ if len(result) > length:
+ result = result[0:length]
+ ctypes.memmove(data, result, len(result))
+ return True
+ except:
+ log_error(traceback.format_exc())
+ return False
+
+ def _invert_branch(self, ctxt, data, addr, length):
+ try:
+ buf = ctypes.create_string_buffer(length)
+ ctypes.memmove(buf, data, length)
+ result = self.perform_invert_branch(buf.raw, addr)
+ if result is None:
+ return False
+ result = str(result)
+ if len(result) > length:
+ result = result[0:length]
+ ctypes.memmove(data, result, len(result))
+ return True
+ except:
+ log_error(traceback.format_exc())
+ return False
+
+ def _skip_and_return_value(self, ctxt, data, addr, length, value):
+ try:
+ buf = ctypes.create_string_buffer(length)
+ ctypes.memmove(buf, data, length)
+ result = self.perform_skip_and_return_value(buf.raw, addr, value)
+ if result is None:
+ return False
+ result = str(result)
+ if len(result) > length:
+ result = result[0:length]
+ ctypes.memmove(data, result, len(result))
+ return True
+ except:
+ log_error(traceback.format_exc())
+ return False
+
+ def perform_get_instruction_low_level_il(self, data, addr, il):
+ return None
+
+ def perform_assemble(self, code, addr):
+ return None, "Architecture does not implement an assembler.\n"
+
+ def perform_is_never_branch_patch_available(self, data, addr):
+ return False
+
+ def perform_is_always_branch_patch_available(self, data, addr):
+ return False
+
+ def perform_is_invert_branch_patch_available(self, data, addr):
+ return False
+
+ def perform_is_skip_and_return_zero_patch_available(self, data, addr):
+ return False
+
+ def perform_is_skip_and_return_value_patch_available(self, data, addr):
+ return False
+
+ def perform_convert_to_nop(self, data, addr):
+ return None
+
+ def perform_always_branch(self, data, addr):
+ return None
+
+ def perform_invert_branch(self, data, addr):
+ return None
+
+ def perform_skip_and_return_value(self, data, addr, value):
+ return None
+
+ def get_instruction_info(self, data, addr):
+ info = core.BNInstructionInfo()
+ data = str(data)
+ buf = (ctypes.c_ubyte * len(data))()
+ ctypes.memmove(buf, data, len(data))
+ if not core.BNGetInstructionInfo(self.handle, buf, addr, len(data), info):
+ return None
+ result = InstructionInfo()
+ result.length = info.length
+ result.branch_delay = info.branchDelay
+ for i in xrange(0, info.branchCount):
+ branch_type = core.BNBranchType_names[info.branchType[i]]
+ target = info.branchTarget[i]
+ if info.branchArch[i]:
+ arch = Architecture(info.branchArch[i])
+ else:
+ arch = None
+ result.add_branch(branch_type, target, arch)
+ return result
+
+ def get_instruction_text(self, data, addr):
+ data = str(data)
+ count = ctypes.c_ulonglong()
+ length = ctypes.c_ulonglong()
+ length.value = len(data)
+ buf = (ctypes.c_ubyte * len(data))()
+ ctypes.memmove(buf, data, len(data))
+ tokens = ctypes.POINTER(core.BNInstructionTextToken)()
+ if not core.BNGetInstructionText(self.handle, buf, addr, length, tokens, count):
+ return None, 0
+ result = []
+ for i in xrange(0, count.value):
+ token_type = core.BNInstructionTextTokenType_names[tokens[i].type]
+ text = tokens[i].text
+ value = tokens[i].value
+ result.append(InstructionTextToken(token_type, text, value))
+ core.BNFreeInstructionText(tokens, count.value)
+ return result, length.value
+
+ def get_instruction_low_level_il(self, data, addr, il):
+ info = core.BNInstructionInfo()
+ data = str(data)
+ length = ctypes.c_ulonglong()
+ length.value = len(data)
+ buf = (ctypes.c_ubyte * len(data))()
+ ctypes.memmove(buf, data, len(data))
+ core.BNGetInstructionLowLevelIL(self.handle, buf, addr, length, il.handle)
+ return length.value
+
+ def get_reg_name(self, reg):
+ return core.BNGetArchitectureRegisterName(self.handle, reg)
+
+ def get_flag_name(self, flag):
+ return core.BNGetArchitectureFlagName(self.handle, flag)
+
+ def get_flag_write_type_name(self, write_type):
+ return core.BNGetArchitectureFlagWriteTypeName(self.handle, write_type)
+
+ def get_flag_by_name(self, flag):
+ return self._flags[flag]
+
+ def get_flag_write_type_by_name(self, write_type):
+ return self._flag_write_types[write_type]
+
+ def get_modified_regs_on_write(self, reg):
+ reg = core.BNGetArchitectureRegisterByName(self.handle, str(reg))
+ count = ctypes.c_ulonglong()
+ regs = core.BNGetModifiedArchitectureRegistersOnWrite(self.handle, reg, count)
+ result = []
+ for i in xrange(0, count.value):
+ result.append(core.BNGetArchitectureRegisterName(self.handle, regs[i]))
+ core.BNFreeRegisterList(regs)
+ return result
+
+ def assemble(self, code, addr = 0):
+ result = DataBuffer()
+ errors = ctypes.c_char_p()
+ if not core.BNAssemble(self.handle, code, addr, result.handle, errors):
+ return None, errors.value
+ return str(result), errors.value
+
+ def is_never_branch_patch_available(self, data, addr):
+ data = str(data)
+ buf = (ctypes.c_ubyte * len(data))()
+ ctypes.memmove(buf, data, len(data))
+ return core.BNIsArchitectureNeverBranchPatchAvailable(self.handle, buf, addr, len(data))
+
+ def is_always_branch_patch_available(self, data, addr):
+ data = str(data)
+ buf = (ctypes.c_ubyte * len(data))()
+ ctypes.memmove(buf, data, len(data))
+ return core.BNIsArchitectureAlwaysBranchPatchAvailable(self.handle, buf, addr, len(data))
+
+ def is_invert_branch_patch_available(self, data, addr):
+ data = str(data)
+ buf = (ctypes.c_ubyte * len(data))()
+ ctypes.memmove(buf, data, len(data))
+ return core.BNIsArchitectureInvertBranchPatchAvailable(self.handle, buf, addr, len(data))
+
+ def is_skip_and_return_zero_patch_available(self, data, addr):
+ data = str(data)
+ buf = (ctypes.c_ubyte * len(data))()
+ ctypes.memmove(buf, data, len(data))
+ return core.BNIsArchitectureSkipAndReturnZeroPatchAvailable(self.handle, buf, addr, len(data))
+
+ def is_skip_and_return_value_patch_available(self, data, addr):
+ data = str(data)
+ buf = (ctypes.c_ubyte * len(data))()
+ ctypes.memmove(buf, data, len(data))
+ return core.BNIsArchitectureSkipAndReturnValuePatchAvailable(self.handle, buf, addr, len(data))
+
+ def convert_to_nop(self, data, addr):
+ data = str(data)
+ buf = (ctypes.c_ubyte * len(data))()
+ ctypes.memmove(buf, data, len(data))
+ if not core.BNArchitectureConvertToNop(self.handle, buf, addr, len(data)):
+ return None
+ result = ctypes.create_string_buffer(len(data))
+ ctypes.memmove(result, buf, len(data))
+ return result.raw
+
+ def always_branch(self, data, addr):
+ data = str(data)
+ buf = (ctypes.c_ubyte * len(data))()
+ ctypes.memmove(buf, data, len(data))
+ if not core.BNArchitectureAlwaysBranch(self.handle, buf, addr, len(data)):
+ return None
+ result = ctypes.create_string_buffer(len(data))
+ ctypes.memmove(result, buf, len(data))
+ return result.raw
+
+ def invert_branch(self, data, addr):
+ data = str(data)
+ buf = (ctypes.c_ubyte * len(data))()
+ ctypes.memmove(buf, data, len(data))
+ if not core.BNArchitectureInvertBranch(self.handle, buf, addr, len(data)):
+ return None
+ result = ctypes.create_string_buffer(len(data))
+ ctypes.memmove(result, buf, len(data))
+ return result.raw
+
+ def skip_and_return_value(self, data, addr, value):
+ data = str(data)
+ buf = (ctypes.c_ubyte * len(data))()
+ ctypes.memmove(buf, data, len(data))
+ if not core.BNArchitectureSkipAndReturnValue(self.handle, buf, addr, len(data), value):
+ return None
+ result = ctypes.create_string_buffer(len(data))
+ ctypes.memmove(result, buf, len(data))
+ return result.raw
+
+ def is_view_type_constant_defined(self, type_name, const_name):
+ return core.BNIsBinaryViewTypeArchitectureConstantDefined(self.handle, type_name, const_name)
+
+ def get_view_type_constant(self, type_name, const_name, default_value = 0):
+ return core.BNGetBinaryViewTypeArchitectureConstant(self.handle, type_name, const_name, default_value)
+
+ def set_view_type_constant(self, type_name, const_name, value):
+ core.BNSetBinaryViewTypeArchitectureConstant(self.handle, type_name, const_name, value)
+
+ def parse_types_from_source(self, source, filename = None, include_dirs = []):
+ 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])
+ parse = core.BNTypeParserResult()
+ errors = ctypes.c_char_p()
+ result = core.BNParseTypesFromSource(self.handle, source, filename, parse, errors, dir_buf, len(include_dirs))
+ error_str = errors.value
+ core.BNFreeString(ctypes.cast(errors, ctypes.POINTER(ctypes.c_byte)))
+ if not result:
+ return (None, error_str)
+ types = {}
+ variables = {}
+ functions = {}
+ for i in xrange(0, parse.typeCount):
+ types[parse.types[i].name] = Type(core.BNNewTypeReference(parse.types[i].type))
+ for i in xrange(0, parse.variableCount):
+ 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))
+ return (TypeParserResult(types, variables, functions), error_str)
+
+ def parse_types_from_source_file(self, filename, include_dirs = []):
+ dir_buf = (ctypes.c_char_p * len(include_dirs))()
+ for i in xrange(0, len(include_dirs)):
+ 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))
+ error_str = errors.value
+ core.BNFreeString(ctypes.cast(errors, ctypes.POINTER(ctypes.c_byte)))
+ if not result:
+ return (None, error_str)
+ types = {}
+ variables = {}
+ functions = {}
+ for i in xrange(0, parse.typeCount):
+ types[parse.types[i].name] = Type(core.BNNewTypeReference(parse.types[i].type))
+ for i in xrange(0, parse.variableCount):
+ 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))
+ return (TypeParserResult(types, variables, functions), error_str)
+
+ def register_calling_convention(self, cc):
+ core.BNRegisterCallingConvention(self.handle, cc.handle)
+
+class ReferenceSource:
+ def __init__(self, func, arch, addr):
+ self.function = func
+ self.arch = arch
+ self.address = addr
+
+ def __repr__(self):
+ if self.arch:
+ return "<ref: %s@0x%x>" % (self.arch.name, self.address)
+ else:
+ return "<ref: 0x%x>" % self.address
+
+class LowLevelILLabel:
+ def __init__(self, handle = None):
+ if handle is None:
+ self.handle = (core.BNLowLevelILLabel * 1)()
+ core.BNLowLevelILInitLabel(self.handle)
+ else:
+ self.handle = handle
+
+class LowLevelILInstruction:
+ ILOperations = {
+ 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_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_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, i):
+ instr = core.BNGetLowLevelILByIndex(func.handle, i)
+ self.function = func
+ self.index = i
+ self.operation = instr.operation
+ self.operation_name = core.BNLowLevelILOperation_names[instr.operation]
+ self.size = instr.size
+ self.address = instr.address
+ self.source_operand = instr.sourceOperand
+ if instr.flags == 0:
+ self.flags = None
+ else:
+ self.flags = func.arch.get_flag_write_type_name(instr.flags)
+ if self.source_operand == 0xffffffff:
+ self.source_operand = None
+ operands = LowLevelILInstruction.ILOperations[instr.operation]
+ self.operands = []
+ for i in xrange(0, len(operands)):
+ name, operand_type = operands[i]
+ if operand_type == "int":
+ value = instr.operands[i]
+ elif operand_type == "expr":
+ value = LowLevelILInstruction(func, instr.operands[i])
+ elif operand_type == "reg":
+ if (instr.operands[i] & 0x80000000) != 0:
+ value = instr.operands[i]
+ else:
+ value = func.arch.get_reg_name(instr.operands[i])
+ elif operand_type == "flag":
+ value = func.arch.get_flag_name(instr.operands[i])
+ elif operand_type == "cond":
+ value = core.BNLowLevelILFlagCondition_names[instr.operands[i]]
+ self.operands.append(value)
+ self.__dict__[name] = value
+
+ def __str__(self):
+ tokens = self.tokens
+ if tokens is None:
+ return "invalid"
+ result = ""
+ for token in tokens:
+ result += token.text
+ return result
+
+ def __repr__(self):
+ return "<il: %s>" % str(self)
+
+ def __getattr__(self, name):
+ if name == "tokens":
+ count = ctypes.c_ulonglong()
+ tokens = ctypes.POINTER(core.BNInstructionTextToken)()
+ if not core.BNGetLowLevelILExprText(self.function.handle, self.function.arch.handle,
+ self.index, tokens, count):
+ return None
+ result = []
+ for i in xrange(0, count.value):
+ token_type = core.BNInstructionTextTokenType_names[tokens[i].type]
+ text = tokens[i].text
+ value = tokens[i].value
+ result.append(InstructionTextToken(token_type, text, value))
+ core.BNFreeInstructionText(tokens, count.value)
+ return result
+ raise AttributeError, "no attribute '%s'" % name
+
+ def __setattr__(self, name, value):
+ if name == "tokens":
+ raise AttributeError, "attribute '%s' is read only" % name
+ else:
+ self.__dict__[name] = value
+
+ def __dir__(self):
+ return dir(self.__class__) + ["tokens"]
+
+class LowLevelILExpr:
+ def __init__(self, index):
+ self.index = index
+
+class LowLevelILFunction:
+ def __init__(self, arch, handle = None):
+ self.arch = arch
+ if handle is not None:
+ self.handle = core.handle_of_type(handle, core.BNLowLevelILFunction)
+ else:
+ self.handle = core.BNCreateLowLevelILFunction()
+
+ def __del__(self):
+ core.BNFreeLowLevelILFunction(self.handle)
+
+ def __getattr__(self, name):
+ if name == "current_address":
+ return core.BNLowLevelILGetCurrentAddress(self.handle)
+ raise AttributeError, "no attribute '%s'" % name
+
+ def __setattr__(self, name, value):
+ if name == "current_address":
+ core.BNLowLevelILSetCurrentAddress(self.handle, value)
+ else:
+ self.__dict__[name] = value
+
+ def __dir__(self):
+ return dir(self.__class__) + ["current_address"]
+
+ def __len__(self):
+ return int(core.BNGetLowLevelILInstructionCount(self.handle))
+
+ def __getitem__(self, i):
+ if isinstance(i, slice) or isinstance(i, tuple):
+ raise IndexError, "expected integer instruction index"
+ if isinstance(i, LowLevelILExpr):
+ return LowLevelILInstruction(self, i.index)
+ if (i < 0) or (i >= len(self)):
+ raise IndexError, "index out of range"
+ return LowLevelILInstruction(self, core.BNGetLowLevelILIndexForInstruction(self.handle, i))
+
+ def __setitem__(self, i):
+ raise IndexError, "instruction modification not implemented"
+
+ 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]
+ if isinstance(flags, str):
+ flags = self.arch.get_flag_write_type_by_name(flags)
+ elif flags is None:
+ flags = 0
+ return LowLevelILExpr(core.BNLowLevelILAddExpr(self.handle, operation, size, flags, a, b, c, d))
+
+ def append(self, expr):
+ return core.BNLowLevelILAddInstruction(self.handle, expr.index)
+
+ def nop(self):
+ return self.expr(core.LLIL_NOP)
+
+ def set_reg(self, size, reg, value, flags = 0):
+ if isinstance(reg, str):
+ reg = self.arch.regs[reg].index
+ return self.expr(core.LLIL_SET_REG, reg, value.index, size = size, flags = flags)
+
+ def set_reg_split(self, size, hi, lo, value, flags = 0):
+ if isinstance(hi, str):
+ hi = self.arch.regs[hi].index
+ if isinstance(lo, str):
+ lo = self.arch.regs[lo].index
+ return self.expr(core.LLIL_SET_REG_SPLIT, hi, lo, value.index, size = size, flags = flags)
+
+ def set_flag(self, flag, value):
+ return self.expr(core.LLIL_SET_FLAG, self.arch.get_flag_by_name(flag), value.index)
+
+ def load(self, size, addr):
+ return self.expr(core.LLIL_LOAD, addr.index, size = size)
+
+ def store(self, size, addr, value):
+ return self.expr(core.LLIL_STORE, addr.index, value.index, size = size)
+
+ def push(self, size, value):
+ return self.expr(core.LLIL_PUSH, value.index, size = size)
+
+ def pop(self, size):
+ return self.expr(core.LLIL_POP, size = size)
+
+ def reg(self, size, reg):
+ if isinstance(reg, str):
+ reg = self.arch.regs[reg].index
+ return self.expr(core.LLIL_REG, reg, size = size)
+
+ def const(self, size, value):
+ return self.expr(core.LLIL_CONST, value, size = size)
+
+ def flag(self, reg):
+ return self.expr(core.LLIL_FLAG, self.arch.get_flag_by_name(reg))
+
+ def flag_bit(self, size, reg, bit):
+ return self.expr(core.LLIL_FLAG_BIT, self.arch.get_flag_by_name(reg), bit, size = size)
+
+ def add(self, size, a, b, flags = None):
+ return self.expr(core.LLIL_ADD, a.index, b.index, size = size, flags = flags)
+
+ def add_carry(self, size, a, b, flags = None):
+ return self.expr(core.LLIL_ADC, a.index, b.index, size = size, flags = flags)
+
+ def sub(self, size, a, b, flags = None):
+ return self.expr(core.LLIL_SUB, a.index, b.index, size = size, flags = flags)
+
+ def sub_borrow(self, size, a, b, flags = None):
+ return self.expr(core.LLIL_SBB, a.index, b.index, size = size, flags = flags)
+
+ def and_expr(self, size, a, b, flags = None):
+ return self.expr(core.LLIL_AND, a.index, b.index, size = size, flags = flags)
+
+ def or_expr(self, size, a, b, flags = None):
+ return self.expr(core.LLIL_OR, a.index, b.index, size = size, flags = flags)
+
+ def xor_expr(self, size, a, b, flags = None):
+ return self.expr(core.LLIL_XOR, a.index, b.index, size = size, flags = flags)
+
+ def shift_left(self, size, a, b, flags = None):
+ return self.expr(core.LLIL_LSL, a.index, b.index, size = size, flags = flags)
+
+ def logical_shift_right(self, size, a, b, flags = None):
+ return self.expr(core.LLIL_LSR, a.index, b.index, size = size, flags = flags)
+
+ def arith_shift_right(self, size, a, b, flags = None):
+ return self.expr(core.LLIL_ASR, a.index, b.index, size = size, flags = flags)
+
+ def rotate_left(self, size, a, b, flags = None):
+ return self.expr(core.LLIL_ROL, a.index, b.index, size = size, flags = flags)
+
+ def rotate_left_carry(self, size, a, b, flags = None):
+ return self.expr(core.LLIL_RLC, a.index, b.index, size = size, flags = flags)
+
+ def rotate_right(self, size, a, b, flags = None):
+ return self.expr(core.LLIL_ROR, a.index, b.index, size = size, flags = flags)
+
+ def rotate_right_carry(self, size, a, b, flags = None):
+ return self.expr(core.LLIL_RRC, a.index, b.index, size = size, flags = flags)
+
+ def mult(self, size, a, b, flags = None):
+ return self.expr(core.LLIL_MUL, a.index, b.index, size = size, flags = flags)
+
+ def mult_double_prec_signed(self, size, a, b, flags = None):
+ return self.expr(core.LLIL_MULS_DP, a.index, b.index, size = size, flags = flags)
+
+ def mult_double_prec_unsigned(self, size, a, b, flags = None):
+ return self.expr(core.LLIL_MULU_DP, a.index, b.index, size = size, flags = flags)
+
+ def div_signed(self, size, a, b, flags = None):
+ return self.expr(core.LLIL_DIVS, a.index, b.index, size = size, flags = flags)
+
+ def div_double_prec_signed(self, size, hi, lo, b, flags = None):
+ return self.expr(core.LLIL_DIVS_DP, hi.index, lo.index, b.index, size = size, flags = flags)
+
+ def div_unsigned(self, size, a, b, flags = None):
+ return self.expr(core.LLIL_DIVS, a.index, b.index, size = size, flags = flags)
+
+ def div_double_prec_unsigned(self, size, hi, lo, b, flags = None):
+ return self.expr(core.LLIL_DIVS_DP, hi.index, lo.index, b.index, size = size, flags = flags)
+
+ def mod_signed(self, size, a, b, flags = None):
+ return self.expr(core.LLIL_MODS, a.index, b.index, size = size, flags = flags)
+
+ def mod_double_prec_signed(self, size, hi, lo, b, flags = None):
+ return self.expr(core.LLIL_MODS_DP, hi.index, lo.index, b.index, size = size, flags = flags)
+
+ def mod_unsigned(self, size, a, b, flags = None):
+ return self.expr(core.LLIL_MODS, a.index, b.index, size = size, flags = flags)
+
+ def mod_double_prec_unsigned(self, size, hi, lo, b, flags = None):
+ return self.expr(core.LLIL_MODS_DP, hi.index, lo.index, b.index, size = size, flags = flags)
+
+ def neg_expr(self, size, value, flags = None):
+ return self.expr(core.LLIL_NEG, value.index, size = size, flags = flags)
+
+ def not_expr(self, size, value, flags = None):
+ return self.expr(core.LLIL_NOT, value.index, size = size, flags = flags)
+
+ def sign_extend(self, size, value):
+ return self.expr(core.LLIL_SX, value.index, size = size)
+
+ def zero_extend(self, size, value):
+ return self.expr(core.LLIL_ZX, value.index, size = size)
+
+ def jump(self, dest):
+ return self.expr(core.LLIL_JUMP, dest.index)
+
+ def call(self, dest):
+ return self.expr(core.LLIL_CALL, dest.index)
+
+ def ret(self, dest):
+ return self.expr(core.LLIL_RET, dest.index)
+
+ def no_ret(self, dest):
+ return self.expr(core.LLIL_NORET, dest.index)
+
+ def flag_condition(self, cond):
+ if isinstance(cond, str):
+ cond = BNLowLevelILFlagCondition_by_name[cond]
+ return self.expr(core.LLIL_FLAG_COND, cond)
+
+ def compare_equal(self, size, a, b):
+ return self.expr(core.LLIL_CMP_E, a.index, b.index, size = size)
+
+ def compare_not_equal(self, size, a, b):
+ return self.expr(core.LLIL_CMP_NE, a.index, b.index, size = size)
+
+ def compare_signed_less_than(self, size, a, b):
+ return self.expr(core.LLIL_CMP_SLT, a.index, b.index, size = size)
+
+ def compare_unsigned_less_than(self, size, a, b):
+ return self.expr(core.LLIL_CMP_ULT, a.index, b.index, size = size)
+
+ def compare_signed_less_equal(self, size, a, b):
+ return self.expr(core.LLIL_CMP_SLE, a.index, b.index, size = size)
+
+ def compare_unsigned_less_equal(self, size, a, b):
+ return self.expr(core.LLIL_CMP_ULE, a.index, b.index, size = size)
+
+ def compare_signed_greater_equal(self, size, a, b):
+ return self.expr(core.LLIL_CMP_SGE, a.index, b.index, size = size)
+
+ def compare_unsigned_greater_equal(self, size, a, b):
+ return self.expr(core.LLIL_CMP_UGE, a.index, b.index, size = size)
+
+ def compare_signed_greater_than(self, size, a, b):
+ return self.expr(core.LLIL_CMP_SGT, a.index, b.index, size = size)
+
+ def compare_unsigned_greater_than(self, size, a, b):
+ return self.expr(core.LLIL_CMP_UGT, a.index, b.index, size = size)
+
+ def test_bit(self, size, a, b):
+ return self.expr(core.LLIL_TEST_BIT, a.index, b.index, size = size)
+
+ def system_call(self):
+ return self.expr(core.LLIL_SYSCALL)
+
+ def breakpoint(self):
+ return self.expr(core.LLIL_BP)
+
+ def trap(self, value):
+ return self.expr(core.LLIL_TRAP, value)
+
+ def undefined(self):
+ return self.expr(core.LLIL_UNDEF)
+
+ def unimplemented(self):
+ return self.expr(core.LLIL_UNIMPL)
+
+ def unimplemented_memory_ref(self, size, addr):
+ return self.expr(core.LLIL_UNIMPL_MEM, addr.index, size = size)
+
+ def goto(self, label):
+ return LowLevelILExpr(core.BNLowLevelILGoto(self.handle, label.handle))
+
+ def if_expr(self, operand, t, f):
+ return LowLevelILExpr(core.BNLowLevelILIf(self.handle, operand.index, t.handle, f.handle))
+
+ def mark_label(self, label):
+ core.BNLowLevelILMarkLabel(self.handle, label.handle)
+
+ def operand(self, n, expr):
+ core.BNLowLevelILSetExprSourceOperand(self.handle, expr.index, n)
+ return expr
+
+ def finalize(self):
+ core.BNFinalizeLowLevelILFunction(self.handle)
+
+ def add_label_for_address(self, arch, addr):
+ if arch is not None:
+ arch = arch.handle
+ core.BNAddLowLevelILLabelForAddress(self.handle, arch, addr)
+
+ def get_label_for_address(self, arch, addr):
+ if arch is not None:
+ arch = arch.handle
+ label = core.BNGetLowLevelILLabelForAddress(self.handle, arch, addr)
+ if label is None:
+ return None
+ return LowLevelILLabel(label)
+
+class TypeParserResult:
+ 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)
+
+class _TransformMetaClass(type):
+ def __getattr__(cls, name):
+ if name == "list":
+ _init_plugins()
+ count = ctypes.c_ulonglong()
+ xforms = core.BNGetTransformTypeList(count)
+ result = []
+ for i in xrange(0, count.value):
+ result.append(Transform(xforms[i]))
+ core.BNFreeTransformTypeList(xforms)
+ return result
+ raise AttributeError, "no attribute '%s'" % name
+
+ def __setattr__(cls, name, value):
+ if (name == "list"):
+ raise AttributeError, "attribute '%s' is read only" % name
+ else:
+ type.__setattr__(cls, name, value)
+
+ def __dir__(self):
+ return dir(self.__class__) + ["list"]
+
+ def __getitem__(cls, name):
+ _init_plugins()
+ xform = core.BNGetTransformByName(name)
+ if xform is None:
+ raise KeyError, "'%s' is not a valid transform" % str(name)
+ return Transform(xform)
+
+ def register(cls):
+ _init_plugins()
+ if cls.name is None:
+ raise ValueError, "transform 'name' is not defined"
+ if cls.long_name is None:
+ cls.long_name = cls.name
+ if cls.transform_type is None:
+ raise ValueError, "transform 'transform_type' is not defined"
+ if cls.group is None:
+ cls.group = ""
+ xform = cls(None)
+ cls._registered_cb = xform._cb
+ xform.handle = core.BNRegisterTransformType(cls.transform_type, cls.name, cls.long_name, cls.group, xform._cb)
+
+class TransformParameter:
+ def __init__(self, name, long_name = None, fixed_length = 0):
+ self.name = name
+ if long_name is None:
+ self.long_name = name
+ else:
+ self.long_name = long_name
+ self.fixed_length = fixed_length
+
+class Transform:
+ transform_type = None
+ name = None
+ long_name = None
+ group = None
+ parameters = []
+ _registered_cb = None
+ __metaclass__ = _TransformMetaClass
+
+ def __init__(self, handle):
+ if handle is None:
+ self._cb = core.BNCustomTransform()
+ self._cb.context = 0
+ self._cb.getParameters = self._cb.getParameters.__class__(self._get_parameters)
+ self._cb.freeParameters = self._cb.freeParameters.__class__(self._free_parameters)
+ self._cb.decode = self._cb.decode.__class__(self._decode)
+ self._cb.encode = self._cb.encode.__class__(self._encode)
+ self._pending_param_lists = {}
+ self.type = self.__class__.transform_type
+ if not isinstance(self.type, str):
+ self.type = core.BNTransformType_names[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_names[core.BNGetTransformType(self.handle)]
+ self.name = core.BNGetTransformName(self.handle)
+ self.long_name = core.BNGetTransformLongName(self.handle)
+ self.group = core.BNGetTransformGroup(self.handle)
+ count = ctypes.c_ulonglong()
+ params = core.BNGetTransformParameterList(self.handle, count)
+ self.parameters = []
+ for i in xrange(0, count.value):
+ self.parameters.append(TransformParameter(params[i].name, params[i].longName, params[i].fixedLength))
+ core.BNFreeTransformParameterList(params, count.value)
+
+ def __repr__(self):
+ return "<transform: %s>" % self.name
+
+ def _get_parameters(self, ctxt, count):
+ try:
+ count[0] = len(self.parameters)
+ param_buf = (core.BNTransformParameterInfo * len(self.parameters))()
+ for i in xrange(0, len(self.parameters)):
+ param_buf[i].name = self.parameters[i].name
+ param_buf[i].longName = self.parameters[i].long_name
+ param_buf[i].fixedLength = self.parameters[i].fixed_length
+ result = ctypes.cast(param_buf, ctypes.c_void_p)
+ self._pending_param_lists[result.value] = (result, param_buf)
+ return result.value
+ except:
+ log_error(traceback.format_exc())
+ count[0] = 0
+ return None
+
+ def _free_parameters(self, params, count):
+ try:
+ buf = ctypes.cast(params, ctypes.c_void_p)
+ if buf.value not in self._pending_param_lists:
+ raise ValueError, "freeing parameter list that wasn't allocated"
+ del self._pending_param_lists[buf.value]
+ except:
+ log_error(traceback.format_exc())
+
+ def _decode(self, ctxt, input_buf, output_buf, params, count):
+ try:
+ input_obj = DataBuffer(handle = core.BNDuplicateDataBuffer(input_buf))
+ param_map = {}
+ for i in xrange(0, count):
+ data = DataBuffer(handle = core.BNDuplicateDataBuffer(params[i].value))
+ param_map[params[i].name] = str(data)
+ result = self.perform_decode(str(input_obj), param_map)
+ if result is None:
+ return False
+ result = str(result)
+ core.BNSetDataBufferContents(output_buf, result, len(result))
+ return True
+ except:
+ log_error(traceback.format_exc())
+ return False
+
+ def _encode(self, ctxt, input_buf, output_buf, params, count):
+ try:
+ input_obj = DataBuffer(handle = core.BNDuplicateDataBuffer(input_buf))
+ param_map = {}
+ for i in xrange(0, count):
+ data = DataBuffer(handle = core.BNDuplicateDataBuffer(params[i].value))
+ param_map[params[i].name] = str(data)
+ result = self.perform_encode(str(input_obj), param_map)
+ if result is None:
+ return False
+ result = str(result)
+ core.BNSetDataBufferContents(output_buf, result, len(result))
+ return True
+ except:
+ log_error(traceback.format_exc())
+ return False
+
+ def perform_decode(self, data, params):
+ if self.type == "InvertingTransform":
+ return perform_encode(data, params)
+ return None
+
+ def perform_encode(self, data, params):
+ return None
+
+ def decode(self, input_buf, params = {}):
+ input_buf = DataBuffer(input_buf)
+ output_buf = DataBuffer()
+ keys = params.keys()
+ param_buf = (core.BNTransformParameter * len(keys))()
+ param_data = []
+ for i in xrange(0, len(keys)):
+ data = DataBuffer(params[keys[i]])
+ param_buf[i].name = keys[i]
+ param_buf[i].value = data.handle
+ if not core.BNDecode(self.handle, input_buf.handle, output_buf.handle, param_buf, len(keys)):
+ return None
+ return str(output_buf)
+
+ def encode(self, input_buf, params = {}):
+ input_buf = DataBuffer(input_buf)
+ output_buf = DataBuffer()
+ keys = params.keys()
+ param_buf = (core.BNTransformParameter * len(keys))()
+ param_data = []
+ for i in xrange(0, len(keys)):
+ data = DataBuffer(params[keys[i]])
+ param_buf[i].name = keys[i]
+ param_buf[i].value = data.handle
+ if not core.BNEncode(self.handle, input_buf.handle, output_buf.handle, param_buf, len(keys)):
+ return None
+ return str(output_buf)
+
+class FunctionRecognizer:
+ _instance = None
+
+ def __init__(self):
+ self._cb = core.BNFunctionRecognizer()
+ self._cb.context = 0
+ self._cb.recognizeLowLevelIL = self._cb.recognizeLowLevelIL.__class__(self._recognize_low_level_il)
+
+ @classmethod
+ def register_global(cls):
+ if cls._instance is None:
+ cls._instance = cls()
+ core.BNRegisterGlobalFunctionRecognizer(cls._instance._cb)
+
+ @classmethod
+ def register_arch(cls, arch):
+ if cls._instance is None:
+ cls._instance = cls()
+ core.BNRegisterArchitectureFunctionRecognizer(arch.handle, cls._instance._cb)
+
+ def _recognize_low_level_il(self, ctxt, data, func, il):
+ try:
+ file_metadata = FileMetadata(handle = core.BNGetFileForView(data))
+ view = BinaryView(file_metadata, handle = core.BNNewViewReference(data))
+ func = Function(view, handle = core.BNNewFunctionReference(func))
+ il = LowLevelILFunction(func.arch, handle = core.BNNewLowLevelILFunctionReference(il))
+ return self.recognize_low_level_il(view, func, il)
+ except:
+ log_error(traceback.format_exc())
+ return False
+
+ def recognize_low_level_il(self, data, func, il):
+ return False
+
+class _UpdateChannelMetaClass(type):
+ def __getattr__(cls, name):
+ if name == "list":
+ _init_plugins()
+ count = ctypes.c_ulonglong()
+ errors = ctypes.c_char_p()
+ channels = core.BNGetUpdateChannels(count, errors)
+ if errors:
+ error_str = errors.value
+ core.BNFreeString(ctypes.cast(errors, ctypes.POINTER(ctypes.c_byte)))
+ raise IOError, error_str
+ result = []
+ for i in xrange(0, count.value):
+ result.append(UpdateChannel(channels[i].name, channels[i].description, channels[i].latestVersion))
+ core.BNFreeUpdateChannelList(channels, count.value)
+ return result
+ elif name == "active":
+ return core.BNGetActiveUpdateChannel()
+ raise AttributeError, "no attribute '%s'" % name
+
+ def __setattr__(cls, name, value):
+ if (name == "list"):
+ raise AttributeError, "attribute '%s' is read only" % name
+ elif name == "active":
+ return core.BNSetActiveUpdateChannel(value)
+ else:
+ type.__setattr__(cls, name, value)
+
+ def __dir__(self):
+ return dir(self.__class__) + ["list","active"]
+
+ def __getitem__(cls, name):
+ _init_plugins()
+ count = ctypes.c_ulonglong()
+ errors = ctypes.c_char_p()
+ channels = core.BNGetUpdateChannels(count, errors)
+ if errors:
+ error_str = errors.value
+ core.BNFreeString(ctypes.cast(errors, ctypes.POINTER(ctypes.c_byte)))
+ raise IOError, error_str
+ result = None
+ for i in xrange(0, count.value):
+ if channels[i].name == str(name):
+ result = UpdateChannel(channels[i].name, channels[i].description, channels[i].latestVersion)
+ break
+ core.BNFreeUpdateChannelList(channels, count.value)
+ if result is None:
+ raise KeyError, "'%s' is not a valid channel" % str(name)
+ return result
+
+class UpdateProgressCallback:
+ 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
+
+ def callback(self, ctxt, progress, total):
+ try:
+ if self.func is not None:
+ return self.func(progress, total)
+ return True
+ except:
+ log_error(traceback.format_exc())
+
+class UpdateChannel:
+ __metaclass__ = _UpdateChannelMetaClass
+
+ def __init__(self, name, desc, ver):
+ self.name = name
+ self.description = desc
+ self.latest_version_num = ver
+
+ def __getattr__(self, name):
+ if name == "versions":
+ count = ctypes.c_ulonglong()
+ errors = ctypes.c_char_p()
+ versions = core.BNGetUpdateChannelVersions(self.name, count, errors)
+ if errors:
+ error_str = errors.value
+ core.BNFreeString(ctypes.cast(errors, ctypes.POINTER(ctypes.c_byte)))
+ raise IOError, error_str
+ result = []
+ for i in xrange(0, count.value):
+ result.append(UpdateVersion(self, versions[i].version, versions[i].notes, versions[i].time))
+ core.BNFreeUpdateChannelVersionList(versions, count.value)
+ return result
+ elif name == "latest_version":
+ count = ctypes.c_ulonglong()
+ errors = ctypes.c_char_p()
+ versions = core.BNGetUpdateChannelVersions(self.name, count, errors)
+ if errors:
+ error_str = errors.value
+ core.BNFreeString(ctypes.cast(errors, ctypes.POINTER(ctypes.c_byte)))
+ raise IOError, error_str
+ result = None
+ for i in xrange(0, count.value):
+ if versions[i].version == self.latest_version_num:
+ result = UpdateVersion(self, versions[i].version, versions[i].notes, versions[i].time)
+ break
+ core.BNFreeUpdateChannelVersionList(versions, count.value)
+ return result
+ elif name == "updates_available":
+ errors = ctypes.c_char_p()
+ result = core.BNAreUpdatesAvailable(self.name, errors)
+ if errors:
+ error_str = errors.value
+ core.BNFreeString(ctypes.cast(errors, ctypes.POINTER(ctypes.c_byte)))
+ raise IOError, error_str
+ return result
+ raise AttributeError, "no attribute '%s'" % name
+
+ def __setattr__(self, name, value):
+ if (name == "versions") or (name == "latest_version"):
+ raise AttributeError, "attribute '%s' is read only" % name
+ else:
+ self.__dict__[name] = value
+
+ def __dir__(self):
+ return dir(self.__class__) + ["versions","latest_version", "updates_available"]
+
+ def __repr__(self):
+ return "<channel: %s>" % self.name
+
+ def __str__(self):
+ return self.name
+
+ def update_to_latest(self, progress = None):
+ cb = UpdateProgressCallback(progress)
+ errors = ctypes.c_char_p()
+ result = core.BNUpdateToLatestVersion(self.name, errors, cb.cb, None)
+ if errors:
+ error_str = errors.value
+ core.BNFreeString(ctypes.cast(errors, ctypes.POINTER(ctypes.c_byte)))
+ raise IOError, error_str
+ return core.BNUpdateResult_names[result]
+
+class UpdateVersion:
+ def __init__(self, channel, ver, notes, t):
+ self.channel = channel
+ self.version = ver
+ self.notes = notes
+ self.time = t
+
+ def __repr__(self):
+ return "<version: %s>" % self.version
+
+ def __str__(self):
+ return self.version
+
+ def update(self, progress = None):
+ cb = UpdateProgressCallback(progress)
+ errors = ctypes.c_char_p()
+ result = core.BNUpdateToVersion(self.channel.name, self.version, errors, cb.cb, None)
+ if errors:
+ error_str = errors.value
+ core.BNFreeString(ctypes.cast(errors, ctypes.POINTER(ctypes.c_byte)))
+ raise IOError, error_str
+ return core.BNUpdateResult_names[result]
+
+class PluginCommandContext:
+ def __init__(self, view):
+ self.view = view
+ self.address = 0
+ self.length = 0
+ self.function = None
+
+class _PluginCommandMetaClass(type):
+ def __getattr__(cls, name):
+ if name == "list":
+ _init_plugins()
+ count = ctypes.c_ulonglong()
+ commands = core.BNGetAllPluginCommands(count)
+ result = []
+ for i in xrange(0, count.value):
+ result.append(PluginCommand(commands[i]))
+ core.BNFreePluginCommandList(commands)
+ return result
+ raise AttributeError, "no attribute '%s'" % name
+
+ def __setattr__(cls, name, value):
+ if (name == "list"):
+ raise AttributeError, "attribute '%s' is read only" % name
+ else:
+ type.__setattr__(cls, name, value)
+
+ def __dir__(self):
+ return dir(self.__class__) + ["list"]
+
+class PluginCommand:
+ _registered_commands = []
+ __metaclass__ = _PluginCommandMetaClass
+
+ def __init__(self, cmd):
+ self.command = core.BNPluginCommand()
+ 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_names[cmd.type]
+
+ @classmethod
+ def _default_action(cls, view, action):
+ try:
+ file_metadata = FileMetadata(handle = core.BNGetFileForView(view))
+ view_obj = BinaryView(file_metadata, handle = core.BNNewViewReference(view))
+ action(view_obj)
+ except:
+ log_error(traceback.format_exc())
+
+ @classmethod
+ def _address_action(cls, view, addr, action):
+ try:
+ file_metadata = FileMetadata(handle = core.BNGetFileForView(view))
+ view_obj = BinaryView(file_metadata, handle = core.BNNewViewReference(view))
+ action(view_obj, addr)
+ except:
+ log_error(traceback.format_exc())
+
+ @classmethod
+ def _range_action(cls, view, addr, length, action):
+ try:
+ file_metadata = FileMetadata(handle = core.BNGetFileForView(view))
+ view_obj = BinaryView(file_metadata, handle = core.BNNewViewReference(view))
+ action(view_obj, addr, length)
+ except:
+ log_error(traceback.format_exc())
+
+ @classmethod
+ def _function_action(cls, view, func, action):
+ try:
+ file_metadata = FileMetadata(handle = core.BNGetFileForView(view))
+ view_obj = BinaryView(file_metadata, handle = core.BNNewViewReference(view))
+ func_obj = Function(view_obj, core.BNNewFunctionReference(func))
+ action(view_obj, func_obj)
+ except:
+ log_error(traceback.format_exc())
+
+ @classmethod
+ def _default_is_valid(cls, view, is_valid):
+ try:
+ if is_valid is None:
+ return True
+ file_metadata = FileMetadata(handle = core.BNGetFileForView(view))
+ view_obj = BinaryView(file_metadata, handle = core.BNNewViewReference(view))
+ return is_valid(view_obj)
+ except:
+ log_error(traceback.format_exc())
+ return False
+
+ @classmethod
+ def _address_is_valid(cls, view, addr, is_valid):
+ try:
+ if is_valid is None:
+ return True
+ file_metadata = FileMetadata(handle = core.BNGetFileForView(view))
+ view_obj = BinaryView(file_metadata, handle = core.BNNewViewReference(view))
+ return is_valid(view_obj, addr)
+ except:
+ log_error(traceback.format_exc())
+ return False
+
+ @classmethod
+ def _range_is_valid(cls, view, addr, length, is_valid):
+ try:
+ if is_valid is None:
+ return True
+ file_metadata = FileMetadata(handle = core.BNGetFileForView(view))
+ view_obj = BinaryView(file_metadata, handle = core.BNNewViewReference(view))
+ return is_valid(view_obj, addr, length)
+ except:
+ log_error(traceback.format_exc())
+ return False
+
+ @classmethod
+ def _function_is_valid(cls, view, func, is_valid):
+ try:
+ if is_valid is None:
+ return True
+ file_metadata = FileMetadata(handle = core.BNGetFileForView(view))
+ view_obj = BinaryView(file_metadata, handle = core.BNNewViewReference(view))
+ func_obj = Function(view_obj, core.BNNewFunctionReference(func))
+ return is_valid(view_obj, func_obj)
+ except:
+ log_error(traceback.format_exc())
+ return False
+
+ @classmethod
+ def register(cls, name, description, action, is_valid = None):
+ _init_plugins()
+ action_obj = ctypes.CFUNCTYPE(None, ctypes.c_void_p, ctypes.POINTER(core.BNBinaryView))(lambda ctxt, view: cls._default_action(view, action))
+ is_valid_obj = ctypes.CFUNCTYPE(ctypes.c_bool, ctypes.c_void_p, ctypes.POINTER(core.BNBinaryView))(lambda ctxt, view: cls._default_is_valid(view, is_valid))
+ cls._registered_commands.append((action_obj, is_valid_obj))
+ core.BNRegisterPluginCommand(name, description, action_obj, is_valid_obj, None)
+
+ @classmethod
+ def register_for_address(cls, name, description, action, is_valid = None):
+ _init_plugins()
+ action_obj = ctypes.CFUNCTYPE(None, ctypes.c_void_p, ctypes.POINTER(core.BNBinaryView), ctypes.c_ulonglong)(lambda ctxt, view, addr: cls._address_action(view, addr, action))
+ is_valid_obj = ctypes.CFUNCTYPE(ctypes.c_bool, ctypes.c_void_p, ctypes.POINTER(core.BNBinaryView), ctypes.c_ulonglong)(lambda ctxt, view, addr: cls._address_is_valid(view, addr, is_valid))
+ cls._registered_commands.append((action_obj, is_valid_obj))
+ core.BNRegisterPluginCommandForAddress(name, description, action_obj, is_valid_obj, None)
+
+ @classmethod
+ def register_for_range(cls, name, description, action, is_valid = None):
+ _init_plugins()
+ action_obj = ctypes.CFUNCTYPE(None, ctypes.c_void_p, ctypes.POINTER(core.BNBinaryView), ctypes.c_ulonglong, ctypes.c_ulonglong)(lambda ctxt, view, addr, length: cls._range_action(view, addr, length, action))
+ is_valid_obj = ctypes.CFUNCTYPE(ctypes.c_bool, ctypes.c_void_p, ctypes.POINTER(core.BNBinaryView), ctypes.c_ulonglong, ctypes.c_ulonglong)(lambda ctxt, view, addr, length: cls._range_is_valid(view, addr, length, is_valid))
+ cls._registered_commands.append((action_obj, is_valid_obj))
+ core.BNRegisterPluginCommandForRange(name, description, action_obj, is_valid_obj, None)
+
+ @classmethod
+ def register_for_function(cls, name, description, action, is_valid = None):
+ _init_plugins()
+ action_obj = ctypes.CFUNCTYPE(None, ctypes.c_void_p, ctypes.POINTER(core.BNBinaryView), ctypes.POINTER(core.BNFunction))(lambda ctxt, view, func: cls._function_action(view, func, action))
+ is_valid_obj = ctypes.CFUNCTYPE(ctypes.c_bool, ctypes.c_void_p, ctypes.POINTER(core.BNBinaryView), ctypes.POINTER(core.BNFunction))(lambda ctxt, view, func: cls._function_is_valid(view, func, is_valid))
+ cls._registered_commands.append((action_obj, is_valid_obj))
+ core.BNRegisterPluginCommandForFunction(name, description, action_obj, is_valid_obj, None)
+
+ @classmethod
+ def get_valid_list(cls, context):
+ commands = cls.list
+ result = []
+ for cmd in commands:
+ if cmd.is_valid(context):
+ result.append(cmd)
+ return result
+
+ def is_valid(self, context):
+ if context.view is None:
+ return False
+ if self.command.type == core.DefaultPluginCommand:
+ if not self.command.defaultIsValid:
+ return True
+ return self.command.defaultIsValid(self.command.context, context.view.handle)
+ elif self.command.type == core.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.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.FunctionPluginCommand:
+ if context.function is None:
+ return False
+ if not self.command.functionIsValid:
+ return True
+ return self.command.functionIsValid(self.command.context, context.view.handle, context.function.handle)
+ return False
+
+ def execute(self, context):
+ if not self.is_valid(context):
+ return
+ if self.command.type == core.DefaultPluginCommand:
+ self.command.defaultCommand(self.command.context, context.view.handle)
+ elif self.command.type == core.AddressPluginCommand:
+ self.command.addressCommand(self.command.context, context.view.handle, context.address)
+ elif self.command.type == core.RangePluginCommand:
+ self.command.rangeCommand(self.command.context, context.view.handle, context.address, context.length)
+ elif self.command.type == core.FunctionPluginCommand:
+ self.command.functionCommand(self.command.context, context.view.handle, context.function.handle)
+
+ def __repr__(self):
+ return "<PluginCommand: %s>" % self.name
+
+class CallingConvention:
+ name = None
+ caller_saved_regs = []
+ int_arg_regs = []
+ float_arg_regs = []
+ arg_regs_share_index = False
+ stack_reserved_for_arg_regs = False
+ int_return_reg = None
+ high_int_return_reg = None
+ float_return_reg = None
+
+ _registered_calling_conventions = []
+
+ def __init__(self, arch, handle = None):
+ if handle is None:
+ self.arch = arch
+ self._pending_reg_lists = {}
+ self._cb = core.BNCustomCallingConvention()
+ self._cb.context = 0
+ self._cb.getCallerSavedRegisters = self._cb.getCallerSavedRegisters.__class__(self._get_caller_saved_regs)
+ self._cb.getIntegerArgumentRegisters = self._cb.getIntegerArgumentRegisters.__class__(self._get_int_arg_regs)
+ self._cb.getFloatArgumentRegisters = self._cb.getFloatArgumentRegisters.__class__(self._get_float_arg_regs)
+ self._cb.freeRegisterList = self._cb.freeRegisterList.__class__(self._free_register_list)
+ self._cb.areArgumentRegistersSharedIndex = self._cb.areArgumentRegistersSharedIndex.__class__(self._arg_regs_share_index)
+ self._cb.isStackReservedForArgumentRegisters = self._cb.isStackReservedForArgumentRegisters.__class__(self._stack_reserved_for_arg_regs)
+ self._cb.getIntegerReturnValueRegister = self._cb.getIntegerReturnValueRegister.__class__(self._get_int_return_reg)
+ self._cb.getHighIntegerReturnValueRegister = self._cb.getHighIntegerReturnValueRegister.__class__(self._get_high_int_return_reg)
+ self._cb.getFloatReturnValueRegister = self._cb.getFloatReturnValueRegister.__class__(self._get_float_return_reg)
+ self.handle = core.BNCreateCallingConvention(arch.handle, self.__class__.name, self._cb)
+ self.__class__._registered_calling_conventions.append(self)
+ else:
+ self.handle = handle
+ self.arch = Architecture(core.BNGetCallingConventionArchitecture(self.handle))
+ self.__dict__["name"] = core.BNGetCallingConventionName(self.handle)
+ self.__dict__["arg_regs_share_index"] = core.BNAreArgumentRegistersSharedIndex(self.handle)
+ self.__dict__["stack_reserved_for_arg_regs"] = core.BNIsStackReservedForArgumentRegisters(self.handle)
+
+ count = ctypes.c_ulonglong()
+ regs = core.BNGetCallerSavedRegisters(self.handle, count)
+ result = []
+ arch = self.arch
+ for i in xrange(0, count.value):
+ result.append(arch.get_reg_name(regs[i]))
+ core.BNFreeRegisterList(regs, count.value)
+ self.__dict__["caller_saved_regs"] = result
+
+ count = ctypes.c_ulonglong()
+ regs = core.BNGetIntegerArgumentRegisters(self.handle, count)
+ result = []
+ arch = self.arch
+ for i in xrange(0, count.value):
+ result.append(arch.get_reg_name(regs[i]))
+ core.BNFreeRegisterList(regs, count.value)
+ self.__dict__["int_arg_regs"] = result
+
+ count = ctypes.c_ulonglong()
+ regs = core.BNGetFloatArgumentRegisters(self.handle, count)
+ result = []
+ arch = self.arch
+ for i in xrange(0, count.value):
+ result.append(arch.get_reg_name(regs[i]))
+ core.BNFreeRegisterList(regs, count.value)
+ self.__dict__["float_arg_regs"] = result
+
+ reg = core.BNGetIntegerReturnValueRegister(self.handle)
+ if reg == 0xffffffff:
+ self.__dict__["int_return_reg"] = None
+ else:
+ self.__dict__["int_return_reg"] = self.arch.get_reg_name(reg)
+
+ reg = core.BNGetHighIntegerReturnValueRegister(self.handle)
+ if reg == 0xffffffff:
+ self.__dict__["high_int_return_reg"] = None
+ else:
+ self.__dict__["high_int_return_reg"] = self.arch.get_reg_name(reg)
+
+ reg = core.BNGetFloatReturnValueRegister(self.handle)
+ if reg == 0xffffffff:
+ self.__dict__["float_return_reg"] = None
+ else:
+ self.__dict__["float_return_reg"] = self.arch.get_reg_name(reg)
+
+ def __del__(self):
+ core.BNFreeCallingConvention(self.handle)
+
+ def _get_caller_saved_regs(self, ctxt, count):
+ try:
+ regs = self.__class__.caller_saved_regs
+ count[0] = len(regs)
+ reg_buf = (ctypes.c_uint * len(regs))()
+ for i in xrange(0, len(regs)):
+ reg_buf[i] = self.arch.regs[regs[i]].index
+ result = ctypes.cast(reg_buf, ctypes.c_void_p)
+ self._pending_reg_lists[result.value] = (result, reg_buf)
+ return result.value
+ except:
+ log_error(traceback.format_exc())
+ count[0] = 0
+ return None
+
+ def _get_int_arg_regs(self, ctxt, count):
+ try:
+ regs = self.__class__.int_arg_regs
+ count[0] = len(regs)
+ reg_buf = (ctypes.c_uint * len(regs))()
+ for i in xrange(0, len(regs)):
+ reg_buf[i] = self.arch.regs[regs[i]].index
+ result = ctypes.cast(reg_buf, ctypes.c_void_p)
+ self._pending_reg_lists[result.value] = (result, reg_buf)
+ return result.value
+ except:
+ log_error(traceback.format_exc())
+ count[0] = 0
+ return None
+
+ def _get_float_arg_regs(self, ctxt, count):
+ try:
+ regs = self.__class__.float_arg_regs
+ count[0] = len(regs)
+ reg_buf = (ctypes.c_uint * len(regs))()
+ for i in xrange(0, len(regs)):
+ reg_buf[i] = self.arch.regs[regs[i]].index
+ result = ctypes.cast(reg_buf, ctypes.c_void_p)
+ self._pending_reg_lists[result.value] = (result, reg_buf)
+ return result.value
+ except:
+ log_error(traceback.format_exc())
+ count[0] = 0
+ return None
+
+ def _free_register_list(self, ctxt, regs):
+ try:
+ buf = ctypes.cast(regs, ctypes.c_void_p)
+ 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:
+ log_error(traceback.format_exc())
+
+ def _arg_regs_share_index(self, ctxt):
+ try:
+ return self.__class__.arg_regs_share_index
+ except:
+ log_error(traceback.format_exc())
+ return False
+
+ def _stack_reserved_for_arg_regs(self, ctxt):
+ try:
+ return self.__class__.stack_reserved_for_arg_regs
+ except:
+ log_error(traceback.format_exc())
+ return False
+
+ def _get_int_return_reg(self, ctxt):
+ try:
+ return self.arch.regs[self.__class__.int_return_reg].index
+ except:
+ log_error(traceback.format_exc())
+ return False
+
+ def _get_high_int_return_reg(self, ctxt):
+ try:
+ if self.__class__.high_int_return_reg is None:
+ return 0xffffffff
+ return self.arch.regs[self.__class__.high_int_return_reg].index
+ except:
+ log_error(traceback.format_exc())
+ return False
+
+ def _get_float_return_reg(self, ctxt):
+ try:
+ if self.__class__.float_return_reg is None:
+ return 0xffffffff
+ return self.arch.regs[self.__class__.float_int_return_reg].index
+ except:
+ log_error(traceback.format_exc())
+ return False
+
+ def __repr__(self):
+ return "<calling convention: %s %s>" % (self.arch.name, self.name)
+
+ def __str__(self):
+ return self.name
+
+class _PlatformMetaClass(type):
+ def __getattr__(cls, name):
+ if name == "list":
+ _init_plugins()
+ count = ctypes.c_ulonglong()
+ platforms = core.BNGetPlatformList(count)
+ result = []
+ for i in xrange(0, count.value):
+ result.append(Platform(None, core.BNNewPlatformReference(platforms[i])))
+ core.BNFreePlatformList(platforms, count.value)
+ return result
+ elif name == "os_list":
+ _init_plugins()
+ count = ctypes.c_ulonglong()
+ platforms = core.BNGetPlatformOSList(count)
+ result = []
+ for i in xrange(0, count.value):
+ result.append(str(platforms[i]))
+ core.BNFreePlatformOSList(platforms, count.value)
+ return result
+ raise AttributeError, "no attribute '%s'" % name
+
+ def __setattr__(cls, name, value):
+ if (name == "list") or (name == "os_list"):
+ raise AttributeError, "attribute '%s' is read only" % name
+ else:
+ type.__setattr__(cls, name, value)
+
+ def __dir__(self):
+ return dir(self.__class__) + ["list","os_list"]
+
+ def __getitem__(cls, value):
+ _init_plugins()
+ platform = core.BNGetPlatformByName(str(value))
+ if platform is None:
+ raise KeyError, "'%s' is not a valid platform" % str(value)
+ return Platform(None, platform)
+
+ def get_list(cls, os = None, arch = None):
+ _init_plugins()
+ count = ctypes.c_ulonglong()
+ if os is None:
+ platforms = core.BNGetPlatformList(count)
+ elif arch is None:
+ platforms = core.BNGetPlatformListByOS(os)
+ else:
+ platforms = core.BNGetPlatformListByArchitecture(os, arch.handle)
+ result = []
+ for i in xrange(0, count.value):
+ result.append(Platform(None, core.BNNewPlatformReference(platforms[i])))
+ core.BNFreePlatformList(platforms, count.value)
+ return result
+
+class Platform:
+ __metaclass__ = _PlatformMetaClass
+ name = None
+
+ def __init__(self, arch, handle = None):
+ if handle is None:
+ self.arch = arch
+ self.handle = core.BNCreatePlatform(arch.handle, self.__class__.name)
+ else:
+ self.handle = handle
+ self.__dict__["name"] = core.BNGetPlatformName(self.handle)
+ self.arch = Architecture(core.BNGetPlatformArchitecture(self.handle))
+
+ def __del__(self):
+ core.BNFreePlatform(self.handle)
+
+ def __getattr__(self, name):
+ if name == "default_calling_convention":
+ result = core.BNGetPlatformDefaultCallingConvention(self.handle)
+ if result is None:
+ return None
+ return CallingConvention(None, result)
+ elif name == "cdecl_calling_convention":
+ result = core.BNGetPlatformCdeclCallingConvention(self.handle)
+ if result is None:
+ return None
+ return CallingConvention(None, result)
+ elif name == "stdcall_calling_convention":
+ result = core.BNGetPlatformStdcallCallingConvention(self.handle)
+ if result is None:
+ return None
+ return CallingConvention(None, result)
+ elif name == "fastcall_calling_convention":
+ result = core.BNGetPlatformFastcallCallingConvention(self.handle)
+ if result is None:
+ return None
+ return CallingConvention(None, result)
+ elif name == "system_call_convention":
+ result = core.BNGetPlatformSystemCallConvention(self.handle)
+ if result is None:
+ return None
+ return CallingConvention(None, result)
+ elif name == "calling_conventions":
+ count = ctypes.c_ulonglong()
+ cc = core.BNGetPlatformCallingConventions(self.handle, count)
+ result = []
+ for i in xrange(0, count.value):
+ result.append(CallingConvention(None, core.BNNewCallingConventionReference(cc[i])))
+ core.BNFreeCallingConventionList(cc, count.value)
+ return result
+ raise AttributeError, "no attribute '%s'" % name
+
+ def __setattr__(self, name, value):
+ if name == "default_calling_convention":
+ core.BNRegisterPlatformDefaultCallingConvention(self.handle, value.handle)
+ elif name == "cdecl_calling_convention":
+ core.BNRegisterPlatformCdeclCallingConvention(self.handle, value.handle)
+ elif name == "stdcall_calling_convention":
+ core.BNRegisterPlatformStdcallCallingConvention(self.handle, value.handle)
+ elif name == "fastcall_calling_convention":
+ core.BNRegisterPlatformFastcallCallingConvention(self.handle, value.handle)
+ elif name == "system_call_convention":
+ core.BNSetPlatformSystemCallConvention(self.handle, value.handle)
+ elif (name == "calling_conventions"):
+ raise AttributeError, "attribute '%s' is read only" % name
+ else:
+ self.__dict__[name] = value
+
+ def __dir__(self):
+ return dir(self.__class__) + ["default_calling_convention", "cdecl_calling_convention",
+ "stdcall_calling_convention", "fastcall_calling_convention", "system_call_convention", "calling_conventions"]
+
+ def __repr__(self):
+ return "<platform: %s>" % self.name
+
+ def __str__(self):
+ return self.name
+
+ def register(self, os):
+ core.BNRegisterPlatform(os, self.handle)
+
+ def register_calling_convention(self, cc):
+ core.BNRegisterPlatformCallingConvention(self.handle, cc.handle)
+
+def LLIL_TEMP(n):
+ return n | 0x80000000
+
+def LLIL_REG_IS_TEMP(n):
+ return (n & 0x80000000) != 0
+
+def LLIL_GET_TEMP_REG_INDEX(n):
+ return n & 0x7fffffff
+
+def shutdown():
+ core.BNShutdown()
+
+def log(level, text):
+ core.BNLog(level, "%s", str(text))
+
+def log_debug(text):
+ core.BNLogDebug("%s", str(text))
+
+def log_info(text):
+ core.BNLogInfo("%s", str(text))
+
+def log_warn(text):
+ core.BNLogWarn("%s", str(text))
+
+def log_error(text):
+ core.BNLogError("%s", str(text))
+
+def log_alert(text):
+ core.BNLogAlert("%s", str(text))
+
+def log_to_stdout(min_level):
+ core.BNLogToStdout(min_level)
+
+def log_to_stderr(min_level):
+ core.BNLogToStderr(min_level)
+
+def log_to_file(min_level, path, append = False):
+ core.BNLogToFile(min_level, str(path), append)
+
+def close_logs():
+ core.BNCloseLogs()
+
+def escape_string(text):
+ return DataBuffer(text).escape()
+
+def unescape_string(text):
+ return DataBuffer(text).unescape()
+
+def preprocess_source(source, filename = None, include_dirs = []):
+ 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)
+
+def are_auto_updates_enabled():
+ return core.BNAreAutoUpdatesEnabled()
+
+def set_auto_updates_enabled(enabled):
+ core.BNSetAutoUpdatesEnabled(enabled)
+
+def get_time_since_last_update_check():
+ return core.BNGetTimeSinceLastUpdateCheck()
+
+def updates_checked():
+ core.BNUpdatesChecked()
+
+bundled_plugin_path = core.BNGetBundledPluginDirectory()
+user_plugin_path = core.BNGetUserPluginDirectory()
+
+core_version = core.BNGetVersionString()
+core_build_id = core.BNGetBuildId()
+
+# Ensure all enumeration constants from the core are exposed by this module
+for name in core.all_enum_values:
+ globals()[name] = core.all_enum_values[name]
diff --git a/python/examples/nes.py b/python/examples/nes.py
new file mode 100644
index 00000000..bce3336b
--- /dev/null
+++ b/python/examples/nes.py
@@ -0,0 +1,661 @@
+from binaryninja import *
+import struct
+import traceback
+import os
+
+InstructionNames = [
+ "brk", "ora", None, None, None, "ora", "asl", None, # 0x00
+ "php", "ora", "asl@", None, None, "ora", "asl", None, # 0x08
+ "bpl", "ora", None, None, None, "ora", "asl", None, # 0x10
+ "clc", "ora", None, None, None, "ora", "asl", None, # 0x18
+ "jsr", "and", None, None, "bit", "and", "rol", None, # 0x20
+ "plp", "and", "rol@", None, "bit", "and", "rol", None, # 0x28
+ "bmi", "and", None, None, None, "and", "rol", None, # 0x30
+ "sec", "and", None, None, None, "and", "rol", None, # 0x38
+ "rti", "eor", None, None, None, "eor", "lsr", None, # 0x40
+ "pha", "eor", "lsr@", None, "jmp", "eor", "lsr", None, # 0x48
+ "bvc", "eor", None, None, None, "eor", "lsr", None, # 0x50
+ "cli", "eor", None, None, None, "eor", "lsr", None, # 0x58
+ "rts", "adc", None, None, None, "adc", "ror", None, # 0x60
+ "pla", "adc", "ror@", None, "jmp", "adc", "ror", None, # 0x68
+ "bvs", "adc", None, None, None, "adc", "ror", None, # 0x70
+ "sei", "adc", None, None, None, "adc", "ror", None, # 0x78
+ None, "sta", None, None, "sty", "sta", "stx", None, # 0x80
+ "dey", None, "txa", None, "sty", "sta", "stx", None, # 0x88
+ "bcc", "sta", None, None, "sty", "sta", "stx", None, # 0x90
+ "tya", "sta", "txs", None, None, "sta", None, None, # 0x98
+ "ldy", "lda", "ldx", None, "ldy", "lda", "ldx", None, # 0xa0
+ "tay", "lda", "tax", None, "ldy", "lda", "ldx", None, # 0xa8
+ "bcs", "lda", None, None, "ldy", "lda", "ldx", None, # 0xb0
+ "clv", "lda", "tsx", None, "ldy", "lda", "ldx", None, # 0xb8
+ "cpy", "cmp", None, None, "cpy", "cmp", "dec", None, # 0xc0
+ "iny", "cmp", "dex", None, "cpy", "cmp", "dec", None, # 0xc8
+ "bne", "cmp", None, None, None, "cmp", "dec", None, # 0xd0
+ "cld", "cmp", None, None, None, "cmp", "dec", None, # 0xd8
+ "cpx", "sbc", None, None, "cpx", "sbc", "inc", None, # 0xe0
+ "inx", "sbc", "nop", None, "cpx", "sbc", "inc", None, # 0xe8
+ "beq", "sbc", None, None, None, "sbc", "inc", None, # 0xf0
+ "sed", "sbc", None, None, None, "sbc", "inc", None # 0xf8
+]
+
+NONE = 0
+ABS = 1
+ABS_DEST = 2
+ABS_X = 3
+ABS_X_DEST = 4
+ABS_Y = 5
+ABS_Y_DEST = 6
+ACCUM = 7
+ADDR = 8
+IMMED = 9
+IND = 10
+IND_X = 11
+IND_X_DEST = 12
+IND_Y = 13
+IND_Y_DEST = 14
+REL = 15
+ZERO = 16
+ZERO_DEST = 17
+ZERO_X = 18
+ZERO_X_DEST = 19
+ZERO_Y = 20
+ZERO_Y_DEST = 21
+InstructionOperandTypes = [
+ NONE, IND_X, NONE, NONE, NONE, ZERO, ZERO_DEST, NONE, # 0x00
+ NONE, IMMED, ACCUM, NONE, NONE, ABS, ABS_DEST, NONE, # 0x08
+ REL, IND_Y, NONE, NONE, NONE, ZERO_X, ZERO_X_DEST, NONE, # 0x10
+ NONE, ABS_Y, NONE, NONE, NONE, ABS_X, ABS_X_DEST, NONE, # 0x18
+ ADDR, IND_X, NONE, NONE, ZERO, ZERO, ZERO_DEST, NONE, # 0x20
+ NONE, IMMED, ACCUM, NONE, ABS, ABS, ABS_DEST, NONE, # 0x28
+ REL, IND_Y, NONE, NONE, NONE, ZERO_X, ZERO_X_DEST, NONE, # 0x30
+ NONE, ABS_Y, NONE, NONE, NONE, ABS_X, ABS_X_DEST, NONE, # 0x38
+ NONE, IND_X, NONE, NONE, NONE, ZERO, ZERO_DEST, NONE, # 0x40
+ NONE, IMMED, ACCUM, NONE, ADDR, ABS, ABS_DEST, NONE, # 0x48
+ REL, IND_Y, NONE, NONE, NONE, ZERO_X, ZERO_X_DEST, NONE, # 0x50
+ NONE, ABS_Y, NONE, NONE, NONE, ABS_X, ABS_X_DEST, NONE, # 0x58
+ NONE, IND_X, NONE, NONE, NONE, ZERO, ZERO_DEST, NONE, # 0x60
+ NONE, IMMED, ACCUM, NONE, IND, ABS, ABS_DEST, NONE, # 0x68
+ REL, IND_Y, NONE, NONE, NONE, ZERO_X, ZERO_X_DEST, NONE, # 0x70
+ NONE, ABS_Y, NONE, NONE, NONE, ABS_X, ABS_X_DEST, NONE, # 0x78
+ NONE, IND_X_DEST, NONE, NONE, ZERO_DEST, ZERO_DEST, ZERO_DEST, NONE, # 0x80
+ NONE, NONE, NONE, NONE, ABS_DEST, ABS_DEST, ABS_DEST, NONE, # 0x88
+ REL, IND_Y_DEST, NONE, NONE, ZERO_X_DEST, ZERO_X_DEST, ZERO_Y_DEST, NONE, # 0x90
+ NONE, ABS_Y_DEST, NONE, NONE, NONE, ABS_X_DEST, NONE, NONE, # 0x98
+ IMMED, IND_X, IMMED, NONE, ZERO, ZERO, ZERO, NONE, # 0xa0
+ NONE, IMMED, NONE, NONE, ABS, ABS, ABS, NONE, # 0xa8
+ REL, IND_Y, NONE, NONE, ZERO_X, ZERO_X, ZERO_Y, NONE, # 0xb0
+ NONE, ABS_Y, NONE, NONE, ABS_X, ABS_X, ABS_Y, NONE, # 0xb8
+ IMMED, IND_X, NONE, NONE, ZERO, ZERO, ZERO_DEST, NONE, # 0xc0
+ NONE, IMMED, NONE, NONE, ABS, ABS, ABS_DEST, NONE, # 0xc8
+ REL, IND_Y, NONE, NONE, NONE, ZERO_X, ZERO_X_DEST, NONE, # 0xd0
+ NONE, ABS_Y, NONE, NONE, NONE, ABS_X, ABS_X_DEST, NONE, # 0xd8
+ IMMED, IND_X, NONE, NONE, ZERO, ZERO, ZERO_DEST, NONE, # 0xe0
+ NONE, IMMED, NONE, NONE, ABS, ABS, ABS_DEST, NONE, # 0xe8
+ REL, IND_Y, NONE, NONE, NONE, ZERO_X, ZERO_X_DEST, NONE, # 0xf0
+ NONE, ABS_Y, NONE, NONE, NONE, ABS_X, ABS_X_DEST, NONE # 0xf8
+]
+
+OperandLengths = [
+ 0, # NONE
+ 2, # ABS
+ 2, # ABS_DEST
+ 2, # ABS_X
+ 2, # ABS_X_DEST
+ 2, # ABS_Y
+ 2, # ABS_Y_DEST
+ 0, # ACCUM
+ 2, # ADDR
+ 1, # IMMED
+ 2, # IND
+ 1, # IND_X
+ 1, # IND_X_DEST
+ 1, # IND_Y
+ 1, # IND_Y_DEST
+ 1, # REL
+ 1, # ZERO
+ 1, # ZREO_DEST
+ 1, # ZERO_X
+ 1, # ZERO_X_DEST
+ 1, # ZERO_Y
+ 1 # ZERO_Y_DEST
+]
+
+OperandTokens = [
+ lambda value: [], # NONE
+ lambda value: [InstructionTextToken(PossibleAddressToken, "$%.4x" % value, value)], # ABS
+ lambda value: [InstructionTextToken(PossibleAddressToken, "$%.4x" % value, value)], # ABS_DEST
+ lambda value: [InstructionTextToken(PossibleAddressToken, "$%.4x" % value, value),
+ InstructionTextToken(TextToken, ", "), InstructionTextToken(RegisterToken, "x")], # ABS_X
+ lambda value: [InstructionTextToken(PossibleAddressToken, "$%.4x" % value, value),
+ InstructionTextToken(TextToken, ", "), InstructionTextToken(RegisterToken, "x")], # ABS_X_DEST
+ lambda value: [InstructionTextToken(PossibleAddressToken, "$%.4x" % value, value),
+ InstructionTextToken(TextToken, ", "), InstructionTextToken(RegisterToken, "y")], # ABS_Y
+ lambda value: [InstructionTextToken(PossibleAddressToken, "$%.4x" % value, value),
+ InstructionTextToken(TextToken, ", "), InstructionTextToken(RegisterToken, "y")], # ABS_Y_DEST
+ lambda value: [InstructionTextToken(RegisterToken, "a")], # ACCUM
+ lambda value: [InstructionTextToken(PossibleAddressToken, "$%.4x" % value, value)], # ADDR
+ lambda value: [InstructionTextToken(TextToken, "#"), InstructionTextToken(IntegerToken, "$%.2x" % value, value)], # IMMED
+ lambda value: [InstructionTextToken(TextToken, "["), InstructionTextToken(PossibleAddressToken, "$%.4x" % value, value),
+ InstructionTextToken(TextToken, "]")], # IND
+ lambda value: [InstructionTextToken(TextToken, "["), InstructionTextToken(PossibleAddressToken, "$%.2x" % value, value),
+ InstructionTextToken(TextToken, ", "), InstructionTextToken(RegisterToken, "x"),
+ InstructionTextToken(TextToken, "]")], # IND_X
+ lambda value: [InstructionTextToken(TextToken, "["), InstructionTextToken(PossibleAddressToken, "$%.2x" % value, value),
+ InstructionTextToken(TextToken, ", "), InstructionTextToken(RegisterToken, "x"),
+ InstructionTextToken(TextToken, "]")], # IND_X_DEST
+ lambda value: [InstructionTextToken(TextToken, "["), InstructionTextToken(PossibleAddressToken, "$%.2x" % value, value),
+ InstructionTextToken(TextToken, "], "), InstructionTextToken(RegisterToken, "y")], # IND_Y
+ lambda value: [InstructionTextToken(TextToken, "["), InstructionTextToken(PossibleAddressToken, "$%.2x" % value, value),
+ InstructionTextToken(TextToken, "], "), InstructionTextToken(RegisterToken, "y")], # IND_Y_DEST
+ lambda value: [InstructionTextToken(PossibleAddressToken, "$%.4x" % value, value)], # REL
+ lambda value: [InstructionTextToken(PossibleAddressToken, "$%.2x" % value, value)], # ZERO
+ lambda value: [InstructionTextToken(PossibleAddressToken, "$%.2x" % value, value)], # ZERO_DEST
+ lambda value: [InstructionTextToken(PossibleAddressToken, "$%.2x" % value, value),
+ InstructionTextToken(TextToken, ", "), InstructionTextToken(RegisterToken, "x")], # ZERO_X
+ lambda value: [InstructionTextToken(PossibleAddressToken, "$%.2x" % value, value),
+ InstructionTextToken(TextToken, ", "), InstructionTextToken(RegisterToken, "x")], # ZERO_X_DEST
+ lambda value: [InstructionTextToken(PossibleAddressToken, "$%.2x" % value, value),
+ InstructionTextToken(TextToken, ", "), InstructionTextToken(RegisterToken, "y")], # ZERO_Y
+ lambda value: [InstructionTextToken(PossibleAddressToken, "$%.2x" % value, value),
+ InstructionTextToken(TextToken, ", "), InstructionTextToken(RegisterToken, "y")] # ZERO_Y_DEST
+]
+
+def indirect_load(il, value):
+ if (value & 0xff) == 0xff:
+ lo_addr = il.const(2, value)
+ hi_addr = il.const(2, (value & 0xff00) | ((value + 1) & 0xff))
+ lo = il.zero_extend(2, il.load(1, lo_addr))
+ hi = il.shift_left(2, il.zero_extend(2, il.load(1, hi_addr)), il.const(2, 8))
+ return il.or_expr(2, lo, hi)
+ return il.load(2, il.const(2, value))
+
+def load_zero_page_16(il, value):
+ if il[value].operation == "LLIL_CONST":
+ if il[value].value == 0xff:
+ lo = il.zero_extend(2, il.load(1, il.const(2, 0xff)))
+ hi = il.shift_left(2, il.zero_extend(2, il.load(1, il.const(2, 0)), il.const(2, 8)))
+ return il.or_expr(2, lo, hi)
+ return il.load(2, il.const(2, il[value].value))
+ il.append(il.set_reg(1, LLIL_TEMP(0), value))
+ value = il.reg(1, LLIL_TEMP(0))
+ lo_addr = value
+ hi_addr = il.add(1, value, il.const(1, 1))
+ lo = il.zero_extend(2, il.load(1, lo_addr))
+ hi = il.shift_left(2, il.zero_extend(2, il.load(1, hi_addr)), il.const(2, 8))
+ return il.or_expr(2, lo, hi)
+
+OperandIL = [
+ lambda il, value: None, # NONE
+ lambda il, value: il.load(1, il.const(2, value)), # ABS
+ lambda il, value: il.const(2, value), # ABS_DEST
+ lambda il, value: il.load(1, il.add(2, il.const(2, value), il.zero_extend(2, il.reg(1, "x")))), # ABS_X
+ lambda il, value: il.add(2, il.const(2, value), il.zero_extend(2, il.reg(1, "x"))), # ABS_X_DEST
+ lambda il, value: il.load(1, il.add(2, il.const(2, value), il.zero_extend(2, il.reg(1, "y")))), # ABS_Y
+ lambda il, value: il.add(2, il.const(2, value), il.zero_extend(2, il.reg(1, "y"))), # ABS_Y_DEST
+ lambda il, value: il.reg(1, "a"), # ACCUM
+ lambda il, value: il.const(2, value), # ADDR
+ lambda il, value: il.const(1, value), # IMMED
+ lambda il, value: indirect_load(il, value), # IND
+ lambda il, value: il.load(1, load_zero_page_16(il, il.add(1, il.const(1, value), il.reg(1, "x")))), # IND_X
+ lambda il, value: load_zero_page_16(il, il.add(1, il.const(1, value), il.reg(1, "x"))), # IND_X_DEST
+ lambda il, value: il.load(1, il.add(2, load_zero_page_16(il, il.const(1, value)), il.reg(1, "y"))), # IND_Y
+ lambda il, value: il.add(2, load_zero_page_16(il, il.const(1, value)), il.reg(1, "y")), # IND_Y_DEST
+ lambda il, value: il.const(2, value), # REL
+ lambda il, value: il.load(1, il.const(2, value)), # ZERO
+ lambda il, value: il.const(2, value), # ZERO_DEST
+ lambda il, value: il.load(1, il.zero_extend(2, il.add(1, il.const(1, value), il.reg(1, "x")))), # ZERO_X
+ lambda il, value: il.zero_extend(2, il.add(1, il.const(1, value), il.reg(1, "x"))), # ZERO_X_DEST
+ lambda il, value: il.load(1, il.zero_extend(2, il.add(1, il.const(1, value), il.reg(1, "y")))), # ZERO_Y
+ lambda il, value: il.zero_extend(2, il.add(1, il.const(1, value), il.reg(1, "y"))) # ZERO_Y_DEST
+]
+
+def cond_branch(il, cond, dest):
+ t = None
+ if il[dest].operation == "LLIL_CONST":
+ t = il.get_label_for_address(Architecture['6502'].standalone_platform, il[dest].value)
+ if t is None:
+ t = LowLevelILLabel()
+ indirect = True
+ else:
+ indirect = False
+ f = LowLevelILLabel()
+ il.append(il.if_expr(cond, t, f))
+ if indirect:
+ il.mark_label(t)
+ il.append(il.jump(dest))
+ il.mark_label(f)
+ return None
+
+def jump(il, dest):
+ label = None
+ if il[dest].operation == "LLIL_CONST":
+ label = il.get_label_for_address(Architecture['6502'].standalone_platform, il[dest].value)
+ if label is None:
+ il.append(il.jump(dest))
+ else:
+ il.append(il.goto(label))
+ return None
+
+def get_p_value(il):
+ c = il.flag_bit(1, "c", 0)
+ z = il.flag_bit(1, "z", 1)
+ i = il.flag_bit(1, "i", 2)
+ d = il.flag_bit(1, "d", 3)
+ b = il.flag_bit(1, "b", 4)
+ v = il.flag_bit(1, "v", 6)
+ s = il.flag_bit(1, "s", 7)
+ return il.or_expr(1, il.or_expr(1, il.or_expr(1, il.or_expr(1, il.or_expr(1,
+ il.or_expr(1, c, z), i), d), b), v), s)
+
+def set_p_value(il, value):
+ il.append(il.set_reg(1, LLIL_TEMP(0), value))
+ il.append(il.set_flag("c", il.test_bit(1, il.reg(1, LLIL_TEMP(0)), il.const(1, 0x01))))
+ il.append(il.set_flag("z", il.test_bit(1, il.reg(1, LLIL_TEMP(0)), il.const(1, 0x02))))
+ il.append(il.set_flag("i", il.test_bit(1, il.reg(1, LLIL_TEMP(0)), il.const(1, 0x04))))
+ il.append(il.set_flag("d", il.test_bit(1, il.reg(1, LLIL_TEMP(0)), il.const(1, 0x08))))
+ il.append(il.set_flag("b", il.test_bit(1, il.reg(1, LLIL_TEMP(0)), il.const(1, 0x10))))
+ il.append(il.set_flag("v", il.test_bit(1, il.reg(1, LLIL_TEMP(0)), il.const(1, 0x40))))
+ il.append(il.set_flag("s", il.test_bit(1, il.reg(1, LLIL_TEMP(0)), il.const(1, 0x80))))
+ return None
+
+def rti(il):
+ set_p_value(il, il.pop(1))
+ return il.ret(il.pop(2))
+
+InstructionIL = {
+ "adc": lambda il, operand: il.set_reg(1, "a", il.add_carry(1, il.reg(1, "a"), operand, flags = "*")),
+ "asl": lambda il, operand: il.store(1, operand, il.shift_left(1, il.load(1, operand), il.const(1, 1), flags = "czs")),
+ "asl@": lambda il, operand: il.set_reg(1, "a", il.shift_left(1, operand, il.const(1, 1), flags = "czs")),
+ "and": lambda il, operand: il.set_reg(1, "a", il.and_expr(1, il.reg(1, "a"), operand, flags = "zs")),
+ "bcc": lambda il, operand: cond_branch(il, il.flag_condition(LLFC_UGE), operand),
+ "bcs": lambda il, operand: cond_branch(il, il.flag_condition(LLFC_ULT), operand),
+ "beq": lambda il, operand: cond_branch(il, il.flag_condition(LLFC_E), operand),
+ "bit": lambda il, operand: il.and_expr(1, il.reg(1, "a"), operand, flags = "czs"),
+ "bmi": lambda il, operand: cond_branch(il, il.flag("s"), operand),
+ "bne": lambda il, operand: cond_branch(il, il.flag_condition(LLFC_NE), operand),
+ "bpl": lambda il, operand: cond_branch(il, il.not_expr(0, il.flag("s")), operand),
+ "brk": lambda il, operand: il.system_call(),
+ "bvc": lambda il, operand: cond_branch(il, il.not_expr(0, il.flag("v")), operand),
+ "bvs": lambda il, operand: cond_branch(il, il.flag("v"), operand),
+ "clc": lambda il, operand: il.set_flag("c", il.const(0, 0)),
+ "cld": lambda il, operand: il.set_flag("d", il.const(0, 0)),
+ "cli": lambda il, operand: il.set_flag("i", il.const(0, 0)),
+ "clv": lambda il, operand: il.set_flag("v", il.const(0, 0)),
+ "cmp": lambda il, operand: il.sub(1, il.reg(1, "a"), operand, flags = "czs"),
+ "cpx": lambda il, operand: il.sub(1, il.reg(1, "x"), operand, flags = "czs"),
+ "cpy": lambda il, operand: il.sub(1, il.reg(1, "y"), operand, flags = "czs"),
+ "dec": lambda il, operand: il.store(1, operand, il.sub(1, il.load(1, operand), il.const(1, 1), flags = "zs")),
+ "dex": lambda il, operand: il.set_reg(1, "x", il.sub(1, il.reg(1, "x"), il.const(1, 1), flags = "zs")),
+ "dey": lambda il, operand: il.set_reg(1, "y", il.sub(1, il.reg(1, "y"), il.const(1, 1), flags = "zs")),
+ "eor": lambda il, operand: il.set_reg(1, "a", il.xor_expr(1, il.reg(1, "a"), operand, flags = "zs")),
+ "inc": lambda il, operand: il.store(1, operand, il.add(1, il.load(1, operand), il.const(1, 1), flags = "zs")),
+ "inx": lambda il, operand: il.set_reg(1, "x", il.add(1, il.reg(1, "x"), il.const(1, 1), flags = "zs")),
+ "iny": lambda il, operand: il.set_reg(1, "y", il.add(1, il.reg(1, "y"), il.const(1, 1), flags = "zs")),
+ "jmp": lambda il, operand: jump(il, operand),
+ "jsr": lambda il, operand: il.call(operand),
+ "lda": lambda il, operand: il.set_reg(1, "a", operand, flags = "zs"),
+ "ldx": lambda il, operand: il.set_reg(1, "x", operand, flags = "zs"),
+ "ldy": lambda il, operand: il.set_reg(1, "y", operand, flags = "zs"),
+ "lsr": lambda il, operand: il.store(1, operand, il.logical_shift_right(1, il.load(1, operand), il.const(1, 1), flags = "czs")),
+ "lsr@": lambda il, operand: il.set_reg(1, "a", il.logical_shift_right(1, il.reg(1, "a"), il.const(1, 1), flags = "czs")),
+ "nop": lambda il, operand: il.nop(),
+ "ora": lambda il, operand: il.set_reg(1, "a", il.or_expr(1, il.reg(1, "a"), operand, flags = "zs")),
+ "pha": lambda il, operand: il.push(1, il.reg(1, "a")),
+ "php": lambda il, operand: il.push(1, get_p_value(il)),
+ "pla": lambda il, operand: il.set_reg(1, "a", il.pop(1), flags = "zs"),
+ "plp": lambda il, operand: set_p_value(il, il.pop(1)),
+ "rol": lambda il, operand: il.store(1, operand, il.rotate_left_carry(1, il.load(1, operand), il.const(1, 1), flags = "czs")),
+ "rol@": lambda il, operand: il.set_reg(1, "a", il.rotate_left_carry(1, il.reg(1, "a"), il.const(1, 1), flags = "czs")),
+ "ror": lambda il, operand: il.store(1, operand, il.rotate_right_carry(1, il.load(1, operand), il.const(1, 1), flags = "czs")),
+ "ror@": lambda il, operand: il.set_reg(1, "a", il.rotate_right_carry(1, il.reg(1, "a"), il.const(1, 1), flags = "czs")),
+ "rti": lambda il, operand: rti(il),
+ "rts": lambda il, operand: il.ret(il.add(2, il.pop(2), il.const(2, 1))),
+ "sbc": lambda il, operand: il.set_reg(1, "a", il.sub_borrow(1, il.reg(1, "a"), operand, flags = "*")),
+ "sec": lambda il, operand: il.set_flag("c", il.const(0, 1)),
+ "sed": lambda il, operand: il.set_flag("d", il.const(0, 1)),
+ "sei": lambda il, operand: il.set_flag("i", il.const(0, 1)),
+ "sta": lambda il, operand: il.store(1, operand, il.reg(1, "a")),
+ "stx": lambda il, operand: il.store(1, operand, il.reg(1, "x")),
+ "sty": lambda il, operand: il.store(1, operand, il.reg(1, "y")),
+ "tax": lambda il, operand: il.set_reg(1, "x", il.reg(1, "a"), flags = "zs"),
+ "tay": lambda il, operand: il.set_reg(1, "y", il.reg(1, "a"), flags = "zs"),
+ "tsx": lambda il, operand: il.set_reg(1, "x", il.reg(1, "s"), flags = "zs"),
+ "txa": lambda il, operand: il.set_reg(1, "a", il.reg(1, "x"), flags = "zs"),
+ "txs": lambda il, operand: il.set_reg(1, "s", il.reg(1, "x")),
+ "tya": lambda il, operand: il.set_reg(1, "a", il.reg(1, "y"), flags = "zs")
+}
+
+class M6502(Architecture):
+ name = "6502"
+ address_size = 2
+ default_int_size = 1
+ regs = {
+ "a": RegisterInfo("a", 1),
+ "x": RegisterInfo("x", 1),
+ "y": RegisterInfo("y", 1),
+ "s": RegisterInfo("s", 1)
+ }
+ stack_pointer = "s"
+ flags = ["c", "z", "i", "d", "b", "v", "s"]
+ flag_write_types = ["*", "czs", "zvs", "zs"]
+
+ def decode_instruction(self, data, addr):
+ if len(data) < 1:
+ return None, None, None, None
+ opcode = ord(data[0])
+ instr = InstructionNames[opcode]
+ if instr is None:
+ return None, None, None, None
+
+ operand = InstructionOperandTypes[opcode]
+ length = 1 + OperandLengths[operand]
+ if len(data) < length:
+ return None, None, None, None
+
+ if OperandLengths[operand] == 0:
+ value = None
+ elif operand == REL:
+ value = (addr + 2 + struct.unpack("b", data[1])[0]) & 0xffff
+ elif OperandLengths[operand] == 1:
+ value = ord(data[1])
+ else:
+ value = struct.unpack("<H", data[1:3])[0]
+
+ return instr, operand, length, value
+
+ def perform_get_instruction_info(self, data, addr):
+ instr, operand, length, value = self.decode_instruction(data, addr)
+ if instr is None:
+ return None
+
+ result = InstructionInfo()
+ result.length = length
+ if instr == "jmp":
+ if operand == ADDR:
+ result.add_branch(UnconditionalBranch, struct.unpack("<H", data[1:3])[0])
+ else:
+ result.add_branch(UnresolvedBranch)
+ elif instr == "jsr":
+ result.add_branch(CallDestination, struct.unpack("<H", data[1:3])[0])
+ elif instr in ["rti", "rts"]:
+ result.add_branch(FunctionReturn)
+ if instr in ["bcc", "bcs", "beq", "bmi", "bne", "bpl", "bvc", "bvs"]:
+ dest = (addr + 2 + struct.unpack("b", data[1])[0]) & 0xffff
+ result.add_branch(TrueBranch, dest)
+ result.add_branch(FalseBranch, addr + 2)
+ return result
+
+ def perform_get_instruction_text(self, data, addr):
+ instr, operand, length, value = self.decode_instruction(data, addr)
+ if instr is None:
+ return None
+
+ tokens = []
+ tokens.append(InstructionTextToken(TextToken, "%-7s " % instr.replace("@", "")))
+ tokens += OperandTokens[operand](value)
+ return tokens, length
+
+ def perform_get_instruction_low_level_il(self, data, addr, il):
+ instr, operand, length, value = self.decode_instruction(data, addr)
+ if instr is None:
+ return None
+
+ operand = OperandIL[operand](il, value)
+ instr = InstructionIL[instr](il, operand)
+ if isinstance(instr, list):
+ for i in instr:
+ il.append(i)
+ elif instr is not None:
+ il.append(instr)
+
+ return length
+
+ def perform_is_never_branch_patch_available(self, data, addr):
+ if (data[0] == "\x10") or (data[0] == "\x30") or (data[0] == "\x50") or (data[0] == "\x70") or (data[0] == "\x90") or (data[0] == "\xb0") or (data[0] == "\xd0") or (data[0] == "\xf0"):
+ return True
+ return False
+
+ def perform_is_invert_branch_patch_available(self, data, addr):
+ if (data[0] == "\x10") or (data[0] == "\x30") or (data[0] == "\x50") or (data[0] == "\x70") or (data[0] == "\x90") or (data[0] == "\xb0") or (data[0] == "\xd0") or (data[0] == "\xf0"):
+ return True
+ return False
+
+ def perform_is_always_branch_patch_available(self, data, addr):
+ return False
+
+ def perform_is_skip_and_return_zero_patch_available(self, data, addr):
+ return (data[0] == "\x20") and (len(data) == 3)
+
+ def perform_is_skip_and_return_value_patch_available(self, data, addr):
+ return (data[0] == "\x20") and (len(data) == 3)
+
+ def perform_convert_to_nop(self, data, addr):
+ return "\xea" * len(data)
+
+ def perform_never_branch(self, data, addr):
+ if (data[0] == "\x10") or (data[0] == "\x30") or (data[0] == "\x50") or (data[0] == "\x70") or (data[0] == "\x90") or (data[0] == "\xb0") or (data[0] == "\xd0") or (data[0] == "\xf0"):
+ return "\xea" * len(data)
+ return None
+
+ def perform_invert_branch(self, data, addr):
+ if (data[0] == "\x10") or (data[0] == "\x30") or (data[0] == "\x50") or (data[0] == "\x70") or (data[0] == "\x90") or (data[0] == "\xb0") or (data[0] == "\xd0") or (data[0] == "\xf0"):
+ return chr(ord(data[0]) ^ 0x20) + data[1:]
+ return None
+
+ def perform_skip_and_return_value(self, data, addr, value):
+ if (data[0] != "\x20") or (len(data) != 3):
+ return None
+ return "\xa9" + chr(value & 0xff) + "\xea"
+
+class NESViewUpdateNotification(BinaryDataNotification):
+ def __init__(self, view):
+ self.view = view
+
+ def data_written(self, view, offset, length):
+ addr = offset - self.view.rom_offset
+ while length > 0:
+ bank_ofs = addr & 0x3fff
+ if (bank_ofs + length) > 0x4000:
+ to_read = 0x4000 - bank_ofs
+ else:
+ to_read = length
+ if length < to_read:
+ to_read = length
+ if (addr >= (bank_ofs + (self.view.__class__.bank * 0x4000))) and (addr < (bank_ofs + ((self.view.__class__.bank + 1) * 0x4000))):
+ self.view.notify_data_written(0x8000 + bank_ofs, to_read)
+ elif (addr >= (bank_ofs + (self.view.rom_length - 0x4000))) and (addr < (bank_ofs + self.view.rom_length)):
+ self.view.notify_data_written(0xc000 + bank_ofs, to_read)
+ length -= to_read
+ addr += to_read
+
+ def data_inserted(self, view, offset, length):
+ self.view.notify_data_written(0x8000, 0x8000)
+
+ def data_removed(self, view, offset, length):
+ self.view.notify_data_written(0x8000, 0x8000)
+
+class NESView(BinaryView):
+ name = "NES"
+ long_name = "NES ROM"
+
+ def __init__(self, data):
+ BinaryView.__init__(self, data.file)
+ self.data = data
+ self.notification = NESViewUpdateNotification(self)
+ self.data.register_notification(self.notification)
+
+ @classmethod
+ def is_valid_for_data(self, data):
+ hdr = data.read(0, 16)
+ if len(hdr) < 16:
+ return False
+ if hdr[0:4] != "NES\x1a":
+ return False
+ rom_banks = struct.unpack("B", hdr[4])[0]
+ if rom_banks < (self.bank + 1):
+ return False
+ return True
+
+ def init(self):
+ try:
+ hdr = self.data.read(0, 16)
+ self.rom_banks = struct.unpack("B", hdr[4])[0]
+ self.vrom_banks = struct.unpack("B", hdr[5])[0]
+ self.rom_flags = struct.unpack("B", hdr[6])[0]
+ self.mapper_index = struct.unpack("B", hdr[7])[0] | (self.rom_flags >> 4)
+ self.ram_banks = struct.unpack("B", hdr[8])[0]
+ self.rom_offset = 16
+ if self.rom_flags & 4:
+ self.rom_offset += 512
+ self.rom_length = self.rom_banks * 0x4000
+
+ nmi = struct.unpack("<H", self.read(0xfffa, 2))[0]
+ start = struct.unpack("<H", self.read(0xfffc, 2))[0]
+ irq = struct.unpack("<H", self.read(0xfffe, 2))[0]
+ self.define_auto_symbol(Symbol(FunctionSymbol, nmi, "_nmi"))
+ self.define_auto_symbol(Symbol(FunctionSymbol, start, "_start"))
+ self.define_auto_symbol(Symbol(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)
+
+ # Hardware registers
+ self.define_auto_symbol(Symbol(DataSymbol, 0x2000, "PPUCTRL"))
+ self.define_auto_symbol(Symbol(DataSymbol, 0x2001, "PPUMASK"))
+ self.define_auto_symbol(Symbol(DataSymbol, 0x2002, "PPUSTATUS"))
+ self.define_auto_symbol(Symbol(DataSymbol, 0x2003, "OAMADDR"))
+ self.define_auto_symbol(Symbol(DataSymbol, 0x2004, "OAMDATA"))
+ self.define_auto_symbol(Symbol(DataSymbol, 0x2005, "PPUSCROLL"))
+ self.define_auto_symbol(Symbol(DataSymbol, 0x2006, "PPUADDR"))
+ self.define_auto_symbol(Symbol(DataSymbol, 0x2007, "PPUDATA"))
+ self.define_auto_symbol(Symbol(DataSymbol, 0x4000, "SQ1_VOL"))
+ self.define_auto_symbol(Symbol(DataSymbol, 0x4001, "SQ1_SWEEP"))
+ self.define_auto_symbol(Symbol(DataSymbol, 0x4002, "SQ1_LO"))
+ self.define_auto_symbol(Symbol(DataSymbol, 0x4003, "SQ1_HI"))
+ self.define_auto_symbol(Symbol(DataSymbol, 0x4004, "SQ2_VOL"))
+ self.define_auto_symbol(Symbol(DataSymbol, 0x4005, "SQ2_SWEEP"))
+ self.define_auto_symbol(Symbol(DataSymbol, 0x4006, "SQ2_LO"))
+ self.define_auto_symbol(Symbol(DataSymbol, 0x4007, "SQ2_HI"))
+ self.define_auto_symbol(Symbol(DataSymbol, 0x4008, "TRI_LINEAR"))
+ self.define_auto_symbol(Symbol(DataSymbol, 0x400a, "TRI_LO"))
+ self.define_auto_symbol(Symbol(DataSymbol, 0x400b, "TRI_HI"))
+ self.define_auto_symbol(Symbol(DataSymbol, 0x400c, "NOISE_VOL"))
+ self.define_auto_symbol(Symbol(DataSymbol, 0x400e, "NOISE_LO"))
+ self.define_auto_symbol(Symbol(DataSymbol, 0x400f, "NOISE_HI"))
+ self.define_auto_symbol(Symbol(DataSymbol, 0x4010, "DMC_FREQ"))
+ self.define_auto_symbol(Symbol(DataSymbol, 0x4011, "DMC_RAW"))
+ self.define_auto_symbol(Symbol(DataSymbol, 0x4012, "DMC_START"))
+ self.define_auto_symbol(Symbol(DataSymbol, 0x4013, "DMC_LEN"))
+ self.define_auto_symbol(Symbol(DataSymbol, 0x4014, "OAMDMA"))
+ self.define_auto_symbol(Symbol(DataSymbol, 0x4015, "SND_CHN"))
+ self.define_auto_symbol(Symbol(DataSymbol, 0x4016, "JOY1"))
+ self.define_auto_symbol(Symbol(DataSymbol, 0x4017, "JOY2"))
+
+ sym_files = [self.data.file.filename + ".%x.nl" % self.__class__.bank,
+ self.data.file.filename + ".ram.nl",
+ self.data.file.filename + ".%x.nl" % (self.rom_banks - 1)]
+ for f in sym_files:
+ if os.path.exists(f):
+ sym_contents = open(f, "r").read()
+ lines = sym_contents.split('\n')
+ for line in lines:
+ sym = line.split('#')
+ if len(sym) < 3:
+ break
+ addr = int(sym[0][1:], 16)
+ name = sym[1]
+ self.define_auto_symbol(Symbol(FunctionSymbol, addr, name))
+ if addr >= 0x8000:
+ self.add_function(Architecture['6502'].standalone_platform, addr)
+
+ return True
+ except:
+ log_error(traceback.format_exc())
+ return False
+
+ def perform_is_valid_offset(self, addr):
+ if (addr >= 0x8000) and (addr < 0x10000):
+ return True
+ return False
+
+ def perform_read(self, addr, length):
+ if addr < 0x8000:
+ return None
+ if addr >= (0x8000 + self.rom_length):
+ return None
+ if (addr + length) > 0x10000:
+ length = 0x10000 - addr
+ result = ""
+ while length > 0:
+ bank_ofs = addr & 0x3fff
+ if (bank_ofs + length) > 0x4000:
+ to_read = 0x4000 - bank_ofs
+ else:
+ to_read = length
+ if addr < 0xc000:
+ data = self.data.read(self.rom_offset + bank_ofs + (self.__class__.bank * 0x4000), to_read)
+ else:
+ data = self.data.read(self.rom_offset + bank_ofs + self.rom_length - 0x4000, to_read)
+ result += data
+ if len(data) < to_read:
+ break
+ length -= to_read
+ addr += to_read
+ return result
+
+ def perform_write(self, addr, value):
+ if addr < 0x8000:
+ return 0
+ if addr >= (0x8000 + self.rom_length):
+ return 0
+ if (addr + len(value)) > (0x8000 + self.rom_length):
+ length = (0x8000 + self.rom_length) - addr
+ else:
+ length = len(value)
+ if (addr + length) > 0x10000:
+ length = 0x10000 - addr
+ offset = 0
+ while length > 0:
+ bank_ofs = addr & 0x3fff
+ if (bank_ofs + length) > 0x4000:
+ to_write = 0x4000 - bank_ofs
+ else:
+ to_write = length
+ if addr < 0xc000:
+ written = self.data.write(self.rom_offset + bank_ofs + (self.__class__.bank * 0x4000), value[offset : offset + to_write])
+ else:
+ written = self.data.write(self.rom_offset + bank_ofs + self.rom_length - 0x4000, value[offset : offset + to_write])
+ if written < to_write:
+ break
+ length -= to_write
+ addr += to_write
+ offset += to_write
+ return offset
+
+ def perform_get_start(self):
+ return 0
+
+ def perform_get_length(self):
+ return 0x10000
+
+ def perform_is_executable(self):
+ return True
+
+ def perform_get_entry_point(self):
+ return struct.unpack("<H", str(self.perform_read(0xfffc, 2)))[0]
+
+banks = []
+for i in xrange(0, 32):
+ class NESViewBank(NESView):
+ bank = i
+ name = "NES Bank %X" % i
+ long_name = "NES ROM (bank %X)" % i
+
+ def __init__(self, data):
+ NESView.__init__(self, data)
+
+ banks.append(NESViewBank)
+ NESViewBank.register()
+
+M6502.register()
+
diff --git a/python/generator.cpp b/python/generator.cpp
new file mode 100644
index 00000000..bd9242d8
--- /dev/null
+++ b/python/generator.cpp
@@ -0,0 +1,302 @@
+#include <stdio.h>
+#include <inttypes.h>
+#include "binaryninjaapi.h"
+
+using namespace BinaryNinja;
+using namespace std;
+
+
+class GeneratorArchitecture: public Architecture
+{
+public:
+ GeneratorArchitecture(): Architecture("generator")
+ {
+ }
+
+ virtual bool GetInstructionInfo(const uint8_t*, uint64_t, size_t, InstructionInfo&) override
+ {
+ return false;
+ }
+
+ virtual bool GetInstructionText(const uint8_t*, uint64_t, size_t&, vector<InstructionTextToken>&) override
+ {
+ return false;
+ }
+
+ virtual BNEndianness GetEndianness() const override
+ {
+ return LittleEndian;
+ }
+
+ virtual size_t GetAddressSize() const override
+ {
+ return 8;
+ }
+};
+
+
+void OutputType(FILE* out, Type* type, bool isReturnType = false, bool isCallback = false)
+{
+ switch (type->GetClass())
+ {
+ case BoolTypeClass:
+ fprintf(out, "ctypes.c_bool");
+ break;
+ case IntegerTypeClass:
+ switch (type->GetWidth())
+ {
+ case 1:
+ if (type->IsSigned())
+ fprintf(out, "ctypes.c_byte");
+ else
+ fprintf(out, "ctypes.c_ubyte");
+ break;
+ case 2:
+ if (type->IsSigned())
+ fprintf(out, "ctypes.c_short");
+ else
+ fprintf(out, "ctypes.c_ushort");
+ break;
+ case 4:
+ if (type->IsSigned())
+ fprintf(out, "ctypes.c_int");
+ else
+ fprintf(out, "ctypes.c_uint");
+ break;
+ default:
+ if (type->IsSigned())
+ fprintf(out, "ctypes.c_longlong");
+ else
+ fprintf(out, "ctypes.c_ulonglong");
+ break;
+ }
+ break;
+ case FloatTypeClass:
+ if (type->GetWidth() == 4)
+ fprintf(out, "ctypes.c_float");
+ else
+ fprintf(out, "ctypes.c_double");
+ break;
+ case StructureTypeClass:
+ fprintf(out, "%s", type->GetStructure()->GetName().c_str());
+ break;
+ case EnumerationTypeClass:
+ fprintf(out, "%s", type->GetEnumeration()->GetName().c_str());
+ break;
+ case PointerTypeClass:
+ if (isCallback || (type->GetChildType()->GetClass() == VoidTypeClass))
+ {
+ fprintf(out, "ctypes.c_void_p");
+ break;
+ }
+ else if ((type->GetChildType()->GetClass() == IntegerTypeClass) &&
+ (type->GetChildType()->GetWidth() == 1) && (type->GetChildType()->IsSigned()))
+ {
+ if (isReturnType)
+ fprintf(out, "ctypes.POINTER(ctypes.c_byte)");
+ else
+ fprintf(out, "ctypes.c_char_p");
+ break;
+ }
+ else if (type->GetChildType()->GetClass() == FunctionTypeClass)
+ {
+ fprintf(out, "ctypes.CFUNCTYPE(");
+ OutputType(out, type->GetChildType()->GetChildType(), true, true);
+ for (auto& i : type->GetChildType()->GetParameters())
+ {
+ fprintf(out, ", ");
+ OutputType(out, i.type);
+ }
+ fprintf(out, ")");
+ break;
+ }
+ fprintf(out, "ctypes.POINTER(");
+ OutputType(out, type->GetChildType());
+ fprintf(out, ")");
+ break;
+ case ArrayTypeClass:
+ OutputType(out, type->GetChildType());
+ fprintf(out, " * %" PRId64, type->GetElementCount());
+ break;
+ default:
+ fprintf(out, "None");
+ break;
+ }
+}
+
+
+int main(int argc, char* argv[])
+{
+ if (argc < 3)
+ {
+ fprintf(stderr, "Usage: generator <header> <output>\n");
+ return 1;
+ }
+
+ Architecture::Register(new GeneratorArchitecture());
+
+ // Parse API header to get type and function information
+ map<string, Ref<Type>> types, vars, funcs;
+ string errors;
+ bool ok = Architecture::GetByName("generator")->ParseTypesFromSourceFile(argv[1], types, vars, funcs, errors);
+ fprintf(stderr, "%s", errors.c_str());
+ if (!ok)
+ return 1;
+
+ FILE* out = fopen(argv[2], "w");
+
+ fprintf(out, "import ctypes, os\n\n");
+
+ 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
+
+ // Create type objects
+ fprintf(out, "# Type definitions\n");
+ map<string, int64_t> enumMembers;
+ for (auto& i : types)
+ {
+ if (i.second->GetClass() == StructureTypeClass)
+ {
+ fprintf(out, "class %s(ctypes.Structure):\n", i.first.c_str());
+ fprintf(out, " pass\n");
+ }
+ else if (i.second->GetClass() == EnumerationTypeClass)
+ {
+ fprintf(out, "%s = ctypes.c_int\n", i.first.c_str());
+ for (auto& j : i.second->GetEnumeration()->GetMembers())
+ fprintf(out, "%s = %" PRId64 "\n", j.name.c_str(), j.value);
+ fprintf(out, "%s_names = {\n", i.first.c_str());
+ for (auto& j : i.second->GetEnumeration()->GetMembers())
+ fprintf(out, " %" PRId64 ": \"%s\",\n", j.value, j.name.c_str());
+ fprintf(out, "}\n");
+ fprintf(out, "%s_by_name = {\n", i.first.c_str());
+ for (auto& j : i.second->GetEnumeration()->GetMembers())
+ fprintf(out, " \"%s\": %" PRId64 ",\n", j.name.c_str(), j.value);
+ fprintf(out, "}\n");
+ for (auto& j : i.second->GetEnumeration()->GetMembers())
+ enumMembers[j.name] = j.value;
+ }
+ else if ((i.second->GetClass() == BoolTypeClass) || (i.second->GetClass() == IntegerTypeClass) ||
+ (i.second->GetClass() == FloatTypeClass) || (i.second->GetClass() == ArrayTypeClass))
+ {
+ fprintf(out, "%s = ", i.first.c_str());
+ OutputType(out, i.second);
+ fprintf(out, "\n");
+ }
+ }
+
+ fprintf(out, "all_enum_values = {\n");
+ for (auto& i : enumMembers)
+ fprintf(out, " \"%s\": %" PRId64 ",\n", i.first.c_str(), i.second);
+ fprintf(out, "}\n");
+
+ fprintf(out, "\n# Structure definitions\n");
+ for (auto& i : types)
+ {
+ if ((i.second->GetClass() == StructureTypeClass) && (i.second->GetStructure()->GetMembers().size() != 0))
+ {
+ fprintf(out, "%s._fields_ = [\n", i.first.c_str());
+ for (auto& j : i.second->GetStructure()->GetMembers())
+ {
+ fprintf(out, " (\"%s\", ", j.name.c_str());
+ OutputType(out, j.type);
+ fprintf(out, "),\n");
+ }
+ fprintf(out, " ]\n");
+ }
+ }
+
+ fprintf(out, "\n# Function definitions\n");
+ for (auto& i : funcs)
+ {
+ // Check for a string result, these will be automatically wrapped to free the string
+ // memory and return a Python string
+ bool stringResult = (i.second->GetChildType()->GetClass() == PointerTypeClass) &&
+ (i.second->GetChildType()->GetChildType()->GetWidth() == 1) &&
+ (i.second->GetChildType()->GetChildType()->IsSigned());
+ // Pointer returns will be automatically wrapped to return None on null pointer
+ bool pointerResult = (i.second->GetChildType()->GetClass() == PointerTypeClass);
+ bool callbackConvention = false;
+ if (i.first == "BNAllocString")
+ {
+ // Don't perform automatic wrapping of string allocation, and return a void
+ // pointer so that callback functions (which is the only valid use of BNAllocString)
+ // can properly return the result
+ stringResult = false;
+ callbackConvention = true;
+ }
+
+ string funcName = i.first;
+ if (stringResult || pointerResult)
+ funcName = string("_") + funcName;
+
+ fprintf(out, "%s = core.%s\n", funcName.c_str(), i.first.c_str());
+ fprintf(out, "%s.restype = ", funcName.c_str());
+ OutputType(out, i.second->GetChildType(), true, callbackConvention);
+ fprintf(out, "\n");
+ if (!i.second->HasVariableArguments())
+ {
+ fprintf(out, "%s.argtypes = [\n", funcName.c_str());
+ for (auto& j : i.second->GetParameters())
+ {
+ fprintf(out, " ");
+ if (i.first == "BNFreeString")
+ {
+ // BNFreeString expects a pointer to a string allocated by the core, so do not use
+ // a c_char_p here, as that would be allocated by the Python runtime. This can
+ // be enforced by outputting like a return value.
+ OutputType(out, j.type, true);
+ }
+ else
+ {
+ OutputType(out, j.type);
+ }
+ fprintf(out, ",\n");
+ }
+ fprintf(out, " ]\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");
+ }
+ 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, "\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, "\n# Set path for core plugins\n");
+ fprintf(out, "BNSetBundledPluginDirectory(os.path.join(_base_path, \"plugins\"))\n");
+
+ fclose(out);
+ return 0;
+}