请参阅:
查找钩子:与其他操作相比,枚举已安装的钩子非常容易。
线程特定钩子记录在一个Windows 32位(win32k)每个线程数据结构中,标记为THREADINFO1。这本质上是一个ETHREAD/TEB类似的结构,但专门用于用户和gdi信息。其中之一成员(aphkStart)是指针的16元素数组,它们分别指向NULL,或者HOOK结构的链接列表的头。枚举挂钩只是沿着这些链行走的措施。
为了方便起见,并且可能不需要迭代即可查看是否设置了任何挂钩,THREADINFO包含另一个成员fsHooks,这是一个位域。如果一个位打开,则钩子数组中的相应索引有效。而不是33个比较(16个用于NULL和17个用于for循环),告诉是否有挂钩仅需要一个,不错!
全局挂钩(每个桌面2)也存储在一个名为DESKTOPINFO的每个对象结构中,并且也存储在一个带有相应位域的数组中。将两者连接起来的是THREADINFO的成员pDeskInfo,它指向其拥有的DESKTOPINFO。
尽管在介绍中抱怨,但实际上使用所有这些未记录的结构并不太难。win32k.sys的Windows 7符号包括它们的布局,这很好。 Vista/Server 2008时代的符号则没有,这就是汇编研究的地方,可以解救危机。
知道这些结构看起来是一件事,而得到它们则是另一回事……
在获取了它们后,我们发现HOOK结构本身记录了大部分相关信息:
struct tagHOOK
{
THRDESKHEAD head; // info about the creator
struct tagHOOK* phkNext; // next entry in linked list
int iHook; // WH_ hook type
UINT_PTR offPfn; // RVA to hook function in ihmod library
UINT flags; // HF_ flags (GLOBAL, ANSI)
int ihmod;
THREADINFO* ptiHooked; // the hooked thread
PVOID rpDesk; // saved desktop pointer
ULONG nTimeout :7;
ULONG fLastHookHung :1;
};
您可以在此处下载软件:点此链接
检测已安装全局钩子的概述如下:
- 调用 PsGetCurrentThread 并获取当前线程的 ETHREAD 结构。根据 MSDN 文档,ETHREAD 是不透明的数据结构。
- 通过调用 PsGetThreadWin32Thread 提取 THREADINFO 结构(两者都是未公开的)。
- 提取 DESKTOPINFO。
- 您可以在其中找到所有已安装的全局钩子。它们以数组形式组织。每个元素都是一个链接列表,并对应于特定的钩子(WH_*)。
检测已安装本地钩子的概述如下:
- 给定线程 ID。
- 调用 PsLookupThreadByThreadId 并获取指定线程的 ETHREAD 结构。
- 通过调用 PsGetThreadWin32Thread 提取 THREADINFO 结构。
- 您可以在其中找到指定线程的所有本地安装钩子。它们以数组形式组织。每个元素都是一个链接列表,并对应于特定的钩子(WH_*)。
您可以在此处查看源代码:点此链接
Process Hacker 2(http://processhacker.sourceforge.net) 的插件,显示系统钩子并可以取消钩子(右键单击菜单)。
获取 Process Hacker 源代码并编译它,然后将 HookTools.vcxproj 添加到 Plugins.sln。使用 VS 2013。 在 VC++ 目录中设置库路径。
或者在此处查看相关问题和答案
但我尚未找到一种可靠的方法来执行此操作。
win32k.sys
驱动程序管理)。内核提供系统调用以注册(NtUserSetWindowsHookEx
)和注销(NtUserUnhookWindowsHookEx
)钩子,但没有等效的获取系统调用。因此,您需要一个驱动程序在内核空间运行代码,然后才能读取这些未记录的数据结构。由于Microsoft可能会更改其布局,任何更新都可能破坏您的驱动程序。真遗憾微软没有提供GetWindowsHookEx
函数! - Simon Kissane