You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

EasyHook捕获DefWindowProcW启动线程后无法拦截嵌套调用问题咨询

EasyHook嵌套捕获DefWindowProcW调用的正确实现方案

原有实现的核心问题

  • 所有钩子共用同一个回调函数,没有区分内外层钩子的分工逻辑,行为自然完全一致
  • ACL设置逻辑完全不符合要求:EasyHook的ACL列表参数为线程ID,传入0代表匹配所有线程,原有代码全填0无法实现按调用层级切换钩子启用状态
  • 存在低级代码错误:初始化时使用了未定义的ACLEntries4变量、设置hHook3的ACL时错用了ACLEntries2变量,多余安装了第三个无意义的钩子

正确实现逻辑

官方提供的双钩子方案核心是用两个钩子分别负责外层、内层调用的捕获,通过ACL动态切换当前线程可触发的钩子,绕开死锁屏障限制:

  1. 仅需安装2个钩子,分别为外层钩子、内层钩子,两者的回调可以复用相同的业务处理逻辑
  2. 初始状态配置:
    • 外层钩子默认对所有线程启用,负责捕获第一层DefWindowProcW调用
    • 内层钩子默认对所有线程禁用
  3. 外层钩子回调执行逻辑:
    • 进入回调后,先将当前线程加入外层钩子的排他ACL,禁止当前线程再次触发外层钩子
    • 把当前线程加入内层钩子的包含ACL,允许当前线程触发内层钩子
    • 执行业务处理逻辑
    • 调用原始DefWindowProcW,此时产生的嵌套调用会被内层钩子捕获
    • 回调返回前恢复两个钩子的初始ACL配置
  4. 内层钩子回调执行逻辑:
    • 直接执行业务处理逻辑
    • 调用原始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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.03 16:45:05