mirror of
https://dev.lirent.ru/Vatrog/vm-introspection-engine.git
synced 2026-06-18 04:16:39 +03:00
Define the win32 engine; add a dump source and physical sigscan
Name and isolate the Windows engine as one of potentially several. The public surface moves to include/win32.h with an opaque vmie_win32 handle (vmie_win32_open/close/mem); the engine's Windows internals — host bring-up, the struct-offset profile, process/module/PE/text decode — live under src/engine/win32. The generic address-space layer stays in src/engine (gva.c + engine-arch.h, carrying no offset table): gva.c is de-profiled, and CR3 bring-up reaches the hot translator through a cold gva_translate bridge so the zero-copy hot path stays private and inlinable. A memory source is now first-class and public: vmie_mem_open/_open_segs/ _close open a flat dump (or an explicit segment map) as a vmie_mem, with gpa_seg promoted to the public contract. The physical signature scan is exposed source-agnostically: sig_scan_mem returns GPAs for any vmie_mem, sig_scan_sources scans several sources with per-source attribution, and sig_from_bytes builds an exact needle from a byte span. The pure matcher is unchanged; dumps and the live engine image are scanned uniformly, neither needing the other.
This commit is contained in:
@@ -0,0 +1,63 @@
|
||||
#include "pe.h"
|
||||
|
||||
#include <string.h>
|
||||
#include "memmodel.h" /* gva_read */
|
||||
#include "sigscan.h" /* mem_sub (pure matcher; engine may use it) */
|
||||
|
||||
bool pe_find_section(mem_view_t v, uint64_t module_base, const char* name,
|
||||
uint64_t* rva_out, uint32_t* vsize_out) {
|
||||
if (!v.data || !name || module_base < v.base_va) return false;
|
||||
const size_t mo = (size_t)(module_base - v.base_va);
|
||||
if (mo + 0x40 > v.size) return false;
|
||||
if (v.data[mo] != 'M' || v.data[mo + 1] != 'Z') return false;
|
||||
|
||||
int32_t e_lfanew;
|
||||
memcpy(&e_lfanew, v.data + mo + 0x3C, 4);
|
||||
const size_t nt = mo + (size_t)(uint32_t)e_lfanew;
|
||||
if (nt + 0x18 > v.size) return false;
|
||||
if (memcmp(v.data + nt, "PE\0\0", 4) != 0) return false;
|
||||
|
||||
uint16_t nsec, opt_size;
|
||||
memcpy(&nsec, v.data + nt + 6, 2); /* NumberOfSections */
|
||||
memcpy(&opt_size, v.data + nt + 20, 2); /* SizeOfOptionalHeader */
|
||||
|
||||
const size_t sec = nt + 24 + opt_size; /* first section header */
|
||||
size_t want = strlen(name);
|
||||
if (want > 8) want = 8;
|
||||
|
||||
for (uint16_t i = 0; i < nsec; i++) {
|
||||
const size_t sh = sec + (size_t)i * 40;
|
||||
if (sh + 40 > v.size) break;
|
||||
char nm[9] = {0};
|
||||
memcpy(nm, v.data + sh, 8);
|
||||
if (strncmp(nm, name, want) == 0 && (want == 8 || nm[want] == '\0')) {
|
||||
uint32_t vsize, vaddr;
|
||||
memcpy(&vsize, v.data + sh + 8, 4); /* Misc.VirtualSize */
|
||||
memcpy(&vaddr, v.data + sh + 12, 4); /* VirtualAddress */
|
||||
if (rva_out) *rva_out = vaddr;
|
||||
if (vsize_out) *vsize_out = vsize;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool pe_section(mem_view_t v, uint64_t module_base, const char* name, mem_view_t* out) {
|
||||
uint64_t rva; uint32_t vsize;
|
||||
if (!out || !pe_find_section(v, module_base, name, &rva, &vsize)) return false;
|
||||
*out = mem_sub(v, module_base + rva, vsize);
|
||||
return out->data != NULL;
|
||||
}
|
||||
|
||||
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) {
|
||||
uint8_t hdr[0x1000];
|
||||
if (!out || !buf || gva_read(m, cr3, module_base, hdr, sizeof hdr)) return -1;
|
||||
const mem_view_t hv = { hdr, sizeof hdr, module_base };
|
||||
uint64_t rva; uint32_t vsize;
|
||||
if (!pe_find_section(hv, module_base, name, &rva, &vsize)) return -1;
|
||||
const size_t n = vsize < bufcap ? vsize : bufcap;
|
||||
if (gva_read(m, cr3, module_base + rva, buf, n)) return -1;
|
||||
out->data = buf; out->size = n; out->base_va = module_base + rva;
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user