Sulaiman Chang Personal Website
Windows PE File Format Walkthrough II

Sulaiman Chang
September 14, 2004


IMAGE_NT_HEADERS

Now, we are on the way to understand the IMAGE_NT_HEADERS structure. This structure is declared in WINNT.H file.
typedef struct _IMAGE_NT_HEADERS {
    DWORD Signature;
    IMAGE_FILE_HEADER FileHeader;
    IMAGE_OPTIONAL_HEADER32 OptionalHeader;
} IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32;
we got so many things to understand now! nevermind, we just move on step by step and hopefully in the end, we would be able to make sense out of it.

The IMAGE_NT_HEADERS structure represents the PE header format. The Signature should contained the value 50 45 00 00 or (ascii) PE 0 0 to be identified as a valid PE image.




IMAGE_FILE_HEADER

The IMAGE_FILE_HEADER is a 20 bytes structure that included in the structure of IMAGE_NT_HEADERS.
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;
MachineSpecifies the architecture type of the computer.
0x014C = Intel 386 (generally we use this one)
0x0200 = Intel 64-bit
NumberOfSectionsSpecifies the number of sections.
TimeDateStampSpecifies the time stamp of the image. This represents the date and time the image was created by the linker.
PointerToSymbolTableOffset of the symbol table, or zero if no symbol table exists.
NumberOfSymbolsSpecifies the number of symbols in the symbol table.
SizeOfOptionalHeaderSpecifies the size of the optional header, in bytes.
CharacteristicsSpecifies the characteristics of the image.

IMAGE_FILE_RELOCS_STRIPPED
0x0001 // Relocation info stripped from file.


IMAGE_FILE_EXECUTABLE_IMAGE
0x0002 // File is executable (i.e. no unresolved externel references).


IMAGE_FILE_LINE_NUMS_STRIPPED
0x0004 // Line nunbers stripped from file.


IMAGE_FILE_LOCAL_SYMS_STRIPPED
0x0008 // Local symbols stripped from file.


IMAGE_FILE_AGGRESIVE_WS_TRIM
0x0010 // Agressively trim working set


IMAGE_FILE_LARGE_ADDRESS_AWARE
0x0020 // App can handle >2gb addresses


IMAGE_FILE_BYTES_REVERSED_LO
0x0080 // Bytes of machine word are reversed.


IMAGE_FILE_32BIT_MACHINE
0x0100 // 32 bit word machine.


IMAGE_FILE_DEBUG_STRIPPED
0x0200 // Debugging info stripped from file in .DBG file


IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP
0x0400 // If Image is on removable media, copy and run from the swap file.


IMAGE_FILE_NET_RUN_FROM_SWAP
0x0800 // If Image is on Net, copy and run from the swap file.


IMAGE_FILE_SYSTEM
0x1000 // System File.


IMAGE_FILE_DLL
0x2000 // File is a DLL.


IMAGE_FILE_UP_SYSTEM_ONLY
0x4000 // File should only be run on a UP machine


IMAGE_FILE_BYTES_REVERSED_HI
0x8000 // Bytes of machine word are reversed.



now, we got some information how to code our IMAGE_NT_HEADERS with IMAGE_FILE_HEADER. Below is what we could form using the above information.
IMAGE_NT_HEADERS:                                ;start : 80 (128) to 1EF (495)
       .Signature           db     'PE',0,0      ;128 131
       

       IMAGE_FILE_HEADER:                        ;start : 84 (132) to 97 (151)
              .Machine                           dw     0x014C        ;132 133 for intel 386
              .NumberOfSection                   dw     0x0003        ;134 135
              .TimeDateStamp                     dd     %t            ;136 139
              .PointerToSymbolTable              dd     0             ;140 143
              .NumberOfSymbols                   dd     0             ;144 147
              .SizeOfOptionalHeader              dw     0x00E0        ;148 149
              .Characteristic                    dw     0x818F        ;150 151

db 0x0B,0x01,0x01,0x37,0x00,0x00,0x00,0x00,\
..... to the end
our characteristic value is 0x818F which is equal to
+----------------------------------------------+
| Characteristic value for general PE EXE file |
+----------------------------------------------+
          IMAGE_FILE_RELOCS_STRIPPED          0x0001
          IMAGE_FILE_EXECUTABLE_IMAGE         0x0002 +  = 0x0003
          IMAGE_FILE_LINE_NUMS_STRIPPED       0x0004 +  = 0x0007
          IMAGE_FILE_LOCAL_SYMS_STRIPPED      0x0008 +  = 0x000F
          IMAGE_FILE_BYTES_REVERSED_LO        0x0080 +  = 0x008F
          IMAGE_FILE_32BIT_MACHINE            0x0100 +  = 0x018F
          IMAGE_FILE_BYTES_REVERSED_HI        0x8000 +  = 0x818F <-- our characteristic value
now, we got some new idea, how our PE file format actually looks like.
PE File Format (so far)
=======================
0x00 .... 0x3F ------------------------------- IMAGE_DOS_HEADER
0x40 .... 0x7F ------------------------------- DOS 2.0 Stub Program
0x80 .... ?    ------------------------------- IMAGE_NT_HEADERS
          0x84 .... 0x97 ---------------------      IMAGE_FILE_HEADER
Our NumberOfSection value is 0x0003 because we got 3 section for our PE, which are, ".data", ".code" and ".idata".

typedef struct _IMAGE_OPTIONAL_HEADER {
    WORD    Magic;
    BYTE    MajorLinkerVersion;
    BYTE    MinorLinkerVersion;
    DWORD   SizeOfCode;
    DWORD   SizeOfInitializedData;
    DWORD   SizeOfUninitializedData;
    DWORD   AddressOfEntryPoint;
    DWORD   BaseOfCode;
    DWORD   BaseOfData;

    DWORD   ImageBase;
    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;
    DWORD   SizeOfStackReserve;
    DWORD   SizeOfStackCommit;
    DWORD   SizeOfHeapReserve;
    DWORD   SizeOfHeapCommit;
    DWORD   LoaderFlags;
    DWORD   NumberOfRvaAndSizes;
    IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
} IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32;
MagicSpecifies the state of the image file

IMAGE_NT_OPTIONAL_HDR_MAGIC
0x010B (32-bit) // The file is an executable image.
0x020B (64-bit) // The file is an executable image.

IMAGE_ROM_OPTIONAL_HDR_MAGIC
0x0107 // The file is a ROM image.
MajorLinkerVersionMajor version number of the linker.
MinorLinkerVersionMinor version number of the linker.
SizeOfCodeThe size of the code section, or the sum of all such sections if there are multiple code sections.
SizeOfInitializedDataThe size of the initialized data section, or the sum of all such sections if there are multiple initialized data sections.
SizeOfUninitializedDataThe size of the uninitialized data section, or the sum of all such sections if there are multiple uninitialized data sections.
AddressOfEntryPointPointer to the entry point function, relative to the image base address. The entry point function is optional for DLLs. When no entry point is present, this member is zero.
BaseOfCodePointer to the beginning of the code section, relative to the image base.
BaseOfDataPointer to the beginning of the data section, relative to the image base.
ImageBasePreferred address of the first byte of the image when it is loaded in memory. This value is a multiple of 64K bytes. The default value for DLLs is 0x10000000. The default value for Win32-based applications on Windows CE is 0x00010000. The default value for Win32-based applications on Windows NT/Windows 2000 and Windows 95/98 is 0x00400000.
SectionAlignmentThe alignment, in bytes, of sections loaded in memory. This value must be greater than or equal to the FileAlignment member. The default value is the page size for the system.
FileAlignmentThe alignment, in bytes, of the raw data of sections in the image file. The value should be a power of 2 between 512 and 64K (inclusive). The default is 512. If the SectionAlignment member is less than the system page size, this member must be the same as SectionAlignment.
MajorOperatingSystemVersionMajor version number of the required operating system.
MinorOperatingSystemVersionMinor version number of the required operating system.
MajorImageVersionMajor version number of the image.
MinorImageVersionMinor version number of the image.
MajorSubsystemVersionMajor version number of the subsystem.
MinorSubsystemVersionMinor version number of the subsystem.
Win32VersionValueThis member is reserved.
SizeOfImageThe size of the image, in bytes, including all headers. Must be a multiple of SectionAlignment.
SizeOfHeadersCombined size of the MS-DOS stub, the PE header, and the section headers, rounded to a multiple of the value specified in the FileAlignment member.
CheckSumImage file checksum.
Subsystem
IMAGE_SUBSYSTEM_UNKNOWN
0x0000 // Unknown subsystem.

IMAGE_SUBSYSTEM_NATIVE
0x0001 // No subsystem required.

IMAGE_SUBSYSTEM_WINDOWS_GUI
0x0002 // Image runs in the Windows GUI subsystem

IMAGE_SUBSYSTEM_WINDOWS_CUI
0x0003 // Image runs in the Windows character-mode subsystem.

IMAGE_SUBSYSTEM_POSIX_CUI
0x0007 // Image runs in the POSIX character-mode subsystem.

IMAGE_SUBSYSTEM_NATIVE_WINDOWS
0x0008 // Image is a native Win9x driver

IMAGE_SUBSYSTEM_WINDOWS_CE_GUI
0x0009 // Image runs in the Windows CE subsystem.
DllCharacteristicsSpecifies the DLL characteristics of the image.
SizeOfStackReserveThe number of bytes to reserve for the stack.
SizeOfStackCommitThe number of bytes to commit for the stack.
SizeOfHeapReserveThe number of bytes to reserve for the local heap.
SizeOfHeapCommitThe number of bytes to commit for the local heap.
LoaderFlagsThis member is obsolete.
NumberOfRvaAndSizesNumber of directory entries.
IMAGE_DATA_DIRECTORY
(Occupies 8 bytes * NumberOfRvaAndSizes)
typedef struct _IMAGE_DATA_DIRECTORY {
    DWORD VirtualAddress;
    DWORD Size;
} IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;

ok, i guess we got some information to code our IMAGE_OPTIONAL_HEADER
PE File Format (so far)
=======================
0x00 .... 0x3F ------------------------------- IMAGE_DOS_HEADER
0x40 .... 0x7F ------------------------------- DOS 2.0 Stub Program
0x80 .... ?    ------------------------------- IMAGE_NT_HEADERS
          0x84 .... 0x97 ---------------------      IMAGE_FILE_HEADER
          0x98 .... 0xF7 ---------------------      IMAGE_OPTIONAL_HEADER
                    0xF8 .... 0x177 ----------           IMAGE_DATA_DIRECTORY
       IMAGE_OPTIONAL_HEADER:                    ;start : 98 (152) to F7 (247) * till IMAGE_DATA_DIRECTORY
                                                                      ;offset
              .Magic                             dw     0x010B        ;152 153
              .MajorLinkerVersion                db     0x01          ;154
              .MinorLinkerVersion                db     0x37          ;155
              .SizeOfCode                        dd     0             ;156 159
              .SizeOfInitializedData             dd     0             ;160 163
              .SizeOfUninitializedData           dd     0             ;164 167
              .AddressOfEntryPoint               dd     0x2000        ;168 171
                                                                      ;base + 2000 = 402000 (.code section)
              .BaseOfCode                        dd     0             ;172 175
              .BaseOfData                        dd     0             ;176 179
              .ImageBase                         dd     0x00400000    ;180 183 (default)
              .SectionAlignment                  dd     0x00001000    ;184 187 4096 bytes
              .FileAlignment                     dd     0x00000200    ;188 191 512 bytes (default)
              .MajorOperatingSystemVersion       dw     1             ;192 193
              .MinorOperatingSystemVersion       dw     0             ;194 195
              .MajorImageVersion                 dw     0             ;196 197
              .MinorImageVersion                 dw     0             ;198 199
              .MajorSubsystemVersion             dw     4             ;200 201
              .MinorSubsystemVersion             dw     0             ;202 203
              .Win32VersionValue                 dd     0             ;204 207
              .SizeOfImage                       dd     0x00004000    ;208 211
              .SizeOfHeaders                     dd     0x00000200    ;212 215
              .CheckSum                          dd     0x0000EF20    ;216 219
              .Subsystem                         dw     2             ;220 221 IMAGE_SUBSYSTEM_WINDOWS_GUI
              .DllCharacteristics                dw     0             ;222 223
              .SizeOfStackReserve                dd     0x00001000    ;224 227 4096 bytes
              .SizeOfStackCommit                 dd     0x00001000    ;228 231 4096 bytes
              .SizeOfHeapReserve                 dd     0x00100000    ;232 235 1048576 bytes
              .SizeOfHeapCommit                  dd     0             ;236 239
              .LoaderFlags                       dd     0             ;240 243
              .NumberOfRvaAndSizes               dd     0x10          ;244 247 16 decimal
              
              IMAGE_DATA_DIRECTORY:              ;start : F8 (248) to 177 (375) * till IMAGE_SECTION_TABLE
                     rq     1                    ;248 255
                     .ImportTableVA              dd     0x00003000           ;256 263
                     .ImportTableSize            dd     0x00000090
                     rq     14                   ;we don't need them also    ;263 + 112 = 375

db 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x2E,0x64,0x61,0x74,0x61,0x00,0x00,0x00,\
.... to the end
Once we finish with IMAGE_DATA_DIRECTORY, we will need to present the system with IMAGE_SECTION_HEADER. Since we got 3 sections as defined above, we would need 3 structures of IMAGE_SECTION_TABLE
#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;
NameAn 8-byte, null-filled string. There is no terminating null character if the string is exactly eight characters long. For longer names, this member contains a forward slash (/) followed by a decimal number that is an offset into the string table. Executable images do not use a string table and do not support section names longer than eight characters.
PhysicalAddressSpecifies the file address.
VirtualSizeTotal size of the section when loaded into memory. If this value is greater than the SizeOfRawData member, the section is filled with zeroes.
VirtualAddressThe address of the first byte of the section when loaded into memory, relative to the image base.
SizeOfRawDataThe size of the initialized data on disk. This value must be a multiple of the FileAlignment member of the IMAGE_OPTIONAL_HEADER structure. If this value is less than the VirtualSize member, the remainder of the section is filled with zeroes. If the section contains only uninitialized data, the member is zero.
PointerToRawDataFile pointer to the first page within the COFF file. This value must be a multiple of the FileAlignment member of the IMAGE_OPTIONAL_HEADER structure. If a section contains only uninitialized data, this member is zero.
PointerToRelocationsFile pointer to the beginning of the relocation entries for the section. If there are no relocations, this value is zero.
PointerToLinenumbersFile pointer to the beginning of the line-number entries for the section. If there are no COFF line numbers, this value is zero.
NumberOfRelocationsNumber of relocation entries for the section. This value is zero for executable images.
NumberOfLinenumbersNumber of line-number entries for the section.
CharacteristicsSpecifies the characteristics of the image.

IMAGE_SCN_TYPE_NO_PAD
0x00000008 // Reserved.

IMAGE_SCN_CNT_CODE
0x00000020 // Section contains code.

IMAGE_SCN_CNT_INITIALIZED_DATA
0x00000040 // Section contains initialized data.

IMAGE_SCN_CNT_UNINITIALIZED_DATA
0x00000080 // Section contains uninitialized data.

IMAGE_SCN_LNK_OTHER
0x00000100 // Reserved.

IMAGE_SCN_LNK_INFO
0x00000200 // Section contains comments or some other type of information.

IMAGE_SCN_LNK_REMOVE
0x00000800 // Section contents will not become part of image.

IMAGE_SCN_LNK_COMDAT
0x00001000 // Section contents comdat.

IMAGE_SCN_NO_DEFER_SPEC_EXC
0x00004000 // Reset speculative exceptions handling bits in the TLB entries for this section.

IMAGE_SCN_GPREL & IMAGE_SCN_MEM_FARDATA
0x00008000 // Section content can be accessed relative to GP

IMAGE_SCN_MEM_PURGEABLE & IMAGE_SCN_MEM_16BIT
0x00020000 // Reserved.

IMAGE_SCN_MEM_LOCKED
0x00040000 // Reserved.

IMAGE_SCN_MEM_PRELOAD
0x00080000 // Reserved.

IMAGE_SCN_ALIGN_1BYTES
0x00100000 // Align data on a 1-byte boundary.

IMAGE_SCN_ALIGN_2BYTES
0x00200000 // Align data on a 2-byte boundary.

IMAGE_SCN_ALIGN_4BYTES
0x00300000 // Align data on a 4-byte boundary.

IMAGE_SCN_ALIGN_8BYTES
0x00400000 // Align data on a 8-byte boundary.

IMAGE_SCN_ALIGN_16BYTES (Default alignment if no others are specified)
0x00500000 // Align data on a 16-byte boundary.

IMAGE_SCN_ALIGN_32BYTES
0x00600000 // Align data on a 32-byte boundary.

IMAGE_SCN_ALIGN_64BYTES
0x00700000 // Align data on a 64-byte boundary.

IMAGE_SCN_ALIGN_128BYTES
0x00800000 // Align data on a 128-byte boundary.

IMAGE_SCN_LNK_NRELOC_OVFL
0x01000000 // Section contains extended relocations.

IMAGE_SCN_MEM_DISCARDABLE
0x02000000 // Section can be discarded.

IMAGE_SCN_MEM_NOT_CACHED
0x04000000 // Section is not cachable.

IMAGE_SCN_MEM_NOT_PAGED
0x08000000 // Section is not pageable.

IMAGE_SCN_MEM_SHARED
0x10000000 // Section is shareable.

IMAGE_SCN_MEM_EXECUTE
0x20000000 // Section is executable.

IMAGE_SCN_MEM_READ
0x40000000 // Section is readable.

IMAGE_SCN_MEM_WRITE
0x80000000 // Section is writeable.



Continue to Windows PE File Format Walkthrough III
Copyright © 2004 Sulaiman Chang. All Rights Reserved.