Hook(鉤子)是 Windows 消息機制的擴展,允許將自定義 DLL 注入目標進程地址空間,攔截並處理特定消息。本文演示如何編寫一個 WH_MOUSE 鉤子 DLL,注入 MSN Messenger 聊天窗口,獲取鼠標點擊位置及窗口文本。
使用 #pragma data_seg("Shared") 與 #pragma comment(linker,"/section:Shared,rws") 建立跨進程共享內存區:
#pragma data_seg("Shared")
HHOOK g_hhook = NULL;
DWORD g_dwThreadIdMsn = 0;
POINT MouseLoc = {0,0};
char text[256] = {0};
HWND g_Hwnd = NULL;
#pragma data_seg()
SetMsnHook(DWORD dwThreadId):安裝鉤子,調用 SetWindowsHookEx(WH_MOUSE, GetMsgProc, g_hinstDll, dwThreadId)。GetText(int &x, int &y, char **ptext):讀取共享區的鼠標座標與文本。GetMyHwnd():返回當前鉤住的窗口句柄。LRESULT WINAPI GetMsgProc(int nCode, WPARAM wParam, LPARAM lParam) {
if (nCode == HC_ACTION) {
MOUSEHOOKSTRUCT *l = (MOUSEHOOKSTRUCT*)lParam;
MouseLoc = l->pt;
HWND hWnd = WindowFromPoint(l->pt);
if (hWnd) {
SendMessage(hWnd, WM_GETTEXT, 256, (LPARAM)text);
SendMessage(hWnd, WM_SETTEXT, 256, (LPARAM)text); // 演示修改文本
g_Hwnd = hWnd;
}
}
return CallNextHookEx(g_hhook, nCode, wParam, lParam);
}
#pragma comment(lib,"MSNHook.lib")) 並聲明導出函數。CWnd *pMsnWin = FindWindow(TEXT("IMWindowClass"), NULL); // MSN 聊天窗口類名
if (pMsnWin) {
DWORD dwThreadId = GetWindowThreadProcessId(pMsnWin->GetSafeHwnd(), NULL);
SetMsnHook(dwThreadId);
SetTimer(101, 100, NULL); // 100ms 輪詢共享數據
}
GetText 獲取座標與文本,更新界面;調用 GetMyHwnd 獲取窗口文本再次驗證。SetMsnHook(0) 觸發 DLL 內 UnhookWindowsHookEx。SetWindowsHookEx 最後參數傳目標線程 ID,實現精準注入,避免全系統鉤子的性能開銷。Interlocked 或互斥量)。IMWindowClass,版本升級可能變化,需做兼容處理。WM_GETTEXT 無法直接獲取富文本編輯區輸入內容,需結合 UI Automation 或內存掃描進一步研究。