簡體   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