PE File Format
(1) IMAGE_DOS_HEADER
Note that the highlighted lines are the fields we need to focus on.
typedef struct _IMAGE_DOS_HEADER {
WORD e_magic; /* 00: MZ Header signature */
WORD e_cblp; /* 02: Bytes on last page of file */
WORD e_cp; /* 04: Pages in file */
WORD e_crlc; /* 06: Relocations */
WORD e_cparhdr; /* 08: Size of header in paragraphs */
WORD e_minalloc; /* 0a: Minimum extra paragraphs needed */
WORD e_maxalloc; /* 0c: Maximum extra paragraphs needed */
WORD e_ss; /* 0e: Initial (relative) SS value */
WORD e_sp; /* 10: Initial SP value */
WORD e_csum; /* 12: Checksum */
WORD e_ip; /* 14: Initial IP value */
WORD e_cs; /* 16: Initial (relative) CS value */
WORD e_lfarlc; /* 18: File address of relocation table */
WORD e_ovno; /* 1a: Overlay number */
WORD e_res[4]; /* 1c: Reserved words */
WORD e_oemid; /* 24: OEM identifier (for e_oeminfo) */
WORD e_oeminfo; /* 26: OEM information; e_oemid specific */
WORD e_res2[10]; /* 28: Reserved words */
DWORD e_lfanew; /* 3c: Offset (pointer) to PE header */
} IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;
The following image illustrates DOS HEADER.
(2) DOS Stub
This part is no longer using after 32 bit mode. The following image shows an example of DOS Stub.
(3) IMAGE_NT_HEADERS (Size:0xF8)
typedef struct _IMAGE_NT_HEADERS {
DWORD Signature; /* "PE"\0\0 */ /* 0x00 */
IMAGE_FILE_HEADER FileHeader; /* 0x04 */
IMAGE_OPTIONAL_HEADER32 OptionalHeader; /* 0x18 */
} IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32;
An example of NT Headers is as following. Note that the starting address matches the value “0x000000E0” with the one from e_lfanew field in DOS Header. NT Header contains both Image File Header and Image Optional Header.
(4) IMAGE_FILE_HEADER
-
Machine field specifies the architecture; 0x14c means x86 and 0x8664 means x86-64.
-
TimeDateStamp field has Unix timestamp whose epoc is 00:00:00 UTC on Jan. 1st, 1970 at link time.
-
SizeOfOptionalHeader field indicates the number of section headers.
-
Characteristics field shows the property of an executable file. See the below.
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;
/* These are the settings of the Machine field. */ #define IMAGE_FILE_MACHINE_UNKNOWN 0 #define IMAGE_FILE_MACHINE_I860 0x014d #define IMAGE_FILE_MACHINE_I386 0x014c #define IMAGE_FILE_MACHINE_R3000 0x0162 #define IMAGE_FILE_MACHINE_R4000 0x0166 #define IMAGE_FILE_MACHINE_R10000 0x0168 #define IMAGE_FILE_MACHINE_WCEMIPSV2 0x0169 #define IMAGE_FILE_MACHINE_ALPHA 0x0184 #define IMAGE_FILE_MACHINE_SH3 0x01a2 #define IMAGE_FILE_MACHINE_SH3DSP 0x01a3 #define IMAGE_FILE_MACHINE_SH3E 0x01a4 #define IMAGE_FILE_MACHINE_SH4 0x01a6 #define IMAGE_FILE_MACHINE_SH5 0x01a8 #define IMAGE_FILE_MACHINE_ARM 0x01c0 #define IMAGE_FILE_MACHINE_THUMB 0x01c2 #define IMAGE_FILE_MACHINE_ARMNT 0x01c4 #define IMAGE_FILE_MACHINE_ARM64 0xaa64 #define IMAGE_FILE_MACHINE_AM33 0x01d3 #define IMAGE_FILE_MACHINE_POWERPC 0x01f0 #define IMAGE_FILE_MACHINE_POWERPCFP 0x01f1 #define IMAGE_FILE_MACHINE_IA64 0x0200 #define IMAGE_FILE_MACHINE_MIPS16 0x0266 #define IMAGE_FILE_MACHINE_ALPHA64 0x0284 #define IMAGE_FILE_MACHINE_MIPSFPU 0x0366 #define IMAGE_FILE_MACHINE_MIPSFPU16 0x0466 #define IMAGE_FILE_MACHINE_AXP64 IMAGE_FILE_MACHINE_ALPHA64 #define IMAGE_FILE_MACHINE_TRICORE 0x0520 #define IMAGE_FILE_MACHINE_CEF 0x0cef #define IMAGE_FILE_MACHINE_EBC 0x0ebc #define IMAGE_FILE_MACHINE_AMD64 0x8664 #define IMAGE_FILE_MACHINE_M32R 0x9041 #define IMAGE_FILE_MACHINE_CEE 0xc0ee
/* These defines the meanings of the bits in the Characteristics field / #define IMAGE_FILE_RELOCS_STRIPPED 0x0001 / No relocation info */ #define IMAGE_FILE_EXECUTABLE_IMAGE 0x0002 #define IMAGE_FILE_LINE_NUMS_STRIPPED 0x0004 #define IMAGE_FILE_LOCAL_SYMS_STRIPPED 0x0008 #define IMAGE_FILE_AGGRESIVE_WS_TRIM 0x0010 #define IMAGE_FILE_LARGE_ADDRESS_AWARE 0x0020 #define IMAGE_FILE_16BIT_MACHINE 0x0040 #define IMAGE_FILE_BYTES_REVERSED_LO 0x0080 #define IMAGE_FILE_32BIT_MACHINE 0x0100 #define IMAGE_FILE_DEBUG_STRIPPED 0x0200 #define IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP 0x0400 #define IMAGE_FILE_NET_RUN_FROM_SWAP 0x0800 #define IMAGE_FILE_SYSTEM 0x1000 #define IMAGE_FILE_DLL 0x2000 #define IMAGE_FILE_UP_SYSTEM_ONLY 0x4000 #define IMAGE_FILE_BYTES_REVERSED_HI 0x8000
(5) IMAGE_OPTIONAL_HEADER
Note that Optional header is not all optional!!
-
_AddressOfEntryPoint _specifies the RVA which the loader starts code execution
-
SizeOfImage tells the amount of contiguous memory reserved to load the binary into memory.
-
SectionAlignment specifies that sections should be aligned on boundaries of multiples of this value.
-
_FileAlignment _field tells that data has to be written to a file in chucks no smaller than this value. i.e 0x200 or 512 in HDD sector size
-
ImageBase field specifies the preferred virtual memory address for the beginning of the binary.
-
DLLCharateristics field provides the loader with security options like ASLR and DEP NX memory regions. -> Not limited to DLLs, IDE compiler with the /DYNAMICBASE option
-
DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES] has two fields: VirtualAddress _and _Size
typedef struct _IMAGE_OPTIONAL_HEADER { /* Standard fields / WORD Magic; / 0x10b or 0x107 / / 0x00 / BYTE MajorLinkerVersion; BYTE MinorLinkerVersion; DWORD SizeOfCode; DWORD SizeOfInitializedData; DWORD SizeOfUninitializedData; DWORD AddressOfEntryPoint; / 0x10 / DWORD BaseOfCode; DWORD BaseOfData; / NT additional fields / DWORD ImageBase; DWORD SectionAlignment; / 0x20 / DWORD FileAlignment; WORD MajorOperatingSystemVersion; WORD MinorOperatingSystemVersion; WORD MajorImageVersion; WORD MinorImageVersion; WORD MajorSubsystemVersion; / 0x30 / WORD MinorSubsystemVersion; DWORD Win32VersionValue; DWORD SizeOfImage; DWORD SizeOfHeaders; DWORD CheckSum; / 0x40 / WORD Subsystem; WORD DllCharacteristics; DWORD SizeOfStackReserve; DWORD SizeOfStackCommit; DWORD SizeOfHeapReserve; / 0x50 / DWORD SizeOfHeapCommit; DWORD LoaderFlags; DWORD NumberOfRvaAndSizes; IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; / 0x60 / / 0xE0 */ } IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32;
// Directory Entries (16 entries are pre-defined) #define IMAGE_DIRECTORY_ENTRY_EXPORT 0 /Export Directory */ #define IMAGE_DIRECTORY_ENTRY_IMPORT 1 /Import Directory / #define IMAGE_DIRECTORY_ENTRY_RESOURCE 2 /Resource Directory / #define IMAGE_DIRECTORY_ENTRY_EXCEPTION 3 /Exception Directory / #define IMAGE_DIRECTORY_ENTRY_SECURITY 4 /Security Directory / #define IMAGE_DIRECTORY_ENTRY_BASERELOC 5 /Base Relocation Table / #define IMAGE_DIRECTORY_ENTRY_DEBUG 6 /Debug Directory / #define IMAGE_DIRECTORY_ENTRY_COPYRIGHT 7 / (x86 usage) / #define IMAGE_DIRECTORY_ENTRY_ARCHITECTURE 7 / Architecture Specific Data / #define IMAGE_DIRECTORY_ENTRY_GLOBALPTR 8 / RVA of GP / #define IMAGE_DIRECTORY_ENTRY_TLS 9 / TLS Directory / #define IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG 10 / Load Configuration Directory / #define IMAGE_DIRECTORY_ENTRY_LOAD_BOUND_IMPORT 11 / Bound Import Directory in headers / #define IMAGE_DIRECTORY_ENTRY_LOAD_IAT 12 / Import Address Table / #define IMAGE_DIRECTORY_ENTRY_LOAD_DELAY_IMPORT 13 / Delay Load Import Descriptors / #define IMAGE_DIRECTORY_ENTRY_LOAD_COM_DESCRIPTOR 14 / COM Runtime descriptor */
Each directory has similar structure as following:
typedef struct _IMAGE_DATA_DIRECTORY {
DWORD VirtualAddress;
DWORD Size;
} IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;
(6) IMAGE_SECTION_HEADER (.text, .data, .rsrc, .reloc, …)
-
VirtualAddress specifies the RVA (Relative Virtual Address) of the section relative to ImageBase.
-
PointerToRawData specifies a relative offset to store the actual section data from the file .
-
SizeOfRawData indicates the size of memory allocation for the section. The value is Mics.VirtualSize which is rounded up to the multiple of alignment.
-
PointerToRawData field indicates the actual file offset from the section.
-
See the below for a characteristics field.
define IMAGE_SIZEOF_SHORT_NAME 8
typedef struct _IMAGE_SECTION_HEADER { BYTE Name[IMAGE_SIZEOF_SHORT_NAME]; union { DWORD PhysicalAddress; DWORD VirtualSize; } Misc; DWORD VirtualAddress; DWORD SizeOfRawData; DWORD PointerToRawData; DWORD PointerToRelocations; DWORD PointerToLinenumbers; WORD NumberOfRelocations; WORD NumberOfLinenumbers; DWORD Characteristics; } IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER;
/* These defines are for the Characteristics bitfield. */
/* #define IMAGE_SCN_TYPE_REG 0x00000000 - Reserved */
/* #define IMAGE_SCN_TYPE_DSECT 0x00000001 - Reserved */
/* #define IMAGE_SCN_TYPE_NOLOAD 0x00000002 - Reserved */
/* #define IMAGE_SCN_TYPE_GROUP 0x00000004 - Reserved */
#define IMAGE_SCN_TYPE_NO_PAD 0x00000008 /* Reserved */
/* #define IMAGE_SCN_TYPE_COPY 0x00000010 - Reserved */
#define IMAGE_SCN_CNT_CODE 0x00000020
#define IMAGE_SCN_CNT_INITIALIZED_DATA 0x00000040
#define IMAGE_SCN_CNT_UNINITIALIZED_DATA 0x00000080
#define IMAGE_SCN_LNK_OTHER 0x00000100
#define IMAGE_SCN_LNK_INFO 0x00000200
/* #define IMAGE_SCN_TYPE_OVER 0x00000400 - Reserved */
#define IMAGE_SCN_LNK_REMOVE 0x00000800
#define IMAGE_SCN_LNK_COMDAT 0x00001000
/* 0x00002000 - Reserved */
/* #define IMAGE_SCN_MEM_PROTECTED 0x00004000 - Obsolete */
#define IMAGE_SCN_MEM_FARDATA 0x00008000
/* #define IMAGE_SCN_MEM_SYSHEAP 0x00010000 - Obsolete */
#define IMAGE_SCN_MEM_PURGEABLE 0x00020000
#define IMAGE_SCN_MEM_16BIT 0x00020000
#define IMAGE_SCN_MEM_LOCKED 0x00040000
#define IMAGE_SCN_MEM_PRELOAD 0x00080000
#define IMAGE_SCN_ALIGN_1BYTES 0x00100000
#define IMAGE_SCN_ALIGN_2BYTES 0x00200000
#define IMAGE_SCN_ALIGN_4BYTES 0x00300000
#define IMAGE_SCN_ALIGN_8BYTES 0x00400000
#define IMAGE_SCN_ALIGN_16BYTES 0x00500000 /* Default */
#define IMAGE_SCN_ALIGN_32BYTES 0x00600000
#define IMAGE_SCN_ALIGN_64BYTES 0x00700000
#define IMAGE_SCN_ALIGN_128BYTES 0x00800000
#define IMAGE_SCN_ALIGN_256BYTES 0x00900000
#define IMAGE_SCN_ALIGN_512BYTES 0x00A00000
#define IMAGE_SCN_ALIGN_1024BYTES 0x00B00000
#define IMAGE_SCN_ALIGN_2048BYTES 0x00C00000
#define IMAGE_SCN_ALIGN_4096BYTES 0x00D00000
#define IMAGE_SCN_ALIGN_8192BYTES 0x00E00000
/* 0x00F00000 - Unused */
#define IMAGE_SCN_ALIGN_MASK 0x00F00000
#define IMAGE_SCN_LNK_NRELOC_OVFL 0x01000000
#define IMAGE_SCN_MEM_DISCARDABLE 0x02000000
#define IMAGE_SCN_MEM_NOT_CACHED 0x04000000
#define IMAGE_SCN_MEM_NOT_PAGED 0x08000000
#define IMAGE_SCN_MEM_SHARED 0x10000000
#define IMAGE_SCN_MEM_EXECUTE 0x20000000
#define IMAGE_SCN_MEM_READ 0x40000000
#define IMAGE_SCN_MEM_WRITE 0x80000000
Here are several good resources to explain PE format.
Enjoy Reading This Article?
Here are some more articles you might like to read next: