Pe
Description
Parsed PE file. Holds the raw bytes plus decoded indices. All three PeOpen* constructors leave the parser as the sole owner of data – see the L / R semantics on the FromMemory / FromMemoryCopy constructors (mirrors VecInsertL / VecInsertR).
Fields
| Name | Description |
|---|---|
data |
Raw PE bytes as a Buf (owned). Carries its own length and allocator – read via BufLength / BufData / BufAllocator. |
machine |
Decoded IMAGE_FILE_HEADER.Machine. |
is_pe32_plus |
True for PE32+ (64-bit). v1 supports both PE32 and PE32+ headers, but the address-bearing fields are widened to 64 bits even on PE32. |
image_base |
OptionalHeader.ImageBase – the runtime virtual address the loader places the image at when no relocation is required. |
size_of_image |
OptionalHeader.SizeOfImage – total in-memory size (helps bounds-check RVAs). |
sections |
All section headers, in original order. |
codeview |
CodeView debug record, if present. |
Usage example (Cross-references)
Usage examples (Cross-references)
- In
PdbCache.h:27:
#include <Misra/Parsers/Pdb.h>
#include <Misra/Parsers/Pe.h>
#include <Misra/Std/Allocator.h>
#include <Misra/Std/Container/Str/Type.h>- In
PdbCache.h:35:
typedef struct PdbCacheEntry {
Str module_path; // owned; cleaned via StrDeinit
Pe pe;
Pdb pdb;
bool pe_open;- In
Pe.h:21:
#define MISRA_PARSERS_PE_H
#include <Misra/Parsers/Pe/Private.h>
#include <Misra/Std/Allocator.h>
#include <Misra/Std/Container/Buf.h>- In
Pe.h:110:
PeSections sections;
PeCodeViewInfo codeview;
} Pe;
///
- In
Pe.h:172:
/// TAGS: Parser, PE, Memory, Ownership
///
bool PeOpenFromMemory(Pe *out, Buf *in);
///
- In
Pe.h:201:
/// TAGS: Parser, PE, Deinit, Lifecycle
///
void PeDeinit(Pe *self);
///
- In
Pe.h:231:
/// TAGS: Parser, PE, Address
///
bool PeRvaToOffset(const Pe *self, u32 rva, u64 *out_offset);
#endif // MISRA_PARSERS_PE_H
- In
PdbCache.c:30:
//
// On success populates `out_path` (an owned Str the caller frees).
static bool find_pdb(const Pe *pe, Zstr pe_path, Str *out_path) {
const PeCodeViewInfo *cv = PeCodeView(pe);
if (!cv->present || !cv->pdb_path)- In
Pe.c:16:
/// - LLVM's `Object/COFF.h` for the reader-side conventions
#include <Misra/Parsers/Pe.h>
#include <Misra/Std.h>
#include <Misra/Std/Container/Buf.h>- In
Pe.c:147:
typedef struct PeContext {
Pe *out;
BufIter file; // bounds for the whole image
u32 nt_offset; // offset of NT signature
- In
Pe.c:506:
// MemSets the caller's view. Anything that fails past the snapshot
// cleans up via PeDeinit -- the buffer never leaks.
bool PeOpenFromMemory(Pe *out, Buf *in) {
if (!out || !in || !BufData(in) || !BufAllocator(in)) {
LOG_FATAL("PeOpenFromMemory: NULL argument (contract violation)");- In
Pe.c:542:
// R-value form: allocate Buf, copy, hand `©` to the L-form.
bool pe_open_from_memory_copy(Pe *out, const u8 *data, size data_size, Allocator *alloc) {
if (!out || !data || !alloc) {
LOG_FATAL("PeOpenFromMemoryCopy: NULL argument (contract violation)");- In
Pe.c:556:
}
bool pe_open(Pe *out, Zstr path, Allocator *alloc) {
if (!out || !path || !alloc) {
LOG_FATAL("PeOpen: NULL argument (contract violation)");- In
Pe.c:569:
}
void PeDeinit(Pe *self) {
if (!self)
return;- In
Pe.c:577:
}
const PeSection *pe_find_section_zstr(const Pe *self, Zstr name) {
if (!self || !name)
return NULL;- In
Pe.c:589:
}
const PeSection *pe_find_section_str(const Pe *self, const Str *name) {
if (!self || !name)
return NULL;- In
Pe.c:595:
}
bool PeRvaToOffset(const Pe *self, u32 rva, u64 *out_offset) {
if (!self || !out_offset)
return false;- In
Pe.c:11:
#include <Misra.h>
#include <Misra/Parsers/Pe.h>
#include <Misra/Std/Zstr.h>
#include <Misra/Std/Allocator/Debug.h>- In
Pe.c:486:
build_pe_blob();
Pe pe;
bool ok = PeOpenFromMemoryCopy(&pe, blob, sizeof(blob), base);
if (!ok) {- In
Pe.c:512:
build_pe_blob();
Pe pe;
if (!PeOpenFromMemoryCopy(&pe, blob, sizeof(blob), base)) {
DefaultAllocatorDeinit(&alloc);- In
Pe.c:540:
garbage[1] = 'X';
Pe pe;
bool ok = !PeOpenFromMemoryCopy(&pe, garbage, sizeof(garbage), base);- In
Pe.c:554:
build_pe_blob();
Pe pe;
if (!PeOpenFromMemoryCopy(&pe, blob, sizeof(blob), base)) {
DefaultAllocatorDeinit(&alloc);- In
Pe.c:578:
build_pe_blob();
Pe pe;
if (!PeOpenFromMemoryCopy(&pe, blob, sizeof(blob), base)) {
DefaultAllocatorDeinit(&alloc);- In
Pe.c:602:
static bool pe_rejects(const u8 *bytes, u64 len) {
DefaultAllocator alloc = DefaultAllocatorInit();
Pe pe;
bool opened = PeOpenFromMemoryCopy(&pe, bytes, len, ALLOCATOR_OF(&alloc));
if (opened)- In
Pe.c:658:
DefaultAllocator alloc = DefaultAllocatorInit();
build_pe_blob_m1();
Pe pe;
if (!PeOpenFromMemoryCopy(&pe, blob, sizeof(blob), ALLOCATOR_OF(&alloc))) {
DefaultAllocatorDeinit(&alloc);- In
Pe.c:679:
// top 4 bytes are all significant.
wr_u64(&blob[OPT_HDR_OFF + 24], 0x7766554433221100ull);
Pe pe;
if (!PeOpenFromMemoryCopy(&pe, blob, sizeof(blob), ALLOCATOR_OF(&alloc))) {
DefaultAllocatorDeinit(&alloc);- In
Pe.c:695:
DefaultAllocator alloc = DefaultAllocatorInit();
build_pe32_blob();
Pe pe;
if (!PeOpenFromMemoryCopy(&pe, blob, sizeof(blob), ALLOCATOR_OF(&alloc))) {
DefaultAllocatorDeinit(&alloc);- In
Pe.c:715:
build_pe32_blob();
wr_u32(&blob[OPT_HDR_OFF + 28], 0x00410000u);
Pe pe;
if (!PeOpenFromMemoryCopy(&pe, blob, sizeof(blob), ALLOCATOR_OF(&alloc))) {
DefaultAllocatorDeinit(&alloc);- In
Pe.c:741:
// the file but assert via the overrun-reject test below. Here we
// confirm the normal (well-within-file) blob is accepted.
Pe pe;
bool ok = PeOpenFromMemoryCopy(&pe, blob, sizeof(blob), ALLOCATOR_OF(&alloc));
if (ok)- In
Pe.c:763:
// 1896. Set size to 1900 (> 1896) so the real code rejects.
wr_u16(&bad[FILE_HDR_OFF + 16], 1900);
Pe pe;
bool opened = PeOpenFromMemoryCopy(&pe, bad, sizeof(bad), ALLOCATOR_OF(&alloc));
if (opened)- In
Pe.c:791:
// path just stays empty. opt ends at OPT_HDR_OFF + 240.
u64 want_len = (u64)OPT_HDR_OFF + OPT_HDR_SIZE_PEPP; // exact fit to EOF
Pe pe;
bool ok = PeOpenFromMemoryCopy(&pe, exact, want_len, ALLOCATOR_OF(&alloc));
if (ok) {- In
Pe.c:812:
build_pe_blob_m1();
wr_u32(&blob[OPT_HDR_OFF + 108], 7); // NumberOfRvaAndSizes = 7
Pe pe;
if (!PeOpenFromMemoryCopy(&pe, blob, sizeof(blob), ALLOCATOR_OF(&alloc))) {
DefaultAllocatorDeinit(&alloc);- In
Pe.c:838:
// read slot 6 and FIND the codeview -> present=true. Asserting
// absent kills that mutation.
Pe pe;
if (!PeOpenFromMemoryCopy(&pe, blob, sizeof(blob), ALLOCATOR_OF(&alloc))) {
DefaultAllocatorDeinit(&alloc);- In
Pe.c:859:
DefaultAllocator alloc = DefaultAllocatorInit();
build_pe_blob_m1();
Pe pe;
if (!PeOpenFromMemoryCopy(&pe, blob, sizeof(blob), ALLOCATOR_OF(&alloc))) {
DefaultAllocatorDeinit(&alloc);- In
Pe.c:880:
// Corrupt the 'R' of RSDS.
blob[CV_REC_RAW_OFF] = 'N';
Pe pe;
if (!PeOpenFromMemoryCopy(&pe, blob, sizeof(blob), ALLOCATOR_OF(&alloc))) {
DefaultAllocatorDeinit(&alloc);- In
Pe.c:897:
build_pe_blob_m1();
wr_u32(&blob[DEBUG_RAW_OFF + 12], 9); // Type != CODEVIEW
Pe pe;
if (!PeOpenFromMemoryCopy(&pe, blob, sizeof(blob), ALLOCATOR_OF(&alloc))) {
DefaultAllocatorDeinit(&alloc);- In
Pe.c:927:
for (u32 i = 0; i < path_region; ++i)
cv[24 + i] = (u8)('A' + i); // no NUL anywhere in the region
Pe pe;
if (!PeOpenFromMemoryCopy(&pe, blob, sizeof(blob), ALLOCATOR_OF(&alloc))) {
DefaultAllocatorDeinit(&alloc);- In
Pe.c:955:
cv[27] = 'D';
cv[28] = '\0'; // terminator is the last in-region byte
Pe pe;
if (!PeOpenFromMemoryCopy(&pe, blob, sizeof(blob), ALLOCATOR_OF(&alloc))) {
DefaultAllocatorDeinit(&alloc);- In
Pe.c:980:
u8 *cv = &blob[CV_REC_RAW_OFF];
cv[24] = '\0'; // empty path, NUL-terminated
Pe pe;
if (!PeOpenFromMemoryCopy(&pe, blob, sizeof(blob), ALLOCATOR_OF(&alloc))) {
DefaultAllocatorDeinit(&alloc);- In
Pe.c:996:
build_pe_blob_m1();
wr_u32(&blob[DEBUG_RAW_OFF + 16], 24); // one below minimum
Pe pe;
if (!PeOpenFromMemoryCopy(&pe, blob, sizeof(blob), ALLOCATOR_OF(&alloc))) {
DefaultAllocatorDeinit(&alloc);- In
Pe.c:1020:
// 0x420 + sz > 0x800: sz = 0x800 - 0x420 + 4 = 0x3E4.
wr_u32(&blob[DEBUG_RAW_OFF + 16], (u32)(BLOB_SIZE - CV_REC_RAW_OFF + 4));
Pe pe;
if (!PeOpenFromMemoryCopy(&pe, blob, sizeof(blob), ALLOCATOR_OF(&alloc))) {
DefaultAllocatorDeinit(&alloc);- In
Pe.c:1044:
build_pe_blob_fullcover(0x300, 28);
put_cv_entry_sz(0x300, 0x200, 0x300);
Pe pe;
if (!PeOpenFromMemoryCopy(&pe, blob, sizeof(blob), ALLOCATOR_OF(&alloc))) {
DefaultAllocatorDeinit(&alloc);- In
Pe.c:1064:
build_pe_blob_fullcover(0x300, 28);
put_cv_entry_sz(0x300, 0x500, 0x300);
Pe pe;
if (!PeOpenFromMemoryCopy(&pe, blob, sizeof(blob), ALLOCATOR_OF(&alloc))) {
DefaultAllocatorDeinit(&alloc);- In
Pe.c:1088:
// 73*28 = 2044, dir_offset 0x400 + 2044 = 0xC00 > 0x800.
wr_u32(&blob[OPT_HDR_OFF + 112 + 6 * 8 + 4], BLOB_SIZE);
Pe pe;
if (!PeOpenFromMemoryCopy(&pe, blob, sizeof(blob), ALLOCATOR_OF(&alloc))) {
DefaultAllocatorDeinit(&alloc);- In
Pe.c:1118:
build_pe_blob_fullcover(DIR_RAW, NENT * 28);
put_cv_entry(DIR_RAW, 0x500); // CodeView in entry 0, record at 0x500
Pe pe;
if (!PeOpenFromMemoryCopy(&pe, blob, sizeof(blob), ALLOCATOR_OF(&alloc))) {
DefaultAllocatorDeinit(&alloc);- In
Pe.c:1141:
build_pe_blob_fullcover(DIR_RAW, 28);
put_cv_entry(DIR_RAW, 0x500); // record at 0x500 (in-bounds)
Pe pe;
if (!PeOpenFromMemoryCopy(&pe, blob, sizeof(blob), ALLOCATOR_OF(&alloc))) {
DefaultAllocatorDeinit(&alloc);- In
Pe.c:1169:
cv[27] = 'D'; // no NUL inside [24,28)
cv[28] = '\0'; // NUL sits exactly AT region_end (one past the region)
Pe pe;
if (!PeOpenFromMemoryCopy(&pe, blob, sizeof(blob), ALLOCATOR_OF(&alloc))) {
DefaultAllocatorDeinit(&alloc);- In
Pe.c:1196:
wr_u32(&d0[24], 0);
put_cv_entry(0x300 + 28, 0x500); // entry1 (just past declared count)
Pe pe;
if (!PeOpenFromMemoryCopy(&pe, blob, sizeof(blob), ALLOCATOR_OF(&alloc))) {
DefaultAllocatorDeinit(&alloc);- In
Pe.c:1237:
u64 plen = ZstrLen(kPdbPath);
MemCopy(&cv2[24], kPdbPath, plen + 1);
Pe pe;
if (!PeOpenFromMemoryCopy(&pe, blob, sizeof(blob), ALLOCATOR_OF(&alloc))) {
DefaultAllocatorDeinit(&alloc);- In
Pe.c:1273:
build_blob(blob, secs, 2);
Pe pe;
if (!PeOpenFromMemoryCopy(&pe, blob, sizeof(blob), ALLOCATOR_OF(&alloc))) {
DefaultAllocatorDeinit(&alloc);- In
Pe.c:1309:
build_blob(blob, secs, 2);
Pe pe;
if (!PeOpenFromMemoryCopy(&pe, blob, total, ALLOCATOR_OF(&alloc))) {
DefaultAllocatorDeinit(&alloc);- In
Pe.c:1335:
build_blob(blob, secs, 1);
Pe pe;
if (!PeOpenFromMemoryCopy(&pe, blob, sizeof(blob), ALLOCATOR_OF(&alloc))) {
DefaultAllocatorDeinit(&alloc);- In
Pe.c:1367:
build_blob(blob, secs, 2);
Pe pe;
bool opened = PeOpenFromMemoryCopy(&pe, blob, total, ALLOCATOR_OF(&alloc));
if (opened)- In
Pe.c:1401:
build_blob(blob, secs, 2);
Pe pe;
if (!PeOpenFromMemoryCopy(&pe, blob, sizeof(blob), ALLOCATOR_OF(&alloc))) {
DefaultAllocatorDeinit(&alloc);- In
Pe.c:1435:
build_blob(blob, secs, 1);
Pe pe;
if (!PeOpenFromMemoryCopy(&pe, blob, sizeof(blob), ALLOCATOR_OF(&alloc))) {
DefaultAllocatorDeinit(&alloc);- In
Pe.c:1474:
build_blob(blob, secs, 1);
Pe pe;
if (!PeOpenFromMemoryCopy(&pe, blob, total, ALLOCATOR_OF(&alloc))) {
DefaultAllocatorDeinit(&alloc);- In
Pe.c:1506:
build_blob(blob, secs, 1);
Pe pe;
if (!PeOpenFromMemoryCopy(&pe, blob, sizeof(blob), ALLOCATOR_OF(&alloc))) {
DefaultAllocatorDeinit(&alloc);- In
Pe.c:1540:
build_blob(blob, secs, 2);
Pe pe;
if (!PeOpenFromMemoryCopy(&pe, blob, sizeof(blob), ALLOCATOR_OF(&alloc))) {
DefaultAllocatorDeinit(&alloc);- In
Pe.c:1581:
build_blob(blob, secs, 2);
Pe pe;
if (!PeOpenFromMemoryCopy(&pe, blob, sizeof(blob), base)) {
DebugAllocatorDeinit(&alloc);- In
Pe.c:1618:
blob[NT_OFF] = 'Q'; // corrupt the 'P' of "PE\0\0" -> fails after DOS
Pe pe;
bool opened = PeOpenFromMemoryCopy(&pe, blob, sizeof(blob), ALLOCATOR_OF(&alloc));
// Real code: rejected AND `out` zeroed by PeDeinit on the fail path.
- In
Pe.c:1665:
}
Pe pe;
bool ok = PeOpen(&pe, (Zstr)StrBegin(&path), base);
if (ok) {- In
Pe.c:1707:
}
Pe pe;
bool opened = PeOpen(&pe, (Zstr)StrBegin(&path), base);
if (opened)- In
Pe.c:1734:
build_blob(blob, secs, 1);
Pe pe;
bool ok = PeOpenFromMemoryCopy(&pe, blob, sizeof(blob), ALLOCATOR_OF(&alloc));
if (ok)- In
Pe.c:1755:
blob[1] = 'X'; // 'MZ' -> 'MX'
Pe pe;
bool opened = PeOpenFromMemoryCopy(&pe, blob, sizeof(blob), ALLOCATOR_OF(&alloc));
if (opened)- In
Pe.c:1764:
int main(void) {
WriteFmt("[INFO] Starting Pe tests\n\n");
TestFunction tests[] = {- In
Pe.c:1820:
};
return run_test_suite(tests, sizeof(tests) / sizeof(tests[0]), NULL, 0, "Pe");
}
Last updated on