iT邦幫忙

0

231解剖室:PE File Format - Part 2 真頭部

  • 分享至 

  • xImage
  •  

NT Headers


◀️ Previously

上一篇分析了DOS Header / DOS Stub / Rich Header
雖然很有趣,但這些區塊在當前Windows系統上不是特別重要
在這篇文章中,我們會開始切入正題,展開NT Headers,了解它的構造


📜 Overview

NT Headers是PE檔案相當重要的一個區塊,PE loader會根據這個區段提供的資訊來載入並執行程式

官方文件提供的架構,我們可以知道NT Headers主要分成三個部分:

// 32 bits
typedef struct _IMAGE_NT_HEADERS {
  DWORD                   Signature;
  IMAGE_FILE_HEADER       FileHeader;
  IMAGE_OPTIONAL_HEADER32 OptionalHeader;
} IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32;

而因為Optional Header的關係,所以有32以及64位元兩種定義

// 64 bits
typedef struct _IMAGE_NT_HEADERS64 {
    DWORD Signature;
    IMAGE_FILE_HEADER FileHeader;
    IMAGE_OPTIONAL_HEADER64 OptionalHeader;
} IMAGE_NT_HEADERS64, *PIMAGE_NT_HEADERS64;

系統會根據_WIN64是否有被定義來決定要使用哪種架構

底下會依序介紹各個部分的組成成員以及這些成員所提供的資訊


✍️ Signature

首先是Signature
是一個長度為4 bytes的data,用來辨識這是一個PE執行檔

https://ithelp.ithome.com.tw/upload/images/20230122/20156936WBpbgUx5Be.png


🤖 File Header

其次是File Header
這是他的資料結構

typedef struct _IMAGE_FILE_HEADER {
  WORD  Machine;
  WORD  NumberOfSections;
  DWORD TimeDateStamp;
  DWORD PointerToSymbolTable;
  DWORD NumberOfSymbols;
  WORD  SizeOfOptionalHeader;
  WORD  Characteristics;
} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;

> Structure

把它整理成一個表格

名稱 功用 備註
Machine 在什麼CPU架構底下編譯的
NumberOfSections Section 數量
TimeDateStamp 檔案創建的時間 epoch (starts from 1970.1.1 00:00 UTC)
PointerToSymbolTable 指向Debug資訊表的指標 在Image File中通常為 0
NumberOfSymbols Debug Symbol 數量 在Image File中通常為 0
SizeOfOptionalHeader Optional Header 大小
Characteristics 檔案的額外資訊

底下分別是Debug Symbol、時間戳記、Characteristics的額外資訊

> Debug Symbol

PointerToSymbolTable和NumberOfSymbols紀錄的是COFF Debug資訊
用NTSD(Windows NT System Debugger)和KD(Windows NT Kernel Debugger)時會用到
PE Image這兩個欄位的值皆為 0

$ gcc .\target.c -o test.exe編譯程式
預設的輸出執行檔會保留這個區域
https://ithelp.ithome.com.tw/upload/images/20230122/20156936ZzgecJXmba.png

$ gcc -s .\target.c -o test.exe則可以刪除Debug Symbol
https://ithelp.ithome.com.tw/upload/images/20230122/20156936hA3wNIMUL8.png

也可以用strip.exe來移除Debug Symbol

  • $ strip test.exe會直接把整個symbol table都翻掉
  • $ strip --strip-unneeded test.exe還會保留global symbol
    ⚠️要注意strip也會同時更改timestamp跟characteristics的值⚠️

> Timestamp

除了COFF File Header之外,在PE檔裡面還有其他地方有存放時間資訊,其中包括

  • _IMAGE_EXPORT_DIRECTORY
  • _IMAGE_RESOURCE_DIRECTORY
  • _IMAGE_DEBUG_DIRECTORY

額外的時間資訊,可以提供病毒分析人員更多的線索來臆測攻擊者的心思
🌞SUNBURST就是一個例子

> Characteristics

Characteristics是用bit flag的方式來存放檔案資訊的一個成員
提供的資訊包含:檔案是不是執行檔、記憶體限制、Debug Symbol有沒有被移除

假設欄位中的數值 = 0x226 (0x02 + 0x04 + 0x20 + 0x200)

  • 0x002 - 檔案為執行檔
  • 0x004 - COFF被移除
  • 0x020 - 記憶體限制 > 2GB
  • 0x200 - Debug Symbol被移除

https://ithelp.ithome.com.tw/upload/images/20230122/20156936vjP6slQGJs.png


🫥 Optional Header

再來是Optional Header
前九個成員是根據COFF Optional Header的標準所制定的成員
後面的註解是他們所對應變數

typedef struct _IMAGE_OPTIONAL_HEADER64 {
  // --- COFF Standard Fields ---
  WORD                 Magic;                    // unsigned short magic;
  BYTE                 MajorLinkerVersion;       // unsigned short vstamp;
  BYTE                 MinorLinkerVersion;       // unsigned short vstamp;
  DWORD                SizeOfCode;               // unsigned long  tsize;
  DWORD                SizeOfInitializedData;    // unsigned long  dsize;
  DWORD                SizeOfUninitializedData;  // unsigned long  bsize;
  DWORD                AddressOfEntryPoint;      // unsigned long  entry;
  DWORD                BaseOfCode;               // unsigned long  text_start;
  ULONGLONG            ImageBase;                // unsigned long  data_start;
  // --- Windows Specific Fields ---
  DWORD                SectionAlignment;
  DWORD                FileAlignment;
  WORD                 MajorOperatingSystemVersion;
  WORD                 MinorOperatingSystemVersion;
  WORD                 MajorImageVersion;
  WORD                 MinorImageVersion;
  WORD                 MajorSubsystemVersion;
  WORD                 MinorSubsystemVersion;
  DWORD                Win32VersionValue;
  DWORD                SizeOfImage;
  DWORD                SizeOfHeaders;
  DWORD                CheckSum;
  WORD                 Subsystem;
  WORD                 DllCharacteristics;
  ULONGLONG            SizeOfStackReserve;
  ULONGLONG            SizeOfStackCommit;
  ULONGLONG            SizeOfHeapReserve;
  ULONGLONG            SizeOfHeapCommit;
  DWORD                LoaderFlags;
  DWORD                NumberOfRvaAndSizes;
  IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
} IMAGE_OPTIONAL_HEADER64, *PIMAGE_OPTIONAL_HEADER64;

其餘的成員(從SectionAlignment開始)為Windows自己定義的成員
在檔案被執行時會被PE loader / linker讀取

值得一提的是,根據官方

This similarity between the two file formats isn't happenstance. The goal of this design is to make the linker's job as easy as possible Theoretically, creating an EXE file from a single OBJ should be just a matter of inserting a few tables and modifying a couple of file offsets within the image. With this in mind, you can think of a COFF file as an embryonic PE file. Only a few things are missing or different, so I'll list them here.

可以知道PE Image與COFF相近的結構可以讓linker的工作(obj轉exe)變得容易很多
理論上只要插入幾個tables、更改一些file offsets就可以了

> Structure

一樣把它整理成表格

成員 功用 備註
Magic 用來辨識是32還是64位元的執行檔 PE32 / PE32+ / ROM
MajorLinkerVersion、MinorLinkerVersion Linker的版本
SizeOfCode .text大小
SizeOfInitializedData .data大小
SizeOfUninitializedData .bss大小
AddressOfEntryPoint entry point的RVA
BaseOfCode .text開頭位置的RVA
BaseOfData .data開頭位置的RVA 只有在32位元的執行檔才有
ImageBase 讀取進記憶體的第一個byte的地址
SectionAlignment Section的最小單位 >= FileAlignment
FileAlignment 占用磁碟的最小單位 64K > value > 512
MajorOperatingSystemVersion MinorOperatingSystemVersion 作業系統版本
MajorImageVersion、MinorImageVersion 檔案版本
MajorSubsystemVersion MinorSubsystemVersion 需要的subsystem版本
Win32VersionValue 保留區 set to 0
SizeOfImage 檔案大小 round up to SectionAlignment*n
SizeOfHeaders 除DOS Header外之Header大小 round up to FileAlignment*n
CheckSum 辨識執行檔完整性 與CRC32相似的自定義算法
Subsystem 執行檔案所需要的subsystem
DllCharacteristics Image file的其他屬性 ref
SizeOfStackReserve 保留給stack的連續虛擬記憶體 upper limit of stack
SizeOfStackCommit 預留給stack的實體記憶體 ref
SizeOfHeapReserve 保留給heap的連續虛擬記憶體
SizeOfHeapCommit 預留給heap的實體記憶體
LoaderFlags 保留區 set to 0
NumberOfRvaAndSizes DataDirectory大小
DataDirectory IMAGE_DATA_DIRECTORY的array

前面提到Optional Header有32位元跟64位元兩個版本
$ nvim -d IMAGE_OPTIONAL_HEADER32 IMAGE_OPTIONAL_HEADER64可以比較兩個架構的差異

https://ithelp.ithome.com.tw/upload/images/20230122/20156936LolVQcWhuM.png

從結果可以觀察到
64位元的架構把限制Stack跟Heap大小的定義從原本的DWORD改成ULONGLONG
同時BaseOfData為了讓位給ImageBase拓展到64 bits而被移除

底下是Alignment跟Subsystem的額外資料

> Alignment

把notepad.exe丟進PE Bear觀察

https://ithelp.ithome.com.tw/upload/images/20230123/20156936knuPgaM1mt.png

分別得到
SectionAlignment = 0x1000 (記憶體上的alignment)
FileAlignment = 0x200 (磁碟上的alignment)

看到.text section實際有放資料的大小為 0x23B6F
https://ithelp.ithome.com.tw/upload/images/20230123/20156936TDqvsKWjun.png
磁碟(SizeOfCode)上的所佔的大小就是 0x23A00 (0x200 * 285)
執行時在記憶體(BaseOfData - BaseOfCode)上佔用的大小就是 0x24000 bytes (0x1000 * 24)
兩個補齊的方式都是用\00做padding

> Subsystem

程式執行時需要的東西
可以猜出程式會用什麼方式呈現(eg. GUI or Console)
https://ithelp.ithome.com.tw/upload/images/20230123/20156936oHaU5yFP6V.png


🦛 Conclusion

我們介紹了NT Headers的架構
並把它拆成三個部分,Signature、File Header、Optional Header
細看資料結構裡面各個member的功能

下一篇,我們會進入Section的領域


ℹ️ References

0xrick's PE file format analysis
https://0xrick.github.io/win-internals/pe4/

Official Documentation
https://learn.microsoft.com/en-us/windows/win32/debug/pe-format

https://learn.microsoft.com/en-us/cpp/build/reference/symbols?view=msvc-170

Optional Header
https://wiki.osdev.org/PE#Optional_header

COFF
https://en.wikipedia.org/wiki/COFF

COFF Optional Header
http://www.delorie.com/djgpp/doc/coff/opthdr.html

timestamp
https://www.microsoft.com/en-us/security/blog/2021/01/20/deep-dive-into-the-solorigate-second-stage-activation-from-sunburst-to-teardrop-and-raindrop/

https://0xc0decafe.com/malware-analyst-guide-to-pe-timestamps

PE/COFF ELF formats & terminology
https://stackoverflow.com/questions/2170818/clarification-on-binary-file-pe-coff-elf-formats-terminology

PE loader
https://security.stackexchange.com/questions/24785/where-is-the-pe-loader-in-windows

strip vs. gcc -s
https://stackoverflow.com/questions/1349166/what-is-the-difference-between-gcc-s-and-a-strip-command


圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言