Adding A Plugin Menu
We will first be adding a popup menu to notepad's main menu; this new popup menu will
hold the various options for each plugin and will be created at
run time via an imported DLL function. Note that plugins will be able to add and modify options in other popup menus as well.
Tools Used
[~] Resource Hacker - For viewing
and modifying menu items and properties.
[~] Win32.hlp
- Reference for Win32
API functions.
[~] OllyDbg
- Debugger.
[~] Dev-C++
- For compiling DLL and
EXE files.
[~] WinDowse - For viewing window
information (optional).
Statically Changing The Main Menu
ResHack is a utility which allows you to view and modify a program's
resources, including menu information. Open up notepad in ResHack and click
on 'Menu -> 1 -> 1033':
Notice that it displays each popup menu, its menu items and their ID
numbers. It is important to note the ID numbers because our plugin menu
items shouldn't have the same ID numbers as the pre-existing options.
We can permanently add a plugin menu by adding something like:
POPUP "&Plugins"
{
MENUITEM "&Test", 2001
}
However, this doesn't allow us to dynamically add new plugin options to
notepad.
Dynamically Changing The Menu
The windows API provides several functions to add and manipulate a
menu's contents such as CreatePopupMenu, AppendMenu, InsertMenu and
SetMenu. In order to use these functions, we need to get a handle to
the menu we want to manipulate; the following C code creates a program
which will add our menu to an instance of notepad which is already
running:
***************Begin Code******************
#include <windows.h>
int main()
{
//retrieve the window handle based on notepad's title text
HWND handle=FindWindow(0,"Untitled - Notepad");
//retrieve the menu handle using the window handle
HMENU menu=GetMenu(handle);
//create a new popup menu
HMENU submenu=CreatePopupMenu();
//add the popup menu to notepad's menu bar
InsertMenu(menu,4,MF_BYPOSITION | MF_POPUP,(UINT)submenu,"&Plugins");
//add submenus to the popup menu
AppendMenu(submenu, MF_STRING, 1, "&Test");
AppendMenu(submenu, MF_STRING, 2, "Test &2");
//apply the changes
SetMenu(handle,menu);
return 0;
}
***************End Code******************
We use FindWindow to obtain a handle to notepad's window, GetMenu to obtain a handle to the window's menu. We then create a popup menu, insert it between 'View' and 'Help' (note that we used a position of 4 for InsertMenu to place it between
the View and Help popup menus), append two options to the popup menu, and then save our changes via SetMenu. Running this program with an instance of notepad already open results
in the addition of a 'Plugins' pop-up menu being added to notepad's
menu bar:
However, this method is still
unsatisfactory because if the window text is different, or if there are
multiple instances of notepad running simultaneously, FindWindow may
not retrieve the proper window handle. What we need to do is place this
code in an exportable DLL function, then make notepad call that
function, passing the window handle to the function.
Finding the Window Handle
First, we need to find where notepad's main window handle is stored so we can pass it to our DLL function. Open notepad in Olly, 'Right Click -> Search for -> All
intermodular calls', and set a break point on all calls to
CreateWindowExW (there are only three) and run notepad. Olly will break
twice; the first time is when the main window is created (this is the
one we are looking for), and the second time is when the edit window is
created. There are several ways to determine which call is creating
which window:
1) Notepad is a simple program, so most likely the first window to be
created will be the main window.
2) Looking at the class names passed to CreateWindowExW, the first one
is "Notepad" and the second is "Edit".
3) Other API calls in notepad (such as GetMenu) which require the main
window handle are passed the handle which is returned by the first call
to CreateWindowExW.
4) By using a program such as WinDowse, you can see that there are two
windows created: the primary window ("Notepad") and a child window
("Edit").
Looking three instructions below the first call to
CreateWindowExW, we see that the handle is stored in two different
memory locations (01009830 and 0100A4A4):
Looking elsewhere at Olly's code, the GetMenu API calls are passed the
value at
address 01009830, so we will pass the handle stored at that address to
our function.
The DLL Function
The following code will create an exportable DLL function, NotePlug,
which
produces our desired results. If you are unfamiliar with DLLs or exportable functions, see my DLL tutorial page. Note that this code is created for Dev-C++, so you may need to change the names of dll.h and DLLIMPORT to suite your compiler:
#include "dll.h"
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
DLLIMPORT int NotePlug(HWND handle)
{
HMENU menu=GetMenu(handle);
HMENU submenu=CreatePopupMenu();
InsertMenu(menu,4,MF_BYPOSITION | MF_POPUP,(UINT)submenu,"&Plugins");
AppendMenu(submenu, MF_STRING, 2001, "&Test");
AppendMenu(submenu, MF_STRING, 2002, "Test &2");
SetMenu(handle,menu);
return 0;
}
DLLIMPORT int NotePadCmd(HWND hwnd,int msg,int unknown)
{
return 0;
}
Compile this code as note_plug.dll; this will be our primary DLL
file which will implement all the necessary features to support plugin
modules. The NotePlug function will be later modified so that the
addition of
submenus via AppendMenu is conducted by each individual plugin, however
this serves its purpose for the time being. The purpose of the NotePadCmd function will be evident in the next tutorial section.
Conclusion
We can now add menu options to notepad's menu bar, allowing the user to
interact with any additional functionality via plugin modules.
Next we need to modify notepad's assembly code to call our NotePlug function from notepad each time it is
run.
Copyright ©2006 craigheffner.com