繁体   English   中英

64位Windows上的Global Keyhook

[英]Global Keyhook on 64-Bit Windows

我目前在使用Windows 7 64位O / S上运行全​​局关键钩时遇到一些麻烦。 现在我知道Stackoverflow上已有很多关于这个主题的线程,但是它们都没有给我一个我可以使用的答案,或者我不太明白这些问题是如何在这些线程中解决的。

因此,我将尝试解释我正在努力解决的问题,并希望任何人都可以帮助我或指出我正确的方向。

基本上我的目标是拦截一种剪贴板管理器的CTRL + C和CTRL + V键盘输入。 出于这个原因,我目前的尝试是注册一个系统范围的WH_KEYBOARD钩子,它根据我的需要处理截获的击键。

我在64位Windows 7操作系统上运行挂钩,这就是问题的起点。 对我来说很明显,32位Hook DLL会导致64位进程出现问题,反之亦然。 出于这个原因,我已经生成了包含钩子的我的库的x86和x64版本,以及钩子的调用者(调用SetWindowsHookEx() ),两者都有不同的文件名,如文档所示。

但现在呢? 如果我将我的64位DLL设置为系统范围的挂钩 ,那么所有32位应用程序在我们聚焦时按下一个键就会立即挂起。 当我应用32位钩子时,我的Windows实际上无法使用,因为explorer.exe是64位。 如果我设置两个钩子,我的系统就会停滞不前,在全球范围内进行“比特”战斗。

现在我假设问题来自于例如64位挂钩DLL试图注入32位进程等等,这当然是无稽之谈。 但是对于这种情况, SetWindowsHookEx()的文档说明如下:

因为钩子在应用程序的上下文中运行,所以它们必须匹配应用程序的“位数”。 如果32位应用程序在64位Windows上安装全局挂钩,则会在每个32位进程中注入32位挂钩(通常的安全边界适用)。 在64位进程中,线程仍标记为“已挂钩”。 但是,因为32位应用程序必须运行钩子代码,系统才会在钩子应用程序的上下文中执行钩子; 特别是在调用SetWindowsHookEx的线程上。 这意味着挂钩应用程序必须继续泵送消息,否则可能会阻止64位进程的正常运行。

我并不完全理解文本的粗体部分,但我将其解释为如果挂钩目标的“位数”与挂钩目标的“位数”不同,则会在实际设置挂钩的线程上执行它可以完全执行。 此外,这意味着此线程仍必须处于活动状态,并且可能正在运行某种消息循环。 这个对吗? 或者我完全不在这一个? 该文档似乎也提供了有关如何为我的方案做的确切说明:

要挂钩64位Windows安装的桌面上的所有应用程序,请安装32位全局挂钩和64位全局挂钩,每个挂钩都来自适当的进程,并确保在挂钩应用程序中保留消息以避免阻塞正常运行。

但是我没有理解在实施过程中必须做些什么。 为了最终显示一些代码,让我们来看一个尝试设置系统范围的keyhook的基本示例。 我想线程的创建代码应该是无关紧要的:

volatile static bool runThread = false;

DWORD WINAPI threadStart(LPVOID lpThreadParameter) {
    HMODULE hMod = LoadLibraryA(is64Bit() ? "keyhook.x64.dll" : "keyhook.x86.dll");
    HHOOK hHook = SetWindowsHookExA(WH_KEYBOARD, (HOOKPROC)GetProcAddress(hMod, "hookProc"), hMod, 0)));

    runThread = true;
    while(runThread) {
        // Message pump? Yes? No? How?
        Sleep(10);
    }

    UnhookWindowsHookEx(hHook);
    FreeLibrary(hMod);
    return 0;
}

钩子本身保持相当微不足道 - 它足以在穿过钻头时引起挂起问题:

extern "C" LRESULT hookProc(int code, WPARAM wParam, LPARAM lParam) {
    if(code == HC_ACTION) {
    }

    return CallNextHookEx(nullptr, code, wParam, lParam);
}

我假设有些人现在可能会把手放在他们的头上,并且你可以告诉我我很少使用钩子;)

但这正是我要问的原因:)

为了简短起见:如果有人能告诉我如何更改上面的示例以使系统范围的keyhook在64位Windows上运行,我将不胜感激。 我的问题是某些应用程序与其他“位数”比挂钩开始挂起,我不知道如何解决问题。

很感谢任何形式的帮助!

谢谢并恭祝安康

PuerNoctis

好的,我弄明白问题是什么。 也许我的解决方案可以帮助其他人遇到同样的问题:如上所述,文档明确指出了这一点

[...]系统在(32位)挂钩应用程序的上下文中执行(32位)挂钩; 特别是在调用SetWindowsHookEx的线程上。 这意味着挂钩应用程序必须继续泵送消息,否则可能会阻止64位进程的正常运行。

我所经历的是所提到的阻塞行为,应该通过消息泵来克服。 在上面的代码示例中,正好缺少这个机制,因为我不知道这应该是一个简单的Windows消息循环(我之前不知道'泵'一词)。 我的初始代码中的最终代码片段必须如下所示:

volatile static bool runThread = false;

DWORD WINAPI threadStart(LPVOID lpThreadParameter) {
    HMODULE hMod = LoadLibraryA(is64Bit() ? "keyhook.x64.dll" : "keyhook.x86.dll");
    HHOOK hHook = SetWindowsHookExA(WH_KEYBOARD, (HOOKPROC)GetProcAddress(hMod, "hookProc"), hMod, 0)));

    MSG msg;
    runThread = true;
    while(runThread) {
        // Keep pumping...
        PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE);
        TranslateMessage(&msg);
        DispatchMessage(&msg);
        Sleep(10);
    }

    UnhookWindowsHookEx(hHook);
    FreeLibrary(hMod);
    return 0;
}

在这个例子中,我使用非阻塞PeekMessage()而不是GetMessage() ,因为我希望我的线程不断检查它的终止标志。

通过这种实现,我的钩子在所有本机64位或WOW64进程中按预期工作,没有应用程序挂起后就会挂起。 消息泵是唯一缺少的部分。

经过所有这些实验后,我得出以下结论 - 如果我错了,请在评论中纠正我:

安装系统范围的挂钩时,会尝试将给定的Hook-DLL注入到每个运行的进程中。 如果进程的“位数”与Hook-DLL中的“位数”匹配,则挂钩过程作为目标进程中的远程线程执行(就像普通的Injectors工作一样)。 在“位数”不同的情况下,Windows将回退绕回到最初调用SetWindowsHookEx()的进程和线程(在我的示例中为代码片段中的线程),并用作进程的执行代理。 t匹配“位数”。 因此,此线程需要不断处理传入的消息,否则将不会为原始目标进程处理任何事件,而原始目标进程又会开始挂起。

同样,如果这不完全正确,不完整,或者如果还有其他补充说明,请在下面发表评论。 谢谢! :)

我的解决方案是编译钩子应用程序(其中调用了SetWindowsHookEx() )和DLL(回调钩子函数所在的位置)到x86和x64版本。 因此,我们有两个EXE(xxx-x86.exe和xxx-x64.exe)和两个DLL(xxx-x86.dll和xxx-x64.dll)。

然后实现一个复杂的IPC协议来同步x86 app和x64 app之间的数据。 看起来很有效,不会阻止另一个“比特”无法比拟的过程。 但是处理精确的事件序列很困难,它只能作为事件的粗略指标。

这个解决方案非常难看,但我没有更好的方法......

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM