Home / Forums / Parsing PE Headers in Memory: DOS, NT, Optional Header & Section Table

UnreliableCode Community

Developer Research, Reverse Engineering & Coding Community

Tutorial

Parsing PE Headers in Memory: DOS, NT, Optional Header & Section Table

PEHeader
PE Format & Linker Tech
VIP
Rep: 350
Join Date: Jun 2023
Posts: 35
Thanks: 95
2y ago · Aug 11, 2024 11:25 AM
#1
Every 64-bit Windows dynamic link library (.dll) or executable (.exe) in memory follows the Portable Executable (PE) format.

Parsing Structure Hierarchy:
CPP
#include <windows.h>
#include <iostream>

void InspectPE(uintptr_t moduleBase) {
    // 1. DOS Header
    auto dosHeader = reinterpret_cast<PIMAGE_DOS_HEADER>(moduleBase);
    if (dosHeader->e_magic != IMAGE_DOS_SIGNATURE) return; // 'MZ'
    
    // 2. NT Headers (x64)
    auto ntHeaders = reinterpret_cast<PIMAGE_NT_HEADERS64>(moduleBase + dosHeader->e_lfanew);
    if (ntHeaders->Signature != IMAGE_NT_SIGNATURE) return; // 'PE'
    
    std::cout << "Entry Point RVA: 0x" << std::hex << ntHeaders->OptionalHeader.AddressOfEntryPoint << std::endl;
    std::cout << "Image Size: 0x" << ntHeaders->OptionalHeader.SizeOfImage << " bytes" << std::endl;
    
    // 3. Section Headers
    auto section = IMAGE_FIRST_SECTION(ntHeaders);
    for (WORD i = 0; i < ntHeaders->FileHeader.NumberOfSections; ++i, ++section) {
        char name[9] = { 0 };
        memcpy(name, section->Name, 8);
        std::cout << "Section: " << name 
                  << " | RVA: 0x" << section->VirtualAddress 
                  << " | Size: 0x" << section->Misc.VirtualSize << std::endl;
    }
}


This is the exact method used to locate the
CODE
.text
section boundaries when scanning for function signatures!
PEHeader | IMAGE_NT_HEADERS & Section Parsing
The following users thanked PEHeader for this post:
DisasmGeek
Capstone & Keystone Specialist
MEMBER
Rep: 160
Join Date: Dec 2024
Posts: 21
Thanks: 38
2y ago · Aug 11, 2024 2:02 PM
#2
Always remember to verify
CODE
e_lfanew
is within a sane range (< 0x1000) when inspecting corrupted or obfuscated binaries before dereferencing!
DisasmGeek · Capstone / Keystone Engine Integration
KernelDiver
Kernel & Systems Researcher
VIP
Rep: 275
Join Date: Jan 2024
Posts: 24
Thanks: 70
2y ago · Aug 11, 2024 4:45 PM
#3
Great foundational writeup. In memory-mapped PEs, the
CODE
VirtualAddress
and
CODE
VirtualSize
represent the runtime addresses, while
CODE
PointerToRawData
applies to on-disk files.
KernelDiver · Windows Internals & Page Tables