diff --git a/binaryninjaapi.h b/binaryninjaapi.h index bf1421fd0..a54e0f943 100644 --- a/binaryninjaapi.h +++ b/binaryninjaapi.h @@ -6905,6 +6905,7 @@ namespace BinaryNinja { static BNBinaryView* ParseCallback(void* ctxt, BNBinaryView* data); static bool IsValidCallback(void* ctxt, BNBinaryView* data); static bool IsDeprecatedCallback(void* ctxt); + static bool IsForceLoadableCallback(void *ctxt); static BNSettings* GetSettingsCallback(void* ctxt, BNBinaryView* data); BinaryViewType(BNBinaryViewType* type); @@ -7042,6 +7043,13 @@ namespace BinaryNinja { \return Whether this BinaryViewType is valid for given data */ virtual bool IsTypeValidForData(BinaryView* data) = 0; + + /*! Check whether this BinaryViewType can be forced to load a binary, even if IsTypeValidForData returns false + + \return Whether this BinaryViewType can be forced to load a binary + */ + virtual bool IsForceLoadable(); + virtual Ref GetLoadSettingsForData(BinaryView* data); Ref GetDefaultLoadSettingsForData(BinaryView* data); @@ -7064,6 +7072,7 @@ namespace BinaryNinja { virtual Ref Parse(BinaryView* data) override; virtual bool IsTypeValidForData(BinaryView* data) override; virtual bool IsDeprecated() override; + virtual bool IsForceLoadable() override; virtual Ref GetLoadSettingsForData(BinaryView* data) override; }; diff --git a/binaryninjacore.h b/binaryninjacore.h index 0d321838a..edf2c1f26 100644 --- a/binaryninjacore.h +++ b/binaryninjacore.h @@ -44,7 +44,7 @@ // will require rebuilding. The minimum version is increased when there are // incompatible changes that break binary compatibility, such as changes to // existing types or functions. -#define BN_MINIMUM_CORE_ABI_VERSION 72 +#define BN_MINIMUM_CORE_ABI_VERSION 73 #ifdef __GNUC__ #ifdef BINARYNINJACORE_LIBRARY @@ -1656,6 +1656,7 @@ extern "C" BNBinaryView* (*parse)(void* ctxt, BNBinaryView* data); bool (*isValidForData)(void* ctxt, BNBinaryView* data); bool (*isDeprecated)(void* ctxt); + bool (*isForceLoadable)(void* ctxt); BNSettings* (*getLoadSettingsForData)(void* ctxt, BNBinaryView* data); } BNCustomBinaryViewType; @@ -3994,6 +3995,7 @@ extern "C" BINARYNINJACOREAPI BNBinaryView* BNCreateBinaryViewOfType(BNBinaryViewType* type, BNBinaryView* data); BINARYNINJACOREAPI BNBinaryView* BNParseBinaryViewOfType(BNBinaryViewType* type, BNBinaryView* data); BINARYNINJACOREAPI bool BNIsBinaryViewTypeValidForData(BNBinaryViewType* type, BNBinaryView* data); + BINARYNINJACOREAPI bool BNIsBinaryViewTypeForceLoadable(BNBinaryViewType* type); BINARYNINJACOREAPI BNSettings* BNGetBinaryViewDefaultLoadSettingsForData( BNBinaryViewType* type, BNBinaryView* data); BINARYNINJACOREAPI BNSettings* BNGetBinaryViewLoadSettingsForData(BNBinaryViewType* type, BNBinaryView* data); diff --git a/binaryviewtype.cpp b/binaryviewtype.cpp index b1ef5226f..2ee8e2ac7 100644 --- a/binaryviewtype.cpp +++ b/binaryviewtype.cpp @@ -61,6 +61,13 @@ bool BinaryViewType::IsDeprecatedCallback(void* ctxt) } +bool BinaryViewType::IsForceLoadableCallback(void* ctxt) +{ + CallbackRef type(ctxt); + return type->IsForceLoadable(); +} + + BNSettings* BinaryViewType::GetSettingsCallback(void* ctxt, BNBinaryView* data) { CallbackRef type(ctxt); @@ -93,6 +100,7 @@ void BinaryViewType::Register(BinaryViewType* type) callbacks.parse = ParseCallback; callbacks.isValidForData = IsValidCallback; callbacks.isDeprecated = IsDeprecatedCallback; + callbacks.isForceLoadable = IsForceLoadableCallback; callbacks.getLoadSettingsForData = GetSettingsCallback; type->AddRefForRegistration(); @@ -247,6 +255,12 @@ bool BinaryViewType::IsDeprecated() } +bool BinaryViewType::IsForceLoadable() +{ + return false; +} + + void BinaryViewType::RegisterBinaryViewFinalizationEvent(const function& callback) { BinaryViewEvent* event = new BinaryViewEvent; @@ -347,6 +361,12 @@ bool CoreBinaryViewType::IsDeprecated() } +bool CoreBinaryViewType::IsForceLoadable() +{ + return BNIsBinaryViewTypeForceLoadable(m_object); +} + + Ref CoreBinaryViewType::GetLoadSettingsForData(BinaryView* data) { BNSettings* settings = BNGetBinaryViewLoadSettingsForData(m_object, data->GetObject()); diff --git a/python/binaryview.py b/python/binaryview.py index cb067db64..c5c259880 100644 --- a/python/binaryview.py +++ b/python/binaryview.py @@ -1271,6 +1271,11 @@ def is_deprecated(self) -> bool: """returns if the BinaryViewType is deprecated (read-only)""" return core.BNIsBinaryViewTypeDeprecated(self.handle) + @property + def is_force_loadable(self) -> bool: + """returns if the BinaryViewType is force loadable (read-only)""" + return core.BNIsBinaryViewTypeForceLoadable(self.handle) + def create(self, data: 'BinaryView') -> Optional['BinaryView']: view = core.BNCreateBinaryViewOfType(self.handle, data.handle) if view is None: @@ -2511,6 +2516,7 @@ def register(cls) -> None: cls._registered_cb.parse = cls._registered_cb.parse.__class__(cls._parse) cls._registered_cb.isValidForData = cls._registered_cb.isValidForData.__class__(cls._is_valid_for_data) cls._registered_cb.isDeprecated = cls._registered_cb.isDeprecated.__class__(cls._is_deprecated) + cls._registered_cb.isForceLoadable = cls._registered_cb.isForceLoadable.__class__(cls._is_force_loadable) cls._registered_cb.getLoadSettingsForData = cls._registered_cb.getLoadSettingsForData.__class__( cls._get_load_settings_for_data ) @@ -2579,6 +2585,17 @@ def _is_deprecated(cls, ctxt): log_error(traceback.format_exc()) return False + @classmethod + def _is_force_loadable(cls, ctxt): + if not callable(getattr(cls, 'is_force_loadable', None)): + return False + + try: + return cls.is_force_loadable() # type: ignore + except: + log_error(traceback.format_exc()) + return False + @classmethod def _get_load_settings_for_data(cls, ctxt, data): try: diff --git a/rust/examples/minidump/src/view.rs b/rust/examples/minidump/src/view.rs index bbbe0bd5e..d35e3f422 100644 --- a/rust/examples/minidump/src/view.rs +++ b/rust/examples/minidump/src/view.rs @@ -48,6 +48,10 @@ impl BinaryViewTypeBase for MinidumpBinaryViewType { false } + fn is_force_loadable(&self) -> bool { + false + } + fn is_valid_for(&self, data: &BinaryView) -> bool { let mut magic_number = Vec::::new(); data.read_into_vec(&mut magic_number, 0, 4); diff --git a/rust/src/custombinaryview.rs b/rust/src/custombinaryview.rs index 05f1acb8d..13c36d5e1 100644 --- a/rust/src/custombinaryview.rs +++ b/rust/src/custombinaryview.rs @@ -68,6 +68,16 @@ where }) } + extern "C" fn cb_force_loadable(ctxt: *mut c_void) -> bool + where + T: CustomBinaryViewType, + { + ffi_wrap!("BinaryViewTypeBase::is_force_loadable", unsafe { + let view_type = &*(ctxt as *mut T); + view_type.is_force_loadable() + }) + } + extern "C" fn cb_create(ctxt: *mut c_void, data: *mut BNBinaryView) -> *mut BNBinaryView where T: CustomBinaryViewType, @@ -131,6 +141,7 @@ where parse: Some(cb_parse::), isValidForData: Some(cb_valid::), isDeprecated: Some(cb_deprecated::), + isForceLoadable: Some(cb_force_loadable::), getLoadSettingsForData: Some(cb_load_settings::), }; @@ -158,6 +169,8 @@ pub trait BinaryViewTypeBase: AsRef { fn is_deprecated(&self) -> bool; + fn is_force_loadable(&self) -> bool; + fn default_load_settings_for_data(&self, data: &BinaryView) -> Result> { let settings_handle = unsafe { BNGetBinaryViewDefaultLoadSettingsForData(self.as_ref().0, data.handle) }; @@ -265,6 +278,10 @@ impl BinaryViewTypeBase for BinaryViewType { unsafe { BNIsBinaryViewTypeDeprecated(self.0) } } + fn is_force_loadable(&self) -> bool { + unsafe { BNIsBinaryViewTypeForceLoadable(self.0) } + } + fn default_load_settings_for_data(&self, data: &BinaryView) -> Result> { let settings_handle = unsafe { BNGetBinaryViewDefaultLoadSettingsForData(self.0, data.handle) }; diff --git a/ui/options.h b/ui/options.h index 6493a1dfe..3206fc7ef 100644 --- a/ui/options.h +++ b/ui/options.h @@ -32,6 +32,7 @@ class BINARYNINJAUIAPI OptionsDialog : public QDialog QString m_fileName; QLabel* m_fileLabel; QComboBox* m_loadAsCombo; + QLabel* m_loadAsLabel; QLabel* m_objectLabel; QComboBox* m_objectCombo; QTabWidget* m_tab;