Structure that describes menu items in OllyDbg.
typedef struct t_menu { // Menu descriptor
wchar_t *name; // Menu command
wchar_t *help; // Explanation of command
int shortcutid; // Shortcut identifier, K_xxx
MENUFUNC *menufunc; // Function that executes menu command
struct t_menu *submenu; // Pointer to descriptor of popup menu
union {
ulong index; // Argument passed to menu function
HMENU hsubmenu; // Handle of pulldown menu
};
} t_menu;
Members:
name
Text that will appear in menu. NULL indicates end of menu or submenu. Note that empty name has different meaning.
If the first symbol in the name is a vertical line ('|'), menu item is preceded by a separator (horizontal line that divides items into the logical groups). OllyDbg automatically removes unnecessary separators (duplicated, at the very beginning or at the end of menu). If you want to force separator, use double vertical line ('||')
If the first character is a greater than sign followed by a keyword (">STANDARD", ">FULLCOPY", ">APPEARANCE"), this menu item is a forwarder to the standard menu. Forwarder also means the end of the menu, subsequent items are not processed. Forwarders to standard menu are not allowed in the main OllyDbg menu or in the submenus of standard OllyDbg windows.
If name begins with an exclamation sign ('!'), this structure is an initializer. Initializers do not appear in menu. Their menufunc is called with mode=MENU_VERIFY to initialize global variables used by other menu items both in standard mode and when looking for a shortcut. Initializer must be the first item in menu or submenu.
Characters '$' and '*' are reserved by OllyDbg. Menu text can't begin with any of these characters.
During menu creation, menu function has the opportunity to change the text associated with menu item
help
If the first symbol in the name is a vertical line ('|'), menu item is preceded by a separator (horizontal line that divides items into the logical groups). OllyDbg automatically removes unnecessary separators (duplicated, at the very beginning or at the end of menu). If you want to force separator, use double vertical line ('||')
If the first character is a greater than sign followed by a keyword (">STANDARD", ">FULLCOPY", ">APPEARANCE"), this menu item is a forwarder to the standard menu. Forwarder also means the end of the menu, subsequent items are not processed. Forwarders to standard menu are not allowed in the main OllyDbg menu or in the submenus of standard OllyDbg windows.
If name begins with an exclamation sign ('!'), this structure is an initializer. Initializers do not appear in menu. Their menufunc is called with mode=MENU_VERIFY to initialize global variables used by other menu items both in standard mode and when looking for a shortcut. Initializer must be the first item in menu or submenu.
Characters '$' and '*' are reserved by OllyDbg. Menu text can't begin with any of these characters.
During menu creation, menu function has the opportunity to change the text associated with menu item
Help string associated with the menu item, may be empty or NULL
shortcutid
Shortcut or shortcut identifier associated with menu item, or K_NONE if there is no associated shortcut. Shortcuts are ignored if item is a forwarder or points to submenu.
menufunc
Menu
function associated with the menu item. During menu creation and
shortcut search it determines whether given item applies or not. If
menu item is selected or shortcut is found, menu function performs
necessary actions. Ignored if submenu is not NULL. See MENUFUNC for details
submenu
If name
is empty (L""), this is a forwarder to the menu that will continue
on the same level (and simultaneously the end of the current menu). If name
is not empty, this is a pointer to submenu. Note that if pointed menu
is empty or all its items are excluded by menu functions, submenu is
not created.
index
(submenu is NULL) User-defined argument which is passed to the menufunc. Allows use of the same menu finction with different menu items
hsubmenu
(submenu is defined) Used internally by OllyDbg, keeps handle of submenu
Standard menus
Pop-up menus in many table windows end with standard sections. Plugins may reference them as ">STANDARD",
">FULLCOPY" or ">APPEARANCE". STANDARD menu includes submenus
"Copy to clipboard", "Sort by" and "Appearance". FULLCOPY
consists of "Copy to clipboard" and "Appearance", and APPEARANCE includes only "Appearance". Here is an example of the FULLCOPY menu:
Table windows process standard menus automatically.
Standard menus are allowed only in the menus owned by plugin windows. Never use them in main menu or insert them into the existing windows!
Table windows process standard menus automatically.
Standard menus are allowed only in the menus owned by plugin windows. Never use them in main menu or insert them into the existing windows!
Keyboard shortcuts
OllyDbg supports immediate and indirect shortcuts.
Immediate shortcut is a virtual key code (VK_xxx) or a character code combined with KK_DIRECT and optionally with any of the following flags:
KK_CHAR - when flag is set, shortcut contains character code ('A', '+' etc.) Otherwise, shortcut contains virtual key code (letter or one of the constants VK_xxx, for example VK_RETURN, defined in the Windows header files)
KK_SHIFT - shortcut includes Shift key. Not allowed with KK_CHAR
KK_CTRL - shortcut includes Ctrl key
KK_ALT - shortcut includes Alt key
KK_WIN - shortcut includes WIN ("flying windows") key
KK_NOSH - shortcut ignores state of the Shift key. Used only in the main OllyDbg menu. Not allowed with KK_SHIFT
KK_DIRECT - indicates immediate shortcut
Available indirect shortcuts (constants in the range 1..1024) are listed in the file plugin.h. They are named K_xxx, for example K_UNDO, K_EDIT or K_COPY. Key combinations associated with indirect shortcuts can be redefined with Shortcut Editor. Plugins can't define new indirect shortcuts, but they can reuse existing. Don't use indirect shortcuts belonging to the main menu!
Immediate shortcut is a virtual key code (VK_xxx) or a character code combined with KK_DIRECT and optionally with any of the following flags:
KK_CHAR - when flag is set, shortcut contains character code ('A', '+' etc.) Otherwise, shortcut contains virtual key code (letter or one of the constants VK_xxx, for example VK_RETURN, defined in the Windows header files)
KK_SHIFT - shortcut includes Shift key. Not allowed with KK_CHAR
KK_CTRL - shortcut includes Ctrl key
KK_ALT - shortcut includes Alt key
KK_WIN - shortcut includes WIN ("flying windows") key
KK_NOSH - shortcut ignores state of the Shift key. Used only in the main OllyDbg menu. Not allowed with KK_SHIFT
KK_DIRECT - indicates immediate shortcut
Available indirect shortcuts (constants in the range 1..1024) are listed in the file plugin.h. They are named K_xxx, for example K_UNDO, K_EDIT or K_COPY. Key combinations associated with indirect shortcuts can be redefined with Shortcut Editor. Plugins can't define new indirect shortcuts, but they can reuse existing. Don't use indirect shortcuts belonging to the main menu!
Example:
This is the slightly modified menu of the INT3 Breakpoints window:
static t_bpoint *menubrk; // Pointer to selected item
// Initialization function of breakpoints menu.
static int Minitbreakmenu(t_table *pt,wchar *name,ulong index,int mode) {
menubrk=(t_bpoint *)Getsortedbyselection(&(pt->sorted),pt->sorted.selected);
return MENU_NORMAL;
};
// Menu function that executes menu command "Delete".
static int Mdeletebreak(t_table *pt,wchar *name,ulong index,int mode) {
int selected;
if (menubrk==NULL || (menubrk->type & BP_MANUAL)==0)
return MENU_ABSENT;
if (mode==MENU_VERIFY)
return MENU_NORMAL;
else if (mode==MENU_EXECUTE) {
selected=pt->sorted.selected;
Removeint3breakpoint(menubrk->addr,BP_MANUAL);
if (selected>=pt->sorted.n)
selected--;
Settableselection(pt,selected);
return MENU_REDRAW; };
return MENU_ABSENT;
};
// Menu function that executes menu commands "Disable" (index=0) and "Enable"
// (index=1).
static int Menablebreak(t_table *pt,wchar *name,ulong index,int mode) {
if (menubrk==NULL || (menubrk->type & BP_MANUAL)==0)
return MENU_ABSENT;
if (mode==MENU_VERIFY) {
if (((menubrk->type & BP_DISABLED)==0 && index!=0) ||
((menubrk->type & BP_DISABLED)!=0 && index==0)) return MENU_ABSENT;
return MENU_NORMAL; }
else if (mode==MENU_EXECUTE) {
Enableint3breakpoint(menubrk->addr,index);
// If menu function is called from shortcut, move selection down.
if (Menufromshortcut() && pt->sorted.selected<pt->sorted.n-1)
Settableselection(pt,pt->sorted.selected+1);
return MENU_REDRAW; };
return MENU_ABSENT;
};
// Menu function that executes menu command "Edit properties" (where index
// is either K_CONDBREAK or K_LOGBREAK, allowing both shortcuts to work).
static int Meditbreak(t_table *pt,wchar *name,ulong index,int mode) {
POINT coord;
if (menubrk==NULL || (menubrk->type & BP_MANUAL)==0)
return MENU_ABSENT;
if (mode==MENU_VERIFY) {
if (index==K_CONDBREAK) return MENU_SHORTCUT;
return MENU_NORMAL; }
else if (mode==MENU_EXECUTE) {
if (Gettableselectionxy(pt,2,&coord)<0)
coord.x=coord.y=-1; // Unknown coordinates, use defaults
if (index==K_CONDBREAK) Condbreakpoint(pt->hw,&(menubrk->addr),1,NULL,
coord.x,coord.y,pt->font);
else Condlogbreakpoint(pt->hw,&(menubrk->addr),1,0,NULL,
coord.x,coord.y,pt->font);
return MENU_REDRAW; };
return MENU_ABSENT;
};
// Menu function that executes menu command "Follow break in Disassembler".
static int Mfollowbreak(t_table *pt,wchar *name,ulong index,int mode) {
if (menubrk==NULL)
return MENU_ABSENT;
if (mode==MENU_VERIFY)
return MENU_NORMAL;
else if (mode==MENU_EXECUTE) {
Setcpu(0,menubrk->addr,0,0,0,CPU_ASMHIST|CPU_ASMCENTER|CPU_ASMFOCUS);
return MENU_NOREDRAW; };
return MENU_ABSENT;
};
// Menu function that executes menu commands "Disable all" (index=0) and
// "Enable all" (index=1).
static int Menableallbreaks(t_table *pt,wchar *name,ulong index,int mode) {
int i,nenabled,ndisabled;
t_bpoint *pbrk;
nenabled=ndisabled=0;
for (i=0; i<pt->sorted.n; i++) {
pbrk=(t_bpoint *)Getsortedbyindex(&(pt->sorted),i);
if ((pbrk->type & BP_MANUAL)==0)
continue;
if (pbrk->type & BP_DISABLED)
ndisabled++;
else
nenabled++;
;
};
if (mode==MENU_VERIFY) {
if (index==0 && nenabled==0) return MENU_ABSENT;
if (index!=0 && ndisabled==0) return MENU_ABSENT;
return MENU_NORMAL; }
else if (mode==MENU_EXECUTE) {
for (i=0; i<pt->sorted.n; i++) {
pbrk=(t_bpoint *)Getsortedbyindex(&(pt->sorted),i);
if ((pbrk->type & BP_MANUAL)==0)
continue;
if (index==0 && (pbrk->type & BP_DISABLED)!=0)
continue;
if (index!=0 && (pbrk->type & BP_DISABLED)==0)
continue;
Enableint3breakpoint(pbrk->addr,index); };
return MENU_REDRAW; };
return MENU_ABSENT;
};
static t_menu bpointmenu[] = {
{ L"!", NULL, // Initialization function
K_NONE, Minitbreakmenu, 0, 0 },
{ N(L"Delete"), N(L"Delete INT3 breakpoint"),
K_DELETEBP, Mdeletebreak, 0, 0 },
{ N(L"Disable"), N(L"Disable breakpoint but don't remove it "
"from the list"),
K_ENABLEBP, Menablebreak, 0, 0 },
{ N(L"Enable"), N(L"Re-enable INT3 breakpoint"),
K_ENABLEBP, Menablebreak, 0, 1 },
{ N(L"Edit properties..."), N(L"Edit properties associated with breakpoint"),
K_CONDBREAK, Meditbreak, 0, K_CONDBREAK },
{ N(L"Edit properties..."), N(L"Edit properties associated with breakpoint"),
K_LOGBREAK, Meditbreak, 0, K_LOGBREAK },
{ N(L"Follow in Disassembler"), N(L"Follow breakpoint in CPU Disassembler"),
K_BPINDASM, Mfollowbreak, 0, 0 },
{ N(L"|Disable all"), N(L"Disable all INT3 breakpoints"),
K_DISABLEALLBP, Menableallbreaks, 0, 0 },
{ N(L"Enable all"), N(L"Re-enable all INT3 breakpoints"),
K_ENABLEALLBP, Menableallbreaks, 0, 1 },
{ L"|*BPOINT", L"", // Plugin menus
0, NULL, NULL, 0 },
{ L"|", L"", // Forwarder to standard menus
K_NONE, NULL, standardmenus, 0
}
};
static t_bpoint *menubrk; // Pointer to selected item
// Initialization function of breakpoints menu.
static int Minitbreakmenu(t_table *pt,wchar *name,ulong index,int mode) {
menubrk=(t_bpoint *)Getsortedbyselection(&(pt->sorted),pt->sorted.selected);
return MENU_NORMAL;
};
// Menu function that executes menu command "Delete".
static int Mdeletebreak(t_table *pt,wchar *name,ulong index,int mode) {
int selected;
if (menubrk==NULL || (menubrk->type & BP_MANUAL)==0)
return MENU_ABSENT;
if (mode==MENU_VERIFY)
return MENU_NORMAL;
else if (mode==MENU_EXECUTE) {
selected=pt->sorted.selected;
Removeint3breakpoint(menubrk->addr,BP_MANUAL);
if (selected>=pt->sorted.n)
selected--;
Settableselection(pt,selected);
return MENU_REDRAW; };
return MENU_ABSENT;
};
// Menu function that executes menu commands "Disable" (index=0) and "Enable"
// (index=1).
static int Menablebreak(t_table *pt,wchar *name,ulong index,int mode) {
if (menubrk==NULL || (menubrk->type & BP_MANUAL)==0)
return MENU_ABSENT;
if (mode==MENU_VERIFY) {
if (((menubrk->type & BP_DISABLED)==0 && index!=0) ||
((menubrk->type & BP_DISABLED)!=0 && index==0)) return MENU_ABSENT;
return MENU_NORMAL; }
else if (mode==MENU_EXECUTE) {
Enableint3breakpoint(menubrk->addr,index);
// If menu function is called from shortcut, move selection down.
if (Menufromshortcut() && pt->sorted.selected<pt->sorted.n-1)
Settableselection(pt,pt->sorted.selected+1);
return MENU_REDRAW; };
return MENU_ABSENT;
};
// Menu function that executes menu command "Edit properties" (where index
// is either K_CONDBREAK or K_LOGBREAK, allowing both shortcuts to work).
static int Meditbreak(t_table *pt,wchar *name,ulong index,int mode) {
POINT coord;
if (menubrk==NULL || (menubrk->type & BP_MANUAL)==0)
return MENU_ABSENT;
if (mode==MENU_VERIFY) {
if (index==K_CONDBREAK) return MENU_SHORTCUT;
return MENU_NORMAL; }
else if (mode==MENU_EXECUTE) {
if (Gettableselectionxy(pt,2,&coord)<0)
coord.x=coord.y=-1; // Unknown coordinates, use defaults
if (index==K_CONDBREAK) Condbreakpoint(pt->hw,&(menubrk->addr),1,NULL,
coord.x,coord.y,pt->font);
else Condlogbreakpoint(pt->hw,&(menubrk->addr),1,0,NULL,
coord.x,coord.y,pt->font);
return MENU_REDRAW; };
return MENU_ABSENT;
};
// Menu function that executes menu command "Follow break in Disassembler".
static int Mfollowbreak(t_table *pt,wchar *name,ulong index,int mode) {
if (menubrk==NULL)
return MENU_ABSENT;
if (mode==MENU_VERIFY)
return MENU_NORMAL;
else if (mode==MENU_EXECUTE) {
Setcpu(0,menubrk->addr,0,0,0,CPU_ASMHIST|CPU_ASMCENTER|CPU_ASMFOCUS);
return MENU_NOREDRAW; };
return MENU_ABSENT;
};
// Menu function that executes menu commands "Disable all" (index=0) and
// "Enable all" (index=1).
static int Menableallbreaks(t_table *pt,wchar *name,ulong index,int mode) {
int i,nenabled,ndisabled;
t_bpoint *pbrk;
nenabled=ndisabled=0;
for (i=0; i<pt->sorted.n; i++) {
pbrk=(t_bpoint *)Getsortedbyindex(&(pt->sorted),i);
if ((pbrk->type & BP_MANUAL)==0)
continue;
if (pbrk->type & BP_DISABLED)
ndisabled++;
else
nenabled++;
;
};
if (mode==MENU_VERIFY) {
if (index==0 && nenabled==0) return MENU_ABSENT;
if (index!=0 && ndisabled==0) return MENU_ABSENT;
return MENU_NORMAL; }
else if (mode==MENU_EXECUTE) {
for (i=0; i<pt->sorted.n; i++) {
pbrk=(t_bpoint *)Getsortedbyindex(&(pt->sorted),i);
if ((pbrk->type & BP_MANUAL)==0)
continue;
if (index==0 && (pbrk->type & BP_DISABLED)!=0)
continue;
if (index!=0 && (pbrk->type & BP_DISABLED)==0)
continue;
Enableint3breakpoint(pbrk->addr,index); };
return MENU_REDRAW; };
return MENU_ABSENT;
};
static t_menu bpointmenu[] = {
{ L"!", NULL, // Initialization function
K_NONE, Minitbreakmenu, 0, 0 },
{ N(L"Delete"), N(L"Delete INT3 breakpoint"),
K_DELETEBP, Mdeletebreak, 0, 0 },
{ N(L"Disable"), N(L"Disable breakpoint but don't remove it "
"from the list"),
K_ENABLEBP, Menablebreak, 0, 0 },
{ N(L"Enable"), N(L"Re-enable INT3 breakpoint"),
K_ENABLEBP, Menablebreak, 0, 1 },
{ N(L"Edit properties..."), N(L"Edit properties associated with breakpoint"),
K_CONDBREAK, Meditbreak, 0, K_CONDBREAK },
{ N(L"Edit properties..."), N(L"Edit properties associated with breakpoint"),
K_LOGBREAK, Meditbreak, 0, K_LOGBREAK },
{ N(L"Follow in Disassembler"), N(L"Follow breakpoint in CPU Disassembler"),
K_BPINDASM, Mfollowbreak, 0, 0 },
{ N(L"|Disable all"), N(L"Disable all INT3 breakpoints"),
K_DISABLEALLBP, Menableallbreaks, 0, 0 },
{ N(L"Enable all"), N(L"Re-enable all INT3 breakpoints"),
K_ENABLEALLBP, Menableallbreaks, 0, 1 },
{ L"|*BPOINT", L"", // Plugin menus
0, NULL, NULL, 0 },
{ L"|", L"", // Forwarder to standard menus
K_NONE, NULL, standardmenus, 0
}
};
See also: