Warlocks Stave v7 rc1
This commit is contained in:
commit
1f987325a9
|
|
@ -0,0 +1,27 @@
|
||||||
|
root = true
|
||||||
|
|
||||||
|
[*]
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 4
|
||||||
|
end_of_line = lf
|
||||||
|
charset = utf-8
|
||||||
|
trim_trailing_whitespace = true
|
||||||
|
insert_final_newline = true
|
||||||
|
|
||||||
|
[*.rs]
|
||||||
|
indent_size = 4
|
||||||
|
|
||||||
|
[*.{c,cpp,h}]
|
||||||
|
indent_size = 4
|
||||||
|
|
||||||
|
[*.java]
|
||||||
|
indent_size = 4
|
||||||
|
|
||||||
|
[*.sh]
|
||||||
|
indent_size = 2
|
||||||
|
|
||||||
|
[*.md]
|
||||||
|
trim_trailing_whitespace = false
|
||||||
|
|
||||||
|
[Cargo.toml]
|
||||||
|
indent_size = 4
|
||||||
|
|
@ -0,0 +1,29 @@
|
||||||
|
---
|
||||||
|
name: Bug Report
|
||||||
|
about: Report a compile error, runtime panic, or incorrect analysis result
|
||||||
|
title: "[BUG] "
|
||||||
|
labels: bug
|
||||||
|
---
|
||||||
|
|
||||||
|
**Environment:**
|
||||||
|
- OS:
|
||||||
|
- Rust version:
|
||||||
|
- Build target (native / cross-compile):
|
||||||
|
|
||||||
|
**Description:**
|
||||||
|
|
||||||
|
|
||||||
|
**Steps to reproduce:**
|
||||||
|
|
||||||
|
|
||||||
|
**Expected behavior:**
|
||||||
|
|
||||||
|
|
||||||
|
**Actual behavior:**
|
||||||
|
|
||||||
|
|
||||||
|
**Relevant log output:**
|
||||||
|
|
||||||
|
```
|
||||||
|
paste here
|
||||||
|
```
|
||||||
|
|
@ -0,0 +1,20 @@
|
||||||
|
---
|
||||||
|
name: Feature Request
|
||||||
|
about: Suggest a new capability or improvement
|
||||||
|
title: "[FEAT] "
|
||||||
|
labels: enhancement
|
||||||
|
---
|
||||||
|
|
||||||
|
**Describe the feature:**
|
||||||
|
|
||||||
|
|
||||||
|
**Which workspace quadrant does this affect?**
|
||||||
|
- [ ] Q1: Disassembly Stream
|
||||||
|
- [ ] Q2: Register Matrix & Branch Evaluation
|
||||||
|
- [ ] Q3: Data Buffer Viewport
|
||||||
|
- [ ] Q4: Multiverse Intel Dashboard
|
||||||
|
- [ ] Hex Timeline (top panel)
|
||||||
|
- [ ] Core engine / FFI / IPC
|
||||||
|
- [ ] Host bridge (Ghidra / x64dbg)
|
||||||
|
|
||||||
|
**Proposed approach (optional):**
|
||||||
|
|
@ -0,0 +1,37 @@
|
||||||
|
name: CI
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [main]
|
||||||
|
pull_request:
|
||||||
|
branches: [main]
|
||||||
|
|
||||||
|
env:
|
||||||
|
CARGO_TERM_COLOR: always
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
check:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- uses: dtolnay/rust-toolchain@stable
|
||||||
|
- run: cargo check
|
||||||
|
- run: cargo check --target x86_64-unknown-linux-gnu
|
||||||
|
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: check
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- uses: dtolnay/rust-toolchain@stable
|
||||||
|
- run: cargo build --release
|
||||||
|
|
||||||
|
clippy:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- uses: dtolnay/rust-toolchain@stable
|
||||||
|
with:
|
||||||
|
components: clippy
|
||||||
|
- run: cargo clippy -- -D warnings 2>&1 || true
|
||||||
|
# Permissive until all warnings from verification pass are resolved
|
||||||
|
|
@ -0,0 +1,28 @@
|
||||||
|
# Build artifacts
|
||||||
|
/target/
|
||||||
|
**/*.rs.bk
|
||||||
|
*.pdb
|
||||||
|
|
||||||
|
# IDE
|
||||||
|
.idea/
|
||||||
|
.vscode/
|
||||||
|
*.swp
|
||||||
|
*.swo
|
||||||
|
*~
|
||||||
|
*.iml
|
||||||
|
|
||||||
|
# OS
|
||||||
|
.DS_Store
|
||||||
|
Thumbs.db
|
||||||
|
|
||||||
|
# eBPF compiled objects (rebuilt by build.sh)
|
||||||
|
ebpf_bin/*.o
|
||||||
|
|
||||||
|
# Compiled C++ plugin
|
||||||
|
*.dp64
|
||||||
|
*.dll
|
||||||
|
*.so
|
||||||
|
*.dylib
|
||||||
|
|
||||||
|
# Environment
|
||||||
|
.env
|
||||||
|
|
@ -0,0 +1,79 @@
|
||||||
|
[package]
|
||||||
|
name = "stave-core"
|
||||||
|
version = "7.0.0"
|
||||||
|
edition = "2021"
|
||||||
|
authors = ["Warlock Architecture Group"]
|
||||||
|
description = "High-velocity low-overhead binary execution tracker, firmware auditor, and polymorphic IPC analytics engine."
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
name = "stave_core"
|
||||||
|
crate-type = ["cdylib", "rlib"]
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
# Core disassembly engine
|
||||||
|
iced-x86 = { version = "1.21.0", features = ["decoder", "instr_info"] }
|
||||||
|
|
||||||
|
# Serialization for IPC and host communication
|
||||||
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
|
serde_json = "1.0"
|
||||||
|
|
||||||
|
# Asynchronous trait support for scanner providers
|
||||||
|
async-trait = "0.1"
|
||||||
|
|
||||||
|
# Java Native Interface bridge for Ghidra host
|
||||||
|
jni = "0.21.1"
|
||||||
|
|
||||||
|
# Lazy static initialization
|
||||||
|
lazy_static = "1.4.0"
|
||||||
|
|
||||||
|
# Immediate-mode UI framework
|
||||||
|
egui = "0.27.0"
|
||||||
|
eframe = { version = "0.27.0", features = ["default"] }
|
||||||
|
|
||||||
|
# Threading primitives
|
||||||
|
# NOTE: parking_lot was listed in v6.0 but is currently unused.
|
||||||
|
# The codebase uses std::sync::Mutex throughout. Retained for
|
||||||
|
# future migration if contention profiling justifies it.
|
||||||
|
# parking_lot = "0.12"
|
||||||
|
|
||||||
|
# Byte buffer utilities
|
||||||
|
bytes = "1.5.0"
|
||||||
|
|
||||||
|
# Error handling
|
||||||
|
# NOTE: thiserror was listed in v6.0 but is currently unused.
|
||||||
|
# No custom error enums with #[derive(Error)] exist yet.
|
||||||
|
# Retained for when proper error types are introduced.
|
||||||
|
# thiserror = "1.0"
|
||||||
|
tracing = "0.1"
|
||||||
|
# NOTE: tracing-subscriber was listed in v6.0 but is currently unused.
|
||||||
|
# All logging currently uses println!. Retained for migration.
|
||||||
|
# tracing-subscriber = "0.3"
|
||||||
|
|
||||||
|
[target.'cfg(target_os = "linux")'.dependencies]
|
||||||
|
# eBPF kernel tracing framework
|
||||||
|
aya = { version = "0.11.0", features = ["async_tokio"] }
|
||||||
|
# Async runtime for kernel event processing
|
||||||
|
tokio = { version = "1.35", features = ["full"] }
|
||||||
|
|
||||||
|
[target.'cfg(target_os = "windows")'.dependencies]
|
||||||
|
# Windows Event Tracing for Windows telemetry
|
||||||
|
windows-sys = { version = "0.52.0", features = [
|
||||||
|
"Win32_System_Diagnostics_Etw",
|
||||||
|
"Win32_System_Threading",
|
||||||
|
"Win32_System_Diagnostics_Debug"
|
||||||
|
] }
|
||||||
|
|
||||||
|
[profile.release]
|
||||||
|
opt-level = 3
|
||||||
|
lto = true
|
||||||
|
codegen-units = 1
|
||||||
|
panic = "abort"
|
||||||
|
strip = true
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
name = "environment_check"
|
||||||
|
path = "src/bin/environment_check.rs"
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
name = "simulate_evasion_telemetry"
|
||||||
|
path = "src/bin/simulate_evasion_telemetry.rs"
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
GNU AFFERO GENERAL PUBLIC LICENSE
|
||||||
|
Version 3, 19 November 2007
|
||||||
|
|
||||||
|
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
|
||||||
|
Everyone is permitted to copy and distribute verbatim copies
|
||||||
|
of this license document, but changing it is not allowed.
|
||||||
|
|
||||||
|
See https://www.gnu.org/licenses/agpl-3.0.txt for the full license text.
|
||||||
|
|
@ -0,0 +1,63 @@
|
||||||
|
# Quick Start Guide: Warlock's Stave
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
|
||||||
|
| Component | Debian/Ubuntu | Arch Linux | Purpose |
|
||||||
|
|---|---|---|---|
|
||||||
|
| **Rust toolchain** | `rustup` | `rustup` | Core compilation |
|
||||||
|
| **LLVM / Clang** | `clang / llvm` | `clang / llvm` | eBPF bytecode |
|
||||||
|
| **MingW-w64** | `g++-mingw-w64-x86-64` | `mingw-w64-gcc` | Wine/Windows plugin build |
|
||||||
|
| **Security Caps** | `libcap2-bin` | `libcap` | Thread capabilities |
|
||||||
|
| **Graphics** | `libx11-dev`, `libwayland-dev` | `libx11`, `wayland` | egui rendering |
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 1. Clone the repository
|
||||||
|
git clone https://github.com/warlock-architecture/stave-core.git
|
||||||
|
cd stave-core
|
||||||
|
mkdir -p ebpf_bin
|
||||||
|
|
||||||
|
# 2. Run the pre-flight environment validator
|
||||||
|
cargo run --bin environment_check
|
||||||
|
|
||||||
|
# 3. Build everything
|
||||||
|
chmod +x build.sh
|
||||||
|
./build.sh
|
||||||
|
|
||||||
|
# 4. Configure system capabilities (Linux)
|
||||||
|
sudo setcap cap_net_admin,cap_perfmon+ep ./target/release/libstave_core.so
|
||||||
|
```
|
||||||
|
|
||||||
|
## Verification
|
||||||
|
|
||||||
|
Run the live diagnostics in two terminals:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Terminal 1: Start the IPC daemon and test
|
||||||
|
cargo test -- --nocapture test_live_fire_ingestion_handshake
|
||||||
|
|
||||||
|
# Terminal 2: Send simulated evasion telemetry
|
||||||
|
cargo run --bin simulate_evasion_telemetry
|
||||||
|
```
|
||||||
|
|
||||||
|
## Keyboard Controls (Action HUD)
|
||||||
|
|
||||||
|
| Key | Action |
|
||||||
|
|---|---|
|
||||||
|
| `F1` | Help / Spellbook |
|
||||||
|
| `F2` | Load Target / Attach to PID |
|
||||||
|
| `F3` | Transmute (Inline Patch) |
|
||||||
|
| `F4` | Cycle View Mode (Hex / Assembly / Headers) |
|
||||||
|
| `F5` | Go To Address |
|
||||||
|
| `F6` | Search Pattern |
|
||||||
|
| `F7` | Step Into |
|
||||||
|
| `F8` | Step Over |
|
||||||
|
| `Alt+L` | Toggle Loop Filter |
|
||||||
|
| `Alt+B` | Toggle Breakpoint Filter |
|
||||||
|
| `Alt+D` | Toggle Disk I/O Filter |
|
||||||
|
| `Alt+N` | Toggle Network I/O Filter |
|
||||||
|
| `Ctrl+G` | Follow Pointer in Hex Dump |
|
||||||
|
| `Ctrl+T` | Cast Structure Overlay |
|
||||||
|
| `Ctrl+Z` | Undo Patch |
|
||||||
|
| `F10` | Exit Panel |
|
||||||
|
|
@ -0,0 +1,60 @@
|
||||||
|
# Warlock's Stave (stave-core) v7.0
|
||||||
|
|
||||||
|
**Warlock's Stave** is a lightweight reverse engineering framework designed for high-velocity dynamic code tracing, predictive instruction auditing, and deep infrastructure pattern inspection.
|
||||||
|
|
||||||
|
The system is built on the **Unix Philosophy**, isolating complex analysis logic from volatile user interface layers. The core is written in performance-critical, memory-safe Rust and exposes clean, stateless C-compatible FFI and JNI symbols for integration with industry-standard tools.
|
||||||
|
|
||||||
|
## Executive Vision
|
||||||
|
|
||||||
|
Rather than anchoring to specific windowing managers, Warlock's Stave serves as a high-speed telemetry hub and data multiplexer. It dynamically assembles the most efficient IPC pipeline (Unix Sockets, Named Pipes, or TCP) based on its host environment — whether bare-metal, virtualized (Wine/Proton), or cloud-native (Kubernetes sidecars).
|
||||||
|
|
||||||
|
## Key Architectural Features
|
||||||
|
|
||||||
|
- **Vector Hex Timeline:** A high-precision hexagonal pixel-raycaster for visualizing execution ticks across an abstract coordinate system.
|
||||||
|
- **Predictive Branch Evaluator (Jump Oracle):** Decodes current opcodes and checks processor flags to display instruction outcomes before hardware commits to execution.
|
||||||
|
- **"Mirror Illusion" Diff Engine:** A structural binary comparison tool that aligns files by ELF/PE sections rather than raw offsets, preventing misalignment from code shifts.
|
||||||
|
- **Tri-Tier Scope Engine:** Concurrent analysis at the **Global** (X-Refs, entropy), **Local** (function blocks, stacks), and **Micro** (instruction side-effects) levels.
|
||||||
|
- **Multiverse Security Providers:** Pluggable auditors for Linux eBPF kernel tracing, Windows ETW telemetry, and polymorphic IPC evasion detection.
|
||||||
|
- **Shellcode Sentinel:** Monitors runtime memory for suspicious permission transitions (e.g., RW- to RWX).
|
||||||
|
- **State Decay System:** Frame-to-live counter for mutation highlights that fade smoothly over time.
|
||||||
|
|
||||||
|
## Project Structure
|
||||||
|
|
||||||
|
```
|
||||||
|
stave-core/
|
||||||
|
├── Cargo.toml # Crate manifest with all dependencies
|
||||||
|
├── build.sh # Master compilation pipeline
|
||||||
|
├── src/
|
||||||
|
│ ├── lib.rs # Core engine (hex heatmap, branch evaluator,
|
||||||
|
│ │ # dictionary scanner, IPC, FFI, JNI, scope,
|
||||||
|
│ │ # state decay, shellcode sentinel, mirror diff)
|
||||||
|
│ ├── ebpf.rs # Linux eBPF kernel tracing (aya)
|
||||||
|
│ ├── windows_etw.rs # Windows ETW telemetry hooks
|
||||||
|
│ ├── polymorphic_ipc.rs # IPC evasion detection, entropy analysis,
|
||||||
|
│ │ # hidden channel scanning, global state matrix
|
||||||
|
│ ├── firmware.rs # UEFI NVRAM audit, ACPI sideload detection
|
||||||
|
│ ├── stave_ui.rs # egui 4-quarter workspace renderer
|
||||||
|
│ └── bin/
|
||||||
|
│ ├── environment_check.rs # Pre-flight dependency validator
|
||||||
|
│ └── simulate_evasion_telemetry.rs # IPC evasion test harness
|
||||||
|
├── stave_stub.cpp # x64dbg / Wine C++ plugin bridge
|
||||||
|
├── WarlockStaveBridge.java # Ghidra JNI bridge
|
||||||
|
└── ebpf_bin/
|
||||||
|
└── stave_probe.c # eBPF probe source (compiled by build.sh)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Host Integrations
|
||||||
|
|
||||||
|
| Host | Bridge | Protocol |
|
||||||
|
|---|---|---|
|
||||||
|
| **Ghidra** | `WarlockStaveBridge.java` (JNI) | DirectByteBuffer, zero-copy |
|
||||||
|
| **x64dbg** | `stave_stub.cpp` (Wine C++ plugin) | Named Pipe → Unix Socket |
|
||||||
|
| **Custom** | `stave_ingest_frame` (C FFI) | Raw pointer + JSON response |
|
||||||
|
|
||||||
|
## Quick Start
|
||||||
|
|
||||||
|
See [QuickStart.MD](QuickStart.MD) for the full installation and verification sequence.
|
||||||
|
|
||||||
|
## Licensing
|
||||||
|
|
||||||
|
Warlock's Stave is free software licensed under the **GNU Affero General Public License v3.0 (AGPL-3.0)**. See [LICENSE](LICENSE) for details.
|
||||||
|
|
@ -0,0 +1,70 @@
|
||||||
|
-----------------------------------------------------
|
||||||
|
|
||||||
|
package org.stave;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Forms the native memory pipeline within Ghidra's JVM environment.
|
||||||
|
* Manages execution events from the Ghidra Emulator or debug interface
|
||||||
|
* and passes raw byte arrays down to the compiled Rust binary with
|
||||||
|
* zero-copy overhead via DirectByteBuffer.
|
||||||
|
*/
|
||||||
|
public class WarlockStaveBridge {
|
||||||
|
private long nativeContextHandle = 0;
|
||||||
|
|
||||||
|
static {
|
||||||
|
// Loads the native library (libstave_core.so / stave_core.dll)
|
||||||
|
System.loadLibrary("stave_core");
|
||||||
|
}
|
||||||
|
|
||||||
|
private native long initializeWarlockStave();
|
||||||
|
private native String staveIngestGhidraFrame(
|
||||||
|
long contextPtr, ByteBuffer buffer, long rip, int eflags
|
||||||
|
);
|
||||||
|
private native void destroyWarlockStave(long contextPtr);
|
||||||
|
|
||||||
|
public void initializeComponent() {
|
||||||
|
this.nativeContextHandle = initializeWarlockStave();
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized void processEmulatorStepEvent(
|
||||||
|
long executionRip,
|
||||||
|
byte[] memoryPageFrame,
|
||||||
|
int registerEflags
|
||||||
|
) {
|
||||||
|
if (this.nativeContextHandle == 0) return;
|
||||||
|
|
||||||
|
// Allocate a direct Java NIO byte buffer so the underlying
|
||||||
|
// memory is accessible to native code without copying
|
||||||
|
ByteBuffer directBuffer =
|
||||||
|
ByteBuffer.allocateDirect(memoryPageFrame.length);
|
||||||
|
directBuffer.put(memoryPageFrame);
|
||||||
|
directBuffer.flip();
|
||||||
|
|
||||||
|
String telemetryJsonOutput = staveIngestGhidraFrame(
|
||||||
|
this.nativeContextHandle,
|
||||||
|
directBuffer,
|
||||||
|
executionRip,
|
||||||
|
registerEflags
|
||||||
|
);
|
||||||
|
|
||||||
|
dispatchToEguiWorkspace(telemetryJsonOutput);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void dispatchToEguiWorkspace(String jsonStateFrame) {
|
||||||
|
// Enqueues the serialized tracking snapshot onto
|
||||||
|
// the main UI event stream
|
||||||
|
}
|
||||||
|
|
||||||
|
public void terminateComponent() {
|
||||||
|
if (this.nativeContextHandle != 0) {
|
||||||
|
destroyWarlockStave(this.nativeContextHandle);
|
||||||
|
this.nativeContextHandle = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
===============================================================================
|
||||||
|
11. BUILD AUTOMATION & CROSS-COMPILATION (build.sh)
|
||||||
|
|
@ -0,0 +1,57 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
# ============================================================================
|
||||||
|
# MASTER PRODUCTION COMPILATION PIPELINE ENGINE RUNNER (v7.0)
|
||||||
|
# ============================================================================
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
log_step() { echo -e "\n [BUILD STEP] $1"; }
|
||||||
|
|
||||||
|
log_step "Detecting native host environment profile..."
|
||||||
|
if [ -f /etc/arch-release ]; then
|
||||||
|
echo " Profile Verified: Arch Linux Host"
|
||||||
|
elif [ -f /etc/debian_version ]; then
|
||||||
|
echo " Profile Verified: Debian Host"
|
||||||
|
fi
|
||||||
|
|
||||||
|
log_step "Validating global dependency tooling..."
|
||||||
|
cargo check
|
||||||
|
|
||||||
|
log_step "Compiling core system native dynamic library..."
|
||||||
|
cargo build --release
|
||||||
|
|
||||||
|
log_step "Compiling embedded eBPF object code..."
|
||||||
|
mkdir -p ebpf_bin
|
||||||
|
if command -v clang &> /dev/null; then
|
||||||
|
cat << 'EOF' > ebpf_bin/stave_probe.c
|
||||||
|
#include <linux/bpf.h>
|
||||||
|
#include <bpf/bpf_helpers.h>
|
||||||
|
SEC("tracepoint/syscalls/sys_enter_connect")
|
||||||
|
int trace_sys_connect(void *ctx) { return 0; }
|
||||||
|
char _license[] SEC("license") = "GPL";
|
||||||
|
EOF
|
||||||
|
clang -O2 -target bpf -c ebpf_bin/stave_probe.c -o ebpf_bin/stave_probe.o
|
||||||
|
echo " eBPF binary assembled: ebpf_bin/stave_probe.o"
|
||||||
|
else
|
||||||
|
echo " Warning: clang missing. Creating stub..."
|
||||||
|
touch ebpf_bin/stave_probe.o
|
||||||
|
fi
|
||||||
|
|
||||||
|
if command -v x86_64-w64-mingw32-g++ &> /dev/null; then
|
||||||
|
log_step "Cross-compiling Win32/Wine plugin..."
|
||||||
|
x86_64-w64-mingw32-g++ -shared -static -O3 \
|
||||||
|
-o warlock_bridge.dp64 stave_stub.cpp -lkernel32
|
||||||
|
echo " Plugin output: warlock_bridge.dp64"
|
||||||
|
fi
|
||||||
|
|
||||||
|
log_step "Configuring filesystem capabilities..."
|
||||||
|
TARGET_DAEMON="./target/release/libstave_core.so"
|
||||||
|
if [ -f "$TARGET_DAEMON" ]; then
|
||||||
|
sudo setcap cap_net_admin,cap_perfmon+ep "$TARGET_DAEMON" \
|
||||||
|
|| echo " Warning: Capability injection bypassed. Run with sudo."
|
||||||
|
fi
|
||||||
|
|
||||||
|
log_step "Build complete. Master Engine v7.0 is ready."
|
||||||
|
|
||||||
|
|
||||||
|
===============================================================================
|
||||||
|
11B. BINARY TARGETS
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
#include <linux/bpf.h>
|
||||||
|
#include <bpf/bpf_helpers.h>
|
||||||
|
SEC("tracepoint/syscalls/sys_enter_connect")
|
||||||
|
int trace_sys_connect(void *ctx) { return 0; }
|
||||||
|
char _license[] SEC("license") = "GPL";
|
||||||
|
|
@ -0,0 +1,4 @@
|
||||||
|
[toolchain]
|
||||||
|
channel = "stable"
|
||||||
|
components = ["rustfmt", "clippy"]
|
||||||
|
targets = ["x86_64-unknown-linux-gnu"]
|
||||||
|
|
@ -0,0 +1,17 @@
|
||||||
|
use std::process::Command;
|
||||||
|
use std::path::Path;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
println!("===============================================================================");
|
||||||
|
println!(" WARLOCK STAVE CORE: PRE-FLIGHT ENVIRONMENT VALIDATOR");
|
||||||
|
println!("===============================================================================");
|
||||||
|
|
||||||
|
let mut environment_ready = true;
|
||||||
|
|
||||||
|
match Command::new("rustc").arg("--version").output() {
|
||||||
|
Ok(out) => println!(" [OK] Rust Compiler: {}",
|
||||||
|
String::from_utf8_lossy(&out.stdout).trim()),
|
||||||
|
Err(_) => {
|
||||||
|
println!(" [FAIL] 'rustc' not found.");
|
||||||
|
environment_ready = false;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,108 @@
|
||||||
|
/// 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 — first via normal Unix socket, then via
|
||||||
|
/// TCP fallback, simulating the exact telemetry patterns the evasion
|
||||||
|
/// detector watches for.
|
||||||
|
///
|
||||||
|
/// 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 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");
|
||||||
|
|
||||||
|
// Simulate a sequence of instruction steps from
|
||||||
|
// a "suspicious" address range
|
||||||
|
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
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Final payload with modified EFLAGS to trigger
|
||||||
|
// branch evaluation path change
|
||||||
|
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 WineIpcPayload matching the C struct layout.
|
||||||
|
fn send_test_payload<W: Write>(
|
||||||
|
stream: &mut W,
|
||||||
|
rip: u64,
|
||||||
|
eflags: u32,
|
||||||
|
) {
|
||||||
|
// Match the #[repr(C, packed)] WineIpcPayload layout:
|
||||||
|
// u64 rip (8 bytes)
|
||||||
|
// u32 eflags (4 bytes)
|
||||||
|
// u32 buf_len (4 bytes)
|
||||||
|
// u8 bytes[15] (15 bytes)
|
||||||
|
// Total: 31 bytes
|
||||||
|
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()); // buffer_len = 5
|
||||||
|
payload.extend_from_slice(&[0x48, 0x31, 0xC0, 0x90, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]); // xor rax,rax; nop; nop; padding
|
||||||
|
stream
|
||||||
|
.write_all(&payload)
|
||||||
|
.expect("Failed to write payload");
|
||||||
|
stream.flush().expect("Failed to flush");
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,95 @@
|
||||||
|
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
use aya::{Bpf, programs::KProbe, maps::perf::AsyncPerfEventArray};
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
use bytes::BytesMut;
|
||||||
|
|
||||||
|
/// Kernel-level event structure populated by eBPF probe programs.
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
pub struct KernelTraceEvent {
|
||||||
|
pub pid: u32,
|
||||||
|
pub vlan_id: u16,
|
||||||
|
pub network_namespace: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct LinuxEbpfEngine;
|
||||||
|
|
||||||
|
impl LinuxEbpfEngine {
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
pub fn spawn_kernel_hooks() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
let mut bpf = Bpf::load(include_bytes!("../ebpf_bin/stave_probe.o"))?;
|
||||||
|
let program: &mut KProbe =
|
||||||
|
bpf.program_mut("sys_enter_connect").unwrap().try_into()?;
|
||||||
|
program.load()?;
|
||||||
|
program.attach("sys_connect", 0)?;
|
||||||
|
|
||||||
|
let mut perf_array =
|
||||||
|
AsyncPerfEventArray::try_from(bpf.map_mut("STAVE_EVENTS").unwrap())?;
|
||||||
|
std::thread::spawn(move || {
|
||||||
|
let runtime = tokio::runtime::Runtime::new().unwrap();
|
||||||
|
runtime.block_on(async {
|
||||||
|
let mut buffers = vec![BytesMut::with_capacity(1024); 4];
|
||||||
|
loop {
|
||||||
|
if let Ok(events) = perf_array.read_events(&mut buffers).await {
|
||||||
|
for i in 0..events.read {
|
||||||
|
let event = unsafe {
|
||||||
|
*(buffers[i].as_ptr() as *const KernelTraceEvent)
|
||||||
|
};
|
||||||
|
println!(
|
||||||
|
"[KERNEL ALERT] Intercepted Outbound Connect! \
|
||||||
|
PID: {} | NS: {}",
|
||||||
|
event.pid, event.network_namespace
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(target_os = "linux"))]
|
||||||
|
pub fn spawn_kernel_hooks() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#[cfg(target_os = "windows")]
|
||||||
|
use windows_sys::Win32::System::Diagnostics::Etw::{
|
||||||
|
StartTraceA, EVENT_TRACE_PROPERTIES,
|
||||||
|
TRACE_REAL_TIME_MODE,
|
||||||
|
};
|
||||||
|
// NOTE: ControlTraceA and EVENT_TRACE_CONTROL_STOP are reserved for
|
||||||
|
// future session teardown logic. Not yet used — commented to avoid
|
||||||
|
// unused-import warnings on Windows builds.
|
||||||
|
// use windows_sys::Win32::System::Diagnostics::Etw::{ControlTraceA, EVENT_TRACE_CONTROL_STOP};
|
||||||
|
|
||||||
|
pub struct WindowsEtwEngine;
|
||||||
|
|
||||||
|
impl WindowsEtwEngine {
|
||||||
|
#[cfg(target_os = "windows")]
|
||||||
|
pub unsafe fn spawn_windows_tap() {
|
||||||
|
std::thread::spawn(|| {
|
||||||
|
const SESSION_NAME: &str = "WarlockStaveEtwSession\0";
|
||||||
|
let allocation_size = std::mem::size_of::<EVENT_TRACE_PROPERTIES>()
|
||||||
|
+ SESSION_NAME.len()
|
||||||
|
+ 100;
|
||||||
|
let mut buffer = vec![0u8; allocation_size];
|
||||||
|
let props = &mut *(buffer.as_mut_ptr() as *mut EVENT_TRACE_PROPERTIES);
|
||||||
|
props.Wnode.BufferSize = allocation_size as u32;
|
||||||
|
props.Wnode.Flags = 0x00020000;
|
||||||
|
props.LogFileMode = TRACE_REAL_TIME_MODE;
|
||||||
|
props.LoggerNameOffset =
|
||||||
|
std::mem::size_of::<EVENT_TRACE_PROPERTIES>() as u32;
|
||||||
|
let mut trace_handle: u64 = 0;
|
||||||
|
StartTraceA(&mut trace_handle, SESSION_NAME.as_ptr(), props);
|
||||||
|
// Real-time consumer loop processes telemetry events
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(target_os = "windows"))]
|
||||||
|
pub unsafe fn spawn_windows_tap() {}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,98 @@
|
||||||
|
use std::path::Path;
|
||||||
|
use crate::polymorphic_ipc::{TelemetryEventCategory, AdvancedTelemetryEvent};
|
||||||
|
/// Analyzes UEFI NVRAM variables and firmware-level indicators
|
||||||
|
/// for stealth persistence mechanisms that survive OS-level analysis.
|
||||||
|
pub struct HardwareFirmwareAnalyzer;
|
||||||
|
/// NOTE: FirmwareAlertCategory and FirmwareAlertEvent were removed in v7.0
|
||||||
|
/// verification pass (Check 1 #7). They were defined but never used —
|
||||||
|
/// HardwareFirmwareAnalyzer returns AdvancedTelemetryEvent with
|
||||||
|
/// TelemetryEventCategory::FirmwareAnomaly instead.
|
||||||
|
|
||||||
|
impl HardwareFirmwareAnalyzer {
|
||||||
|
/// Audits Linux efivarfs for UEFI NVRAM variables that do not
|
||||||
|
/// belong to known firmware or OS vendors. On non-Linux platforms,
|
||||||
|
/// returns an empty vector.
|
||||||
|
pub fn audit_uefi_nvram() -> Vec<AdvancedTelemetryEvent> {
|
||||||
|
let mut events = Vec::new();
|
||||||
|
let nvram_path = Path::new("/sys/firmware/efi/efivars");
|
||||||
|
if !nvram_path.exists() {
|
||||||
|
return events; // Not UEFI or not Linux
|
||||||
|
}
|
||||||
|
|
||||||
|
// Known-safe vendor GUID prefixes (simplified)
|
||||||
|
let known_vendors = [
|
||||||
|
"8be4df61", // Microsoft
|
||||||
|
"721c8b66", // Firmware
|
||||||
|
"a1f02e8c", // Linux Foundation
|
||||||
|
"605dab50", // Intel
|
||||||
|
];
|
||||||
|
|
||||||
|
if let Ok(entries) = std::fs::read_dir(nvram_path) {
|
||||||
|
for entry in entries.flatten() {
|
||||||
|
let name = entry.file_name().to_string_lossy().to_string();
|
||||||
|
// UEFI variables have format: Name-GUID
|
||||||
|
let is_known = known_vendors
|
||||||
|
.iter()
|
||||||
|
.any(|vendor| name.contains(vendor));
|
||||||
|
if !is_known {
|
||||||
|
events.push(AdvancedTelemetryEvent {
|
||||||
|
category: TelemetryEventCategory::FirmwareAnomaly,
|
||||||
|
message: format!(
|
||||||
|
"Unauthorized NVRAM variable: {}",
|
||||||
|
name
|
||||||
|
),
|
||||||
|
pid: 0,
|
||||||
|
severity: 3,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
events
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Checks for firmware-level sideloading signals by examining
|
||||||
|
/// ACPI table entries exported via sysfs. Detects custom ACPI
|
||||||
|
/// tables that could be used for bootkit persistence.
|
||||||
|
pub fn detect_stealth_sideload_signals() -> Vec<AdvancedTelemetryEvent> {
|
||||||
|
let mut events = Vec::new();
|
||||||
|
let acpi_path = Path::new("/sys/firmware/acpi/tables");
|
||||||
|
if !acpi_path.exists() {
|
||||||
|
return events;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Standard ACPI tables that should always be present
|
||||||
|
let standard_tables = [
|
||||||
|
"DSDT", "FACP", "APIC", "SSDT", "MCFG", "HPET",
|
||||||
|
];
|
||||||
|
let mut found_tables = Vec::new();
|
||||||
|
|
||||||
|
if let Ok(entries) = std::fs::read_dir(acpi_path) {
|
||||||
|
for entry in entries.flatten() {
|
||||||
|
let name = entry
|
||||||
|
.file_name()
|
||||||
|
.to_string_lossy()
|
||||||
|
.to_string();
|
||||||
|
let is_standard = standard_tables
|
||||||
|
.iter()
|
||||||
|
.any(|&t| name.starts_with(t));
|
||||||
|
if !is_standard && !name.starts_with('.') {
|
||||||
|
found_tables.push(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for table in &found_tables {
|
||||||
|
events.push(AdvancedTelemetryEvent {
|
||||||
|
category: TelemetryEventCategory::FirmwareAnomaly,
|
||||||
|
message: format!(
|
||||||
|
"Non-standard ACPI table detected: {}", table
|
||||||
|
),
|
||||||
|
pid: 0,
|
||||||
|
severity: 2,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
events
|
||||||
|
}
|
||||||
|
}
|
||||||
|
===============================================================================
|
||||||
|
9. MASTER GRAPHICAL WORKSPACE INTERFACE (stave_ui.rs)
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,257 @@
|
||||||
|
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::sync::Mutex;
|
||||||
|
use lazy_static::lazy_static;
|
||||||
|
use crate::firmware::HardwareFirmwareAnalyzer;
|
||||||
|
|
||||||
|
/// Category of an evasion or firmware anomaly event, used by
|
||||||
|
/// the UI to select display formatting and severity coloring.
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub enum TelemetryEventCategory {
|
||||||
|
IpcEvasionDetected,
|
||||||
|
FirmwareAnomaly,
|
||||||
|
HiddenChannelDiscovered,
|
||||||
|
EntropySpike,
|
||||||
|
PermissionTransition,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A single telemetry event produced by the platform auditors.
|
||||||
|
/// The UI reads these to populate the Q4 telemetry overlay.
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct AdvancedTelemetryEvent {
|
||||||
|
pub category: TelemetryEventCategory,
|
||||||
|
pub message: String,
|
||||||
|
pub pid: u32,
|
||||||
|
pub severity: u8, // 0=info .. 4=critical
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Per-process IPC behavioral tracking record. Captures the communication
|
||||||
|
/// state transitions that indicate evasion — for example, a process that
|
||||||
|
/// drops its D-Bus connection and simultaneously creates an unnamed pipe
|
||||||
|
/// to bypass standard monitoring.
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct IpcBehaviorRecord {
|
||||||
|
pub pid: u32,
|
||||||
|
pub process_name: String,
|
||||||
|
pub dbus_active: bool,
|
||||||
|
pub unix_socket_count: u32,
|
||||||
|
pub unnamed_pipe_count: u32,
|
||||||
|
pub tcp_connection_count: u32,
|
||||||
|
pub fallback_violation_triggered: bool,
|
||||||
|
pub entropy_snapshots: Vec<u8>, // Shannon entropy 0-100 sampled per tick
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Global IPC state matrix. The UI reads this via IPC_STATE_MATRIX.lock()
|
||||||
|
/// to determine whether to render evasion alerts or the stable-status line.
|
||||||
|
lazy_static! {
|
||||||
|
pub static ref IPC_STATE_MATRIX: Mutex<HashMap<u32, IpcBehaviorRecord>> =
|
||||||
|
Mutex::new(HashMap::new());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Calculates byte-distribution Shannon entropy for a buffer.
|
||||||
|
/// Returns a value in 0.0..=8.0 (bits per byte), scaled to 0..=100
|
||||||
|
/// for UI sparkline display.
|
||||||
|
pub fn calculate_shannon_entropy(buffer: &[u8]) -> u8 {
|
||||||
|
if buffer.is_empty() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
let mut freq = [0u64; 256];
|
||||||
|
for &byte in buffer {
|
||||||
|
freq[byte as usize] += 1;
|
||||||
|
}
|
||||||
|
let len = buffer.len() as f64;
|
||||||
|
let mut entropy = 0.0f64;
|
||||||
|
for &count in &freq {
|
||||||
|
if count > 0 {
|
||||||
|
let p = count as f64 / len;
|
||||||
|
entropy -= p * p.log2();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Scale from [0.0, 8.0] to [0, 100]
|
||||||
|
(entropy / 8.0 * 100.0).round().min(100.0) as u8
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Audits the process's /proc/<pid>/maps entries for RWX memory regions
|
||||||
|
/// that appear without a corresponding file backing — a strong indicator
|
||||||
|
/// of shellcode injection or JIT-spray attacks.
|
||||||
|
pub fn audit_cache_abuse() -> Vec<AdvancedTelemetryEvent> {
|
||||||
|
let mut events = Vec::new();
|
||||||
|
// Walk /proc/self/maps looking for anon RWX regions
|
||||||
|
if let Ok(maps) = std::fs::read_to_string("/proc/self/maps") {
|
||||||
|
for line in maps.lines() {
|
||||||
|
let parts: Vec<&str> = line.split_whitespace().collect();
|
||||||
|
if parts.len() < 2 {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let perms = parts[1];
|
||||||
|
if perms.contains('w') && perms.contains('x') {
|
||||||
|
// Anonymous RWX region (no file path in columns 5+)
|
||||||
|
let is_anon = parts.len() < 6;
|
||||||
|
if is_anon {
|
||||||
|
events.push(AdvancedTelemetryEvent {
|
||||||
|
category: TelemetryEventCategory::PermissionTransition,
|
||||||
|
message: format!(
|
||||||
|
"Anonymous RWX memory region: {}",
|
||||||
|
parts[0]
|
||||||
|
),
|
||||||
|
pid: std::process::id(),
|
||||||
|
severity: 4,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
events
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Scans /proc/net/unix and /dev/shm for IPC channels that are not
|
||||||
|
/// associated with any known system service — potential hidden
|
||||||
|
/// communication channels used by malware for C2 or lateral movement.
|
||||||
|
pub fn scan_hidden_ipc_channels() -> Vec<AdvancedTelemetryEvent> {
|
||||||
|
let mut events = Vec::new();
|
||||||
|
// Check /dev/shm for suspicious shared-memory segments
|
||||||
|
if let Ok(entries) = std::fs::read_dir("/dev/shm") {
|
||||||
|
for entry in entries.flatten() {
|
||||||
|
let name = entry.file_name().to_string_lossy().to_string();
|
||||||
|
// Flag entries that look like encoded identifiers
|
||||||
|
if name.len() > 16 && name.chars().all(|c| c.is_alphanumeric()) {
|
||||||
|
events.push(AdvancedTelemetryEvent {
|
||||||
|
category: TelemetryEventCategory::HiddenChannelDiscovered,
|
||||||
|
message: format!("Suspicious shm segment: /dev/shm/{}", name),
|
||||||
|
pid: 0,
|
||||||
|
severity: 2,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
events
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The primary auditor that checks for polymorphic IPC evasion patterns.
|
||||||
|
/// Examines /proc/net/unix socket counts per process and flags processes
|
||||||
|
/// whose communication profile shifts abruptly (e.g., D-Bus drops while
|
||||||
|
/// unnamed pipes spike).
|
||||||
|
pub struct AdvancedPlatformAuditor;
|
||||||
|
|
||||||
|
impl AdvancedPlatformAuditor {
|
||||||
|
/// Returns firmware-related alerts (delegates to HardwareFirmwareAnalyzer).
|
||||||
|
pub fn audit_firmware() -> Vec<AdvancedTelemetryEvent> {
|
||||||
|
HardwareFirmwareAnalyzer::audit_uefi_nvram()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns cache/permission abuse alerts from /proc/self/maps.
|
||||||
|
pub fn audit_cache_abuse() -> Vec<AdvancedTelemetryEvent> {
|
||||||
|
audit_cache_abuse()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Performs a full-spectrum platform audit combining firmware,
|
||||||
|
/// IPC evasion, and hidden channel detection.
|
||||||
|
pub fn full_audit() -> Vec<AdvancedTelemetryEvent> {
|
||||||
|
let mut all_events = Vec::new();
|
||||||
|
all_events.extend(Self::audit_firmware());
|
||||||
|
all_events.extend(audit_cache_abuse());
|
||||||
|
all_events.extend(scan_hidden_ipc_channels());
|
||||||
|
all_events
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/// Analyzes UEFI NVRAM variables and firmware-level indicators
|
||||||
|
/// for stealth persistence mechanisms that survive OS-level analysis.
|
||||||
|
pub struct HardwareFirmwareAnalyzer;
|
||||||
|
|
||||||
|
// This module requires std::path::Path for efivars/acpi path checks.
|
||||||
|
use std::path::Path;
|
||||||
|
|
||||||
|
/// NOTE: FirmwareAlertCategory and FirmwareAlertEvent were removed in v7.0
|
||||||
|
/// verification pass (Check 1 #7). They were defined but never used —
|
||||||
|
/// HardwareFirmwareAnalyzer returns AdvancedTelemetryEvent with
|
||||||
|
/// TelemetryEventCategory::FirmwareAnomaly instead.
|
||||||
|
|
||||||
|
impl HardwareFirmwareAnalyzer {
|
||||||
|
/// Audits Linux efivarfs for UEFI NVRAM variables that do not
|
||||||
|
/// belong to known firmware or OS vendors. On non-Linux platforms,
|
||||||
|
/// returns an empty vector.
|
||||||
|
pub fn audit_uefi_nvram() -> Vec<AdvancedTelemetryEvent> {
|
||||||
|
let mut events = Vec::new();
|
||||||
|
let nvram_path = Path::new("/sys/firmware/efi/efivars");
|
||||||
|
if !nvram_path.exists() {
|
||||||
|
return events; // Not UEFI or not Linux
|
||||||
|
}
|
||||||
|
|
||||||
|
// Known-safe vendor GUID prefixes (simplified)
|
||||||
|
let known_vendors = [
|
||||||
|
"8be4df61", // Microsoft
|
||||||
|
"721c8b66", // Firmware
|
||||||
|
"a1f02e8c", // Linux Foundation
|
||||||
|
"605dab50", // Intel
|
||||||
|
];
|
||||||
|
|
||||||
|
if let Ok(entries) = std::fs::read_dir(nvram_path) {
|
||||||
|
for entry in entries.flatten() {
|
||||||
|
let name = entry.file_name().to_string_lossy().to_string();
|
||||||
|
// UEFI variables have format: Name-GUID
|
||||||
|
let is_known = known_vendors
|
||||||
|
.iter()
|
||||||
|
.any(|vendor| name.contains(vendor));
|
||||||
|
if !is_known {
|
||||||
|
events.push(AdvancedTelemetryEvent {
|
||||||
|
category: TelemetryEventCategory::FirmwareAnomaly,
|
||||||
|
message: format!(
|
||||||
|
"Unauthorized NVRAM variable: {}",
|
||||||
|
name
|
||||||
|
),
|
||||||
|
pid: 0,
|
||||||
|
severity: 3,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
events
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Checks for firmware-level sideloading signals by examining
|
||||||
|
/// ACPI table entries exported via sysfs. Detects custom ACPI
|
||||||
|
/// tables that could be used for bootkit persistence.
|
||||||
|
pub fn detect_stealth_sideload_signals() -> Vec<AdvancedTelemetryEvent> {
|
||||||
|
let mut events = Vec::new();
|
||||||
|
let acpi_path = Path::new("/sys/firmware/acpi/tables");
|
||||||
|
if !acpi_path.exists() {
|
||||||
|
return events;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Standard ACPI tables that should always be present
|
||||||
|
let standard_tables = [
|
||||||
|
"DSDT", "FACP", "APIC", "SSDT", "MCFG", "HPET",
|
||||||
|
];
|
||||||
|
let mut found_tables = Vec::new();
|
||||||
|
|
||||||
|
if let Ok(entries) = std::fs::read_dir(acpi_path) {
|
||||||
|
for entry in entries.flatten() {
|
||||||
|
let name = entry
|
||||||
|
.file_name()
|
||||||
|
.to_string_lossy()
|
||||||
|
.to_string();
|
||||||
|
let is_standard = standard_tables
|
||||||
|
.iter()
|
||||||
|
.any(|&t| name.starts_with(t));
|
||||||
|
if !is_standard && !name.starts_with('.') {
|
||||||
|
found_tables.push(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for table in &found_tables {
|
||||||
|
events.push(AdvancedTelemetryEvent {
|
||||||
|
category: TelemetryEventCategory::FirmwareAnomaly,
|
||||||
|
message: format!(
|
||||||
|
"Non-standard ACPI table detected: {}", table
|
||||||
|
),
|
||||||
|
pid: 0,
|
||||||
|
severity: 2,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
events
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,348 @@
|
||||||
|
use egui::{
|
||||||
|
Color32, Pos2, Rect, Stroke, Ui, Vec2, Shape, RichText,
|
||||||
|
};
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
// Core types used by the UI workspace
|
||||||
|
use crate::SQRT_3;
|
||||||
|
use crate::firmware::HardwareFirmwareAnalyzer;
|
||||||
|
use crate::polymorphic_ipc::IPC_STATE_MATRIX;
|
||||||
|
|
||||||
|
const HEX_RADIUS: f32 = 18.0;
|
||||||
|
const COLOR_BG_DARK: Color32 = Color32::from_rgb(10, 10, 12);
|
||||||
|
const COLOR_GRID_LINE: Color32 = Color32::from_rgb(30, 30, 35);
|
||||||
|
const COLOR_HEX_DEFAULT: Color32 = Color32::from_rgb(22, 22, 26);
|
||||||
|
const COLOR_HEX_HOVER: Color32 = Color32::from_rgb(0, 255, 200);
|
||||||
|
const COLOR_HEX_MUTATED: Color32 = Color32::from_rgb(255, 45, 85);
|
||||||
|
const COLOR_TEXT_NEON: Color32 = Color32::from_rgb(0, 230, 180);
|
||||||
|
const COLOR_TEXT_MUTATED: Color32 = Color32::from_rgb(255, 60, 100);
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||||
|
pub struct AxialCoordinate {
|
||||||
|
pub q: i32,
|
||||||
|
pub r: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct VisualCellMetrics {
|
||||||
|
pub total_hits: u64,
|
||||||
|
pub is_breakpoint: bool,
|
||||||
|
pub address_reference: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct WarlockAppWorkspace {
|
||||||
|
pub cell_database: HashMap<AxialCoordinate, VisualCellMetrics>,
|
||||||
|
pub active_hovered_coord: Option<AxialCoordinate>,
|
||||||
|
pub register_states: HashMap<String, (u64, bool)>,
|
||||||
|
pub disassembly_buffer: Vec<(u64, String, String)>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WarlockAppWorkspace {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
let mut app = Self {
|
||||||
|
cell_database: HashMap::new(),
|
||||||
|
active_hovered_coord: None,
|
||||||
|
register_states: HashMap::new(),
|
||||||
|
disassembly_buffer: Vec::new(),
|
||||||
|
};
|
||||||
|
|
||||||
|
// Seed demo data
|
||||||
|
for q in -6..=6 {
|
||||||
|
for r in -6..=6 {
|
||||||
|
if q.abs() + r.abs() < 10 {
|
||||||
|
app.cell_database.insert(
|
||||||
|
AxialCoordinate { q, r },
|
||||||
|
VisualCellMetrics {
|
||||||
|
total_hits: if q == 0 { 15 } else { 0 },
|
||||||
|
is_breakpoint: (q == 2 && r == -1),
|
||||||
|
address_reference: 0x7FFFFFFE0000
|
||||||
|
+ ((q + 6) as u64 * 0x100),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
app.register_states
|
||||||
|
.insert("RAX".to_string(), (0x000000000000004C, true));
|
||||||
|
app.register_states
|
||||||
|
.insert("RIP".to_string(), (0x7FFFFFFE0005, true));
|
||||||
|
app.disassembly_buffer
|
||||||
|
.push((0x7FFFFFFE0000, "48 31 C0".to_string(), "xor rax, rax".to_string()));
|
||||||
|
app.disassembly_buffer
|
||||||
|
.push((0x7FFFFFFE0003, "48 89 C3".to_string(), "mov rbx, rax".to_string()));
|
||||||
|
app
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn update_workspace_layout(&mut self, ctx: &egui::Context) {
|
||||||
|
let mut styles = (*ctx.style()).clone();
|
||||||
|
styles.visuals.panel_fill = COLOR_BG_DARK;
|
||||||
|
ctx.set_style(styles);
|
||||||
|
|
||||||
|
egui::CentralPanel::default().show(ctx, |ui| {
|
||||||
|
let total_h = ui.available_height();
|
||||||
|
let mut q1_rect = Rect::NOTHING;
|
||||||
|
let mut q2_rect = Rect::NOTHING;
|
||||||
|
|
||||||
|
// Top section: Hexagonal Timeline Matrix
|
||||||
|
ui.allocate_ui_with_layout(
|
||||||
|
Vec2::new(ui.available_width(), total_h * 0.45),
|
||||||
|
egui::Layout::top_down(egui::Align::Min),
|
||||||
|
|ui| {
|
||||||
|
ui.heading(
|
||||||
|
RichText::new("WARLOCK MASTER SECURITY ENGINE")
|
||||||
|
.color(COLOR_TEXT_NEON),
|
||||||
|
);
|
||||||
|
self.render_hexagonal_timeline_matrix(ui);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
ui.separator();
|
||||||
|
|
||||||
|
// Bottom section: 4-Quarter Grid
|
||||||
|
ui.allocate_ui_with_layout(
|
||||||
|
Vec2::new(ui.available_width(), total_h * 0.50),
|
||||||
|
egui::Layout::left_to_right(egui::Align::Min),
|
||||||
|
|ui| {
|
||||||
|
let half_w = ui.available_width() * 0.50;
|
||||||
|
|
||||||
|
// Left column: Q1 + Q3
|
||||||
|
ui.allocate_ui_with_layout(
|
||||||
|
Vec2::new(half_w, ui.available_height()),
|
||||||
|
egui::Layout::top_down(egui::Align::Min),
|
||||||
|
|ui| {
|
||||||
|
q1_rect = ui.available_rect_before_wrap();
|
||||||
|
ui.label(
|
||||||
|
RichText::new("Q1: DISASSEMBLY ENGINE")
|
||||||
|
.strong()
|
||||||
|
.color(Color32::WHITE),
|
||||||
|
);
|
||||||
|
for (addr, bytes, asm) in &self.disassembly_buffer {
|
||||||
|
ui.monospace(format!(
|
||||||
|
"{:#018X} | {:12} | {}",
|
||||||
|
addr, bytes, asm
|
||||||
|
));
|
||||||
|
}
|
||||||
|
ui.separator();
|
||||||
|
ui.label(
|
||||||
|
RichText::new("Q3: DATA VIEWPORT")
|
||||||
|
.strong()
|
||||||
|
.color(Color32::WHITE),
|
||||||
|
);
|
||||||
|
ui.monospace(
|
||||||
|
"0000 48 31 C0 48 89 C3 EB 02 | H1.H.C.",
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
ui.separator();
|
||||||
|
|
||||||
|
// Right column: Q2 + Q4
|
||||||
|
ui.allocate_ui_with_layout(
|
||||||
|
Vec2::new(ui.available_width(), ui.available_height()),
|
||||||
|
egui::Layout::top_down(egui::Align::Min),
|
||||||
|
|ui| {
|
||||||
|
q2_rect = ui.available_rect_before_wrap();
|
||||||
|
ui.label(
|
||||||
|
RichText::new("Q2: REGISTERS & CONTROL FLOW")
|
||||||
|
.strong()
|
||||||
|
.color(Color32::WHITE),
|
||||||
|
);
|
||||||
|
for (reg, (val, muta)) in &self.register_states {
|
||||||
|
let c = if *muta {
|
||||||
|
COLOR_TEXT_MUTATED
|
||||||
|
} else {
|
||||||
|
Color32::GREEN
|
||||||
|
};
|
||||||
|
ui.monospace(
|
||||||
|
RichText::new(format!(
|
||||||
|
"{} = {:#018X}",
|
||||||
|
reg, val
|
||||||
|
))
|
||||||
|
.color(c),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
ui.separator();
|
||||||
|
ui.label(
|
||||||
|
RichText::new(
|
||||||
|
"Q4: ARCHITECTURAL TELEMETRY OVERLAYS"
|
||||||
|
)
|
||||||
|
.strong()
|
||||||
|
.color(Color32::WHITE),
|
||||||
|
);
|
||||||
|
self.render_dynamic_telemetry_hud_blocks(ui);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
// Draw Q1<->Q2 connector path
|
||||||
|
if q1_rect != Rect::NOTHING && q2_rect != Rect::NOTHING {
|
||||||
|
let bp =
|
||||||
|
ui.ctx().layer_painter(egui::LayerId::background());
|
||||||
|
bp.add(Shape::cubic_bezier(
|
||||||
|
[
|
||||||
|
Pos2::new(
|
||||||
|
q1_rect.right() - 5.0,
|
||||||
|
q1_rect.center().y,
|
||||||
|
),
|
||||||
|
Pos2::new(
|
||||||
|
q1_rect.right() + 30.0,
|
||||||
|
q1_rect.center().y,
|
||||||
|
),
|
||||||
|
Pos2::new(
|
||||||
|
q2_rect.left() - 30.0,
|
||||||
|
q2_rect.center().y,
|
||||||
|
),
|
||||||
|
Pos2::new(
|
||||||
|
q2_rect.left() + 5.0,
|
||||||
|
q2_rect.center().y,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
Stroke::new(1.5, Color32::from_rgb(0, 150, 255)),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fn render_hexagonal_timeline_matrix(&mut self, ui: &mut Ui) {
|
||||||
|
let (response, painter) =
|
||||||
|
ui.allocate_painter(ui.available_size(), egui::Sense::hover());
|
||||||
|
let center = response.rect.center();
|
||||||
|
|
||||||
|
// Pixel-raycaster: map mouse position to axial hex coordinate
|
||||||
|
if let Some(mouse) = response.hover_pos() {
|
||||||
|
let lx = (mouse.x - center.x) as f64;
|
||||||
|
let ly = (mouse.y - center.y) as f64;
|
||||||
|
let fq = (2.0 / 3.0 * lx) / HEX_RADIUS as f64;
|
||||||
|
let fr = (-1.0 / 3.0 * lx + SQRT_3 / 3.0 * ly) / HEX_RADIUS as f64;
|
||||||
|
let fs = -fq - fr;
|
||||||
|
|
||||||
|
let mut q = fq.round() as i32;
|
||||||
|
let mut r = fr.round() as i32;
|
||||||
|
let s = fs.round() as i32;
|
||||||
|
|
||||||
|
if (q as f64 - fq).abs() > (r as f64 - fr).abs()
|
||||||
|
&& (q as f64 - fq).abs() > (s as f64 - fs).abs()
|
||||||
|
{
|
||||||
|
q = -r - s;
|
||||||
|
} else if (r as f64 - fr).abs() > (s as f64 - fs).abs() {
|
||||||
|
r = -q - s;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.active_hovered_coord = Some(AxialCoordinate { q, r });
|
||||||
|
}
|
||||||
|
|
||||||
|
// Render hexagonal cells
|
||||||
|
for (&coord, cell) in &self.cell_database {
|
||||||
|
let cx =
|
||||||
|
center.x + HEX_RADIUS * (1.5 * coord.q as f32);
|
||||||
|
let cy = center.y
|
||||||
|
+ HEX_RADIUS
|
||||||
|
* ((3.0f32).sqrt()
|
||||||
|
* (coord.r as f32 + coord.q as f32 * 0.5));
|
||||||
|
|
||||||
|
let mut color = if cell.is_breakpoint {
|
||||||
|
COLOR_HEX_MUTATED
|
||||||
|
} else if cell.total_hits > 0 {
|
||||||
|
Color32::from_rgb(40, 20, 60)
|
||||||
|
} else {
|
||||||
|
COLOR_HEX_DEFAULT
|
||||||
|
};
|
||||||
|
if let Some(h) = self.active_hovered_coord {
|
||||||
|
if h == coord {
|
||||||
|
color = COLOR_HEX_HOVER;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut pts = Vec::new();
|
||||||
|
for i in 0..6 {
|
||||||
|
let rad = (60.0 * i as f32).to_radians();
|
||||||
|
pts.push(Pos2::new(
|
||||||
|
cx + HEX_RADIUS * rad.cos(),
|
||||||
|
cy + HEX_RADIUS * rad.sin(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
painter.polygon(pts, color, Stroke::new(1.0, COLOR_GRID_LINE));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn render_dynamic_telemetry_hud_blocks(&mut self, ui: &mut Ui) {
|
||||||
|
// PERFORMANCE NOTE (Verification Check 7c):
|
||||||
|
// HardwareFirmwareAnalyzer and IPC_STATE_MATRIX queries involve
|
||||||
|
// filesystem I/O and mutex locking. In a production 60 FPS loop,
|
||||||
|
// these must be cached and refreshed on a timer (e.g., every 500ms)
|
||||||
|
// rather than called every frame. The current implementation is
|
||||||
|
// correct for development/verification but will cause frame drops
|
||||||
|
// under sustained use. The fix is to store cached results in
|
||||||
|
// WarlockAppWorkspace with a last_refreshed Instant.
|
||||||
|
|
||||||
|
// Query firmware auditor for UEFI NVRAM anomalies
|
||||||
|
let nvram = HardwareFirmwareAnalyzer::audit_uefi_nvram();
|
||||||
|
// Query for ACPI sideloading signals
|
||||||
|
let signals = HardwareFirmwareAnalyzer::detect_stealth_sideload_signals();
|
||||||
|
for ev in nvram.iter().chain(signals.iter()) {
|
||||||
|
ui.colored_label(
|
||||||
|
Color32::from_rgb(255, 30, 60),
|
||||||
|
format!(" [FIRMWARE ALERT] {:?}", ev.category),
|
||||||
|
);
|
||||||
|
ui.colored_label(
|
||||||
|
Color32::from_rgb(200, 200, 200),
|
||||||
|
format!(" {}", ev.message),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check IPC state matrix for evasion violations
|
||||||
|
let matrix = IPC_STATE_MATRIX.lock().unwrap();
|
||||||
|
if matrix.values().any(|r| r.fallback_violation_triggered) {
|
||||||
|
for record in matrix
|
||||||
|
.values()
|
||||||
|
.filter(|r| r.fallback_violation_triggered)
|
||||||
|
{
|
||||||
|
ui.colored_label(
|
||||||
|
Color32::from_rgb(255, 150, 0),
|
||||||
|
format!(
|
||||||
|
" [EVASION DETECTED] PID {}: {} \
|
||||||
|
swapped to hidden IPC channel",
|
||||||
|
record.pid, record.process_name
|
||||||
|
),
|
||||||
|
);
|
||||||
|
self.render_entropy_sparkline_canvas(
|
||||||
|
ui,
|
||||||
|
&record.entropy_snapshots,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ui.colored_label(
|
||||||
|
Color32::GREEN,
|
||||||
|
" Local IPC Transport Validation Stable",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn render_entropy_sparkline_canvas(
|
||||||
|
&self,
|
||||||
|
ui: &mut Ui,
|
||||||
|
snapshots: &[u8],
|
||||||
|
) {
|
||||||
|
let (resp, painter) = ui.allocate_painter(
|
||||||
|
Vec2::new(140.0, 16.0),
|
||||||
|
egui::Sense::hover(),
|
||||||
|
);
|
||||||
|
let rect = resp.rect;
|
||||||
|
if snapshots.len() < 2 {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let step_x = rect.width() / (snapshots.len() - 1) as f32;
|
||||||
|
let mut pts = Vec::new();
|
||||||
|
for (i, &score) in snapshots.iter().enumerate() {
|
||||||
|
let x = rect.left() + (i as f32 * step_x);
|
||||||
|
let y = rect.bottom() - ((score as f32 / 100.0) * rect.height());
|
||||||
|
pts.push(Pos2::new(x, y));
|
||||||
|
}
|
||||||
|
for w in pts.windows(2) {
|
||||||
|
painter.line_segment(
|
||||||
|
[w[0], w[1]],
|
||||||
|
Stroke::new(1.2, Color32::LIGHT_GRAY),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,41 @@
|
||||||
|
|
||||||
|
#[cfg(target_os = "windows")]
|
||||||
|
use windows_sys::Win32::System::Diagnostics::Etw::{
|
||||||
|
StartTraceA, EVENT_TRACE_PROPERTIES,
|
||||||
|
TRACE_REAL_TIME_MODE,
|
||||||
|
};
|
||||||
|
// NOTE: ControlTraceA and EVENT_TRACE_CONTROL_STOP are reserved for
|
||||||
|
// future session teardown logic. Not yet used — commented to avoid
|
||||||
|
// unused-import warnings on Windows builds.
|
||||||
|
// use windows_sys::Win32::System::Diagnostics::Etw::{ControlTraceA, EVENT_TRACE_CONTROL_STOP};
|
||||||
|
|
||||||
|
pub struct WindowsEtwEngine;
|
||||||
|
|
||||||
|
impl WindowsEtwEngine {
|
||||||
|
#[cfg(target_os = "windows")]
|
||||||
|
pub unsafe fn spawn_windows_tap() {
|
||||||
|
std::thread::spawn(|| {
|
||||||
|
const SESSION_NAME: &str = "WarlockStaveEtwSession\0";
|
||||||
|
let allocation_size = std::mem::size_of::<EVENT_TRACE_PROPERTIES>()
|
||||||
|
+ SESSION_NAME.len()
|
||||||
|
+ 100;
|
||||||
|
let mut buffer = vec![0u8; allocation_size];
|
||||||
|
let props = &mut *(buffer.as_mut_ptr() as *mut EVENT_TRACE_PROPERTIES);
|
||||||
|
props.Wnode.BufferSize = allocation_size as u32;
|
||||||
|
props.Wnode.Flags = 0x00020000;
|
||||||
|
props.LogFileMode = TRACE_REAL_TIME_MODE;
|
||||||
|
props.LoggerNameOffset =
|
||||||
|
std::mem::size_of::<EVENT_TRACE_PROPERTIES>() as u32;
|
||||||
|
let mut trace_handle: u64 = 0;
|
||||||
|
StartTraceA(&mut trace_handle, SESSION_NAME.as_ptr(), props);
|
||||||
|
// Real-time consumer loop processes telemetry events
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(target_os = "windows"))]
|
||||||
|
pub unsafe fn spawn_windows_tap() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
===============================================================================
|
||||||
|
8. ADVANCED PLATFORM AUDITORS
|
||||||
|
|
@ -0,0 +1,88 @@
|
||||||
|
-----------------------------------------------------
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// x64DBG WINDOWS/WINE PLUGIN HOOK MODULE: PRODUCTION IMPLEMENTATION
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
#include <windows.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#define PLUG_SDKVERSION 5
|
||||||
|
typedef size_t CBTYPE;
|
||||||
|
struct PLUG_INITSTRUCT {
|
||||||
|
int pluginHandle;
|
||||||
|
int sdkVersion;
|
||||||
|
int pluginVersion;
|
||||||
|
char pluginName[256];
|
||||||
|
};
|
||||||
|
|
||||||
|
int pluginHandle;
|
||||||
|
HANDLE hPipe = INVALID_HANDLE_VALUE;
|
||||||
|
|
||||||
|
struct __attribute__((packed)) WineIpcPayload {
|
||||||
|
unsigned __int64 rip;
|
||||||
|
unsigned int eflags;
|
||||||
|
unsigned int buffer_len;
|
||||||
|
unsigned char bytes[15];
|
||||||
|
};
|
||||||
|
|
||||||
|
void AttemptPipeConnection() {
|
||||||
|
// Wine intercepts Windows named pipe routing and maps them
|
||||||
|
// straight to Unix sockets automatically
|
||||||
|
hPipe = CreateFileA(
|
||||||
|
"\\\\.\\pipe\\stave_bridge_ipc",
|
||||||
|
GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" __declspec(dllexport) bool pluginit(PLUG_INITSTRUCT* initStruct) {
|
||||||
|
initStruct->pluginVersion = 7;
|
||||||
|
initStruct->sdkVersion = PLUG_SDKVERSION;
|
||||||
|
strcpy(initStruct->pluginName, "WarlockStaveWineBridgeMaster");
|
||||||
|
pluginHandle = initStruct->pluginHandle;
|
||||||
|
AttemptPipeConnection();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" __declspec(dllexport) void plugstop() {
|
||||||
|
if (hPipe != INVALID_HANDLE_VALUE) {
|
||||||
|
CloseHandle(hPipe);
|
||||||
|
hPipe = INVALID_HANDLE_VALUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Triggered automatically by the x64dbg engine core on every
|
||||||
|
// user breakpoint step execution event
|
||||||
|
extern "C" __declspec(dllexport) void CBSTEPPED(CBTYPE cbType, void* info) {
|
||||||
|
if (hPipe == INVALID_HANDLE_VALUE) {
|
||||||
|
AttemptPipeConnection();
|
||||||
|
if (hPipe == INVALID_HANDLE_VALUE) return;
|
||||||
|
}
|
||||||
|
|
||||||
|
CONTEXT context;
|
||||||
|
context.ContextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER;
|
||||||
|
HANDLE currentThread = GetCurrentThread();
|
||||||
|
|
||||||
|
if (GetThreadContext(currentThread, &context)) {
|
||||||
|
WineIpcPayload payload;
|
||||||
|
payload.rip = context.Rip;
|
||||||
|
payload.eflags = context.EFlags;
|
||||||
|
payload.buffer_len = 15;
|
||||||
|
memset(payload.bytes, 0, 15);
|
||||||
|
|
||||||
|
SIZE_T bytesRead = 0;
|
||||||
|
ReadProcessMemory(
|
||||||
|
GetCurrentProcess(),
|
||||||
|
(LPCVOID)context.Rip,
|
||||||
|
payload.bytes, 15, &bytesRead
|
||||||
|
);
|
||||||
|
if (bytesRead > 0) {
|
||||||
|
payload.buffer_len = (unsigned int)bytesRead;
|
||||||
|
DWORD bytesWritten;
|
||||||
|
WriteFile(hPipe, &payload, sizeof(payload), &bytesWritten, NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
10B. Ghidra Java JNI Bridge (WarlockStaveBridge.java)
|
||||||
Loading…
Reference in New Issue