64位Windows上的全局键盘 [英] Global Keyhook on 64-Bit Windows

查看:177
本文介绍了64位Windows上的全局键盘的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我目前有一些麻烦,要获得一个全局钥匙钩在Windows 7 64位O / S。现在我知道在这个话题上有很多线程已经在这里的Stackoverflow,但没有人给我一个答案,我可以工作,或者我不太明白如何解决这些问题在这些线程。 p>

因此,我将尝试解释我正在努力的工作,希望任何人都能帮助我或指出正确的方向。



基本上我的目标是截取CTRL + C和CTRL + V键盘输入一种剪贴板管理器。为此,我目前的尝试是注册一个系统范围的 WH_KEYBOARD 钩子,处理截取的击键对我的需要。



我在64位Windows 7 O / S上运行钩子,这就是问题的起点。对我来说很明显,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位
进程中,线程仍被标记为hooked。 然而,因为
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){
//消息泵?是?没有?怎么样?
Sleep(10);
}

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

钩子本身保持相当微不足道 - 当跨越bitness时:

  externCLRESULT 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 = 

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){
//保持抽运...
PeekMessage(& msg,nullptr,0,0,PM_REMOVE);
TranslateMessage(& msg);
DispatchMessage(& msg);
Sleep(10);
}

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

在本例中,我使用非阻塞 PeekMessage()而不是 GetMessage(),因为我想让我的线程不断检查它的终止标志。



通过这个实现,我的挂钩在所有本地64位或WOW64进程中都能正常工作,没有应用程序挂机时就会挂起。消息泵是唯一缺少的部分。



在所有这些实验后,我得出以下结论 - 如果我错了,请在注释中更正我: p>

当安装了系统范围的钩子时,它试图将给定的Hook-DLL注入每个进程运行。如果进程的位数与Hook-DLL中的位数匹配,则挂钩过程作为目标进程中的远程线程执行(像正常的注入器工作)。如果bitness不同,Windows会回滚到最初调用 SetWindowsHookEx()(在我的例子中是代码片段中的线程)的进程和线程,并且用作与比特率不匹配的处理的执行代理。因此,这个线程需要持续处理传入的消息,否则将不会为原始目标进程处理事件,而后者会开始挂起。



如果有不完全正确的,不完整的,或者如果有任何进一步的笔记添加,请在下面注释。谢谢! :)


I currently have some trouble to get a global keyhook working on a Windows 7 64-Bit O/S. Now I know that there are a lot of threads on this topic already here on Stackoverflow, but none of them quite give me an answer that I can work with or I don't quite understand how the issue is solved in these threads.

So I will try to explain what I am struggling with and hope that anyone can help me out or point me into the right direction.

Basically my goal is to intercept the CTRL+C and CTRL+V keyboard inputs for a sort of clipboard manager. For this reason my current attempt is to register a syste-wide WH_KEYBOARD hook which deals with the intercepted keystrokes to my needs.

I am running the hook on a 64-Bit Windows 7 O/S, and that is where the problems start. It is obvious to me that a 32-Bit Hook DLL causes problems for 64-Bit processes, vice versa. For this reason I have generated a x86 and x64 version of my library containing the hook, as well as for the invoker of the hook (the one who calls SetWindowsHookEx()), both with different filenames as the documentation suggests.

But what now? If I set a my 64-Bit DLL as a system-wide hook, all the 32-Bit applications start hanging as soon as I press a key when they are focused. Same thing when I apply the 32-Bit hook, my Windows is practically unusable because the explorer.exe is 64-Bit. If I set both hooks, my system is effectivley at a standstill, having a global "bitness" fight in place.

Now I assume that the issue arises from e.g. the 64-Bit hooking DLL trying to be injected into a 32-Bit process and so forth, which is of course nonesense. But for this case the documentation of SetWindowsHookEx() says the following:

Because hooks run in the context of an application, they must match the "bitness" of the application. If a 32-bit application installs a global hook on 64-bit Windows, the 32-bit hook is injected into each 32-bit process (the usual security boundaries apply). In a 64-bit process, the threads are still marked as "hooked." However, because a 32-bit application must run the hook code, the system executes the hook in the hooking app's context; specifically, on the thread that called SetWindowsHookEx. This means that the hooking application must continue to pump messages or it might block the normal functioning of the 64-bit processes.

I don't fully understand the bold part of the text, but I interpret it as in that if the "bitness" of a hooking target differs from the one of the hook, it is executed on the thread that has actually set the hook so it can be executed at all. Furthermore, this means that this thread must still be active and probably running a sort of message loop. Is this correct? Or am I totally off on this one? The documentation also seems to give exact instructions on what to do for my scenario:

To hook all applications on the desktop of a 64-bit Windows installation, install a 32-bit global hook and a 64-bit global hook, each from appropriate processes, and be sure to keep pumping messages in the hooking application to avoid blocking normal functioning.

But yet I fail to grasp what has to be done in my implementation. To finally show some code, let's take this basic example of trying to set a system-wide keyhook. I guess the creating code for the thread should be irrelevant:

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;
}

The hook itself is kept quite trivial - it is enough to cause the hangup issues when crossing the bitness:

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

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

I assume that some people might throw there hands over their heads right now, and that you can tell that I seldom have worked with hooks ;)

But that's exactly why I am asking :)

To keep things short: I would be grateful if someone could tell me how to change the above example to get a system-wide keyhook working on 64-Bit Windows. My problem is that certain applications with other "bitness" than the hook start hanging and I don't know how to solve the issue.

Any help is very much appreciated!

Thanks and regards

PuerNoctis

解决方案

Okay, I figured out what the problem was. Maybe my solution helps others experiencing the same issue: As mentioned above, the documentation explicitly states that

[...] the system executes the (32-Bit) hook in the (32-Bit) hooking app's context; specifically, on the thread that called SetWindowsHookEx. This means that the hooking application must continue to pump messages or it might block the normal functioning of the 64-bit processes.

What I was experiencing was the mentioned blocking behaviour that is supposed to be overcome with a message pump. In my above code example, exactly this piece of mechanism was missing, as I wasn't aware that this is supposed to be a simple Windows Message Loop (I didn't know of the term 'pump' before). The finalized code snippet from my initial code must look something like this:

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;
}

In this example I am using the non-blocking PeekMessage() instead of GetMessage(), as I want my thread to constantly check it's termination flag.

With this implementation my hook works as expected in all native 64-Bit or WOW64 processes, no applications hang up as soon as they are hooked. The message pump was the only part missing.

After all this experimentation I come to the following conclusion - and if I am wrong, please correct me in the comments:

When a system-wide hook is installed, it is tried to inject the given Hook-DLL into every process running. If the "bitness" of a process matches the one from the Hook-DLL, the hooking procedure is executed as a remote thread in the target process (like normal Injectors work). In case the "bitness" differs, Windows takes a fallback detour back to the process and thread that initially called SetWindowsHookEx() (in my example the thread in the code snippet), and serves as an execution-proxy for the process that doesn't match the "bitness". For this reason, it is required for this thread to constantly handle incoming messages, otherwise no events will be processed for the original target process which in return starts hanging.

Again, if there is this is not quite right, incomplete, or if there are any further notes to add, please put a comment below. Thanks! :)

这篇关于64位Windows上的全局键盘的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆