mirror of
https://dev.lirent.ru/Vatrog/vm-introspection-engine.git
synced 2026-06-18 02:06:36 +03:00
1ec70b7ede
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.
106 lines
2.3 KiB
C
106 lines
2.3 KiB
C
#include <stdint.h>
|
|
#include <stddef.h>
|
|
#include <string.h>
|
|
#include <fcntl.h>
|
|
#include <unistd.h>
|
|
#include <sys/mman.h>
|
|
#include <sys/stat.h>
|
|
#include "include/memory.h"
|
|
|
|
#define RAM_H (1ul<<32)
|
|
#define PROT_RW (PROT_READ | PROT_WRITE)
|
|
|
|
__attribute__((hot))
|
|
static int gpa_offset(const gpa_ctx* ctx, uintptr_t offs, uintptr_t* out) {
|
|
if (offs < ctx->low) {
|
|
*out = offs;
|
|
return 0;
|
|
}
|
|
|
|
if (offs >= RAM_H) {
|
|
const uint64_t x = ctx->low + (offs - RAM_H);
|
|
|
|
if (x < ctx->fsize) {
|
|
*out = x;
|
|
return 0;
|
|
} else { /* Out of bounds */ }
|
|
} else { /* Not RAM */ }
|
|
|
|
return -1;
|
|
}
|
|
|
|
static void clean_ctx(gpa_ctx* ctx) {
|
|
memset(ctx, 0, sizeof(gpa_ctx));
|
|
ctx->fd = -1;
|
|
}
|
|
|
|
static int out_of_bounds(gpa_ctx* ctx, uintptr_t* offs, const size_t nmemb) {
|
|
return gpa_offset(ctx, *offs, offs) || *offs + nmemb > ctx->fsize;
|
|
}
|
|
|
|
__attribute__((hot))
|
|
int gpa_read(gpa_ctx* ctx, uintptr_t offs, void* buf, const size_t nmemb) {
|
|
if (out_of_bounds(ctx, &offs, nmemb)) {
|
|
return -1;
|
|
}
|
|
memcpy(buf, ctx->pa + offs, nmemb);
|
|
return 0;
|
|
}
|
|
|
|
int gpa_write(gpa_ctx* ctx, uintptr_t offs, const void* src, const size_t nmemb) {
|
|
if (out_of_bounds(ctx, &offs, nmemb)) {
|
|
return -1;
|
|
}
|
|
memcpy(ctx->pa + offs, src, nmemb);
|
|
return 0;
|
|
}
|
|
|
|
/* Zero-copy host pointer to [offs, offs+nmemb) GPA, or NULL if that range is not
|
|
* fully backed by the mapped image. Same split + bounds check as gpa_read. */
|
|
void* gpa_ptr(gpa_ctx* ctx, uintptr_t offs, const size_t nmemb) {
|
|
if (out_of_bounds(ctx, &offs, nmemb)) {
|
|
return NULL;
|
|
}
|
|
return (uint8_t*)ctx->pa + offs;
|
|
}
|
|
|
|
__attribute__((cold))
|
|
int gpa_open(gpa_ctx* ctx, const char* path, uintptr_t low) {
|
|
struct stat st;
|
|
|
|
if ((ctx->fd = open(path, O_RDWR)) < 0) {
|
|
goto ret_;
|
|
}
|
|
|
|
if (fstat(ctx->fd, &st)) {
|
|
goto close_;
|
|
}
|
|
|
|
if ((ctx->pa = mmap(NULL, st.st_size, PROT_RW, MAP_SHARED, ctx->fd, 0)) == MAP_FAILED) {
|
|
close_:
|
|
close(ctx->fd);
|
|
ret_:
|
|
clean_ctx(ctx);
|
|
return -1;
|
|
}
|
|
|
|
ctx->fsize = st.st_size;
|
|
ctx->low = low;
|
|
|
|
return 0;
|
|
}
|
|
|
|
__attribute__((cold))
|
|
void gpa_close(gpa_ctx* ctx) {
|
|
if (ctx->pa) {
|
|
munmap(ctx->pa, ctx->fsize);
|
|
}
|
|
|
|
if (ctx->fd >= 0) {
|
|
close(ctx->fd);
|
|
}
|
|
|
|
clean_ctx(ctx);
|
|
}
|
|
|