🌵
Rotta
  • ☕General
    • About Me
    • Recently Added
  • ☣️Offensive Tool Development
    • Windows Internals
      • Registers
      • x64 Calling Convention
      • PE File Format
        • PE File Structure
        • DOS Header, DOS Stub, & Rich Header
        • NT Headers
        • Data Directories & Section Headers
        • Import Directory Table, ILT & IAT
        • Image Export Table
        • PE Base Relocations
      • Processes & PEB Structure
      • Threads & TEB Structure
      • Event Tracing for Windows (ETW)
        • Interacting with ETW
        • ETW Tools
    • Enumeration
      • Process Enumeration
        • CreateToolhelp32Snapshot
        • EnumProcesses (psapi.h)
        • NtQuerySystemInformation
        • NtQueryInformationProcess
      • Thread Enumeration
        • CreateToolhelp32Snapshot
        • NtQuerySystemInformation
      • DLL Enumeration
    • Memory Allocation
      • Private Memory Allocation
      • Memory Mapping
    • Access Tokens
      • Page 1
    • Techniques and Exploitation Methods
      • Thread Hijacking
      • DLL Injection
      • Shellcode Reflective DLL Injection
      • APC Injection
      • Callback Process Injection
      • Function Stomping
      • DLL Sideloading
      • Local PE Injection
      • Reflective DLL Injection
      • Process Hollowing
    • PE Tips & Tricks
      • Parsing PE Headers
      • Patching IAT
      • Patching Base Relocations
      • Fixing Memory Permissions
      • Embed an EXE inside a LNK
      • PE Infection
    • Staging
      • Fetch Payload from Web Server
      • Fetch DLL from Web Server
    • Bypassing AV
      • String Hashing
      • Hiding & Obfuscating IAT
      • Custom WINAPI Functions
        • GetProcAddressHash
      • File Bloating
    • Evading EDR
      • Payload Execution Control
      • Wrapping NTAPI Functions
        • NtCreateUserProcess
        • NtQuerySystemInformation
      • PPID Spoofing
      • Call Stack Spoofing
      • NTDLL Unhooking
        • NTDLL Unhooking - From Disk
        • NTDLL Unhooking - From KnownDlls
        • NTDLL Unhooking - From Suspended Process
        • NTDLL Unhooking - From Web Server
    • Anti-Analysis Techniques
      • Anti-Debugging Techniques
        • Check If Running In a Debugger
        • Self Deleting Malware
      • Anti-Virtual Environments (AVE) Techniques
        • Detecting Hardware Specs
        • Delaying Execution
        • API Hammering
      • Reducing Binary Entropy
      • Brute Forcing Decryption Key
      • Removing MSCRT
      • Hiding / Camouflaging IAT
    • API Hooking
      • Userland Hooking
      • Custom Hooking Function
      • Open-Source Hooking Libraries
        • Microsoft's Detours Library
        • MinHook Library
    • Syscalls
      • NTAPI Syscall Process Injection
      • Direct Syscalls
        • SysWhispers
      • Indirect Syscalls
    • C2 Development
      • Consensus & Design Patterns
      • Infrastructure
      • Teamserver
      • Listeners
      • Agent Stubs
      • Encrypting Communication
    • User Defined Reflective Loader (UDRL)
    • MalDev Environment Setup
      • Setting up Dev Box
      • Setting up Pwn Box
      • Setting up Dev Server
      • Commando VM
    • Maldev Checklist
  • 👺Red Teaming
    • Setting up Infrastructure
    • External Recon
    • Internal Recon & Enumeration
      • Host Reconnaissance
      • Host Enumeration
    • Password Attacks
      • Password Spraying OWA
    • Phishing / Initial Compromise
      • Setting up Infrastructure
      • Crafting the Email
      • EvilGinx
      • Browser In Browser Attack
      • MS Office Phishing
        • VBA Macro Beacon
        • Remote Template Injection
        • HTML Smuggling
    • Privilege Escalation
      • Windows Services
      • UAC Bypass
      • Elevated SYSTEM Persistence
    • Persistence
      • Scheduled Tasks
      • Registry AutoRun
      • Startup Folder
      • COM Hijacking
      • Elevated SYSTEM Persistence
    • Payload Delivery
      • MS Office Payloads
        • Mark of the Web (MOTW).
        • Visual Basic Macro (VBA)
        • Remote Template Injection
      • SCR File Attack
    • Stealing Credentials
      • MimiKatz
      • Rubeus
      • Page 2
    • Domain Reconnaissance
      • PowerView & SharpView
      • ADSearch
    • Lateral Movement
      • User Impersonation
        • Pass The Hash (PTH)
        • Pass The Ticket (PTT)
        • Overpass The Hash
        • Token Impersonation
        • Token Store
    • Kerberos & Active Directory Attacks
      • Kerberoasting
      • ASREP Roasting
      • Kerberos Relay Attacks
      • Shadow Credentials
      • Unconstrained Delegation
      • Constrained Delegation
    • Cobalt Strike
      • Start Team Server
      • Configure Listeners
      • Beacons
        • UDRLess Beacon
    • Cracking Passwords
    • Tools & Checklists
      • Commands Cheat Sheet
      • Tools
      • Red Team Checklist
  • 🪟Active Directory
    • Active Directory Toolkit
      • Windows Tools
        • ActiveDirectory PowerShell Module
        • PowerView
        • SharpHound/BloodHound
        • Snaffler
      • Kali Linux Tools
        • Windapsearch & Ldapsearch
        • CrackMapExec
        • SMBMap
        • rpcclient
        • Impacket Toolkit
        • Bloodhound
    • Enumerating Active Directory
      • net.exe
      • Powershell Active Directory Commands
      • Powershell & .NET Classes
      • PowerView / SharpView
      • Enumerating Service Accounts
      • Enumerating Object Permissions
      • Enumerating Objects
      • Active Directory Certificate Services (AD CS)
    • Attacking Active Directory Authentication
      • AS-REP Roasting
      • Kerberoasting
      • Silver Tickets
      • Domain Controller Synchronization (Dsync Attack)
      • Kerberos Relay Attack
      • NTLM Relay Attack
      • Attacking Service Accounts
    • Password Spraying
      • Enumeration & Retrieving Password Policy
      • Creating a Target User List
      • Brute Force / Password Spraying - Linux Tools
      • Internal Spraying - From Windows
    • Lateral Movement Techniques
      • WMI and WinRM
      • PsExec
      • Pass The Hash
      • Overpass The Hash
      • Pass The Ticket
      • DCOM
    • Persistence
      • Golden Ticket
      • Shadow Copies
    • God Access
      • GenericAll Abuse
      • NTDS Tom Foolery
    • Lab Environment Setup
      • Installing Forest
      • Adding Data to Active Directory
    • Templates & Cheat Sheets
  • 🦈Penetration Testing
    • Information Gathering / Reconnaisance
      • Client Fingerprinting
      • External Recon and Enumeration
      • Network Reconnaisance
        • Scanning for Hosts
        • Initial Enumeration of AD Network
        • SMB Network Shares
      • Vulnerability Scanning
        • Nessus
        • Nmap
      • Popped a Shell
    • Pivoting, Tunneling, and Port Forwarding
      • SSH
      • Socat
      • Pivoting
        • plink.exe
        • netsh
        • Web Server Pivoting with Rpivot
      • Tunneling
        • Chisel
        • sshuttle
        • Dnscat2
      • Double Pivots
        • RDP and SOCKS Tunneling with SocksOverRDP
    • Cracking Passwords
      • Password Cracking Prerequisites
      • Mutating Wordlists
        • Identifying & Building Rules
      • Password Managers
      • SSH Private Keys
      • NTLM Toolkit
      • NTLMv2
      • MS-Cachev2 (DCC2)
      • Password Protected Files
    • Windows Privilege Escalation
      • Initial Enumeration
      • Searching For Sensitive Files
      • Searching Logs & Event Viewer
      • Escalating Privilege
      • Leveraging Windows Services
        • Service Binary Hijacking
        • Service DLL Hijacking
        • Abusing Unquoted Paths
      • Scheduled Tasks
      • Enumerating Services & Tasks
      • Dumping Secrets
    • Linux Privilege Escalation
      • Initial Enumeration
      • Automated Enumeration
      • Searching For Sensitive Information
      • Insecure File Permissions
      • Insecure System Components
        • Abusing Setuid Binaries and Capabilities
        • Sudo Trickery
        • Kernel Vulnerabilities
      • Abusing Environment Variables
      • Escaping Jail
      • Wildcard Injection
    • Exploiting Microsoft Office
      • Phishing with Teams
      • Malicious Macros
      • Windows Library Files
    • Setting up Infrastructure
      • C2 Infrastructure
      • EvilGinx2 Phishing Infrastructure
    • Ex-filtrating Data
      • WebDAV
      • SMB
      • Converting files to Hex Strings
    • Phishing
      • OSCP Phishing Guide
    • Templates & Cheat Sheets
      • OSCP Cheat Sheet
      • Impacket Cheat Sheet
      • Useful Commands
      • Penetration Test Checklist
  • 🛡️Azure & M365
    • Information Gathering / Reconnaissance
      • Domain Enumeration
      • User Enumeration
      • AADInternals
    • Attacking Authentication
      • OWA Password Spraying
      • OAuth Abuse
    • Azure AD Killchain
    • Azure Lab Setup
    • Azure & M365 Checklist
  • 🥾Security Operation Center
    • Network Traffic Analysis
      • Tcpdump
      • Wireshark
    • Windows Event Logs
      • Sysmon
    • Event Tracing for Windows (ETW)
    • Microsoft 365 Defender
    • Splunk as SIEM
      • Using Splunk Applications
      • Search Processing Language (SPL) Commands
      • Hunting with Splunk
      • Intrusion Detection
    • Incident Response Process
    • MITRE ATT&CK Framework
      • Persistence
        • Registry Run Keys
    • Templates & Cheat Sheets
      • Interview Prep
  • 🔬Digital Forensics
    • Tools
  • 🔍Malware Analysis
    • Network Traffic Analysis
      • INetSim
    • Static Analysis
      • Signatures & Fingerprints
      • Pestudio
      • x64dbg
    • Dynamic Analysis
      • Noriben
    • Reverse Engineering / Code Analysis
      • IDA
      • x64dbg
      • Returning Source Code
        • .NET Binary
    • Creating Detection Rules
    • Tools
  • 🛠️Programming
    • MASM Assembly
    • Qt
      • Setting up Qt in CLion
    • Windows Development on MacOS
      • CLion Setup
    • Windows API
      • Deleting Files
      • Strings
      • wininet.h
      • Wrapping WinAPI Functions
      • code_seg
      • Locating WinAPI Functions - Tips
    • Visual Studio
      • Creating DLL's
      • Debug & Release Mode
    • Mingw
      • Windows Development
    • Position Independent Code (PIC)
      • Creating Shellcode
      • Debugging & Development Tips
      • Strings
      • Macros
      • PIC Checklist
  • 🏠Home Lab
    • Current Setup
Powered by GitBook
On this page
  • PE Structure
  • Access Local PEB (x64)
  • MSVC Intrinsic Function
  • NtCurrentTeb
  • NtQueryInformationProcess
  • PE Sections & Headeres
  • Parsing PE Headers
  • Parsing PE Sections
  • Adding PE Sections
  • Structuring our code
  • Populating _PE_HDRS struct
  • Relative Virtual Addresses (RVAs)
  • DOS Header (IMAGE_DOS_HEADER)
  • NT Header (IMAGE_NT_HEADER)
  • File Header (IMAGE_FILE_HEADER)
  • Optional Header (IMAGE_OPTIONAL_HEADER)
  • DataDirectory (IMAGE_DATA_DIRECTORY)
  • Export Table (IMAGE_EXPORT_DIRECTORY)
  • Import Table (IMAGE_IMPORT_DIRECTORY)
  • Parse Import Address Table
  • Additional Undocumented Structures
  • PE Sections (IMPORTANT)
  1. Offensive Tool Development
  2. PE Tips & Tricks

Parsing PE Headers

Understanding how PEs (portable executables) work is a crucial part of Windows exploitation. Whether we're developing evasive malware or reverse engineering, we need to understand how they work.

PreviousPE Tips & TricksNextPatching IAT

Last updated 7 months ago

PE Structure

Every header shown is a struct that holds information about the PE file.

Access Local PEB (x64)

MSVC Intrinsic Function

#include <winternl.h>
// Get PEB structure
#ifdef _WIN64
	PPEB pPeb = (PPEB)__readgsqword(0x60);
#elif _WIN32
	PPEB pPeb = (PPEB)__readfsdword(0x30);
#endif // _WIN64

// HELPER FUNCTIONS
// Get of current process (call pLdr->DllBase to get base address)
PLDR_DATA_TABLE_ENTRY pLdr = (PLDR_DATA_TABLE_ENTRY)((PBYTE)(pPeb->Ldr->InMemoryOrderModuleList.Flink) - 0x10);
// pLdr->DllBase (Entrypoint to .exe)

NtCurrentTeb

    // 64 bit
    P_TEB teb = (P_TEB)NtCurrentTeb();
    P_PEB peb  = (P_PEB)teb->ProcessEnvironmentBlock;
    
    // Getting Base Address
    PVOID pBaseAddress = peb->ImageBaseAddress;
    // Getting Ldr
    PPEB_LDR_DATA pLdr = (PPEB_LDR_DATA)(peb->Ldr);

NtQueryInformationProcess

typedef NTSTATUS (NTAPI *fnNtQueryInformationProcess)(
    HANDLE ProcessHandle,
    PROCESSINFOCLASS ProcessInformationClass,
    PVOID ProcessInformation,
    ULONG ProcessInformationLength,
    PULONG ReturnLength
);

int main(void) {
    fnNtQueryInformationProcess ntQueryPE = (fnNtQueryInformationProcess)GetProcAddress(GetModuleHandleW(L"ntdll.dll"), "NtQueryInformationProcess");

    PROCESS_BASIC_INFORMATION pbi;
    ULONG ulRetLength;
    NTSTATUS STATUS = ntQueryPE(GetCurrentProcess(), ProcessBasicInformation, &pbi, sizeof(pbi), &ulRetLength);
    if (STATUS != 0) {
        printf("NtQueryInformation Failed %ld", STATUS);
    }
    PPEB pPeb = (PPEB)pbi.PebBaseAddress;
    PLDR_DATA_TABLE_ENTRY pLdr = (PLDR_DATA_TABLE_ENTRY)((PBYTE)(pPeb->Ldr->InMemoryOrderModuleList.Flink) - 0x10);
    printf("%p", pLdr->DllBase); // Print base address of current process
}

PE Sections & Headeres

Parsing PE Headers

PE

Parsing PE Sections

Get Built In Sections

// Dos Header
PIMAGE_DOS_HEADER pImgDosHdr = (PIMAGE_DOS_HEADER)pPE;
if (pImgDosHdr->e_magic != IMAGE_DOS_SIGNATURE){
	return -1;
}
// Nt Header
PIMAGE_NT_HEADERS pImgNtHdrs = (PIMAGE_NT_HEADERS)(pPE + pImgDosHdr->e_lfanew);
if (pImgNtHdrs->Signature != IMAGE_NT_SIGNATURE) {
	return -1;
}

// IMAGE_FILE_HEADER
IMAGE_FILE_HEADER ImgFileHdr = pImgNtHdrs->FileHeader;
// POINTER FILE HEADER
PIMAGE_FILE_HEADER pFileHeader = (PIMAGE_FILE_HEADER)(pBaseAddress + pDosHeader->e_lfanew + sizeof(DWORD));

PIMAGE_OPTIONAL_HEADER pOptionalHeader = (PIMAGE_OPTIONAL_HEADER)(pBaseAddress + pDosHeader->e_lfanew + sizeof(DWORD)+sizeof(IMAGE_FILE_HEADER));

PIMAGE_SECTION_HEADER pSectionHeader = (PIMAGE_SECTION_HEADER)(pBaseAddress + pDosHeader->e_lfanew + sizeof(IMAGE_NT_HEADERS));

Loop through all sections

Adding PE Sections

Structuring our code

One common way to structure code when parsing a Portable Executable is to create a struct that holds all data and headers for the PE.

typedef struct _PE_HDRS
{
	PBYTE                    pFileBuffer; // Buffer from ReadFile
	DWORD                    dwFileSize;  // Size of file from GetFileSize

	PIMAGE_NT_HEADERS        pImgNtHdrs;
	PIMAGE_SECTION_HEADER    pImgSecHdr;

	PIMAGE_DATA_DIRECTORY    pEntryImportDataDir;
	PIMAGE_DATA_DIRECTORY    pEntryBaseRelocDataDir;
	PIMAGE_DATA_DIRECTORY    pEntryTLSDataDir;
	PIMAGE_DATA_DIRECTORY    pEntryExceptionDataDir;
	PIMAGE_DATA_DIRECTORY    pEntryExportDataDir;

	BOOL                     bIsDLLFile;

} PE_HDRS, *PPE_HDRS;

Then when we parse each header we add it to the struct.

Populating _PE_HDRS struct

Here's an example of a function we can use to parse the PE filebuffer we are working with into our struct above. For more information read below.

BOOL InitializePeStruct(OUT PPE_HDRS pPeHdrs, IN PBYTE pFileBuffer, IN DWORD dwFileSize) {

	if (!pPeHdrs || !pFileBuffer || !dwFileSize)
              return FALSE;

	pPeHdrs->pFileBuffer              = pFileBuffer;
	pPeHdrs->dwFileSize               = dwFileSize;
	pPeHdrs->pImgNtHdrs               = (PIMAGE_NT_HEADERS)(pFileBuffer + ((PIMAGE_DOS_HEADER)pFileBuffer)->e_lfanew);

	if (pPeHdrs->pImgNtHdrs->Signature != IMAGE_NT_SIGNATURE)
             return FALSE;

	pPeHdrs->bIsDLLFile               = (pPeHdrs->pImgNtHdrs->FileHeader.Characteristics & IMAGE_FILE_DLL) ? TRUE : FALSE;
	pPeHdrs->pImgSecHdr               = IMAGE_FIRST_SECTION(pPeHdrs->pImgNtHdrs);
	pPeHdrs->pEntryImportDataDir      = &pPeHdrs->pImgNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT];
	pPeHdrs->pEntryBaseRelocDataDir   = &pPeHdrs->pImgNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];
	pPeHdrs->pEntryTLSDataDir         = &pPeHdrs->pImgNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS];
	pPeHdrs->pEntryExceptionDataDir   = &pPeHdrs->pImgNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXCEPTION];
	pPeHdrs->pEntryExportDataDir      = &pPeHdrs->pImgNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];

	return TRUE;
}

Relative Virtual Addresses (RVAs)

Relative Virtual Addresses are addresses used to reference locations within a PE file. For example, specifying the location of code, data, and resources.

IMPORTANT: An RVA is a 32-bit value that specifies the offset of a data structure or section from the beginning of the PE file. Hence relative because it specifies the offset from the beginning of the file, rather than an absolute memory address.

The PE header contains several RVAs that specify the location of the code and data sections, the import and export tables, and other important data structures.

DOS Header (IMAGE_DOS_HEADER)

The DOS header is located at the beginning of the PE file and contains information about the file, such as its size, and characteristics. But most importantly, it contains the RVA (offset) to the NT header.

Retrieve DOS Header (IMAGE_DOS_HEADER):

// Pointer to the structure 
PIMAGE_DOS_HEADER pImgDosHdr = (PIMAGE_DOS_HEADER)pPE;
	
if (pImgDosHdr->e_magic != IMAGE_DOS_SIGNATURE){
	return -1;
}

NOTE: Since the DOS header is at the very beginning of a PE file, retrieving the value is only a matter of getting a pointer. (pPE).

NT Header (IMAGE_NT_HEADER)

The e_lfanew member of the DOS header is an RVA to the IMAGE_NT_HEADERS structure.

Retrieve NT Header (IMAGE_NT_HEADER):

// Pointer to the structure
PIMAGE_NT_HEADERS pImgNtHdrs = (PIMAGE_NT_HEADERS)(pPE + pImgDosHdr->e_lfanew);

if (pImgNtHdrs->Signature != IMAGE_NT_SIGNATURE) {
	return -1;
}

File Header (IMAGE_FILE_HEADER)

Since the file header is a member of the IMAGE_NT_HEADERS structure, it can be accessed using the following line of code.

IMAGE_FILE_HEADER		ImgFileHdr	= pImgNtHdrs->FileHeader;

Optional Header (IMAGE_OPTIONAL_HEADER)

Since the optional header is a member of the IMAGE_NT_HEADERS structure, it is can be accessed using the following code.

Retrieve Optional Header (IMAGE_OPTIONAL_HEADER):

IMAGE_OPTIONAL_HEADER	ImgOptHdr = pImgNtHdrs->OptionalHeader;

if (ImgOptHdr.Magic != IMAGE_NT_OPTIONAL_HDR_MAGIC) {
	return -1;
}

NOTE: Depending on the compiler architecture, the IMAGE_NT_OPTIONAL_HDR_MAGIC constant will automatically expand to the correct value:

  • IMAGE_NT_OPTIONAL_HDR32_MAGIC - 32-bit

  • IMAGE_NT_OPTIONAL_HDR64_MAGIC - 64-bit

DataDirectory (IMAGE_DATA_DIRECTORY)

The Data Directory can be accessed from the optional's header last member. This is an array of IMAGE_DATA_DIRECTORY meaning each element in the array is an IMAGE_DATA_DIRECTORY structure that references a special data directory. The IMAGE_DATA_DIRECTORY structure is shown below.

typedef struct _IMAGE_DATA_DIRECTORY {
    DWORD   VirtualAddress;
    DWORD   Size;
} IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;

The fields of the structure contain information such as:

  • VirtualAddress - Specifies the virtual address of the specified structure in the PE file, these are RVAs.

  • Size - Specifies the size of the data directory.

Export Table (IMAGE_EXPORT_DIRECTORY)

This structure is not officially documented by Microsoft. You will need to use unofficial documentation.\

Export Table Structure

The export table is a structure defined as IMAGE_EXPORT_DIRECTORY which is shown below.

typedef struct _IMAGE_EXPORT_DIRECTORY {
    DWORD   Characteristics;
    DWORD   TimeDateStamp;
    WORD    MajorVersion;
    WORD    MinorVersion;
    DWORD   Name;
    DWORD   Base;
    DWORD   NumberOfFunctions;
    DWORD   NumberOfNames;
    DWORD   AddressOfFunctions;     // RVA from base of image
    DWORD   AddressOfNames;         // RVA from base of image
    DWORD   AddressOfNameOrdinals;  // RVA from base of image
} IMAGE_EXPORT_DIRECTORY, *PIMAGE_EXPORT_DIRECTORY;

Retrieving The Export Table

The IMAGE_EXPORT_DIRECTORY structure is used to store information about the functions and data that are exported from a PE file. This information is stored in the data directory array with the index IMAGE_DIRECTORY_ENTRY_EXPORT. To fetch it from the IMAGE_OPTIONAL_HEADER structure:

Retrieve Export Table:

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

Import Table (IMAGE_IMPORT_DIRECTORY)

The import address table is an array of IMAGE_IMPORT_DESCRIPTOR structures with each one being for a DLL file that contains the functions that were used from these DLLs.

Import Address Table Structure

typedef struct _IMAGE_IMPORT_DESCRIPTOR {
    union {
        DWORD   Characteristics;
        DWORD   OriginalFirstThunk;
    } DUMMYUNIONNAME;
    DWORD   TimeDateStamp;
    DWORD   ForwarderChain;
    DWORD   Name;
    DWORD   FirstThunk;
} IMAGE_IMPORT_DESCRIPTOR;

Retrieving The Import Address Table

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

Parse Import Address Table

Here is an example of crudely parsing an IAT. To iterate through the IAT we add the size of IMAGE_DATA_DIRECTORY with every iteration until we reach a NULLified version. (Represents the end). (View Local PE Injection & Reflective DLL Injection for reference).

BOOL ParseImportAddressTable(IN PIMAGE_DATA_DIRECTORY pEntryImportDataDir, IN PBYTE pPeBaseAddress) {
    for (SIZE_T i =0; i < pEntryImportDataDir->Size; i+=sizeof(IMAGE_IMPORT_DESCRIPTOR)) {
        PIMAGE_IMPORT_DESCRIPTOR currentImport = (PIMAGE_IMPORT_DESCRIPTOR)(pPeBaseAddress + pEntryImportDataDir->VirtualAddress + i);
        wprintf(L"%s\n", pPeBaseAddress + currentImport->Name);
        if (currentImport-> FirstThunk == 0 && currentImport->OriginalFirstThunk == 0)
            break
    }
}

Alternatively we can use the common SectionFromRVA & Rva2Offset method which determines what section an RVA resides in by iterating through each section and calculating the difference.

Additional Undocumented Structures

Several undocumented structures can be accessed via the IMAGE_DATA_DIRECTORY array in the optional header but are not documented in the Winnt.h header file.

PIMAGE_TLS_DIRECTORY pImgTlsDir  = (PIMAGE_TLS_DIRECTORY)(pPE + ImgOptHdr.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress);

IMAGE_RUNTIME_FUNCTION_ENTRY - This structure is used to store information about a runtime function in the PE file.

PIMAGE_RUNTIME_FUNCTION_ENTRY pImgRunFuncEntry = (PIMAGE_RUNTIME_FUNCTION_ENTRY)(pPE + ImgOptHdr.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXCEPTION].VirtualAddress);

IMAGE_BASE_RELOCATION - This structure is used to store information about the base relocations in the PE file.

PIMAGE_BASE_RELOCATION pImgBaseReloc = (PIMAGE_BASE_RELOCATION)(pPE + ImgOptHdr.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress);

PE Sections (IMPORTANT)

Structure of a PE Sections (.text, .data, .reloc, .rsrc)

typedef struct _IMAGE_SECTION_HEADER {
  BYTE  Name[IMAGE_SIZEOF_SHORT_NAME];
  union {
    DWORD PhysicalAddress;
    DWORD VirtualSize;
  } Misc;
  DWORD VirtualAddress;
  DWORD SizeOfRawData;
  DWORD PointerToRawData;
  DWORD PointerToRelocations;
  DWORD PointerToLinenumbers;
  WORD  NumberOfRelocations;
  WORD  NumberOfLinenumbers;
  DWORD Characteristics;
} IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER;

IMPORTANT:** IMAGE_SECTION_HEADER Important Members**

Some of IMAGE_SECTION_HEADER's most important members;

  • Name - A null-terminated ASCII string that specifies the name of the section.

  • VirtualAddress - The virtual address of the section in memory, this is an RVA.

  • SizeOfRawData - The size of the section in the PE file in bytes.

  • PointerToRelocations - The file offset of the relocations for the section.

  • NumberOfRelocations - The number of relocations for the section.

  • Characteristics - Contains flags that specify the characteristics of the section.

Retrieving The IMAGE_SECTION_HEADER Structure

The IMAGE_SECTION_HEADER structure is stored in an array within the PE file's headers. To access the first element, skip past the IMAGE_NT_HEADERS since the sections are located immediately after the NT headers. The following snippet shows how to retrieve the IMAGE_SECTION_HEADER structure, where pImgNtHdrs is a pointer to IMAGE_NT_HEADERS structure.

PIMAGE_SECTION_HEADER pImgSectionHdr = (PIMAGE_SECTION_HEADER)(((PBYTE)pImgNtHdrs) + sizeof(IMAGE_NT_HEADERS));

Looping Through The Array

Looping through the array requires the array size which can be retrieved from the IMAGE_FILE_HEADER.NumberOfSections member. The subsequent elements in the array are located at an interval of sizeof(IMAGE_SECTION_HEADER) from the current element.

PIMAGE_SECTION_HEADER pImgSectionHdr = (PIMAGE_SECTION_HEADER)(((PBYTE)pImgNtHdrs) + sizeof(IMAGE_NT_HEADERS));

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
}

We will need to include our own & objects (PTEB_A & PPEB_A)

The IMAGE_IMPORT_DESCRIPTOR structure is also not officially documented by Microsoft although it is defined in the as follows:

IMAGE_TLS_DIRECTORY - This structure is used to store information about (TLS) data in the PE file.

☣️
PEB
TEB
Winnt.h Header File
Thread-Local Storage