PE Header file crafting_
PE Header file crafting_
The PE file format described at its most basic is a wrapper with information for the windows loader, which envelops
an executable image. This information allows the windows loader to place the executable image and its associated
resources into memory so that execution can begin and resources can be correctly accessed. Using a description of the
PE file layout it is possible to produce a valid PE file, which is accepted by the windows loader even without an
executable image present. The best description of the PE layout available is the ARTeam PE Tutorial authored by
Goppit . Using the information from this tutorial I decided to build a PE file from scratch in a Hex editor in order to
better understand the structure of the file. It is definitely best to follow this tutorial with a hex editor open and filled in
as you go as well as a PE tutorial for full explanation of the sections.
First thing is to make a file of arbitrary size but greater than 0x400 or 1024 bytes as we wish to produce an executable
image inside later. I made a file 0x540 or 1334 bytes in size. IT should be full of zeroes to start with.
The first section of the file is the DOS header which has only 2 essential elements
In OllyDBG this is shown with the elements annotated with the DOS information which is irrelevant to a windows PE
executable so they can be left as zero. As we are not likely to run the executable we produce it is not necessary to
include any DOS stuff in the header.
As you can see from the above OllyDBG PE header information only the 2 offsets mentioned above have been filled in
.
The PE header
At offset 0x044 is a word which signifies the Processor or CPU for which the file is designed – bytes 0x4C & 0x01 -
0x014C signifying the 80386 and above Processor type.
Offset 0x046 gives the number of Sections present in the file. We are only going to provide a single section for this
executable, a decision which will be explained in the second part of the tutorial.
At the next offset [0x048] is a DWORD (DD) which contains the TimeDateStamp. It is not necessary to fill this in and
in fact, the values present I inserted with the editor from PETools later when the full executable was completed.
The next 2 DWORDS [offsets 0x04C & 0x050] are zero as there are no symbols present in the file.
The size of the Optional Header is 0xE0 or 224 bytes and this is defined by the WORD at offset [0x054].
The data for setting the File Characteristics [ offset 0x056 ] was obtained from the Windows.inc file which is part of the
MASM32 package.
IMAGE_SIZEOF_FILE_HEADER equ 20
IMAGE_FILE_RELOCS_STRIPPED equ 0001h
IMAGE_FILE_EXECUTABLE_IMAGE equ 0002h
IMAGE_FILE_LINE_NUMS_STRIPPED equ 0004h
IMAGE_FILE_LOCAL_SYMS_STRIPPED equ 0008h
IMAGE_FILE_AGGRESIVE_WS_TRIM equ 0010h
IMAGE_FILE_LARGE_ADDRESS_AWARE equ 0020h
IMAGE_FILE_BYTES_REVERSED_LO equ 0080h
IMAGE_FILE_32BIT_MACHINE equ 0100h
IMAGE_FILE_DEBUG_STRIPPED equ 0200h
IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP equ 0400h
IMAGE_FILE_NET_RUN_FROM_SWAP equ 0800h
IMAGE_FILE_SYSTEM equ 1000h
IMAGE_FILE_DLL equ 2000h
The next part of the PE header is the Optional Header and its size is defined by the WORD value at offset 0x54 as seen
above. The Optional Header includes the Data Directory but we shall look at the Data Directory separately [offsets
0x0B8 to 0x134].
The information relating to this region of the file is shown in the following OllyDBG output
The MagicNumber is the code which says the file is PE32 format. The bytes are 0x0B 0x01 at offset 0x058.
The Major and Minor LinkerVersions can both be zero – the values 0x05 and 0x0C I got from a MASM32 assembled
file.
The size of the file is 0x540 bytes and the Code Section begins at offset 0x200, therefore, at offset 0x05C
(SizeOfCode) the value needed is the difference i.e. 0x340. As this is a DWORD 0x40 0x03 0x00 0x00 is the necessary
order of the bytes.
As there is no DATA section the next 2 DWORDS can be left as all zeroes.
The EntryPoint of the code is going to be at offset 0x200, therefore, at offset 0x68 the bytes need to be 0x00 0x02 0x00
0x00. As this is also the BaseOfCode is the same value as the EntryPoint, therefore, the same bytes are entered at offset
0x6C.
There is no DATA section so its base is left as DWORD 0x00000000 at offset 0x070
The Image Base of PE files is usually at 0x00400000 so offset 0x074 is set to 0x00 0x00 0x40 0x00.
The SectionAlignment and FileAlignment are both set at 0x200 so at offsets 0x078 and 0x7C the bytes 0x00 0x02 0x00
0x00 are entered.
In most files I have examined MajorOsVersion is 0x04 0x00, however, I chose 0x01 0x00 for the WORD at offset
0x080. It works on my version of XP SP2.
The next 3 WORDs are 0x0000. This does not affect the working of the PE executable.
The WORD at 0x088 is the MajorSubsystemVersion. In all files I have examined the bytes are 0x04 0x00. I have tried
other values and received the error that the executable is not a valid Win32 PE file.
Offset 0x90 is the DWORD specifying the size of the PE file on disk. It has already been chosen at 0x540 so at the
offset is typed 0x40 0x05 0x00 0x00.
The SizeOfHeaders value should have been 0x154 but 0x150 seems to work fine so offset 0x094 can be typed as 0x50
0x01 0x00 0x00.
Offset at 0x09C is the windows subsystem on which the executable is to be run. It is a WORD value and the value for
the Windows GUI is 2. Therefore the bytes typed are 0x02 0x00.
As the file we are building is not a DLL the WORD at offset 0x09E is 0x0000.
The next 4 DWORDs I took from a MASM32 executable as the figures seemed reasonable. They should be input as
follows:
Offset Bytes
0x0A0 0x00 0x00 0x10 0x00
0x0A4 0x00 0x40 0x00 0x00
0x0A8 0x00 0x00 0x10 0x00
0x0AC 0x00 0x10 0x00 0x00
The DWORD value at offset 0x0B4 is 0x10000000 i.e. 16 decimal as this is the number of 8 byte sections which
compose the Data Directory, which follows immediately after this DWORD at offset 0x0B8. This is always 16 and
corresponds to the information given by LordPE when the Directories option is chosen.
As can be seen from the above 2 illustrations only one of the 16 Data directories contains any data and this is the Import
Table at offset 0x0C0. This is the only absolutely essential directory in order to produce a valid PE file. From the Hex
editor printout it can be seen that the bytes present at offset 0x0c0 are 0x00 0x04 0x00 0x00. this corresponds to the
value seen in the LordPE illustration as 0x00000400 and indicatesthat the Import Address Table begins at offset
0x0400. The contents of the Import Address Table will be discussed later. For further illustration of the Data Directory
read the PE file tutorial or the MessageBoxA.asm.pdf document which accompanies this one.
It will be seen that the Import Table has zero size. This was an oversight on my part but it has not affected the validity
of the file as the import is revealed by LordPE as will be seen later.
Following the Data Directory is the Section Table where the code and data sections reside. As we only have one
section the table will be rather short.
The first part of the Section Table is the name of the section. This can be any set of 8 byte values or 8 zero bytes.
OllyDBG gives an excellent description of this section also.
I chose to use the full 8 bytes for a section name, which is clearly seen from the printouts.
Of the next 4 DWORDs 2 are lies due to the fact that I added an extra 64 bytes to the end of the file. So the VirtualSize
of section NECROtAC is given as 0x300 bytes in size as is the SizeOfRawData. As the file executed fine and was
accepted as a valid PE file I have just noticed this. But as the file is padded from the actual end to the next multiple of
the value of the file alignment (0x200) the extra data is loaded and the file works. Do not make the same sloppy error in
your file. That said the sequence of bytes at offsets 0x0140 and 0x0148 are 0x00 0x03 0x00 0x00.
At offset 0x0144 is the VirtualAddress which because of FileAlignment, SectionAlignment and BaseOFCode all being
set at 0x200 is also 0x200. Therefore the byte sequence here is 0x00 0x02 0x00 0x00. The same is true for the
sequence of bytes at offset 0x014C the PointerTORawData.
The DWORDs at offsets 0x0150 and 0x0154 plus the WORDs at offsets 0x0158 and 0x15A are all set to zero as none
of the elements they refer to are present.
The characteristics DWORD at offset 0x015c should contain the bytes 0x00 0x00 0x00 0xE0 which is the following
characteristics values summed
The 2 which is probably a typo as I have no idea where it came from, is stated by LordPE to mean NOLOAD
That is the end of the Headers part of the file. The final thing we need to do is provide an Import Address Table as the
Windows loader requires at least one DLL to be referenced by an executable file to recognise it as a valid PE file. The
API from the DLL does not need to be called. I have chosen the DLL comctl32.dll and the API
InitCommonControlsEx. The reason for this is that I wished to ‘manually’ load and reference dlls in the executable part
of the file and show that kernel32.dll can be accessed without being present in the Import Address Table.
That is all that is required for a valid PE file. However if we try to execute it an error will occur due to only zero bytes
being present at the entrypoint of the executable part of the file. But if the file is loaded into OllyDBG it is accepted as
a valid PE executable and breaks on the address 0x200. I put a value of 0xC3 at offset 0x0200 which is the opcode for
the RET instruction which returns control to the the kernel32.dll.
Part 2 Adding an executable section with OllyDBG
The ARTeam PE tutorial has sections on adding code to an executable and adding imports to an executable so I will not
go over old ground. The code I produce here will show a simple Message Box. But as has been noticed there is no
reference to kernell32.dll in the Import Table, only comdlg32 which we will not even call. However the Windows
loader will overwrite the DWORD at offset 0x0438 with the address in memory of the function
InitCommonControlsEx, which you wil notice if you load the PE file already produced into OllyDBG.
If you have looked closely at the initial windows present when OllyDBG loads a file you may have noticed that the
value at the top of the Stack window is an address in the kernel32.dll address space. This can be used to find the base
address of this DLL and hence any functions we wish to import from it. You may think that GetProcAddress would be
the first to obtain but it is not necessary at all as will be seen in the code. I have tried to comment the code as copiously
as possible so that long winded explanation is unnecessary.
The above code will not work on Win9x/ME due to the kernel32.dll being loaded at a much higher address.
The 2 functions we wish to load the addresses of from kernel32.dll are LoadLibraryA and Free Library and for showing
a Message Box we need MessageBoxA from user32.dll. We also need a title and message for the Message Box.
The above data were added to the file in the Hex editor. In UltraEdit I annotated the OllyDBG output as follows
The storage areas for the DLL base addresses and funtion addresses are also indicated in the above illustration.
So far the code typed has found the kernel32.dll image base and found and stored the addresses of the 2 required
functions. In order to show a Message Box we need to import the function MessageBoxA from the DLL user32.dll.
Using the LoadLibraryA function imported from kernel32.dll we can load the DLL user32.dll. The return value from
this function returns a handle to the function which is also the base address of the function. So we store this handle so
that we can subsequently reference it. If we had imported GetProcAddress from kernel32.dll we could use that to find
the address of the MessageBoxA function. However, we have no need of it as seen when retrieving function addresses
from kernel32.dll. As the handle to user32.dll is also the base address of the DLL we can use the same method to find
the function we need as we use to find the functions in kernel32.dll. In light of this the following code is less
comprehensively annotated than the previous code example.
Code for the second part of the executable section of the PE file
Once the MessageBoxA function address has been found it is stored at DWORD 0x004004A0 + 4. After pushing the
necessary parameters for MessageBoxA on the stack the function itself is called indirectly via a pointer to its stored
address. When the Message Box has been dismissed user32.dll is no longer needed so using its handle it is freed by a
call to FreeLibrary. Finally the stack is returned to its state at the program entry point and control is returned to
kernel32.dll to terminate the program.
Although the visual aspect of the program is extremely limited in scope a number of programming techniques have
been shown which may be new to some beginners in the art of both assembler programming and cracking. I hope I
have shown how OllyDBG can be used as an assembler which together with a PE format template can produce an
executable Windows file of very small size, as well as showing how to import API functions, which may be used in
patch code, added to a file to be amended when the kernel32.dll is not loaded implicitly in the programs import section.
Best wishes
InsaneFIDO