Dissecting the PE Header [Windows PE Internals]
Tags: cybersecurity, security
Published: 2021-04-24 05:37:00

# Previous Windows PE Internals Writeups
1. [Creating a Windows Project in Visual Studio](https://dev.to/wireless90/creating-a-windows-project-in-visual-studio-windows-pe-internals-2p6e)
2. [Getting a Handle to a Dynamically Linked Library ](https://dev.to/wireless90/getmodulehandlea-windows-pe-internals-1b0l)
3. [Validating the MZ Signature](https://dev.to/wireless90/getting-the-windows-pe-internals-kka/)
4. [Validating the PE Signature](https://dev.to/wireless90/validating-the-pe-signature-my-av-flagged-me-windows-pe-internals-2m5o/)


# Previously

In the [previous article](https://dev.to/wireless90/validating-the-pe-signature-my-av-flagged-me-windows-pe-internals-2m5o/), we learnt about how do we validate the `PE Signature`, also commonly referred to as the `File Signature`, which tells us that the file is very likely, a `Portable Executable (PE) file.`

This signature is `PE\0\0` (the letters "P" and "E" followed by two null bytes).

We have also seen how to navigate our way from the `IMAGE_DOS_HEADER` into the `IMAGE_NT_HEADER`

We also saw that the `IMAGE_NT_HEADER` comprises of 3 parts.
- PE Signature
- PE Header
- Optional Header

We will be dissecting the `PE Header` in this article.

# Let's Begin

Following the PE Signature, we have the PE Header.

![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/23a3ajgmhf06kfe4woca.png)

As the `PE Header` is one of the subsection of the `IMAGE_NT_HEADER`, we can easily retrieve as such.

```cpp
PIMAGE_FILE_HEADER imageFileHeader = &imageNtHeaders->FileHeader;
```

Taking a deeper look into the PE Header, we have the following sections.

![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/co9vygr5af9b4p3eizz4.png)
 
In visual studio, we can see the matching fields as well.

![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4ynajhel0t14dpzmthmn.png)

## Let's write some code to visualize these information

```cpp
wsprintfA(c + strlen(c), "Number of Symbols: %d\n", imageFileHeader->NumberOfSymbols);
wsprintfA(c + strlen(c), "Pointer to Symbol Table: 0x%02X\n", imageFileHeader->PointerToSymbolTable);
wsprintfA(c + strlen(c), "Number of Sections: %hd\n", imageFileHeader->NumberOfSections);
wsprintfA(c + strlen(c), "TimeDateStamp: %d\n", imageFileHeader->TimeDateStamp);
wsprintfA(c + strlen(c), "Size of Optional Header: %hd\n", imageFileHeader->SizeOfOptionalHeader);
wsprintfA(c + strlen(c), "Machine: 0x%02X\n", imageFileHeader->Machine);
wsprintfA(c + strlen(c), "Characteristix: 0x%02X\n", imageFileHeader->Characteristics);

MessageBoxA(0, c, "PE Header", MB_OK | MB_ICONINFORMATION);
```

And the result is,

![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ul9ii6f03z1cmjz1ay0b.png)

 
## Number of Symbols

This is deprecated and should contain 0.

## Pointer to symbol table

This is also deprecated and should contain 0.

## Number of sections

Sections will be covered in another article. This field basically stores the number of sections.

## TimeDateStamp

The number of seconds that has passed from epoch since the file creation.

## Size of Optional Headers

The `Optional Header` comes after the `PE Header`. We will discuss it in other articles.

## Machine

The number that identifies the type of target machine that this executable was compiled for.

Looking into `winnt.h`, 
```cpp
#define IMAGE_FILE_MACHINE_I386              0x014c  // Intel 386.
// omitted
#define IMAGE_FILE_MACHINE_AMD64             0x8664  // AMD64 (K8)
```

Visual studio always runs in a 32bit emulator while debugging even though I am using a 64 bit machine. Thus it shows as `0x014c` which is a `32 bit` executable.

# Characteristics

We can use tools like `CFF Explorer` to understand this.
![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qeyhpoe1ehscm789gse1.png)

As expected, all of these macros can be found in `winnt.h`.

```cpp
#define IMAGE_FILE_RELOCS_STRIPPED           0x0001  // Relocation info stripped from file.
#define IMAGE_FILE_EXECUTABLE_IMAGE          0x0002  // File is executable  (i.e. no unresolved external references).
#define IMAGE_FILE_LINE_NUMS_STRIPPED        0x0004  // Line nunbers stripped from file.
#define IMAGE_FILE_LOCAL_SYMS_STRIPPED       0x0008  // Local symbols stripped from file.
#define IMAGE_FILE_AGGRESIVE_WS_TRIM         0x0010  // Aggressively trim working set
#define IMAGE_FILE_LARGE_ADDRESS_AWARE       0x0020  // App can handle >2gb addresses
#define IMAGE_FILE_BYTES_REVERSED_LO         0x0080  // Bytes of machine word are reversed.
#define IMAGE_FILE_32BIT_MACHINE             0x0100  // 32 bit word machine.
#define IMAGE_FILE_DEBUG_STRIPPED            0x0200  // Debugging info stripped from file in .DBG file
#define IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP   0x0400  // If Image is on removable media, copy and run from the swap file.
#define IMAGE_FILE_NET_RUN_FROM_SWAP         0x0800  // If Image is on Net, copy and run from the swap file.
#define IMAGE_FILE_SYSTEM                    0x1000  // System File.
#define IMAGE_FILE_DLL                       0x2000  // File is a DLL.
#define IMAGE_FILE_UP_SYSTEM_ONLY            0x4000  // File should only be run on a UP machine
#define IMAGE_FILE_BYTES_REVERSED_HI         0x8000  // Bytes of machine word are reversed.
```

The overall code would look like,

```cpp
#include <Windows.h>

int  WinMain(
    HINSTANCE hInstance,
    HINSTANCE hPrevInstance,
    LPSTR     lpCmdLine,
    int       nCmdShow
)
{
    HMODULE peBase = GetModuleHandleA("user32.dll");

    if (peBase == NULL)
    {
        MessageBoxA(0, "Can't load user32.dll", "Error", MB_OK | MB_ICONERROR);
        return 1;
    }

    PIMAGE_DOS_HEADER imageDosHeader = (PIMAGE_DOS_HEADER)peBase;

    if (imageDosHeader->e_magic != IMAGE_DOS_SIGNATURE)
    {
        MessageBoxA(0, "user32.dll has the wrong Image Dos Signature!", "Error", MB_OK | MB_ICONERROR);
        return 1;
    }

    PIMAGE_NT_HEADERS imageNtHeaders = (PIMAGE_NT_HEADERS)((unsigned char*)imageDosHeader + imageDosHeader->e_lfanew);

    if (imageNtHeaders->Signature != IMAGE_NT_SIGNATURE)
    {
        MessageBoxA(0, "user32.dll has the wrong PE Signature!", "Error", MB_OK | MB_ICONERROR);
        return 1;
    }

    PIMAGE_FILE_HEADER imageFileHeader = &imageNtHeaders->FileHeader;

    char buffer[1024 * 20] = { 0 };

    wsprintfA(buffer + strlen(buffer), "Number of Symbols: %d\n", imageFileHeader->NumberOfSymbols);
    wsprintfA(buffer + strlen(buffer), "Pointer to Symbol Table: 0x%02X\n", imageFileHeader->PointerToSymbolTable);
    wsprintfA(buffer + strlen(buffer), "Number of Sections: %hd\n", imageFileHeader->NumberOfSections);
    wsprintfA(buffer + strlen(buffer), "TimeDateStamp: %d\n", imageFileHeader->TimeDateStamp);
    wsprintfA(buffer + strlen(buffer), "Size of Optional Header: %hd\n", imageFileHeader->SizeOfOptionalHeader);
    wsprintfA(buffer + strlen(buffer), "Machine: 0x%02X\n", imageFileHeader->Machine);
    wsprintfA(buffer + strlen(buffer), "Characteristix: 0x%02X\n", imageFileHeader->Characteristics);

    MessageBoxA(0, buffer, "PE Header", MB_OK | MB_ICONINFORMATION);

    return 0;
}
```
In this article, we have understood the meaning behind each field in the PE Header.


# Next
[Exploring the Export Table](https://dev.to/wireless90/exploring-the-export-table-windows-pe-internals-4l47)