// Copyright (c) 2015-2022 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 using namespace BinaryNinja; using namespace std; struct WorkerThreadActionContext { std::function action; }; void BinaryNinja::DisablePlugins() { BNDisablePlugins(); } bool BinaryNinja::IsPluginsEnabled() { return BNIsPluginsEnabled(); } bool BinaryNinja::InitPlugins(bool allowUserPlugins) { return BNInitPlugins(allowUserPlugins); } void BinaryNinja::InitCorePlugins() { BNInitCorePlugins(); } void BinaryNinja::InitUserPlugins() { BNInitUserPlugins(); } void BinaryNinja::InitRepoPlugins() { BNInitRepoPlugins(); } string BinaryNinja::GetBundledPluginDirectory() { char* path = BNGetBundledPluginDirectory(); if (!path) return string(); string result = path; BNFreeString(path); return result; } void BinaryNinja::SetBundledPluginDirectory(const string& path) { BNSetBundledPluginDirectory(path.c_str()); } string BinaryNinja::GetUserDirectory(void) { char* dir = BNGetUserDirectory(); if (!dir) return string(); string result(dir); BNFreeString(dir); return result; } string BinaryNinja::GetSettingsFileName() { char* dir = BNGetSettingsFileName(); if (!dir) return string(); string result(dir); BNFreeString(dir); return result; } string BinaryNinja::GetRepositoriesDirectory() { char* dir = BNGetRepositoriesDirectory(); if (!dir) return string(); string result(dir); BNFreeString(dir); return result; } string BinaryNinja::GetInstallDirectory() { char* path = BNGetInstallDirectory(); if (!path) return string(); string result = path; BNFreeString(path); return result; } string BinaryNinja::GetUserPluginDirectory() { char* path = BNGetUserPluginDirectory(); if (!path) return string(); string result = path; BNFreeString(path); return result; } string BinaryNinja::GetPathRelativeToBundledPluginDirectory(const string& rel) { char* path = BNGetPathRelativeToBundledPluginDirectory(rel.c_str()); if (!path) return rel; string result = path; BNFreeString(path); return result; } string BinaryNinja::GetPathRelativeToUserPluginDirectory(const string& rel) { char* path = BNGetPathRelativeToUserPluginDirectory(rel.c_str()); if (!path) return rel; string result = path; BNFreeString(path); return result; } string BinaryNinja::GetPathRelativeToUserDirectory(const string& rel) { char* path = BNGetPathRelativeToUserDirectory(rel.c_str()); if (!path) return rel; string result = path; BNFreeString(path); return result; } bool BinaryNinja::ExecuteWorkerProcess(const string& path, const vector& args, const DataBuffer& input, string& output, string& errors, bool stdoutIsText, bool stderrIsText) { const char** argArray = new const char*[args.size() + 1]; for (size_t i = 0; i < args.size(); i++) argArray[i] = args[i].c_str(); argArray[args.size()] = nullptr; char* outputStr; char* errorStr; bool result = BNExecuteWorkerProcess( path.c_str(), argArray, input.GetBufferObject(), &outputStr, &errorStr, stdoutIsText, stderrIsText); output = outputStr; errors = errorStr; BNFreeString(outputStr); BNFreeString(errorStr); delete[] argArray; return result; } string BinaryNinja::GetVersionString() { char* str = BNGetVersionString(); string result = str; BNFreeString(str); return result; } string BinaryNinja::GetLicensedUserEmail() { char* str = BNGetLicensedUserEmail(); string result = str; BNFreeString(str); return result; } string BinaryNinja::GetProduct() { char* str = BNGetProduct(); string result = str; BNFreeString(str); return result; } string BinaryNinja::GetProductType() { char* str = BNGetProductType(); string result = str; BNFreeString(str); return result; } string BinaryNinja::GetSerialNumber() { char* str = BNGetSerialNumber(); string result = str; BNFreeString(str); return result; } int BinaryNinja::GetLicenseCount() { return BNGetLicenseCount(); } bool BinaryNinja::IsUIEnabled() { return BNIsUIEnabled(); } uint32_t BinaryNinja::GetBuildId() { return BNGetBuildId(); } void BinaryNinja::SetCurrentPluginLoadOrder(BNPluginLoadOrder order) { BNSetCurrentPluginLoadOrder(order); } void BinaryNinja::AddRequiredPluginDependency(const string& name) { BNAddRequiredPluginDependency(name.c_str()); } void BinaryNinja::AddOptionalPluginDependency(const string& name) { BNAddOptionalPluginDependency(name.c_str()); } static void WorkerActionCallback(void* ctxt) { WorkerThreadActionContext* action = (WorkerThreadActionContext*)ctxt; action->action(); delete action; } void BinaryNinja::WorkerEnqueue(const function& action) { WorkerThreadActionContext* ctxt = new WorkerThreadActionContext; ctxt->action = action; BNWorkerEnqueue(ctxt, WorkerActionCallback); } void BinaryNinja::WorkerEnqueue(RefCountObject* owner, const function& action) { struct { Ref owner; function func; } context; context.owner = owner; context.func = action; WorkerEnqueue([=]() { context.func(); }); } void BinaryNinja::WorkerPriorityEnqueue(const function& action) { WorkerThreadActionContext* ctxt = new WorkerThreadActionContext; ctxt->action = action; BNWorkerPriorityEnqueue(ctxt, WorkerActionCallback); } void BinaryNinja::WorkerPriorityEnqueue(RefCountObject* owner, const function& action) { struct { Ref owner; function func; } context; context.owner = owner; context.func = action; WorkerPriorityEnqueue([=]() { context.func(); }); } void BinaryNinja::WorkerInteractiveEnqueue(const function& action) { WorkerThreadActionContext* ctxt = new WorkerThreadActionContext; ctxt->action = action; BNWorkerInteractiveEnqueue(ctxt, WorkerActionCallback); } void BinaryNinja::WorkerInteractiveEnqueue(RefCountObject* owner, const function& action) { struct { Ref owner; function func; } context; context.owner = owner; context.func = action; WorkerInteractiveEnqueue([=]() { context.func(); }); } size_t BinaryNinja::GetWorkerThreadCount() { return BNGetWorkerThreadCount(); } void BinaryNinja::SetWorkerThreadCount(size_t count) { BNSetWorkerThreadCount(count); } string BinaryNinja::GetUniqueIdentifierString() { char* str = BNGetUniqueIdentifierString(); string result = str; BNFreeString(str); return result; } map BinaryNinja::GetMemoryUsageInfo() { size_t count; BNMemoryUsageInfo* info = BNGetMemoryUsageInfo(&count); map result; for (size_t i = 0; i < count; i++) result[info[i].name] = info[i].value; BNFreeMemoryUsageInfo(info, count); return result; } std::function BinaryNinja::SplitProgress( std::function originalFn, size_t subpart, size_t subpartCount) { return SplitProgress(originalFn, subpart, std::vector(subpartCount, 1.0 / (double)subpartCount)); } std::function BinaryNinja::SplitProgress( std::function originalFn, size_t subpart, std::vector subpartWeights) { if (!originalFn) return [](size_t, size_t) { return true; }; // Normalize weights double weightSum = std::accumulate(subpartWeights.begin(), subpartWeights.end(), 0.0); if (weightSum < 0.0001f) return [](size_t, size_t) { return true; }; // Keep a running count of weights for the start std::vector subpartStarts; double start = 0.0; for (size_t i = 0; i < subpartWeights.size(); ++i) { subpartStarts.push_back(start); subpartWeights[i] /= weightSum; start += subpartWeights[i]; } return [=](size_t current, size_t max) { // Just use a large number for easy divisibility size_t steps = 1000000; double subpartSize = steps * subpartWeights[subpart]; double subpartProgress = ((double)current / (double)max) * subpartSize; return originalFn(subpartStarts[subpart] * steps + subpartProgress, steps); }; } bool BinaryNinja::ProgressCallback(void* ctxt, size_t current, size_t total) { ProgressContext* pctxt = reinterpret_cast(ctxt); if (!pctxt->callback) return true; return pctxt->callback(current, total); }