简体   繁体   English

32位程序无法捕获在32位进程上进行的击键,但能够捕获在64位进程上进行的击键

[英]32-bit program is unable to capture keystrokes made on a 32-bit process, but able to capture those made on a 64-bit process

My environment details: 我的环境详细信息:

  • Operating system: Windows 7 Enterprise Service Pack 1 (64-bit Operating System) 操作系统:Windows 7 Enterprise Service Pack 1(64位操作系统)
  • Compiler: Microsoft Visual Studio 2005 (Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 14.00.50727.762 for 80x86) 编译器:Microsoft Visual Studio 2005(适用于80x86的Microsoft(R)32位C / C ++优化编译器版本14.00.50727.762)
  • My program main.exe and hook.dll are 32-bit 我的程序main.exe和hook.dll是32位的
  • Internet Explorer (iexplore.exe) is 64-bit Internet Explorer(iexplore.exe)是64位
  • Chrome (chrome.exe) is 32-bit Chrome(chrome.exe)是32位

I have written a C++ program called main.exe that makes the following calls: 我编写了一个名为main.exe的C ++程序,该程序进行以下调用:

HOOKPROC callback = (HOOKPROC) GetProcAddress(dll, "keyboardHook");
HHOOK hook = SetWindowsHookEx(WH_KEYBOARD, callback, dll, NULL);

The keyboardHook function is defined in a DLL called hook.dll. keyboardHook函数在一个名为hook.dll的DLL中定义。 This function logs every keystroke on the console as well as a file called out.txt. 此功能记录控制台上的每个按键以及一个名为out.txt的文件。

I perform the following experiment. 我执行以下实验。

  1. Execute main.exe on command prompt. 在命令提示符下执行main.exe。
  2. Make Internet Explorer (64-bit) as my active window and press A , B and C on it. 将Internet Explorer(64位)作为我的活动窗口,然后在其上按ABC。
  3. Make Chrome (32-bit) as my active window and press X , Y and Z on it. 将Chrome(32位)作为我的活动窗口,然后按XYZ。
  4. Make command prompt my active window and kill main.exe by pressing Ctrl + C . 使命令提示我的活动窗口,并按Ctrl + C杀死main.exe。

I see only the following output on the console. 我在控制台上仅看到以下输出。

C:\lab\keyhook>main,exe
hinstDLL: 10000000; fdwReason: 1; lpvReserved: 00000000
); scan code: 28; transition state: 1
nCode: 0; wParam: 65 (A); scan code: 30; transition state: 0
nCode: 0; wParam: 65 (A); scan code: 30; transition state: 1
nCode: 0; wParam: 66 (B); scan code: 48; transition state: 0
nCode: 0; wParam: 66 (B); scan code: 48; transition state: 1
nCode: 0; wParam: 67 (C); scan code: 46; transition state: 0
nCode: 0; wParam: 67 (C); scan code: 46; transition state: 1
nCode: 0; wParam: 17 (◄); scan code: 29; transition state: 0
nCode: 0; wParam: 67 (C); scan code: 46; transition state: 0
hinstDLL: 10000000; fdwReason: 2; lpvReserved: 00000000
hinstDLL: 10000000; fdwReason: 0; lpvReserved: 00000001

And I see only the following output in the file I am logging to. 而且我正在登录的文件中仅看到以下输出。

C:\lab\keyhook>type out.txt
); scan code: 28; transition state: 1
nCode: 0; wParam: 65 (A); scan code: 30; transition state: 0
nCode: 0; wParam: 65 (A); scan code: 30; transition state: 1
nCode: 0; wParam: 66 (B); scan code: 48; transition state: 0
nCode: 0; wParam: 66 (B); scan code: 48; transition state: 1
nCode: 0; wParam: 67 (C); scan code: 46; transition state: 0
nCode: 0; wParam: 67 (C); scan code: 46; transition state: 1
nCode: 0; wParam: 17 (◄); scan code: 29; transition state: 0
nCode: 0; wParam: 67 (C); scan code: 46; transition state: 0

You can see that the keystrokes made on 32-bit Chrome have not been captured either in the console or in the log file. 您可以看到在控制台或日志文件中都未捕获在32位Chrome上进行的击键。

Why is it that my 32-bit program compiled with a 32-bit C++ compiler succeeds in capturing keystrokes made on 64-bit iexplore.exe but fails to capture keystrokes made on 32-bit chrome.exe? 为什么我的用32位C ++编译器编译的32位程序能够成功捕获在64位iexplore.exe上进行的击键,但是却无法捕获在32位chrome.exe上进行的击键?

The SetWindowsHookEx documentation on MSDN seems to indicate that my 32-bit program should be able to capture keystrokes made on other 32-bit programs only. MSDN上的SetWindowsHookEx文档似乎表明,我的32位程序应该只能捕获在其他32位程序上进行的击键。

SetWindowsHookEx can be used to inject a DLL into another process. SetWindowsHookEx可用于将DLL注入另一个进程。 A 32-bit DLL cannot be injected into a 64-bit process, and a 64-bit DLL cannot be injected into a 32-bit process. 无法将32位DLL注入到64位进程中,并且不能将64位DLL注入到32位进程中。 If an application requires the use of hooks in other processes, it is required that a 32-bit application call SetWindowsHookEx to inject a 32-bit DLL into 32-bit processes, and a 64-bit application call SetWindowsHookEx to inject a 64-bit DLL into 64-bit processes. 如果应用程序需要在其他进程中使用钩子,则需要32位应用程序调用SetWindowsHookEx才能将32位DLL注入32位进程,而64位应用程序调用SetWindowsHookEx可以注入64位。 DLL转换为64位进程。 The 32-bit and 64-bit DLLs must have different names. 32位和64位DLL必须具有不同的名称。

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). 如果32位应用程序在64位Windows上安装了全局钩子,则32位钩子将注入到每个32位进程中(通常存在安全边界)。 In a 64-bit process, the threads are still marked as "hooked." 在64位进程中,线程仍标记为“已挂钩”。 However, because a 32-bit application must run the hook code, the system executes the hook in the hooking app's context; 但是,由于32位应用程序必须运行挂钩代码,因此系统会在挂钩应用程序的上下文中执行挂钩; specifically, on the thread that called SetWindowsHookEx. 具体来说,在名为SetWindowsHookEx的线程上。 This means that the hooking application must continue to pump messages or it might block the normal functioning of the 64-bit processes. 这意味着挂钩应用程序必须继续泵送消息,否则可能会阻止64位进程的正常运行。

Here is the complete code of my main program that invokes SetWindowsHookEx . 这是调用SetWindowsHookEx主程序的完整代码。

// Filename: main.cc
#include <iostream>
#include <windows.h>

int main(int argc, char **argv)
{
    HMODULE dll = LoadLibrary("hook.dll");
    if (dll == NULL) {
        std::cerr << "LoadLibrary error " << GetLastError() << std::endl;
        return 1;
    }

    HOOKPROC callback = (HOOKPROC) GetProcAddress(dll, "keyboardHook");
    if (callback == NULL) {
        std::cerr << "GetProcAddress error " << GetLastError() << std::endl;
        return 1;
    }

    HHOOK hook = SetWindowsHookEx(WH_KEYBOARD, callback, dll, NULL);
    if (hook == NULL) {
        std::cerr << "SetWindowsHookEx error " << GetLastError() << std::endl;
        return 1;
    }

    MSG messages;
    while (GetMessage (&messages, NULL, 0, 0))
    {
        TranslateMessage(&messages);
        DispatchMessage(&messages);
    }
    UnhookWindowsHookEx(hook);
}

Here is the DLL code. 这是DLL代码。

// Filename: hook.cc
#include <iostream>
#include <fstream>
#include <windows.h>

extern "C" __declspec(dllexport)
LRESULT keyboardHook(int nCode, WPARAM wParam, LPARAM lParam)
{
    std::ofstream outputTxt("out.txt", std::ofstream::out | std::ofstream::app);
    outputTxt << "nCode: " << nCode << "; wParam: " << wParam
              <<" (" << char(wParam) << "); scan code: "
              << ((lParam & 0xFF0000) >> 16)
              << "; transition state: " << ((lParam & 0x80000000) >> 31)
              << std::endl;
    outputTxt.close();

    std::cout << "nCode: " << nCode << "; wParam: " << wParam
              <<" (" << char(wParam) << "); scan code: "
              << ((lParam & 0xFF0000) >> 16)
              << "; transition state: " << ((lParam & 0x80000000) >> 31)
              << std::endl;
    return CallNextHookEx(NULL, nCode, wParam, lParam);
}

BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
    std::cout << "hinstDLL: " << hinstDLL
              << "; fdwReason: " << fdwReason
              << "; lpvReserved: " << lpvReserved << std::endl;

    return TRUE;
}

This is how I compile this project: 这就是我编译该项目的方式:

vcvars32.bat
cl /LD hook.cc /link user32.lib
cl main.cc /link user32.lib

This is what the processes look like. 这就是过程的样子。 See that chrome.exe and main.exe are 32-bit processes whereas instances of iexplore.exe are 64-bit processes. 请参阅chrome.exe和main.exe是32位进程,而iexplore.exe实例是64位进程。

任务管理器

Can you explain why my observation does not match the MSDN documentation? 您能解释为什么我的观察结果与MSDN文档不匹配吗?

The comments by Hans Passant to this question and this answer by manuell helped me to understand and fix my code. 汉斯· 帕桑特 (Hans Passant)对这个问题的评论以及manuell的回答都帮助我理解和修复了我的代码。

The relative path "out.txt" was the source of all confusion. 相对路径"out.txt"是所有混乱的根源。

My 32-bit program successfully injects its 32-bit hook into 32-bit Chrome. 我的32位程序成功将其32位挂钩插入了32位Chrome。 Therefore, the hook runs in Chrome's context and the "out.txt" file is written in Chrome's working directory. 因此,该挂钩在Chrome的上下文中运行,而“ out.txt”文件则写在Chrome的工作目录中。 Thus, the keystrokes X , Y and Z that were made on Chrome as the active window were logged at "C:\\Program Files (x86)\\Google\\Chrome\\Application\\31.0.1650.63\\out.txt". 因此,在Chrome上作为活动窗口进行的击键XYZ记录在“ C:\\ Program Files(x86)\\ Google \\ Chrome \\ Application \\ 31.0.1650.63 \\ out.txt”中。

C:\>type "C:\Program Files (x86)\Google\Chrome\Application\31.0.1650.63\out.txt"
nCode: 0; wParam: 88 (X); scan code: 45; transition state: 0
nCode: 0; wParam: 88 (X); scan code: 45; transition state: 1
nCode: 0; wParam: 89 (Y); scan code: 21; transition state: 0
nCode: 0; wParam: 89 (Y); scan code: 21; transition state: 1
nCode: 0; wParam: 90 (Z); scan code: 44; transition state: 0
nCode: 0; wParam: 90 (Z); scan code: 44; transition state: 1

This output didn't appear in the console because no console is associated with Chrome. 此输出未出现在控制台中,因为没有控制台与Chrome关联。

However, my 32-bit program cannot inject its 32-bit hook into 64-bit Internet Explorer. 但是,我的32位程序无法将其32位挂钩插入64位Internet Explorer。 As a result, the hook executes in my program's context and the "out.txt" file is created in my program's working directory when it logs the keystrokes made on 64-bit Internet Explorer. 结果,该挂钩在我的程序的上下文中执行,并且当它记录在64位Internet Explorer上进行的击键时,在程序的工作目录中创建了“ out.txt”文件。 This output is also logged on the console because there is a console associated with my program. 此输出也记录在控制台上,因为有一个与我的程序关联的控制台。 This is what you saw mentioned in my question. 这就是您在我的问题中提到的内容。

A simple fix to my code would be to log the keystrokes to an absolute path "C:\\\\out.txt" instead of the relative path "C:\\out.txt" in hook.cc, so that I can see keystrokes made on both 32-bit programs and 64-bit programs in the same file. 对我的代码的一个简单修复是将击键记录到绝对路径"C:\\\\out.txt"而不是hook.cc中的相对路径“ C:\\ out.txt”,这样我就可以看到进行的击键在同一文件中的32位程序和64位程序上。

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

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