Environment: VC6 , Windows 2000/NT/ME/9x
This article describes how to install a Keyboard hook in Microsoft Windows.
There are two types of Hooks – Thread specific hooks and Systemwide hooks. A thread specific hook is associated with particular thread only (Any thread owned by the calling process.). If you want to associate the hook with other processes and threads, you will have to use a systemwide hook. There is a hook procedure associated with a hook. This procedure is always called when the particular event occurs. For eg. the mouse. When there is an event associated with the mouse, this hook procedure is called. The hook is set by calling the function SetWindowsHookEx( ). The hook is removed by calling UnhookWindowsHookEx( ).
For thread hooks, the hook procedure may be in an EXE file or a DLL. But for Global or System hooks, the hook procedure must reside in a DLL. For this, we need to create a DLL.
To do this, create a Win32 DLL project with only the starter files in it and modify it to suit your needs. It is better to put the code for installing and removing the hook in the DLL itself.
Now, define the functions in the DLL’s header file as follows.
#ifdef KEYDLL3_EXPORTS #define KEYDLL3_API __declspec(dllexport) #else #define KEYDLL3_API __declspec(dllimport) #endif //This function installs the Keyboard hook: KEYDLL3_API void installhook(HWND h); //This function removes the previously installed hook. KEYDLL3_API void removehook(); //hook procedure: KEYDLL3_API LRESULT CALLBACK hookproc( int ncode, WPARAM wparam, LPARAM lparam);
For exporting the functions in the DLL, it is a good idea to use the __declspec and dllexport keywords rather than using a separate .DEF file. The SetWindowsHookEx( ) function returns a handle to a hook – which is stored for later uninstall of the hook from the hook chain. We also have a window handle, which we will use to send messages to the main Application Window. We first find the application window by using the FindWindow( ) function, and then send the keystroke message parameters to the Application’s main window using the PostMessage( ) call. This is as in the code fragment below:
//Find application window handle hwnd = FindWindow("#32770","Keylogger Exe"); //Send info to app Window. PostMessage(hwnd,WM_USER+755,wparam,lparam);
At the end of the hook procedure, we must call the CallNextHookEx( ) function to pass on the parameters to the next hook installed in the hook chain. This is highly recommended because not doing so can cause unpredictable system behaviour and lockouts. The procedures for installing, removing the hooks, and the hook procedure are as shown below:
KEYDLL3_API void installhook(HWND h) { hook = NULL; hwnd = h; hook = SetWindowsHookEx( WH_KEYBOARD, hookproc, hinstance, NULL); if(hook==NULL) MessageBox( NULL, "Unable to install hook", "Error!", MB_OK); } KEYDLL3_API void removehook() { UnhookWindowsHookEx(hook); } KEYDLL3_API LRESULT CALLBACK hookproc( int ncode, WPARAM wparam, LPARAM lparam) { if(ncode>=0) { //Find application window handle hwnd = FindWindow("#32770","Keylogger Exe"); //Send info to app Window. PostMessage(hwnd,WM_USER+755,wparam,lparam); } //pass control to next hook. return ( CallNextHookEx(hook,ncode,wparam,lparam) ); }
If there are multiple instances of the DLL in memory, they all have different values for each data member of the different DLL instances. But, certain data, such as the hook handle, the window handle should be the same for all instances. This is because all instances send info to the same Application window. For this, we need to define the data as shared in the DLL’s .CPP file. This is done as follows:
#pragma data_seg(".HOOKDATA")//Shared data among all instances.
HHOOK hook = NULL;
HWND hwnd = NULL;
#pragma data_seg()
Now, the linker must be given instructions so as to place the shared data in separate space in the DLL. To do this, we use the following code, soon after the abovementioned code.
//linker directive
#pragma comment(linker, "/SECTION:.HOOKDATA,RWS")
So much for the DLL. Now, we will take a look at the Main application(EXE). Create an MFC application (windowed or dialog based). I created a Dialog based EXE for simplicity. After creating the project, Go to Project settings dialog box by selecting Project>Settings from the Main Menubar. Select the ‘Link’ tab and type ‘Keydll3.lib’ in the ‘Object/library modules’ box. Click OK. Now, Insert the DLL’s header file into the workspace by selecting Project>Add to project> files from the main menubar. Select the .h file of the DLL that we built earlier. ‘#include’ it in your project as follows:
//Include this for functions in the DLL:
#include "..\Keydll3\Keydll3.h"
This should be in the .CPP file for the Main dialog class. Now, in the main dialog class, add a public member function to process the keystroke messages sent by the DLL. This function is as shown below:
afx_msg LRESULT processkey(WPARAM w,LPARAM l);//declaration LRESULT CKeyexeDlg::processkey(WPARAM w, LPARAM l)//definition { //This block processes the keystroke info. . . . return 0L; }
(This member can be easily added using the wizardbar). Now, define the Message we shall receive from the DLL in the .CPP file as follows:
//This message is recieved when key is down/up
#define WM_KEYSTROKE (WM_USER + 755)
Now add the newly created member function as the message handler for the WM_KEYSTROKE message, using the ON_MESSAGE( ) macro in the Message maps section(in the CPP file) as below: \
BEGIN_MESSAGE_MAP(CKeyexeDlg, CDialog) //{{AFX_MSG_MAP(CKeyexeDlg) . . . ON_MESSAGE(WM_KEYSTROKE, processkey) //}}AFX_MSG_MAP END_MESSAGE_MAP()
We are almost finished. But, before compiling and building the EXE, add the path to the .LIB file (Keydll3.lib) to the Visual studio Library paths. To do this, select Tools>Options from the main menubar and select the ‘Directories’ tab. Select ‘Library files’ from the 2nd dropdown list, and add the path to the DLL’s .LIB file in the box below. Click OK, Save all files and workspace, and then build your project.
For more information on Hooks, see the following sections in the MSDN library:
- SetWindowsHookEx( ),
- Hook functions,
- Virtual-key codes,
- Keystroke message flags.
The example I have used here is provided for download (See below).
Note: For Windows NT/2000, your windows password might be logged by the hook procedure if you have not enabled the ‘Ctrl-Alt-Del’ logon sequence(Only while unlocking the PC).