Examples
This page is currently a stub. We're working on additional examples tailored for beginners, so expect more samples soon.
The IDA SDK, which you can get from our Download Center in My Hex-Rays Portal, provides sample code in addition to necessary libraries and headers. These exemplary plugins, processor modules, or file loaders are designed to help you create your own plugins, modules, and more.
Where can I find all the examples?
The IDA SDK is shipped with plenty of samples (including, for example, sample processor modules or loaders) and exemplary plugins that you can find in the IDA SDK folder. To kickstart your journey with the IDA SDK, we encourage you to check out the included samples, compile them, and run them.
Sample plugins
The plugins
folder contains sample plugins written in C++. Usually, the subfolders contains at minimum the cpp file(s) and a makefile.
Below, we present only a selection of samples to familiarize yourself with the possibilities of the C++ SDK. All of these samples and their corresponding makefiles can be found in your plugins
folder inside the SDK directory.
hello
Simple hello word plugin ideal to get started with IDA SDK.
#include <ida.hpp>
#include <idp.hpp>
#include <loader.hpp>
#include <kernwin.hpp>
//--------------------------------------------------------------------------
struct plugin_ctx_t : public plugmod_t
{
virtual bool idaapi run(size_t) override;
};
//--------------------------------------------------------------------------
bool idaapi plugin_ctx_t::run(size_t)
{
msg("Hello, world! (cpp)\n");
return true;
}
//--------------------------------------------------------------------------
static plugmod_t *idaapi init()
{
return new plugin_ctx_t;
}
//--------------------------------------------------------------------------
plugin_t PLUGIN =
{
IDP_INTERFACE_VERSION,
PLUGIN_UNL // Unload the plugin immediately after calling 'run'
| PLUGIN_MULTI, // The plugin can work with multiple idbs in parallel
init, // initialize
nullptr,
nullptr,
nullptr, // long comment about the plugin
nullptr, // multiline help about the plugin
"Hello, world", // the preferred short name of the plugin
nullptr, // the preferred hotkey to run the plugin
};
vcsample
Sample plugin, ideal to get familiar with plugins structure.
/*
* This is a sample plugin module
*
* It can be compiled by any of the supported compilers:
*
* - Visual C++
* - GCC
*
*/
#include <ida.hpp>
#include <idp.hpp>
#include <expr.hpp>
#include <bytes.hpp>
#include <loader.hpp>
#include <kernwin.hpp>
//#define INSTALL_SAMPLE_CALLBACK
//#define HAS_USER_DEFINED_PREFIX
//--------------------------------------------------------------------------
//lint -e754 struct member not referenced
struct plugin_data_t : public plugmod_t, public event_listener_t
{
ea_t old_ea = BADADDR;
int old_lnnum = -1;
virtual ssize_t idaapi on_event(ssize_t event_id, va_list) override;
virtual bool idaapi run(size_t arg) override;
idaapi ~plugin_data_t();
};
//--------------------------------------------------------------------------
// Example of a user-defined IDC function in C++
//#define DEFINE_IDC_FUNC
#ifdef DEFINE_IDC_FUNC
static error_t idaapi myfunc5(idc_value_t *argv, idc_value_t *res)
{
msg("myfunc is called with arg0=%x and arg1=%s\n", argv[0].num, argv[1].c_str());
res->num = 5; // let's return 5
return eOk;
}
static const char myfunc5_args[] = { VT_LONG, VT_STR, 0 };
static const ext_idcfunc_t myfunc5_desc =
{
{ "MyFunc5", myfunc5, myfunc5_args, nullptr, 0, 0 }
};
#endif // DEFINE_IDC_FUNC
//--------------------------------------------------------------------------
// This callback is called for UI notification events
ssize_t idaapi plugin_data_t::on_event(ssize_t event_id, va_list)
{
if ( event_id != ui_msg // avoid recursion
&& event_id != ui_refreshmarked ) // ignore uninteresting events
{
msg("ui_callback %" FMT_ZS "\n", event_id);
}
return 0; // 0 means "continue processing the event"
// otherwise the event is considered as processed
}
//--------------------------------------------------------------------------
// A sample how to generate user-defined line prefixes
#ifdef HAS_USER_DEFINED_PREFIX
static const int prefix_width = 8;
struct sample_prefix_t : public user_defined_prefix_t
{
plugin_data_t *pd;
sample_prefix_t(plugin_data_t *d) :
user_defined_prefix_t(prefix_width, d), pd(d) {}
virtual void idaapi get_user_defined_prefix(
qstring *out,
ea_t ea,
const insn_t & /*insn*/,
int lnnum,
int indent,
const char *line) override
{
out->qclear(); // empty prefix by default
// We want to display the prefix only the lines which
// contain the instruction itself
if ( indent != -1 ) // a directive
return;
if ( line[0] == '\0' ) // empty line
return;
if ( tag_advance(line,1)[-1] == ash.cmnt[0] ) // comment line...
return;
// We don't want the prefix to be printed again for other lines of the
// same instruction/data. For that we remember the line number
// and compare it before generating the prefix
if ( pd->old_ea == ea && pd->old_lnnum == lnnum )
return;
// Ok, seems that we found an instruction line.
// Let's display the size of the current item as the user-defined prefix
asize_t our_size = get_item_size(ea);
// We don't bother about the width of the prefix
// because it will be padded with spaces by the kernel
out->sprnt(" %" FMT_64 "d", our_size);
// Remember the address and line number we produced the line prefix for:
pd->old_ea = ea;
pd->old_lnnum = lnnum;
}
};
#endif // HAS_USER_DEFINED_PREFIX
//--------------------------------------------------------------------------
static plugmod_t *idaapi init()
{
if ( inf_get_filetype() == f_ELF )
return nullptr; // we do not want to work with this idb
plugin_data_t *pd = new plugin_data_t;
// notifications
#ifdef INSTALL_SAMPLE_CALLBACK
hook_event_listener(HT_UI, pd, pd);
#endif // INSTALL_SAMPLE_CALLBACK
// user-defined prefix. will be automatically uninstalled by the kernel
// when our plugin gets unloaded.
#ifdef HAS_USER_DEFINED_PREFIX
new sample_prefix_t(pd);
#endif // HAS_USER_DEFINED_PREFIX
// custom IDC function
#ifdef DEFINE_IDC_FUNC
add_idc_func(myfunc5_desc);
#endif // DEFINE_IDC_FUNC
// an example how to retrieve plugin options
const char *options = get_plugin_options("vcsample");
if ( options != nullptr )
warning("command line options: %s", options);
return pd;
}
//--------------------------------------------------------------------------
plugin_data_t::~plugin_data_t()
{
#ifdef DEFINE_IDC_FUNC
del_idc_func(myfunc5_desc.name);
#endif
}
//--------------------------------------------------------------------------
bool idaapi plugin_data_t::run(size_t arg)
{
warning("vcsample plugin has been called with arg %" FMT_Z, arg);
// msg("just fyi: the current screen address is: %a\n", get_screen_ea());
return true;
}
//--------------------------------------------------------------------------
static const char comment[] = "This is a sample plugin. It does nothing useful";
static const char help[] =
"A sample plugin module\n"
"\n"
"This module shows you how to create plugin modules.\n"
"\n"
"It does nothing useful - just prints a message that is was called\n"
"and shows the current address.\n";
//--------------------------------------------------------------------------
// This is the preferred name of the plugin module in the menu system
// The preferred name may be overridden in plugins.cfg file
static const char wanted_name[] = "Sample plugin";
// This is the preferred hotkey for the plugin module
// The preferred hotkey may be overridden in plugins.cfg file
static const char wanted_hotkey[] = "";
//--------------------------------------------------------------------------
//
// PLUGIN DESCRIPTION BLOCK
//
//--------------------------------------------------------------------------
plugin_t PLUGIN =
{
IDP_INTERFACE_VERSION,
PLUGIN_MULTI, // plugin flags
init, // initialize
nullptr, // terminate. this pointer may be nullptr.
nullptr, // invoke plugin
comment, // long comment about the plugin
// it could appear in the status line
// or as a hint
help, // multiline help about the plugin
wanted_name, // the preferred short name of the plugin
wanted_hotkey // the preferred hotkey to run the plugin
};
calle
Sample plugin that allows the user to change the address of the called function.
/*
* Change the callee address for constructions like
*
* call esi ; LocalFree
*
*/
#include <ida.hpp>
#include <idp.hpp>
#include <loader.hpp>
#include <kernwin.hpp>
#include <bytes.hpp>
#include <auto.hpp>
#include <segregs.hpp>
#define T 20
struct callee_vars_t : public plugmod_t
{
processor_t &ph;
callee_vars_t(processor_t &_ph) : ph(_ph) {}
virtual bool idaapi run(size_t arg) override;
};
//--------------------------------------------------------------------------
static plugmod_t *idaapi init()
{
processor_t &ph = PH;
if ( ph.id != PLFM_386 && ph.id != PLFM_MIPS && ph.id != PLFM_ARM )
return nullptr; // only for x86, MIPS and ARM
return new callee_vars_t(ph);
}
//--------------------------------------------------------------------------
static const char comment[] = "Change the callee address";
static const char help[] =
"This plugin allows the user to change the address of the called function\n"
"in constructs like\n"
"\n"
" call esi\n"
"\n"
"You can enter a function name instead of its address\n";
//--------------------------------------------------------------------------
static const char *const form =
"HELP\n"
"%s\n"
"ENDHELP\n"
"Enter the callee address\n"
"\n"
" <~C~allee:$::40:::>\n"
"\n"
"\n";
bool idaapi callee_vars_t::run(size_t)
{
const char *nname;
if ( ph.id == PLFM_MIPS )
nname = "$ mips";
else if ( ph.id == PLFM_ARM )
nname = " $arm";
else
nname = "$ vmm functions";
netnode n(nname);
ea_t ea = get_screen_ea(); // get current address
if ( !is_code(get_flags(ea)) )
return false; // not an instruction
// get the callee address from the database
ea_t callee = node2ea(n.altval_ea(ea)-1);
// remove thumb bit for arm
if ( ph.id == PLFM_ARM )
callee &= ~1;
char buf[MAXSTR];
qsnprintf(buf, sizeof(buf), form, help);
if ( ask_form(buf, &callee) )
{
if ( callee == BADADDR )
{
n.altdel_ea(ea);
}
else
{
if ( ph.id == PLFM_ARM && (callee & 1) == 0 )
{
// if we're calling a thumb function, set bit 0
sel_t tbit = get_sreg(callee, T);
if ( tbit != 0 && tbit != BADSEL )
callee |= 1;
}
// save the new address
n.altset_ea(ea, ea2node(callee)+1);
}
gen_idb_event(idb_event::callee_addr_changed, ea, callee);
plan_ea(ea); // reanalyze the current instruction
}
return true;
}
//--------------------------------------------------------------------------
static const char wanted_name[] = "Change the callee address";
static const char wanted_hotkey[] = "Alt-F11";
//--------------------------------------------------------------------------
//
// PLUGIN DESCRIPTION BLOCK
//
//--------------------------------------------------------------------------
plugin_t PLUGIN =
{
IDP_INTERFACE_VERSION,
PLUGIN_MULTI, // plugin flags
init, // initialize
nullptr, // terminate. this pointer may be nullptr.
nullptr, // invoke plugin
comment, // long comment about the plugin
// it could appear in the status line
// or as a hint
help, // multiline help about the plugin
wanted_name, // the preferred short name of the plugin
wanted_hotkey // the preferred hotkey to run the plugin
};
choose
Sample plugin module that demonstrates the use of the choose() function.
/*
* This is a sample plugin module
*
* It demonstrates the use of the choose() function
*
*/
#include <ida.hpp>
#include <idp.hpp>
#include <loader.hpp>
#include <bytes.hpp>
#include <kernwin.hpp>
struct plugin_ctx_t : public plugmod_t
{
virtual bool idaapi run(size_t arg) override;
};
//--------------------------------------------------------------------------
static plugmod_t *idaapi init()
{
return new plugin_ctx_t;
}
//-------------------------------------------------------------------------
// non-modal call instruction chooser
struct calls_chooser_t : public chooser_t
{
protected:
static const int widths_[];
static const char *const header_[];
public:
// remember the call instruction addresses in this qvector
eavec_t list;
// this object must be allocated using `new`
calls_chooser_t(const char *title, bool ok, func_item_iterator_t *fii);
// function that is used to decide whether a new chooser should be opened
// or we can use the existing one.
// The contents of the window are completely determined by its title
virtual const void *get_obj_id(size_t *len) const override
{
*len = strlen(title);
return title;
}
// function that returns number of lines in the list
virtual size_t idaapi get_count() const override { return list.size(); }
// function that generates the list line
virtual void idaapi get_row(
qstrvec_t *cols,
int *icon_,
chooser_item_attrs_t *attrs,
size_t n) const override;
// function that is called when the user hits Enter
virtual cbret_t idaapi enter(size_t n) override
{
if ( n < list.size() )
jumpto(list[n]);
return cbret_t(); // nothing changed
}
protected:
void build_list(bool ok, func_item_iterator_t *fii)
{
insn_t insn;
while ( ok )
{
ea_t ea = fii->current();
if ( decode_insn(&insn, ea) > 0 && is_call_insn(insn) ) // a call instruction is found
list.push_back(ea);
ok = fii->next_code();
}
}
};
// column widths
const int calls_chooser_t::widths_[] =
{
CHCOL_HEX | 8, // Address
32, // Instruction
};
// column headers
const char *const calls_chooser_t::header_[] =
{
"Address", // 0
"Instruction", // 1
};
inline calls_chooser_t::calls_chooser_t(
const char *title_,
bool ok,
func_item_iterator_t *fii)
: chooser_t(0, qnumber(widths_), widths_, header_, title_),
list()
{
CASSERT(qnumber(widths_) == qnumber(header_));
// build the list of calls
build_list(ok, fii);
}
void idaapi calls_chooser_t::get_row(
qstrvec_t *cols_,
int *,
chooser_item_attrs_t *,
size_t n) const
{
// assert: n < list.size()
ea_t ea = list[n];
// generate the line
qstrvec_t &cols = *cols_;
cols[0].sprnt("%08a", ea);
generate_disasm_line(&cols[1], ea, GENDSM_REMOVE_TAGS);
CASSERT(qnumber(header_) == 2);
}
//--------------------------------------------------------------------------
// The plugin method
// This is the main function of the plugin.
bool idaapi plugin_ctx_t::run(size_t)
{
qstring title;
// Let's display the functions called from the current one
// or from the selected area
// First we determine the working area
func_item_iterator_t fii;
bool ok;
ea_t ea1, ea2;
if ( read_range_selection(nullptr, &ea1, &ea2) ) // the selection is present?
{
callui(ui_unmarksel); // unmark selection
title.sprnt("Functions called from %08a..%08a", ea1, ea2);
ok = fii.set_range(ea1, ea2);
}
else // nothing is selected
{
func_t *pfn = get_func(get_screen_ea()); // try the current function
if ( pfn == nullptr )
{
warning("Please position the cursor on a function or select an area");
return true;
}
ok = fii.set(pfn);
get_func_name(&title, pfn->start_ea);
title.insert("Functions called from ");
}
// now open the window
calls_chooser_t *ch = new calls_chooser_t(title.c_str(), ok, &fii);
ch->choose(); // the default cursor position is 0 (first row)
return true; //-V773
}
//--------------------------------------------------------------------------
//
// PLUGIN DESCRIPTION BLOCK
//
//--------------------------------------------------------------------------
plugin_t PLUGIN =
{
IDP_INTERFACE_VERSION,
// plugin flags
PLUGIN_MULTI,
// initialize
init,
nullptr,
nullptr,
// long comment about the plugin
// it could appear in the status line
// or as a hint
"This is a sample plugin. It displays the chooser window",
// multiline help about the plugin
"A sample plugin module\n"
"\n"
"This module shows you how to use choose() function.\n",
// the preferred short name of the plugin
"Called functions",
// the preferred hotkey to run the plugin
""
};
custdata
This sample plugin demonstates how to install a custom data type and a custom data format.
custview
This sample plugin demonstates how to create and manipulate a simple custom viewer, that allows you to create a view which displays colored lines.
cvt64_sample
Plugin with CVT64 examples.
dwarf
The source code of the dwarf plugin
ex_debidc
This sample Debugger IDC Helper executes IDC script when the process is launched and allows to hook IDC scripts to various debugger events.
// Debugger IDC Helper
// Executes IDC script when the process is launched
// In fact, this approach can be used to hook IDC scripts to various debugger
// events.
#include <ida.hpp>
#include <idp.hpp>
#include <dbg.hpp>
#include <expr.hpp>
#include <loader.hpp>
int data_id;
//--------------------------------------------------------------------------
// The plugin stores the IDC file name in the database
// It will create a node for this purpose
static const char node_name[] = "$ debugger idc file";
//--------------------------------------------------------------------------
struct plugin_ctx_t;
DECLARE_LISTENER(dbg_listener_t, plugin_ctx_t, ctx);
DECLARE_LISTENER(idp_listener_t, plugin_ctx_t, ctx);
struct plugin_ctx_t : public plugmod_t
{
dbg_listener_t dbg_listener = dbg_listener_t(*this);
idp_listener_t idp_listener = idp_listener_t(*this);
plugin_ctx_t()
{
hook_event_listener(HT_DBG, &dbg_listener);
#ifdef ENABLE_MERGE
hook_event_listener(HT_IDP, &idp_listener);
#endif
set_module_data(&data_id, this);
}
~plugin_ctx_t()
{
clr_module_data(data_id);
// listeners are uninstalled automatically
// when the owner module is unloaded
}
virtual bool idaapi run(size_t) override;
};
//--------------------------------------------------------------------------
// Get the IDC file name from the database
static bool get_idc_name(char *buf, size_t bufsize)
{
// access the node
netnode mynode(node_name);
// retrieve the value
return mynode.valstr(buf, bufsize) > 0;
}
//--------------------------------------------------------------------------
// Store the IDC file name in the database
static void set_idc_name(const char *idc)
{
// access the node
netnode mynode;
// if it doesn't exist yet, create it
// otherwise get its id
mynode.create(node_name);
// store the value
mynode.set(idc, strlen(idc)+1);
}
//--------------------------------------------------------------------------
ssize_t idaapi idp_listener_t::on_event(ssize_t code, va_list va)
{
return 0;
}
//--------------------------------------------------------------------------
ssize_t idaapi dbg_listener_t::on_event(ssize_t code, va_list /*va*/)
{
switch ( code )
{
case dbg_process_start:
case dbg_process_attach:
// it is time to run the script
char idc[QMAXPATH];
if ( get_idc_name(idc, sizeof(idc)) )
{
qstring errbuf;
if ( !exec_idc_script(nullptr, idc, "main", nullptr, 0, &errbuf) )
warning("%s", errbuf.c_str());
}
break;
}
return 0;
}
//--------------------------------------------------------------------------
bool idaapi plugin_ctx_t::run(size_t)
{
// retrieve the old IDC name from the database
char idc[QMAXPATH];
if ( !get_idc_name(idc, sizeof(idc)) )
qstrncpy(idc, "*.idc", sizeof(idc));
char *newidc = ask_file(false, idc, "Specify the script to run upon debugger launch");
if ( newidc != nullptr )
{
// store it back in the database
set_idc_name(newidc);
msg("Script %s will be run when the debugger is launched\n", newidc);
}
return true;
}
//--------------------------------------------------------------------------
static plugmod_t *idaapi init()
{
// Our plugin works only for x86 PE executables
processor_t &ph = PH;
if ( ph.id != PLFM_386 || inf_get_filetype() != f_PE )
return nullptr;
return new plugin_ctx_t;
}
//--------------------------------------------------------------------------
static const char wanted_name[] = "Specify Debugger IDC Script";
static const char wanted_hotkey[] = "";
//--------------------------------------------------------------------------
//
// PLUGIN DESCRIPTION BLOCK
//
//--------------------------------------------------------------------------
plugin_t PLUGIN =
{
IDP_INTERFACE_VERSION,
PLUGIN_MULTI, // The plugin can work with multiple idbs in parallel
init, // initialize
nullptr,
nullptr,
wanted_name, // long comment about the plugin
wanted_name, // multiline help about the plugin
wanted_name, // the preferred short name of the plugin
wanted_hotkey // the preferred hotkey to run the plugin
};
ex_events1
Sample plugin illustrating analysis improvement; it checks branch targets for newly created instructions.
/*
This is a sample plugin.
It illustrates how the analysis can be improved
The plugin checks branch targets for newly created instructions.
If the target does not exist in the program, the plugin
forbids the instruction creation.
*/
#include <ida.hpp>
#include <idp.hpp>
#include <loader.hpp>
#include <kernwin.hpp>
#include <allins.hpp>
//--------------------------------------------------------------------------
struct plugin_ctx_t : public plugmod_t, public event_listener_t
{
plugin_ctx_t()
{
hook_event_listener(HT_IDB, this);
}
~plugin_ctx_t()
{
// listeners are uninstalled automatically
// when the owner module is unloaded
}
virtual bool idaapi run(size_t) override;
virtual ssize_t idaapi on_event(ssize_t code, va_list va) override;
};
//--------------------------------------------------------------------------
// This callback is called by the kernel when database related events happen
ssize_t idaapi plugin_ctx_t::on_event(ssize_t event_id, va_list va)
{
switch ( event_id )
{
case idb_event::make_code: // An instruction is being created
// args: insn_t *
// returns: 1-ok, <=0-the kernel should stop
insn_t *insn = va_arg(va, insn_t *);
// we are interested in the branch instructions
if ( insn->itype >= NN_ja && insn->itype <= NN_jmpshort )
{
// the first operand contains the jump target
ea_t target = to_ea(insn->cs, insn->Op1.addr);
if ( !is_mapped(target) )
return -1;
}
}
return 0; // event not processed
// let other plugins handle it
}
//--------------------------------------------------------------------------
static plugmod_t *idaapi init()
{
return new plugin_ctx_t;
}
//--------------------------------------------------------------------------
bool idaapi plugin_ctx_t::run(size_t)
{
// since the plugin is fully automatic, there is nothing to do
warning("Branch checker is fully automatic");
return true;
}
//--------------------------------------------------------------------------
plugin_t PLUGIN =
{
IDP_INTERFACE_VERSION,
PLUGIN_HIDE // Plugin should not appear in the Edit, Plugins menu
| PLUGIN_MULTI, // The plugin can work with multiple idbs in parallel
init, // initialize
nullptr,
nullptr,
nullptr, // long comment about the plugin
nullptr, // multiline help about the plugin
"Branch checker", // the preferred short name of the plugin
nullptr, // the preferred hotkey to run the plugin
};
extlang
Sample plugin that illustrates how to register a thid party language interpreter.
/*
This is a sample plugin. It illustrates
how to register a thid party language interpreter
*/
#include <ida.hpp>
#include <idp.hpp>
#include <loader.hpp>
#include <expr.hpp>
#include <kernwin.hpp>
//--------------------------------------------------------------------------
static bool idaapi compile_expr(// Compile an expression
const char *name, // in: name of the function which will
// hold the compiled expression
ea_t current_ea, // in: current address. if unknown then BADADDR
const char *expr, // in: expression to compile
qstring *errbuf) // out: error message if compilation fails
{ // Returns: success
qnotused(name);
qnotused(current_ea);
qnotused(expr);
// our toy interpreter doesn't support separate compilation/evaluation
// some entry fields in ida won't be useable (bpt conditions, for example)
if ( errbuf != nullptr )
*errbuf = "compilation error";
return false;
}
//--------------------------------------------------------------------------
static bool idaapi call_func( // Evaluate a previously compiled expression
idc_value_t *result, // out: function result
const char *name, // in: function to call
const idc_value_t args[], // in: input arguments
size_t nargs, // in: number of input arguments
qstring *errbuf) // out: error message if compilation fails
{ // Returns: success
qnotused(name);
qnotused(nargs);
qnotused(args);
qnotused(result);
if ( errbuf != nullptr )
*errbuf = "evaluation error";
return false;
}
//--------------------------------------------------------------------------
bool idaapi eval_expr( // Compile and evaluate expression
idc_value_t *rv, // out: expression value
ea_t current_ea, // in: current address. if unknown then BADADDR
const char *expr, // in: expression to evaluation
qstring *errbuf) // out: error message if compilation fails
{ // Returns: success
qnotused(current_ea);
// we know to parse and decimal and hexadecimal numbers
int radix = 10;
const char *ptr = skip_spaces(expr);
bool neg = false;
if ( *ptr == '-' )
{
neg = true;
ptr = skip_spaces(ptr+1);
}
if ( *ptr == '0' && *(ptr+1) == 'x' )
{
radix = 16;
ptr += 2;
}
sval_t value = 0;
while ( radix == 10 ? qisdigit(*ptr) : qisxdigit(*ptr) )
{
int d = *ptr <= '9' ? *ptr-'0' : qtolower(*ptr)-'a'+10;
value *= radix;
value += d;
ptr++;
}
if ( neg )
value = -value;
ptr = skip_spaces(ptr);
if ( *ptr != '\0' )
{
msg("EVAL FAILED: %s\n", expr);
if ( errbuf != nullptr )
*errbuf = "syntax error";
return false;
}
// we have the result, store it in the return value
if ( rv != nullptr )
{
rv->clear();
rv->num = value;
}
msg("EVAL %" FMT_EA "d: %s\n", value, expr);
return true;
}
//--------------------------------------------------------------------------
struct plugin_ctx_t : public plugmod_t
{
extlang_t my_extlang =
{
sizeof(extlang_t), // Size of this structure
0, // Language features, currently 0
0, // refcnt
"extlang sample", // Language name
nullptr, // fileext
nullptr, // syntax highlighter
compile_expr,
nullptr, // compile_file
call_func,
eval_expr,
nullptr, // create_object
nullptr, // get_attr
nullptr, // set_attr
nullptr, // call_method
nullptr, // eval_snippet
nullptr, // load_procmod
nullptr, // unload_procmod
};
bool installed = false;
plugin_ctx_t()
{
installed = install_extlang(&my_extlang) >= 0;
}
~plugin_ctx_t()
{
if ( installed )
remove_extlang(&my_extlang);
}
virtual bool idaapi run(size_t) override { return false; }
};
//--------------------------------------------------------------------------
static plugmod_t *idaapi init()
{
plugin_ctx_t *ctx = new plugin_ctx_t;
if ( !ctx->installed )
{
msg("extlang: install_extlang() failed\n");
delete ctx;
ctx = nullptr;
}
return ctx;
}
//--------------------------------------------------------------------------
plugin_t PLUGIN =
{
IDP_INTERFACE_VERSION,
PLUGIN_HIDE // Plugin should not appear in the Edit, Plugins menu
| PLUGIN_FIX // Load plugin when IDA starts and keep it in the
// memory until IDA stops
| PLUGIN_MULTI, // The plugin can work with multiple idbs in parallel
init, // initialize
nullptr,
nullptr,
nullptr, // long comment about the plugin
nullptr, // multiline help about the plugin
"Sample third party language", // the preferred short name of the plugin
nullptr, // the preferred hotkey to run the plugin
};
formsample
This plugin demonstrates how to use complex forms.
/*
* This plugin demonstrates how to use complex forms.
*
*/
#include <ida.hpp>
#include <idp.hpp>
#include <loader.hpp>
#include <kernwin.hpp>
//--------------------------------------------------------------------------
struct plugin_ctx_t : public plugmod_t
{
virtual bool idaapi run(size_t) override;
};
//--------------------------------------------------------------------------
static int idaapi btn_cb(int, form_actions_t &)
{
warning("button pressed");
return 0;
}
//--------------------------------------------------------------------------
static int idaapi modcb(int fid, form_actions_t &fa)
{
switch ( fid )
{
case CB_INIT:
msg("initializing\n");
break;
case CB_YES:
msg("terminating\n");
break;
case 5: // operand
msg("changed operand\n");
break;
case 6: // check
msg("changed check\n");
break;
case 7: // button
msg("changed button\n");
break;
case 8: // color button
msg("changed color button\n");
break;
default:
msg("unknown id %d\n", fid);
break;
}
bool is_gui = is_idaq();
qstring buf0;
if ( !fa.get_string_value(5, &buf0) )
INTERR(30145);
if ( buf0 == "on" )
fa.enable_field(12, true);
if ( buf0 == "off" )
fa.enable_field(12, false);
ushort buf1;
if ( !fa.get_cbgroup_value(12, &buf1) )
INTERR(30146);
fa.show_field(7, (buf1 & 1) != 0);
fa.enable_field(8, (buf1 & 2) != 0);
ushort c13;
if ( !fa.get_checkbox_value(13, &c13) )
INTERR(30147);
fa.enable_field(10, c13 != 0);
ushort c14;
if ( !fa.get_checkbox_value(14, &c14) )
INTERR(30148);
fa.enable_field(5, c14 != 0);
ushort c15;
if ( !fa.get_checkbox_value(15, &c15) )
INTERR(30149);
if ( (buf1 & 8) != 0 )
{
sval_t x, y, w, h;
fa.get_signed_value(4, &x);
fa.get_signed_value(3, &y);
fa.get_signed_value(2, &w);
fa.get_signed_value(1, &h);
fa.move_field(5, x, y, w, h);
if ( x != -1 && c15 )
fa.move_field(-5, x-7, y, w, h);
}
// get_field_value() for buttons must return false always
if ( fa._get_field_value(7, nullptr) )
INTERR(30150);
bgcolor_t bgc = -1;
if ( is_gui && !fa.get_color_value(8, &bgc) )
INTERR(30151);
msg(" op=%s change=%x color=%x\n", buf0.c_str(), buf1, bgc);
fa.set_label_value(9, buf0.c_str());
return 1;
}
//--------------------------------------------------------------------------
bool idaapi plugin_ctx_t::run(size_t)
{
static const char form[] =
"@0:477[]\n"
"Manual operand\n"
"\n"
"%/Enter alternate string for the %9X operand\n"
"\n"
" <~O~perand:q5:100:40::>\n"
" <~X~:D4:100:10::>\n"
" <~Y~:D3:100:10::>\n"
" <~W~:D2:100:10::>\n"
" <~H~:D1:100:10::>\n"
"\n"
" <S~h~ow Button:C10>\n"
" <~E~nable color Button:C11>\n"
" <~E~nable C10:C13>\n"
" <~S~et operand bounds:C6>\n"
" <Enable operand:C14>\n"
" <Move label:C15>12>\n"
"\n"
" <~B~utton:B7:0:::> <~C~olor button:K8::::>\n"
"\n"
"\n";
qstring buf("original");
ushort check = 0x12;
bgcolor_t bgc = 0x556677;
uval_t x = -1;
uval_t y = -1;
uval_t w = -1;
uval_t h = -1;
CASSERT(IS_FORMCHGCB_T(modcb));
CASSERT(IS_QSTRING(buf));
if ( ask_form(form, modcb, buf.c_str(), &buf, &x, &y, &w, &h, &check, btn_cb, &bgc) > 0 )
{
msg("operand: %s\n", buf.c_str());
msg("check = %d\n", check);
msg("dim = %a %a %a %a\n", x, y, w, h);
msg("bgc = %x\n", bgc);
}
return true;
}
//--------------------------------------------------------------------------
static plugmod_t *idaapi init()
{
return new plugin_ctx_t;
}
funclist
This sample plugin demonstrates how to get the the entry point prototypes.
/*
* This is a sample plugin module
*
* It demonstrates how to get the the entry point prototypes
*
*/
#include <ida.hpp>
#include <idp.hpp>
#include <auto.hpp>
#include <entry.hpp>
#include <bytes.hpp>
#include <loader.hpp>
#include <kernwin.hpp>
#include <typeinf.hpp>
//--------------------------------------------------------------------------
struct plugin_ctx_t : public plugmod_t
{
virtual bool idaapi run(size_t) override;
};
//-------------------------------------------------------------------------
// non-modal entry point chooser
struct entry_chooser_t : public chooser_t
{
protected:
struct item_t
{
ea_t ea;
qstring decl;
int ord;
uint32 argsize;
};
// remember the information about an entry point in this qvector
qvector<item_t> list;
static const int widths_[];
static const char *const header_[];
public:
// this object must be allocated using `new`
entry_chooser_t();
// function that is used to decide whether a new chooser should be opened
// or we can use the existing one.
// There should be the only window as the entry points data are static.
virtual const void *get_obj_id(size_t *len) const override { *len = 1; return ""; }
// function that returns number of lines in the list
virtual size_t idaapi get_count() const override { return list.size(); }
// function that generates the list line
virtual void idaapi get_row(
qstrvec_t *cols,
int *icon_,
chooser_item_attrs_t *attrs,
size_t n) const override;
// function that is called when the user hits Enter
virtual cbret_t idaapi enter(size_t n) override
{
if ( n < list.size() )
jumpto(list[n].ea);
return cbret_t(); // nothing changed
}
// function that is called when the chooser is initialized
virtual bool idaapi init() override
{
// rebuild the list
list.clear();
size_t n = get_entry_qty();
// gather information about the entry points
for ( size_t i = 0; i < n; ++i )
{
asize_t ord = get_entry_ordinal(int(i));
ea_t ea = get_entry(ord);
if ( ord == ea )
continue;
tinfo_t type;
qstring decl;
qstring long_name;
qstring true_name;
asize_t argsize = 0;
qstring entry_name;
get_entry_name(&entry_name, ord);
if ( get_tinfo(&type, ea) && type.print(&decl, entry_name.c_str()) )
{
// found type info, calc the size of arguments
func_type_data_t fi;
if ( type.get_func_details(&fi) && !fi.empty() )
{
for ( int k=0; k < fi.size(); k++ )
{
int s1 = fi[k].type.get_size();
uchar szi = inf_get_cc_size_i();
s1 = qmax(s1, szi);
argsize += s1;
}
}
}
else if ( get_long_name(&long_name, ea) > 0
&& get_name(&true_name, ea, GN_NOT_DUMMY) > 0
&& long_name != true_name )
{
// found mangled name
}
else
{
// found nothing, just show the name
if ( get_visible_name(&decl, ea) <= 0 )
continue;
}
if ( argsize == 0 )
{
func_t *pfn = get_func(ea);
if ( pfn != nullptr )
argsize = pfn->argsize;
}
item_t x;
x.ord = ord;
x.ea = ea;
x.decl.swap(decl);
x.argsize = uint32(argsize);
list.push_back(x);
}
return true;
}
// function that is called when the user wants to refresh the chooser
virtual cbret_t idaapi refresh(ssize_t n) override
{
init();
if ( n < 0 )
return NO_SELECTION;
return adjust_last_item(n); // try to preserve the cursor
}
};
DECLARE_TYPE_AS_MOVABLE(entry_chooser_t::item_t);
// column widths
const int entry_chooser_t::widths_[] =
{
CHCOL_DEC | 4, // Ordinal
CHCOL_HEX | 8, // Address
CHCOL_HEX | 6, // ArgSize
70, // Declaration
};
// column headers
const char *const entry_chooser_t::header_[] =
{
"Ordinal", // 0
"Address", // 1
"ArgSize", // 2
"Declaration", // 3
};
inline entry_chooser_t::entry_chooser_t()
: chooser_t(CH_CAN_REFRESH, // user can refresh the chooser using Ctrl-U
qnumber(widths_), widths_, header_,
"Exported functions"),
list()
{
CASSERT(qnumber(widths_) == qnumber(header_));
}
void idaapi entry_chooser_t::get_row(
qstrvec_t *cols_,
int *,
chooser_item_attrs_t *,
size_t n) const
{
// assert: n < list.size()
const item_t &item = list[n];
// generate the line
qstrvec_t &cols = *cols_;
cols[0].sprnt("%d", item.ord);
cols[1].sprnt("%08a", item.ea);
if ( item.argsize != 0 )
cols[2].sprnt("%04x", item.argsize);
cols[3] = item.decl;
CASSERT(qnumber(header_) == 4);
}
//--------------------------------------------------------------------------
bool idaapi plugin_ctx_t::run(size_t)
{
if ( !auto_is_ok()
&& ask_yn(ASKBTN_NO,
"HIDECANCEL\n"
"The autoanalysis has not finished yet.\n"
"The result might be incomplete.\n"
"Do you want to continue?") < ASKBTN_YES )
{
return true;
}
// open the window
entry_chooser_t *ch = new entry_chooser_t();
ch->choose();
return true; //-V773
} //lint !e429 'ch' has not been freed or returned
//--------------------------------------------------------------------------
static plugmod_t *idaapi init()
{
if ( get_entry_qty() == 0 )
return nullptr;
return new plugin_ctx_t;
}
//--------------------------------------------------------------------------
plugin_t PLUGIN =
{
IDP_INTERFACE_VERSION,
PLUGIN_MULTI, // The plugin can work with multiple idbs in parallel
init, // initialize
nullptr,
nullptr,
"Generate list of exported function prototypes",
"Generate list of exported function prototypes",
"List of exported functions",
"Ctrl-F11",
};
getlines
This sample plugin demonstrates how to get the disassembly lines for one address.
/*
* This is a sample plugin module
*
* It demonstrates how to get the disassembly lines for one address
*
*/
#include <ida.hpp>
#include <idp.hpp>
#include <bytes.hpp>
#include <loader.hpp>
#include <kernwin.hpp>
//--------------------------------------------------------------------------
struct plugin_ctx_t : public plugmod_t
{
virtual bool idaapi run(size_t) override;
};
//--------------------------------------------------------------------------
bool idaapi plugin_ctx_t::run(size_t)
{
ea_t ea = get_screen_ea();
if ( ask_addr(&ea, "Please enter the disassembly address")
&& is_mapped(ea) ) // address belongs to disassembly
{
int flags = calc_default_idaplace_flags();
linearray_t ln(&flags);
idaplace_t pl;
pl.ea = ea;
pl.lnnum = 0;
ln.set_place(&pl);
msg("printing disassembly lines:\n");
int n = ln.get_linecnt(); // how many lines for this address?
for ( int i=0; i < n; i++ ) // process all of them
{
qstring buf;
tag_remove(&buf, *ln.down()); // get line and remove color codes
msg("%d: %s\n", i, buf.c_str()); // display it on the message window
}
msg("total %d lines\n", n);
}
return true;
}
//--------------------------------------------------------------------------
static plugmod_t *idaapi init()
{
return new plugin_ctx_t;
}
//--------------------------------------------------------------------------
static const char comment[] = "Generate disassembly lines for one address";
static const char help[] = "Generate disassembly lines for one address\n";
//--------------------------------------------------------------------------
// This is the preferred name of the plugin module in the menu system
// The preferred name may be overridden in plugins.cfg file
static const char wanted_name[] = "Disassembly lines sample";
// This is the preferred hotkey for the plugin module
// The preferred hotkey may be overridden in plugins.cfg file
static const char wanted_hotkey[] = "";
//--------------------------------------------------------------------------
//
// PLUGIN DESCRIPTION BLOCK
//
//--------------------------------------------------------------------------
plugin_t PLUGIN =
{
IDP_INTERFACE_VERSION,
PLUGIN_MULTI, // The plugin can work with multiple idbs in parallel
init, // initialize
nullptr,
nullptr,
comment, // long comment about the plugin
help, // multiline help about the plugin
wanted_name, // the preferred short name of the plugin
wanted_hotkey // the preferred hotkey to run the plugin
};
highlighter
This plugin will display a colored box at the executed instructions.
// Highlighter plugin v1.0
// Highlights executed instructions
// This plugin will display a colored box at the executed instructions.
// It will take into account only the instructions where the application
// has been suspended.
// http://www.hexblog.com/2005/11/the_highlighter.html
// Copyright 2005 Ilfak Guilfanov, <ig@hexblog.com>
#include <ida.hpp>
#include <idp.hpp>
#include <dbg.hpp>
#include <loader.hpp>
#include <kernwin.hpp>
//--------------------------------------------------------------------------
struct plugin_ctx_t;
struct idd_post_events_t : public post_event_visitor_t
{
plugin_ctx_t &ctx;
idd_post_events_t(plugin_ctx_t &_ctx) : ctx(_ctx) {}
virtual ssize_t idaapi handle_post_event(
ssize_t code,
int notification_code,
va_list va) override;
};
//--------------------------------------------------------------------------
struct exec_prefix_t : public user_defined_prefix_t
{