// Copyright (c) 2015-2025 Vector 35 Inc // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to // deal in the Software without restriction, including without limitation the // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or // sell copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS // IN THE SOFTWARE. #include "binaryninjaapi.h" #include "binaryninjacore.h" using namespace BinaryNinja; static BNFirmwareNinjaFunctionMemoryAccesses** MemoryInfoVectorToArray( const std::vector& fma) { BNFirmwareNinjaFunctionMemoryAccesses** result = new BNFirmwareNinjaFunctionMemoryAccesses*[fma.size()]; for (size_t i = 0; i < fma.size(); i++) { result[i] = new BNFirmwareNinjaFunctionMemoryAccesses; result[i]->start = fma[i].start; result[i]->count = fma[i].count; result[i]->accesses = new BNFirmwareNinjaMemoryAccess*[fma[i].count]; for (size_t j = 0; j < fma[i].count; j++) { result[i]->accesses[j] = new BNFirmwareNinjaMemoryAccess; std::memcpy(result[i]->accesses[j], &fma[i].accesses[j], sizeof(BNFirmwareNinjaMemoryAccess)); } } return result; } static void FreeMemoryInfoArray(BNFirmwareNinjaFunctionMemoryAccesses** fma, size_t count) { for (size_t i = 0; i < count; i++) { for (size_t j = 0; j < fma[i]->count; j++) delete fma[i]->accesses[j]; delete[] fma[i]->accesses; delete fma[i]; } } FirmwareNinjaRelationship::FirmwareNinjaRelationship(Ref view, BNFirmwareNinjaRelationship* handle) { if (handle) m_object = handle; else m_object = BNNewFirmwareNinjaRelationshipReference(BNCreateFirmwareNinjaRelationship(view->GetObject())); } 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) { 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 FirmwareNinjaRelationship::GetPrimaryAddress() const { std::optional result; uint64_t tmp; if (BNFirmwareNinjaRelationshipGetPrimaryAddress(m_object, &tmp)) result = tmp; return result; } Ref FirmwareNinjaRelationship::GetPrimaryFunction() const { auto bnFunction = BNFirmwareNinjaRelationshipGetPrimaryFunction(m_object); if (!bnFunction) return nullptr; return new Function(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) { BNFirmwareNinjaRelationshipSetSecondaryFunction(m_object, function->GetObject()); } void FirmwareNinjaRelationship::SetSecondaryExternalAddress(Ref projectFile, uint64_t address) { BNFirmwareNinjaRelationshipSetSecondaryExternalAddress(m_object, projectFile->GetObject(), address); } void FirmwareNinjaRelationship::SetSecondaryExternalSymbol(Ref 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 FirmwareNinjaRelationship::GetSecondaryExternalProjectFile() const { auto bnProjectFile = BNFirmwareNinjaRelationshipGetSecondaryExternalProjectFile(m_object); if (!bnProjectFile) return nullptr; return new ProjectFile(BNNewProjectFileReference(bnProjectFile)); } std::optional FirmwareNinjaRelationship::GetSecondaryAddress() const { std::optional 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 FirmwareNinjaRelationship::GetSecondaryFunction() const { auto bnFunction = BNFirmwareNinjaRelationshipGetSecondaryFunction(m_object); if (!bnFunction) return nullptr; return new Function(bnFunction); } std::string FirmwareNinjaRelationship::GetSecondaryExternalSymbol() const { auto bnSymbol = BNFirmwareNinjaRelationshipGetSecondaryExternalSymbol(m_object); if (!bnSymbol) return ""; std::string result = bnSymbol; BNFreeString(bnSymbol); return result; } void FirmwareNinjaRelationship::SetDescription(const std::string& description) { BNFirmwareNinjaRelationshipSetDescription(m_object, description.c_str()); } std::string FirmwareNinjaRelationship::GetDescription() const { auto bnDescription = BNFirmwareNinjaRelationshipGetDescription(m_object); if (!bnDescription) return ""; std::string result = bnDescription; BNFreeString(bnDescription); return result; } void FirmwareNinjaRelationship::SetProvenance(const std::string& provenance) { BNFirmwareNinjaRelationshipSetProvenance(m_object, provenance.c_str()); } std::string FirmwareNinjaRelationship::GetProvenance() const { auto bnProvenance = BNFirmwareNinjaRelationshipGetProvenance(m_object); if (!bnProvenance) return ""; std::string result = bnProvenance; BNFreeString(bnProvenance); return result; } std::string FirmwareNinjaRelationship::GetGuid() const { auto bnGuid = BNFirmwareNinjaRelationshipGetGuid(m_object); if (!bnGuid) return ""; std::string result = bnGuid; BNFreeString(bnGuid); return result; } FirmwareNinjaReferenceNode::FirmwareNinjaReferenceNode(BNFirmwareNinjaReferenceNode* node) { m_object = node; } FirmwareNinjaReferenceNode::~FirmwareNinjaReferenceNode() { BNFreeFirmwareNinjaReferenceNode(m_object); } bool FirmwareNinjaReferenceNode::IsFunction() { return BNFirmwareNinjaReferenceNodeIsFunction(m_object); } bool FirmwareNinjaReferenceNode::IsDataVariable() { return BNFirmwareNinjaReferenceNodeIsDataVariable(m_object); } bool FirmwareNinjaReferenceNode::HasChildren() { return BNFirmwareNinjaReferenceNodeHasChildren(m_object); } bool FirmwareNinjaReferenceNode::GetFunction(Ref& function) { auto bnFunction = BNFirmwareNinjaReferenceNodeGetFunction(m_object); if (!bnFunction) return false; function = new Function(bnFunction); return true; } bool FirmwareNinjaReferenceNode::GetDataVariable(DataVariable& variable) { 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); return true; } std::vector> FirmwareNinjaReferenceNode::GetChildren() { std::vector> result; size_t count = 0; auto bnChildren = BNFirmwareNinjaReferenceNodeGetChildren(m_object, &count); result.reserve(count); for (size_t i = 0; i < count; ++i) { result.push_back(new FirmwareNinjaReferenceNode( BNNewFirmwareNinjaReferenceNodeReference(bnChildren[i]))); } return result; } FirmwareNinja::FirmwareNinja(Ref view) { m_view = view; m_object = BNCreateFirmwareNinja(view->GetObject()); } FirmwareNinja::~FirmwareNinja() { BNFreeFirmwareNinja(m_object); } bool FirmwareNinja::StoreCustomDevice(FirmwareNinjaDevice& device) { return BNFirmwareNinjaStoreCustomDevice(m_object, device.name.c_str(), device.start, device.end, device.info.c_str()); } bool FirmwareNinja::RemoveCustomDevice(const std::string& name) { return BNFirmwareNinjaRemoveCustomDevice(m_object, name.c_str()); } std::vector FirmwareNinja::QueryCustomDevices() { std::vector result; BNFirmwareNinjaDevice* devices; int count = BNFirmwareNinjaQueryCustomDevices(m_object, &devices); if (count <= 0) return result; result.reserve(count); for (size_t i = 0; i < count; i++) result.push_back({ devices[i].name, devices[i].start, devices[i].end, devices[i].info }); BNFirmwareNinjaFreeDevices(devices, count); return result; } std::vector<:string> FirmwareNinja::QueryBoardNames() { std::vector<:string> result; char** boards; auto platform = m_view->GetDefaultPlatform(); if (!platform) return result; auto arch = platform->GetArchitecture(); if (!arch) return result; int count = BNFirmwareNinjaQueryBoardNamesForArchitecture(m_object, arch->GetObject(), &boards); if (count <= 0) return result; result.reserve(count); for (size_t i = 0; i < count; i++) result.push_back(boards[i]); BNFirmwareNinjaFreeBoardNames(boards, count); sort(result.begin(), result.end()); return result; } std::vector FirmwareNinja::QueryDevicesForBoard(const std::string& board) { std::vector result; BNFirmwareNinjaDevice* devices; auto platform = m_view->GetDefaultPlatform(); if (!platform) return result; auto arch = platform->GetArchitecture(); if (!arch) return result; int count = BNFirmwareNinjaQueryBoardDevices(m_object, arch->GetObject(), board.c_str(), &devices); if (count <= 0) return result; result.reserve(count); for (size_t i = 0; i < count; i++) result.push_back({ devices[i].name, devices[i].start, devices[i].end, devices[i].info }); BNFirmwareNinjaFreeDevices(devices, count); return result; } std::vector FirmwareNinja::FindSections(float highCodeEntropyThreshold, float lowCodeEntropyThreshold, size_t blockSize, BNFirmwareNinjaSectionAnalysisMode mode) { std::vector result; BNFirmwareNinjaSection* sections; int count = BNFirmwareNinjaFindSectionsWithEntropy(m_object, &sections, highCodeEntropyThreshold, lowCodeEntropyThreshold, blockSize, mode); if (count <= 0) return result; result.reserve(count); for (size_t i = 0; i < count; i++) result.push_back(sections[i]); BNFirmwareNinjaFreeSections(sections, count); return result; } std::vector FirmwareNinja::GetFunctionMemoryAccesses(BNProgressFunction progress, void* progressContext) { std::vector result; BNFirmwareNinjaFunctionMemoryAccesses** fma; int count = BNFirmwareNinjaGetFunctionMemoryAccesses(m_object, &fma, progress, progressContext); if (count <= 0) return result; result.reserve(count); for (size_t i = 0; i < count; i++) { FirmwareNinjaFunctionMemoryAccesses info; info.start = fma[i]->start; info.count = fma[i]->count; for (size_t j = 0; j < info.count; j++) { BNFirmwareNinjaMemoryAccess access; std::memcpy(&access, fma[i]->accesses[j], sizeof(BNFirmwareNinjaMemoryAccess)); info.accesses.push_back(access); } result.push_back(info); } BNFirmwareNinjaFreeFunctionMemoryAccesses(fma, count); std::sort(result.begin(), result.end(), [](const FirmwareNinjaFunctionMemoryAccesses& a, const FirmwareNinjaFunctionMemoryAccesses& b) { return a.count > b.count; }); return result; } void FirmwareNinja::StoreFunctionMemoryAccesses(const std::vector& fma) { if (fma.empty()) return; BNFirmwareNinjaFunctionMemoryAccesses** fmaArray = MemoryInfoVectorToArray(fma); BNFirmwareNinjaStoreFunctionMemoryAccessesToMetadata(m_object, fmaArray, fma.size()); FreeMemoryInfoArray(fmaArray, fma.size()); } std::vector FirmwareNinja::QueryFunctionMemoryAccesses() { std::vector result; BNFirmwareNinjaFunctionMemoryAccesses** fma; int count = BNFirmwareNinjaQueryFunctionMemoryAccessesFromMetadata(m_object, &fma); if (count <= 0) return result; result.reserve(count); for (size_t i = 0; i < count; i++) { FirmwareNinjaFunctionMemoryAccesses info; info.start = fma[i]->start; info.count = fma[i]->count; for (size_t j = 0; j < info.count; j++) { BNFirmwareNinjaMemoryAccess access; std::memcpy(&access, fma[i]->accesses[j], sizeof(BNFirmwareNinjaMemoryAccess)); info.accesses.push_back(access); } result.push_back(info); } BNFirmwareNinjaFreeFunctionMemoryAccesses(fma, count); std::sort(result.begin(), result.end(), [](const FirmwareNinjaFunctionMemoryAccesses& a, const FirmwareNinjaFunctionMemoryAccesses& b) { return a.count > b.count; }); return result; } std::vector FirmwareNinja::GetBoardDeviceAccesses( const std::vector& fma) { std::vector result; if (fma.empty()) return result; auto platform = m_view->GetDefaultPlatform(); if (!platform) return result; auto arch = platform->GetArchitecture(); if (!arch) return result; BNFirmwareNinjaFunctionMemoryAccesses** fmaArray = MemoryInfoVectorToArray(fma); BNFirmwareNinjaDeviceAccesses* accesses; int count = BNFirmwareNinjaGetBoardDeviceAccesses(m_object, fmaArray, fma.size(), &accesses, arch->GetObject()); FreeMemoryInfoArray(fmaArray, fma.size()); if (count <= 0) return result; result.reserve(count); for (size_t i = 0; i < count; i++) result.push_back({accesses[i].name, accesses[i].total, accesses[i].unique}); BNFirmwareNinjaFreeBoardDeviceAccesses(accesses, count); sort(result.begin(), result.end(), [](const FirmwareNinjaDeviceAccesses& a, const FirmwareNinjaDeviceAccesses& b) { return a.total > b.total; }); return result; } Ref FirmwareNinja::GetReferenceTree( FirmwareNinjaDevice& device, const std::vector& fma, uint64_t* value) { BNFirmwareNinjaFunctionMemoryAccesses** fmaArray = nullptr; if (!fma.empty()) fmaArray = MemoryInfoVectorToArray(fma); auto bnReferenceTree = BNFirmwareNinjaGetMemoryRegionReferenceTree( m_object, device.start, device.end, fmaArray, fma.size(), value); FreeMemoryInfoArray(fmaArray, fma.size()); if (!bnReferenceTree) return nullptr; return new FirmwareNinjaReferenceNode(BNNewFirmwareNinjaReferenceNodeReference(bnReferenceTree)); } Ref FirmwareNinja::GetReferenceTree( Section& section, const std::vector& fma, uint64_t* value) { BNFirmwareNinjaFunctionMemoryAccesses** fmaArray = nullptr; if (!fma.empty()) fmaArray = MemoryInfoVectorToArray(fma); auto bnReferenceTree = BNFirmwareNinjaGetMemoryRegionReferenceTree( m_object, section.GetStart(), section.GetStart() + section.GetLength(), fmaArray, fma.size(), value); FreeMemoryInfoArray(fmaArray, fma.size()); if (!bnReferenceTree) return nullptr; return new FirmwareNinjaReferenceNode(BNNewFirmwareNinjaReferenceNodeReference(bnReferenceTree)); } Ref FirmwareNinja::GetReferenceTree( uint64_t address, const std::vector& fma, uint64_t* value) { BNFirmwareNinjaFunctionMemoryAccesses** fmaArray = nullptr; if (!fma.empty()) fmaArray = MemoryInfoVectorToArray(fma); auto bnReferenceTree = BNFirmwareNinjaGetAddressReferenceTree(m_object, address, fmaArray, fma.size(), value); FreeMemoryInfoArray(fmaArray, fma.size()); if (!bnReferenceTree) return nullptr; return new FirmwareNinjaReferenceNode(BNNewFirmwareNinjaReferenceNodeReference(bnReferenceTree)); } std::vector> FirmwareNinja::QueryRelationships() { std::vector> 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]))); } BNFirmwareNinjaFreeRelationships(bnRelationships, count); return result; } void FirmwareNinja::AddRelationship(Ref relationship) { BNFirmwareNinjaAddRelationship(m_object, relationship->GetObject()); } Ref 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()); }