Hook是Windows操作系统的消息传递机制的重要组成部分。通过使用Hook,程序可以监视系统中其他进程的消息传递,并在该消息到达目的前对其进行处理。
注意,由于Hook可能访问其他进程的地址空间,故必要时应通过DLL实现。并且,全局Hook会降低系统的性能,应该尽量避免使用。
Windows为不同类型的消息提供了不同类型的Hook,并分别维护一个Hook链表。新创建的Hook将被放到链首,首先获得消息,并对其进行处理。但要注意,Hook不会自动将接收到的消息传递给链表上的下一Hook,需要在代码中显式声明。
下面看看Hook的一般使用顺序:
1、使用SetWindowsHookEx在特定Hook链首添加一个新Hook。
2、相应消息传递到SetWindowsHookEx说明的函数,并由其进行处理。该函数的原型必须为:
LRESULT CALLBACK HookProc{
int nCode,
WPARAM wParam,
LPARAM lParam
};
3、在HookProc处理消息后,可以选择使用CallNextHookEx将该消息传递给链表中的下一个节点进行处理。
4、在完成Hook的使用后,用函数UnhookWindowsHookEx将其撤销。
现在来看看Windows支持的几种常用的Hook类型。
WH_CALLWNDPROC:捕获传递给窗口的消息。
WH_CBT:窗口创建、销毁、激活、最大最小化、移动、缩放,系统调用,鼠标、键盘事件等,几乎包括了所有的基本操作。
WH_GETMESSAGE:捕获使用GetMessage或PeekMessage传递的消息。
WH_KEYBOARD:捕获GetMessage或PeekMessage传递的WM_KEYDOWN或WM_KEYUP消息。
WH_MOUSE:捕获GetMessage或PeekMessage传递的鼠标相关消息。
WH_MSGFILTER和WH_SYSMSGFILTER:捕获应该由Windows标准控件处理的局部和全局消息。
Hook的基本情况就介绍到这里。最后,我再给出一段Hook的代码,用于监控键盘消息(代码用C++编写,在Windows XP SP2下调试通过)。
// DLL
#include <windows.h>
#include <strsafe.h>
#ifdef __cplusplus
#define EXPORT extern "C" __declspec (dllexport)
#else
#define EXPORT __declspec (dllexport)
#endif
HHOOK hHook;
HINSTANCE hInst;
EXPORT LRESULT __stdcall KeyboardProc(int nCode, WPARAM wParam, LPARAM lParam);
EXPORT void __stdcall InitHook();
int WINAPI DllMain(HINSTANCE hInstance, DWORD fdwReason, PVOID pvReserved)
{
MessageBox(NULL, "DLL init succeeded!", "Message", MB_ICONINFORMATION || MB_OK);
hInst=hInstance;
return TRUE ;
}
EXPORT void __stdcall FreeHook()
{
if (!UnhookWindowsHookEx(hHook))
MessageBox(NULL, "UnhookWindowsHookEx() failed!", "Error", 0x10);
}
EXPORT void __stdcall InitHook()
{
hHook = SetWindowsHookEx(WH_KEYBOARD, KeyboardProc, hInst, NULL);
if (hHook == NULL)
MessageBox(NULL, "SetWindowsHookEx() failed!", "Error", 0x10);
}
EXPORT LRESULT __stdcall KeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)
{
if (nCode < 0)
return CallNextHookEx(hHook, nCode, wParam, lParam);
if (nCode == HC_NOREMOVE)
MessageBox(NULL, "Message hasn't been removed!", "Message", MB_ICONINFORMATION || MB_OK);
char buf[128];
memset(buf, 0, 128);
StringCchPrintf(buf, 128/sizeof(TCHAR), "KEYBOARD - nCode: %d, vk: %d", nCode, wParam);
MessageBox(NULL, buf, "Message", MB_ICONINFORMATION || MB_OK);
return CallNextHookEx(hHook, nCode, wParam, lParam);
}
这样,只需要再编写一段程序,调用这个DLL库里的初始化函数,并在调用结束后释放Hook就可以了。