如何使用SetWindowsHookEx过滤低级别的键事件?

时间:2013-07-06 11:27:59

标签: c windows hook keylogger

我有这个代码为低级事件设置键盘钩子,然后显示一个消息框。

HHOOK keyboardHook = SetWindowsHookEx (WH_KEYBOARD_LL, HookKey, hInstance, 0);

MessageBox(NULL, L"Click to exit", L"hook test", NULL);

UnhookWindowsHookEx(keyboardHook);

如何在不创建前景窗口的情况下运行应用程序的主循环,如何设置hInstance来捕获全局事件?

2 个答案:

答案 0 :(得分:3)

答案全部包含在the MSDN docs page for SetWindowsHookEx中。要试验示例应用程序,请创建一个新解决方案,添加两个项目,一个控制台应用程序和一个DLL。每个项目只需要一个文件。 DLL将包含钩子,控制台应用程序将安装钩子。

钩子的代码必须存在于DLL中,因为MSDN文档非常明确地说:“如果 dwThreadId 参数为零或指定由不同进程创建的线程的标识符, lpfn 参数必须指向DLL中的钩子过程。“实际上,钩子显然必须在DLL中,或者shell如何在另一个应用程序的消息循环中运行代码? DLL使用其HINSTANCE安装钩子来识别函数指针所在的位置。

主应用程序运行启动挂钩并泵送消息,再次按照MSDN文档中的说明操作:“......挂钩应用程序必须继续泵送消息,否则可能会阻止64位进程的正常运行。“

请注意,这是一个非常小众的应用程序 - 几乎不需要像这样注入DLL。拜托,请三思而后行。对于许多应用程序,没有必要捕获低级别事件,尽管抑制“开始”菜单的沉浸式应用程序是合理的用例。更重要的是,您很少需要捕获发送到其他应用程序的输入。在使用此代码之前检查您确实需要这样做。例如,只需将输入挂钩到您自己的应用程序窗口即可完成录制宏。

的main.cpp

#include <windows.h>
#include <tchar.h>

__declspec(dllimport) void (__stdcall runHook)(BOOL startOrStop);
__declspec(dllimport) LRESULT (CALLBACK hookProc)(int code, WPARAM wParam, LPARAM lParam);

int _tmain(int argc, _TCHAR* argv[])
{
  runHook(true);
  MSG Msg;
  while(GetMessage(&Msg, NULL, 0, 0) > 0 && Msg.message != WM_QUIT) {
    TranslateMessage(&Msg);
    DispatchMessage(&Msg);
  }
  runHook(false);
  return 0;
}

Dll.cpp

#include <assert.h>
#include <windows.h>

static HINSTANCE dllInst = 0;
static HHOOK hookSelf = 0;

BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
                     )
{
  dllInst = (HINSTANCE)dllInst;
  return TRUE;
}

__declspec(dllexport) LRESULT (CALLBACK hookProc)(int code, WPARAM wParam, LPARAM lParam)
{
  if (code >= 0) {
    UINT msgType = wParam;
    KBDLLHOOKSTRUCT* msgInfo = (KBDLLHOOKSTRUCT*)lParam;
    // The msgInfo contains the VK_CODE and flags.
  }  
  return hookSelf ? CallNextHookEx(hookSelf, code, wParam, lParam) : 0;
}

__declspec(dllexport) void (__stdcall runHook)(BOOL startOrStop)
{
  assert((bool)hookSelf != (bool)startOrStop);
  if (startOrStop)
    hookSelf = SetWindowsHookEx(WH_KEYBOARD_LL, hookProc, dllInst, 0);
  else {
    UnhookWindowsHookEx(hookSelf);
    hookSelf = 0;
  }
}

答案 1 :(得分:1)

执行此操作的一种方法是在Windows上创建TSR(Terminate and Stay Resident)程序。

在Windows上,典型的TSR程序包含以下组件:

  • 创建并隐藏主窗口。
  • 注册热键。
  • 循环测试事件。
  • 响应热键的功能。
  • 定时器定期调用的函数。

这是一个很好的 article ,包含代码片段和有关在Windows上编写TSR的详细说明。