summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRyan Snyder <ryan@vector35.com>2021-08-04 11:17:40 -0400
committerRyan Snyder <ryan@vector35.com>2021-08-20 04:34:14 -0400
commitcc1e85a4a8b2001f9fd6cf91b93fb39abef3a0e2 (patch)
tree45fdf52d2bdb8e09f57fc76079a3a91b6528f4a1
parentc1e526ea39d97c4c374de4cf8c211dc39ebbb538 (diff)
platforms: specify platform types and add bvt platform callbacks
-rw-r--r--binaryninjaapi.h10
-rw-r--r--binaryninjacore.h45
-rw-r--r--binaryviewtype.cpp29
-rw-r--r--platform.cpp10
-rw-r--r--python/binaryview.py29
-rw-r--r--python/platform.py10
6 files changed, 126 insertions, 7 deletions
diff --git a/binaryninjaapi.h b/binaryninjaapi.h
index c2529942..59e920aa 100644
--- a/binaryninjaapi.h
+++ b/binaryninjaapi.h
@@ -2052,6 +2052,11 @@ __attribute__ ((format (printf, 1, 2)))
std::function<void(BinaryView*)> action;
};
+ struct PlatformRecognizerFunction
+ {
+ std::function<Ref<Platform>(BinaryView*, Metadata*)> action;
+ };
+
protected:
std::string m_nameForRegister, m_longNameForRegister;
@@ -2081,6 +2086,9 @@ __attribute__ ((format (printf, 1, 2)))
void RegisterDefaultPlatform(Architecture* arch, Platform* platform);
Ref<Platform> GetPlatform(uint32_t id, Architecture* arch);
+ void RegisterPlatformRecognizer(uint64_t id, BNEndianness endian, const std::function<Ref<Platform>(BinaryView* view, Metadata*)>& callback);
+ Ref<Platform> RecognizePlatform(uint64_t id, BNEndianness endian, BinaryView* view, Metadata* metadata);
+
std::string GetName();
std::string GetLongName();
@@ -2095,6 +2103,7 @@ __attribute__ ((format (printf, 1, 2)))
static void RegisterBinaryViewInitialAnalysisCompletionEvent(const std::function<void(BinaryView* view)>& callback);
static void BinaryViewEventCallback(void* ctxt, BNBinaryView* view);
+ static BNPlatform* PlatformRecognizerCallback(void* ctxt, BNBinaryView* view, BNMetadata* metadata);
};
class CoreBinaryViewType: public BinaryViewType
@@ -5133,6 +5142,7 @@ __attribute__ ((format (printf, 1, 2)))
{
protected:
Platform(Architecture* arch, const std::string& name);
+ Platform(Architecture* arch, const std::string& name, const std::string& typeFile, const std::vector<std::string>& includeDirs = std::vector<std::string>());
public:
Platform(BNPlatform* platform);
diff --git a/binaryninjacore.h b/binaryninjacore.h
index 08f2f483..6eb5dfae 100644
--- a/binaryninjacore.h
+++ b/binaryninjacore.h
@@ -3109,15 +3109,48 @@ __attribute__ ((format (printf, 1, 2)))
BNCustomBinaryViewType* type);
BINARYNINJACOREAPI void BNRegisterArchitectureForViewType(BNBinaryViewType* type, uint32_t id,
- BNEndianness endian, BNArchitecture* arch);
+ BNEndianness endian, BNArchitecture* arch); // Deprecated, use BNRegisterPlatformRecognizerForViewType
BINARYNINJACOREAPI BNArchitecture* BNGetArchitectureForViewType(BNBinaryViewType* type, uint32_t id,
- BNEndianness endian);
+ BNEndianness endian); // Deprecated, use BNRecognizePlatformForViewType
+
+ BINARYNINJACOREAPI void BNRegisterPlatformForViewType(BNBinaryViewType* type, uint32_t id,
+ BNArchitecture* arch, BNPlatform* platform); // Deprecated, use BNRegisterPlatformRecognizerForViewType
+ BINARYNINJACOREAPI BNPlatform* BNGetPlatformForViewType(BNBinaryViewType* type,
+ uint32_t id, BNArchitecture* arch); // Deprecated, use BNRecognizePlatformForViewType
- BINARYNINJACOREAPI void BNRegisterPlatformForViewType(BNBinaryViewType* type, uint32_t id, BNArchitecture* arch,
- BNPlatform* platform);
BINARYNINJACOREAPI void BNRegisterDefaultPlatformForViewType(BNBinaryViewType* type, BNArchitecture* arch,
BNPlatform* platform);
- BINARYNINJACOREAPI BNPlatform* BNGetPlatformForViewType(BNBinaryViewType* type, uint32_t id, BNArchitecture* arch);
+
+ // Expanded identification of Platform for BinaryViewTypes. Supersedes BNRegisterArchitectureForViewType
+ // and BNRegisterPlatformForViewType, as these have certain edge cases (overloaded elf families, for example)
+ // that can't be represented.
+ //
+ // The callback returns a Platform object or null (failure), and most recently added callbacks are called first
+ // to allow plugins to override any default behaviors. When a callback returns a platform, architecture will be
+ // derived from the identified platform.
+ //
+ // The BinaryView pointer is the *parent* view (usually 'Raw') that the BinaryView is being created for. This
+ // means that generally speaking the callbacks need to be aware of the underlying file format, however the
+ // BinaryView implementation may have created datavars in the 'Raw' view by the time the callback is invoked.
+ // Behavior regarding when this callback is invoked and what has been made available in the BinaryView passed as an
+ // argument to the callback is up to the discretion of the BinaryView implementation.
+ //
+ // The 'id' ind 'endian' arguments are used as a filter to determine which registered Platform recognizer callbacks
+ // are invoked.
+ //
+ // Support for this API tentatively requires explicit support in the BinaryView implementation.
+ BINARYNINJACOREAPI void BNRegisterPlatformRecognizerForViewType(BNBinaryViewType* type, uint64_t id, BNEndianness endian,
+ BNPlatform* (*callback)(void* ctx, BNBinaryView* view, BNMetadata* metadata), void* ctx);
+
+ // BinaryView* passed in here should be the parent view (not the partially constructed object!), and this function should
+ // be called from the BNCustomBinaryView::init implementation.
+ //
+ // 'id' and 'endianness' are used to determine which registered callbacks are actually invoked to eliminate some common sources
+ // of boilerplate that all callbacks would have to implement otherwise. If these aren't applicable to your binaryviewtype just
+ // use constants here and document them so that people registering Platform recognizers for your view type know what to use.
+ BINARYNINJACOREAPI BNPlatform* BNRecognizePlatformForViewType(BNBinaryViewType* type, uint64_t id, BNEndianness endian,
+ BNBinaryView* view, BNMetadata* metadata);
+
BINARYNINJACOREAPI void BNRegisterBinaryViewEvent(BNBinaryViewEventType type,
void (*callback)(void* ctx, BNBinaryView* view), void* ctx);
@@ -4966,6 +4999,8 @@ __attribute__ ((format (printf, 1, 2)))
// Platforms
BINARYNINJACOREAPI BNPlatform* BNCreatePlatform(BNArchitecture* arch, const char* name);
+ BINARYNINJACOREAPI BNPlatform* BNCreatePlatformWithTypes(BNArchitecture* arch, const char* name,
+ const char* typeFile, const char** includeDirs, size_t includeDirCount);
BINARYNINJACOREAPI void BNRegisterPlatform(const char* os, BNPlatform* platform);
BINARYNINJACOREAPI BNPlatform* BNNewPlatformReference(BNPlatform* platform);
BINARYNINJACOREAPI void BNFreePlatform(BNPlatform* platform);
diff --git a/binaryviewtype.cpp b/binaryviewtype.cpp
index b49191f8..3e0feae2 100644
--- a/binaryviewtype.cpp
+++ b/binaryviewtype.cpp
@@ -197,6 +197,23 @@ Ref<Platform> BinaryViewType::GetPlatform(uint32_t id, Architecture* arch)
}
+void BinaryViewType::RegisterPlatformRecognizer(uint64_t id, BNEndianness endian, const std::function<Ref<Platform>(BinaryView* view, Metadata* metadata)>& callback)
+{
+ PlatformRecognizerFunction* ctxt = new PlatformRecognizerFunction;
+ ctxt->action = callback;
+ BNRegisterPlatformRecognizerForViewType(m_object, id, endian, PlatformRecognizerCallback, ctxt);
+}
+
+
+Ref<Platform> BinaryViewType::RecognizePlatform(uint64_t id, BNEndianness endian, BinaryView* view, Metadata* metadata)
+{
+ BNPlatform* platform = BNRecognizePlatformForViewType(m_object, id, endian, view->GetObject(), metadata->GetObject());
+ if (!platform)
+ return nullptr;
+ return new Platform(platform);
+}
+
+
string BinaryViewType::GetName()
{
char* contents = BNGetBinaryViewTypeName(m_object);
@@ -244,6 +261,18 @@ void BinaryViewType::BinaryViewEventCallback(void* ctxt, BNBinaryView* view)
}
+BNPlatform* BinaryViewType::PlatformRecognizerCallback(void* ctxt, BNBinaryView* view, BNMetadata* metadata)
+{
+ PlatformRecognizerFunction* callback = (PlatformRecognizerFunction*) ctxt;
+ Ref<BinaryView> viewObject = new BinaryView(BNNewViewReference(view));
+ Ref<Metadata> metadataObject = new Metadata(BNNewMetadataReference(metadata));
+ Ref<Platform> result = callback->action(viewObject, metadataObject);
+ if (!result)
+ return nullptr;
+ return BNNewPlatformReference(result->GetObject());
+}
+
+
CoreBinaryViewType::CoreBinaryViewType(BNBinaryViewType* type): BinaryViewType(type)
{
}
diff --git a/platform.cpp b/platform.cpp
index 54fdbcc6..181f4e7c 100644
--- a/platform.cpp
+++ b/platform.cpp
@@ -36,6 +36,16 @@ Platform::Platform(Architecture* arch, const string& name)
}
+Platform::Platform(Architecture* arch, const string& name, const string& typeFile, const vector<string>& includeDirs)
+{
+ const char** includeDirList = new const char*[includeDirs.size()];
+ for (size_t i = 0; i < includeDirs.size(); i++)
+ includeDirList[i] = includeDirs[i].c_str();
+ m_object = BNCreatePlatformWithTypes(arch->GetObject(), name.c_str(), typeFile.c_str(), includeDirList, includeDirs.size());
+ delete[] includeDirList;
+}
+
+
Ref<Architecture> Platform::GetArchitecture() const
{
return new CoreArchitecture(BNGetPlatformArchitecture(m_object));
diff --git a/python/binaryview.py b/python/binaryview.py
index 092cceec..e2bae443 100644
--- a/python/binaryview.py
+++ b/python/binaryview.py
@@ -302,7 +302,6 @@ class BinaryViewEvent(object):
except:
binaryninja.log.log_error(traceback.format_exc())
-
class ActiveAnalysisInfo(object):
def __init__(self, func, analysis_time, update_count, submit_count):
self._func = func
@@ -787,6 +786,10 @@ class _BinaryViewTypeMetaclass(type):
return BinaryViewType(view_type)
+
+# Used to force Python callback objects to not get garbage collected
+_platform_recognizers = {}
+
class BinaryViewType(with_metaclass(_BinaryViewTypeMetaclass, object)):
def __init__(self, handle):
@@ -1042,12 +1045,36 @@ class BinaryViewType(with_metaclass(_BinaryViewTypeMetaclass, object)):
def register_default_platform(self, arch, plat):
core.BNRegisterDefaultPlatformForViewType(self.handle, arch.handle, plat.handle)
+ def register_platform_recognizer(self, ident, endian, cb):
+ def callback(cb, view, meta):
+ try:
+ file_metadata = binaryninja.filemetadata.FileMetadata(handle = core.BNGetFileForView(view))
+ view_obj = binaryninja.binaryview.BinaryView(file_metadata = file_metadata, handle = core.BNNewViewReference(view))
+ meta_obj = binaryninja.metadata.Metadata(handle = core.BNNewMetadataReference(meta))
+ plat = cb(view_obj, meta_obj)
+ if plat:
+ return ctypes.cast(core.BNNewPlatformReference(plat.handle), ctypes.c_void_p).value
+ except:
+ binaryninja.log.log_error(traceback.format_exc())
+ return None
+
+ callback_obj = ctypes.CFUNCTYPE(ctypes.c_void_p, ctypes.c_void_p, ctypes.POINTER(core.BNBinaryView), ctypes.POINTER(core.BNMetadata))(lambda ctxt, view, meta: callback(cb, view, meta))
+ core.BNRegisterPlatformRecognizerForViewType(self.handle, ident, endian, callback_obj, None)
+ global _platform_recognizers
+ _platform_recognizers[len(_platform_recognizers)] = callback_obj
+
def get_platform(self, ident, arch):
plat = core.BNGetPlatformForViewType(self.handle, ident, arch.handle)
if plat is None:
return None
return binaryninja.platform.Platform(handle = plat)
+ def recognize_platform(self, ident, endian, view, metadata):
+ plat = core.BNRecognizePlatformForViewType(self.handle, ident, endian, view.handle, metadata.handle)
+ if plat is None:
+ return None
+ return binaryninja.platform.Platform(handle = plat)
+
@staticmethod
def add_binaryview_finalized_event(callback):
"""
diff --git a/python/platform.py b/python/platform.py
index 4983adff..5039f1ca 100644
--- a/python/platform.py
+++ b/python/platform.py
@@ -94,6 +94,8 @@ class Platform(with_metaclass(_PlatformMetaClass, object)):
calling conventions used.
"""
name = None
+ type_file_path = None # path to platform types file
+ type_include_dirs = [] # list of directories available to #include from type_file_path
def __init__(self, arch = None, handle = None):
if handle is None:
@@ -101,7 +103,13 @@ class Platform(with_metaclass(_PlatformMetaClass, object)):
self.handle = None
raise ValueError("platform must have an associated architecture")
self._arch = arch
- self.handle = core.BNCreatePlatform(arch.handle, self.__class__.name)
+ if self.__class__.type_file_path is None:
+ self.handle = core.BNCreatePlatform(arch.handle, self.__class__.name)
+ else:
+ dir_buf = (ctypes.c_char_p * len(self.__class__.type_include_dirs))()
+ for (i, dir) in enumerate(self.__class__.type_include_dirs):
+ dir_buf[i] = dir.encode('charmap')
+ self.handle = core.BNCreatePlatformWithTypes(arch.handle, self.__class__.name, self.__class__.type_file_path, dir_buf, len(self.__class__.type_include_dirs))
else:
self.handle = handle
self.__dict__["name"] = core.BNGetPlatformName(self.handle)