[C++] Code Implementation: Global Hook Injection Technology

Keywords: Windows Linker

I. Overview

Most applications in Windows are based on message mechanism. They all have a process function to perform different functions according to different messages.

The hook mechanism provided by Windows operating system is used to intercept and monitor these messages in the system.

According to the range of hooks, they can be divided into local hooks and global hooks. Local hooks are for a thread, while global hooks are message-based applications for the whole system.

Global hooks need to use DLL files to implement corresponding hook functions in DLL.

II. Realization Principle

If a global hook is created, then the hook function must be in a DLL. This is because the address space of the process is independent, and the corresponding process can not call the hook function of other process address space.

If the hook function is to implement the code in the DLL, then when the corresponding event occurs, the system will load the DLL into the process address space of the event, so that it can call the hook function for processing.

In order to allow DLL to be injected into all processes, the program sets the global hook for WH_GETMESSAGE messages. Because WH_GETMESSAGE-type hooks monitor message queues and Windows systems are message-driven, all processes have their own message queues, which load WH_GETMESSAGE-type global hook DLLs.

III. Major Codes

  • Set the global hook:
// Setting global hooks
BOOL SetGlobalHook()
{
	g_hHook = ::SetWindowsHookEx(WH_GETMESSAGE, (HOOKPROC)GetMsgProc, g_hDllModule, 0);
	if (NULL == g_hHook)
	{
		return FALSE;
	}
	return TRUE;
}
  • Hook callback function:
// Hook callback function
LRESULT GetMsgProc(
	int code,
	WPARAM wParam,
	LPARAM lParam)
{
	return ::CallNextHookEx(g_hHook, code, wParam, lParam);
}
  • Unloading hook:
// Unloading hook
BOOL UnsetGlobalHook()
{
	if (g_hHook)
	{
		::UnhookWindowsHookEx(g_hHook);
	}
	return TRUE;
}

The setting of the global hook, the implementation of the callback function of the hook and the unloading of the global hook are introduced. All these operations need the handle of the global hook as a parameter. Global hooks are loaded into other process spaces in the form of DLL, and processes are independent, so any modification of data in one memory will not affect the other process.

So how do you pass hook handles to other processes? The method is to create shared memory in the DLL.

Shared memory refers to breaking through process independence and sharing the same segment of memory by multiple processes. To create shared memory in DLL is to create a variable in DLL and then load the DLL into multiple process spaces. As long as one process modifies the value of the variable, the value in other process DLL will change, which is equivalent to multiple processes sharing one memory.

The implementation of shared memory is relatively simple. First, create a data segment for DLL, and then set the linker of the program to link the specified data segment to the shared data segment. In this way, shared memory can be successfully created.

  • Create shared memory:
// Shared memory
#pragma data_seg("mydata")
    HHOOK g_hHook = NULL;
#pragma data_seg()
#pragma comment(linker, "/SECTION:mydata,RWS")

IV. Sample Code

  • DLL code:
// GlobalHook_Test.cpp: Defines the export function of the DLL application.
//

#include "stdafx.h"

extern HMODULE g_hDllModule;
// Shared memory
#pragma data_seg("mydata")
    HHOOK g_hHook = NULL;
#pragma data_seg()
#pragma comment(linker, "/SECTION:mydata,RWS")

// Hook callback function
LRESULT GetMsgProc(
	int code,
	WPARAM wParam,
	LPARAM lParam)
{
	return ::CallNextHookEx(g_hHook, code, wParam, lParam);
}

// Setting global hooks
BOOL SetGlobalHook()
{
	g_hHook = ::SetWindowsHookEx(WH_GETMESSAGE, (HOOKPROC)GetMsgProc, g_hDllModule, 0);
	if (NULL == g_hHook)
	{
		return FALSE;
	}
	return TRUE;
}

// Unloading hook
BOOL UnsetGlobalHook()
{
	if (g_hHook)
	{
		::UnhookWindowsHookEx(g_hHook);
	}
	return TRUE;
}
  • Call code:
#include "stdafx.h"
#include <Windows.h>

int _tmain(int argc, _TCHAR* argv[])
{
	typedef BOOL(*typedef_SetGlobalHook)();
	typedef BOOL(*typedef_UnsetGlobalHook)();
	HMODULE hDll = NULL;
	typedef_SetGlobalHook SetGlobalHook = NULL;
	typedef_UnsetGlobalHook UnsetGlobalHook = NULL;
	BOOL bRet = FALSE;

	do
	{
		hDll = ::LoadLibrary("GlobalHook_Test.dll");
		if (NULL == hDll)
		{
			printf("LoadLibrary Error[%d]\n", ::GetLastError());
			break;
		}

		SetGlobalHook = (typedef_SetGlobalHook)::GetProcAddress(hDll, "SetGlobalHook");
		if (NULL == SetGlobalHook)
		{
			printf("GetProcAddress Error[%d]\n", ::GetLastError());
			break;
		}

		bRet = SetGlobalHook();
		if (bRet)
		{
			printf("SetGlobalHook OK.\n");
		}
		else
		{
			printf("SetGlobalHook ERROR.\n");
		}

		system("pause");

		UnsetGlobalHook = (typedef_UnsetGlobalHook)::GetProcAddress(hDll, "UnsetGlobalHook");
		if (NULL == UnsetGlobalHook)
		{
			printf("GetProcAddress Error[%d]\n", ::GetLastError());
			break;
		}
		UnsetGlobalHook();
		printf("UnsetGlobalHook OK.\n");

	}while(FALSE);

	system("pause");
	return 0;
}

 

Posted by ehutchison on Fri, 26 Jul 2019 06:05:56 -0700