diff options
| author | Ryan Snyder <ryan@vector35.com> | 2021-08-04 11:17:40 -0400 |
|---|---|---|
| committer | Ryan Snyder <ryan@vector35.com> | 2021-08-20 04:34:14 -0400 |
| commit | cc1e85a4a8b2001f9fd6cf91b93fb39abef3a0e2 (patch) | |
| tree | 45fdf52d2bdb8e09f57fc76079a3a91b6528f4a1 | |
| parent | c1e526ea39d97c4c374de4cf8c211dc39ebbb538 (diff) | |
platforms: specify platform types and add bvt platform callbacks
| -rw-r--r-- | binaryninjaapi.h | 10 | ||||
| -rw-r--r-- | binaryninjacore.h | 45 | ||||
| -rw-r--r-- | binaryviewtype.cpp | 29 | ||||
| -rw-r--r-- | platform.cpp | 10 | ||||
| -rw-r--r-- | python/binaryview.py | 29 | ||||
| -rw-r--r-- | python/platform.py | 10 |
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) |
