mirror of
https://dev.lirent.ru/Vatrog/vm-introspection-engine.git
synced 2026-06-18 04:16:39 +03:00
Windows guest VMI core: host library, CLI, guest agent
Static library over a flat RW mmap of guest RAM: GPA/GVA paging walks, beacon-driven bootstrap, dynamic struct-offset profiling, process and module enumeration, a region map, and value/pointer/signature scanners on a shared windowed sweep. Public API in include/; internals under src/. Thin CLI demonstrator over the public API. Guest agent cross-compiled to Windows x86-64 via mingw-w64. CMake: static library + CLI + guest target, C17.
This commit is contained in:
@@ -0,0 +1,161 @@
|
||||
/* cli.c - thin demonstrator over the public w32ms API.
|
||||
*
|
||||
* Opens a guest RAM backing file, brings up the VMI context, lists processes,
|
||||
* and for the first user process dumps its loaded modules and mapped regions.
|
||||
* Public surface only (include/include.h); never reaches into src/include.
|
||||
*
|
||||
* argv[1] path to the guest RAM backing file
|
||||
* argv[2] `low` - size in bytes of below-4G guest RAM (strtoull, base 0)
|
||||
* argv[3] optional cap on the process count (default 512)
|
||||
*/
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <inttypes.h>
|
||||
#include "include.h"
|
||||
|
||||
#define DEFAULT_NMAX 512
|
||||
#define MOD_CAP 256
|
||||
#define RGN_CAP 4096
|
||||
#define TEXT_CAP 512
|
||||
|
||||
static const char* bootstrap_stage(int rc) {
|
||||
switch (rc) {
|
||||
case -1: return "beacon not found in guest RAM";
|
||||
case -2: return "could not recover a bootstrap CR3";
|
||||
case -3: return "ntoskrnl not located";
|
||||
case -4: return "PsInitialSystemProcess unresolved";
|
||||
case -5: return "struct-offset profile build failed";
|
||||
case -6: return "kernel DirectoryTableBase read failed";
|
||||
default: return "unknown bootstrap failure";
|
||||
}
|
||||
}
|
||||
|
||||
static void decode_prot(uint32_t prot, char out[5]) {
|
||||
out[0] = (prot & VR_R) ? 'R' : '-';
|
||||
out[1] = (prot & VR_W) ? 'W' : '-';
|
||||
out[2] = (prot & VR_X) ? 'X' : '-';
|
||||
out[3] = (prot & VR_U) ? 'U' : '-';
|
||||
out[4] = 0;
|
||||
}
|
||||
|
||||
static void dump_modules(gva_ctx* ctx, const process* pr) {
|
||||
pmodule mods[MOD_CAP];
|
||||
const int nm = proc_modules(ctx, pr, mods, MOD_CAP);
|
||||
if (nm <= 0) {
|
||||
printf(" (no modules)\n");
|
||||
return;
|
||||
}
|
||||
for (int i = 0; i < nm; i++) {
|
||||
char name[TEXT_CAP], path[TEXT_CAP];
|
||||
/* module strings are user-space: read under the process cr3. */
|
||||
if (mods[i].name.va) {
|
||||
gva_read_text(ctx, pr->cr3, mods[i].name.va, mods[i].name.len, name, sizeof name);
|
||||
} else {
|
||||
name[0] = 0;
|
||||
}
|
||||
if (mods[i].path.va) {
|
||||
gva_read_text(ctx, pr->cr3, mods[i].path.va, mods[i].path.len, path, sizeof path);
|
||||
} else {
|
||||
path[0] = 0;
|
||||
}
|
||||
printf(" %016" PRIx64 " %8" PRIu32 " %-24s %s\n",
|
||||
mods[i].base, mods[i].size,
|
||||
name[0] ? name : "<unreadable>",
|
||||
path[0] ? path : "");
|
||||
}
|
||||
}
|
||||
|
||||
static void dump_regions(gva_ctx* ctx, const process* pr) {
|
||||
vregion* rg = malloc((size_t)RGN_CAP * sizeof *rg);
|
||||
if (!rg) {
|
||||
return;
|
||||
}
|
||||
const int total = gva_regions(ctx, pr->cr3, 0, ~0ull, 0, rg, RGN_CAP);
|
||||
const int shown = total < 0 ? 0 : (total < RGN_CAP ? total : RGN_CAP);
|
||||
for (int i = 0; i < shown; i++) {
|
||||
char prot[5];
|
||||
decode_prot(rg[i].prot, prot);
|
||||
printf(" %016" PRIx64 " %12" PRIu64 " %s\n", rg[i].va, rg[i].len, prot);
|
||||
}
|
||||
if (total > shown) {
|
||||
printf(" ... (%d more regions truncated)\n", total - shown);
|
||||
}
|
||||
free(rg);
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
if (argc < 3) {
|
||||
fprintf(stderr, "usage: %s <ram-file> <low> [nmax]\n",
|
||||
argc > 0 ? argv[0] : "w32ms_cli");
|
||||
return 2;
|
||||
}
|
||||
|
||||
const char* ram_path = argv[1];
|
||||
const uint64_t low = strtoull(argv[2], NULL, 0);
|
||||
size_t nmax = DEFAULT_NMAX;
|
||||
if (argc > 3) {
|
||||
const unsigned long long v = strtoull(argv[3], NULL, 0);
|
||||
if (v > 0) {
|
||||
nmax = (size_t)v;
|
||||
}
|
||||
}
|
||||
|
||||
gva_ctx* ctx = gva_ctx_alloc(ram_path, low);
|
||||
if (!ctx) {
|
||||
fprintf(stderr, "error: cannot open RAM backing file '%s'\n", ram_path);
|
||||
return 1;
|
||||
}
|
||||
|
||||
const int rc = host_bootstrap(ctx);
|
||||
if (rc != 0) {
|
||||
fprintf(stderr, "error: bootstrap failed (%d): %s\n", rc, bootstrap_stage(rc));
|
||||
gva_ctx_free(ctx);
|
||||
return 1;
|
||||
}
|
||||
|
||||
process* procs = malloc(nmax * sizeof *procs);
|
||||
if (!procs) {
|
||||
fprintf(stderr, "error: out of memory\n");
|
||||
gva_ctx_free(ctx);
|
||||
return 1;
|
||||
}
|
||||
|
||||
const int np = proc_list(ctx, 1, procs, nmax);
|
||||
if (np < 0) {
|
||||
fprintf(stderr, "error: proc_list failed (%d)\n", np);
|
||||
free(procs);
|
||||
gva_ctx_free(ctx);
|
||||
return 1;
|
||||
}
|
||||
|
||||
printf("%-6s %-6s %-16s %-18s %-18s %-18s\n",
|
||||
"PID", "PPID", "NAME", "CR3", "EPROCESS", "PEB");
|
||||
for (int i = 0; i < np; i++) {
|
||||
const process* p = &procs[i];
|
||||
char ppid[12];
|
||||
if (p->ppid == (uint32_t)-1) {
|
||||
snprintf(ppid, sizeof ppid, "%s", "?");
|
||||
} else {
|
||||
snprintf(ppid, sizeof ppid, "%" PRIu32, p->ppid);
|
||||
}
|
||||
printf("%-6" PRIu32 " %-6s %-16s %016" PRIx64 " %016" PRIx64 " %016" PRIx64 "\n",
|
||||
p->pid, ppid, p->name[0] ? p->name : "<unnamed>",
|
||||
p->cr3, p->eprocess, p->peb);
|
||||
}
|
||||
|
||||
if (np > 0) {
|
||||
const process* first = &procs[0];
|
||||
printf("\nmodules of PID %" PRIu32 " (%s):\n",
|
||||
first->pid, first->name[0] ? first->name : "<unnamed>");
|
||||
dump_modules(ctx, first);
|
||||
printf("\nregions of PID %" PRIu32 " (%s):\n",
|
||||
first->pid, first->name[0] ? first->name : "<unnamed>");
|
||||
dump_regions(ctx, first);
|
||||
}
|
||||
|
||||
free(procs);
|
||||
gva_ctx_free(ctx);
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user