作者: linzhenqun(风)
时间: 2005-10-6
Blog: http://blog.csdn.net/linzhengqun
-----------------------------------------------------------------------------------------------------
前言
这不是关于钩子的长篇大论,而更关注于其实际应用。
不过实践总要有理论作为基础。因此本文第一部分给出了关于钩子的基本理论。大部分都直接翻译于MSDN,大家如果有兴趣可以找MDSN中的Win32 Hooks这篇文章来看,非常详尽的说明了钩子的应用,再看看对于那些API的声明,基本就OK了。
第二部分给出一个实际的程序,关于宏的实现,从这部分可以学到钩子的具体应用。第三部分会给出一个简单的SPY程序,理解全局钩子的应用。
(一)基本理论
钩子是Windows中是一项非常有用的技术。钩子是这样的一种机制:它允许一个函数在事件(消息,鼠标动作,键盘)到达应用程序之前截获它们。该函数可以作用于事件,某些情况下,可以修改和丢弃它们。接收事件的函数称为过滤函数,它将依照所截获事件的类型来分类。例如,一个过滤函数可能想要接收所有的键盘和鼠标事件。Windows要调用一个过滤函数,该函数必须被安装到一个Windows 钩子(比如,一个键盘钩子)上面。如果一个钩子附带有多个过滤函数,Windows维护一个过滤函数的链,最近安装的函数在链的前面,最先安装的则在链的后面。
钩子有很多种,这里不能一一列出,其他可以看MSDN:
- WH_CALLWNDPROC
- WH_CALLWNDPROCRET
- WH_GETMESSAGE
- WH_JOURNALPLAYBACK
- WH_JOURNALRECORD
- WH_KEYBOARD
- WH_MOUSE
这些钩子分别对应于系统中不同的事件,我们的程序可以使用钩子做很多的事情,比如:
l 处理和修改系统中的所有消息,无论GetMessage或PeekMessage何时被调用(WH_GETMESSAGE)。
l 处理和修改所有消息,无论SendMessage何时被调用(WH_CALLWNDPROC)。
l 记录和回放键盘和鼠标事件(WH_JOURNALRECORD, WH_JOURNALPLAYBACK)。
l 处理,修改或移除键盘事件(WH_KEYBOARD)。
l 处理,修改或丢弃鼠标事件(WH_MOUSE)。
等等。
对于我们的程序,要使用钩子,将用到下面几个重要的API函数:
SetWindowsHook, UnhookWindowsHook和CallNextHookEx,Windows使用这几个函数管理钩子的过滤函数链。下面我们将详细介绍:
SetWindowsHookEx
SetWindowsHookEx增加一个过滤函数到一个钩子中。该函数带有四个参数:
l 一个整型编码描述了那种过滤函数被附带上。这些码定义在WINUSER.H中。。
l 过滤函数的地址。在应用程序或DLL的模块定义文件中。
l 包含过滤函数的模块的实例句柄。
l 钩子被安装到某个线程的线程ID,如果线程ID不为零,安装了的过滤函数将只在特定线程的上下文中被调用。如果线程ID为空,则线程将在系统范围内或任何的线程上下文中被调用。一个库或应用程序可以使用GetCurrentThreadId获得当前线程ID。
SetWindowsHookEx返回安装的钩子的句柄(HHook), 程序在随后调用UnhookWindowsHookEx时要使用该句柄。
SetWindowsHookEx也返回一个值标识为什么调用失败,可以查看MSDN。
UnhookWindowsHookEx
要从一个钩子链中移除一个过滤函数,调用UnhookWindowsHookEx。该函数需要从SetWindowsHookEx中返回的句柄作为参数,并返回一个值以确定钩子是否删除。
过滤函数
钩子过滤函数是被附带到钩子的函数。过滤函数是由系统而不是由程序调用。
所有过滤函数必须有如下的形式:
LRESULT CALLBACK FilterFunc( nCode, wParam, lParam )
int nCode;
WORD wParam;
DWORD lParam;
所有过滤函数都返回一个LONG值。FilterFunc只是实际的过滤函数名的一个符号。
参数
过滤函数接收三个参数:nCode, wParamt和lParam。nCode是一个整值,它通知过滤函数任何应该知道附加数据。
当Windows传递一个负值的nCode给过滤函数时,应该调用CallNextHookEx并传递三个过滤函数的参数。过滤函数也必须返回CallNextHookEx返回的值。
第二个传递给过滤函数的参数,一个WPARAM类型,而第三个参数是LPARAM类型。这些参数传递过滤函数需要的信息。wParam和lParam对不同的钩子意义不同。
钩子 | 过滤函数 |
WH_CALLWNDPROC | CallWndProc |
WH_GETMESSAGE | GetMsgProc |
WH_JOURNALRECORD | JournalRecordProc |
WH_JOURNALPLAYBACK | JournalPlaybackProc |
WH_KEYBOARD | KeyboardProc |
WH_MOUSE | MouseProc |
WH_CALLWNDPROCRET | CallWndRetProc |
其本质的差别就在于函数带的参数表示的意义。可以根据函数名查阅MSDN,以获得更详尽的描述。