mirror of
https://dev.lirent.ru/Vatrog/vm-introspection-engine.git
synced 2026-06-18 02:06:36 +03:00
4015e839eb
gva_ptr: leaf-bounded zero-copy guest reads. gva_sweep redesigned to drive on it — large-page leaves are lent to the callback while 4K runs stay buffered, and the run loop is guarded against wrap at the top of the address space. gva_gpa fetches PTEs zero-copy; optional W32MS_LTO build option folds the per-fetch call boundary (shipped -O2 default unchanged). Correctness: subtract-form bounds check (no add overflow), memcpy decode in place of type-punned wide loads, zero-init PDB name before compare, PCI-hole-crossing range rejection, single-sourced VA_CANON and USER bounds. hot/cold attributes audited across the translation and scan path.
112 lines
3.3 KiB
C
112 lines
3.3 KiB
C
#include <stdint.h>
|
|
#include <stddef.h>
|
|
#include <string.h>
|
|
#include "include/memory.h"
|
|
#include "../include/include.h"
|
|
|
|
#define pr_(ctx) ((ctx)->prof)
|
|
|
|
#define RING_GUARD 100000u
|
|
#define MOD_GUARD 4096u
|
|
|
|
static void grab_ustr(gva_ctx* ctx, uintptr_t cr3, uint64_t va, gtext* out) {
|
|
uint16_t len = 0;
|
|
uint64_t buf = 0;
|
|
out->va = 0;
|
|
out->len = 0;
|
|
if (gva_read(ctx, cr3, va, &len, 2) || gva_read(ctx, cr3, va + 8, &buf, 8)) {
|
|
return;
|
|
}
|
|
out->va = buf;
|
|
out->len = len;
|
|
}
|
|
|
|
int proc_list(gva_ctx* ctx, int skip_system, process* dst, size_t nmax) {
|
|
const profile* p = &pr_(ctx);
|
|
const uint64_t kcr3 = ctx->kcr3;
|
|
if (!kcr3 || !ctx->sysproc) {
|
|
return -1;
|
|
}
|
|
|
|
size_t n = 0;
|
|
unsigned guard = 0;
|
|
uint64_t ep = ctx->sysproc, node;
|
|
|
|
do {
|
|
uint64_t pid = 0, ppid = 0, dtb = 0, peb = 0;
|
|
gva_read(ctx, kcr3, ep + p->ep_pid, &pid, 8);
|
|
gva_read(ctx, kcr3, ep + p->ep_dtb, &dtb, 8);
|
|
if (p->ep_peb) { gva_read(ctx, kcr3, ep + p->ep_peb, &peb, 8); }
|
|
if (p->ep_ppid) { gva_read(ctx, kcr3, ep + p->ep_ppid, &ppid, 8); }
|
|
|
|
if (!skip_system || peb) {
|
|
if (n >= nmax) {
|
|
return (int)n;
|
|
}
|
|
process* q = &dst[n++];
|
|
q->eprocess = ep;
|
|
q->cr3 = dtb & PFN_MASK;
|
|
q->peb = peb;
|
|
q->pid = (uint32_t)pid;
|
|
q->ppid = p->ep_ppid ? (uint32_t)ppid : (uint32_t)-1;
|
|
q->create_time = 0;
|
|
if (p->ep_createtime) {
|
|
gva_read(ctx, kcr3, ep + p->ep_createtime, &q->create_time, 8);
|
|
}
|
|
memset(q->name, 0, sizeof q->name);
|
|
gva_read(ctx, kcr3, ep + p->ep_name, q->name, sizeof q->name - 1);
|
|
q->path.va = 0;
|
|
q->path.len = 0;
|
|
if (p->ep_imgpath) {
|
|
grab_ustr(ctx, kcr3, ep + p->ep_imgpath, &q->path); /* read text under kcr3 */
|
|
}
|
|
}
|
|
|
|
if (gva_read(ctx, kcr3, ep + p->ep_links, &node, 8)) {
|
|
break;
|
|
}
|
|
ep = node - p->ep_links;
|
|
} while (ep != ctx->sysproc && ++guard < RING_GUARD);
|
|
|
|
return (int)n;
|
|
}
|
|
|
|
int proc_modules(gva_ctx* ctx, const process* pr, pmodule* dst, size_t nmax) {
|
|
const profile* p = &pr_(ctx);
|
|
const uint64_t cr3 = pr->cr3;
|
|
if (!pr->peb || !cr3) {
|
|
return 0;
|
|
}
|
|
|
|
uint64_t ldr = 0, head, link;
|
|
if (gva_read(ctx, cr3, pr->peb + p->peb_ldr, &ldr, 8) || !ldr) {
|
|
return 0;
|
|
}
|
|
head = ldr + p->ldr_loadlist;
|
|
if (gva_read(ctx, cr3, head, &link, 8)) {
|
|
return 0;
|
|
}
|
|
|
|
size_t n = 0;
|
|
unsigned guard = 0;
|
|
while (link != head && n < nmax && ++guard < MOD_GUARD) {
|
|
const uint64_t entry = link; /* InLoadOrderLinks at offset 0 of the entry */
|
|
uint64_t base = 0;
|
|
uint32_t size = 0;
|
|
gva_read(ctx, cr3, entry + p->lde_base, &base, 8);
|
|
gva_read(ctx, cr3, entry + p->lde_size, &size, 4);
|
|
|
|
pmodule* m = &dst[n++];
|
|
m->pr = pr;
|
|
m->entry = entry;
|
|
m->base = base;
|
|
m->size = size;
|
|
grab_ustr(ctx, cr3, entry + p->lde_name, &m->name);
|
|
grab_ustr(ctx, cr3, entry + p->lde_fullname, &m->path);
|
|
|
|
if (gva_read(ctx, cr3, link, &link, 8)) {
|
|
break;
|
|
}
|
|
}
|
|
return (int)n;
|
|
} |