// Copyright (c) 2015-2026 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::GetSystemCacheDirectory()
{
char* dir = BNGetSystemCacheDirectory();
if (!dir)
return string();
std::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;
}
VersionInfo BinaryNinja::GetVersionInfo()
{
BNVersionInfo result = BNGetVersionInfo();
VersionInfo info;
info.major = result.major;
info.minor = result.minor;
info.build = result.build;
info.channel = "";
if (result.channel)
info.channel = result.channel;
BNFreeString(result.channel);
return info;
}
VersionInfo ParseVersionString(const string &version)
{
BNVersionInfo result = BNParseVersionString(version.c_str());
VersionInfo info;
info.major = result.major;
info.minor = result.minor;
info.build = result.build;
info.channel = "";
if (result.channel)
info.channel = result.channel;
BNFreeString(result.channel);
return info;
}
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, const std::string& name)
{
WorkerThreadActionContext* ctxt = new WorkerThreadActionContext;
ctxt->action = action;
BNWorkerEnqueueNamed(ctxt, WorkerActionCallback, name.c_str());
}
void BinaryNinja::WorkerEnqueue(RefCountObject* owner, const function& action, const std::string& name)
{
struct
{
Ref owner;
function func;
} context;
context.owner = owner;
context.func = action;
WorkerEnqueue([=]() { context.func(); }, name);
}
void BinaryNinja::WorkerPriorityEnqueue(const function& action, const std::string& name)
{
WorkerThreadActionContext* ctxt = new WorkerThreadActionContext;
ctxt->action = action;
BNWorkerPriorityEnqueueNamed(ctxt, WorkerActionCallback, name.c_str());
}
void BinaryNinja::WorkerPriorityEnqueue(RefCountObject* owner, const function& action, const std::string& name)
{
struct
{
Ref owner;
function func;
} context;
context.owner = owner;
context.func = action;
WorkerPriorityEnqueue([=]() { context.func(); }, name);
}
void BinaryNinja::WorkerInteractiveEnqueue(const function& action, const std::string& name)
{
WorkerThreadActionContext* ctxt = new WorkerThreadActionContext;
ctxt->action = action;
BNWorkerInteractiveEnqueueNamed(ctxt, WorkerActionCallback, name.c_str());
}
void BinaryNinja::WorkerInteractiveEnqueue(RefCountObject* owner, const function& action, const std::string& name)
{
struct
{
Ref owner;
function func;
} context;
context.owner = owner;
context.func = action;
WorkerInteractiveEnqueue([=]() { context.func(); }, name);
}
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;
}
bool BinaryNinja::DefaultProgressFunction(size_t, size_t)
{
return true;
}
BinaryNinja::ProgressFunction BinaryNinja::SplitProgress(
BinaryNinja::ProgressFunction originalFn, size_t subpart, size_t subpartCount)
{
return SplitProgress(originalFn, subpart, std::vector(subpartCount, 1.0 / (double)subpartCount));
}
BinaryNinja::ProgressFunction BinaryNinja::SplitProgress(
BinaryNinja::ProgressFunction 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;
subpartStarts.reserve(subpartWeights.size());
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);
}
fmt::format_context::iterator fmtByteString(const std::vector& string, fmt::format_context& ctx)
{
*ctx.out()++ = 'b';
*ctx.out()++ = '\"';
for (uint8_t ch: string)
{
if (ch == '\n')
{
*ctx.out()++ = '\\';
*ctx.out()++ = 'n';
}
else if (ch == '\r')
{
*ctx.out()++ = '\\';
*ctx.out()++ = 'r';
}
else if (ch == '\t')
{
*ctx.out()++ = '\\';
*ctx.out()++ = 't';
}
else if (ch == '\"')
{
*ctx.out()++ = '\\';
*ctx.out()++ = '\"';
}
else if (ch == '\\')
{
*ctx.out()++ = '\\';
*ctx.out()++ = '\\';
}
else if (ch < 0x20 || ch >= 0x7f)
{
fmt::format_to(ctx.out(), "\\x{:02x}", ch);
}
else
{
*ctx.out()++ = ch;
}
}
*ctx.out()++ = '\"';
return ctx.out();
}
fmt::format_context::iterator fmtQuotedString(const std::string& string, fmt::format_context& ctx)
{
*ctx.out()++ = '\"';
for (char ch: string)
{
if (ch == '\n')
{
*ctx.out()++ = '\\';
*ctx.out()++ = 'n';
}
else if (ch == '\r')
{
*ctx.out()++ = '\\';
*ctx.out()++ = 'r';
}
else if (ch == '\t')
{
*ctx.out()++ = '\\';
*ctx.out()++ = 't';
}
else if (ch == '\"')
{
*ctx.out()++ = '\\';
*ctx.out()++ = '\"';
}
else if (ch == '\\')
{
*ctx.out()++ = '\\';
*ctx.out()++ = '\\';
}
else if (ch < 0x20 || ch >= 0x7f)
{
fmt::format_to(ctx.out(), "\\x{:02x}", ch);
}
else
{
*ctx.out()++ = ch;
}
}
*ctx.out()++ = '\"';
return ctx.out();
}
fmt::format_context::iterator fmt::formatter<:metadata>::format(const BinaryNinja::Metadata& obj, format_context& ctx) const
{
switch (obj.GetType())
{
default:
case InvalidDataType:
return fmt::format_to(ctx.out(), "(invalid)");
case BooleanDataType:
return fmt::format_to(ctx.out(), "{}", obj.GetBoolean());
case StringDataType:
return fmt::format_to(ctx.out(), "{}", obj.GetString());
case UnsignedIntegerDataType:
return fmt::format_to(ctx.out(), "{}", obj.GetUnsignedInteger());
case SignedIntegerDataType:
return fmt::format_to(ctx.out(), "{}", obj.GetSignedInteger());
case DoubleDataType:
return fmt::format_to(ctx.out(), "{}", obj.GetDouble());
case RawDataType:
return fmtByteString(obj.GetRaw(), ctx);
case KeyValueDataType:
{
*ctx.out()++ = '{';
bool first = true;
for (auto& [name, value]: obj.GetKeyValueStore())
{
if (!first)
{
*ctx.out()++ = ',';
*ctx.out()++ = ' ';
}
first = false;
fmtQuotedString(name, ctx);
*ctx.out()++ = ':';
*ctx.out()++ = ' ';
fmt::format_to(ctx.out(), "{}", value);
}
*ctx.out()++ = '}';
return ctx.out();
}
case ArrayDataType:
*ctx.out()++ = '[';
bool first = true;
for (auto& value: obj.GetArray())
{
if (!first)
{
*ctx.out()++ = ',';
*ctx.out()++ = ' ';
}
first = false;
fmt::format_to(ctx.out(), "{}", value);
}
*ctx.out()++ = ']';
return ctx.out();
}
}
fmt::format_context::iterator fmt::formatter<:namelist>::format(const BinaryNinja::NameList& obj, format_context& ctx) const
{
return fmt::format_to(ctx.out(), "{}", obj.GetString());
}
std::optional BinaryNinja::FuzzyMatchSingle(const std::string& target, const std::string& query)
{
size_t result = BNFuzzyMatchSingle(target.c_str(), query.c_str());
if (result == 0)
{
return std::nullopt;
}
return result;
}
void BinaryNinja::SetThreadName(const std::string& name)
{
BNSetThreadName(name.c_str());
}