很多人对windows钩子比较熟悉,也可以轻易的写出一个全局钩子程序。但是一个32位钩子是否可以捕获64位进程的消息呢?又或者64位钩子能否捕获32位进程的消息呢?下面我们分析一下。
MSDN在对SetWindowsHookEx函数有如下说明:
SetWindowsHookEx can be used to inject a DLL into another process. A 32-bit DLL cannot be injected into a 64-bit process, and a 64-bit DLL cannot be injected into a 32-bit process. If an application requires the use of hooks in other processes, it is required that a 32-bit application call SetWindowsHookEx to inject a 32-bit DLL into 32-bit processes, and a 64-bit application call SetWindowsHookEx to inject a 64-bit DLL into 64-bit processes. The 32-bit and 64-bit DLLs must have different names.
Because hooks run in the context of an application, they must match the "bitness" of the application. If a 32-bit application installs a global hook on 64-bit Windows, the 32-bit hook is injected into each 32-bit process (the usual security boundaries apply). In a 64-bit process, the threads are still marked as "hooked." However, because a 32-bit application must run the hook code, the system executes the hook in the hooking app's context; specifically, on the thread that called SetWindowsHookEx. This means that the hooking application must continue to pump messages or it might block the normal functioning of the 64-bit processes.
首先解释的一点是如果安装hook的进程没有调用UnhookWindowsHookEx而提前结束掉,windows消息hook还有效吗?答案是无效的,之后启动的进程不会被注入hook dll,已注入hook dll的进程会注销钩子、卸载hook dll。
32位dll是不能注入到64位进程中,同理64位dll不能注入到32位进程中。如果32位进程调用SetWindowsHookEx 注入32位dll,其只能注入到32位进程中,虽然不能注入到64位进程,但是64位进程的线程依然被标注为hooked。当64位进程产生需要被hook处理的事件时,系统会在调用SetWindowsHookEx函数的进程(严格的说是线程)中执行hook例程。这要求调用SetWindowsHookEx的线程拥有一个消息泵,否则会阻止64位进程的执行。
据我的推测,要求调用SetWindowsHookEx的线程拥有一个消息泵,是因为64位进程通过windows消息向调用SetWindowsHookEx的线程发送windows消息,通知钩子事件发生。如果这个线程没有处理消息,通信阻塞,64位进程挂起。如果此时安装hook的进程结束掉,64位进程继续执行。
注:64位进程安装hook,对32位目标进程的影响同上。
如果系统针对某些钩子同时安装了32位hook dll及64位hook dll,那hook例程怎么执行呢?在先安装64位hook dll再安装32位hook dll的情况下,32位hook位于hook 链表的顶端。如果某个32位进程产生了hook事件,就会在其进程上下文中执行hook例程,执行完毕后交由下一个消息钩子执行。如果下一个消息钩子是64位hook dll,则向安装此hook的线程发送消息,在安装hook的线程上下文中执行hook例程。如果是64位进程产生了hook事件,则向安装顶端32位hook的线程发送消息,交由此线程执行hook例程,执行完毕后由下一个消息钩子执行。在我的测试中,即便下一个消息钩子为64位进程安装,依然是向此安装hook的64位进程发送消息处理hook。
在先安装32位hook dll再安装64位hook dll的情况下,64位hook位于hook 链表的顶端。如果某个64位进程产生了hook事件,就会在其进程上下文中执行hook例程,执行完毕后交由下一个消息钩子执行。如果下一个消息钩子是32位hook dll,则向安装此hook的线程发送消息,在安装hook的线程上下文中执行hook例程。如果是32位进程产生了hook事件,则向安装顶端64位hook的线程发送消息,交由此线程执行hook例程,执行完毕后由下一个消息钩子执行。在我的测试中,即便下一个消息钩子为32位进程安装,依然是向此安装hook的32位进程发送消息处理hook。
MSDN文档中说The 32-bit and 64-bit DLLs must have different names. 在我的测试及我搜索的文档中,这是不必须的。
问题来了,如果在安装hook的进程中执行hook例程怎么确认究竟是哪个进程产生的hook事件呢?