HyperDbg Debugger
Loading...
Searching...
No Matches
pe-image-reader.h File Reference

Bounded in-memory Portable Executable reader. More...

Go to the source code of this file.

Classes

struct  _IMAGE_DOS_HEADER
struct  _IMAGE_FILE_HEADER
struct  _IMAGE_SECTION_HEADER
struct  _PE_IMAGE_READER

Macros

#define IMAGE_SIZEOF_SHORT_NAME   8

Typedefs

typedef struct _IMAGE_DOS_HEADER IMAGE_DOS_HEADER
typedef struct _IMAGE_DOS_HEADERPIMAGE_DOS_HEADER
typedef struct _IMAGE_FILE_HEADER IMAGE_FILE_HEADER
typedef struct _IMAGE_FILE_HEADERPIMAGE_FILE_HEADER
typedef struct _IMAGE_SECTION_HEADER IMAGE_SECTION_HEADER
typedef struct _IMAGE_SECTION_HEADERPIMAGE_SECTION_HEADER
typedef struct _PE_IMAGE_READER PE_IMAGE_READER
typedef struct _PE_IMAGE_READERPPE_IMAGE_READER

Functions

BOOLEAN PeImageReaderInitialize (const BYTE *ImageBase, SIZE_T ImageSize, PPE_IMAGE_READER Reader)
 Parses and validates all PE headers in an in-memory image buffer.
BOOLEAN PeImageReaderIs32Bit (PPE_IMAGE_READER Reader)
 Returns whether the PE image is a 32-bit (PE32) image.
BOOLEAN PeImageReaderGetPointerAtOffset (PPE_IMAGE_READER Reader, SIZE_T Offset, SIZE_T Length, const BYTE **Pointer)
 Returns a validated pointer into the image at a raw file offset.
BOOLEAN PeImageReaderGetSectionName (const IMAGE_SECTION_HEADER *SectionHeader, CHAR *NameBuffer, SIZE_T NameBufferSize)
 Copies the section name from a section header into a null-terminated buffer.
BOOLEAN PeImageReaderRvaToFileOffset (PPE_IMAGE_READER Reader, DWORD Rva, DWORD Length, PSIZE_T FileOffset)
 Translates a relative virtual address (RVA) to a raw file offset.

Detailed Description

Bounded in-memory Portable Executable reader.

Author
jtaw5649
Version
0.19
Date
2026-06-01

Macro Definition Documentation

◆ IMAGE_SIZEOF_SHORT_NAME

#define IMAGE_SIZEOF_SHORT_NAME   8

Typedef Documentation

◆ IMAGE_DOS_HEADER

◆ IMAGE_FILE_HEADER

◆ IMAGE_SECTION_HEADER

◆ PE_IMAGE_READER

◆ PIMAGE_DOS_HEADER

◆ PIMAGE_FILE_HEADER

◆ PIMAGE_SECTION_HEADER

◆ PPE_IMAGE_READER

Function Documentation

◆ PeImageReaderGetPointerAtOffset()

BOOLEAN PeImageReaderGetPointerAtOffset ( PPE_IMAGE_READER Reader,
SIZE_T Offset,
SIZE_T Length,
const BYTE ** Pointer )

Returns a validated pointer into the image at a raw file offset.

Verifies that the range [Offset, Offset + Length) lies within the image buffer before setting *Pointer. Use this function when working with raw file offsets rather than virtual addresses.

Parameters
ReaderPointer to an initialized PE_IMAGE_READER; must not be NULL
OffsetRaw file offset from the start of the image
LengthNumber of bytes that must be accessible at the offset
PointerOutput pointer set to ImageBase + Offset on success; must not be NULL
Returns
BOOLEAN TRUE on success, FALSE on invalid arguments or out-of-bounds offset
220{
221 if (Reader == NULL || Reader->ImageBase == NULL || Pointer == NULL || !PeImageReaderHasRange(Reader->ImageSize, Offset, Length))
222 {
223 return FALSE;
224 }
225
226 *Pointer = Reader->ImageBase + Offset;
227 return TRUE;
228}
#define TRUE
Definition BasicTypes.h:114
#define FALSE
Definition BasicTypes.h:113
SIZE_T ImageSize
Definition pe-image-reader.h:76
const BYTE * ImageBase
Definition pe-image-reader.h:75

◆ PeImageReaderGetSectionName()

BOOLEAN PeImageReaderGetSectionName ( const IMAGE_SECTION_HEADER * SectionHeader,
CHAR * NameBuffer,
SIZE_T NameBufferSize )

Copies the section name from a section header into a null-terminated buffer.

The PE section name field (IMAGE_SIZEOF_SHORT_NAME bytes) is not required to be null-terminated when it uses all 8 bytes. This function always appends a null terminator and truncates to NameBufferSize - 1 characters if necessary.

Parameters
SectionHeaderPointer to the section header to read; must not be NULL
NameBufferDestination buffer for the null-terminated name; must not be NULL
NameBufferSizeSize of NameBuffer in bytes; must be at least 1
Returns
BOOLEAN TRUE on success, FALSE on NULL arguments or zero-length buffer
245{
246 if (SectionHeader == NULL || NameBuffer == NULL || NameBufferSize == 0)
247 {
248 return FALSE;
249 }
250
251 SIZE_T NameLength = 0;
252 while (NameLength < IMAGE_SIZEOF_SHORT_NAME && SectionHeader->Name[NameLength] != '\0')
253 {
254 NameLength++;
255 }
256
257 SIZE_T CopyLength = NameLength;
258 if (CopyLength >= NameBufferSize)
259 {
260 CopyLength = NameBufferSize - 1;
261 }
262
263 CopyMemory(NameBuffer, SectionHeader->Name, CopyLength);
264 NameBuffer[CopyLength] = '\0';
265
266 return TRUE;
267}
BYTE Name[IMAGE_SIZEOF_SHORT_NAME]
Definition pe-image-reader.h:55

◆ PeImageReaderInitialize()

BOOLEAN PeImageReaderInitialize ( const BYTE * ImageBase,
SIZE_T ImageSize,
PPE_IMAGE_READER Reader )

Parses and validates all PE headers in an in-memory image buffer.

Verifies the DOS signature, the NT signature, the optional header magic, and ensures all headers and the section table fit within the supplied buffer. On success the Reader structure is populated with pointers into ImageBase.

Parameters
ImageBasePointer to the start of the image buffer; must not be NULL
ImageSizeSize of the buffer in bytes
ReaderOutput structure to populate on success; must not be NULL
Returns
BOOLEAN TRUE if the image was parsed successfully, FALSE on any validation failure or NULL argument
95{
96 if (ImageBase == NULL || Reader == NULL)
97 {
98 return FALSE;
99 }
100
101 ZeroMemory(Reader, sizeof(*Reader));
102
103 if (!PeImageReaderHasRange(ImageSize, 0, sizeof(IMAGE_DOS_HEADER)))
104 {
105 return FALSE;
106 }
107
108 const IMAGE_DOS_HEADER * DosHeader = (const IMAGE_DOS_HEADER *)ImageBase;
109 if (DosHeader->e_magic != IMAGE_DOS_SIGNATURE || DosHeader->e_lfanew < 0)
110 {
111 return FALSE;
112 }
113
114 SIZE_T NtHeaderOffset = (SIZE_T)DosHeader->e_lfanew;
115 if (!PeImageReaderHasRange(ImageSize, NtHeaderOffset, sizeof(DWORD) + sizeof(IMAGE_FILE_HEADER)))
116 {
117 return FALSE;
118 }
119
120 const BYTE * NtHeaders = ImageBase + NtHeaderOffset;
121 if (*(const DWORD *)NtHeaders != IMAGE_NT_SIGNATURE)
122 {
123 return FALSE;
124 }
125
126 const IMAGE_FILE_HEADER * FileHeader = (const IMAGE_FILE_HEADER *)(NtHeaders + sizeof(DWORD));
127 SIZE_T OptionalHeaderOffset = NtHeaderOffset + sizeof(DWORD) + sizeof(IMAGE_FILE_HEADER);
128
129 if (FileHeader->SizeOfOptionalHeader < sizeof(WORD) ||
130 !PeImageReaderHasRange(ImageSize, OptionalHeaderOffset, FileHeader->SizeOfOptionalHeader))
131 {
132 return FALSE;
133 }
134
135 WORD OptionalHeaderMagic = *(const WORD *)(ImageBase + OptionalHeaderOffset);
136 BOOLEAN Is32Bit = FALSE;
137 SIZE_T MinimumOptionalHeaderSize = 0;
138
139 if (OptionalHeaderMagic == IMAGE_NT_OPTIONAL_HDR32_MAGIC)
140 {
141 Is32Bit = TRUE;
142 MinimumOptionalHeaderSize = sizeof(IMAGE_OPTIONAL_HEADER32);
143 }
144 else if (OptionalHeaderMagic == IMAGE_NT_OPTIONAL_HDR64_MAGIC)
145 {
146 MinimumOptionalHeaderSize = sizeof(IMAGE_OPTIONAL_HEADER64);
147 }
148 else
149 {
150 return FALSE;
151 }
152
153 if (FileHeader->SizeOfOptionalHeader < MinimumOptionalHeaderSize)
154 {
155 return FALSE;
156 }
157
158 SIZE_T SectionTableOffset = OptionalHeaderOffset + FileHeader->SizeOfOptionalHeader;
159 SIZE_T SectionTableSize = (SIZE_T)FileHeader->NumberOfSections * sizeof(IMAGE_SECTION_HEADER);
160
161 if (FileHeader->NumberOfSections != 0 && SectionTableSize / sizeof(IMAGE_SECTION_HEADER) != FileHeader->NumberOfSections)
162 {
163 return FALSE;
164 }
165
166 if (!PeImageReaderHasRange(ImageSize, SectionTableOffset, SectionTableSize))
167 {
168 return FALSE;
169 }
170
171 Reader->ImageBase = ImageBase;
172 Reader->ImageSize = ImageSize;
173 Reader->DosHeader = DosHeader;
174 Reader->NtHeaders = NtHeaders;
175 Reader->FileHeader = FileHeader;
176 Reader->SectionHeaders = (const IMAGE_SECTION_HEADER *)(ImageBase + SectionTableOffset);
177 Reader->OptionalHeaderMagic = OptionalHeaderMagic;
178 Reader->Is32Bit = Is32Bit;
179
180 return TRUE;
181}
#define IMAGE_NT_SIGNATURE
Definition Hooks.h:63
#define IMAGE_DOS_SIGNATURE
Special signatures.
Definition Hooks.h:59
unsigned short WORD
Definition BasicTypes.h:42
UCHAR BOOLEAN
Definition BasicTypes.h:35
unsigned char BYTE
Definition BasicTypes.h:40
unsigned long DWORD
Definition BasicTypes.h:38
struct _IMAGE_FILE_HEADER IMAGE_FILE_HEADER
struct _IMAGE_DOS_HEADER IMAGE_DOS_HEADER
struct _IMAGE_SECTION_HEADER IMAGE_SECTION_HEADER
WORD e_magic
Definition pe-image-reader.h:19
LONG e_lfanew
Definition pe-image-reader.h:37
WORD SizeOfOptionalHeader
Definition pe-image-reader.h:47
WORD NumberOfSections
Definition pe-image-reader.h:43
WORD OptionalHeaderMagic
Definition pe-image-reader.h:81
const IMAGE_FILE_HEADER * FileHeader
Definition pe-image-reader.h:79
BOOLEAN Is32Bit
Definition pe-image-reader.h:82
const IMAGE_DOS_HEADER * DosHeader
Definition pe-image-reader.h:77
const IMAGE_SECTION_HEADER * SectionHeaders
Definition pe-image-reader.h:80
const BYTE * NtHeaders
Definition pe-image-reader.h:78

◆ PeImageReaderIs32Bit()

BOOLEAN PeImageReaderIs32Bit ( PPE_IMAGE_READER Reader)

Returns whether the PE image is a 32-bit (PE32) image.

Examines the Is32Bit flag populated by PeImageReaderInitialize. A return value of FALSE means either the reader is NULL or the image is PE32+.

Parameters
ReaderPointer to an initialized PE_IMAGE_READER
Returns
BOOLEAN TRUE for PE32 (32-bit), FALSE for PE32+ (64-bit) or NULL reader
195{
196 if (Reader == NULL)
197 {
198 return FALSE;
199 }
200
201 return Reader->Is32Bit;
202}

◆ PeImageReaderRvaToFileOffset()

BOOLEAN PeImageReaderRvaToFileOffset ( PPE_IMAGE_READER Reader,
DWORD Rva,
DWORD Length,
PSIZE_T FileOffset )

Translates a relative virtual address (RVA) to a raw file offset.

First checks whether the RVA falls within the PE headers (before any section), in which case the file offset equals the RVA. Otherwise iterates the section table to find the section that contains the range [Rva, Rva + Length) and computes the corresponding raw offset via PointerToRawData. Returns FALSE if no section contains the range, if the raw data mapping is out of bounds, or if any arithmetic overflows.

Parameters
ReaderPointer to an initialized PE_IMAGE_READER; must not be NULL
RvaRelative virtual address to translate
LengthNumber of bytes that must be accessible at the translated offset
FileOffsetOutput pointer that receives the raw file offset on success; must not be NULL
Returns
BOOLEAN TRUE if the RVA was translated successfully, FALSE otherwise
288{
289 if (Reader == NULL || Reader->ImageBase == NULL || Reader->FileHeader == NULL || Reader->SectionHeaders == NULL || FileOffset == NULL)
290 {
291 return FALSE;
292 }
293
294 DWORD SizeOfHeaders = PeImageReaderGetSizeOfHeaders(Reader);
295 SIZE_T HeaderEnd = 0;
296
297 if (PeImageReaderAddSize((SIZE_T)Rva, (SIZE_T)Length, &HeaderEnd) &&
298 SizeOfHeaders <= Reader->ImageSize && Rva < SizeOfHeaders && HeaderEnd <= SizeOfHeaders &&
299 PeImageReaderHasRange(Reader->ImageSize, (SIZE_T)Rva, (SIZE_T)Length))
300 {
301 *FileOffset = (SIZE_T)Rva;
302 return TRUE;
303 }
304
305 for (WORD Index = 0; Index < Reader->FileHeader->NumberOfSections; Index++)
306 {
307 const IMAGE_SECTION_HEADER * SectionHeader = &Reader->SectionHeaders[Index];
308 DWORD SectionSpan = max(SectionHeader->Misc.VirtualSize, SectionHeader->SizeOfRawData);
309
310 if (SectionSpan == 0 || Rva < SectionHeader->VirtualAddress)
311 {
312 continue;
313 }
314
315 DWORD Delta = Rva - SectionHeader->VirtualAddress;
316 if (Delta >= SectionSpan || Length > SectionSpan - Delta)
317 {
318 continue;
319 }
320
321 if (Delta > SectionHeader->SizeOfRawData || Length > SectionHeader->SizeOfRawData - Delta)
322 {
323 return FALSE;
324 }
325
326 SIZE_T RawOffset = 0;
327
328 if (!PeImageReaderAddSize((SIZE_T)SectionHeader->PointerToRawData, (SIZE_T)Delta, &RawOffset) ||
329 !PeImageReaderHasRange(Reader->ImageSize, RawOffset, (SIZE_T)Length))
330 {
331 return FALSE;
332 }
333
334 *FileOffset = RawOffset;
335 return TRUE;
336 }
337
338 return FALSE;
339}
DWORD SizeOfRawData
Definition pe-image-reader.h:62
union _IMAGE_SECTION_HEADER::@110214036316356314152306243141306316071137200254 Misc
DWORD PointerToRawData
Definition pe-image-reader.h:63
DWORD VirtualAddress
Definition pe-image-reader.h:61
DWORD VirtualSize
Definition pe-image-reader.h:59