/* pe.h - PE/COFF image parsing (engine-private, Windows-specific). * * Locating a section by name inside a mapped PE image is a Windows-image * concern, not a property of the source-agnostic matcher: it lives in the * engine, alongside the rest of the Windows bring-up. Handlers never see this * header - they consume only the generic memory model (memmodel.h) and the pure * matcher (sigscan.h). The engine uses these to build mem_view_t windows out of * a guest image and feed them to the matcher. */ #ifndef VMIE_PE_H #define VMIE_PE_H #include #include #include #include "memmodel.h" /* mem_view_t, vmie_mem */ /* One enumerated PE section header, decoded by pe_sections. Mirrors the public * win32 section_desc, but stays engine-private (this header is engine-only). * name - section name, NUL-terminated (PE names are <= 8 bytes; name[8] NUL) * rva - section RVA (relative to module_base) * vsize - virtual size in bytes * prot - VR_R/VR_W/VR_X from the section Characteristics (VR_U never set) */ typedef struct { char name[9]; uint32_t rva; uint32_t vsize; uint32_t prot; } pe_secrec; /* Enumerate the section headers of the PE image based at `module_base` inside a * view holding at least the image headers (the first page is enough). * out, max - caller array receiving up to `max` pe_secrec; out may be NULL to * count only. Headers truncated by the view end are not reported. * Returns the TOTAL section count (may exceed `max`), or -1 if `v` does not hold * a parseable PE at `module_base`. Shares the section-table walk with * pe_find_section (one header parser, no duplication). */ int pe_sections(mem_view_t v, uint64_t module_base, pe_secrec* out, int max); /* Locate a PE section by name within a view that contains at least the image * headers at `module_base` (the first page is enough). * module_base - image base VA, must be >= v.base_va and inside `v` * name - section name, e.g. ".text" (compared up to 8 bytes) * rva_out - receives the section RVA (relative to module_base); may be NULL * vsize_out - receives the section virtual size; may be NULL * Returns true if found. Only the headers need to be present in `v`; the section * body does not. */ bool pe_find_section(mem_view_t v, uint64_t module_base, const char* name, uint64_t* rva_out, uint32_t* vsize_out); /* Locate a PE section AND return a sub-view spanning it. Requires the whole * section body to be present in `v` (true for an in-memory image dump). Prefer * scanning ".text" over a whole image: faster, and avoids false hits in data. * Returns true and fills *out on success. For guest memory, where the body is * usually not co-resident with the headers, use vmie_pe_section. */ bool pe_section(mem_view_t v, uint64_t module_base, const char* name, mem_view_t* out); /* Read a PE section out of guest memory under `cr3` into `buf`. * module_base - image base VA (headers read from the first page) * name - section name, e.g. ".text" * buf, bufcap - destination buffer and its capacity (section is truncated to fit) * out - on success, a view spanning the bytes read into `buf` * Returns 0 on success, -1 if the headers/section are unreadable or absent. The * guest image body need not be co-resident with the headers (unlike pe_section).*/ int vmie_pe_section(vmie_mem* m, uintptr_t cr3, uint64_t module_base, const char* name, uint8_t* buf, size_t bufcap, mem_view_t* out); /* OptionalHeader DataDirectory indices used across the engine. */ #define PE_DIR_EXPORT 0u /* IMAGE_DIRECTORY_ENTRY_EXPORT */ #define PE_DIR_IMPORT 1u /* IMAGE_DIRECTORY_ENTRY_IMPORT */ #define PE_DIR_DEBUG 6u /* IMAGE_DIRECTORY_ENTRY_DEBUG */ #define PE_DIR_EXCEPTION 3u /* IMAGE_DIRECTORY_ENTRY_EXCEPTION (.pdata) */ /* Read one OptionalHeader DataDirectory entry of the PE32+ image based at `base` * in the address space `cr3`. This is the SINGLE data-directory accessor used by * every directory walk in the engine (.pdata / export / debug) - it walks the * DOS+NT headers from `base` once and reads DataDirectory[idx]. * idx - directory index (PE_DIR_*). * rva - receives DataDirectory[idx].VirtualAddress (0 if the directory is * absent); never NULL. * size - receives DataDirectory[idx].Size; may be NULL. * Returns 0 on success (rva/size filled), -1 if the headers are unreadable. A * present-but-absent directory reports rva==0 with return 0. */ int pe_data_dir(vmie_mem* m, uintptr_t cr3, uint64_t base, unsigned idx, uint32_t* rva, uint32_t* size); /* Extract a module's CodeView RSDS reference from its debug directory. This is * the SINGLE debug-dir/RSDS parser in the engine, shared by the kernel bootstrap * (host.c) and the public vmie_win32_pdb_ref - there is no second copy. * base - image base VA in `cr3`. * guid[16] - receives the PDB GUID (in-memory byte order); never NULL. * age - receives the PDB age; never NULL. * name - receives the NUL-terminated PDB file name; never NULL. * namecap - capacity of `name` (>= 1). The name is truncated to namecap-1. * Walks PE_DIR_DEBUG for an IMAGE_DEBUG_TYPE_CODEVIEW entry whose payload starts * with 'RSDS', then reads {guid, age, name}. Returns 0 on success, -1 if there * is no debug directory, no CodeView/RSDS entry, or the bytes are unreadable. */ int pe_pdb_ref(vmie_mem* m, uintptr_t cr3, uint64_t base, uint8_t guid[16], uint32_t* age, char* name, size_t namecap); #endif /* VMIE_PE_H */