Sitemap

Deep Dive Into Pe Structure Part 2

7 min readJun 14, 2026

--

part 1: https://medium.com/@rootuser62/deep-dive-into-pe-structure-51b900c226f7

Now Its Time To Adding Some Additional

introduction:
this part i want to add that in rick blog seem missing, when i read his blog its wonderful but sometime there a ton question leave in my mind that the answered doesnt exist in his blog. before i write someof add stuff maybe we can in this introduction part i put whatever thing to need to know:
- to get entry point in text section
EP = OptionalHeader.AddressOfEntryPoint-section.VirtualAddress+section.PointerToRawData
- to get offset memory use formula
off_mem = RVA-section.VirtualAddress+section.PointerToRawData

  1. Impor Data Section
    since msvc merge .idata to .rdata we must find it with offset to get thunkdata or function list for import or IAT/ILT. first we need take a look in Data Directories in Optional Header part from NTHeader.
    first we need to know IMAGEFILEDESCRIPTOR size and size is 20 byte
Press enter or click to view image in full size
section
Press enter or click to view image in full size
data directores

from my case in pic import directory (in #define it values is 1) address 0x113c4with size 0x3c then we compute with constant formula

desttination_address = RVA - section.VirtualAddress + section.PointerToRawData

to get IMAGE_IMPORT_DESCRIPTOR now formula become:

image_import_descriptor = 0x113c4 - rdata_section.VirtualAddress + rdata_section.PointerToRawData
image_import_descriptor = 0x113c4 - c000 + 5a8a

to know RVA which section range address to, just check is it RVA section.VirtualAddress ≤ RVA < section.VirtualAddress + section.VirtualSize
now from calculation we get offset 0xfbc4for image file descriptor, and same as pe bear:

Press enter or click to view image in full size
image file descriptor

because size is c4 we can seperate it each other with 20 byte size and get 2 image file descriptor and end in 0xfbc4+3c. one for kernel32 and user32.

ok next step is get IMAGE_THUNK_DATA32 struct like this:

typedef struct _IMAGE_THUNK_DATA {
union {
DWORD ForwarderStringl // RVA to forwarder string
uint32_t* Function; // address of imported function
uint32_t Ordinal; // ordinal value of function
int32_t AddressOfData; // RVA of imported name
} u1;
} IMAGE_THUNK_DATA, *PIMAGE_THUNK_DATA;

now we need get rva offset again with formula

image_thunk_data32 = image_import_descriptor.OriginalFirstThunk - rdata.VirtualAddress + rdata.PointerToRawData;
image_thunk_data32 = 0x11500 - c000 + a800

now we get value 0xfd00 which reference to thunk data with size 4 byte with terminate AddressOfData is 0 or 4 byte 0x00:

Press enter or click to view image in full size

next we get to IAT is import by ordinal or by name can use & bit in high bit of IMAGE_THUNK_DATA32.ordinal if set import by ordinal else import by name, here my case is import by name. IMAGE_THUNK_DATA32.AddressOfData == _IMAGE_IMPORT_BY_NAME

typedef struct _IMAGE_IMPORT_BY_NAME {
WORD Hint;
CHAR Name[1];
} IMAGE_IMPORT_BY_NAME, *PIMAGE_IMPORT_BY_NAME;

now get formula againt with import by name structure with formula

name = image_thunkdata32[i].AddressOfData - rdata.VirtualAddress + rdata.PointerToRawData +2
name = 0x000115BC - c000 + a800

note that this offset is 4th image_thunkdata32 now we get 0xfdbe for offset it reffer to BeginPaint function, as pebear show:

Press enter or click to view image in full size
fx

for first thunk can use this address:

import_function = 1158a — c000 + a800

get offset adress to fd8a and can iterate then from list

Get root user’s stories in your inbox

Join Medium for free to get updates from this writer.

Manually Analysis with Hex Tool
its not imposible to analysis with hex tool eg: hexdump,hxd,xd,etc. i try with hxd and must use note to trace my step:

  • from 0x00 start of address need to know 0x3c offset to get e_lfanew in my case is 32 bit app generally windows use little endian, i get 0xf8 offset:
Press enter or click to view image in full size
  • in 0xf8 offset go tooptional header with formula
    image_import = e_lfanew + nt_header.signature + sizeof file_header + optional_header.DataDirectory[1]
    note that check optional_header.NumberRvaSize to know number of array data directory. now in address get:
    image_import = 0xf8 + 4 + 0x14+ 0x60(before data directories) + 8(import datadirectories)
    get 0x178 offset 4 byte virtual address other 4 byte size:
Press enter or click to view image in full size
  • now need to get rdata section offset with formula:
    section_number_offset = e_lfanew + nt_header.signature +fileheader.SectionCount
    size_optional_header_offset = e_lfanew + nt_header.signature +fileheader.SizeOfOptionalHeader
    start_section_header_offset = e_lfanew + nt_header.signature +sizeof fileheader + sizeof optionalheader
    start_get_rdata_string_address_offset = start_section_header_offset +sectionheader[i]+0
    end_get_rdata_string_address_offset = start_section_header_offset +sectionheader[i]+8
    get_rdata_virtual_address_offset = rdata_section_header.VirtualAddress
    get_rdata_rawData_offset = rdata_section_header.PointerToRawData
    remember that to get_rdata_string need to check first 8 bytes from section header offset after optional header address if notmatch with .rdata string try search next 40byte from first section header till max of section count. now let get offset with formula:
    section_number_offset = 0xf8 + 4 + 4. == 0xfe
    size_optional_header_offset = 0xf8 + 4 + 0x10 == 0x10c
    start_section_header_offset = 0xf8 + 4 + 0x14 + 0xe0 == 0x1f0
    start_get_rdata_string_address_offset = 0x1f0 + 0x28 + 0 == 0x218
    end_get_rdata_string_address_offset = 0x1f0 + 0x28 + 8 == 0x220
    get_rdata_virtual_address_offset = 0x218 + 0xc == 224
    get_rdata_rawData_offset = 0x218 + 0x14 == 22c
    get_image_import_descriptor[0] = 113c4-c000+a800 == fbc4
    get_imageThunkData32[4] = 11500-c000+a800 == fd00+0x10
    get_import_name = 115bc-c000+a800+2 == fdbe
    in my case each offset value are:
    *fdbe value is ascii beginPaint 00
    *fbc4 value is 00 15 01 00 ….. till + c4
    *0x178 value is c4 13 01 00 3c 00 00 00
    *0xfe value is 04 00
    *0x10c value is e0 00
    *0x218-*0x220 value is “.rdata” rmaining 0x00
    *224 value is 00 c0 00 00
    *22c value is 00 a8 00 00
Press enter or click to view image in full size

Struct and Preprocessor

Dos Image Header

typedef struct _IMAGE_DOS_HEADER {      // DOS .EXE header
WORD e_magic; // Magic number
WORD e_cblp; // Bytes on last page of file
WORD e_cp; // Pages in file
WORD e_crlc; // Relocations
WORD e_cparhdr; // Size of header in paragraphs
WORD e_minalloc; // Minimum extra paragraphs needed
WORD e_maxalloc; // Maximum extra paragraphs needed
WORD e_ss; // Initial (relative) SS value
WORD e_sp; // Initial SP value
WORD e_csum; // Checksum
WORD e_ip; // Initial IP value
WORD e_cs; // Initial (relative) CS value
WORD e_lfarlc; // File address of relocation table
WORD e_ovno; // Overlay number
WORD e_res[4]; // Reserved words
WORD e_oemid; // OEM identifier (for e_oeminfo)
WORD e_oeminfo; // OEM information; e_oemid specific
WORD e_res2[10]; // Reserved words
LONG e_lfanew; // File address of new exe header
} IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;

Dos Stub

Dos Stub is 64 byte size,follow with rich header

NtHeader

typedef struct _IMAGE_NT_HEADERS64 {
DWORD Signature;
IMAGE_FILE_HEADER FileHeader;
IMAGE_OPTIONAL_HEADER64 OptionalHeader;
} IMAGE_NT_HEADERS64, *PIMAGE_NT_HEADERS64;

typedef struct _IMAGE_NT_HEADERS {
DWORD Signature;
IMAGE_FILE_HEADER FileHeader;
IMAGE_OPTIONAL_HEADER32 OptionalHeader;
} IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32;
ypedef struct _IMAGE_FILE_HEADER {
WORD Machine;
WORD NumberOfSections;
DWORD TimeDateStamp;
DWORD PointerToSymbolTable;
DWORD NumberOfSymbols;
WORD SizeOfOptionalHeader;
WORD Characteristics;
} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;
ypedef struct _IMAGE_OPTIONAL_HEADER {
//
// Standard fields.
//

WORD Magic;
BYTE MajorLinkerVersion;
BYTE MinorLinkerVersion;
DWORD SizeOfCode;
DWORD SizeOfInitializedData;
DWORD SizeOfUninitializedData;
DWORD AddressOfEntryPoint;
DWORD BaseOfCode;
DWORD BaseOfData;

//
// NT additional fields.
//

DWORD ImageBase;
DWORD SectionAlignment;
DWORD FileAlignment;
WORD MajorOperatingSystemVersion;
WORD MinorOperatingSystemVersion;
WORD MajorImageVersion;
WORD MinorImageVersion;
WORD MajorSubsystemVersion;
WORD MinorSubsystemVersion;
DWORD Win32VersionValue;
DWORD SizeOfImage;
DWORD SizeOfHeaders;
DWORD CheckSum;
WORD Subsystem;
WORD DllCharacteristics;
DWORD SizeOfStackReserve;
DWORD SizeOfStackCommit;
DWORD SizeOfHeapReserve;
DWORD SizeOfHeapCommit;
DWORD LoaderFlags;
DWORD NumberOfRvaAndSizes;
IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
} IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32;
typedef struct _IMAGE_OPTIONAL_HEADER64 {
WORD Magic;
BYTE MajorLinkerVersion;
BYTE MinorLinkerVersion;
DWORD SizeOfCode;
DWORD SizeOfInitializedData;
DWORD SizeOfUninitializedData;
DWORD AddressOfEntryPoint;
DWORD BaseOfCode;
ULONGLONG ImageBase;
DWORD SectionAlignment;
DWORD FileAlignment;
WORD MajorOperatingSystemVersion;
WORD MinorOperatingSystemVersion;
WORD MajorImageVersion;
WORD MinorImageVersion;
WORD MajorSubsystemVersion;
WORD MinorSubsystemVersion;
DWORD Win32VersionValue;
DWORD SizeOfImage;
DWORD SizeOfHeaders;
DWORD CheckSum;
WORD Subsystem;
WORD DllCharacteristics;
ULONGLONG SizeOfStackReserve;
ULONGLONG SizeOfStackCommit;
ULONGLONG SizeOfHeapReserve;
ULONGLONG SizeOfHeapCommit;
DWORD LoaderFlags;
DWORD NumberOfRvaAndSizes;
IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
} IMAGE_OPTIONAL_HEADER64, *PIMAGE_OPTIONAL_HEADER64;

Image Directory

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

Directory Entries

// Directory Entries

#define IMAGE_DIRECTORY_ENTRY_EXPORT 0 // Export Directory
#define IMAGE_DIRECTORY_ENTRY_IMPORT 1 // Import Directory
#define IMAGE_DIRECTORY_ENTRY_RESOURCE 2 // Resource Directory
#define IMAGE_DIRECTORY_ENTRY_EXCEPTION 3 // Exception Directory
#define IMAGE_DIRECTORY_ENTRY_SECURITY 4 // Security Directory
#define IMAGE_DIRECTORY_ENTRY_BASERELOC 5 // Base Relocation Table
#define IMAGE_DIRECTORY_ENTRY_DEBUG 6 // Debug Directory
// IMAGE_DIRECTORY_ENTRY_COPYRIGHT 7 // (X86 usage)
#define IMAGE_DIRECTORY_ENTRY_ARCHITECTURE 7 // Architecture Specific Data
#define IMAGE_DIRECTORY_ENTRY_GLOBALPTR 8 // RVA of GP
#define IMAGE_DIRECTORY_ENTRY_TLS 9 // TLS Directory
#define IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG 10 // Load Configuration Directory
#define IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT 11 // Bound Import Directory in headers
#define IMAGE_DIRECTORY_ENTRY_IAT 12 // Import Address Table
#define IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT 13 // Delay Load Import Descriptors
#define IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR 14 // COM Runtime descriptor

Image Section Header

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;

Image Import Descriptor

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

Image Bound Descriptor

typedef struct _IMAGE_BOUND_IMPORT_DESCRIPTOR {
DWORD TimeDateStamp;
WORD OffsetModuleName;
WORD NumberOfModuleForwarderRefs;
// Array of zero or more IMAGE_BOUND_FORWARDER_REF follows
} IMAGE_BOUND_IMPORT_DESCRIPTOR, *PIMAGE_BOUND_IMPORT_DESCRIPTOR;

Import By name

typedef struct _IMAGE_IMPORT_BY_NAME {
WORD Hint;
CHAR Name[1];
} IMAGE_IMPORT_BY_NAME, *PIMAGE_IMPORT_BY_NAME;

Image Relocation Descriptor

typedef struct _IMAGE_BASE_RELOCATION {
DWORD VirtualAddress;
DWORD SizeOfBlock;
} IMAGE_BASE_RELOCATION;
typedef IMAGE_BASE_RELOCATION UNALIGNED * PIMAGE_BASE_RELOCATION;

Image Thunk Data32

typedef struct _IMAGE_THUNK_DATA32 {
union {
DWORD ForwarderString; // Pointer to a forwarder string
DWORD Function; // Pointer to the function address
DWORD Ordinal; // Import ordinal (if MSB is set)
DWORD AddressOfData; // RVA to IMAGE_IMPORT_BY_NAME
} u1;
} IMAGE_THUNK_DATA32, *PIMAGE_THUNK_DATA32;

try write this article again if i have free time

--

--