The Portable Executable (PE)file format has been around since the 1980s. As its name suggests it was designed to support different program types on different computers (not just Windows® and Intel). The first section is a legacy of these early days. Like all good file formats it starts off with a special marker value to indicate it is PE file format. It would be unsafe, particularly for programs for the system to 'run' anything just on the basis of an appropriate looking file type extension. In fact now all sorts of compatibility checks are made but the starting point is the first two bytes of a file, if it has the value 'MZ' then it is considered a possible PE file. 'MZ' happens to the initials of Mark Zbikowski one of the MSDOS developers. The only other value of interest in the first header section of a PE file is the field e_lfanew which refers to the extended PE file header. The MSDOS header allowed any Windows program that were accidentally run on MSDOS to at least report 'This program requires Windows' before terminating.
The PE Header first declares its type, for Windows this can be DOS, OS/2 or NT. A PE file is NT type and the value is PE. The NT Header has an IMAGE_FILE_HEADER part and an optional header (IMAGE_OPTIONAL_HEADER) part. The file header contains information about the processor type it will run on and most importantly the number of sections that make up the PE image file.
The optional header, is of course, not optional for the vast majority of applications. It contains a lot of attribute information about the program that is needed to be able to load it. Within the Optional Header is an array of IMAGE_DATA_DIRECTORY entries. These directories describe all the important non-executable attributes of the program image : functions imported, functions exported, the windows resources, the COR header (for .NET programs), Delayed load DLLs and many other rarer data structures.
The NT Header is followed by the section table that describes each section in the file. This includes its size, where it is within the PE file, where it should be loaded in memory and its characteristics.
Anatomy of a PE File
As the PE file has developed over many years it is full of idiosyncratic features. Many fields are now unused, having been put in as a possible future feature and never actually developed any further. One of the worst features is that the format has had to be adjusted for 64 bit images and so programs that analyze a 32bit program will not work with 64bit programs.
The purpose of the file is to act as a completely self-contained description of the program how to run it.
Although a PE File is just a sequence of bytes this does not reflect how the program will operate when loaded into memory. The code and data that make up a program are split into a number of sections, each section is loaded at a different base address within the program image. Each section of memory has different characteristics reflecting its usage : readable, executable, writable and other more specialized operations.
Each section is given a name and several names indicate the usage of the section. The linker puts together the contents of each section type from the compiled source that makes up the complete program.
|.text||Main program code- usually execute and read access only.|
|.data||Main initialized data code that is used by the program.|
|.rsrc||Contains the Windows Resource data.|
|.rdata||Read only data.|
|.idata||Imported function data.|
|.tls||Thread Local Storage. Data private to each thread.|
|.CRT||Data reserved for the 'C' Run-Time Libnrary.|
Viewing Sections with InspectExe
InspectExe lets you list all the section for any DLL or EXE file and various attributes read from the PE File header.
It also lets you dump out the contents of individual program sections.