summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBrandon Miller <brandon@vector35.com>2025-02-03 16:33:46 -0500
committerBrandon Miller <brandon@vector35.com>2025-02-04 08:56:37 -0500
commited08160e6782b3f8b371370bfad3a04e80e94f4d (patch)
treecc73ad9a24301aed63b51b28a90a44cc4ac2550b
parent60ae03fed8aee9bc88c6d04023bcd3c922ec273e (diff)
Firmware Ninja relationships API
-rw-r--r--binaryninjaapi.h280
-rw-r--r--binaryninjacore.h44
-rw-r--r--firmwareninja.cpp300
-rw-r--r--python/firmwareninja.py530
-rw-r--r--ui/uicontext.h1
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; }