C++鉤子技術,攔截帶有某些關鍵字的窗體
這次想寫一篇,自己曾經做過的一個Hook程式,溫故而知新。
作為一個C++程式設計師,肯定對鉤子(Hook)技術有所瞭解:訊息鉤子,API鉤子。
基本概念:
鉤子(Hook),是Windows訊息處理機制的一個平臺,應用程式可以在上面設定子程以監視指定視窗的某種訊息,而且所監視的視窗可以是其他程序所建立的。當訊息到達後,在目標視窗處理函式之前處理它。鉤子機制允許應用程式截獲處理window訊息或特定事件。
鉤子實際上是一個處理訊息的程式段,通過系統呼叫,把它掛入系統。每當特定的訊息發出,在沒有到達目的視窗前,鉤子程式就先捕獲該訊息,亦即鉤子函式先得到控制權。這時鉤子函式即可以加工處理(改變)該訊息,也可以不作處理而繼續傳遞該訊息,還可以強制結束訊息的傳遞。
對於標題所描述的攔截帶有某些關鍵字窗體,基本思路是:我們需要建立一個全域性鉤子,然後捕獲到窗體顯示訊息,捕獲到後利用Windows訊息機制,丟擲去到外層獲取視窗標題,當匹配關鍵字時,給對應視窗傳送關閉訊息。
對於建立全域性鉤子,我們需要採用DLL注入的方式,Hook的DLL工程主程式碼如下:
#include <Windows.h> #pragma data_seg("HookWnd") HHOOK g_HookWnd = NULL; //鉤子控制代碼 HWND g_DestWnd = NULL; //目的視窗控制代碼,就是截獲的訊息要發往什麼視窗 HINSTANCE g_hInst = NULL; #pragma data_seg() #pragma comment( linker, "/section:HookWnd,RWS" ) __declspec(dllexport) BOOL SetHook(HWND hWnd); __declspec(dllexport) void DestroyHook(); #define WM_MYMESSAGE (WM_USER + 1) BOOL WINAPI DllMain(HINSTANCE hinstDll, DWORD fdwReason, LPVOID lpvReserved) { g_hInst = hinstDll;//儲存應用程式例項 return TRUE; } LRESULT CALLBACK MyWndProc(int nCode, WPARAM wParam, LPARAM lParam) { CWPSTRUCT *pCwp = reinterpret_cast<CWPSTRUCT*>(lParam); if (pCwp->message == WM_SHOWWINDOW) { ::SendMessage(g_DestWnd, WM_MYMESSAGE, wParam, reinterpret_cast<LPARAM>(pCwp->hwnd)); return 0; } else return CallNextHookEx(g_HookWnd, nCode, wParam, lParam); } BOOL SetHook(HWND hWnd) { if (NULL == hWnd) return FALSE; g_DestWnd = hWnd; //第三個引數還可通過些方法獲得:GetModuleHandle("HookTest.dll") return (NULL != (g_HookWnd = ::SetWindowsHookEx(WH_CALLWNDPROC, MyWndProc, g_hInst, 0))); } void DestroyHook() { if (NULL != g_HookWnd) { UnhookWindowsHookEx(g_HookWnd); g_DestWnd = NULL; } }
SetWindowsHookEx(WH_CALLWNDPROC, MyWndProc, g_hInst, 0));最後一個引數0,代表建立的是全域性鉤子。
WH_CALLWNDPROC裝載的是:視窗鉤子,當系統向目標視窗傳送訊息時將觸發此鉤子 進入到MyWndProc回撥函式處理;
當回撥函式裡面捕獲到:WM_SHOWWINDOW訊息,傳送訊息到外層處理;
外層訊息處理函式為:
LRESULT CHookTestDlg::OnMyMessage( WPARAM wParam, LPARAM lParam ) { HWND hwnd = reinterpret_cast<HWND>(lParam); UINT nTitleLen = ::GetWindowTextLength(hwnd); TCHAR *pStr = new TCHAR[nTitleLen + 1](); ZeroMemory(pStr, nTitleLen + 1); ::GetWindowText(hwnd, pStr, nTitleLen + 1); CString str(pStr); delete []pStr; if (str.Find(m_str) != -1) //CString查詢字串未找到返回-1 { ::SendMessage(hwnd, WM_CLOSE, NULL, NULL); return 1; } return 0; }
獲取對應視窗控制代碼的視窗標題,和設定的關鍵字匹配,當滿足條件則傳送關閉訊息;
外層呼叫Hook的DLL函式例項:
HINSTANCE hIst = NULL;
// 建立全域性鉤子,監控所有程序
void CHookTestDlg::OnCreateDllHook()
{
m_edit.GetWindowText(m_str);
m_edit.EnableWindow(FALSE);
hIst = ::LoadLibrary("..\\HookTest\\HookDll.dll"); // 載入dll
if (NULL != hIst)
{
typedef BOOL (*pFunSetHook)(HWND);
pFunSetHook pSetHook = (pFunSetHook)GetProcAddress(hIst, "SetHook");
if (NULL != pSetHook)
{
if(pSetHook(m_hWnd))
AfxMessageBox("建立全域性鉤子成功...");
}
}
}
//解除安裝全域性鉤子
void CHookTestDlg::OnDestroyDllHook()
{
if (NULL != hIst)
{
typedef void (*pFunDestroyHook)();
pFunDestroyHook pDestryHook = (pFunDestroyHook)GetProcAddress(hIst, "DestroyHook");
if (NULL != pDestryHook)
{
pDestryHook();
::FreeLibrary(hIst);
hIst = NULL;
AfxMessageBox("銷燬全域性鉤子成功!");
}
}
m_edit.EnableWindow(TRUE);
}
.........
至此,一個簡單的攔截視窗程式,已經實現。