Plugins are dynamic link libraries (DLLs) that attach to the OllyDbg and extend its functionality.
How plugins work
During startup, OllyDbg walks plugin directory (specified under Options | Directories | Plugin directory) and attempts to load all files with extension .dll. In each file it looks for the procedure named ODBG2_Pluginquery() (or _ODBG2_Pluginquery(), see Compilation below) and calls it, passing actual OllyDbg version. If this version is too low and does not support all required features, plugin must return 0. Otherwise, it must return PLUGIN_VERSION defined in the API header file plugin.h. If version of the plugin interface for which plugin was compiled is not compatible with the actual, OllyDbg will unload plugin and won't use it anymore.
All other plugin entries are optional. Let's assume that plugin implements them all. In this case, the sequence of calls is following:
- when plugin starts, OllyDbg calls ODBG2_Plugininit();
- when user opens Plugin options dialog, OllyDbg calls ODBG2_Pluginoptions() several times with different messages;
- when plugin starts or when new application is loaded, OllyDbg calls ODBG2_Pluginreset();
- when OllyDbg loads .udd file and encounters data previously saved by plugin, for each data record it calls ODBG2_Pluginuddrecord();
- when OllyDbg analyses some module, at the end of analysis it calls ODBG2_Pluginanalyse(), giving plugin the chance to make additional analysis;
- periodically, OllyDbg calls ODBG2_Pluginmainloop(NULL);
- when OllyDbg receives debugging event from the debugged application, it passes this event to ODBG2_Pluginmainloop(). Additionally, if event is EXCEPTION_DEBUG_EVENT, it calls ODBG2_Pluginexception(). If event is a temporary breakpoint (INT3 or hardware) that was previously set by plugin or on its request, it calls ODBG2_Plugintempbreakpoint();
- on some more or less important events, OllyDbg calls ODBG2_Pluginnotify();
- when OllyDbg redraws any dump window, it calls ODBG2_Plugindump(). Plugin can change the displayed text or its appearance;
- when user invokes main OllyDbg menu or popup menu in the standard window, plugin receives call to ODBG2_Pluginmenu() and can add its own items to the menu;
- when Windows unload module (.dll or .exe) from the memory, OllyDbg calls ODBG2_Pluginsaveudd(), so that plugin can save module-related data to the .udd file;
- when user closes OllyDbg, plugin receives ODBG2_Pluginclose() and may prevent debugger from closing;
- when OllyDbg terminates, it calls ODBG2_Plugindestroy().
They are called very frequently and may slow down the debugging.
Private data types
OllyDbg keeps small pieces of the data of variable size in the central depository called data table. Each kind of data has its own tag, or data type. For example, labels added by the Analyser are saved as NM_ANALYSE and switch cases - as records of type DT_CASE. Data table may keep tens of millions of records. Access to these records is very quick, so it looks like an ideal depository for the plugin-related data. However, data types are scarce resource (only 126 types available to plugins) and can't be distributed statically.
To get private tags, plugin may call Plugingetuniquedatatype(), once for each private data type it needs. These types are valid till OllyDbg closes. Types are distributed according to the "first asked - first served" rule. The best time to get private types is inside the ODBG2_Plugininit().
As data types is a really scarce resource, please always check whether there is an alternative way to keep your data.
Compilation
When creating and compiling plugins, please note the following:
- OllyDbg is now a UNICODE application;
- OllyDbg structures are byte-aligned;
- names of exported functions are not prefixed (Setint3breakpoint, HexprintW);
- names of exported data items are preceded by underscore (_module, _ischild);
- most API functions are not thread-safe;
- plugins should export callback functions by name, not by ordinal;
- underscore prefix for exported callback functions is optional. That is, your compiler may produce either _ODBG2_Pluginquery() or ODBG2_Pluginquery() etc., and plugin will remain functional
Plugin callback functions:
int ODBG2_Pluginquery(int ollydbgversion,ulong *features,wchar_t pluginname[SHORTNAME],wchar_t pluginversion[SHORTNAME]);
int ODBG2_Plugininit(void);
void ODBG2_Pluginanalyse(t_module *pmod);
void ODBG2_Pluginmainloop(DEBUG_EVENT *debugevent);
int ODBG2_Pluginexception(t_run *prun,const t_disasm *da,t_thread *pthr,t_reg *preg,wchar_t *message);
void ODBG2_Plugintempbreakpoint(ulong addr,const t_disasm *da,t_thread *pthr,t_reg *preg);
void ODBG2_Pluginnotify(int code,void *data,ulong parm1,ulong parm2);
int ODBG2_Plugindump(t_dump *pd,wchar_t *s,uchar *mask,int n,int *select,ulong addr,int column);
t_menu * ODBG2_Pluginmenu(wchar_t *type);
t_control * ODBG2_Pluginoptions(UINT msg,WPARAM wp,LPARAM lp);
void ODBG2_Pluginsaveudd(t_uddsave *psave,t_module *pmod,int ismainmodule);
void ODBG2_Pluginuddrecord(t_module *pmod,int ismainmodule,ulong tag,ulong size,void *data);
void ODBG2_Pluginreset(void);
int ODBG2_Pluginclose(void);
void ODBG2_Plugindestroy(void);
Functions used only by plugins:
int Pluginsaverecord(t_uddsave *psave,ulong tag,ulong size,void *data);
int Pluginpackedrecord(t_uddsave *psave,ulong tag,ulong size,void *data);
void Pluginmodulechanged(ulong addr);
int Plugingetuniquedatatype(void);
int Plugintempbreakpoint(ulong addr,ulong type,int forceint3);
void Pluginshowoptions(t_control *options);
Example:
See annotated copies of bookmark.c and traceapi.c