2022年7月29日 星期五

PE/COFF header of UEFI image

參考網站:
Microsoft pe-format
Wiki Portable_Executable
osdev COFF

UEFI image都是遵循微軟所定義的 PE/COFF格式,PE/COFF的格式可以參考維基百科的這張 圖:

CC BY 4.0, Link

使用 EDK2的 CpuDxe.efi來觀察一下:

可以看到一開始的 0x40個 Byte,是 DOS Header,起始的開頭為"MZ"(0x4D 0x5A),在 EDK2 structure定義如下:

///
/// PE images can start with an optional DOS header, so if an image is run
/// under DOS it can print an error message.
///
typedef struct {
  UINT16    e_magic;    ///< Magic number.
  UINT16    e_cblp;     ///< Bytes on last page of file.
  UINT16    e_cp;       ///< Pages in file.
  UINT16    e_crlc;     ///< Relocations.
  UINT16    e_cparhdr;  ///< Size of header in paragraphs.
  UINT16    e_minalloc; ///< Minimum extra paragraphs needed.
  UINT16    e_maxalloc; ///< Maximum extra paragraphs needed.
  UINT16    e_ss;       ///< Initial (relative) SS value.
  UINT16    e_sp;       ///< Initial SP value.
  UINT16    e_csum;     ///< Checksum.
  UINT16    e_ip;       ///< Initial IP value.
  UINT16    e_cs;       ///< Initial (relative) CS value.
  UINT16    e_lfarlc;   ///< File address of relocation table.
  UINT16    e_ovno;     ///< Overlay number.
  UINT16    e_res[4];   ///< Reserved words.
  UINT16    e_oemid;    ///< OEM identifier (for e_oeminfo).
  UINT16    e_oeminfo;  ///< OEM information; e_oemid specific.
  UINT16    e_res2[10]; ///< Reserved words.
  UINT32    e_lfanew;   ///< File address of new exe header.
} EFI_IMAGE_DOS_HEADER;

而 0x3C則定義了PE Signature的位置,長度為 4 Bytes。以 CpuDxe.efi來說,是在 0x000000B8的位置。可從 0x000000B8的位置看到"PE\0\0"(0x50 0x45 0x00 0x00)的 PE Signature。

而從 0x40到 0xb7的這段空間稱為 DOS Stub,以前為了與 DOS相容而遺留下的產物,現在則直 接全部都填上 0x00。

PE Signature之後是 COFF File Header,在 EDK2中的定義如下:

///
/// COFF File Header (Object and Image).
///
typedef struct {
  UINT16    Machine;
  UINT16    NumberOfSections;
  UINT32    TimeDateStamp;
  UINT32    PointerToSymbolTable;
  UINT32    NumberOfSymbols;
  UINT16    SizeOfOptionalHeader;
  UINT16    Characteristics;
} EFI_IMAGE_FILE_HEADER;

COFF File Header長度為 20 Bytes,將其獨立拿出來看:


OffsetSizeFieldValueDescription
02Machine0x8664代表 x64系統使用。
22NumberOfSections0x0006Section Table 的數量。
44TimeDateStamp0x0
84PointerToSymbolTable0x0
124NumberOfSymbols0x0
162SizeOfOptionalHeader0x00F0Optional Header的 size。
182Characteristics0x2022IMAGE_FILE_EXECUTABLE_IMAGE +
IMAGE_FILE_LARGE_ADDRESS_AWARE +
IMAGE_FILE_DLL

緊接下來則是 Optional Header,其長度可以從 COFF File Header得知為 0xF0。

其分成 3個部分,Standard FieldsWindows Specific FieldsData Directories

Standard Fields
OffsetSizeFieldValueDescription
02Magic0x020BPE32+格式。
21MajorLinkerVersion0x0E
31MinorLinkerVersion0x1D
44SizeOfCode0x0000BAE0code section的 size。
84SizeOfInitializedData0x00001AE0initialized data section的 size。
124SizeOfUninitializedData0x0uninitialized data section的 size。
164AddressOfEntryPoint0x00001268entry point對ImageBase的相對位址。
204BaseOfCode0x000002C0code section對ImageBase的相對位址。

Windows Specific Fields (PE32+)
OffsetSizeFieldValueDescription
248ImageBase0x0
324SectionAlignment0x00000020section在記憶體中為 32 Bytes alignment。
364FileAlignment0x00000020section中的raw data為 32 Bytes alignment。
402MajorOperatingSystemVersion0x0
422MinorOperatingSystemVersion0x0
442MajorImageVersion0x0
462MinorImageVersion0x0
482MajorSubsystemVersion0x0
502MinorSubsystemVersion0x0
524Win32VersionValue0x0
564SizeOfImage0x0000DC40Image的 size,包含所有 headers。
CpuDxe.efi的 size就是0xDC40。
604SizeOfHeaders0x000002C0DOS stub、PE Header和 section headers的 size總和。
644CheckSum0x0
682Subsystem0x000B代表為 IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_ DRIVER。
702DLL Characteristics0x0
728SizeOfStackReserve0x0
808SizeOfStackCommit0x0
888SizeOfHeapReserve0x0
968SizeOfHeapCommit0x0
1044LoaderFlags0x0
1084NumberOfRvaAndSizes0x00000010Data Directories的數量。

Data Directories (PE32+)
OffsetSizeFieldValueDescription
1128Export Table0x0
1208Import Table0x0
1288Resource Table0x0
1368Exception Table0x0
1448Certificate Table0x0
1528Base Relocation Table0x0000DBC0
1608Debug0x0
1688Architecture0x0
1768Global Ptr0x0
1848TLS Table0x0
1928Load Config Table0x0
2008Bound Import0x0
2088IAT0x0
2168Delay Import Descriptor0x0
2248CLR Runtime Header0x0
2328Reserved0x0

Optional Header的下個部份則為 Section Headers,其數量可以從 COFF File Header
NumberOfSections讀出。

Section Header
OffsetSizeFieldDescription
08Name8 Bytes的 ASCII字串,代表此 section的名字。
84VirtualSize此section在記憶體中的 size,如果大於 SizeOfRawData
則後面會填上 0x0。
124VirtualAddress此 section在記憶體中相對於 ImageBase的起始位址。
164SizeOfRawDatainitialized date的 size。
204PointerToRawDatasection raw data的 offset。
244PointerToRelocationsRelocation table的 offset。
284PointerToLinenumbersLine Number table的 offset。
322NumberOfRelocationsRelocatione table的數量。
342NumberOfLinenumbersLine Number table的數量。
364Characteristics32 Bits flag。

CpuDxe.efi可以使用 xpeviewer讀出 6個 sections:


Section NameContent
.textExecutable code
.rodataRead-only initialized data
.dataInitialized data
.xdataException information
.relocImage relocations

沒有留言:

張貼留言