/* pmap.h - pointer-graph index and structure analysis (OS-agnostic handler). * * Layered above the memory-model contract (memmodel.h) and the scanning surface * (scan.h, for `range` and `scan_ptr_path`). A `pmap` is a one-pass reverse + * forward index of every intra-address-space pointer under a `cr3`: for each * 8-byte-aligned qword whose VALUE lands inside a mapped region, it records the * edge `referrer_va -> target_va`. Two sorted views answer the keystone queries * in O(log n): who-points-here (referrers) and what-does-this-point-to * (targets). Everything is keyed by `vmie_mem* + cr3`; it names no Windows * object. * * Ownership: pmap_build / pmap_free (create/destroy). All queries are read-only * and re-entrant against a built pmap; pmap_free is safe on NULL. */ #ifndef VMIE_PMAP_H #define VMIE_PMAP_H #include #include #include "memmodel.h" /* vmie_mem, vregion, range */ #include "scan.h" /* scan_ptr_path, SCAN_PTR_MAXDEPTH */ typedef struct pmap pmap; /* reverse + forward index (opaque) */ /* One gva_sweep over [lo,hi] (prot filter): for every 8-byte-aligned qword whose * VALUE lands inside a mapped region (membership tested against a gva_regions * set), record the edge referrer_va -> target_va. Stores two sorted views (by * target, by referrer) for O(log n) queries. Returns NULL on OOM or bad input. */ pmap* pmap_build(vmie_mem* m, uintptr_t cr3, uint64_t lo, uint64_t hi, uint32_t prot_any); /* Release a pmap from pmap_build. Safe on NULL. */ void pmap_free(pmap* pm); /* All VAs holding a pointer whose value == target_va. THE keystone query: * who-points-here; vtable-instance enumeration (target = a vtable VA, since an * object's first qword is its vtable); string-xref target. Writes up to `max` * referrer VAs to `out` (NULL to count only) and returns the TOTAL. */ int pmap_referrers(const pmap* pm, uint64_t target_va, uint64_t* out, int max); /* Forward edges: pointer VALUES stored at/around referrer_va (what this region * points to). For path walking / dissection. Writes up to `max` target VAs to * `out` (NULL to count only) and returns the TOTAL. */ int pmap_targets(const pmap* pm, uint64_t referrer_va, uint64_t* out, int max); /* Map-accelerated pointer paths to `target`, anchored on module ranges `mods`. * Same result type as scan_pointer. Cost profile differs deliberately: * scan_pointer is a ONE-SHOT live DFS that builds no index (low memory for a * single query); pmap_paths runs over the ALREADY-BUILT index (one sweep amort- * ized across many cheap queries). Not a duplicate path - a different trade-off. * Writes up to `max` paths to `out` and returns the TOTAL, or -1 on bad input. */ int pmap_paths(const pmap* pm, uint64_t target, const range* mods, int nmods, int max_depth, uint32_t max_off, scan_ptr_path* out, int max); /* string-xref: find the needle bytes anywhere in the AS (matcher over the * sweep), then pmap_referrers for each occurrence's VA. The caller pre-encodes * the byte image (e.g. a UTF-16 string), so `needle`/`nlen` are matched as raw * bytes. Writes up to `max` referrer VAs to `out` (NULL to count only) and * returns the TOTAL number of referrers, or -1 on bad input. */ int xref_string(vmie_mem* m, uintptr_t cr3, const pmap* pm, const void* needle, size_t nlen, uint64_t* out, int max); /* ---- structure dissection ------------------------------------------------ * * Classify each 8-byte slot in [va, va+nbytes). */ typedef enum { FK_UNKNOWN, FK_PTR, FK_VTABLE, FK_F32, FK_F64, FK_I32, FK_I64, FK_ASCII, FK_UTF16 } field_kind; typedef struct { uint32_t off; /* byte offset from va */ field_kind kind; uint64_t raw; /* the raw 8 bytes at off */ uint64_t target; /* pointee VA for FK_PTR/FK_VTABLE, else 0 */ } field_desc; /* Classify each slot: PTR = value lands in a mapped region. VTABLE = value * points into a non-writable region whose first qwords are themselves pointers * into X-regions. F32/F64 = finite, sane magnitude. ASCII/UTF16 = printable run * >= 4. Else I32/I64/UNKNOWN. Reuses gva_read + gva_regions (+ pm if given, may * be NULL). Writes slots to `out` and returns the number written (<= max). */ int struct_dissect(vmie_mem* m, uintptr_t cr3, uint64_t va, size_t nbytes, const pmap* pm, field_desc* out, int max); #endif /* VMIE_PMAP_H */