102 lines
3.9 KiB
C
102 lines
3.9 KiB
C
/*
|
|
* Warlock's Stave — Quick FFI Demo Harness
|
|
*
|
|
* Compile: gcc -o demo demo.c -ldl -Wl,-rpath,./target/release
|
|
* Run: LD_LIBRARY_PATH=./target/release ./demo
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <dlfcn.h>
|
|
|
|
/* Mirrors the 4 C-FFI functions from libstave_core.so */
|
|
typedef void* (*init_fn)(void);
|
|
typedef const char* (*ingest_fn)(void*, const unsigned char*, size_t, unsigned long, unsigned int);
|
|
typedef void (*free_str_fn)(const char*);
|
|
typedef void (*destroy_fn)(void*);
|
|
|
|
int main(void) {
|
|
printf("=== Warlock's Stave FFI Demo ===\n\n");
|
|
|
|
/* --- Load the shared library --- */
|
|
void *lib = dlopen("./target/release/libstave_core.so", RTLD_NOW);
|
|
if (!lib) {
|
|
fprintf(stderr, "dlopen failed: %s\n", dlerror());
|
|
fprintf(stderr, "Run ./build.sh first, then use:\n");
|
|
fprintf(stderr, " LD_LIBRARY_PATH=./target/release ./demo\n");
|
|
return 1;
|
|
}
|
|
|
|
init_fn init = (init_fn) dlsym(lib, "initialize_warlock_stave");
|
|
ingest_fn ingest = (ingest_fn) dlsym(lib, "stave_ingest_frame");
|
|
free_str_fn freestr = (free_str_fn)dlsym(lib, "free_stave_string");
|
|
destroy_fn destroy = (destroy_fn) dlsym(lib, "destroy_warlock_stave");
|
|
|
|
if (!init || !ingest || !freestr || !destroy) {
|
|
fprintf(stderr, "dlsym failed: %s\n", dlerror());
|
|
dlclose(lib);
|
|
return 1;
|
|
}
|
|
|
|
/* --- Initialize the engine --- */
|
|
void *ctx = init();
|
|
printf("[Engine] Context created: %p\n\n", ctx);
|
|
|
|
/*
|
|
* Feed a realistic x86-64 sequence.
|
|
* Each frame: (bytes, length, RIP, EFLAGS)
|
|
*
|
|
* Instructions:
|
|
* 0x7FF0: 48 31 C0 xor rax, rax
|
|
* 0x7FF3: 48 89 C3 mov rbx, rax
|
|
* 0x7FF6: 0F 84 10 00 00 00 je +0x10 (conditional — ZF=1 in EFLAGS)
|
|
* 0x7FFC: E9 05 00 00 00 jmp +0x5 (unconditional)
|
|
* 0x8001: 48 83 C4 28 add rsp, 0x28
|
|
*/
|
|
struct { unsigned char *bytes; size_t len; unsigned long rip; unsigned int eflags; } frames[] = {
|
|
{ (unsigned char[]){ 0x48, 0x31, 0xC0 }, 3, 0x7FF0, 0x202 }, /* ZF=1 */
|
|
{ (unsigned char[]){ 0x48, 0x89, 0xC3 }, 3, 0x7FF3, 0x202 },
|
|
{ (unsigned char[]){ 0x0F, 0x84, 0x10, 0x00, 0x00, 0x00 }, 6, 0x7FF6, 0x246 }, /* ZF=1, SF=1 */
|
|
{ (unsigned char[]){ 0xE9, 0x05, 0x00, 0x00, 0x00 }, 5, 0x7FFC, 0x246 },
|
|
{ (unsigned char[]){ 0x48, 0x83, 0xC4, 0x28 }, 4, 0x8001, 0x246 },
|
|
};
|
|
int n = sizeof(frames) / sizeof(frames[0]);
|
|
|
|
for (int i = 0; i < n; i++) {
|
|
const char *json = ingest(ctx, frames[i].bytes, frames[i].len,
|
|
frames[i].rip, frames[i].eflags);
|
|
printf("[Frame %d] RIP=0x%04lX bytes=%zu EFLAGS=0x%X\n",
|
|
i+1, frames[i].rip, frames[i].len, frames[i].eflags);
|
|
printf(" %s\n\n", json);
|
|
freestr(json);
|
|
}
|
|
|
|
/* --- Telemetry round-trip: hit the same cell twice --- */
|
|
printf("[Frame 6] Re-visiting RIP=0x7FF0 (heatmap intensity should increase)...\n");
|
|
const char *json = ingest(ctx,
|
|
(unsigned char[]){ 0x48, 0x31, 0xC0 }, 3, 0x7FF0, 0x202);
|
|
printf(" %s\n\n", json);
|
|
freestr(json);
|
|
|
|
/* --- Conditional branch with ZF=0 (not-taken path) --- */
|
|
printf("[Frame 7] je with ZF=0 (should report ConditionNotMet)...\n");
|
|
json = ingest(ctx,
|
|
(unsigned char[]){ 0x0F, 0x84, 0x10, 0x00, 0x00, 0x00 }, 6, 0x7FF6, 0x242);
|
|
printf(" %s\n\n", json);
|
|
freestr(json);
|
|
|
|
/* --- Dictionary scan: URL pattern in bytes --- */
|
|
printf("[Frame 8] Bytes containing 'http://' (dictionary hit expected)...\n");
|
|
json = ingest(ctx,
|
|
(unsigned char[]){ 0x68, 0x74, 0x74, 0x70, 0x3A, 0x2F, 0x2F }, 7, 0x9000, 0x246);
|
|
printf(" %s\n\n", json);
|
|
freestr(json);
|
|
|
|
/* --- Cleanup --- */
|
|
destroy(ctx);
|
|
dlclose(lib);
|
|
|
|
printf("=== Done. ===\n");
|
|
return 0;
|
|
} |