[英]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
我的环境详细信息:
我编写了一个名为main.exe的C ++程序,该程序进行以下调用:
HOOKPROC callback = (HOOKPROC) GetProcAddress(dll, "keyboardHook");
HHOOK hook = SetWindowsHookEx(WH_KEYBOARD, callback, dll, NULL);
keyboardHook
函数在一个名为hook.dll的DLL中定义。 此功能记录控制台上的每个按键以及一个名为out.txt的文件。
我执行以下实验。
我在控制台上仅看到以下输出。
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上作为活动窗口进行的击键X , Y和Z记录在“ 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.