diff options
| author | Brandon Miller <brandon@vector35.com> | 2025-02-03 16:33:46 -0500 |
|---|---|---|
| committer | Brandon Miller <brandon@vector35.com> | 2025-02-04 08:56:37 -0500 |
| commit | ed08160e6782b3f8b371370bfad3a04e80e94f4d (patch) | |
| tree | cc73ad9a24301aed63b51b28a90a44cc4ac2550b | |
| parent | 60ae03fed8aee9bc88c6d04023bcd3c922ec273e (diff) | |
Firmware Ninja relationships API
| -rw-r--r-- | binaryninjaapi.h | 280 | ||||
| -rw-r--r-- | binaryninjacore.h | 44 | ||||
| -rw-r--r-- | firmwareninja.cpp | 300 | ||||
| -rw-r--r-- | python/firmwareninja.py | 530 | ||||
| -rw-r--r-- | ui/uicontext.h | 1 |
5 files changed, 954 insertions, 201 deletions
diff --git a/binaryninjaapi.h b/binaryninjaapi.h index f247fc41..8805efd7 100644 --- a/binaryninjaapi.h +++ b/binaryninjaapi.h @@ -18570,60 +18570,250 @@ namespace BinaryNinja { }; - /*! FirmwareNinjaReferenceNode is a class used to build reference trees to memory regions, functions, and data + /*! FirmwareNinjaReferenceNode is a class used to build reference trees for memory regions, functions, and data variables. This class is only available in the Ultimate Edition of Binary Ninja. \ingroup firmwareninja */ class FirmwareNinjaReferenceNode : public CoreRefCountObject<BNFirmwareNinjaReferenceNode, BNNewFirmwareNinjaReferenceNodeReference, BNFreeFirmwareNinjaReferenceNode> { - BNFirmwareNinjaReferenceNode* m_object; public: FirmwareNinjaReferenceNode(BNFirmwareNinjaReferenceNode* node); ~FirmwareNinjaReferenceNode(); - /*! Determine if the reference tree node is for a function + /*! Returns true if the reference tree node contains a function - \return true if the reference tree node is for a function, false otherwise + \return true if the reference tree node contains a function, false otherwise */ bool IsFunction(); - /*! Determine if the reference tree node is for a data variable + /*! Returns true if the reference tree node contains a data variable - \return true if the reference tree node is for a data variable, false otherwise + \return true if the reference tree node contains a data variable, false otherwise */ bool IsDataVariable(); - /*! Determine if the reference tree node contains child nodes + /*! Returns true if the reference tree node contains child nodes \return true if the reference tree node contains child nodes, false otherwise */ bool HasChildren(); - /*! Query the function contained in the reference tree node + /*! Get the function contained in the reference tree node \param function Output function object - \return true if the function was queried successfully, false otherwise + \return true if the function was queried successfully, false if the reference tree node does not contain a function */ bool GetFunction(Ref<Function>& function); - /*! Query the data variable contained in the reference tree node + /*! Get the data variable contained in the reference tree node \param function Output data variable object - \return true if the data variable was queried successfully, false otherwise + \return true if the data variable was queried successfully, false if the reference tree node does not contain a data variable */ bool GetDataVariable(DataVariable& variable); - /*! Query the child nodes contained in the reference tree node + /*! Get the child nodes contained in the reference tree node \return Vector of child reference tree nodes */ std::vector<Ref<FirmwareNinjaReferenceNode>> GetChildren(); }; + /*! FirmwareNinjaRelationship is a class used to represent inter-binary and cross-binary relationships. This class is + only available in the Ultimate Edition of Binary Ninja. - /*! FirmwareNinja is a class containing features specific to embedded firmware analysis. This class is only - available in the Ultimate Edition of Binary Ninja. + \ingroup firmwareninja + */ + class FirmwareNinjaRelationship : public CoreRefCountObject<BNFirmwareNinjaRelationship, BNNewFirmwareNinjaRelationshipReference, BNFreeFirmwareNinjaRelationship> + { + public: + FirmwareNinjaRelationship(Ref<BinaryView> view, BNFirmwareNinjaRelationship* relationship = nullptr); + ~FirmwareNinjaRelationship(); + + /*! Set the primary relationship object to an address + + \param address Address in current binary view + */ + void SetPrimaryAddress(uint64_t address); + + /*! Set the primary relationship object to a data variable + + \param var DataVariable in current binary view + */ + void SetPrimaryDataVariable(DataVariable& variable); + + /*! Set the primary relationship object to a function + + \param function Function in current binary view + */ + void SetPrimaryFunction(Ref<Function> function); + + /*! Determine if the primary object is an address + + \return true if the primary object is an address, false otherwise + */ + bool PrimaryIsAddress() const; + + /*! Returns true if the primary object is a data variable + + \return true if the primary object is a data variable, false otherwise + */ + bool PrimaryIsDataVariable() const; + + /*! Returns true if the primary object is a function + + \return true if the primary object is a function, false otherwise + */ + bool PrimaryIsFunction() const; + + /*! Get the primary data variable contained in the relationship + + \param var Output data variable + \return true if the data variable was queried successfully, false if the primary object is not a data variable + */ + bool GetPrimaryDataVariable(DataVariable& var); + + /*! Get the primary address contained in the relationship + + \return Optional address with a value if the primary object is an address + */ + std::optional<uint64_t> GetPrimaryAddress() const; + + /*! Get the primary function contained in the relationship + + \return Function object if the primary object is a function, nullptr otherwise + */ + Ref<Function> GetPrimaryFunction() const; + + /*! Set the secondary relationship object to an address + + \param address Address in current binary view + */ + void SetSecondaryAddress(uint64_t address); + + /*! Set the secondary relationship object to a data variable + + \param var DataVariable in current binary view + */ + void SetSecondaryDataVariable(DataVariable& variable); + + /*! Set the secondary relationship object to a function + + \param function Function in current binary view + */ + void SetSecondaryFunction(Ref<Function> function); + + /*! Set the secondary relationship object to an external address + + \param projectFile Project file for external binary in the project + \param address Address in the external binary + */ + void SetSecondaryExternalAddress(Ref<ProjectFile> projectFile, uint64_t address); + + /*! Set the secondary relationship object to an external symbol + + \param projectFile Project file for the external binary in the project + \param sybmol Symbol in external binary + */ + void SetSecondaryExternalSymbol(Ref<ProjectFile> projectFile, const std::string& symbol); + + /*! Determine if the secondary object is an address in the current binary view + + \return true if the secondary object is an address in the current binary view, false otherwise + */ + bool SecondaryIsAddress() const; + + /*! Returns true if the secondary object is a data variable in the current binary view + + \return true if the secondary object is a data variable in the current binary view, false otherwise + */ + bool SecondaryIsDataVariable() const; + + /*! Returns true if the secondary object is a function in the current binary view + + \return true if the secondary object is a function in the current binary view, false otherwise + */ + bool SecondaryIsFunction() const; + + /*! Returns true if the secondary object is an address contained in another binary in the project + + \return true if the secondary object is an external address, false otherwise + */ + bool SecondaryIsExternalAddress() const; + + /*! Returns true if the secondary object is a symbol contained in another binary in the project + + \return true if the secondary object is an external symbol, false otherwise + */ + bool SecondaryIsExternalSymbol() const; + + /*! Get the secondary object's external project file + + \return The secondary object's external project file or nullptr if the secondary object is not an external address + */ + Ref<ProjectFile> GetSecondaryExternalProjectFile() const; + + /*! Get the secondary address from the relationship + + \return Optional address containing a value, if the secondary object is an address + */ + std::optional<uint64_t> GetSecondaryAddress() const; + + /*! Get the secondary data variable from the relationship + + \param var Output data variable + \return true if the data variable was queried successfully, false if the secondary object is not a data variable + */ + bool GetSecondaryDataVariable(DataVariable& variable); + + /*! Get the secondary function from the relationship + + \return Function object if the secondary object is a function, nullptr otherwise + */ + Ref<Function> GetSecondaryFunction() const; + + + /*! Get the secondary external address from the relationship + + \return External symbol string, or empty string if the secondary object is not an external symbol + */ + std::string GetSecondaryExternalSymbol() const; + + + /*! Set the description of the relationship + + \param description Description string + */ + void SetDescription(const std::string& description); + + /*! Get the description of the relationship + + \return Description string, or empty string if not set + */ + std::string GetDescription() const; + + /*! Set the provenance for the relationship + + \param provenance Provenance string + */ + void SetProvenance(const std::string& provenance); + + /*! Get the provenance for the relationship + + \return Provenance string, or empty string if not set + */ + std::string GetProvenance() const; + + /*! Get the relationship identifier + + \return Relationship GUID string + */ + std::string GetGuid() const; + }; + + /*! FirmwareNinja is a class containing features specific to firmware analysis. This class is only available in the + Ultimate Edition of Binary Ninja. \ingroup firmwareninja */ @@ -18666,7 +18856,7 @@ namespace BinaryNinja { /*! Query Firmware Ninja device definitions for the specified board \param board Name of the board to query devices for - \return Vector of Firmware Ninja device definitions + \return Vector containing Firmware Ninja device definitions */ std::vector<FirmwareNinjaDevice> QueryDevicesForBoard(const std::string& board); @@ -18676,7 +18866,7 @@ namespace BinaryNinja { \param board lowCodeEntropyThreshold Low threshold for code entropy value range \param blockSize Size of blocks to analyze \param mode Analysis mode of operation - \return Vector of Firmware Ninja section information + \return Vector containing Firmware Ninja section information */ std::vector<BNFirmwareNinjaSection> FindSections(float highCodeEntropyThreshold, float lowCodeEntropyThreshold, size_t blockSize, BNFirmwareNinjaSectionAnalysisMode mode); @@ -18685,39 +18875,40 @@ namespace BinaryNinja { \param progress Progress callback function \param progressContext Progress context - \return Vector of Firmware Ninja function memory accesses information + \return Vector containing Firmware Ninja function memory accesses */ std::vector<FirmwareNinjaFunctionMemoryAccesses> GetFunctionMemoryAccesses(BNProgressFunction progress, void* progressContext); /*! Store Firmware Ninja function memory accesses information in the binary view metadata - \param fma Vector of Firmware Ninja function memory accesses information + \param fma Vector containin Firmware Ninja function memory accesses */ void StoreFunctionMemoryAccesses(const std::vector<FirmwareNinjaFunctionMemoryAccesses>& fma); - /*! Query cached Firmware Ninja function memory accesses information from the binary view metadata + /*! Query Firmware Ninja function memory accesses that are stored in the binary view metadata - \return Vector of Firmware Ninja memory analyis information + \return Vector containing Firmware Ninja function memory accesses */ std::vector<FirmwareNinjaFunctionMemoryAccesses> QueryFunctionMemoryAccesses(); - /*! Compute number of accesses mad to memory-mapped hardware devices for each board that is compatible with the - current architecture + /*! Compute number of accesses made to memory-mapped hardware devices for each bundled board that is compatible with + the current architecture - \param fma Vector of Firmware Ninja function memory accesses information - \return Vector of Firmware Ninja device accesses information for each board + \param fma Vector containing Firmware Ninja function memory accesses + \return Vector containing Firmware Ninja device accesses for each board */ std::vector<FirmwareNinjaDeviceAccesses> GetBoardDeviceAccesses( const std::vector<FirmwareNinjaFunctionMemoryAccesses>& fma); - /*! Returns a tree of reference nodes that reference the memory region represented by the given device + /*! Returns a tree of reference nodes that reference the memory region represented by the given Firmware Ninja + device \param device Firmware Ninja device - \param fma Vector of Firmware Ninja function memory accesses information - \param value (Optional) only include components that originate with a write of this value to the device - \return Root reference node of tree + \param fma Vector containing Firmware Ninja function memory accesses + \param value (Optional) only build reference trees that originate with a write of the specified value + \return Root reference node for the tree */ Ref<FirmwareNinjaReferenceNode> GetReferenceTree( FirmwareNinjaDevice& device, @@ -18728,8 +18919,8 @@ namespace BinaryNinja { /*! Returns a tree of reference nodes that reference the memory region represented by the given section \param device Firmware Ninja device - \param fma Vector of Firmware Ninja function memory accesses information - \param value (Optional) only include components that originate with a write of this value to the device + \param fma Vector containing Firmware Ninja function memory accesses + \param value (Optional) only build reference trees that originate with a write of the specified value \return Root reference node of tree */ Ref<FirmwareNinjaReferenceNode> GetReferenceTree( @@ -18742,8 +18933,8 @@ namespace BinaryNinja { /*! Returns a tree of reference nodes that reference the given address \param device Firmware Ninja device - \param fma Vector of Firmware Ninja function memory accesses information - \param value (Optional) only include components that originate with a write of this value to the device + \param fma Vector containing Firmware Ninja function memory accesses + \param value (Optional) only build reference trees that originate with a write of the specified value \return Root reference node of tree */ Ref<FirmwareNinjaReferenceNode> GetReferenceTree( @@ -18751,6 +18942,31 @@ namespace BinaryNinja { const std::vector<FirmwareNinjaFunctionMemoryAccesses>& fma, uint64_t* value = nullptr ); + + /*! Query Firmware Ninja relationships from the binary view metadata + + \return Vector containing Firmware Ninja relationships + */ + std::vector<Ref<FirmwareNinjaRelationship>> QueryRelationships(); + + /*! Store a Firmware Ninja relationship in the binary view metadata + + \param relationship Firmware Ninja relationship + */ + void AddRelationship(Ref<FirmwareNinjaRelationship> relationship); + + /* Query a Firmware Ninja relationship by GUID + + \param guid GUID of the relationship to query + \return Firmware Ninja relationship if found, nullptr otherwise + */ + Ref<FirmwareNinjaRelationship> GetRelationshipByGuid(const std::string& guid); + + /*! Remove a Firmware Ninja relationship from the binary view metadata + + \param guid GUID of the relationship to remove + */ + void RemoveRelationshipByGuid(const std::string& guid); }; diff --git a/binaryninjacore.h b/binaryninjacore.h index 5d213793..ccc40bdf 100644 --- a/binaryninjacore.h +++ b/binaryninjacore.h @@ -37,14 +37,14 @@ // Current ABI version for linking to the core. This is incremented any time // there are changes to the API that affect linking, including new functions, // new types, or modifications to existing functions or types. -#define BN_CURRENT_CORE_ABI_VERSION 91 +#define BN_CURRENT_CORE_ABI_VERSION 92 // Minimum ABI version that is supported for loading of plugins. Plugins that // are linked to an ABI version less than this will not be able to load and // 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 89 +#define BN_MINIMUM_CORE_ABI_VERSION 92 #ifdef __GNUC__ #ifdef BINARYNINJACORE_LIBRARY @@ -302,6 +302,7 @@ extern "C" typedef struct BNDemangler BNDemangler; typedef struct BNFirmwareNinja BNFirmwareNinja; typedef struct BNFirmwareNinjaReferenceNode BNFirmwareNinjaReferenceNode; + typedef struct BNFirmwareNinjaRelationship BNFirmwareNinjaRelationship; typedef struct BNLineFormatter BNLineFormatter; typedef struct BNRenderLayer BNRenderLayer; @@ -8116,17 +8117,54 @@ extern "C" BINARYNINJACOREAPI void BNFirmwareNinjaFreeBoardDeviceAccesses(BNFirmwareNinjaDeviceAccesses *accesses, int size); BINARYNINJACOREAPI BNFirmwareNinjaReferenceNode* BNFirmwareNinjaGetMemoryRegionReferenceTree(BNFirmwareNinja* fn, uint64_t start, uint64_t end, BNFirmwareNinjaFunctionMemoryAccesses** fma, int size, uint64_t* value); BINARYNINJACOREAPI BNFirmwareNinjaReferenceNode* BNFirmwareNinjaGetAddressReferenceTree(BNFirmwareNinja* fn, uint64_t address, BNFirmwareNinjaFunctionMemoryAccesses** fma, int size, uint64_t* value); + BINARYNINJACOREAPI BNFirmwareNinjaRelationship** BNFirmwareNinjaQueryRelationships(BNFirmwareNinja* fn, size_t* count); + BINARYNINJACOREAPI void BNFirmwareNinjaAddRelationship(BNFirmwareNinja* fn, BNFirmwareNinjaRelationship* rel); + BINARYNINJACOREAPI BNFirmwareNinjaRelationship* BNFirmwareNinjaGetRelationshipByGuid(BNFirmwareNinja* fn, const char* guid); + BINARYNINJACOREAPI void BNFirmwareNinjaRemoveRelationshipByGuid(BNFirmwareNinja* fn, const char* guid); BINARYNINJACOREAPI bool BNFirmwareNinjaReferenceNodeIsFunction(BNFirmwareNinjaReferenceNode* node); BINARYNINJACOREAPI bool BNFirmwareNinjaReferenceNodeIsDataVariable(BNFirmwareNinjaReferenceNode* node); BINARYNINJACOREAPI bool BNFirmwareNinjaReferenceNodeHasChildren(BNFirmwareNinjaReferenceNode* node); BINARYNINJACOREAPI BNFunction* BNFirmwareNinjaReferenceNodeGetFunction(BNFirmwareNinjaReferenceNode* node); - BINARYNINJACOREAPI BNDataVariable* BNFirmwareNinjaReferenceNodeGetDataVariable(BNFirmwareNinjaReferenceNode* node); + BINARYNINJACOREAPI bool BNFirmwareNinjaReferenceNodeGetDataVariable(BNFirmwareNinjaReferenceNode* node, BNDataVariable* dataVariable); BINARYNINJACOREAPI BNFirmwareNinjaReferenceNode** BNFirmwareNinjaReferenceNodeGetChildren(BNFirmwareNinjaReferenceNode* parent, size_t* count); BINARYNINJACOREAPI void BNFreeFirmwareNinjaReferenceNode(BNFirmwareNinjaReferenceNode* node); BINARYNINJACOREAPI BNFirmwareNinjaReferenceNode* BNNewFirmwareNinjaReferenceNodeReference(BNFirmwareNinjaReferenceNode* node); BINARYNINJACOREAPI void BNFreeFirmwareNinjaReferenceNodes(BNFirmwareNinjaReferenceNode** nodes, size_t count); + BINARYNINJACOREAPI BNFirmwareNinjaRelationship* BNCreateFirmwareNinjaRelationship(BNBinaryView* view); + BINARYNINJACOREAPI void BNFreeFirmwareNinjaRelationship(BNFirmwareNinjaRelationship* rel); + BINARYNINJACOREAPI BNFirmwareNinjaRelationship* BNNewFirmwareNinjaRelationshipReference(BNFirmwareNinjaRelationship* rel); + BINARYNINJACOREAPI void BNFirmwareNinjaRelationshipSetPrimaryAddress(BNFirmwareNinjaRelationship* rel, uint64_t address); + BINARYNINJACOREAPI void BNFirmwareNinjaRelationshipSetPrimaryDataVariable(BNFirmwareNinjaRelationship* rel, uint64_t dataVariableAddress); + BINARYNINJACOREAPI void BNFirmwareNinjaRelationshipSetPrimaryFunction(BNFirmwareNinjaRelationship* rel, BNFunction* function); + BINARYNINJACOREAPI bool BNFirmwareNinjaRelationshipPrimaryIsDataVariable(BNFirmwareNinjaRelationship* rel); + BINARYNINJACOREAPI bool BNFirmwareNinjaRelationshipPrimaryIsFunction(BNFirmwareNinjaRelationship* rel); + BINARYNINJACOREAPI bool BNFirmwareNinjaRelationshipPrimaryIsAddress(BNFirmwareNinjaRelationship* rel); + BINARYNINJACOREAPI bool BNFirmwareNinjaRelationshipGetPrimaryDataVariable(BNFirmwareNinjaRelationship* rel, BNDataVariable* dataVariable); + BINARYNINJACOREAPI BNFunction* BNFirmwareNinjaRelationshipGetPrimaryFunction(BNFirmwareNinjaRelationship* rel); + BINARYNINJACOREAPI bool BNFirmwareNinjaRelationshipGetPrimaryAddress(BNFirmwareNinjaRelationship* rel, uint64_t* result); + BINARYNINJACOREAPI void BNFirmwareNinjaRelationshipSetSecondaryExternalAddress(BNFirmwareNinjaRelationship* rel, BNProjectFile* projectFile, uint64_t address); + BINARYNINJACOREAPI void BNFirmwareNinjaRelationshipSetSecondaryExternalSymbol(BNFirmwareNinjaRelationship* rel, BNProjectFile* projectFile, const char* symbol); + BINARYNINJACOREAPI void BNFirmwareNinjaRelationshipSetSecondaryAddress(BNFirmwareNinjaRelationship* rel, uint64_t address); + BINARYNINJACOREAPI void BNFirmwareNinjaRelationshipSetSecondaryDataVariable(BNFirmwareNinjaRelationship* rel, uint64_t dataVariableAddress); + BINARYNINJACOREAPI void BNFirmwareNinjaRelationshipSetSecondaryFunction(BNFirmwareNinjaRelationship* rel, BNFunction* function); + BINARYNINJACOREAPI bool BNFirmwareNinjaRelationshipSecondaryIsDataVariable(BNFirmwareNinjaRelationship* rel); + BINARYNINJACOREAPI bool BNFirmwareNinjaRelationshipSecondaryIsFunction(BNFirmwareNinjaRelationship* rel); + BINARYNINJACOREAPI bool BNFirmwareNinjaRelationshipSecondaryIsAddress(BNFirmwareNinjaRelationship* rel); + BINARYNINJACOREAPI bool BNFirmwareNinjaRelationshipSecondaryIsExternalAddress(BNFirmwareNinjaRelationship* rel); + BINARYNINJACOREAPI bool BNFirmwareNinjaRelationshipSecondaryIsExternalSymbol(BNFirmwareNinjaRelationship* rel); + BINARYNINJACOREAPI BNProjectFile* BNFirmwareNinjaRelationshipGetSecondaryExternalProjectFile(BNFirmwareNinjaRelationship* rel); + BINARYNINJACOREAPI bool BNFirmwareNinjaRelationshipGetSecondaryAddress(BNFirmwareNinjaRelationship* rel, uint64_t* result); + BINARYNINJACOREAPI bool BNFirmwareNinjaRelationshipGetSecondaryDataVariable(BNFirmwareNinjaRelationship* rel, BNDataVariable* dataVariable); + BINARYNINJACOREAPI BNFunction* BNFirmwareNinjaRelationshipGetSecondaryFunction(BNFirmwareNinjaRelationship* rel); + BINARYNINJACOREAPI const char* BNFirmwareNinjaRelationshipGetSecondaryExternalSymbol(BNFirmwareNinjaRelationship* rel); + BINARYNINJACOREAPI void BNFirmwareNinjaRelationshipSetDescription(BNFirmwareNinjaRelationship* rel, const char* description); + BINARYNINJACOREAPI const char* BNFirmwareNinjaRelationshipGetDescription(BNFirmwareNinjaRelationship* rel); + BINARYNINJACOREAPI void BNFirmwareNinjaRelationshipSetProvenance(BNFirmwareNinjaRelationship* rel, const char* provenance); + BINARYNINJACOREAPI const char* BNFirmwareNinjaRelationshipGetProvenance(BNFirmwareNinjaRelationship* rel); + BINARYNINJACOREAPI const char* BNFirmwareNinjaRelationshipGetGuid(BNFirmwareNinjaRelationship* rel); + // Line formatters BINARYNINJACOREAPI BNLineFormatter* BNRegisterLineFormatter(const char* name, BNCustomLineFormatter* callbacks); BINARYNINJACOREAPI BNLineFormatter** BNGetLineFormatterList(size_t* count); diff --git a/firmwareninja.cpp b/firmwareninja.cpp index 8e13fccd..9fd53930 100644 --- a/firmwareninja.cpp +++ b/firmwareninja.cpp @@ -58,6 +58,248 @@ static void FreeMemoryInfoArray(BNFirmwareNinjaFunctionMemoryAccesses** fma, siz } +FirmwareNinjaRelationship::FirmwareNinjaRelationship(Ref<BinaryView> view, BNFirmwareNinjaRelationship* handle) +{ + if (handle) + m_object = handle; + else + m_object = BNNewFirmwareNinjaRelationshipReference(BNCreateFirmwareNinjaRelationship(view->GetObject())); +} + + +FirmwareNinjaRelationship::~FirmwareNinjaRelationship() +{ + BNFreeFirmwareNinjaRelationship(m_object); +} + + +void FirmwareNinjaRelationship::SetPrimaryAddress(uint64_t address) +{ + BNFirmwareNinjaRelationshipSetPrimaryAddress(m_object, address); +} + + +void FirmwareNinjaRelationship::SetPrimaryDataVariable(DataVariable& variable) +{ + BNFirmwareNinjaRelationshipSetPrimaryDataVariable(m_object, variable.address); +} + + +void FirmwareNinjaRelationship::SetPrimaryFunction(Ref<Function> function) +{ + BNFirmwareNinjaRelationshipSetPrimaryFunction(m_object, function->GetObject()); +} + + +bool FirmwareNinjaRelationship::PrimaryIsAddress() const +{ + return BNFirmwareNinjaRelationshipPrimaryIsAddress(m_object); +} + + +bool FirmwareNinjaRelationship::PrimaryIsDataVariable() const +{ + return BNFirmwareNinjaRelationshipPrimaryIsDataVariable(m_object); +} + + +bool FirmwareNinjaRelationship::PrimaryIsFunction() const +{ + return BNFirmwareNinjaRelationshipPrimaryIsFunction(m_object); +} + + +bool FirmwareNinjaRelationship::GetPrimaryDataVariable(DataVariable& variable) +{ + BNDataVariable bnVariable; + if (!BNFirmwareNinjaRelationshipGetPrimaryDataVariable(m_object, &bnVariable)) + return false; + + variable.address = bnVariable.address; + variable.type = Confidence(new Type(BNNewTypeReference(bnVariable.type)), bnVariable.typeConfidence); + variable.autoDiscovered = bnVariable.autoDiscovered; + BNFreeDataVariable(&bnVariable); + return true; +} + + +std::optional<uint64_t> FirmwareNinjaRelationship::GetPrimaryAddress() const +{ + std::optional<uint64_t> result; + uint64_t tmp; + if (BNFirmwareNinjaRelationshipGetPrimaryAddress(m_object, &tmp)) + result = tmp; + + return result; +} + + +Ref<Function> FirmwareNinjaRelationship::GetPrimaryFunction() const +{ + auto bnFunction = BNFirmwareNinjaRelationshipGetPrimaryFunction(m_object); + if (!bnFunction) + return nullptr; + + return new Function(BNNewFunctionReference(bnFunction)); +} + + +void FirmwareNinjaRelationship::SetSecondaryAddress(uint64_t address) +{ + BNFirmwareNinjaRelationshipSetSecondaryAddress(m_object, address); +} + + +void FirmwareNinjaRelationship::SetSecondaryDataVariable(DataVariable& variable) +{ + BNFirmwareNinjaRelationshipSetSecondaryDataVariable(m_object, variable.address); +} + + +void FirmwareNinjaRelationship::SetSecondaryFunction(Ref<Function> function) +{ + BNFirmwareNinjaRelationshipSetSecondaryFunction(m_object, function->GetObject()); +} + + +void FirmwareNinjaRelationship::SetSecondaryExternalAddress(Ref<ProjectFile> projectFile, uint64_t address) +{ + BNFirmwareNinjaRelationshipSetSecondaryExternalAddress(m_object, projectFile->GetObject(), address); +} + + +void FirmwareNinjaRelationship::SetSecondaryExternalSymbol(Ref<ProjectFile> projectFile, const std::string& symbol) +{ + BNFirmwareNinjaRelationshipSetSecondaryExternalSymbol(m_object, projectFile->GetObject(), symbol.c_str()); +} + + +bool FirmwareNinjaRelationship::SecondaryIsAddress() const +{ + return BNFirmwareNinjaRelationshipSecondaryIsAddress(m_object); +} + + +bool FirmwareNinjaRelationship::SecondaryIsDataVariable() const +{ + return BNFirmwareNinjaRelationshipSecondaryIsDataVariable(m_object); +} + + +bool FirmwareNinjaRelationship::SecondaryIsFunction() const +{ + return BNFirmwareNinjaRelationshipSecondaryIsFunction(m_object); +} + + +bool FirmwareNinjaRelationship::SecondaryIsExternalAddress() const +{ + return BNFirmwareNinjaRelationshipSecondaryIsExternalAddress(m_object); +} + + +bool FirmwareNinjaRelationship::SecondaryIsExternalSymbol() const +{ + return BNFirmwareNinjaRelationshipSecondaryIsExternalSymbol(m_object); +} + + +Ref<ProjectFile> FirmwareNinjaRelationship::GetSecondaryExternalProjectFile() const +{ + auto bnProjectFile = BNFirmwareNinjaRelationshipGetSecondaryExternalProjectFile(m_object); + if (!bnProjectFile) + return nullptr; + + return new ProjectFile(BNNewProjectFileReference(bnProjectFile)); +} + + +std::optional<uint64_t> FirmwareNinjaRelationship::GetSecondaryAddress() const +{ + std::optional<uint64_t> result; + uint64_t tmp; + if (BNFirmwareNinjaRelationshipGetSecondaryAddress(m_object, &tmp)) + result = tmp; + + return result; +} + + +bool FirmwareNinjaRelationship::GetSecondaryDataVariable(DataVariable& variable) +{ + BNDataVariable bnVariable; + if (!BNFirmwareNinjaRelationshipGetSecondaryDataVariable(m_object, &bnVariable)) + return false; + + variable.address = bnVariable.address; + variable.type = Confidence(new Type(BNNewTypeReference(bnVariable.type)), bnVariable.typeConfidence); + variable.autoDiscovered = bnVariable.autoDiscovered; + BNFreeDataVariable(&bnVariable); + return true; +} + + +Ref<Function> FirmwareNinjaRelationship::GetSecondaryFunction() const +{ + auto bnFunction = BNFirmwareNinjaRelationshipGetSecondaryFunction(m_object); + if (!bnFunction) + return nullptr; + + return new Function(BNNewFunctionReference(bnFunction)); +} + + +std::string FirmwareNinjaRelationship::GetSecondaryExternalSymbol() const +{ + std::string result = ""; + auto bnSymbol = BNFirmwareNinjaRelationshipGetSecondaryExternalSymbol(m_object); + if (bnSymbol) + result = std::string(bnSymbol); + + return result; +} + + +void FirmwareNinjaRelationship::SetDescription(const std::string& description) +{ + BNFirmwareNinjaRelationshipSetDescription(m_object, description.c_str()); +} + + +std::string FirmwareNinjaRelationship::GetDescription() const +{ + std::string result = ""; + auto bnDescription = BNFirmwareNinjaRelationshipGetDescription(m_object); + if (bnDescription) + result = std::string(bnDescription); + + return result; +} + + +void FirmwareNinjaRelationship::SetProvenance(const std::string& provenance) +{ + BNFirmwareNinjaRelationshipSetProvenance(m_object, provenance.c_str()); +} + + +std::string FirmwareNinjaRelationship::GetProvenance() const +{ + std::string result = ""; + auto bnProvenance = BNFirmwareNinjaRelationshipGetProvenance(m_object); + if (bnProvenance) + result = std::string(bnProvenance); + + return result; +} + + +std::string FirmwareNinjaRelationship::GetGuid() const +{ + return BNFirmwareNinjaRelationshipGetGuid(m_object); +} + + FirmwareNinjaReferenceNode::FirmwareNinjaReferenceNode(BNFirmwareNinjaReferenceNode* node) { m_object = node; @@ -101,14 +343,14 @@ bool FirmwareNinjaReferenceNode::GetFunction(Ref<Function>& function) bool FirmwareNinjaReferenceNode::GetDataVariable(DataVariable& variable) { - auto bnVariable = BNFirmwareNinjaReferenceNodeGetDataVariable(m_object); - if (!bnVariable) + BNDataVariable bnVariable; + if (!BNFirmwareNinjaReferenceNodeGetDataVariable(m_object, &bnVariable)) return false; - variable.address = bnVariable->address; - variable.type = Confidence(new Type(BNNewTypeReference(bnVariable->type)), bnVariable->typeConfidence); - variable.autoDiscovered = bnVariable->autoDiscovered; - BNFreeDataVariable(bnVariable); + variable.address = bnVariable.address; + variable.type = Confidence(new Type(BNNewTypeReference(bnVariable.type)), bnVariable.typeConfidence); + variable.autoDiscovered = bnVariable.autoDiscovered; + BNFreeDataVariable(&bnVariable); return true; } @@ -125,8 +367,6 @@ std::vector<Ref<FirmwareNinjaReferenceNode>> FirmwareNinjaReferenceNode::GetChil BNNewFirmwareNinjaReferenceNodeReference(bnChildren[i]))); } - if (count) - BNFreeFirmwareNinjaReferenceNodes(bnChildren, count); return result; } @@ -383,7 +623,7 @@ Ref<FirmwareNinjaReferenceNode> FirmwareNinja::GetReferenceTree( if (!bnReferenceTree) return nullptr; - return new FirmwareNinjaReferenceNode(bnReferenceTree); + return new FirmwareNinjaReferenceNode(BNNewFirmwareNinjaReferenceNodeReference(bnReferenceTree)); } @@ -401,7 +641,7 @@ Ref<FirmwareNinjaReferenceNode> FirmwareNinja::GetReferenceTree( if (!bnReferenceTree) return nullptr; - return new FirmwareNinjaReferenceNode(bnReferenceTree); + return new FirmwareNinjaReferenceNode(BNNewFirmwareNinjaReferenceNodeReference(bnReferenceTree)); } @@ -418,5 +658,43 @@ Ref<FirmwareNinjaReferenceNode> FirmwareNinja::GetReferenceTree( if (!bnReferenceTree) return nullptr; - return new FirmwareNinjaReferenceNode(bnReferenceTree); + return new FirmwareNinjaReferenceNode(BNNewFirmwareNinjaReferenceNodeReference(bnReferenceTree)); +} + + +std::vector<Ref<FirmwareNinjaRelationship>> FirmwareNinja::QueryRelationships() +{ + std::vector<Ref<FirmwareNinjaRelationship>> result; + size_t count = 0; + auto bnRelationships = BNFirmwareNinjaQueryRelationships(m_object, &count); + result.reserve(count); + for (size_t i = 0; i < count; ++i) + { + result.push_back(new FirmwareNinjaRelationship(m_view, + BNNewFirmwareNinjaRelationshipReference(bnRelationships[i]))); + } + + return result; +} + + +void FirmwareNinja::AddRelationship(Ref<FirmwareNinjaRelationship> relationship) +{ + BNFirmwareNinjaAddRelationship(m_object, relationship->GetObject()); +} + + +Ref<FirmwareNinjaRelationship> FirmwareNinja::GetRelationshipByGuid(const std::string& guid) +{ + auto bnRelationship = BNFirmwareNinjaGetRelationshipByGuid(m_object, guid.c_str()); + if (!bnRelationship) + return nullptr; + + return new FirmwareNinjaRelationship(m_view, BNNewFirmwareNinjaRelationshipReference(bnRelationship)); +} + + +void FirmwareNinja::RemoveRelationshipByGuid(const std::string& guid) +{ + BNFirmwareNinjaRemoveRelationshipByGuid(m_object, guid.c_str()); } diff --git a/python/firmwareninja.py b/python/firmwareninja.py index 834cdd80..2a0a6878 100644 --- a/python/firmwareninja.py +++ b/python/firmwareninja.py @@ -31,63 +31,232 @@ from .enums import ( FirmwareNinjaSectionType, ) from .function import Function +from .project import ProjectFile from . import _binaryninjacore as core -class FirmwareNinjaReferenceNode: +class FirmwareNinjaRelationship: """ - ``class FirmwareNinjaReferenceNode`` is a class for building reference trees for functions, data variables, and - memory regions. + ``class FirmwareNinjaRelationship`` is a class for representing inter-binary and cross-binary relationships. This + class is only available in the Ultimate Edition of Binary Ninja. """ - def __init__(self, handle=None, view=None): - assert handle is not None, "Cannot create reference node directly, run `FirmwareNinja.get_reference_tree`" - self._handle = handle + def __init__(self, view: BinaryView, handle=None) -> None: + if handle is None: + self.handle = core.BNCreateFirmwareNinjaRelationship(view.handle) + else: + self.handle = handle self._view = view def __del__(self): if core is not None: - core.BNFreeFirmwareNinjaReferenceNode(self._handle) + core.BNFreeFirmwareNinjaRelationship(self.handle) + + @property + def _primary_data_variable(self) -> DataVariable: + bn_data_var = core.BNDataVariable() + if not core.BNFirmwareNinjaRelationshipGetPrimaryDataVariable(self.handle, ctypes.byref(bn_data_var)): + return None + + result = None + try: + result = DataVariable.from_core_struct(bn_data_var, self._view) + finally: + core.BNFreeDataVariable(ctypes.byref(bn_data_var)) + + return result + + @property + def _primary_function(self) -> Function: + bn_function = core.BNFirmwareNinjaRelationshipGetPrimaryFunction(self.handle) + if not bn_function: + return None - def is_function(self) -> bool: + return Function(handle=bn_function) + + @property + def _primary_address(self) -> int: + result = ctypes.c_uint64() + if not core.BNFirmwareNinjaRelationshipGetPrimaryAddress(self.handle, ctypes.byref(result)): + return None + + return result.value + + @property + def primary(self) -> Union[DataVariable, Function, int]: """ - ``is_function`` determines if the reference tree node is for a function + ``primary`` returns the primary function, data variable, or address of the relationship - :return: True if the reference tree node is for a function, False otherwise - :rtype: bool + :return: Primary object of the relationship + :rtype: Union[DataVariable, Function, int] """ - return core.BNFirmwareNinjaReferenceNodeIsFunction(self._handle) + if core.BNFirmwareNinjaRelationshipPrimaryIsDataVariable(self.handle): + return self._primary_data_variable + elif core.BNFirmwareNinjaRelationshipPrimaryIsFunction(self.handle): + return self._primary_function + elif core.BNFirmwareNinjaRelationshipPrimaryIsAddress(self.handle): + return self._primary_address + else: + return None + + @primary.setter + def primary(self, obj: Union[DataVariable, Function, int]) -> None: + if isinstance(obj, DataVariable): + core.BNFirmwareNinjaRelationshipSetPrimaryDataVariable(self.handle, obj.address) + elif isinstance(obj, Function): + core.BNFirmwareNinjaRelationshipSetPrimaryFunction(self.handle, obj.handle) + elif isinstance(obj, int): + core.BNFirmwareNinjaRelationshipSetPrimaryAddress(self.handle, obj) + else: + raise ValueError("Primary object must be a DataVariable, Function, or integer address") + + @property + def _secondary_data_variable(self) -> DataVariable: + bn_data_var = core.BNDataVariable() + if not core.BNFirmwareNinjaRelationshipGetSecondaryDataVariable(self.handle, ctypes.byref(bn_data_var)): + return None + + result = None + try: + result = DataVariable.from_core_struct(bn_data_var, self._view) + finally: + core.BNFreeDataVariable(ctypes.byref(bn_data_var)) - def is_data_variable(self) -> bool: + return result + + @property + def _secondary_function(self) -> Function: + bn_function = core.BNFirmwareNinjaRelationshipGetSecondaryFunction(self.handle) + if not bn_function: + return None + + return Function(handle=bn_function) + + @property + def _secondary_address(self) -> int: + result = ctypes.c_uint64() + if not core.BNFirmwareNinjaRelationshipGetSecondaryAddress(self.handle, ctypes.byref(result)): + return None + + return result.value + + @property + def _secondary_external_symbol(self) -> str: + return core.BNFirmwareNinjaRelationshipGetSecondaryExternalSymbol(self.handle) + + @property + def _secondary_external_project_file(self) -> ProjectFile: + bn_project_file = core.BNFirmwareNinjaRelationshipGetSecondaryExternalProjectFile(self.handle) + if not bn_project_file: + return None + + return ProjectFile(bn_project_file) + + @property + def secondary(self) -> Union[DataVariable, Function, int, tuple[int, ProjectFile], tuple[str, ProjectFile]]: """ - ``is_data_variable`` determines if the reference tree node is for a data variable + ``secondary`` returns the secondary function, data variable, address, external address, or external symbol of + the relationship - :return: True if the reference tree node is for a data variable, False otherwise - :rtype: bool + :return: Secondary object of the relationship + :rtype: Union[DataVariable, Function, int, tuple[int, ProjectFile], tuple[str, ProjectFile]] """ - return core.BNFirmwareNinjaReferenceNodeIsDataVariable(self._handle) + if core.BNFirmwareNinjaRelationshipSecondaryIsDataVariable(self.handle): + return self._secondary_data_variable + elif core.BNFirmwareNinjaRelationshipSecondaryIsFunction(self.handle): + return self._secondary_function + elif core.BNFirmwareNinjaRelationshipSecondaryIsAddress(self.handle): + return self._secondary_address + elif core.BNFirmwareNinjaRelationshipSecondaryIsExternalAddress(self.handle): + return self._secondary_address, self._secondary_external_project_file + elif core.BNFirmwareNinjaRelationshipSecondaryIsExternalSymbol(self.handle): + return self._secondary_external_symbol, self._secondary_external_project_file + else: + return None + + @secondary.setter + def secondary( + self, obj: Union[DataVariable, Function, int, str], project_file: Optional[ProjectFile] = None + ) -> None: + if isinstance(obj, str) and not project_file: + raise ValueError("Secondary object can only be a symbol string if external project file is provided") + + if project_file and not (isinstance(obj, int) or isinstance(obj, str)): + raise ValueError("Secondary object must be an integer address or symbol if external project file is provided") - def has_children(self) -> bool: + if isinstance(obj, DataVariable): + core.BNFirmwareNinjaRelationshipSetSecondaryDataVariable(self.handle, obj.address) + elif isinstance(obj, Function): + core.BNFirmwareNinjaRelationshipSetSecondaryFunction(self.handle, obj.handle) + elif isinstance(obj, int): + if project_file: + core.BNFirmwareNinjaRelationshipSetSecondaryExternalAddress(self.handle, project_file._handle, obj) + else: + core.BNFirmwareNinjaRelationshipSetSecondaryAddress(self.handle, obj) + elif isinstance(obj, str): + core.BNFirmwareNinjaRelationshipSetSecondaryExternalSymbol(self.handle, project_file._handle, obj) + + @property + def description(self) -> str: """ - ``has_children`` determines if the reference tree node contains child reference tree nodes + ``description`` returns the description of the relationship - :return: True if the reference tree node contains children, False otherwise - :rtype: bool + :return: Description of the relationship + :rtype: str """ - return core.BNFirmwareNinjaReferenceNodeHasChildren(self._handle) + return core.BNFirmwareNinjaRelationshipGetDescription(self.handle) + + @description.setter + def description(self, description: str) -> None: + core.BNFirmwareNinjaRelationshipSetDescription(self.handle, description) @property - def function(self) -> Function: + def provenance(self) -> str: """ - ``function`` query the function from the reference tree node + ``provenance`` returns the provenance of the relationship - :return: Function contained in the reference tree node - :rtype: Function + :return: Provenance of the relationship + :rtype: str """ + return core.BNFirmwareNinjaRelationshipGetProvenance(self.handle) + + @provenance.setter + def provenance(self, provenance: str) -> None: + core.BNFirmwareNinjaRelationshipSetProvenance(self.handle, provenance) + + @property + def guid(self) -> str: + """ + ``guid`` returns the GUID of the relationship + + :return: GUID of the relationship + :rtype: str + """ + + return core.BNFirmwareNinjaRelationshipGetGuid(self.handle) + + +class FirmwareNinjaReferenceNode: + """ + ``class FirmwareNinjaReferenceNode`` is a class for building reference trees for functions, data variables, and + memory regions. This class is only available in the Ultimate Edition of Binary Ninja. + """ + + def __init__(self, handle=None, view=None): + assert handle is not None, "Cannot create reference node directly, run `FirmwareNinja.get_reference_tree`" + self._handle = handle + self._view = view + + def __del__(self): + if core is not None: + core.BNFreeFirmwareNinjaReferenceNode(self._handle) + + @property + def _function(self) -> Function: bn_function = core.BNFirmwareNinjaReferenceNodeGetFunction(self._handle) if not bn_function: return None @@ -95,44 +264,56 @@ class FirmwareNinjaReferenceNode: return Function(handle=bn_function) @property - def data_variable(self) -> DataVariable: - """ - ``data_variable`` query the data variable from the reference tree node + def _data_variable(self) -> DataVariable: + bn_data_var = core.BNDataVariable() + if not core.BNFirmwareNinjaReferenceNodeGetDataVariable(self._handle, ctypes.byref(bn_data_var)): + return None - :return: Data variable contained in the reference tree node - :rtype: DataVariable + result = None + try: + result = DataVariable.from_core_struct(bn_data_var, self._view) + finally: + core.BNFreeDataVariable(ctypes.byref(bn_data_var)) + + return result; + + @property + def object(self) -> Union[Function, DataVariable]: """ + ``object`` returns the function or data variable contained in the reference tree node, or None if the object is + a root node and only contains children - try: - bn_data_var = core.BNFirmwareNinjaReferenceNodeGetDataVariable( - self._handle) - if not bn_data_var: - return None + :return: Object contained in the reference tree node + :rtype: Union[Function, DataVariable] + """ - data_var = DataVariable.from_core_struct(bn_data_var.contents, self._view) - finally: - core.BNFreeDataVariable(bn_data_var) - return data_var + if core.BNFirmwareNinjaReferenceNodeIsFunction(self._handle): + return self._function + elif core.BNFirmwareNinjaReferenceNodeIsDataVariable(self._handle): + return self._data_variable + else: + return None @property - def children(self) -> list['FirmwareNinjaReferenceNode']: + def children(self) -> list["FirmwareNinjaReferenceNode"]: """ - ``children`` query the child reference tree nodes + ``children`` returns the child nodes contained in the reference tree node :return: Child nodes contained in the reference tree node :rtype: list[FirmwareNinjaReferenceNode] """ + if not core.BNFirmwareNinjaReferenceNodeHasChildren(self._handle): + return [] + count = ctypes.c_ulonglong(0) nodes = [] try: - bn_nodes = core.BNFirmwareNinjaReferenceNodeGetChildren( - self._handle, count) + bn_nodes = core.BNFirmwareNinjaReferenceNodeGetChildren(self._handle, count) for i in range(count.value): nodes.append( - FirmwareNinjaReferenceNode( - core.BNNewFirmwareNinjaReferenceNodeReference( - bn_nodes[i]), self._view)) + FirmwareNinjaReferenceNode(core.BNNewFirmwareNinjaReferenceNodeReference(bn_nodes[i]), self._view) + ) finally: core.BNFreeFirmwareNinjaReferenceNodes(bn_nodes, count.value) @@ -143,7 +324,8 @@ class FirmwareNinjaReferenceNode: class FirmwareNinjaDevice: """ ``class FirmwareNinjaDevice`` is a class that stores information about a hardware device, including the device - name, start address, size, and information about the device. + name, start address, size, and information about the device. This class is only available in the Ultimate Edition + of Binary Ninja. """ name: str @@ -156,7 +338,8 @@ class FirmwareNinjaDevice: class FirmwareNinjaSection: """ ``class FirmwareNinjaSection`` is a class that stores information about a section identified with Firmware Ninja - analysis, including the section type, start address, size, and entropy of the section. + analysis, including the section type, start address, size, and entropy. This class is only available in the + Ultimate Edition of Binary Ninja. """ type: FirmwareNinjaSectionType @@ -169,7 +352,8 @@ class FirmwareNinjaSection: class FirmwareNinjaMemoryAccess: """ ``class FirmwareNinjaMemoryAccess`` is a class that stores information on instructions that access regions of - memory that are not file-backed, such as memory-mapped I/O and RAM. + memory that are not file-backed, such as memory-mapped I/O and RAM. This class is only available in the Ultimate + Edition of Binary Ninja. """ instr_address: int @@ -179,9 +363,7 @@ class FirmwareNinjaMemoryAccess: value: RegisterValue @classmethod - def from_BNFirmwareNinjaMemoryAccess( - cls, access: core.BNFirmwareNinjaMemoryAccess - ) -> "FirmwareNinjaMemoryAccess": + def from_BNFirmwareNinjaMemoryAccess(cls, access: core.BNFirmwareNinjaMemoryAccess) -> "FirmwareNinjaMemoryAccess": return cls( instr_address=access.instrAddress, mem_address=RegisterValue.from_BNRegisterValue(access.memAddress), @@ -191,9 +373,7 @@ class FirmwareNinjaMemoryAccess: ) @classmethod - def to_BNFirmwareNinjaMemoryAccess( - cls, access: "FirmwareNinjaMemoryAccess" - ) -> core.BNFirmwareNinjaMemoryAccess: + def to_BNFirmwareNinjaMemoryAccess(cls, access: "FirmwareNinjaMemoryAccess") -> core.BNFirmwareNinjaMemoryAccess: return core.BNFirmwareNinjaMemoryAccess( instrAddress=access.instr_address, memAddress=RegisterValue.to_BNRegisterValue(access.mem_address), @@ -207,7 +387,8 @@ class FirmwareNinjaMemoryAccess: class FirmwareNinjaFunctionMemoryAccesses: """ ``class FirmwareNinjaFunctionMemoryAccesses`` is a class that stores information on accesses made by a function - to memory regions that are not file-backed, such as memory-mapped I/O and RAM. + to memory regions that are not file-backed, such as memory-mapped I/O and RAM. This class is only available in the + Ultimate Edition of Binary Ninja. """ function: Function @@ -222,9 +403,7 @@ class FirmwareNinjaFunctionMemoryAccesses: accesses = [] for i in range(info.count): access = info.accesses[i] - accesses.append( - FirmwareNinjaMemoryAccess.from_BNFirmwareNinjaMemoryAccess( - access.contents)) + accesses.append(FirmwareNinjaMemoryAccess.from_BNFirmwareNinjaMemoryAccess(access.contents)) return cls( function=view.get_function_at(info.start), @@ -237,7 +416,8 @@ class FirmwareNinjaDeviceAccesses: """ ``class FirmwareNinjaDeviceAccesses`` is a class that stores information on the number of accesses to hardware devices for each board that is compatible with the current architecture. This information can be used to identify - a board based on the number of accesses to hardware devices. + a board based on the number of accesses to hardware devices. This class is only available in the Ultimate Edition + of Binary Ninja. """ board_name: str @@ -247,8 +427,8 @@ class FirmwareNinjaDeviceAccesses: class FirmwareNinja: """ - ``class FirmwareNinja`` is a class that aids in analysis of embedded firmware images. This class is only available - in the Ultimate Edition of Binary Ninja. + ``class FirmwareNinja`` is a class that aids in analysis of firmware binaries. This class is only available in the + Ultimate Edition of Binary Ninja. :Example: @@ -267,8 +447,7 @@ class FirmwareNinja: if core is not None: core.BNFreeFirmwareNinja(self._handle) - def store_custom_device(self, name: str, start: int, size: int, - info: str) -> bool: + def store_custom_device(self, name: str, start: int, size: int, info: str) -> bool: """ ``store_custom_device`` stores a user-defined Firmware Ninja device in the binary view metadata @@ -280,8 +459,7 @@ class FirmwareNinja: :rtype: bool """ - return core.BNFirmwareNinjaStoreCustomDevice(self._handle, name, start, - start + size, info) + return core.BNFirmwareNinjaStoreCustomDevice(self._handle, name, start, start + size, info) def remove_custom_device(self, name: str) -> bool: """ @@ -295,17 +473,17 @@ class FirmwareNinja: return core.BNFirmwareNinjaRemoveCustomDevice(self._handle, name) - def query_custom_devices(self) -> list[FirmwareNinjaDevice]: + @property + def user_devices(self) -> list[FirmwareNinjaDevice]: """ - ``query_custom_devices`` queries user-defined Firmware Ninja devices from the binary view metadata + ``user_devices`` queries user-defined Firmware Ninja devices from the binary view metadata :return: List of Firmware Ninja devices :rtype: list[FirmwareNinjaDevice] """ devices = ctypes.POINTER(core.BNFirmwareNinjaDevice)() - count = core.BNFirmwareNinjaQueryCustomDevices(self._handle, - ctypes.byref(devices)) + count = core.BNFirmwareNinjaQueryCustomDevices(self._handle, ctypes.byref(devices)) if count == -1: raise RuntimeError("BNFirmwareNinjaQueryCustomDevices") @@ -318,15 +496,17 @@ class FirmwareNinja: start=devices[i].start, size=devices[i].end - devices[i].start, info=devices[i].info, - )) + ) + ) return device_list finally: core.BNFirmwareNinjaFreeDevices(devices, count) - def query_board_names(self) -> list[str]: + @property + def boards(self) -> list[str]: """ - ``query_board_names`` queries the name of all boards that are compatible with the current architecture + ``boards`` queries the name of all boards that are compatible with the current architecture :return: List of board names :rtype: list[str] @@ -334,7 +514,8 @@ class FirmwareNinja: boards = ctypes.POINTER(ctypes.c_char_p)() count = core.BNFirmwareNinjaQueryBoardNamesForArchitecture( - self._handle, self._view.arch.handle, ctypes.byref(boards)) + self._handle, self._view.arch.handle, ctypes.byref(boards) + ) if count == -1: raise RuntimeError("BNFirmwareNinjaQueryBoardNamesForArchitecture") @@ -347,15 +528,14 @@ class FirmwareNinja: finally: core.BNFirmwareNinjaFreeBoardNames(boards, count) - def query_devices_by_board_name(self, - name: str) -> list[FirmwareNinjaDevice]: + def get_devices_for_board(self, name: str) -> list[FirmwareNinjaDevice]: """ - ``query_devices_by_board_name`` queries the hardware device information for a specific board + ``get_devices_for_board`` queries the hardware device information for a specific board :Example: >>> fwn = FirmwareNinja(bv) - >>> fwn.query_devices_by_board_name(fwn.query_board_names()[0])[0] + >>> fwn.get_devices_for_board(fwn.boards[0])[0] FirmwareNinjaDevice(name='nand@12f', start=303, size=1024, info='marvell,orion-nand') :param str name: Name of the board @@ -364,10 +544,7 @@ class FirmwareNinja: """ devices = ctypes.POINTER(core.BNFirmwareNinjaDevice)() - count = core.BNFirmwareNinjaQueryBoardDevices(self._handle, - self._view.arch.handle, - name, - ctypes.byref(devices)) + count = core.BNFirmwareNinjaQueryBoardDevices(self._handle, self._view.arch.handle, name, ctypes.byref(devices)) if count == -1: raise RuntimeError("BNFirmwareNinjaQueryBoardDevices") @@ -380,35 +557,36 @@ class FirmwareNinja: start=devices[i].start, size=devices[i].end - devices[i].start, info=devices[i].info, - )) + ) + ) return device_list finally: core.BNFirmwareNinjaFreeDevices(devices, count) - def find_sections( + def get_sections_from_entropy( self, high_code_entropy_threshold: float = 0.910, low_code_entropy_threshold: float = 0.500, block_size: int = 4096, - mode: FirmwareNinjaSectionAnalysisMode = FirmwareNinjaSectionAnalysisMode - .DetectStringsSectionAnalysisMode, + mode: FirmwareNinjaSectionAnalysisMode = FirmwareNinjaSectionAnalysisMode.DetectStringsSectionAnalysisMode, ) -> list[FirmwareNinjaSection]: """ - ``find_sections`` finds sections with Firmware Ninja entropy analysis and heuristics + ``get_sections_from_entropy`` uses entropy analysis and heuristics to identify code, data, padding, and + compressed sections in the file-backed regions of the binary view :Example: >>> fwn = FirmwareNinja(bv) - >>> fwn.find_sections(block_size=2048)[0].entropy + >>> fwn.get_sections_from_entropy(block_size=2048)[0].entropy 0.48716872930526733 - >>> fwn.find_sections(block_size=2048)[0].type + >>> fwn.get_sections_from_entropy(block_size=2048)[0].type <FirmwareNinjaSectionType.DataSectionType: 1> :param float high_code_entropy_threshold: High code entropy threshold :param float low_code_entropy_threshold: Low code entropy threshold :param int block_size: Block size - :param str mode: Analysis mode + :param FirmwareNinjaSectionAnalysisMode mode: Analysis mode :return: List of sections :rtype: list[FirmwareNinjaSection] """ @@ -434,16 +612,14 @@ class FirmwareNinja: start=sections[i].start, size=sections[i].end - sections[i].start, entropy=sections[i].entropy, - )) + ) + ) return section_list finally: core.BNFirmwareNinjaFreeSections(sections, count) - def get_function_memory_accesses( - self, - progress_func: Callable = None - ) -> list[FirmwareNinjaFunctionMemoryAccesses]: + def get_function_memory_accesses(self, progress_func: Callable = None) -> list[FirmwareNinjaFunctionMemoryAccesses]: """ ``get_function_memory_accesses`` runs analysis to find accesses to memory regions that are not file-backed, such as memory-mapped I/O and RAM @@ -453,20 +629,19 @@ class FirmwareNinja: :rtype: list[FirmwareNinjaFunctionMemoryAccesses] """ - fma_info = ctypes.POINTER( - (ctypes.POINTER(core.BNFirmwareNinjaFunctionMemoryAccesses)))() + fma_info = ctypes.POINTER((ctypes.POINTER(core.BNFirmwareNinjaFunctionMemoryAccesses)))() if progress_func is None: - progress_cfunc = ctypes.CFUNCTYPE( - ctypes.c_bool, ctypes.c_void_p, ctypes.c_ulonglong, - ctypes.c_ulonglong)(lambda ctxt, cur, total: True) + progress_cfunc = ctypes.CFUNCTYPE(ctypes.c_bool, ctypes.c_void_p, ctypes.c_ulonglong, ctypes.c_ulonglong)( + lambda ctxt, cur, total: True + ) else: - progress_cfunc = ctypes.CFUNCTYPE( - ctypes.c_bool, ctypes.c_void_p, ctypes.c_ulonglong, - ctypes.c_ulonglong)( - lambda ctxt, cur, total: progress_func(cur, total)) + progress_cfunc = ctypes.CFUNCTYPE(ctypes.c_bool, ctypes.c_void_p, ctypes.c_ulonglong, ctypes.c_ulonglong)( + lambda ctxt, cur, total: progress_func(cur, total) + ) count = core.BNFirmwareNinjaGetFunctionMemoryAccesses( - self._handle, ctypes.byref(fma_info), progress_cfunc, None) + self._handle, ctypes.byref(fma_info), progress_cfunc, None + ) if count == -1: raise RuntimeError("BNFirmwareNinjaGetFunctionMemoryAccesses") @@ -474,28 +649,21 @@ class FirmwareNinja: fma_info_list = [] for i in range(count): fma_info_list.append( - FirmwareNinjaFunctionMemoryAccesses. - from_BNFirmwareNinjaFunctionMemoryAccesses( - fma_info[i].contents, self._view)) + FirmwareNinjaFunctionMemoryAccesses.from_BNFirmwareNinjaFunctionMemoryAccesses( + fma_info[i].contents, self._view + ) + ) return fma_info_list finally: core.BNFirmwareNinjaFreeFunctionMemoryAccesses(fma_info, count) - def _fma_info_list_to_array( - self, - fma: list[FirmwareNinjaFunctionMemoryAccesses]) -> ctypes.POINTER: - fma_info_ptr_array = ( - ctypes.POINTER(core.BNFirmwareNinjaFunctionMemoryAccesses) * - len(fma))() + def _fma_info_list_to_array(self, fma: list[FirmwareNinjaFunctionMemoryAccesses]) -> ctypes.POINTER: + fma_info_ptr_array = (ctypes.POINTER(core.BNFirmwareNinjaFunctionMemoryAccesses) * len(fma))() for i, info in enumerate(fma): - accesses_ptr_array = ( - ctypes.POINTER(core.BNFirmwareNinjaMemoryAccess) * - len(info.accesses))() + accesses_ptr_array = (ctypes.POINTER(core.BNFirmwareNinjaMemoryAccess) * len(info.accesses))() for j, access in enumerate(info.accesses): - accesses_ptr_array[j] = ctypes.pointer( - FirmwareNinjaMemoryAccess.to_BNFirmwareNinjaMemoryAccess( - access)) + accesses_ptr_array[j] = ctypes.pointer(FirmwareNinjaMemoryAccess.to_BNFirmwareNinjaMemoryAccess(access)) fma_info_struct = core.BNFirmwareNinjaFunctionMemoryAccesses( start=info.function.start, @@ -507,8 +675,7 @@ class FirmwareNinja: return fma_info_ptr_array - def store_function_memory_accesses( - self, fma: list[FirmwareNinjaFunctionMemoryAccesses]) -> None: + def store_function_memory_accesses(self, fma: list[FirmwareNinjaFunctionMemoryAccesses]) -> None: """ ``store_function_memory_accesses`` saves information on function memory accesses to binary view metadata @@ -519,16 +686,12 @@ class FirmwareNinja: >>> fwn.store_function_memory_accesses(fma) :param list[FirmwareNinjaFunctionMemoryAccesses] fma: List of function memory accesses - :return: None - :rtype: None """ fma_info_ptr_array = self._fma_info_list_to_array(fma) - core.BNFirmwareNinjaStoreFunctionMemoryAccessesToMetadata( - self._handle, fma_info_ptr_array, len(fma)) + core.BNFirmwareNinjaStoreFunctionMemoryAccessesToMetadata(self._handle, fma_info_ptr_array, len(fma)) - def query_function_memory_accesses( - self) -> list[FirmwareNinjaFunctionMemoryAccesses]: + def query_function_memory_accesses(self) -> list[FirmwareNinjaFunctionMemoryAccesses]: """ ``query_function_memory_accesses`` queries information on function memory accesses from binary view metadata @@ -536,10 +699,8 @@ class FirmwareNinja: :rtype: list[FirmwareNinjaFunctionMemoryAccesses] """ - fma = ctypes.POINTER( - (ctypes.POINTER(core.BNFirmwareNinjaFunctionMemoryAccesses)))() - count = core.BNFirmwareNinjaQueryFunctionMemoryAccessesFromMetadata( - self._handle, ctypes.byref(fma)) + fma = ctypes.POINTER((ctypes.POINTER(core.BNFirmwareNinjaFunctionMemoryAccesses)))() + count = core.BNFirmwareNinjaQueryFunctionMemoryAccessesFromMetadata(self._handle, ctypes.byref(fma)) if count == -1: return None @@ -547,9 +708,10 @@ class FirmwareNinja: fma_info_list = [] for i in range(count): fma_info_list.append( - FirmwareNinjaFunctionMemoryAccesses. - from_BNFirmwareNinjaFunctionMemoryAccesses( - fma[i].contents, self._view)) + FirmwareNinjaFunctionMemoryAccesses.from_BNFirmwareNinjaFunctionMemoryAccesses( + fma[i].contents, self._view + ) + ) return fma_info_list finally: @@ -577,8 +739,8 @@ class FirmwareNinja: fma_info_ptr_array = self._fma_info_list_to_array(fma) device_accesses = ctypes.POINTER(core.BNFirmwareNinjaDeviceAccesses)() count = core.BNFirmwareNinjaGetBoardDeviceAccesses( - self._handle, fma_info_ptr_array, len(fma), - ctypes.byref(device_accesses), self._view.arch.handle) + self._handle, fma_info_ptr_array, len(fma), ctypes.byref(device_accesses), self._view.arch.handle + ) if count == -1: raise RuntimeError("BNFirmwareNinjaGetBoardDeviceAccesses") @@ -590,19 +752,21 @@ class FirmwareNinja: board_name=device_accesses[i].name, total=device_accesses[i].total, unique=device_accesses[i].unique, - )) + ) + ) return device_accesses_list finally: core.BNFirmwareNinjaFreeBoardDeviceAccesses(device_accesses, count) def get_reference_tree( - self, - location: Union[Section, FirmwareNinjaDevice, Function, DataVariable, int], - fma: list[FirmwareNinjaFunctionMemoryAccesses], - value: Optional[int] = None) -> FirmwareNinjaReferenceNode: + self, + location: Union[Section, FirmwareNinjaDevice, Function, DataVariable, int], + fma: list[FirmwareNinjaFunctionMemoryAccesses], + value: Optional[int] = None, + ) -> FirmwareNinjaReferenceNode: """ - ``get_reference_tree`` returns a tree of references for a memory region, function, or data location + ``get_reference_tree`` returns a tree of reference nodes for a memory region, function, or address :param Union[Section, FirmwareNinjaDevice, DataVariable, Function, int] location: Memory location to build the reference tree for @@ -616,8 +780,7 @@ class FirmwareNinja: if fma is None and (isinstance(location, Section) or isinstance(location, FirmwareNinjaDevice)): raise ValueError("Function memory accesses cannot be None for location type Section or FirmwareNinjaDevice") - value = ctypes.pointer( - ctypes.c_uint64(value)) if value is not None else None + value = ctypes.pointer(ctypes.c_uint64(value)) if value is not None else None fma_info_ptr_array = None if fma is not None and len(fma) > 0: @@ -625,23 +788,24 @@ class FirmwareNinja: if isinstance(location, FirmwareNinjaDevice): bn_node = core.BNFirmwareNinjaGetMemoryRegionReferenceTree( - self._handle, location.start, location.start + location.size, - fma_info_ptr_array, len(fma), value) + self._handle, location.start, location.start + location.size, fma_info_ptr_array, len(fma), value + ) elif isinstance(location, Function): bn_node = core.BNFirmwareNinjaGetAddressReferenceTree( - self._handle, location.start, fma_info_ptr_array, len(fma), - value) + self._handle, location.start, fma_info_ptr_array, len(fma), value + ) elif isinstance(location, Section): bn_node = core.BNFirmwareNinjaGetMemoryRegionReferenceTree( - self._handle, location.start, location.start + location.length, - fma_info_ptr_array, len(fma), value) + self._handle, location.start, location.start + location.length, fma_info_ptr_array, len(fma), value + ) elif isinstance(location, DataVariable): bn_node = core.BNFirmwareNinjaGetAddressReferenceTree( - self._handle, location.address, fma_info_ptr_array, len(fma), - value) + self._handle, location.address, fma_info_ptr_array, len(fma), value + ) elif isinstance(location, int): bn_node = core.BNFirmwareNinjaGetAddressReferenceTree( - self._handle, location, fma_info_ptr_array, len(fma), value) + self._handle, location, fma_info_ptr_array, len(fma), value + ) else: raise ValueError("Invalid location type") @@ -649,3 +813,59 @@ class FirmwareNinja: return None return FirmwareNinjaReferenceNode(handle=bn_node, view=self._view) + + @property + def relationships(self) -> list[FirmwareNinjaRelationship]: + """ + ``relationships`` queries all Firmware Ninja relationships from the binary view metadata + + :return: List of relationships + :rtype: list[FirmwareNinjaRelationship] + """ + + count = ctypes.c_ulonglong(0) + relationships = core.BNFirmwareNinjaQueryRelationships(self._handle, count) + relationship_list = [] + for i in range(count.value): + relationship_list.append(FirmwareNinjaRelationship(self._view, handle=relationships[i])) + + return relationship_list + + def add_relationship(self, relationship: FirmwareNinjaRelationship) -> None: + """ + ``add_relationship`` adds a relationship to the binary view metadata + + :param FirmwareNinjaRelationship relationship: Relationship to add + """ + + if relationship.primary is None: + raise ValueError("Primary object must be set") + + if relationship.secondary is None: + raise ValueError("Secondary object must be set") + + core.BNFirmwareNinjaAddRelationship(self._handle, relationship.handle) + + def get_relationship_by_guid(self, guid: str) -> FirmwareNinjaRelationship: + """ + ``get_relationship_by_guid`` queries a relationship from the binary view metadata by GUID + + :param str guid: GUID of the relationship + :return: Relationship + :rtype: FirmwareNinjaRelationship + """ + + relationship = core.BNFirmwareNinjaGetRelationshipByGuid(self._handle, guid) + if not relationship: + return None + + return FirmwareNinjaRelationship(self._view, handle=relationship) + + def remove_relationship_by_guid(self, guid: str) -> None: + """ + ``remove_relationship_by_guid`` removes a relationship from the binary view metadata by GUID + + :param str guid: GUID of the relationship + """ + + core.BNFirmwareNinjaRemoveRelationshipByGuid(self._handle, guid) diff --git a/ui/uicontext.h b/ui/uicontext.h index 0a4b54ea..6c541b9c 100644 --- a/ui/uicontext.h +++ b/ui/uicontext.h @@ -522,6 +522,7 @@ public: virtual ProjectRef openProject(const QString& path); virtual ViewFrame* openFileContext(FileContext* file, const QString& forcedView = "", bool addTab = true); virtual bool openProjectFile(ProjectFileRef file, ExternalLocationRef loc = nullptr, bool openWithOptions = false); + virtual bool openUrl(const QUrl& url, bool openWithOptions = false); virtual void recreateViewFrames(FileContext* file) = 0; UIActionHandler* globalActions() { return &m_globalActions; } |
