RustAegis
Advanced Rust code virtualization and obfuscation framework
Install / Use
/learn @onurkun/RustAegisREADME
🛡️ RustAegis
Next-Generation Virtualization & Obfuscation Framework for Rust
RustAegis is a research-grade software protection system that compiles Rust code into custom, polymorphic virtual machine bytecode. It is designed to protect sensitive logic against reverse engineering and tampering by moving execution from the native CPU to a secure, randomized software interpreter.
🚀 Key Features
- Virtualization: Converts Rust AST directly into a custom stack-based VM instruction set with 100+ opcodes.
- Native Function Calls: External functions called inside
#[vm_protect]are automatically wrapped and executed. No manual setup required. - Rich Type Support: Strings, Vectors/Arrays, integers (signed/unsigned), booleans with proper type tracking.
- Heap Memory: Dynamic memory allocation with automatic cleanup on scope exit.
- Variable Shadowing: Full Rust-like scoping with nested block support.
- Polymorphism: The instruction set mapping (Opcode Table) is randomized for every build via a
.build_seedartifact. - Mixed Boolean-Arithmetic (MBA): Transforms simple arithmetic (
+,-,^) into complex, mathematically equivalent boolean expressions. - Compile-Time Encryption: Bytecode is encrypted with a unique key per build and decrypted only at runtime.
- White-Box Cryptography (WBC): AES key derivation uses Chow et al. (2002) scheme - keys are never exposed in memory.
- Anti-Tamper: Integrated integrity checks ensure the bytecode has not been modified.
- Junk Code Injection: Inserts dead code and entropy-based instructions to break signature scanning.
- WASM Support: Full WebAssembly compatibility for browser and Node.js environments.
📦 Installation
Add the following to your Cargo.toml:
[dependencies]
aegis_vm = "0.2.51"
🛠️ Usage
Apply the #[vm_protect] attribute to any sensitive function you wish to virtualize.
use aegis_vm::vm_protect;
// Standard protection (Polymorphism + Encryption)
#[vm_protect]
fn check_password(input: u64) -> bool {
input == 0xCAFEBABE
}
// Paranoid protection (Heavy MBA + Obfuscation)
// Use this for critical logic like key derivation.
#[vm_protect(level = "paranoid")]
fn derive_key(seed: u64) -> u64 {
// All arithmetic here is transformed into complex boolean logic
(seed ^ 0x1234) + 0xABCD
}
// Advanced: Strings, Arrays, and Control Flow
#[vm_protect(level = "standard")]
fn compute_checksum() -> u64 {
let secret = "LICENSE-KEY";
let weights = [1, 2, 3, 4, 5];
// String length check
if secret.is_empty() {
return 0;
}
// Array iteration with weighted sum
let mut sum: u64 = 0;
for i in 0..weights.len() {
sum += weights.get(i) * (i as u64 + 1);
}
// Combine with string hash
sum + secret.len()
}
// NEW in v0.2.2: Native Function Calls
fn is_license_valid() -> bool {
// External license check logic
true
}
fn log_event(code: u64) {
println!("Event: {}", code);
}
#[vm_protect]
fn check_authorization() -> bool {
// External functions are automatically wrapped!
let valid: bool = is_license_valid(); // Note: explicit bool type
if !valid {
log_event(1); // Native call works
return false;
}
log_event(0);
true
}
⚙️ Architecture & The .build_seed
RustAegis uses a split architecture:
- Compiler (
vm-macro): Runs at compile time, generating encrypted bytecode. - Runtime (
vm): Runs inside your application, executing the bytecode.
Synchronization via .anticheat_build_seed
To ensure the compiler uses the exact same encryption keys and opcode mapping that the runtime expects, the system generates a temporary artifact named .anticheat_build_seed in your project root during the build process.
- Local Development: This happens automatically. If you encounter a "Build ID mismatch" error, simply run
cargo cleanto regenerate the seed. - CI/CD: The seed is unique to each build environment. Do not commit
.anticheat_build_seedto version control if you want unique polymorphism for every deployment. - Reproducible Builds: If you need exactly the same VM bytecode across different machines, you can set the
ANTICHEAT_BUILD_KEYenvironment variable. This overrides the random generation.
# For reproducible builds (same opcodes, same keys)
export ANTICHEAT_BUILD_KEY="my-secret-company-build-key"
cargo build --release
🔍 Analysis & Reverse Engineering
RustAegis significantly complicates static and dynamic analysis by flattening control flow and obfuscating data flow.
Indirect Threading Dispatch
The VM uses indirect threading (function pointer table) instead of a traditional switch-case dispatcher. This eliminates recognizable patterns in binary analysis:
Traditional Switch-Case:
cmp x8, #0x01 ; Compare opcode
b.eq handler_push ; Branch to handler
cmp x8, #0x02
b.eq handler_pop
...
Indirect Threading (RustAegis):
ldrb w8, [decode_table, opcode] ; Decode shuffled opcode
ldr x9, [handler_table, x8, lsl#3] ; Load handler pointer
blr x9 ; Indirect call
This approach:
- Eliminates ~10KB switch-case pattern → ~800 bytes dispatcher
- No sequential CMP/branch patterns visible in IDA/Ghidra
- Handler functions distributed across binary
- Opcode mapping hidden in runtime table lookup
Control Flow Flattening
The original control flow (if/else, loops) is flattened into data-driven jumps within the interpreter loop.
Native CFG:
Distinct blocks for if, else, and return, easily readable by decompilers.
Figure 1: Native assembly of the license check function. Logic is linear and easy to follow.
VM CFG: A single "God Node" (the dispatcher) with edges pointing back to itself. The actual logic is hidden in the bytecode data, not the CPU instructions.
Figure 2: The same function protected by the VM. The control flow is flattened into the VM's fetch-decode-execute loop.
Arithmetic Obfuscation (MBA)
Instead of a single ADD instruction, the analyst sees a randomized sequence of stack operations implementing mathematically equivalent formulas like:
x + y = (x ^ y) + 2 * (x & y) or (x | y) + (x & y)
Figure 3: Even a simple arithmetic function explodes into a complex graph due to MBA transformations and the VM dispatcher overhead.
⚡ Performance & Constraints
Virtualization comes with a cost. RustAegis is designed for security, not speed.
- Performance: Expect a 10x-100x slowdown compared to native code. This is standard for software-based virtualization.
- Usage: Apply
#[vm_protect]only to sensitive functions (license checks, key generation, encryption logic). Do not virtualize tight loops in performance-critical rendering or physics code. - Supported Platforms: Works on
x86_64,aarch64,wasm32, and any platform supported by Ruststdoralloc(no_std compatible).
📂 Examples
Check the examples/ directory for complete test cases:
001_test.rs: Native function call support demo.01_arithmetic.rs: Demonstrates MBA transformations.02_control_flow.rs: Demonstrates if/else logic protection.03_loops.rs: Demonstrates loop virtualization.04_wasm.rs: Demonstrates WASM integration.05_whitebox_crypto.rs: Demonstrates White-Box Cryptography key protection.06_native_calls.rs: Manual NativeRegistry usage (legacy).07_native_call_macro.rs: Automatic native call via macro.08_async_vm.rs: NEW - Async VM with state machine obfuscation (experimental).wasm_test/: Complete WASM test project withwasm-pack.
Run them with:
cargo run --example 001_test
cargo run --example 01_arithmetic
cargo run --example 07_native_call_macro
cargo run --example 08_async_vm --features async_vm
# For WASM tests
cd examples/wasm_test
wasm-pack test --node
🌐 WASM Support
RustAegis fully supports WebAssembly. To use with WASM:
Setup
# Add WASM target
rustup target add wasm32-unknown-unknown
# Install wasm-pack (optional, for building/testing)
cargo install wasm-pack
Cargo.toml Configuration
[dependencies]
aegis_vm = { version = "0.2.51", default-features = false }
wasm-bindgen = "0.2"
Usage Pattern
Since #[vm_protect] and #[wasm_bindgen] cannot be combined directly, use a wrapper:
use aegis_vm::vm_protect;
use wasm_bindgen::prelude::*;
// VM-protected implementation
#[vm_protect(level = "debug")]
fn secret_impl(x: u64) -> u64 {
x ^ 0xDEADBEEF
}
// WASM export wrapper
#[wasm_bindgen]
pub fn secret(x: u64) -> u64 {
secret_impl(x)
}
Building WASM
cd examples/wasm_test
# Build for web
wasm-pack build --target web --release
# Run tests with Node.js
wasm-pack test --node
# Run tests in headless browser
wasm-pack test --headless --firefox
The compiled .wasm file will be in pkg/ directory.
🧪 Experimental Features
Async VM Engine (async_vm)
Status: Experimental - Use for testing and research only
The Async VM feature transforms the VM execution loop into an async/await state machine, adding an extra layer of obfuscation against reverse engineering.
How it works:
- Rust compiler transforms
async fninto a complex state machine enum - Debuggers stepping through code see executor tra
Related Skills
node-connect
349.9kDiagnose OpenClaw node connection and pairing failures for Android, iOS, and macOS companion apps
frontend-design
109.8kCreate distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.
openai-whisper-api
349.9kTranscribe audio via OpenAI Audio Transcriptions API (Whisper).
qqbot-media
349.9kQQBot 富媒体收发能力。使用 <qqmedia> 标签,系统根据文件扩展名自动识别类型(图片/语音/视频/文件)。
