【C++】代码实现:全局钩子注入技术

一、概述

在 Windows  中大部分的应用程序都是基于消息机制的,它们都有一个过程函数,根据不同的消息完成不同的功能。

Windows 操作系统提供的钩子机制就是用来截获和监视系统中这些消息的。

按照钩子作用的范围不同,它们又可以分为局部钩子和全局钩子。局部钩子是针对某个线程的,而全局钩子则是作用于整个系统的基于消息的应用。

全局钩子需要使用 DLL 文件,在 DLL 中实现相应的钩子函数。

二、实现原理

如果创建的是全局钩子,那么钩子函数必须在一个 DLL 中。这是因为进程的地址空间是独立的,发生对应事件的进程不能调用其他进程地址空间的钩子函数。

如果钩子函数是实现代码在 DLL 中,则在对应事件发生时,系统会把这个 DLL 加载到发生事件的进程地址空间中,使它能够调用钩子函数进行处理。

为了能够让 DLL 注入到所有的进程中,程序设置 WH_GETMESSAGE 消息的全局钩子。因为 WH_GETMESSAGE 类型的钩子会监视消息队列,并且 Windows 系统是基于消息驱动的,所以所有进程都会有自己的一个消息队列,都会加载 WH_GETMESSAGE 类型的全局钩子 DLL。

三、主要代码

  • 设置全局钩子:
// 设置全局钩子
BOOL SetGlobalHook()
{
	g_hHook = ::SetWindowsHookEx(WH_GETMESSAGE, (HOOKPROC)GetMsgProc, g_hDllModule, 0);
	if (NULL == g_hHook)
	{
		return FALSE;
	}
	return TRUE;
}
  • 钩子回调函数:
// 钩子回调函数
LRESULT GetMsgProc(
	int code,
	WPARAM wParam,
	LPARAM lParam)
{
	return ::CallNextHookEx(g_hHook, code, wParam, lParam);
}
  • 卸载钩子:
// 卸载钩子
BOOL UnsetGlobalHook()
{
	if (g_hHook)
	{
		::UnhookWindowsHookEx(g_hHook);
	}
	return TRUE;
}

上面介绍了全局钩子的设置、钩子回调函数的实现以及全局钩子的卸载,这些操作都需要用到全局钩子的句柄作为参数。而全局钩子是以 DLL 形式加载到其他进程空间中的,而且进程都是独立的,所以任意修改其中一个内存里的数据是不会影响另一个进程的。

那么,如何将钩子句柄传递给其他进程呢?方法是在 DLL 中创建共享内存。

共享内存是指突破进程独立性,多个进程共享同一段内存。在 DLL 中创建共享内存,就是在 DLL 中创建一个变量,然后将 DLL 加载到多个进程空间,只要一个进程修改了该变量值,其他进程 DLL 中的这个值也会改变,就相当于多个进程共享一个内存。

共享内存的实现有的是比较简单,首先为 DLL 创建一个数据段,然后再对程序的链接器进行设置,把指定的数据段链接为共享数据段。这样,就可以成功地创建共享内存了。

  • 创建共享内存:
// 共享内存
#pragma data_seg("mydata")
    HHOOK g_hHook = NULL;
#pragma data_seg()
#pragma comment(linker, "/SECTION:mydata,RWS")

四、示例代码

  • DLL 代码:
// GlobalHook_Test.cpp : 定义 DLL 应用程序的导出函数。
//

#include "stdafx.h"

extern HMODULE g_hDllModule;
// 共享内存
#pragma data_seg("mydata")
    HHOOK g_hHook = NULL;
#pragma data_seg()
#pragma comment(linker, "/SECTION:mydata,RWS")

// 钩子回调函数
LRESULT GetMsgProc(
	int code,
	WPARAM wParam,
	LPARAM lParam)
{
	return ::CallNextHookEx(g_hHook, code, wParam, lParam);
}

// 设置全局钩子
BOOL SetGlobalHook()
{
	g_hHook = ::SetWindowsHookEx(WH_GETMESSAGE, (HOOKPROC)GetMsgProc, g_hDllModule, 0);
	if (NULL == g_hHook)
	{
		return FALSE;
	}
	return TRUE;
}

// 卸载钩子
BOOL UnsetGlobalHook()
{
	if (g_hHook)
	{
		::UnhookWindowsHookEx(g_hHook);
	}
	return TRUE;
}
  • 调用代码:
#include "stdafx.h"
#include 

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;
}

 

你可能感兴趣的:(C++,实战应用技巧)