首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> .NET 實例教學

Windows 核心機制:利用 FS 暫存器獲取 KERNEL32.DLL 基址的三種演算法證明

     編輯:.NET 實例教學

背景知識:FS 暫存器與 TEB/PEB 結構

在 x86 Windows 使用者模式下,FS 暫存器指向當前執行緒的 TEB (Thread Environment Block)。TEB 偏移 0x30 指向 PEB (Process Environment Block)。這兩個結構是核心物件,記錄了進程與執行緒的關鍵資訊,也是 Shellcode 定位 KERNEL32.DLL 基址的核心依據。

TEB 關鍵偏移表

偏移名稱說明
0x00SEH Chain結構化例外處理鏈表頭
0x04Stack Top執行緒堆疊頂端
0x08Stack Bottom執行緒堆疊底端
0x18SelfFS 暫存器在記憶體中的鏡像地址(指向 TEB 自身)
0x30PEB指向進程 PEB 結構

PEB 關鍵偏移

  • 0x0C:Ldr — 指向 PEB_LDR_DATA 結構,管理載入模組鏈表。

演算法一:透過 PEB (FS:[0x30]) 遍歷模組鏈表

組合語言流程

mov eax, fs:[30h]      ; 取得 PEB 地址
mov eax, [eax + 0Ch]   ; 取得 PEB_LDR_DATA 地址
mov esi, [eax + 1Ch]   ; 取得 InInitializationOrderModuleList 連結頭
lodsd                  ; ESI 指向第一個 LDR_MODULE(通常為 ntdll.dll),EAX = 下一個結構地址
mov edx, [eax + 08h]   ; 取得 BaseAddress,即 KERNEL32.DLL 基址

實測驗證 (WinDbg)

0:000> dd fs:30 L1
003b:00000030  7ffd6000          ; PEB = 0x7ffd6000
0:000> dd 7ffd6000+0c L1
7ffd600c  00181ea0          ; PEB_LDR_DATA = 0x00181ea0
0:000> dd 00181ea0+1c L1
00181ebc  00181f58          ; InInitializationOrderModuleList = 0x00181f58
0:000> dd 00181f58+8 L1
00181f60  7c920000          ; BaseAddress = 0x7c920000 (此處為 ntdll.dll)
; 注意:在 Shellcode 環境中,第一個模組通常是 kernel32.dll,故直接取第一個即可。
; 實際 Shellcode 需遍歷鏈表比對模組名稱(Unicode),但受限於體積常假設順序固定。

演算法二:透過 TEB (FS:[0x18]) 掃描堆疊尋找 KERNEL32 返回位址

原理

TEB+0x04 指向堆疊頂。主執行緒啟動時,堆疊上殘留 KERNEL32!BaseProcessStart 或相關函數的返回位址,該位址落在 KERNEL32.DLL 映像範圍內。從該位址向下按 64KB 對齊掃描 MZ (0x5A4D) PE 標誌,即可定位基址。

組合語言流程

xor esi, esi
mov esi, fs:[esi + 0x18]  ; TEB
mov eax, [esi + 4]        ; Stack Top
mov eax, [eax - 0x1C]     ; 取得指向 KERNEL32 內部的返回位址
find_kernel32_base:
    dec eax
    xor ax, ax            ; 對齊 64KB 邊界
    cmp word ptr [eax], 0x5A4D  ; "MZ"
    jne find_kernel32_base
; EAX 即為 KERNEL32.DLL 基址

實測驗證

0:000> dd fs:18 L1
003b:00000018  7ffdd000          ; TEB
0:000> dd 7ffdd000+4 L1
7ffdd004  00070000          ; Stack Top
0:000> dd 00070000-1c L1
0006ffe4  7c839aa8          ; 指向 KERNEL32 內部位址
; 向下掃描...
0:000> db 7c800000 L4
7c800000  4d 5a 90 00       ; 找到 MZ 標誌,基址 = 0x7c800000

演算法三:透過 SEH (FS:[0x00]) 遍歷例外處理鏈表

原理

FS:[0] 指向當前 SEH 記錄鏈表頭。遍歷至最外層(Next = 0xFFFFFFFF)的 EXCEPTION_REGISTRATION,其 Handler 指向系統預設例外處理器(位於 KERNEL32.DLL)。同樣按 64KB 對齊向下掃描 MZ 標誌。

組合語言流程

xor ecx, ecx
mov esi, fs:[ecx]         ; SEH 头
find_seh:
    mov eax, [esi]        ; Next
    mov esi, eax
    cmp [eax], ecx        ; Next == 0xFFFFFFFF ?
    jns find_seh
mov eax, [eax + 4]        ; Handler (指向 KERNEL32 內部)
find_kernel32_base:
    dec eax
    xor ax, ax
    cmp word ptr [eax], 0x5A4D
    jne find_kernel32_base

實測驗證

0:000> dd fs:0 L1
003b:00000000  0006fedc          ; 第一層 SEH
; 遍歷兩次到達頂層...
0:000> dd 0006ffe0+4 L1
0006ffe4  7c839aa8          ; Handler 指向 KERNEL32 內部
; 向下掃描同演算法二,最終定位 0x7c800000

總結與啟示

  • 三種演算法均利用 FS 暫存器存取 TEB/PEB/SEH 這三個核心結構,本質上都是從已知的執行緒/進程狀態出發,定位到 KERNEL32.DLL 映像範圍內的某個位址,再透過 PE 標誌回溯基址。
  • PEB 法最直接、穩定,適合需列舉所有模組的場景;SEH/堆疊法體積極小(約 30-40 bytes),是 Shellcode 首選,但依賴特定執行環境(主執行緒、預設 SEH 結構),相容性稍弱。
  • 現代 Windows (ASLR、SafeSEH、CFG) 已大幅增加此類技術的利用難度,但在受限環境(舊版本、嵌入式、CTF)仍具參考價值。
  • 知其然,更要知其所以然:深入理解作業系統資料結構,是逆向工程與安全研究的基石。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved