EasyHook捕获DefWindowProcW启动线程后无法拦截嵌套调用问题咨询
EasyHook嵌套捕获DefWindowProcW调用的正确实现方案
原有实现的核心问题
- 所有钩子共用同一个回调函数,没有区分内外层钩子的分工逻辑,行为自然完全一致
- ACL设置逻辑完全不符合要求:EasyHook的ACL列表参数为线程ID,传入0代表匹配所有线程,原有代码全填0无法实现按调用层级切换钩子启用状态
- 存在低级代码错误:初始化时使用了未定义的
ACLEntries4变量、设置hHook3的ACL时错用了ACLEntries2变量,多余安装了第三个无意义的钩子
正确实现逻辑
官方提供的双钩子方案核心是用两个钩子分别负责外层、内层调用的捕获,通过ACL动态切换当前线程可触发的钩子,绕开死锁屏障限制:
- 仅需安装2个钩子,分别为外层钩子、内层钩子,两者的回调可以复用相同的业务处理逻辑
- 初始状态配置:
- 外层钩子默认对所有线程启用,负责捕获第一层DefWindowProcW调用
- 内层钩子默认对所有线程禁用
- 外层钩子回调执行逻辑:
- 进入回调后,先将当前线程加入外层钩子的排他ACL,禁止当前线程再次触发外层钩子
- 把当前线程加入内层钩子的包含ACL,允许当前线程触发内层钩子
- 执行业务处理逻辑
- 调用原始DefWindowProcW,此时产生的嵌套调用会被内层钩子捕获
- 回调返回前恢复两个钩子的初始ACL配置
- 内层钩子回调执行逻辑:
- 直接执行业务处理逻辑
- 调用原始DefWindowProcW返回即可,无需修改ACL配置
示例代码
#include <Windows.h> #include "easyhook.h" HOOK_TRACE_INFO hHookOuter = { NULL }; HOOK_TRACE_INFO hHookInner = { NULL }; // 公共业务处理逻辑,内外层钩子复用 LRESULT ProcessDefWindowProcW(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) { switch (Msg) { // 此处填写你的业务处理代码 default: break; } static auto pOriginalDefWindowProcW = (decltype(&DefWindowProcW))GetProcAddress(GetModuleHandleW(L"user32.dll"), "DefWindowProcW"); return pOriginalDefWindowProcW(hWnd, Msg, wParam, lParam); } // 内层钩子回调 LRESULT __stdcall DefWindowProcW_Hook_Inner(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) { return ProcessDefWindowProcW(hWnd, Msg, wParam, lParam); } // 外层钩子回调 LRESULT __stdcall DefWindowProcW_Hook_Outer(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) { ULONG currentTid = GetCurrentThreadId(); // 禁止当前线程触发外层钩子 ULONG excludeTid[1] = { currentTid }; LhSetExclusiveACL(excludeTid, 1, &hHookOuter); // 允许当前线程触发内层钩子 ULONG includeTid[1] = { currentTid }; LhSetInclusiveACL(includeTid, 1, &hHookInner); LRESULT result = ProcessDefWindowProcW(hWnd, Msg, wParam, lParam); // 恢复初始ACL配置 ULONG excludeAll[1] = { 0 }; LhSetExclusiveACL(excludeAll, 1, &hHookOuter); ULONG includeNone[1] = { 0 }; LhSetInclusiveACL(includeNone, 0, &hHookInner); return result; } void __stdcall NativeInjectionEntryPoint(REMOTE_ENTRY_INFO* inRemoteInfo) { auto pTargetFunc = GetProcAddress(GetModuleHandleW(L"user32.dll"), "DefWindowProcW"); // 安装外层钩子 LhInstallHook(pTargetFunc, DefWindowProcW_Hook_Outer, NULL, &hHookOuter); ULONG excludeAll[1] = { 0 }; LhSetExclusiveACL(excludeAll, 1, &hHookOuter); // 安装内层钩子 LhInstallHook(pTargetFunc, DefWindowProcW_Hook_Inner, NULL, &hHookInner); ULONG includeNone[1] = { 0 }; LhSetInclusiveACL(includeNone, 0, &hHookInner); }
注意事项
- 如果需要捕获更多层级的嵌套调用,可以按相同逻辑增加更多钩子,每一层对应一个钩子,进入上一层回调时启用下一层钩子的ACL即可
- 业务逻辑中不要执行耗时操作,避免影响原程序的消息循环效率
- ACL修改操作仅针对当前钩子生效,不会影响其他钩子的执行逻辑
内容的提问来源于stack exchange,提问作者user12733526
相关产品推荐
相关产品推荐

