程式 A 安裝 WH_GETMESSAGE 全域 Hook,Hook 函式在 B.dll。當其他程式呼叫 GetMessage,系統檢測到 Hook,若目標進程未載入 B.dll,呼叫 LoadLibrary 強制載入。此機制導致 Hook DLL 注入所有呼叫 GetMessage 的進程。
kernel32.dll;Hook DLL 載入來自 user32.dll(XP 驗證,新版本類似)。LoadLibraryExW,檢查呼叫者回傳位址是否落在 user32.dll 模組範圍內。NULL 模擬載入失敗,阻止 Hook 注入。
HMODULE WINAPI NewLoadLibraryExW(LPCWSTR lpLibFileName, HANDLE hFile, DWORD dwFlags) {
DWORD dwCaller;
__asm {
push dword ptr [ebp+4] // 取得回傳位址
pop dword ptr [dwCaller]
}
if (dwCaller > g_dwUser32Base && dwCaller < g_dwUser32End) {
// 來自 user32.dll → Hook DLL 載入
return NULL; // 阻止
}
return RealLoadLibraryExW(lpLibFileName, hFile, dwFlags); // 正常載入
}
LoadLibraryExW 前 7 位元組(兩條指令)到 FakeLoadLibraryExW。FakeLoadLibraryExW 末尾加 JMP 回原函式第 8 位元組處。
// 修改 LoadLibraryExW 前 5 位元組為 JMP NewLoadLibraryExW
// 並將原始函式指標指向 FakeLoadLibraryExW
class GBlockHookDll {
public:
GBlockHookDll() {
MODULEINFO mi = {0};
GetModuleInformation(GetCurrentProcess(), GetModuleHandle("user32.dll"), &mi, sizeof(mi));
m_dwUser32Low = (DWORD)mi.lpBaseOfDll;
m_dwUser32Hi = m_dwUser32Low + mi.SizeOfImage;
}
void PatchLoadLibrary() {
LPVOID* pRaw = (LPVOID*)&RealLoadLibraryExW;
LPVOID pNew = (LPVOID)NewLoadLibraryExW;
BYTE* pRawCode = (BYTE*)*pRaw;
// 1. 備份前 7 位元組到 Fake
const int N = 7;
memcpy(FakeLoadLibraryExW, *pRaw, N);
FakeLoadLibraryExW[N] = 0xE9; // JMP
*(DWORD*)(FakeLoadLibraryExW + N + 1) = (DWORD)(pRawCode + N) - (DWORD)(FakeLoadLibraryExW + N + 5);
// 2. 修改原始函式入口 JMP 到 New
DWORD oldProtect;
VirtualProtect(pRawCode, N, PAGE_READWRITE, &oldProtect);
pRawCode[0] = 0xE9;
*(DWORD*)(pRawCode + 1) = (DWORD)pNew - (DWORD)(pRawCode + 5);
VirtualProtect(pRawCode, N, oldProtect, &oldProtect);
// 3. 更新函式指標
*pRaw = FakeLoadLibraryExW;
}
private:
static HMODULE WINAPI NewLoadLibraryExW(LPCWSTR, HANDLE, DWORD);
static DWORD m_dwUser32Low, m_dwUser32Hi;
static BYTE FakeLoadLibraryExW[12];
static HMODULE (WINAPI *RealLoadLibraryExW)(LPCWSTR, HANDLE, DWORD);
};
// 靜態成員定義
DWORD GBlockHookDll::m_dwUser32Low = 0;
DWORD GBlockHookDll::m_dwUser32Hi = 0;
BYTE GBlockHookDll::FakeLoadLibraryExW[12] = {0};
HMODULE (WINAPI *GBlockHookDll::RealLoadLibraryExW)(LPCWSTR, HANDLE, DWORD) = LoadLibraryExW;
GBlockHookDll g_Blocker; // 全域物件
// 在初始化階段 (如 CWinApp::InitInstance) 呼叫
g_Blocker.PatchLoadLibrary();
push ebp / mov ebp, esp 後,[ebp+4] 為回傳位址。VirtualProtect 修改代碼段屬性為可寫。LoadLibraryExW,32 位元環境;64 位元需調整指令編碼與呼叫慣例。LdrLoadDll 或手動映射 DLL。透過 Inline Hook LoadLibraryExW、回傳位址溯源識別 user32.dll 發起的載入請求,可有效阻止全域 Hook DLL 強制注入。此技術展示 Windows 使用者模式 Hook 防禦的核心思路,實戰中建議結合簽名驗證、完整性檢查等多層防護。