VC8 引入 /GS (Buffer Security Check) 編譯選項,在函數序言/結語插入 Security Cookie 機制,於運行時偵測堆疊緩衝區溢位導致的返回位址/框架指標竄改。本文從組合語言層面完整還原 Cookie 生成、植入、驗證流程,並展示 `__security_check_cookie` 內部實作。
高位址 +------------------+ | 函數參數 | +------------------+ | 返回位址 (RET) | ← 攻擊目標:覆蓋控制流 +------------------+ | 儲存的 EBP | ← 攻擊目標:破壞堆疊幀鏈 +------------------+ | Security Cookie | ← /GS 插入的金絲雀值 +------------------+ | 區域變數/緩衝區 | ← 溢位來源 +------------------+ 低位址
Cookie 置於 區域變數與舊 EBP 之間,溢位寫入必須先覆蓋 Cookie 才能觸及 EBP/RET。
// gs_cookie.c
#ifdef _WIN64
#define DEFAULT_SECURITY_COOKIE 0x00002B992DDFA232
#else
#define DEFAULT_SECURITY_COOKIE 0xBB40E64E
#endif
DECLSPEC_SELECTANY UINT_PTR __security_cookie = DEFAULT_SECURITY_COOKIE;
DECLSPEC_SELECTANY UINT_PTR __security_cookie_complement = ~DEFAULT_SECURITY_COOKIE;
在 `mainCRTStartup` → `__security_init_cookie()` 中執行:
void __cdecl __security_init_cookie() {
UINT_PTR cookie;
FILETIME systime;
LARGE_INTEGER perfctr;
GetSystemTimeAsFileTime(&systime);
cookie = systime.dwLowDateTime;
cookie ^= systime.dwHighDateTime;
cookie ^= GetCurrentProcessId();
cookie ^= GetCurrentThreadId();
cookie ^= GetTickCount();
QueryPerformanceCounter(&perfctr);
cookie ^= perfctr.LowPart;
cookie ^= perfctr.HighPart;
__security_cookie = cookie;
__security_cookie_complement = ~cookie;
}
綜合系統時間、進程/執行緒 ID、TickCount、高效能計數器多重熵源,確保每次執行 Cookie 值不可預測。
反組譯範例 (Debug 模式):
main:
push ebp
mov ebp, esp
sub esp, 0E0h
; ... 省略暫存器保存 ...
mov eax, dword ptr [__security_cookie] ; 取得全域 Cookie
xor eax, ebp ; 與 EBP 異或
mov dword ptr [ebp-4], eax ; 存入 [EBP-4] (Cookie 變數)
異或 EBP 的雙重目的:
; ... 函數本體結束 ...
mov ecx, dword ptr [ebp-4] ; 取出 Cookie 變數
xor ecx, ebp ; 還原原始 Cookie
call @__security_check_cookie@4 ; 快速呼叫慣例,參數在 ECX
; ... 恢復堆疊、返回 ...
// secchk.c (Intel 目錄)
void __declspec(naked) __fastcall __security_check_cookie(UINT_PTR cookie) {
__asm {
cmp ecx, __security_cookie ; 比較還原值與全域 Cookie
jne failure ; 不等 → 跳轉失敗處理
rep ret ; REP 防 AMD 分支預測罰分
failure:
jmp __report_gsfailure ; 回報緩衝區溢位失敗
}
}
__fastcall:唯一參數放 `ECX`,無堆疊操作極致高效。naked:編譯器不產生序言/結語,完全手工控制。終止進程、呼叫錯誤回報機制 (WER)、可選擇啟動偵錯器。細節留待後續文章探討。
中斷點停下時,在「即時運算視窗」輸入 `__security_cookie` 即可查看當前進程的全域 Cookie 值。
本文為逆向工程視角剖析 VC8 /GS 機制,歡迎指正補充。