Add a dump-scan demonstrator (vmie_scan)

A thin CLI proving the OS-agnostic dump path end to end: open one or more raw
memory dumps as flat identity images (vmie_mem) and scan them all for an
IDA-style pattern, printing each hit as source:gpa. Two-pass (count, then size
the buffer exactly) so nothing is silently truncated.

Kept separate from vmie_cli rather than folded in as a subcommand: vmie_cli
demonstrates live win32 bring-up, this demonstrates the source-agnostic scan.
Its source includes only the public memmodel/sigscan/scan headers and names no
Windows symbol - it compiles against include/ alone.
This commit is contained in:
2026-06-16 16:25:27 +03:00
parent dc09d7f2a4
commit 25b8ed8ca9
2 changed files with 96 additions and 0 deletions
+5
View File
@@ -35,6 +35,11 @@ add_executable(vmie_cli src/cli.c)
target_link_libraries(vmie_cli PRIVATE vmie) # public include/ comes via vmie (PUBLIC) target_link_libraries(vmie_cli PRIVATE vmie) # public include/ comes via vmie (PUBLIC)
target_compile_options(vmie_cli PRIVATE -Wall -Wextra) target_compile_options(vmie_cli PRIVATE -Wall -Wextra)
# ---- host: dump-scan demonstrator (OS-agnostic, no win32) ----------------
add_executable(vmie_scan src/scan_cli.c)
target_link_libraries(vmie_scan PRIVATE vmie)
target_compile_options(vmie_scan PRIVATE -Wall -Wextra)
# ---- guest: cross-compile to Windows x86-64 via mingw-w64 --------------- # ---- guest: cross-compile to Windows x86-64 via mingw-w64 ---------------
find_program(MINGW_CC NAMES x86_64-w64-mingw32-gcc REQUIRED) find_program(MINGW_CC NAMES x86_64-w64-mingw32-gcc REQUIRED)
set(VMIE_STARTUP ${CMAKE_CURRENT_BINARY_DIR}/vmie-startup.exe) set(VMIE_STARTUP ${CMAKE_CURRENT_BINARY_DIR}/vmie-startup.exe)
+91
View File
@@ -0,0 +1,91 @@
/* scan_cli.c - thin demonstrator of the OS-agnostic dump -> signature path.
*
* Opens one or more raw memory dumps as flat physical images (vmie_mem) and
* scans them all for an IDA-style byte pattern, printing every hit as
* "source:gpa". No guest, no bootstrap, no win32: this links only the dump
* source (core), the physical signature bridge, and the pure matcher - proof
* that scanning a dump needs nothing from the Windows engine.
*
* argv[1] IDA pattern, e.g. "48 8B 05 ? ? ? ? 48 85 C0"
* argv[2..] one or more dump files, each mapped as a flat identity image
* (reported GPA == file offset)
*/
#include <stdint.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <inttypes.h>
#include "memmodel.h" /* vmie_mem_open / vmie_mem_close */
#include "sigscan.h" /* sig_parse_ida / sig_pattern_t / sig_free */
#include "scan.h" /* sig_scan_sources / sig_hit_src */
int main(int argc, char** argv) {
if (argc < 3) {
fprintf(stderr, "usage: %s <ida-pattern> <dump-file> [dump-file...]\n",
argc > 0 ? argv[0] : "vmie_scan");
return 2;
}
sig_pattern_t pat;
if (!sig_parse_ida(argv[1], &pat)) {
fprintf(stderr, "error: bad IDA pattern: '%s'\n", argv[1]);
return 2;
}
const int nsrc = argc - 2;
vmie_mem** srcs = calloc((size_t)nsrc, sizeof *srcs);
if (!srcs) {
fprintf(stderr, "error: out of memory\n");
sig_free(&pat);
return 1;
}
int rc = 0, opened = 0;
for (int i = 0; i < nsrc; i++) {
const char* path = argv[2 + i];
srcs[i] = vmie_mem_open(path, ~0ull); /* low >= fsize => flat identity dump */
if (!srcs[i]) {
fprintf(stderr, "error: cannot open dump '%s'\n", path);
rc = 1;
goto cleanup;
}
opened++;
}
{
/* count pass (out == NULL), then size the buffer exactly: no caps, no
* silent truncation. */
const int total = sig_scan_sources(srcs, nsrc, &pat, NULL, 0);
if (total < 0) {
fprintf(stderr, "error: scan failed (%d)\n", total);
rc = 1;
goto cleanup;
}
if (total == 0) {
printf("no matches in %d source(s)\n", nsrc);
goto cleanup;
}
sig_hit_src* hits = malloc((size_t)total * sizeof *hits);
if (!hits) {
fprintf(stderr, "error: out of memory\n");
rc = 1;
goto cleanup;
}
const int got = sig_scan_sources(srcs, nsrc, &pat, hits, total);
for (int i = 0; i < got; i++) {
printf("%d:%016" PRIx64 " %s\n",
hits[i].source, hits[i].gpa, argv[2 + hits[i].source]);
}
printf("%d match(es) across %d source(s)\n", got, nsrc);
free(hits);
}
cleanup:
for (int i = 0; i < opened; i++) {
vmie_mem_close(srcs[i]);
}
free(srcs);
sig_free(&pat);
return rc;
}