【发布时间】:2018-05-17 23:46:52
【问题描述】:
我正在为键盘设置一个全局挂钩。当我向其他应用程序提供键盘输入时,应用程序没有收到输入并且挂起。当控制台停止时,应用程序恢复并且键盘输入一起发布。
DLL 源代码:
#include <iostream>
#include <Windows.h>
#include <string>
using namespace std;
#define DLLEXPORT __declspec(dllexport)
DLLEXPORT bool installhook();
DLLEXPORT void unhook();
DLLEXPORT string TestLoaded();
DLLEXPORT LRESULT CALLBACK KeyboardProc ( int code, WPARAM wParam, LPARAM lParam );
static HHOOK kb_hook;
string test = "not loaded";
HINSTANCE hDLL;
DLLEXPORT LRESULT CALLBACK KeyboardProc ( int code, WPARAM wParam, LPARAM lParam )
{
if(code == HC_ACTION) // if there is an incoming action and a key was pressed
{
switch(wParam)
{
case VK_SPACE:
printf("Space was pressed\n"); //tried without this also
MessageBoxA(NULL, "Hi", "Space", MB_OK);
break;
}
}
return CallNextHookEx(NULL, code, wParam, lParam);
}
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
test = "loaded";
switch(ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
hDLL = hModule;
break;
}
printf("test str = %s \n", test.c_str());
return TRUE;
}
bool installhook()
{
kb_hook = SetWindowsHookEx(WH_KEYBOARD, KeyboardProc, hDLL, NULL);
if(!kb_hook)
{
return false;
}
return true;
}
void unhook()
{
if(kb_hook)
{
UnhookWindowsHookEx(kb_hook);
}
}
string TestLoaded()
{
return test;
}
控制台应用程序来源:
#include <iostream>
#include <Windows.h>
#include <string>
#define DLLIMPORT __declspec(dllimport)
using namespace std;
DLLIMPORT void unhook();
DLLIMPORT bool installhook();
DLLIMPORT string TestLoaded();
int main()
{
cout << TestLoaded() <<endl;
installhook();
for(int i = 1; i<=10 ; i++)
{
//Do some keyboard activities in this 10 secs
Sleep(1000);
cout << i<<endl;
}
unhook();
cin.get();
return 1;
}
我的怀疑是,由于 dll 将被加载到进程自己的地址空间中的每个进程中,并且控制台不会出现在其他应用程序中,因此它会变得无效并崩溃。所以我删除了控制台输出并替换为消息框。那么也没什么区别。
可能是什么问题?
更新:
我尝试在全局尝试之前对特定线程进行本地挂钩。但我在 setwindowshookex 收到 Parameter is incorrect 错误 87。以下是更新后的代码:
dll:
bool installhook(DWORD ThreadId) //exporting this function
{
kb_hook = SetWindowsHookEx(WH_KEYBOARD, KeyboardProc, NULL, ThreadId); //tried with the dll module's handle also instead of NULL
if(!kb_hook)
{
printf("SetWindowsHookEx failed : %d\n", GetLastError());
return false;
}
return true;
}
控制台应用程序来源:
DWORD myThread()
{
cout<< "Thread started\n";
char str[250];
cin>>str;
return 0;
}
int main()
{
cout << TestLoaded() <<endl;
DWORD myThreadID;
HANDLE myHandle = CreateThread(0, 0, (LPTHREAD_START_ROUTINE)myThread, NULL, 0, &myThreadID);
installhook(myThreadID);
for(int i = 0; i<100 ; i++)
{
Sleep(100);
if(i%10 == 0)
{
cout << i<<endl;
}
}
unhook();
}
【问题讨论】:
-
不要像 MessageBox 那样做任何阻塞回调或导致递归的事情。您通常只是看不到 printf() 输出,使用 /MT 构建 DLL 也很重要,因此它可以获得自己的 CRT 副本并且不会意外使用注入程序使用的 CRT。您可以安全地写入日志文件。首先通过将注入限制在您自己的一个程序中进行测试。请注意,除非您创建两个 DLL 和注入器并拥有足够的权限,否则无法在 64 位操作系统上注入所有这些。
-
@HansPassant 我从 dll 中删除了所有控制台写入和消息框并更改为 /MT,仍然阻止其他应用程序接收键盘输入。我的是 64 位操作系统,DLL 是 32 位的。我将尝试将其专门注入到 32 位进程的单个线程中。
-
@HansPassant 请检查更新。尝试挂钩到单个线程时,Setwindowshookex 失败。
标签: c++ windows hook setwindowshookex