[user@n0.lol ~/bp/wow64pe]

Windows 64 Bit PE Internals

This will be a decently comprehensive look at the internals of a Windows 64 Bit Portable Executable. First, let's create a really simple executable with mingw. You don't have to use mingw, but I don't have a Visual Studio license anymore and it's way easier to compile this way for me. Just grab any ol' exe if you need :D.

Here's what I used:

#include <windows.h> 

int WINAPI 
WinMain (HINSTANCE hInstance, HINSTANCE hPrevInst, LPTSTR lpCmdLine, int nShowCmd) 
{ 
  MessageBoxW (NULL, L"we out here", L"supp", MB_OK | MB_ICONINFORMATION); 
  return 0; 
}

Compile like this:

x86_64-w64-mingw32-gcc -o hello64.exe hello.c 

or if you want a 32 bit one, do this

i686-w64-mingw32-gcc -o hello32.exe hello.c 

Okay, now fire up your hex editors, let's take a look at what we have here.

DOS Header


The DOS Header is present in nearly every EXE file. It is used for backwards compatibility with DOS based systems, in order to tell the user that the program cannot be run on DOS or while using 16 bit DOS mode (which by and large, no longer exists.) This relic of backwards compatibility is what makes the PE header one of the most interesting to look at (and abuse.)

Some info adapted from OSDEV

Note: A paragraph is 16 bytes in size.

#   ADDR  Name       Desc
------------------------------------------------------------------------------
dA  0x00  signature  MZ
dB  0x02  lastsize   Number of bytes in the last page
dC  0x04  nblocks    Number of pages
dD  0x06  nreloc     Number of relocation entries in relocation table
dE  0x08  hdrsize    Header size (number of paragraphs)
dF  0x0A  minalloc   Number of paragraphs required by the program.
dG  0x0C  maxalloc   Number of paragraphs requested by the program.
dH  0x0E  *ss        Relocatable segment address for SS
dI  0x10  *sp        Initial stack pointer value.
dJ  0x12  checksum   When added to the sum of all other words in the file, 
                     the result should be zero.
dK  0x14  *ip        Initial instruction pointer value.
dL  0x16  *cs        Relocatable segment address for CS
dM  0x18  relocpos   Absolute offset of the relocation table.
dN  0x1A  noverlay   Used for overlay management, if zero, this is the main 
                     executable. Funny because it's not :D
dO  0x1C  reserved 
dP  0x1E  oem_id     Note, this is not really used.
dQ  0x20  oem_info   Same as oem_id
dR  0x22  reserved   10 bytes
dS  0x3C  e_lfanew   Pointer to the PE Signature
------------------------------------------------------------------------------
          dA--- dB--- dC--- dD---  dE--- dF--- dG--- dH---
00000000  4d 5a 90 00 03 00 00 00  04 00 00 00 ff ff 00 00  |MZ..............|
          dI--- dJ--- dK--- dL---  dM--- dN--- dO--- dP---
00000010  b8 00 00 00 00 00 00 00  40 00 00 00 00 00 00 00  |........@.......|
          dQ--- dR----------------------------
00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
                                               dS---
00000030  00 00 00 00 00 00 00 00  00 00 00 00 80 00 00 00  |................|

Realistically, anything between 1A and 0x40 in this case could be considered free to use. The only thing the parser is looking for is that sweet sweet pointer to the PE header at 0x3C.

DOS Stub


This program will run on 16 bit machines, and serves the purpose of telling you that you can't run it there.

00000040  0e 1f ba 0e 00 b4 09 cd  21 b8 01 4c cd 21 54 68  |........!..L.!Th|
00000050  69 73 20 70 72 6f 67 72  61 6d 20 63 61 6e 6e 6f  |is program canno|
00000060  74 20 62 65 20 72 75 6e  20 69 6e 20 44 4f 53 20  |t be run in DOS |
00000070  6d 6f 64 65 2e 0d 0d 0a  24 00 00 00 00 00 00 00  |mode....$.......|

The stub disassembled: 

00000040    0e        push cs
00000041    1f        pop ds
00000042    ba 0e 00  mov dx, 0x000e   ; The string's address (relative)
00000045    b4 09     mov ah, 0x9      ; Write string to STDOUT syscall
00000047    cd 21     int 0x21         ; Call DOS API 
00000049    b8 01 4c  mov ax, 0x4c01   ; 4C is the exit syscall, 01 is the return value.
0000004C    cd 21     int 0x21

Note: These bytes for 16 bit x86, meaning that you can't normally disassemble these with certain disassemblers. Refer to any table of one byte x86 instructions for more info. Also, for more info on DOS Interrupts and the DOS API, check out here and here

PE Header (COFF)


The PE/COFF Header is remarkably pretty simple and straightforward in it's base form. The optional header is, optional... but most programs will require one. More on that in the next section. This section is present in both COFF object files before linking, and in PE files as well.

#   ADDR   Desc
------------------------------------------------------------------------------
pA  0x80   mMagic - PE Signature 
pB  0x84   mMachine
pC  0x86   mNumberOfSections
pD  0x88   mTimeDateStamp
pE  0x8C   mPointerToSymbolTable
pF  0x90   mNumberOfSymbols
pG  0x94   mSizeOfOptionalHeader
pH  0x96   mCharacteristics

------------------------------------------------------------------------------
          pA--------- pB--- pC---  pD--------- pE---------
00000080  50 45 00 00 64 86 09 00  86 85 00 00 00 00 00 00  |PE..d...........|
          pF--------- pG--- pH--- 
00000090  00 00 00 00 f0 00 2f 02                           |....../.

Optional Header


The optional header contains a lot more info.

#   ADDR   Desc
------------------------------------------------------------------------------
oA  0x98   Optional Header Magic - 0x020b for x86_64, 0x010b for x86
oB  0x9A   mMajorLinkerVersion
oC  0x9B   mMinorLinkerVersion
oD  0x9C   mSizeOfCode
oE  0xA0   mSizeOfInitializedData
oF  0xA4   mSizeOfUninitializedData
oG  0xA8   mAddressOfEntryPoint
oH  0xAC   mBaseOfCode 
oI  0xB0   mBaseOfData
oJ  0xB4   mImageBase
oK  0xB8   mSectionAlignment
oL  0xBC   mFileAlignment;
oM  0xC0   mMajorOperatingSystemVersion
oN  0xC2   mMinorOperatingSystemVersion
oO  0xC4   mMajorImageVersion
oP  0xC6   mMinorImageVersion
oQ  0xC8   mMajorSubsystemVersion
oR  0xCA   mMinorSubsystemVersion
oS  0xCC   mWin32VersionValue
oT  0xD0   mSizeOfImage
oU  0xD4   mSizeOfHeaders
oV  0xD8   mCheckSum
oW  0xDC   mSubsystem
oX  0xDE   mDllCharacteristics
oY  0xE0   mSizeOfStackReserve
oZ  0xE4   mSizeOfStackCommit
oAA 0xE8   mSizeOfHeapReserve
oAB 0xEC   mSizeOfHeapCommit
oAC 0xF0   mLoaderFlags
oAD 0xF4   mNumberOfRvaAndSizes

------------------------------------------------------------------------------
                                   oA--- oB oC oD---------
                                   0b 02 02 1a 00 1e 00 00  |....../.........|
          oE--------- oF---------  oG--------- oH---------
000000a0  00 1e 00 00 00 0a 00 00  10 15 00 00 00 10 00 00  |................|
          oI--------- oJ---------  oK--------- oL---------
000000b0  00 00 40 00 00 00 00 00  00 10 00 00 00 02 00 00  |..@.............|
          oM--- oN--- oO--- oP---  oQ--- oR--- oS---------
000000c0  04 00 00 00 00 00 00 00  05 00 02 00 00 00 00 00  |................|
          oT--------- oU---------  oV--------- oW--- oX---
000000d0  00 b0 00 00 00 04 00 00  04 de 00 00 03 00 00 00  |................|
          oY--------- oZ---------  oAA-------- oAB--------
000000e0  00 00 20 00 00 00 00 00  00 10 00 00 00 00 00 00  |.. .............|
          oAC-------- oAD--------
000000f0  00 00 10 00 00 00 00 00  00 10 00 00 00 00 00 00  |................|
00000100  00 00 00 00 10 00 00 00  00 00 00 00 00 00 00 00  |................|
00000110  00 80 00 00 fc 07 00 00  00 00 00 00 00 00 00 00  |................|
00000120  00 50 00 00 40 02 00 00  00 00 00 00 00 00 00 00  |.P..@...........|
00000130  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|

Section Headers


Each section has a 40 byte entry that has a consistent format. Here, they start at 0x188, and are one right after another.

#    Sz   Desc
------------------------------------------------------------------------------
sA   8    mName
sB   4    mVirtualSize
sC   4    mVirtualAddress
sD   4    mSizeOfRawData
sE   4    mPointerToRawData
sF   4    mPointerToRealocations
sG   4    mPointerToLinenumbers
sH   2    mNumberOfRealocations
sI   2    mNumberOfLinenumbers
sJ   4    mCharacteristics

00000150  20 a0 00 00 28 00 00 00  00 00 00 00 00 00 00 00  | ...(...........|
00000160  00 00 00 00 00 00 00 00  08 82 00 00 b8 01 00 00  |................|
00000170  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|

                                   sA---------------------
00000180  00 00 00 00 00 00 00 00  2e 74 65 78 74 00 00 00  |.........text...|
          sB--------- sC---------  sD--------- sE---------
00000190  90 1d 00 00 00 10 00 00  00 1e 00 00 00 04 00 00  |................|
          sF--------- sG---------  sH--- sI--- sJ---------
000001a0  00 00 00 00 00 00 00 00  00 00 00 00 20 00 50 60  |............ .P`|
          sA---------------------  sB--------- sC--------- 
000001b0  2e 64 61 74 61 00 00 00  90 00 00 00 00 30 00 00  |.data........0..|
          sD--------- sE---------  sF--------- sG---------
000001c0  00 02 00 00 00 22 00 00  00 00 00 00 00 00 00 00  |....."..........|
          sH--- sI--- sJ---------  sA---------------------
000001d0  00 00 00 00 40 00 50 c0  2e 72 64 61 74 61 00 00  |....@.P..rdata..|
          sB--------- sC---------  sD--------- sE---------
000001e0  50 08 00 00 00 40 00 00  00 0a 00 00 00 24 00 00  |P....@.......$..|
          sF--------- sG---------  sH--- sI--- sJ---------
000001f0  00 00 00 00 00 00 00 00  00 00 00 00 40 00 50 40  |............@.P@|
          sA---------------------  sB--------- sC--------- 
00000200  2e 70 64 61 74 61 00 00  40 02 00 00 00 50 00 00  |.pdata..@....P..|
          sD--------- sE---------  sF--------- sG---------
00000210  00 04 00 00 00 2e 00 00  00 00 00 00 00 00 00 00  |................|
          sH--- sI--- sJ---------  sA---------------------
00000220  00 00 00 00 40 00 30 40  2e 78 64 61 74 61 00 00  |....@.0@.xdata..|
          sB--------- sC---------  sD--------- sE---------
00000230  e8 01 00 00 00 60 00 00  00 02 00 00 00 32 00 00  |.....`.......2..|
          sF--------- sG---------  sH--- sI--- sJ---------
00000240  00 00 00 00 00 00 00 00  00 00 00 00 40 00 30 40  |............@.0@|

Further Reading