mirror of
https://dev.lirent.ru/Vatrog/vm-introspection-engine.git
synced 2026-06-18 02:06:36 +03:00
93966c3df2
Name and isolate the Windows engine as one of potentially several. The public surface moves to include/win32.h with an opaque vmie_win32 handle (vmie_win32_open/close/mem); the engine's Windows internals — host bring-up, the struct-offset profile, process/module/PE/text decode — live under src/engine/win32. The generic address-space layer stays in src/engine (gva.c + engine-arch.h, carrying no offset table): gva.c is de-profiled, and CR3 bring-up reaches the hot translator through a cold gva_translate bridge so the zero-copy hot path stays private and inlinable. A memory source is now first-class and public: vmie_mem_open/_open_segs/ _close open a flat dump (or an explicit segment map) as a vmie_mem, with gpa_seg promoted to the public contract. The physical signature scan is exposed source-agnostically: sig_scan_mem returns GPAs for any vmie_mem, sig_scan_sources scans several sources with per-source attribution, and sig_from_bytes builds an exact needle from a byte span. The pure matcher is unchanged; dumps and the live engine image are scanned uniformly, neither needing the other.
53 lines
2.1 KiB
C
53 lines
2.1 KiB
C
#include <stdint.h>
|
|
#include <stddef.h>
|
|
#include "engine-win32.h"
|
|
#include "win32.h"
|
|
|
|
static void utf8_emit(uint32_t cp, char* dst, size_t size, size_t* need, size_t* wrote) {
|
|
uint8_t b[4]; size_t k;
|
|
if (cp < 0x80) { b[0]=(uint8_t)cp; k=1; }
|
|
else if (cp < 0x800) { b[0]=0xC0|(uint8_t)(cp>>6); b[1]=0x80|(cp&0x3F); k=2; }
|
|
else if (cp < 0x10000) { b[0]=0xE0|(uint8_t)(cp>>12); b[1]=0x80|((cp>>6)&0x3F); b[2]=0x80|(cp&0x3F); k=3; }
|
|
else { b[0]=0xF0|(uint8_t)(cp>>18); b[1]=0x80|((cp>>12)&0x3F); b[2]=0x80|((cp>>6)&0x3F); b[3]=0x80|(cp&0x3F); k=4; }
|
|
if (dst && *need + k < size) {
|
|
for (size_t j = 0; j < k; j++) dst[*need + j] = (char)b[j];
|
|
*wrote = *need + k; /* end of last full code point */
|
|
}
|
|
*need += k;
|
|
}
|
|
|
|
size_t gva_read_text(vmie_win32* v, uintptr_t cr3, uintptr_t va, size_t nmemb, char* dst, size_t size) {
|
|
vmie_mem* m = &v->mem;
|
|
size_t need = 0, wrote = 0;
|
|
uint16_t stage[256];
|
|
uint32_t hi = 0;
|
|
nmemb &= ~(size_t)1;
|
|
|
|
while (nmemb) {
|
|
size_t chunk = nmemb < sizeof stage ? nmemb : sizeof stage;
|
|
if (gva_read(m, cr3, va, stage, chunk)) {
|
|
break;
|
|
}
|
|
const size_t units = chunk / 2;
|
|
for (size_t i = 0; i < units; i++) {
|
|
uint32_t u = stage[i];
|
|
if (hi) {
|
|
if (u >= 0xDC00 && u <= 0xDFFF) {
|
|
utf8_emit(0x10000u + ((hi - 0xD800u) << 10) + (u - 0xDC00u), dst, size, &need, &wrote);
|
|
hi = 0;
|
|
continue;
|
|
}
|
|
utf8_emit(0xFFFD, dst, size, &need, &wrote);
|
|
hi = 0;
|
|
}
|
|
if (u >= 0xD800 && u <= 0xDBFF) hi = u;
|
|
else if (u >= 0xDC00 && u <= 0xDFFF) utf8_emit(0xFFFD, dst, size, &need, &wrote);
|
|
else utf8_emit(u, dst, size, &need, &wrote);
|
|
}
|
|
va += chunk;
|
|
nmemb -= chunk;
|
|
}
|
|
if (hi) utf8_emit(0xFFFD, dst, size, &need, &wrote);
|
|
if (dst && size) dst[need < size ? need : wrote] = 0;
|
|
return need;
|
|
} |