繁体   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

我的环境详细信息:

  • 操作系统:Windows 7 Enterprise Service Pack 1(64位操作系统)
  • 编译器:Microsoft Visual Studio 2005(适用于80x86的Microsoft(R)32位C / C ++优化编译器版本14.00.50727.762)
  • 我的程序main.exe和hook.dll是32位的
  • Internet Explorer(iexplore.exe)是64位
  • Chrome(chrome.exe)是32位

我编写了一个名为main.exe的C ++程序,该程序进行以下调用:

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

keyboardHook函数在一个名为hook.dll的DLL中定义。 此功能记录控制台上的每个按键以及一个名为out.txt的文件。

我执行以下实验。

  1. 在命令提示符下执行main.exe。
  2. 将Internet Explorer(64位)作为我的活动窗口,然后在其上按ABC。
  3. 将Chrome(32位)作为我的活动窗口,然后按XYZ。
  4. 使命令提示我的活动窗口,并按Ctrl + C杀死main.exe。

我在控制台上仅看到以下输出。

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

而且我正在登录的文件中仅看到以下输出。

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

您可以看到在控制台或日志文件中都未捕获在32位Chrome上进行的击键。

为什么我的用32位C ++编译器编译的32位程序能够成功捕获在64位iexplore.exe上进行的击键,但是却无法捕获在32位chrome.exe上进行的击键?

MSDN上的SetWindowsHookEx文档似乎表明,我的32位程序应该只能捕获在其他32位程序上进行的击键。

SetWindowsHookEx可用于将DLL注入另一个进程。 无法将32位DLL注入到64位进程中,并且不能将64位DLL注入到32位进程中。 如果应用程序需要在其他进程中使用钩子,则需要32位应用程序调用SetWindowsHookEx才能将32位DLL注入32位进程,而64位应用程序调用SetWindowsHookEx可以注入64位。 DLL转换为64位进程。 32位和64位DLL必须具有不同的名称。

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

这是调用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);
}

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

这就是我编译该项目的方式:

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

这就是过程的样子。 请参阅chrome.exe和main.exe是32位进程,而iexplore.exe实例是64位进程。

任务管理器

您能解释为什么我的观察结果与MSDN文档不匹配吗?

汉斯· 帕桑特 (Hans Passant)对这个问题的评论以及manuell的回答都帮助我理解和修复了我的代码。

相对路径"out.txt"是所有混乱的根源。

我的32位程序成功将其32位挂钩插入了32位Chrome。 因此,该挂钩在Chrome的上下文中运行,而“ out.txt”文件则写在Chrome的工作目录中。 因此,在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

此输出未出现在控制台中,因为没有控制台与Chrome关联。

但是,我的32位程序无法将其32位挂钩插入64位Internet Explorer。 结果,该挂钩在我的程序的上下文中执行,并且当它记录在64位Internet Explorer上进行的击键时,在程序的工作目录中创建了“ out.txt”文件。 此输出也记录在控制台上,因为有一个与我的程序关联的控制台。 这就是您在我的问题中提到的内容。

对我的代码的一个简单修复是将击键记录到绝对路径"C:\\\\out.txt"而不是hook.cc中的相对路径“ C:\\ out.txt”,这样我就可以看到进行的击键在同一文件中的32位程序和64位程序上。

暂无
暂无

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

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