SetWindowsHookEx 挂钩到每个正在运行的程序

Posted

技术标签:

【中文标题】SetWindowsHookEx 挂钩到每个正在运行的程序【英文标题】:SetWindowsHookEx hooking into every running program 【发布时间】:2021-05-01 11:47:22 【问题描述】:

我编写了一个小 DLL,它被注入到游戏中以应用运行时修复。我决定添加一些键盘监听器:

while (1)
    if (AsyncKeyState(...)) (...)

但是,这会占用 CPU 资源,并引入一些明显的卡顿。所以我决定使用 MSDN 通过SetWindowsHookExAKeyboardProc 回调建议的回调方法。起初,我通过SetWindowsHookExA(WH_Keyboard, KeyboardProc, NULL, 0) 运行该方法,但收到错误代码ERROR_HOOK_NEEDS_HMOD (0x594)。所以我把我的代码改成了这样:

bool APIENTRY DllMain(HMODULE hModule, DWORD reason, LPVOID lpRes)

    HHOOK hook_ = nullptr;
    switch (reason)
    
    case DLL_PROCESS_ATTACH:
        
        if (!(hook_ = SetWindowsHookEx(WH_KEYBOARD, KeyboardProc, hModule, 0)))
        
            char x[100];
            sprintf(x, "Failed To Hook Keyboard FN: 0x%X", GetLastError());
            MessageBox(NULL, x, "Error", MB_ICONERROR);
        
        break;
    case DLL_THREAD_ATTACH:
    case DLL_THREAD_DETACH:
    case DLL_PROCESS_DETACH:
        UnhookWindowsHookEx(hook_);
        break;
    
    return true;

这不再给出错误,我的挂钩键盘功能运行良好。然而,一个非常意想不到的副作用是所有正在运行的应用程序的所有键盘捕获都被忽略了。 我注意到 MSDN 的这句话,所以我将它添加到我的代码中:

如果code大于等于0,并且hook过程没有处理该消息,强烈建议调用CallNextHookEx并返回它返回的值;否则,其他安装了 WH_KEYBOARD 挂钩的应用程序将不会收到挂钩通知,因此可能会出现错误行为。如果钩子过程处理了消息,它可能会返回一个非零值,以防止系统将消息传递给钩子链的其余部分或目标窗口过程。

这解决了键盘问题,但现在还有另一个问题,即我无法删除我创建的 DLL。当我尝试删除它时,它显示“dll 正在 Explorer.exe 中运行”。当我杀死explorer.exe 时,它说“dll 正在 SteamHelper.exe 中运行”。当我杀死 steamhelper.exe 时,它说“dll 正在 Chrome.exe 中运行”。这表明我已经以某种方式迷上了每个正在运行的应用程序?

我无法解决此问题,也找不到任何帮助。非常感谢任何见解!

【问题讨论】:

我不明白这个问题。您已经要求系统将您的 DLL 注入到每个进程中,并且现在对 DLL 被注入到每个进程中感到惊讶?解决方法是不要将您的 DLL 注入每个进程,但您似乎已经决定这是必需的。 【参考方案1】:

您正在挂钩每个应用程序进程,因为您正在全局安装挂钩,方法是将SetWindowsHookEx()dwThreadId 参数设置为0:

dwThreadId

类型:DWORD

与钩子过程相关联的线程的标识符。对于桌面应用程序,如果此参数为零,则挂钩过程与在与调用线程相同的桌面上运行的所有现有线程相关联。对于 Windows 应用商店应用,请参阅备注部分。

相反,您应该将该参数设置为要为其挂钩事件的游戏线程的实际线程 ID。

【讨论】:

谢谢。我用GetCurrentThreadId() 替换了“0”参数,效果很好。我对他们的措辞感到困惑,因为这个参数依赖于前一个参数,所以我知道如果你从同一个代码库中调用它,你将两者都设置为 0。

以上是关于SetWindowsHookEx 挂钩到每个正在运行的程序的主要内容,如果未能解决你的问题,请参考以下文章

窗户挂钩问题

SetWindowsHookEx 与 Qt4 中的 WH_JOURNALRECORD 挂钩

增加 Windows 7 中的 SetWindowsHookEx 限制

c#中的窗口挂钩

SetWindowsHookEx 不适用于线程 ID

调用外部 SetWindowsHookEx 和 GetModuleHandle 的 PInvoke 错误