Skip to content

Commit f041c02

Browse files
committed
Add global plugin command type
Register plugins which are available outside the context of a binary view
1 parent 1b555c2 commit f041c02

File tree

13 files changed

+259
-53
lines changed

13 files changed

+259
-53
lines changed

binaryninjaapi.h

Lines changed: 75 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16502,6 +16502,12 @@ namespace BinaryNinja {
1650216502
{
1650316503
BNPluginCommand m_command;
1650416504

16505+
struct RegisteredGlobalCommand
16506+
{
16507+
std::function<void()> action;
16508+
std::function<bool()> isValid;
16509+
};
16510+
1650516511
struct RegisteredDefaultCommand
1650616512
{
1650716513
std::function<void(BinaryView*)> action;
@@ -16568,6 +16574,7 @@ namespace BinaryNinja {
1656816574
std::function<bool(Project*)> isValid;
1656916575
};
1657016576

16577+
static void GlobalPluginCommandActionCallback(void* ctxt);
1657116578
static void DefaultPluginCommandActionCallback(void* ctxt, BNBinaryView* view);
1657216579
static void AddressPluginCommandActionCallback(void* ctxt, BNBinaryView* view, uint64_t addr);
1657316580
static void RangePluginCommandActionCallback(void* ctxt, BNBinaryView* view, uint64_t addr, uint64_t len);
@@ -16586,6 +16593,7 @@ namespace BinaryNinja {
1658616593
void* ctxt, BNBinaryView* view, BNHighLevelILFunction* func, size_t instr);
1658716594
static void ProjectPluginCommandActionCallback(void* ctxt, BNProject* project);
1658816595

16596+
static bool GlobalPluginCommandIsValidCallback(void* ctxt);
1658916597
static bool DefaultPluginCommandIsValidCallback(void* ctxt, BNBinaryView* view);
1659016598
static bool AddressPluginCommandIsValidCallback(void* ctxt, BNBinaryView* view, uint64_t addr);
1659116599
static bool RangePluginCommandIsValidCallback(void* ctxt, BNBinaryView* view, uint64_t addr, uint64_t len);
@@ -16611,9 +16619,74 @@ namespace BinaryNinja {
1661116619

1661216620
PluginCommand& operator=(const PluginCommand& cmd);
1661316621

16622+
/*! Register a command.
16623+
16624+
This will appear in the top menu.
16625+
16626+
\code{.cpp}
16627+
16628+
// Registering a command using a lambda expression
16629+
PluginCommand::RegisterGlobal("MyPlugin\\MyAction", "Perform an action", []() { });
16630+
16631+
// Registering a command using a standard static function
16632+
// This also works with functions in the global namespace, e.g. "void myCommand()"
16633+
void MyPlugin::MyCommand()
16634+
{
16635+
// Perform an action
16636+
}
16637+
16638+
PluginCommand::Register("MyPlugin\\MySecondAction", "Perform an action", MyPlugin::MyCommand);
16639+
\endcode
16640+
16641+
\param name
16642+
\parblock
16643+
Name of the command to register. This will appear in the top menu.
16644+
16645+
You can register submenus to an item by separating names with a \c "\\". The base (farthest right) name will
16646+
be the item which upon being clicked will perform the action.
16647+
\endparblock
16648+
\param description Description of the command
16649+
\param action Action to perform
16650+
*/
16651+
static void RegisterGlobal(const std::string& name, const std::string& description, const std::function<void()>& action);
16652+
16653+
/*! Register a command globally, with a validity check.
16654+
16655+
This will appear in the top menu.
16656+
16657+
\code{.cpp}
16658+
16659+
// Registering a command using lambda expressions
16660+
PluginCommand::Register("MyPlugin\\MyAction", "Perform an action", [](){ }, [](){ });
16661+
16662+
// Registering a command using a standard static function, and a lambda for the isValid check
16663+
// This also works with functions in the global namespace, e.g. "void myCommand()"
16664+
void MyPlugin::MyCommand(BinaryView* view)
16665+
{
16666+
// Perform an action
16667+
}
16668+
16669+
PluginCommand::Register("MyPlugin\\MySecondAction", "Perform an action", MyPlugin::MyCommand,
16670+
[](){ return true; });
16671+
\endcode
16672+
16673+
\param name
16674+
\parblock
16675+
Name of the command to register. This will appear in the top menu and the context menu.
16676+
16677+
You can register submenus to an item by separating names with a \c "\\". The base (farthest right) name will
16678+
be the item which upon being clicked will perform the action.
16679+
\endparblock
16680+
\param description Description of the command
16681+
\param action Action to perform
16682+
\param isValid Function that returns whether the command is allowed to be performed.
16683+
*/
16684+
static void RegisterGlobal(const std::string& name, const std::string& description,
16685+
const std::function<void()>& action, const std::function<bool()>& isValid);
16686+
1661416687
/*! Register a command for a given BinaryView.
1661516688

16616-
This will appear in the top menu and the right-click context menu.
16689+
This will appear in the top menu.
1661716690

1661816691
\code{.cpp}
1661916692

@@ -16649,7 +16722,7 @@ namespace BinaryNinja {
1664916722

1665016723
/*! Register a command for a given BinaryView, with a validity check.
1665116724

16652-
This will appear in the top menu and the right-click context menu.
16725+
This will appear in the top menu.
1665316726

1665416727
\code{.cpp}
1665516728

binaryninjacore.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2784,7 +2784,8 @@ extern "C"
27842784
MediumLevelILInstructionPluginCommand,
27852785
HighLevelILFunctionPluginCommand,
27862786
HighLevelILInstructionPluginCommand,
2787-
ProjectPluginCommand
2787+
ProjectPluginCommand,
2788+
GlobalPluginCommand
27882789
};
27892790

27902791
typedef struct BNPluginCommand
@@ -2794,6 +2795,7 @@ extern "C"
27942795
BNPluginCommandType type;
27952796
void* context;
27962797

2798+
void (*globalCommand)(void* ctxt);
27972799
void (*defaultCommand)(void* ctxt, BNBinaryView* view);
27982800
void (*addressCommand)(void* ctxt, BNBinaryView* view, uint64_t addr);
27992801
void (*rangeCommand)(void* ctxt, BNBinaryView* view, uint64_t addr, uint64_t len);
@@ -2808,6 +2810,7 @@ extern "C"
28082810
void* ctxt, BNBinaryView* view, BNHighLevelILFunction* func, size_t instr);
28092811
void (*projectCommand)(void* ctxt, BNProject* view);
28102812

2813+
bool (*globalIsValid)(void* ctxt);
28112814
bool (*defaultIsValid)(void* ctxt, BNBinaryView* view);
28122815
bool (*addressIsValid)(void* ctxt, BNBinaryView* view, uint64_t addr);
28132816
bool (*rangeIsValid)(void* ctxt, BNBinaryView* view, uint64_t addr, uint64_t len);
@@ -7426,6 +7429,8 @@ extern "C"
74267429
BINARYNINJACOREAPI void BNInstallPendingUpdate(char** errors);
74277430

74287431
// Plugin commands
7432+
BINARYNINJACOREAPI void BNRegisterPluginCommandGlobal(const char* name, const char* description,
7433+
void (*action)(void* ctxt), bool (*isValid)(void* ctxt), void* context);
74297434
BINARYNINJACOREAPI void BNRegisterPluginCommand(const char* name, const char* description,
74307435
void (*action)(void* ctxt, BNBinaryView* view), bool (*isValid)(void* ctxt, BNBinaryView* view), void* context);
74317436
BINARYNINJACOREAPI void BNRegisterPluginCommandForAddress(const char* name, const char* description,
@@ -7460,6 +7465,7 @@ extern "C"
74607465
void (*action)(void* ctxt, BNProject* project), bool (*isValid)(void* ctxt, BNProject* project), void* context);
74617466

74627467
BINARYNINJACOREAPI BNPluginCommand* BNGetAllPluginCommands(size_t* count);
7468+
BINARYNINJACOREAPI BNPluginCommand* BNGetValidPluginCommandsGlobal(size_t* count);
74637469
BINARYNINJACOREAPI BNPluginCommand* BNGetValidPluginCommands(BNBinaryView* view, size_t* count);
74647470
BINARYNINJACOREAPI BNPluginCommand* BNGetValidPluginCommandsForAddress(
74657471
BNBinaryView* view, uint64_t addr, size_t* count);

plugin.cpp

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,13 @@ PluginCommand& PluginCommand::operator=(const PluginCommand& cmd)
6868
}
6969

7070

71+
void PluginCommand::GlobalPluginCommandActionCallback(void* ctxt)
72+
{
73+
RegisteredGlobalCommand* cmd = (RegisteredGlobalCommand*)ctxt;
74+
cmd->action();
75+
}
76+
77+
7178
void PluginCommand::DefaultPluginCommandActionCallback(void* ctxt, BNBinaryView* view)
7279
{
7380
RegisteredDefaultCommand* cmd = (RegisteredDefaultCommand*)ctxt;
@@ -172,6 +179,13 @@ void PluginCommand::ProjectPluginCommandActionCallback(void *ctxt, BNProject* pr
172179
}
173180

174181

182+
bool PluginCommand::GlobalPluginCommandIsValidCallback(void* ctxt)
183+
{
184+
RegisteredGlobalCommand* cmd = (RegisteredGlobalCommand*)ctxt;
185+
return cmd->isValid();
186+
}
187+
188+
175189
bool PluginCommand::DefaultPluginCommandIsValidCallback(void* ctxt, BNBinaryView* view)
176190
{
177191
RegisteredDefaultCommand* cmd = (RegisteredDefaultCommand*)ctxt;
@@ -276,6 +290,23 @@ bool PluginCommand::ProjectPluginCommandIsValidCallback(void* ctxt, BNProject* p
276290
}
277291

278292

293+
void PluginCommand::RegisterGlobal(const string& name, const string& description, const function<void()>& action)
294+
{
295+
RegisterGlobal(name, description, action, []() { return true; });
296+
}
297+
298+
299+
void PluginCommand::RegisterGlobal(const string& name, const string& description,
300+
const function<void()>& action, const function<bool()>& isValid)
301+
{
302+
RegisteredGlobalCommand* cmd = new RegisteredGlobalCommand;
303+
cmd->action = action;
304+
cmd->isValid = isValid;
305+
BNRegisterPluginCommandGlobal(name.c_str(), description.c_str(), GlobalPluginCommandActionCallback,
306+
GlobalPluginCommandIsValidCallback, cmd);
307+
}
308+
309+
279310
void PluginCommand::Register(
280311
const string& name, const string& description, const function<void(BinaryView* view)>& action)
281312
{
@@ -515,6 +546,10 @@ bool PluginCommand::IsValid(const PluginCommandContext& ctxt) const
515546
{
516547
switch (m_command.type)
517548
{
549+
case GlobalPluginCommand:
550+
if (!m_command.globalIsValid)
551+
return true;
552+
return m_command.globalIsValid(m_command.context);
518553
case DefaultPluginCommand:
519554
if (!ctxt.binaryView)
520555
return false;
@@ -606,6 +641,9 @@ void PluginCommand::Execute(const PluginCommandContext& ctxt) const
606641

607642
switch (m_command.type)
608643
{
644+
case GlobalPluginCommand:
645+
m_command.globalCommand(m_command.context);
646+
break;
609647
case DefaultPluginCommand:
610648
m_command.defaultCommand(m_command.context, ctxt.binaryView->GetObject());
611649
break;

plugins/bntl_utils/src/command/create.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use crate::process::{new_processing_state_background_thread, TypeLibProcessor};
33
use crate::validate::TypeLibValidater;
44
use binaryninja::background_task::BackgroundTask;
55
use binaryninja::binary_view::{BinaryView, BinaryViewExt};
6-
use binaryninja::command::{Command, ProjectCommand};
6+
use binaryninja::command::{Command, GlobalCommand, ProjectCommand};
77
use binaryninja::interaction::{Form, FormInputField, MessageBoxButtonSet, MessageBoxIcon};
88
use binaryninja::platform::Platform;
99
use binaryninja::project::Project;
@@ -188,14 +188,14 @@ impl CreateFromDirectory {
188188
}
189189
}
190190

191-
impl Command for CreateFromDirectory {
192-
fn action(&self, _view: &BinaryView) {
191+
impl GlobalCommand for CreateFromDirectory {
192+
fn action(&self) {
193193
thread::spawn(move || {
194194
CreateFromDirectory::execute();
195195
});
196196
}
197197

198-
fn valid(&self, _view: &BinaryView) -> bool {
198+
fn valid(&self) -> bool {
199199
true
200200
}
201201
}

plugins/bntl_utils/src/command/diff.rs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,7 @@ use crate::command::OutputDirectoryField;
22
use crate::diff::TILDiff;
33
use crate::helper::path_to_type_libraries;
44
use binaryninja::background_task::BackgroundTask;
5-
use binaryninja::binary_view::BinaryView;
6-
use binaryninja::command::Command;
5+
use binaryninja::command::GlobalCommand;
76
use binaryninja::interaction::{Form, FormInputField};
87
use std::path::PathBuf;
98
use std::thread;
@@ -95,14 +94,14 @@ impl Diff {
9594
}
9695
}
9796

98-
impl Command for Diff {
99-
fn action(&self, _view: &BinaryView) {
97+
impl GlobalCommand for Diff {
98+
fn action(&self) {
10099
thread::spawn(move || {
101100
Diff::execute();
102101
});
103102
}
104103

105-
fn valid(&self, _view: &BinaryView) -> bool {
104+
fn valid(&self) -> bool {
106105
true
107106
}
108107
}

plugins/bntl_utils/src/command/dump.rs

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,7 @@ use crate::command::{InputDirectoryField, OutputDirectoryField};
22
use crate::dump::TILDump;
33
use crate::helper::path_to_type_libraries;
44
use binaryninja::background_task::BackgroundTask;
5-
use binaryninja::binary_view::BinaryView;
6-
use binaryninja::command::Command;
5+
use binaryninja::command::GlobalCommand;
76
use binaryninja::interaction::Form;
87

98
pub struct Dump;
@@ -48,15 +47,14 @@ impl Dump {
4847
}
4948
}
5049

51-
impl Command for Dump {
52-
// TODO: We need a command type that does not require a binary view.
53-
fn action(&self, _view: &BinaryView) {
50+
impl GlobalCommand for Dump {
51+
fn action(&self) {
5452
std::thread::spawn(move || {
5553
Dump::execute();
5654
});
5755
}
5856

59-
fn valid(&self, _view: &BinaryView) -> bool {
57+
fn valid(&self) -> bool {
6058
true
6159
}
6260
}

plugins/bntl_utils/src/command/validate.rs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
use crate::command::{InputDirectoryField, OutputDirectoryField};
22
use crate::helper::path_to_type_libraries;
33
use crate::validate::TypeLibValidater;
4-
use binaryninja::binary_view::BinaryView;
5-
use binaryninja::command::Command;
4+
use binaryninja::command::GlobalCommand;
65
use binaryninja::interaction::Form;
76
use binaryninja::platform::Platform;
87

@@ -68,14 +67,14 @@ impl Validate {
6867
}
6968
}
7069

71-
impl Command for Validate {
72-
fn action(&self, _view: &BinaryView) {
70+
impl GlobalCommand for Validate {
71+
fn action(&self) {
7372
std::thread::spawn(move || {
7473
Validate::execute();
7574
});
7675
}
7776

78-
fn valid(&self, _view: &BinaryView) -> bool {
77+
fn valid(&self) -> bool {
7978
true
8079
}
8180
}

plugins/bntl_utils/src/lib.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,25 +35,25 @@ fn plugin_init() -> Result<(), ()> {
3535
command::create::CreateFromProject {},
3636
);
3737

38-
binaryninja::command::register_command(
38+
binaryninja::command::register_global_command(
3939
"BNTL\\Create\\From Directory",
4040
"Create .bntl files from the given directory",
4141
command::create::CreateFromDirectory {},
4242
);
4343

44-
binaryninja::command::register_command(
44+
binaryninja::command::register_global_command(
4545
"BNTL\\Diff",
4646
"Diff two .bntl files and output the difference to a file",
4747
command::diff::Diff {},
4848
);
4949

50-
binaryninja::command::register_command(
50+
binaryninja::command::register_global_command(
5151
"BNTL\\Dump To Header",
5252
"Dump a .bntl file to a header file",
5353
command::dump::Dump {},
5454
);
5555

56-
binaryninja::command::register_command(
56+
binaryninja::command::register_global_command(
5757
"BNTL\\Validate",
5858
"Validate a .bntl file and report the issues",
5959
command::validate::Validate {},

plugins/warp/src/plugin.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ use crate::{core_signature_dir, user_signature_dir};
1111
use binaryninja::background_task::BackgroundTask;
1212
use binaryninja::command::{
1313
register_command, register_command_for_function, register_command_for_project,
14+
register_global_command,
1415
};
1516
use binaryninja::is_ui_enabled;
1617
use binaryninja::settings::{QueryOptions, Settings};
@@ -192,7 +193,7 @@ fn plugin_init() -> bool {
192193
load::LoadSignatureFile {},
193194
);
194195

195-
register_command(
196+
register_global_command(
196197
"WARP\\Commit File",
197198
"Commit file to a source",
198199
commit::CommitFile {},
@@ -234,7 +235,7 @@ fn plugin_init() -> bool {
234235
create::CreateFromCurrentView {},
235236
);
236237

237-
register_command(
238+
register_global_command(
238239
"WARP\\Create\\From File(s)",
239240
"Creates a signature file containing all selected functions",
240241
create::CreateFromFiles {},

0 commit comments

Comments
 (0)