第21章:Windows訊息鉤取
阿新 • • 發佈:2020-07-23
Windows向用戶提供GUI,以事件驅動的方式工作.
常規的Windows訊息流:
發生鍵盤輸入事件時,WM_KeyDown訊息被新增到OS訊息佇列.
OS判斷哪個應用程式發生了事件,然後從OS訊息佇列重取出訊息,新增到應用程式的訊息佇列中.
應用程式監視自身的訊息佇列,發現新新增的訊息後,呼叫相應的事件處理程式處理.
SetWindowsHookEx()可以實現訊息鉤取.
第一個引數是鉤子型別,例如可以為 WH_KeyBoard ,鍵盤鉤子.
第二個引數是鉤子過程,是由作業系統呼叫的回撥函式,說白了就是處理程式.
第三個引數是鉤子過程所屬的DLL控制代碼,因為鉤子過程需要存在於某個DLL內部
第四個引數代表想要影響的程序,若為0則影響所有程序.
可執行程式載入並安裝鉤子 -> 其它程序發生硬碟輸入事件 -> OS將Dll檔案載入到相應得程序記憶體 -> 呼叫回撥函式
重點看一下HookMain.exe檔案的原始碼.
#include "stdio.h" #include "conio.h" #include "windows.h" #define DEF_DLL_NAME "KeyHook.dll" #define DEF_HOOKSTART "HookStart" #define DEF_HOOKSTOP "HookStop" typedefvoid (*PFN_HOOKSTART)(); typedef void (*PFN_HOOKSTOP)(); //宣告一個返回值為NULL的函式指標 void main() { HMODULE hDll = NULL; PFN_HOOKSTART HookStart = NULL; //定義函式指標 PFN_HOOKSTOP HookStop = NULL; //函式指標賦值為NULL,避免成為野指標 char ch = 0; // 載入 KeyHook.dll hDll = LoadLibraryA(DEF_DLL_NAME);if( hDll == NULL ) { printf("LoadLibrary(%s) failed!!! [%d]", DEF_DLL_NAME, GetLastError()); return; } // 獲取匯出函式地址 HookStart = (PFN_HOOKSTART)GetProcAddress(hDll, DEF_HOOKSTART); // 將函式返回值轉換為自定義的型別 HookStop = (PFN_HOOKSTOP)GetProcAddress(hDll, DEF_HOOKSTOP); // 開始鉤取 HookStart();
printf("press 'q' to quit!\n"); while( _getch() != 'q' ) ; // 終止鉤取 HookStop(); // 解除安裝KeyHook.dll FreeLibrary(hDll); }
#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) //此處猜測是覆寫了KeyBoardProc()函式 { char szPath[MAX_PATH] = {0,}; char *p = NULL; if( nCode >= 0 ) { // bit 31 : 0 => press, 1 => release if( !(lParam & 0x80000000) ) { GetModuleFileNameA(NULL, szPath, MAX_PATH); p = strrchr(szPath, '\\'); //返回字串中從右側搜尋首次出現字元 \\ 的地址。 if( !_stricmp(p + 1, DEF_PROCESS_NAME) ) //字串相等時,返回值為0 return 1; //程式為notepad.exe時,直接返回1即不將鍵盤按鍵資料傳到應用程式 } } // 若當前程序名稱不是notepad.exe則呼叫 CallNextHookEx() 函式,將訊息傳遞給應用程式或下一個鉤子 return CallNextHookEx(g_hHook, nCode, wParam, lParam); } #ifdef __cplusplus extern "C" { #endif __declspec(dllexport) void HookStart() //declspec是針對編譯器的關鍵字,指出相應函式為匯出函式 { 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
安裝好鍵盤鉤子之後,無論哪個程序發生鍵盤輸入事件,OS會將KeyHook.dll注入到相應程序,而此程序發生鍵盤事件時也會首先呼叫執行KeyHook.KeyboardProc()
Printf()函式看著簡單,其實挺複雜的.