1. Portable Executable Structure

https://www.linkedin.com/pulse/understanding-portable-executable-pe-files-malware-ignatius-michael/

So much credit to this guy.
https://library.mosse-institute.com/articles/2022/05/reverse-engineering-portable-executables-pe-part-2/reverse-engineering-portable-executables-pe-part-2.html
![](/img/user/Attack Computer/Attack Windows/1. Windows Basic/attachments/Pasted image 20250310083349.png)

![](/img/user/Attack Computer/Attack Windows/1. Windows Basic/attachments/Pasted image 20250310083411.png)

1. Portable Executable - PE

The Portable Executable (PE) format is used for executables (.exe), dynamic-link libraries (.dll), and other system files in Windows. It contains various headers and sections that define how the file should be loaded and executed.

Overall, concept.

graph TD
  A[DOS Headers -- IMAGE_DOS_HEADER] -->|e_lfanew _File Offset_| B[NT Headers -- IMAGE_NT_HEADERS]
  B --> C[File Header -- IMAGE_FILE_HEADER]
  B --> D[Optional Header -- IMAGE_OPTIONAL_HEADER]
  D --> E[Data Directories _Contain RVAs_]
  E --> F[Export Table RVA]
  E --> G[Import Table RVA]
  E --> H[Resource Table RVA]
  D --> I[Section Table -- IMAGE_SECTION_HEADER]
  I --> J[.text - RVA]
  I --> K[.data - RVA]
  I --> L[.rdata - RVA]

graph TD
  A[Start of PE File _pPE_] --> B[IMAGE_DOS_HEADER]
  B -->|e_lfanew _File Offset_| C[IMAGE_NT_HEADERS]
  C --> D[Signature _PE\0\0_]
  D -->|Check if 0x00004550| E[Valid PE File?]
  E -->|Yes| F[Process PE Headers]
  E -->|No| G[Return -1 _Invalid PE_]

Relative Virtual Addresses (RVAs)

1.1 PE Structure

A PE file consists of:


DOS/MZ Header

// Pointer to the structure 
PIMAGE_DOS_HEADER pImgDosHdr = (PIMAGE_DOS_HEADER)pPE;		
//pPE is a pointer to the start of the PE file in memory
//This casts pPE into a pointer of type PIMAGE_DOS_HEADER (which is IMAGE_DOS_HEADER*).
//The Cast: (PIMAGE_DOS_HEADER)pPE takes the memory address stored in pPE and tells the compiler, "Treat this address as the starting point of an IMAGE_DOS_HEADER structure."
//interpreting the memory that pPE points to as being laid out in the format of an IMAGE_DOS_HEADER structure.
//This allows structured access to the PE file's DOS Header fields.

Visualization of (PIMAGE_DOS_HEADER)pPE : Type Casting

Why Casting?
This allows structured access to the PE file's DOS Header fields. Without casting, pPE is just a void* or BYTE* (raw memory).
The Cast: (PIMAGE_DOS_HEADER)pPE takes the memory address stored in pPE and tells the compiler, "Treat this address as the starting point of an IMAGE_DOS_HEADER structure."

graph TD
  A[Raw Memory pPE] -->|Cast to| B[PIMAGE_DOS_HEADER]
  B -->|Access Fields| C[e_magic MZ]
  B -->|Access Fields| D[e_lfanew NT Headers Offset]

Overall:

// Pointer to the structure 
PIMAGE_DOS_HEADER pImgDosHdr = (PIMAGE_DOS_HEADER)pPE;		
//pPE is a pointer to the start of the PE file in memory
//This casts pPE into a pointer of type PIMAGE_DOS_HEADER (which is IMAGE_DOS_HEADER*).
//The Cast: (PIMAGE_DOS_HEADER)pPE takes the memory address stored in pPE and tells the compiler, "Treat this address as the starting point of an IMAGE_DOS_HEADER structure."
//interpreting the memory that pPE points to as being laid out in the format of an IMAGE_DOS_HEADER structure.
//This allows structured access to the PE file's DOS Header fields.

if (pImgDosHdr->e_magic != IMAGE_DOS_SIGNATURE){
	return -1;
}
graph TD
  A[Start of PE File -- _pPE_] --> B[IMAGE_DOS_HEADER]
  B -->|Check e_magic == MZ| C[Valid DOS Header?]
  C -->|Yes| D[Proceed to e_lfanew]
  C -->|No| E[Return -1 _Invalid PE_]

NT Header

PIMAGE_NT_HEADERS pImgNtHdrs = (PIMAGE_NT_HEADERS)(pPE + pImgDosHdr->e_lfanew);

//(pPE + pImgDosHdr->e_lfanewso) this is telling pPE (base) + e_flanew(offset) will be  interpreted into PIMAGE_NT_HEADER format

if (pImgNtHdrs->Signature != IMAGE_NT_SIGNATURE) {
	return -1;
}
//IMAGE_NT_SIGNATURE is a predefined value "PE\0\0"

Let's break it down - IMAGE_NT_HEADERS

typedef struct _IMAGE_NT_HEADERS {
    DWORD Signature;                  // "PE\0\0"
    IMAGE_FILE_HEADER FileHeader;     // 20 bytes
    IMAGE_OPTIONAL_HEADER32 OptionalHeader; // Varies (e.g., 224 bytes for PE32)
} IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32;

// For 64-bit (PE32+), it’s IMAGE_NT_HEADERS64 with IMAGE_OPTIONAL_HEADER64
IMAGE_FILE_HEADER Structure
typedef struct _IMAGE_FILE_HEADER {
    WORD  Machine;              // 2 bytes - Target machine type
    WORD  NumberOfSections;     // 2 bytes - Number of sections in the PE file
    DWORD TimeDateStamp;        // 4 bytes - File creation timestamp
    DWORD PointerToSymbolTable; // 4 bytes - Offset to the symbol table (deprecated)
    DWORD NumberOfSymbols;      // 4 bytes - Number of symbols in the table (deprecated)
    WORD  SizeOfOptionalHeader; // 2 bytes - Size of the optional header
    WORD  Characteristics;      // 2 bytes - Flags defining file characteristics
} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;
Field Size Description
Machine 2 bytes The type of machine for which the PE file or object file is intended.
NumberOfSections 2 bytes The number of sections in the PE file or object file.
TimeDateStamp 4 bytes Time and date when the PE file or object file was created.
PointerToSymbolTable 4 bytes Offset in the file to the symbol table, if it exists.
NumberOfSymbols 4 bytes Number of symbols in the symbol table.
SizeOfOptionalHeader 2 bytes The size of the optional header.
Characteristics 2 bytes The characteristics of the PE file or object file. Defined by IMAGE_FILE_* constants to specify the file type (.exe, .dll, .sys).
IMAGE_OPTIONAL_HEADER
typedef struct _IMAGE_OPTIONAL_HEADER32 {
    WORD  Magic;                          // 2 bytes
    BYTE  MajorLinkerVersion;             // 1 byte
    BYTE  MinorLinkerVersion;             // 1 byte
    DWORD SizeOfCode;                      // 4 bytes
    DWORD SizeOfInitializedData;           // 4 bytes
    DWORD SizeOfUninitializedData;         // 4 bytes
    DWORD AddressOfEntryPoint;             // 4 bytes
    DWORD BaseOfCode;                      // 4 bytes
    DWORD BaseOfData;                      // 4 bytes
    DWORD ImageBase;                       // 4 bytes
    DWORD SectionAlignment;                // 4 bytes
    DWORD FileAlignment;                   // 4 bytes
    WORD  MajorOperatingSystemVersion;     // 2 bytes
    WORD  MinorOperatingSystemVersion;     // 2 bytes
    WORD  MajorImageVersion;               // 2 bytes
    WORD  MinorImageVersion;               // 2 bytes
    WORD  MajorSubsystemVersion;           // 2 bytes
    WORD  MinorSubsystemVersion;           // 2 bytes
    DWORD Win32VersionValue;               // 4 bytes
    DWORD SizeOfImage;                     // 4 bytes
    DWORD SizeOfHeaders;                   // 4 bytes
    DWORD CheckSum;                        // 4 bytes
    WORD  Subsystem;                       // 2 bytes
    WORD  DllCharacteristics;              // 2 bytes
    DWORD SizeOfStackReserve;              // 4 bytes
    DWORD SizeOfStackCommit;               // 4 bytes
    DWORD SizeOfHeapReserve;               // 4 bytes
    DWORD SizeOfHeapCommit;                // 4 bytes
    DWORD LoaderFlags;                     // 4 bytes
    DWORD NumberOfRvaAndSizes;             // 4 bytes
    IMAGE_DATA_DIRECTORY DataDirectory[16]; // 128 bytes
} IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32;

typedef struct _IMAGE_OPTIONAL_HEADER64 {
    WORD  Magic;                          // 2 bytes
    BYTE  MajorLinkerVersion;             // 1 byte
    BYTE  MinorLinkerVersion;             // 1 byte
    DWORD SizeOfCode;                      // 4 bytes
    DWORD SizeOfInitializedData;           // 4 bytes
    DWORD SizeOfUninitializedData;         // 4 bytes
    DWORD AddressOfEntryPoint;             // 4 bytes
    DWORD BaseOfCode;                      // 4 bytes
    ULONGLONG ImageBase;                   // 8 bytes (different from 32-bit)
    DWORD SectionAlignment;                // 4 bytes
    DWORD FileAlignment;                   // 4 bytes
    WORD  MajorOperatingSystemVersion;     // 2 bytes
    WORD  MinorOperatingSystemVersion;     // 2 bytes
    WORD  MajorImageVersion;               // 2 bytes
    WORD  MinorImageVersion;               // 2 bytes
    WORD  MajorSubsystemVersion;           // 2 bytes
    WORD  MinorSubsystemVersion;           // 2 bytes
    DWORD Win32VersionValue;               // 4 bytes
    DWORD SizeOfImage;                     // 4 bytes
    DWORD SizeOfHeaders;                   // 4 bytes
    DWORD CheckSum;                        // 4 bytes
    WORD  Subsystem;                       // 2 bytes
    WORD  DllCharacteristics;              // 2 bytes
    ULONGLONG SizeOfStackReserve;          // 8 bytes (different from 32-bit)
    ULONGLONG SizeOfStackCommit;           // 8 bytes (different from 32-bit)
    ULONGLONG SizeOfHeapReserve;           // 8 bytes (different from 32-bit)
    ULONGLONG SizeOfHeapCommit;            // 8 bytes (different from 32-bit)
    DWORD LoaderFlags;                     // 4 bytes
    DWORD NumberOfRvaAndSizes;             // 4 bytes
    IMAGE_DATA_DIRECTORY DataDirectory[16]; // 128 bytes
} IMAGE_OPTIONAL_HEADER64, *PIMAGE_OPTIONAL_HEADER64;

Field Description
Magic Specifies the type of optional header present in the file.
MajorLinkerVersion & MinorLinkerVersion Version of the linker used to create the PE file.
SizeOfCode Size of the code section in the PE file.
SizeOfInitializedData Size of the initialized data section in the PE file.
SizeOfUninitializedData Size of the uninitialized data section in the PE file.
AddressOfEntryPoint RVA of the entry point function in the PE file.
BaseOfCode RVA of the base address of the code section.
BaseOfData (Only in 32-bit) RVA of the base address of the data section.
ImageBase Preferred base address at which the PE file should be loaded.
MajorOperatingSystemVersion & MinorOperatingSystemVersion Minimum OS version required to run the PE file.
MajorImageVersion & MinorImageVersion Version of the PE file.
DataDirectory An array of IMAGE_DATA_DIRECTORY, which contains important directories in the PE file.
DataDirectory (IMAGE_DATA_DIRECTORY)
typedef struct _IMAGE_DATA_DIRECTORY {
    DWORD VirtualAddress;  // 4 bytes - RVA of the table
    DWORD Size;            // 4 bytes - Size of the table in bytes
} IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;

Index Directory Entry Description
0 IMAGE_DIRECTORY_ENTRY_EXPORT Contains information about the functions and data that are exported from the PE file.
1 IMAGE_DIRECTORY_ENTRY_IMPORT Contains information about the functions and data that are imported from other modules.
2 IMAGE_DIRECTORY_ENTRY_RESOURCE Contains information about the resources (such as icons, strings, and bitmaps) that are included in the PE file.
3 IMAGE_DIRECTORY_ENTRY_EXCEPTION Contains information about the exception handling tables in the PE file.
4 IMAGE_DIRECTORY_ENTRY_SECURITY Contains digital signature data.
5 IMAGE_DIRECTORY_ENTRY_BASERELOC Holds base relocation entries for address adjustments.
6 IMAGE_DIRECTORY_ENTRY_DEBUG Contains debugging information.
7 IMAGE_DIRECTORY_ENTRY_ARCHITECTURE Reserved, usually unused.
8 IMAGE_DIRECTORY_ENTRY_GLOBALPTR Used for IA64 architecture, generally not present.
9 IMAGE_DIRECTORY_ENTRY_TLS Contains Thread Local Storage (TLS) data.
10 IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG Holds system security settings and mitigation policies.
11 IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT Lists precomputed binding information for imports.
12 IMAGE_DIRECTORY_ENTRY_IAT Stores addresses of imported functions for runtime resolution.
13 IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT Stores delayed-load import information.
14 IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR Used for .NET assemblies.
15 IMAGE_DIRECTORY_ENTRY_RESERVED Unused, reserved for future use.
// IMAGE_EXPORT_DIRECTORY - Stores information about exported functions and data
typedef struct _IMAGE_EXPORT_DIRECTORY {
    DWORD   Characteristics;
    DWORD   TimeDateStamp;
    WORD    MajorVersion;
    WORD    MinorVersion;
    DWORD   Name;                    // RVA to the name of the module
    DWORD   Base;                    // Starting ordinal number
    DWORD   NumberOfFunctions;        // Total number of exported functions
    DWORD   NumberOfNames;            // Number of exported function names
    DWORD   AddressOfFunctions;       // RVA to function address array
    DWORD   AddressOfNames;           // RVA to function names array
    DWORD   AddressOfNameOrdinals;    // RVA to function ordinals array
} IMAGE_EXPORT_DIRECTORY, *PIMAGE_EXPORT_DIRECTORY;

// IMAGE_IMPORT_DESCRIPTOR - Stores information about imported functions and modules
typedef struct _IMAGE_IMPORT_DESCRIPTOR {
    union {
        DWORD   Characteristics;
        DWORD   OriginalFirstThunk;  // RVA to the import lookup table
    } DUMMYUNIONNAME;
    DWORD   TimeDateStamp;
    DWORD   ForwarderChain;
    DWORD   Name;                     // RVA to the name of the DLL
    DWORD   FirstThunk;                // RVA to the import address table (IAT)
} IMAGE_IMPORT_DESCRIPTOR, *PIMAGE_IMPORT_DESCRIPTOR;

// IMAGE_RESOURCE_DIRECTORY - Stores resource data such as icons, bitmaps, strings
typedef struct _IMAGE_RESOURCE_DIRECTORY {
    DWORD   Characteristics;
    DWORD   TimeDateStamp;
    WORD    MajorVersion;
    WORD    MinorVersion;
    WORD    NumberOfNamedEntries;
    WORD    NumberOfIdEntries;
} IMAGE_RESOURCE_DIRECTORY, *PIMAGE_RESOURCE_DIRECTORY;

// IMAGE_EXCEPTION_DIRECTORY - Stores exception handling information
typedef struct _IMAGE_RUNTIME_FUNCTION_ENTRY {
    DWORD BeginAddress;
    DWORD EndAddress;
    DWORD UnwindData;  // RVA to unwind information
} IMAGE_RUNTIME_FUNCTION_ENTRY, *PIMAGE_RUNTIME_FUNCTION_ENTRY;

// IMAGE_SECURITY_DIRECTORY - Stores digital signature data
typedef struct _WIN_CERTIFICATE {
    DWORD dwLength;
    WORD  wRevision;
    WORD  wCertificateType; // WIN_CERT_TYPE_PKCS_SIGNED_DATA
    BYTE  bCertificate[1];  // Certificate data
} WIN_CERTIFICATE, *PWIN_CERTIFICATE;

// IMAGE_BASERELOC_DIRECTORY - Stores base relocation data
typedef struct _IMAGE_BASE_RELOCATION {
    DWORD   VirtualAddress;  // RVA of the page that needs relocation
    DWORD   SizeOfBlock;     // Size of this relocation block
} IMAGE_BASE_RELOCATION, *PIMAGE_BASE_RELOCATION;

// IMAGE_DEBUG_DIRECTORY - Stores debugging information
typedef struct _IMAGE_DEBUG_DIRECTORY {
    DWORD   Characteristics;
    DWORD   TimeDateStamp;
    WORD    MajorVersion;
    WORD    MinorVersion;
    DWORD   Type;
    DWORD   SizeOfData;
    DWORD   AddressOfRawData;
    DWORD   PointerToRawData;
} IMAGE_DEBUG_DIRECTORY, *PIMAGE_DEBUG_DIRECTORY;

// IMAGE_ARCHITECTURE_DIRECTORY - Reserved, usually unused
typedef struct _IMAGE_ARCHITECTURE_ENTRY {
    DWORD FixupInstRVA;
    DWORD NewInst;
} IMAGE_ARCHITECTURE_ENTRY, *PIMAGE_ARCHITECTURE_ENTRY;

// IMAGE_GLOBALPTR_DIRECTORY - Used for IA64 architecture
typedef struct _IMAGE_GLOBALPTR {
    DWORD VirtualAddress;
} IMAGE_GLOBALPTR, *PIMAGE_GLOBALPTR;

// IMAGE_TLS_DIRECTORY - Stores Thread Local Storage (TLS) data
typedef struct _IMAGE_TLS_DIRECTORY {
    DWORD   StartAddressOfRawData;
    DWORD   EndAddressOfRawData;
    DWORD   AddressOfIndex;
    DWORD   AddressOfCallBacks;  // RVA to an array of TLS callback functions
    DWORD   SizeOfZeroFill;
    DWORD   Characteristics;
} IMAGE_TLS_DIRECTORY, *PIMAGE_TLS_DIRECTORY;

// IMAGE_LOAD_CONFIG_DIRECTORY - Stores system security settings
typedef struct _IMAGE_LOAD_CONFIG_DIRECTORY {
    DWORD   Size;
    DWORD   TimeDateStamp;
    WORD    MajorVersion;
    WORD    MinorVersion;
    DWORD   GlobalFlagsClear;
    DWORD   GlobalFlagsSet;
    DWORD   CriticalSectionDefaultTimeout;
    DWORD   DeCommitFreeBlockThreshold;
    DWORD   DeCommitTotalFreeThreshold;
    DWORD   LockPrefixTable;
    DWORD   MaximumAllocationSize;
    DWORD   VirtualMemoryThreshold;
    DWORD   ProcessHeapFlags;
    DWORD   Reserved[2];
} IMAGE_LOAD_CONFIG_DIRECTORY, *PIMAGE_LOAD_CONFIG_DIRECTORY;

// IMAGE_BOUND_IMPORT_DESCRIPTOR - Stores bound import information
typedef struct _IMAGE_BOUND_IMPORT_DESCRIPTOR {
    DWORD   TimeDateStamp;
    WORD    OffsetModuleName;
    WORD    NumberOfModuleForwarderRefs;
} IMAGE_BOUND_IMPORT_DESCRIPTOR, *PIMAGE_BOUND_IMPORT_DESCRIPTOR;

// IMAGE_IMPORT_ADDRESS_TABLE - Stores imported function addresses
typedef struct _IMAGE_IMPORT_ADDRESS_TABLE {
    DWORD   FunctionRVA;
} IMAGE_IMPORT_ADDRESS_TABLE, *PIMAGE_IMPORT_ADDRESS_TABLE;

// IMAGE_DELAY_IMPORT_DESCRIPTOR - Stores delayed import information
typedef struct _IMAGE_DELAY_IMPORT_DESCRIPTOR {
    DWORD Attributes;
    DWORD Name;
    DWORD ModuleHandle;
    DWORD ImportAddressTable;
    DWORD ImportNameTable;
    DWORD BoundImportAddressTable;
    DWORD UnloadInformationTable;
    DWORD TimeStamp;
} IMAGE_DELAY_IMPORT_DESCRIPTOR, *PIMAGE_DELAY_IMPORT_DESCRIPTOR;

// IMAGE_COM_DESCRIPTOR - Used for .NET assemblies
typedef struct _IMAGE_COR20_HEADER {
    DWORD   cb;
    WORD    MajorRuntimeVersion;
    WORD    MinorRuntimeVersion;
    IMAGE_DATA_DIRECTORY MetaData;
    DWORD   Flags;
    DWORD   EntryPointToken;
    IMAGE_DATA_DIRECTORY Resources;
    IMAGE_DATA_DIRECTORY StrongNameSignature;
} IMAGE_COR20_HEADER, *PIMAGE_COR20_HEADER;

How to call.

PIMAGE_EXPORT_DIRECTORY pImgExportDir = (PIMAGE_EXPORT_DIRECTORY)(pPE + ImgOptHdr.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);



IMAGE_IMPORT_DESCRIPTOR* pImgImpDesc = (PIMAGE_IMPORT_DESCRIPTOR)(pPE + ImgOptHdr.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);



PE Sections

PE sections define different parts of an executable file.

Section Description
.text Contains executable code.
.data Holds global and static variables.
.reloc Stores base relocation entries.
.rsrc Contains resources like icons, bitmaps, and version information.

Each section has an IMAGE_SECTION_HEADER structure that provides metadata about the section.


IMAGE_SECTION_HEADER Structure

typedef struct _IMAGE_SECTION_HEADER {
  BYTE  Name[IMAGE_SIZEOF_SHORT_NAME]; // Section name (ASCII, null-terminated)
  union {
    DWORD PhysicalAddress;
    DWORD VirtualSize;
  } Misc;
  DWORD VirtualAddress;        // RVA of section in memory
  DWORD SizeOfRawData;         // Size of section in the PE file
  DWORD PointerToRawData;      // File offset to section data
  DWORD PointerToRelocations;  // File offset to relocations
  DWORD PointerToLinenumbers;  // File offset to line numbers
  WORD  NumberOfRelocations;   // Number of relocations
  WORD  NumberOfLinenumbers;   // Number of line numbers
  DWORD Characteristics;       // Section attributes (executable, readable, writable, etc.)
} IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER;

Retrieving the IMAGE_SECTION_HEADER Structure

  1. The IMAGE_SECTION_HEADER array is stored immediately after IMAGE_NT_HEADERS
PIMAGE_SECTION_HEADER pImgSectionHdr = (PIMAGE_SECTION_HEADER)(((PBYTE)pImgNtHdrs) + sizeof(IMAGE_NT_HEADERS));
  1. Loop through sections using IMAGE_FILE_HEADER.NumberOfSections.

Looping Through PE Sections

PIMAGE_SECTION_HEADER pImgSectionHdr = (PIMAGE_SECTION_HEADER)(((PBYTE)pImgNtHdrs) + sizeof(IMAGE_NT_HEADERS));
/* 
pImgNtHdrs is a pointer to an IMAGE_NT_HEADERS structure, which contains details about the PE file, including its sections.



sizeof(IMAGE_NT_HEADERS) moves the pointer past the NT Headers to reach the start of the IMAGE_SECTION_HEADER array.

(PBYTE)pImgNtHdrs ensures byte-wise pointer arithmetic (since pImgNtHdrs is a struct pointer). PBYTE is a pointer to a BYTE, which is an unsigned 8-bit integer (typedef unsigned char BYTE;).

Final Effect: pImgSectionHdr now points to the first section header in the PE file.

*/*

for (size_t i = 0; i < pImgNtHdrs->FileHeader.NumberOfSections; i++) {
    // pImgSectionHdr is a pointer to section 1
    pImgSectionHdr = (PIMAGE_SECTION_HEADER)((PBYTE)pImgSectionHdr + (DWORD)sizeof(IMAGE_SECTION_HEADER));
    // pImgSectionHdr is a pointer to section 2
}