warlocks-stave/src/bin/simulate_evasion_telemetry.rs

97 lines
3.5 KiB
Rust

/// Standalone binary that simulates a polymorphic IPC evasion event
/// for verification testing. Connects to the running Stave IPC daemon
/// and sends a sequence of payloads that mimic a process shifting its
/// communication channels.
///
/// Usage:
/// Terminal 1: cargo run --bin environment_check && ./build.sh
/// Terminal 2: cargo run --bin simulate_evasion_telemetry
use std::io::Write;
use std::net::TcpStream;
use std::os::unix::net::UnixStream;
fn main() {
println!("=== Warlock's Stave: Evasion Telemetry Simulator ===");
println!("Simulating polymorphic IPC evasion pattern...\n");
// Stage 1: Attempt Unix socket connection (normal path)
let socket_path = "/tmp/stave_bridge_ipc.sock";
if std::path::Path::new(socket_path).exists() {
println!("[STAGE 1] Connecting via Unix socket...");
match UnixStream::connect(socket_path) {
Ok(mut stream) => {
send_test_payload(&mut stream, 0x7FFFFFFE0000, 0x202);
println!("[STAGE 1] Unix socket payload delivered.\n");
}
Err(e) => {
println!("[STAGE 1] Unix socket failed: {}. Falling back to TCP.", e);
}
}
} else {
println!("[STAGE 1] Unix socket not found. Skipping to TCP.");
}
// Stage 2: TCP fallback (containerized / evasion scenario)
println!("[STAGE 2] Connecting via TCP fallback (port 21860)...");
match TcpStream::connect("127.0.0.1:21860") {
Ok(mut stream) => {
stream
.set_nodelay(true)
.expect("Failed to set TCP_NODELAY");
let test_rips = [
0x7FFFF7A01000u64,
0x7FFFF7A01003,
0x7FFFF7A01005,
0x7FFFF7A0100A,
0x7FFFF7A0100C,
];
for (i, rip) in test_rips.iter().enumerate() {
send_test_payload(&mut stream, *rip, 0x202);
println!(
"[STAGE 2] Evasion payload {}/{} delivered (RIP: {:#018X})",
i + 1,
test_rips.len(),
rip
);
}
send_test_payload(&mut stream, 0x7FFFF7A01010, 0x246);
println!("[STAGE 2] Final payload with altered EFLAGS delivered.");
}
Err(e) => {
println!(
"[STAGE 2] TCP connection failed: {}",
e
);
println!("Is the Stave daemon running? Try: ./build.sh first.");
return;
}
}
println!("\n=== Simulation complete. ===");
println!("Check the Stave dashboard for:");
println!(" - Hex heatmap updates at the delivered RIP coordinates");
println!(" - Branch evaluation results in the telemetry output");
println!(" - Dictionary scanner hits for embedded patterns");
}
/// Constructs and sends a payload matching the WineIpcPayload layout.
/// Layout: u64 rip (8) + u32 eflags (4) + u32 buf_len (4) + u8[15] = 31 bytes
fn send_test_payload<W: Write>(
stream: &mut W,
rip: u64,
eflags: u32,
) {
let mut payload = Vec::with_capacity(31);
payload.extend_from_slice(&rip.to_le_bytes());
payload.extend_from_slice(&eflags.to_le_bytes());
payload.extend_from_slice(&5u32.to_le_bytes());
payload.extend_from_slice(&[0x48, 0x31, 0xC0, 0x90, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
stream
.write_all(&payload)
.expect("Failed to write payload");
stream.flush().expect("Failed to flush");
}