// 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 "lowlevelilinstruction.h"
#include "mediumlevelilinstruction.h"
#include "highlevelilinstruction.h"
using namespace BinaryNinja;
using namespace std;
PluginCommandContext::PluginCommandContext()
{
address = length = 0;
instrIndex = BN_INVALID_EXPR;
}
PluginCommand::PluginCommand(const BNPluginCommand& cmd)
{
m_command = cmd;
m_command.name = BNAllocString(cmd.name);
m_command.description = BNAllocString(cmd.description);
}
PluginCommand::PluginCommand(const PluginCommand& cmd)
{
m_command = cmd.m_command;
m_command.name = BNAllocString(cmd.m_command.name);
m_command.description = BNAllocString(cmd.m_command.description);
}
PluginCommand::~PluginCommand()
{
BNFreeString(m_command.name);
BNFreeString(m_command.description);
}
PluginCommand& PluginCommand::operator=(const PluginCommand& cmd)
{
BNFreeString(m_command.name);
BNFreeString(m_command.description);
m_command = cmd.m_command;
m_command.name = BNAllocString(cmd.m_command.name);
m_command.description = BNAllocString(cmd.m_command.description);
return *this;
}
void PluginCommand::DefaultPluginCommandActionCallback(void* ctxt, BNBinaryView* view)
{
RegisteredDefaultCommand* cmd = (RegisteredDefaultCommand*)ctxt;
Ref viewObject = new BinaryView(BNNewViewReference(view));
cmd->action(viewObject);
}
void PluginCommand::AddressPluginCommandActionCallback(void* ctxt, BNBinaryView* view, uint64_t addr)
{
RegisteredAddressCommand* cmd = (RegisteredAddressCommand*)ctxt;
Ref viewObject = new BinaryView(BNNewViewReference(view));
cmd->action(viewObject, addr);
}
void PluginCommand::RangePluginCommandActionCallback(void* ctxt, BNBinaryView* view, uint64_t addr, uint64_t len)
{
RegisteredRangeCommand* cmd = (RegisteredRangeCommand*)ctxt;
Ref viewObject = new BinaryView(BNNewViewReference(view));
cmd->action(viewObject, addr, len);
}
void PluginCommand::FunctionPluginCommandActionCallback(void* ctxt, BNBinaryView* view, BNFunction* func)
{
RegisteredFunctionCommand* cmd = (RegisteredFunctionCommand*)ctxt;
Ref viewObject = new BinaryView(BNNewViewReference(view));
Ref funcObject = new Function(BNNewFunctionReference(func));
cmd->action(viewObject, funcObject);
}
void PluginCommand::LowLevelILFunctionPluginCommandActionCallback(
void* ctxt, BNBinaryView* view, BNLowLevelILFunction* func)
{
RegisteredLowLevelILFunctionCommand* cmd = (RegisteredLowLevelILFunctionCommand*)ctxt;
Ref viewObject = new BinaryView(BNNewViewReference(view));
Ref funcObject = new LowLevelILFunction(BNNewLowLevelILFunctionReference(func));
cmd->action(viewObject, funcObject);
}
void PluginCommand::LowLevelILInstructionPluginCommandActionCallback(
void* ctxt, BNBinaryView* view, BNLowLevelILFunction* func, size_t instr)
{
RegisteredLowLevelILInstructionCommand* cmd = (RegisteredLowLevelILInstructionCommand*)ctxt;
Ref viewObject = new BinaryView(BNNewViewReference(view));
Ref funcObject = new LowLevelILFunction(BNNewLowLevelILFunctionReference(func));
LowLevelILInstruction instrObject = funcObject->GetInstruction(instr);
cmd->action(viewObject, instrObject);
}
void PluginCommand::MediumLevelILFunctionPluginCommandActionCallback(
void* ctxt, BNBinaryView* view, BNMediumLevelILFunction* func)
{
RegisteredMediumLevelILFunctionCommand* cmd = (RegisteredMediumLevelILFunctionCommand*)ctxt;
Ref viewObject = new BinaryView(BNNewViewReference(view));
Ref funcObject = new MediumLevelILFunction(BNNewMediumLevelILFunctionReference(func));
cmd->action(viewObject, funcObject);
}
void PluginCommand::MediumLevelILInstructionPluginCommandActionCallback(
void* ctxt, BNBinaryView* view, BNMediumLevelILFunction* func, size_t instr)
{
RegisteredMediumLevelILInstructionCommand* cmd = (RegisteredMediumLevelILInstructionCommand*)ctxt;
Ref viewObject = new BinaryView(BNNewViewReference(view));
Ref funcObject = new MediumLevelILFunction(BNNewMediumLevelILFunctionReference(func));
MediumLevelILInstruction instrObject = funcObject->GetInstruction(instr);
cmd->action(viewObject, instrObject);
}
void PluginCommand::HighLevelILFunctionPluginCommandActionCallback(
void* ctxt, BNBinaryView* view, BNHighLevelILFunction* func)
{
RegisteredHighLevelILFunctionCommand* cmd = (RegisteredHighLevelILFunctionCommand*)ctxt;
Ref viewObject = new BinaryView(BNNewViewReference(view));
Ref funcObject = new HighLevelILFunction(BNNewHighLevelILFunctionReference(func));
cmd->action(viewObject, funcObject);
}
void PluginCommand::HighLevelILInstructionPluginCommandActionCallback(
void* ctxt, BNBinaryView* view, BNHighLevelILFunction* func, size_t instr)
{
RegisteredHighLevelILInstructionCommand* cmd = (RegisteredHighLevelILInstructionCommand*)ctxt;
Ref viewObject = new BinaryView(BNNewViewReference(view));
Ref funcObject = new HighLevelILFunction(BNNewHighLevelILFunctionReference(func));
HighLevelILInstruction instrObject = funcObject->GetInstruction(instr);
cmd->action(viewObject, instrObject);
}
bool PluginCommand::DefaultPluginCommandIsValidCallback(void* ctxt, BNBinaryView* view)
{
RegisteredDefaultCommand* cmd = (RegisteredDefaultCommand*)ctxt;
Ref viewObject = new BinaryView(BNNewViewReference(view));
return cmd->isValid(viewObject);
}
bool PluginCommand::AddressPluginCommandIsValidCallback(void* ctxt, BNBinaryView* view, uint64_t addr)
{
RegisteredAddressCommand* cmd = (RegisteredAddressCommand*)ctxt;
Ref viewObject = new BinaryView(BNNewViewReference(view));
return cmd->isValid(viewObject, addr);
}
bool PluginCommand::RangePluginCommandIsValidCallback(void* ctxt, BNBinaryView* view, uint64_t addr, uint64_t len)
{
RegisteredRangeCommand* cmd = (RegisteredRangeCommand*)ctxt;
Ref viewObject = new BinaryView(BNNewViewReference(view));
return cmd->isValid(viewObject, addr, len);
}
bool PluginCommand::FunctionPluginCommandIsValidCallback(void* ctxt, BNBinaryView* view, BNFunction* func)
{
RegisteredFunctionCommand* cmd = (RegisteredFunctionCommand*)ctxt;
Ref viewObject = new BinaryView(BNNewViewReference(view));
Ref funcObject = new Function(BNNewFunctionReference(func));
return cmd->isValid(viewObject, funcObject);
}
bool PluginCommand::LowLevelILFunctionPluginCommandIsValidCallback(
void* ctxt, BNBinaryView* view, BNLowLevelILFunction* func)
{
RegisteredLowLevelILFunctionCommand* cmd = (RegisteredLowLevelILFunctionCommand*)ctxt;
Ref viewObject = new BinaryView(BNNewViewReference(view));
Ref funcObject = new LowLevelILFunction(BNNewLowLevelILFunctionReference(func));
return cmd->isValid(viewObject, funcObject);
}
bool PluginCommand::LowLevelILInstructionPluginCommandIsValidCallback(
void* ctxt, BNBinaryView* view, BNLowLevelILFunction* func, size_t instr)
{
RegisteredLowLevelILInstructionCommand* cmd = (RegisteredLowLevelILInstructionCommand*)ctxt;
Ref viewObject = new BinaryView(BNNewViewReference(view));
Ref funcObject = new LowLevelILFunction(BNNewLowLevelILFunctionReference(func));
LowLevelILInstruction instrObject = funcObject->GetInstruction(instr);
return cmd->isValid(viewObject, instrObject);
}
bool PluginCommand::MediumLevelILFunctionPluginCommandIsValidCallback(
void* ctxt, BNBinaryView* view, BNMediumLevelILFunction* func)
{
RegisteredMediumLevelILFunctionCommand* cmd = (RegisteredMediumLevelILFunctionCommand*)ctxt;
Ref viewObject = new BinaryView(BNNewViewReference(view));
Ref funcObject = new MediumLevelILFunction(BNNewMediumLevelILFunctionReference(func));
return cmd->isValid(viewObject, funcObject);
}
bool PluginCommand::MediumLevelILInstructionPluginCommandIsValidCallback(
void* ctxt, BNBinaryView* view, BNMediumLevelILFunction* func, size_t instr)
{
RegisteredMediumLevelILInstructionCommand* cmd = (RegisteredMediumLevelILInstructionCommand*)ctxt;
Ref viewObject = new BinaryView(BNNewViewReference(view));
Ref funcObject = new MediumLevelILFunction(BNNewMediumLevelILFunctionReference(func));
MediumLevelILInstruction instrObject = funcObject->GetInstruction(instr);
return cmd->isValid(viewObject, instrObject);
}
bool PluginCommand::HighLevelILFunctionPluginCommandIsValidCallback(
void* ctxt, BNBinaryView* view, BNHighLevelILFunction* func)
{
RegisteredHighLevelILFunctionCommand* cmd = (RegisteredHighLevelILFunctionCommand*)ctxt;
Ref viewObject = new BinaryView(BNNewViewReference(view));
Ref funcObject = new HighLevelILFunction(BNNewHighLevelILFunctionReference(func));
return cmd->isValid(viewObject, funcObject);
}
bool PluginCommand::HighLevelILInstructionPluginCommandIsValidCallback(
void* ctxt, BNBinaryView* view, BNHighLevelILFunction* func, size_t instr)
{
RegisteredHighLevelILInstructionCommand* cmd = (RegisteredHighLevelILInstructionCommand*)ctxt;
Ref viewObject = new BinaryView(BNNewViewReference(view));
Ref funcObject = new HighLevelILFunction(BNNewHighLevelILFunctionReference(func));
HighLevelILInstruction instrObject = funcObject->GetInstruction(instr);
return cmd->isValid(viewObject, instrObject);
}
void PluginCommand::Register(
const string& name, const string& description, const function& action)
{
Register(name, description, action, [](BinaryView*) { return true; });
}
void PluginCommand::Register(const string& name, const string& description,
const function& action, const function& isValid)
{
RegisteredDefaultCommand* cmd = new RegisteredDefaultCommand;
cmd->action = action;
cmd->isValid = isValid;
BNRegisterPluginCommand(name.c_str(), description.c_str(), DefaultPluginCommandActionCallback,
DefaultPluginCommandIsValidCallback, cmd);
}
void PluginCommand::RegisterForAddress(
const string& name, const string& description, const function& action)
{
RegisterForAddress(name, description, action, [](BinaryView*, uint64_t) { return true; });
}
void PluginCommand::RegisterForAddress(const string& name, const string& description,
const function& action,
const function& isValid)
{
RegisteredAddressCommand* cmd = new RegisteredAddressCommand;
cmd->action = action;
cmd->isValid = isValid;
BNRegisterPluginCommandForAddress(name.c_str(), description.c_str(), AddressPluginCommandActionCallback,
AddressPluginCommandIsValidCallback, cmd);
}
void PluginCommand::RegisterForRange(const string& name, const string& description,
const function& action)
{
RegisterForRange(name, description, action, [](BinaryView*, uint64_t, uint64_t) { return true; });
}
void PluginCommand::RegisterForRange(const string& name, const string& description,
const function& action,
const function& isValid)
{
RegisteredRangeCommand* cmd = new RegisteredRangeCommand;
cmd->action = action;
cmd->isValid = isValid;
BNRegisterPluginCommandForRange(
name.c_str(), description.c_str(), RangePluginCommandActionCallback, RangePluginCommandIsValidCallback, cmd);
}
void PluginCommand::RegisterForFunction(
const string& name, const string& description, const function& action)
{
RegisterForFunction(name, description, action, [](BinaryView*, Function*) { return true; });
}
void PluginCommand::RegisterForFunction(const string& name, const string& description,
const function& action,
const function& isValid)
{
RegisteredFunctionCommand* cmd = new RegisteredFunctionCommand;
cmd->action = action;
cmd->isValid = isValid;
BNRegisterPluginCommandForFunction(name.c_str(), description.c_str(), FunctionPluginCommandActionCallback,
FunctionPluginCommandIsValidCallback, cmd);
}
void PluginCommand::RegisterForLowLevelILFunction(const string& name, const string& description,
const function& action)
{
RegisterForLowLevelILFunction(name, description, action, [](BinaryView*, LowLevelILFunction*) { return true; });
}
void PluginCommand::RegisterForLowLevelILFunction(const string& name, const string& description,
const function& action,
const function& isValid)
{
RegisteredLowLevelILFunctionCommand* cmd = new RegisteredLowLevelILFunctionCommand;
cmd->action = action;
cmd->isValid = isValid;
BNRegisterPluginCommandForLowLevelILFunction(name.c_str(), description.c_str(),
LowLevelILFunctionPluginCommandActionCallback, LowLevelILFunctionPluginCommandIsValidCallback, cmd);
}
void PluginCommand::RegisterForLowLevelILInstruction(const string& name, const string& description,
const function& action)
{
RegisterForLowLevelILInstruction(
name, description, action, [](BinaryView*, const LowLevelILInstruction&) { return true; });
}
void PluginCommand::RegisterForLowLevelILInstruction(const string& name, const string& description,
const function& action,
const function& isValid)
{
RegisteredLowLevelILInstructionCommand* cmd = new RegisteredLowLevelILInstructionCommand;
cmd->action = action;
cmd->isValid = isValid;
BNRegisterPluginCommandForLowLevelILInstruction(name.c_str(), description.c_str(),
LowLevelILInstructionPluginCommandActionCallback, LowLevelILInstructionPluginCommandIsValidCallback, cmd);
}
void PluginCommand::RegisterForMediumLevelILFunction(const string& name, const string& description,
const function& action)
{
RegisterForMediumLevelILFunction(
name, description, action, [](BinaryView*, MediumLevelILFunction*) { return true; });
}
void PluginCommand::RegisterForMediumLevelILFunction(const string& name, const string& description,
const function& action,
const function& isValid)
{
RegisteredMediumLevelILFunctionCommand* cmd = new RegisteredMediumLevelILFunctionCommand;
cmd->action = action;
cmd->isValid = isValid;
BNRegisterPluginCommandForMediumLevelILFunction(name.c_str(), description.c_str(),
MediumLevelILFunctionPluginCommandActionCallback, MediumLevelILFunctionPluginCommandIsValidCallback, cmd);
}
void PluginCommand::RegisterForMediumLevelILInstruction(const string& name, const string& description,
const function& action)
{
RegisterForMediumLevelILInstruction(
name, description, action, [](BinaryView*, const MediumLevelILInstruction&) { return true; });
}
void PluginCommand::RegisterForMediumLevelILInstruction(const string& name, const string& description,
const function& action,
const function& isValid)
{
RegisteredMediumLevelILInstructionCommand* cmd = new RegisteredMediumLevelILInstructionCommand;
cmd->action = action;
cmd->isValid = isValid;
BNRegisterPluginCommandForMediumLevelILInstruction(name.c_str(), description.c_str(),
MediumLevelILInstructionPluginCommandActionCallback, MediumLevelILInstructionPluginCommandIsValidCallback, cmd);
}
void PluginCommand::RegisterForHighLevelILFunction(const string& name, const string& description,
const function& action)
{
RegisterForHighLevelILFunction(name, description, action, [](BinaryView*, HighLevelILFunction*) { return true; });
}
void PluginCommand::RegisterForHighLevelILFunction(const string& name, const string& description,
const function& action,
const function& isValid)
{
RegisteredHighLevelILFunctionCommand* cmd = new RegisteredHighLevelILFunctionCommand;
cmd->action = action;
cmd->isValid = isValid;
BNRegisterPluginCommandForHighLevelILFunction(name.c_str(), description.c_str(),
HighLevelILFunctionPluginCommandActionCallback, HighLevelILFunctionPluginCommandIsValidCallback, cmd);
}
void PluginCommand::RegisterForHighLevelILInstruction(const string& name, const string& description,
const function& action)
{
RegisterForHighLevelILInstruction(
name, description, action, [](BinaryView*, const HighLevelILInstruction&) { return true; });
}
void PluginCommand::RegisterForHighLevelILInstruction(const string& name, const string& description,
const function& action,
const function& isValid)
{
RegisteredHighLevelILInstructionCommand* cmd = new RegisteredHighLevelILInstructionCommand;
cmd->action = action;
cmd->isValid = isValid;
BNRegisterPluginCommandForHighLevelILInstruction(name.c_str(), description.c_str(),
HighLevelILInstructionPluginCommandActionCallback, HighLevelILInstructionPluginCommandIsValidCallback, cmd);
}
vector PluginCommand::GetList()
{
vector result;
size_t count;
BNPluginCommand* commands = BNGetAllPluginCommands(&count);
result.reserve(count);
for (size_t i = 0; i < count; i++)
result.emplace_back(commands[i]);
BNFreePluginCommandList(commands);
return result;
}
vector PluginCommand::GetValidList(const PluginCommandContext& ctxt)
{
vector commands = GetList();
vector result;
for (auto& i : commands)
{
if (i.IsValid(ctxt))
result.push_back(i);
}
return result;
}
bool PluginCommand::IsValid(const PluginCommandContext& ctxt) const
{
if (!ctxt.binaryView)
return false;
switch (m_command.type)
{
case DefaultPluginCommand:
if (!m_command.defaultIsValid)
return true;
return m_command.defaultIsValid(m_command.context, ctxt.binaryView->GetObject());
case AddressPluginCommand:
if (!m_command.addressIsValid)
return true;
return m_command.addressIsValid(m_command.context, ctxt.binaryView->GetObject(), ctxt.address);
case RangePluginCommand:
if (ctxt.length == 0)
return false;
if (!m_command.rangeIsValid)
return true;
return m_command.rangeIsValid(m_command.context, ctxt.binaryView->GetObject(), ctxt.address, ctxt.length);
case FunctionPluginCommand:
if (!ctxt.function)
return false;
if (!m_command.functionIsValid)
return true;
return m_command.functionIsValid(m_command.context, ctxt.binaryView->GetObject(), ctxt.function->GetObject());
case LowLevelILFunctionPluginCommand:
if (!ctxt.lowLevelILFunction)
return false;
if (!m_command.lowLevelILFunctionIsValid)
return true;
return m_command.lowLevelILFunctionIsValid(
m_command.context, ctxt.binaryView->GetObject(), ctxt.lowLevelILFunction->GetObject());
case LowLevelILInstructionPluginCommand:
if (!ctxt.lowLevelILFunction)
return false;
if (ctxt.instrIndex == BN_INVALID_EXPR)
return false;
if (!m_command.lowLevelILInstructionIsValid)
return true;
return m_command.lowLevelILInstructionIsValid(
m_command.context, ctxt.binaryView->GetObject(), ctxt.lowLevelILFunction->GetObject(), ctxt.instrIndex);
case MediumLevelILFunctionPluginCommand:
if (!ctxt.mediumLevelILFunction)
return false;
if (!m_command.mediumLevelILFunctionIsValid)
return true;
return m_command.mediumLevelILFunctionIsValid(
m_command.context, ctxt.binaryView->GetObject(), ctxt.mediumLevelILFunction->GetObject());
case MediumLevelILInstructionPluginCommand:
if (!ctxt.mediumLevelILFunction)
return false;
if (ctxt.instrIndex == BN_INVALID_EXPR)
return false;
if (!m_command.mediumLevelILInstructionIsValid)
return true;
return m_command.mediumLevelILInstructionIsValid(
m_command.context, ctxt.binaryView->GetObject(), ctxt.mediumLevelILFunction->GetObject(), ctxt.instrIndex);
case HighLevelILFunctionPluginCommand:
if (!ctxt.highLevelILFunction)
return false;
if (!m_command.highLevelILFunctionIsValid)
return true;
return m_command.highLevelILFunctionIsValid(
m_command.context, ctxt.binaryView->GetObject(), ctxt.highLevelILFunction->GetObject());
case HighLevelILInstructionPluginCommand:
if (!ctxt.highLevelILFunction)
return false;
if (ctxt.instrIndex == BN_INVALID_EXPR)
return false;
if (!m_command.highLevelILInstructionIsValid)
return true;
return m_command.highLevelILInstructionIsValid(
m_command.context, ctxt.binaryView->GetObject(), ctxt.highLevelILFunction->GetObject(), ctxt.instrIndex);
default:
return false;
}
}
void PluginCommand::Execute(const PluginCommandContext& ctxt) const
{
if (!IsValid(ctxt))
return;
switch (m_command.type)
{
case DefaultPluginCommand:
m_command.defaultCommand(m_command.context, ctxt.binaryView->GetObject());
break;
case AddressPluginCommand:
m_command.addressCommand(m_command.context, ctxt.binaryView->GetObject(), ctxt.address);
break;
case RangePluginCommand:
m_command.rangeCommand(m_command.context, ctxt.binaryView->GetObject(), ctxt.address, ctxt.length);
break;
case FunctionPluginCommand:
m_command.functionCommand(m_command.context, ctxt.binaryView->GetObject(), ctxt.function->GetObject());
break;
case LowLevelILFunctionPluginCommand:
m_command.lowLevelILFunctionCommand(
m_command.context, ctxt.binaryView->GetObject(), ctxt.lowLevelILFunction->GetObject());
break;
case LowLevelILInstructionPluginCommand:
m_command.lowLevelILInstructionCommand(
m_command.context, ctxt.binaryView->GetObject(), ctxt.lowLevelILFunction->GetObject(), ctxt.instrIndex);
break;
case MediumLevelILFunctionPluginCommand:
m_command.mediumLevelILFunctionCommand(
m_command.context, ctxt.binaryView->GetObject(), ctxt.mediumLevelILFunction->GetObject());
break;
case MediumLevelILInstructionPluginCommand:
m_command.mediumLevelILInstructionCommand(
m_command.context, ctxt.binaryView->GetObject(), ctxt.mediumLevelILFunction->GetObject(), ctxt.instrIndex);
break;
case HighLevelILFunctionPluginCommand:
m_command.highLevelILFunctionCommand(
m_command.context, ctxt.binaryView->GetObject(), ctxt.highLevelILFunction->GetObject());
break;
case HighLevelILInstructionPluginCommand:
m_command.highLevelILInstructionCommand(
m_command.context, ctxt.binaryView->GetObject(), ctxt.highLevelILFunction->GetObject(), ctxt.instrIndex);
break;
default:
break;
}
}