summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--binaryninjaapi.h10
-rw-r--r--binaryninjacore.h16
-rw-r--r--binaryviewtype.cpp25
-rw-r--r--python/binaryview.py46
-rw-r--r--suite/testcommon.py36
5 files changed, 132 insertions, 1 deletions
diff --git a/binaryninjaapi.h b/binaryninjaapi.h
index fb5e77fc..6f39b8d5 100644
--- a/binaryninjaapi.h
+++ b/binaryninjaapi.h
@@ -1803,6 +1803,11 @@ __attribute__ ((format (printf, 1, 2)))
class BinaryViewType: public StaticCoreRefCountObject<BNBinaryViewType>
{
+ struct BinaryViewEvent
+ {
+ std::function<void(BinaryView*)> action;
+ };
+
protected:
std::string m_nameForRegister, m_longNameForRegister;
@@ -1841,6 +1846,11 @@ __attribute__ ((format (printf, 1, 2)))
virtual BinaryView* Parse(BinaryView* data) = 0;
virtual bool IsTypeValidForData(BinaryView* data) = 0;
virtual Ref<Settings> GetLoadSettingsForData(BinaryView* data) = 0;
+
+ static void RegisterBinaryViewFinalizationEvent(const std::function<void(BinaryView* view)>& callback);
+ static void RegisterBinaryViewInitialAnalysisCompletionEvent(const std::function<void(BinaryView* view)>& callback);
+
+ static void BinaryViewEventCallback(void* ctxt, BNBinaryView* view);
};
class CoreBinaryViewType: public BinaryViewType
diff --git a/binaryninjacore.h b/binaryninjacore.h
index e878ccb5..6bdc68f4 100644
--- a/binaryninjacore.h
+++ b/binaryninjacore.h
@@ -2422,6 +2422,19 @@ extern "C"
uint64_t start, end;
};
+ enum BNBinaryViewEventType
+ {
+ BinaryViewFinalizationEvent,
+ BinaryViewInitialAnalysisCompletionEvent
+ };
+
+ struct BNBinaryViewEvent
+ {
+ BNBinaryViewEventType type;
+ void (*callback)(void* ctx, BNBinaryView* view);
+ void* ctx;
+ };
+
BINARYNINJACOREAPI char* BNAllocString(const char* contents);
BINARYNINJACOREAPI void BNFreeString(char* str);
BINARYNINJACOREAPI char** BNAllocStringList(const char** contents, size_t size);
@@ -2790,6 +2803,9 @@ __attribute__ ((format (printf, 1, 2)))
BNPlatform* platform);
BINARYNINJACOREAPI BNPlatform* BNGetPlatformForViewType(BNBinaryViewType* type, uint32_t id, BNArchitecture* arch);
+ BINARYNINJACOREAPI void BNRegisterBinaryViewEvent(BNBinaryViewEventType type,
+ void (*callback)(void* ctx, BNBinaryView* view), void* ctx);
+
// Stream reader object
BINARYNINJACOREAPI BNBinaryReader* BNCreateBinaryReader(BNBinaryView* view);
BINARYNINJACOREAPI void BNFreeBinaryReader(BNBinaryReader* stream);
diff --git a/binaryviewtype.cpp b/binaryviewtype.cpp
index 8b0f8007..6691b820 100644
--- a/binaryviewtype.cpp
+++ b/binaryviewtype.cpp
@@ -219,6 +219,31 @@ bool BinaryViewType::IsDeprecated()
return BNIsBinaryViewTypeDeprecated(m_object);
}
+
+void BinaryViewType::RegisterBinaryViewFinalizationEvent(const function<void(BinaryView* view)>& callback)
+{
+ BinaryViewEvent* event = new BinaryViewEvent;
+ event->action = callback;
+ BNRegisterBinaryViewEvent(BinaryViewFinalizationEvent, BinaryViewEventCallback, event);
+}
+
+
+void BinaryViewType::RegisterBinaryViewInitialAnalysisCompletionEvent(const function<void(BinaryView* view)>& callback)
+{
+ BinaryViewEvent* event = new BinaryViewEvent;
+ event->action = callback;
+ BNRegisterBinaryViewEvent(BinaryViewInitialAnalysisCompletionEvent, BinaryViewEventCallback, event);
+}
+
+
+void BinaryViewType::BinaryViewEventCallback(void* ctxt, BNBinaryView* view)
+{
+ BinaryViewEvent* event = (BinaryViewEvent*)ctxt;
+ Ref<BinaryView> viewObject = new BinaryView(BNNewViewReference(view));
+ event->action(viewObject);
+}
+
+
CoreBinaryViewType::CoreBinaryViewType(BNBinaryViewType* type): BinaryViewType(type)
{
}
diff --git a/python/binaryview.py b/python/binaryview.py
index 16127873..545fcc15 100644
--- a/python/binaryview.py
+++ b/python/binaryview.py
@@ -32,7 +32,8 @@ from collections import OrderedDict
# Binary Ninja components
from binaryninja import _binaryninjacore as core
from binaryninja.enums import (AnalysisState, SymbolType, InstructionTextTokenType,
- Endianness, ModificationStatus, StringType, SegmentFlag, SectionSemantics, FindFlag, TypeClass, SaveOption)
+ Endianness, ModificationStatus, StringType, SegmentFlag, SectionSemantics, FindFlag,
+ TypeClass, SaveOption, BinaryViewEventType)
import binaryninja
from binaryninja import associateddatastore # required for _BinaryViewAssociatedDataStore
from binaryninja import log
@@ -252,7 +253,42 @@ class AnalysisCompletionEvent(object):
def view(self, value):
self._view = value
+# This has no functional purposes;
+# we just need it to stop Python from prematurely freeing the object
+_binaryview_events = {}
+class BinaryViewEvent(object):
+ """
+ The ``BinaryViewEvent`` object provides a mechanism for receiving callbacks when a BinaryView
+ is Finalized or the initial analysis is finished. The BinaryView finalized callbacks run before the
+ intialanalysis starts. The callbacks run one-after-another in the same order as they get registered.
+ It is a good place to modify the BinaryView to add extra information to it.
+
+ The callback function receives a BinaryView as its parameter. It is possible to call
+ BinaryView.add_analysis_completion_event() on it to set up other callbacks for analysis completion.
+
+ :Example:
+ >>> def callback(bv):
+ ... print('start: 0x%x' % bv.start)
+ ...
+ >>> BinaryViewEvent.add_binaryview_finalized_event(callback)
+ """
+ @classmethod
+ def register(cls, event_type, callback):
+ callback_obj = ctypes.CFUNCTYPE(None, ctypes.c_void_p, ctypes.POINTER(core.BNBinaryView))(lambda ctxt, view: cls._notify(view, callback))
+ core.BNRegisterBinaryViewEvent(event_type, callback_obj, None)
+ global _binaryview_events
+ _binaryview_events[len(_binaryview_events)] = callback_obj
+ @classmethod
+ def _notify(cls, view, callback):
+ try:
+ file_metadata = binaryninja.filemetadata.FileMetadata(handle = core.BNGetFileForView(view))
+ view_obj = binaryninja.binaryview.BinaryView(file_metadata = file_metadata, handle = core.BNNewViewReference(view))
+ callback(view_obj)
+ except:
+ binaryninja.log.log_error(traceback.format_exc())
+
+
class ActiveAnalysisInfo(object):
def __init__(self, func, analysis_time, update_count, submit_count):
self._func = func
@@ -932,6 +968,14 @@ class BinaryViewType(with_metaclass(_BinaryViewTypeMetaclass, object)):
return None
return binaryninja.platform.Platform(handle = plat)
+ @staticmethod
+ def add_binaryview_finalized_event(callback):
+ BinaryViewEvent.register(BinaryViewEventType.BinaryViewFinalizationEvent, callback)
+
+ @staticmethod
+ def add_binaryview_initial_analysis_completion_event(callback):
+ BinaryViewEvent.register(BinaryViewEventType.BinaryViewInitialAnalysisCompletionEvent, callback)
+
class Segment(object):
def __init__(self, handle):
diff --git a/suite/testcommon.py b/suite/testcommon.py
index 34316a53..992a7961 100644
--- a/suite/testcommon.py
+++ b/suite/testcommon.py
@@ -1505,3 +1505,39 @@ class VerifyBuilder(Builder):
assert(test_helper(binja.PossibleValueSet.in_set_of_values([1,2,3,4])))
assert(test_helper(binja.PossibleValueSet.not_in_set_of_values([1,2,3,4])))
return True
+
+ def test_binaryview_callbacks(self):
+ """BinaryView finalized callback and analysis completion callback"""
+ file_name = self.unpackage_file("helloworld")
+
+ # Currently, there is no way to unregister a BinaryView event callback.
+ # This boolean tells the callback function whether it should run or just return
+ callback_should_run = True
+
+ def bv_finalized_callback(bv):
+ if callback_should_run:
+ bv.store_metadata('finalized', 'yes')
+
+ def bv_finalized_callback_2(bv):
+ if callback_should_run:
+ bv.store_metadata('finalized_2', 'yes')
+
+ def bv_analysis_completion_callback(bv):
+ if callback_should_run:
+ bv.store_metadata('analysis_completion', 'yes')
+
+ BinaryViewType.add_binaryview_finalized_event(bv_finalized_callback)
+ BinaryViewType.add_binaryview_finalized_event(bv_finalized_callback_2)
+ BinaryViewType.add_binaryview_initial_analysis_completion_event(bv_analysis_completion_callback)
+
+ try:
+ with binja.open_view(file_name) as bv:
+ finalized = bv.query_metadata('finalized') == 'yes'
+ finalized_2 = bv.query_metadata('finalized_2') == 'yes'
+ analysis_completion = bv.query_metadata('analysis_completion') == 'yes'
+ return finalized and finalized_2 and analysis_completion
+
+ finally:
+ self.delete_package("helloworld")
+ callback_should_run = False
+