首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 組合語言

PE 檔案格式深度剖析:從 DOS Header 到 Import Table,以 4.exe 實戰追蹤

     編輯:組合語言

PE (Portable Executable) 結構總覽

PE 檔案 = DOS 相容區塊 + PE 標誌/頭部 + 區段表 + 區段資料。本文以系列教程 4.exe (主控台輸出範例) 為實例,結合 UltraEdit 十六進位檢視與 W32Dasm 反組譯,層層剖析。

四大區塊對應 (文中紅框標註)

  • Ⅰ - DOS Header / Stub:IMAGE_DOS_HEADER + DOS Stub 程式碼 (顯示 "This program cannot be run in DOS mode.")。
  • Ⅱ - .text Section:程式碼區段 (CODE / .text)。
  • Ⅲ - .rdata Section:唯讀資料區段,含匯入表 (IAT/Import Directory/Thunk)。
  • Ⅳ - .data Section:可讀寫資料區段 (全域變數、字串常數)。

逐層剖析 (對應 UltraEdit 偏移量)

1. IMAGE_DOS_HEADER (Offset 0x00)

IMAGE_DOS_HEADER STRUCT
    e_magic    WORD ?   ; "MZ" (0x5A4D)
    e_cblp     WORD ?
    ...
    e_lfanew   DWORD ?  ; **關鍵:PE Header 檔案偏移量**
IMAGE_DOS_HEADER ENDS

本例 e_lfanew = 0xB0 (Offset 0x3C 處),指向 PE Header 起始位置。

2. PE Header (Offset 0xB0)

IMAGE_NT_HEADERS STRUCT
    Signature      DWORD ?   ; "PE\0\0" (0x00004550)
    FileHeader     IMAGE_FILE_HEADER <>
    OptionalHeader IMAGE_OPTIONAL_HEADER32 <>
IMAGE_NT_HEADERS ENDS
  • Signature:50 45 00 00 ("PE\0\0")。
  • FileHeader (IMAGE_FILE_HEADER):Machine=0x14C (i386), NumberOfSections=3 (.text/.rdata/.data), Characteristics=0x10F (可執行、32-bit、行號/符號表移除)。
  • OptionalHeader (IMAGE_OPTIONAL_HEADER32):
    AddressOfEntryPoint=0x1000 (RVA, 程式入口點在 .text 區段內),
    ImageBase=0x00400000 (建議載入基址),
    SectionAlignment=0x1000 (記憶體對齊), FileAlignment=0x200 (檔案對齊),
    Subsystem=3 (IMAGE_SUBSYSTEM_WINDOWS_CUI 主控台),
    DataDirectory[16]:第 1 項 Export Table (0), 第 2 項 Import Table RVA=0x2000, Size=0x?? (指向 .rdata)。

3. 區段表 (Section Table, Offset 0xB0 + sizeof(NT_HEADERS) ≈ 0xF8)

IMAGE_SECTION_HEADER STRUCT
    Name            BYTE 8 dup(?)  ; ".text", ".rdata", ".data"
    VirtualSize     DWORD ?
    VirtualAddress  DWORD ?        ; RVA (相對虛擬位址)
    SizeOfRawData   DWORD ?        ; 檔案中大小 (FileAlignment 對齊)
    PointerToRawData DWORD ?       ; 檔案偏移
    Characteristics DWORD ?        ; 屬性旗標
IMAGE_SECTION_HEADER ENDS

本例三區段 (W32Dasm 驗證):

區段NameRVAFile OffsetRaw SizeFlags (特徵)
1.text0x10000x4000x2000x60000020 (CODE | EXECUTE | READ)
2.rdata0x20000x6000x2000x40000040 (INITIALIZED_DATA | READ)
3.data0x30000x8000x2000xC0000040 (INITIALIZED_DATA | READ | WRITE)

4. .text 區段 (Offset 0x400, RVA 0x1000) - 程式碼

W32Dasm 反組譯入口點 00401000 (ImageBase 0x400000 + RVA 0x1000):

:00401000 6800304000  push 00403000       ; 字串 "How are you !" 位址 (RVA 0x3000 -> VA 0x403000)
:00401005 E80E000000  call 00401018       ; 內部函式 (lstrlen 邏輯)
:0040100A 6A00        push 00000000
:0040100C E801000000  call 00401012       ; -> ExitProcess Thunk
:00401011 CC          int 3
:00401012 FF2508204000 jmp dword ptr [00402008] ; **IAT Thunk: ExitProcess**
:00401018 55          push ebp            ; lstrlen 開始
...
:00401088 FF2500204000 jmp dword ptr [00402000] ; **IAT Thunk: GetStdHandle**
:0040108E FF2504204000 jmp dword ptr [00402004] ; **IAT Thunk: WriteFile**

關鍵模式:所有外部 API 呼叫均為 CALL Near Thunk -> JMP [IAT_Entry]。載入器只需修補 IAT 表 (0x402000 區域),無需修改程式碼區段 (實現 Code Sharing / ASLR 友善)。

5. .rdata 區段 (Offset 0x600, RVA 0x2000) - 匯入表核心

包含三個關鍵結構陣列:

  1. IAT (Import Address Table):RVA 0x2000 (VA 0x402000)。儲存函式實際位址 (載入器填寫)。本例:
    00402000: GetStdHandle
    00402004: WriteFile
    00402008: ExitProcess
  2. Import Directory (IMAGE_IMPORT_DESCRIPTOR 陣列):每個 DLL 一項,結尾全 0。本例僅 1 個 DLL (KERNEL32) + 1 個終結項。
    關鍵欄位:
    OriginalFirstThunk (INT RVA) -> 指向 Hint/Name 表。
    FirstThunk (IAT RVA) -> 指向 IAT 表 (同上 0x2000)。
    Name RVA -> 指向 "KERNEL32.dll" 字串。
  3. Hint/Name Table (IMAGE_THUNK_DATA / IMAGE_IMPORT_BY_NAME):
    陣列項目 = 指向 IMAGE_IMPORT_BY_NAME 結構的 RVA。
    IMAGE_IMPORT_BY_NAME:Hint (WORD) + Name (ASCIIZ)。
    例:Hint=0x13D, Name="GetStdHandle", Hint=0x2B9, Name="WriteFile", Hint=0x75, Name="ExitProcess"。
    陣列以 0 結束。

6. .data 區段 (Offset 0x800, RVA 0x3000) - 字串資料

Offset 0x800 (VA 0x403000): "How are you !", 0

核心結構體定義彙總 (來自 windows.inc)

IMAGE_DOS_HEADER STRUCT ... e_lfanew DWORD ? ENDS
IMAGE_NT_HEADERS STRUCT Signature DWORD ?, FileHeader IMAGE_FILE_HEADER <>, OptionalHeader IMAGE_OPTIONAL_HEADER32 <> ENDS
IMAGE_FILE_HEADER STRUCT Machine WORD ?, NumberOfSections WORD ?, TimeDateStamp DWORD ?, PointerToSymbolTable DWORD ?, NumberOfSymbols DWORD ?, SizeOfOptionalHeader WORD ?, Characteristics WORD ? ENDS
IMAGE_OPTIONAL_HEADER32 STRUCT ... ImageBase DWORD ?, SectionAlignment DWORD ?, FileAlignment DWORD ?, Subsystem WORD ?, DllCharacteristics WORD ?, SizeOfStackReserve DWORD ?, SizeOfStackCommit DWORD ?, SizeOfHeapReserve DWORD ?, SizeOfHeapCommit DWORD ?, LoaderFlags DWORD ?, NumberOfRvaAndSizes DWORD ?, DataDirectory IMAGE_DATA_DIRECTORY 16 dup(<>) ENDS
IMAGE_DATA_DIRECTORY STRUCT VirtualAddress DWORD ?, Size DWORD ? ENDS
IMAGE_SECTION_HEADER STRUCT Name BYTE 8 dup(?), VirtualSize DWORD ?, VirtualAddress DWORD ?, SizeOfRawData DWORD ?, PointerToRawData DWORD ?, PointerToRelocations DWORD ?, PointerToLinenumbers DWORD ?, NumberOfRelocations WORD ?, NumberOfLinenumbers WORD ?, Characteristics DWORD ? ENDS
IMAGE_IMPORT_DESCRIPTOR STRUCT OriginalFirstThunk DWORD ?, TimeDateStamp DWORD ?, ForwarderChain DWORD ?, Name DWORD ?, FirstThunk DWORD ? ENDS
IMAGE_IMPORT_BY_NAME STRUCT Hint WORD ?, Name BYTE ? ENDS
IMAGE_THUNK_DATA32 STRUCT union ForwarderString DWORD ?, Function DWORD ?, Ordinal DWORD ?, AddressOfData DWORD ? ends ENDS

載入器處理匯入表流程 (簡述)

  1. 讀取 DataDirectory[1] (Import Table RVA) 定位 Import Directory 陣列。
  2. 遍歷每個 IMAGE_IMPORT_DESCRIPTOR:
    a. LoadLibrary(Name) 載入 DLL。
    b. 遍歷 OriginalFirstThunk (INT) 指向的 Hint/Name 陣列。
    c. 對每個函式:GetProcAddress(hDll, Name) (或按 Ordinal)。
    d. 將返回位址寫入 FirstThunk (IAT) 對應項目。
  3. 完成後,程式碼區段的 CALL Thunk -> JMP [IAT] 即可正確跳轉。

實戰工具驗證

  • W32Dasm:快速查看區段、匯入函式、反組譯碼、Thunk 跳轉關係。
  • UltraEdit / HxD / 010 Editor:十六進位檢視原始結構,驗證 e_lfanew、區段表、IAT 實際內容。
  • LordPE / CFF Explorer:專業 PE 編輯器,視覺化結構、修補、重建 IAT、去殼分析。

緩衝區溢位/惡意代碼視角提示

理解 PE 結構是:

  • 加殼/脫殼:修改 Entry Point、區段屬性、重建 IAT。
  • Hooking/Detours:修改 IAT 表項目導向自訂函式。
  • Shellcode:手動解析 PEB->Ldr->InMemoryOrderModuleList 找 Kernel32 基址,遍歷其 Export Table 找 LoadLibrary/GetProcAddress,進而動態解析任意 API。

本文基於 Win9x/早期 Win32 時代教程 (4.exe 為主控台程式,ImageBase 0x400000,無 ASLR/DEP/SEH/Guard CF)。現代 PE (Win10/11) 引入 ASLR (動態基址)、DEP (NX)、CFG (Control Flow Guard)、簽名強制、最小化 IAT 等防護,分析思路同但細節更複雜。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved