有趣——windows键盘消息截获
理解下windows的消息机制:
1.发生键盘输入事件时,WM_KEYDOWN消息被添加到操作系统消息队列
2.OS判断哪个APP发生了事件,然后从系统消息队列取出消息分发到应用程序消息队列
3.APP监视自身的消息队列,发现新的消息,调用相应的事件处理程序
在OS消息队列和APP消息队列之间存在一条钩链,处于钩链之中的钩子比APP消息队列先看到相应信息
API函数SetWindowsHookEx()可实现消息钩取,钩子过程是由OS调用的回调函数,安装“钩子”时,“钩子”过程需要存在某个DLL内部
安装好钩子后,某个进程生成指定消息时,OS会将相应DLL强制注入进程中,然后调用“钩子”过程
dll源码
#include<stdio.h> #include<Windows.h> #define DEF_PROCESS_NAME "notepad++.exe" HINSTANCE g_hInstance = NULL; HHOOK g_hHook = NULL; HWND g_hWnd = NULL; BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD dwReason, LPVOID lpvReserved) { switch (dwReason) { case DLL_PROCESS_ATTACH: g_hInstance = hinstDLL; break; case DLL_PROCESS_DETACH: break; } return true; } LRESULT CALLBACK KeyboardProc(int nCode, WPARAM wParam, LPARAM lParam) { char szPath[MAX_PATH] = { 0, }; char* p = NULL; if (nCode=0) { if (!(lParam & 0x80000000)) { GetModuleFileNameA(NULL, szPath, MAX_PATH); p = strrchr(szPath, \); } if (!_stricmp(p + 1, DEF_PROCESS_NAME)) return 1; } return 1;//CallNextHookEx(g_hHook, nCode, wParam, lParam); } #ifdef __cplusplus extern "C" { #endif __declspec(dllexport) void HookStart() { g_hHook = SetWindowsHookEx(WH_KEYBOARD, KeyboardProc, g_hInstance, 0); } __declspec(dllexport) void HookStop() { if (g_hHook) { UnhookWindowsHookEx(g_hHook); g_hHook = NULL; } } #ifdef __cplusplus } #endif
主程序源码
#include<stdio.h> #include<conio.h> #include<Windows.h> #define DEF_DLL_NAME "KeyHookDLL.dll" #define DEF_HOOKSTART "HookStart" #define DEF_HOOKSTOP "HookStop" typedef void(*PFN_HOOKSTART)(); typedef void(*PFN_HOOKSTOP)(); int main() { HMODULE hDLL = NULL; PFN_HOOKSTART HookStart = NULL; PFN_HOOKSTOP HookStop = NULL; char ch = 0; hDLL = LoadLibraryA(DEF_DLL_NAME); //获取导出函数地址 HookStart = (PFN_HOOKSTART)GetProcAddress(hDLL, DEF_HOOKSTART); HookStop = (PFN_HOOKSTOP)GetProcAddress(hDLL, DEF_HOOKSTOP); HookStart(); printf("press q to quit! "); while (getchar() != q); HookStop(); FreeLibrary(hDLL); }
windows7下亲测通过,钩子为全局钩子,所有程序都无法接收键盘消息
下一篇:
Redis哨兵模式原理剖析,监控、选主