summaryrefslogtreecommitdiff
path: root/python
diff options
context:
space:
mode:
authorRusty Wagner <rusty@vector35.com>2016-09-19 22:26:56 -0400
committerRusty Wagner <rusty@vector35.com>2016-09-19 22:27:49 -0400
commit1364a9bc7b3887441540cd27685c1addb028afb3 (patch)
tree619a46a156811837165126d3ccf6f20707a74b71 /python
parentf91afbf10a7d51b8166c16a371e1ba2a7de890b9 (diff)
Adding APIs to store arbitrary data on a per-view, per-file, or per-function basis
Diffstat (limited to 'python')
-rw-r--r--python/__init__.py121
1 files changed, 121 insertions, 0 deletions
diff --git a/python/__init__.py b/python/__init__.py
index 854de5c7..23059068 100644
--- a/python/__init__.py
+++ b/python/__init__.py
@@ -27,6 +27,7 @@ import struct
import threading
import code
import sys
+import copy
_plugin_init = False
def _init_plugins():
@@ -181,7 +182,35 @@ class NavigationHandler(object):
log_error(traceback.format_exc())
return False
+class _AssociatedDataStore(dict):
+ _defaults = {}
+
+ @classmethod
+ def set_default(cls, name, value):
+ cls._defaults[name] = value
+
+ def __getattr__(self, name):
+ if name in self.__dict__:
+ return self.__dict__[name]
+ if name not in self:
+ if name in self.__class__._defaults:
+ result = copy.copy(self.__class__._defaults[name])
+ self[name] = result
+ return result
+ return self.__getitem__(name)
+
+ def __setattr__(self, name, value):
+ self.__setitem__(name, value)
+
+ def __delattr__(self, name):
+ self.__delitem__(name)
+
+class _FileMetadataAssociatedDataStore(_AssociatedDataStore):
+ _defaults = {}
+
class FileMetadata(object):
+ _associated_data = {}
+
"""
``class FileMetadata`` represents the file being analyzed by Binary Ninja. It is responsible for opening,
closing, creating the database (.bndb) files, and is used to keep track of undoable actions.
@@ -207,6 +236,16 @@ class FileMetadata(object):
core.BNSetFileMetadataNavigationHandler(self.handle, None)
core.BNFreeFileMetadata(self.handle)
+ @classmethod
+ def _unregister(cls, f):
+ handle = ctypes.cast(f, ctypes.c_void_p)
+ if handle.value in cls._associated_data:
+ del cls._associated_data[handle.value]
+
+ @classmethod
+ def set_default_data(cls, name, value):
+ _FileMetadataAssociatedDataStore.set_default(name, value)
+
@property
def filename(self):
"""The name of the file (read/write)"""
@@ -284,6 +323,17 @@ class FileMetadata(object):
value._register(self.handle)
self.nav = value
+ @property
+ def data(self):
+ """Dictionary object where plugins can store arbitrary data associated with the file"""
+ handle = ctypes.cast(self.handle, ctypes.c_void_p)
+ if handle.value not in FileMetadata._associated_data:
+ obj = _FileMetadataAssociatedDataStore()
+ FileMetadata._associated_data[handle.value] = obj
+ return obj
+ else:
+ return FileMetadata._associated_data[handle.value]
+
def close(self):
"""
Closes the underlying file handle. It is recommended that this is done in a
@@ -874,6 +924,9 @@ class DataVariable(object):
def __repr__(self):
return "<var 0x%x: %s>" % (self.address, str(self.type))
+class _BinaryViewAssociatedDataStore(_AssociatedDataStore):
+ _defaults = {}
+
class BinaryView(object):
"""
``class BinaryView`` implements a view on binary data, and presents a queryable interface of a binary file. One key
@@ -927,6 +980,7 @@ class BinaryView(object):
_registered_cb = None
registered_view_type = None
next_address = 0
+ _associated_data = {}
def __init__(self, file_metadata = None, handle = None):
if handle is not None:
@@ -1035,6 +1089,16 @@ class BinaryView(object):
result = BinaryView(file_metadata, handle = view)
return result
+ @classmethod
+ def _unregister(cls, view):
+ handle = ctypes.cast(view, ctypes.c_void_p)
+ if handle.value in cls._associated_data:
+ del cls._associated_data[handle.value]
+
+ @classmethod
+ def set_default_data(cls, name, value):
+ _BinaryViewAssociatedDataStore.set_default(name, value)
+
def __del__(self):
for i in self.notifications.values():
i._unregister()
@@ -1246,6 +1310,17 @@ class BinaryView(object):
core.BNFreeTypeList(type_list, count.value)
return result
+ @property
+ def data(self):
+ """Dictionary object where plugins can store arbitrary data associated with the view"""
+ handle = ctypes.cast(self.handle, ctypes.c_void_p)
+ if handle.value not in BinaryView._associated_data:
+ obj = _BinaryViewAssociatedDataStore()
+ BinaryView._associated_data[handle.value] = obj
+ return obj
+ else:
+ return BinaryView._associated_data[handle.value]
+
def __len__(self):
return int(core.BNGetViewLength(self.handle))
@@ -4485,7 +4560,12 @@ class HighlightColor(object):
return result
+class _FunctionAssociatedDataStore(_AssociatedDataStore):
+ _defaults = {}
+
class Function(object):
+ _associated_data = {}
+
def __init__(self, view, handle):
self._view = view
self.handle = core.handle_of_type(handle, core.BNFunction)
@@ -4496,6 +4576,16 @@ class Function(object):
core.BNReleaseAdvancedFunctionAnalysisDataMultiple(self.handle, self._advanced_analysis_requests)
core.BNFreeFunction(self.handle)
+ @classmethod
+ def _unregister(cls, func):
+ handle = ctypes.cast(func, ctypes.c_void_p)
+ if handle.value in cls._associated_data:
+ del cls._associated_data[handle.value]
+
+ @classmethod
+ def set_default_data(cls, name, value):
+ _FunctionAssociatedDataStore.set_default(name, value)
+
@property
def name(self):
"""Symbol name for the function"""
@@ -4620,6 +4710,17 @@ class Function(object):
core.BNFreeIndirectBranchList(branches)
return result
+ @property
+ def data(self):
+ """Dictionary object where plugins can store arbitrary data associated with the function"""
+ handle = ctypes.cast(self.handle, ctypes.c_void_p)
+ if handle.value not in Function._associated_data:
+ obj = _FunctionAssociatedDataStore()
+ Function._associated_data[handle.value] = obj
+ return obj
+ else:
+ return Function._associated_data[handle.value]
+
def __iter__(self):
count = ctypes.c_ulonglong()
blocks = core.BNGetFunctionBasicBlockList(self.handle, count)
@@ -10242,6 +10343,26 @@ class InteractionHandler(object):
def get_directory_name_input(self, prompt, default_name):
return get_text_line_input(title, "Select Directory")
+class _DestructionCallbackHandler:
+ def __init__(self):
+ self._cb = core.BNObjectDestructionCallbacks()
+ self._cb.context = 0
+ self._cb.destructBinaryView = self._cb.destructBinaryView.__class__(self.destruct_binary_view)
+ self._cb.destructFileMetadata = self._cb.destructFileMetadata.__class__(self.destruct_file_metadata)
+ self._cb.destructFunction = self._cb.destructFunction.__class__(self.destruct_function)
+ core.BNRegisterObjectDestructionCallbacks(self._cb)
+
+ def destruct_binary_view(self, ctxt, view):
+ BinaryView._unregister(view)
+
+ def destruct_file_metadata(self, ctxt, f):
+ FileMetadata._unregister(f)
+
+ def destruct_function(self, ctxt, func):
+ Function._unregister(func)
+
+_destruct_callbacks = _DestructionCallbackHandler()
+
def LLIL_TEMP(n):
return n | 0x80000000