本專案展示如何利用 Windows 全域 Hook 機制,構建一套常駐後台的程式執行審計與封鎖系統。核心功能包含:
SetWindowsHookEx(WH_SHELL, ...) 安裝全域 Shell Hook。當任何進程建立或銷毀主視窗 (Top-level Window) 時,系統會呼叫 Hook 回呼函式 HookedShellProc,傳遞 HSHELL_WINDOWCREATED / HSHELL_WINDOWDESTROYED 通知碼及視窗句柄 (wParam)。
這正是 Windows 工作列「按鈕」更新的底層機制——我們攔截它,即可實現自訂的視窗歷史記錄或干預。
全域 Hook 回呼函式**必須**位於 DLL 中,因為系統需將該 DLL 注入所有目標進程的位址空間執行。EXE 無法被其他進程載入。本專案結構:
hwhpdrv.dll:包含 Hook 回呼、共享資料結構定義、安裝/移除 Hook 匯出函式。hwhpapp.exe:主控程式,負責 UI、日誌寫入、黑名單比對、載入 DLL 並觸發安裝 Hook。Hook 回呼執行於**目標進程**內容中,無法存取主程式 (EXE) 的全域變數。解決方案:CreateFileMapping(INVALID_HANDLE_VALUE, ...) 建立「具名共享記憶體」,映射至所有進程虛擬位址空間同一邏輯位址。專案採用 Victor VCL 元件庫的 TSharedMemory 封裝,共享結構包含:
hHook):供 CallNextHookEx 使用。hMainForm):Hook 透過 PostMessage 將事件轉發給主程式處理 (寫日誌、比對黑名單)。啟動極早期 (WinMain 入口) 檢查共享記憶體是否已存在:
if (AppMem.Exists) { // 已有實例在跑
if (stricmp(lpCmdLine, "/SHOW") == 0)
PostMessage(AppMem.AppInfo->hMainForm, WM_USERCMD, UC_SHOWWIN, 0);
return 0; // 直接退出
}
支援命令列參數 /SHOW 喚醒已隱藏主視窗。
在 Application->Run() 前設定擴充視窗樣式:
SetWindowLong(Application->Handle, GWL_EXSTYLE,
GetWindowLong(Application->Handle, GWL_EXSTYLE) | WS_EX_TOOLWINDOW);
WS_EX_TOOLWINDOW 讓視窗不顯示在工作列、Alt+Tab 切換清單、甚至工作管理員的「應用程式」分頁中。
hwhpapp.sys (偽裝系統檔,實為文字)。hwhpapp.cfg (記事本可編輯),格式支援 CLASS=視窗類別名 或 CAPTION=視窗標題。HookedShellProc 收到 HSHELL_WINDOWCREATED。hMainWnd。PostMessage(hMainWnd, WM_USERCMD, UC_WINHOOK, hNewWnd) 非同步通知主程式。WndProc 接收,呼叫 WinHookMessage:GetWindowText/GetClassName 取得資訊。.sys 日誌。ValidAppCheck 掃描 .cfg 黑名單,命中則 PostMessage(hwnd, WM_CLOSE, 0, 0) 關閉視窗並記錄「(關閉禁用程式)」。CallNextHookEx 傳遞給下一個 Hook。void WINAPI THookedProcs::InitFuncs(void) {
UninitFuncs();
hThisHook = SetWindowsHookEx(WH_SHELL, (HOOKPROC)HookedShellProc, HInstance, 0);
TSharedMemory AppMem(MYAPPMARK, 4096);
THookSharedData *HookSharedData = (THookSharedData*)(AppMem.AppInfo->Data);
HookSharedData->hHook = hThisHook; // 關鍵:將 Hook 句柄存入共享區供 CallNextHookEx 使用
}
void __fastcall TFormMain::WinHookMessage(long Param) {
HWND hWnd = (HWND)Param;
char szClass[256], szCaption[256];
GetClassName(hWnd, szClass, 256);
GetWindowText(hWnd, szCaption, 256);
AnsiString log = FormatDateTime("yyyy-mm-dd hh:nn:ss ", Now()) +
"\"" + szClass + "\" -> \"" + szCaption + "\"";
if (!ValidAppCheck(hWnd, szClass, szCaption))
log += " (關閉禁用程式)";
log += "\r\n";
TBinFileFuncs::WriteLogFileInfo(TRelPath().Extension("sys").c_str(), log.c_str());
}
bool __fastcall TFormMain::ValidAppCheck(HWND hwnd, char *cls, char *cap) {
// 讀取 .cfg,逐行比對 CLASS= 或 CAPTION=,命中即 PostMessage(WM_CLOSE) 並回傳 false
}
| 檔案 | 說明 |
|---|---|
| hwhpapp.exe | 主程式,需放入啟動項 HKLM\...\Run |
| hwhpdrv.dll | Hook DLL,與 EXE 同目錄 |
| hwhpapp.cfg | 黑名單設定,文字編輯即可 |
| hwhpapp.sys | 自動產生日誌,記事本可讀 |
此技術屬系統級監控,具備攔截、記錄所有視窗程式的能力。開發類似工具時,請嚴格遵守:
/SHOW 顯示介面關閉)。WH_KEYBOARD_LL/WH_MOUSE_LL 實現鍵盤/滑鼠記錄器 (需簽署驅動程式或 UAC 提權)。AppInit_DLLs 或驅動程式實現更早期、更難移除的注入。