Warlock's Stave is a lightweight reverse engineering framework designed for high-velocity dynamic code tracing, predictive instruction auditing, and deep infrastructure pattern inspection.
This commit is contained in:
commit
5078a9ec99
|
|
@ -0,0 +1,6 @@
|
||||||
|
[build]
|
||||||
|
rustdocflags = ["--document-private-items"]
|
||||||
|
|
||||||
|
[target.x86_64-unknown-linux-gnu]
|
||||||
|
# Uncomment to enable eBPF during development without sudo:
|
||||||
|
# rustflags = ["-C", "link-arg=-lbpf"]
|
||||||
|
|
@ -0,0 +1,24 @@
|
||||||
|
root = true
|
||||||
|
|
||||||
|
[*]
|
||||||
|
charset = utf-8
|
||||||
|
end_of_line = lf
|
||||||
|
insert_final_newline = true
|
||||||
|
trim_trailing_whitespace = true
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 4
|
||||||
|
|
||||||
|
[*.rs]
|
||||||
|
indent_size = 4
|
||||||
|
|
||||||
|
[*.md]
|
||||||
|
trim_trailing_whitespace = false
|
||||||
|
|
||||||
|
[*.{yml,yaml,toml}]
|
||||||
|
indent_size = 2
|
||||||
|
|
||||||
|
[*.java]
|
||||||
|
indent_size = 4
|
||||||
|
|
||||||
|
[*.cpp,*.h]
|
||||||
|
indent_size = 4
|
||||||
|
|
@ -0,0 +1,25 @@
|
||||||
|
# Build artifacts
|
||||||
|
/target/
|
||||||
|
*.o
|
||||||
|
*.so
|
||||||
|
*.dll
|
||||||
|
*.dylib
|
||||||
|
*.dp64
|
||||||
|
|
||||||
|
# eBPF compiled output (regenerated by build.sh)
|
||||||
|
/ebpf_bin/stave_probe.o
|
||||||
|
/ebpf_bin/stave_probe.c
|
||||||
|
|
||||||
|
# IDE
|
||||||
|
.idea/
|
||||||
|
.vscode/
|
||||||
|
*.swp
|
||||||
|
*.swo
|
||||||
|
*~
|
||||||
|
|
||||||
|
# OS
|
||||||
|
.DS_Store
|
||||||
|
Thumbs.db
|
||||||
|
|
||||||
|
# Environment
|
||||||
|
.env
|
||||||
|
|
@ -0,0 +1,36 @@
|
||||||
|
# Changelog
|
||||||
|
|
||||||
|
All notable changes to Warlock's Stave (`stave-core` crate) will be documented in this file.
|
||||||
|
|
||||||
|
## [7.0.0] - 2026-07-04
|
||||||
|
|
||||||
|
### Added
|
||||||
|
- Core engine with hexagonal heatmap timeline (axial coordinates, f64 pixel raycasting)
|
||||||
|
- Predictive branch evaluator (iced-x86 1.21.0, 15-byte safe decoder bounds)
|
||||||
|
- Dictionary scanner with default threat-hunting library (6 rules)
|
||||||
|
- Pluggable signature database engine with `ExternalScannerProvider` trait
|
||||||
|
- Mirror Illusion section-aware binary diff engine
|
||||||
|
- Tri-Tier Scope Engine (Global, Local, Micro)
|
||||||
|
- State Decay System for mutation highlight fadeout
|
||||||
|
- Shellcode Sentinel (memory permission transition monitor via `/proc/<pid>/maps`)
|
||||||
|
- Self-assembling IPC: Unix sockets, TCP loopback, named-pipe translation
|
||||||
|
- Thread-safe core via `Arc<Mutex<HexHeatmapEngine>>`
|
||||||
|
- C-FFI boundary layer (4 public functions with `#[no_mangle]`)
|
||||||
|
- JNI extension for Java-based host integration
|
||||||
|
- egui 0.27.0 4-quarter workspace UI
|
||||||
|
- Linux eBPF kernel tracing (aya 0.11.0, kprobe on `sys_enter_connect`)
|
||||||
|
- Windows ETW real-time telemetry session
|
||||||
|
- Polymorphic IPC evasion detection with Shannon entropy analysis
|
||||||
|
- UEFI NVRAM and ACPI table firmware analysis
|
||||||
|
- Pre-flight environment validator binary
|
||||||
|
- Evasion telemetry simulation binary
|
||||||
|
- Cross-compilation support for Wine plugin bridge (MinGW)
|
||||||
|
- Comprehensive unit test suite (14 tests)
|
||||||
|
- `rustdoc` examples on all FFI functions
|
||||||
|
|
||||||
|
### Design Decisions
|
||||||
|
- Engine is permanent; UI is disposable (Unix Philosophy)
|
||||||
|
- Host environments are untrusted; core has zero UI toolkit dependencies
|
||||||
|
- All IPC and FFI communication uses stateless JSON-Lines protocol
|
||||||
|
- Error paths return static data-segment strings to prevent host memory leaks
|
||||||
|
- `setcap` is never called inside the build script; printed as optional post-build step
|
||||||
|
|
@ -0,0 +1,72 @@
|
||||||
|
[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."
|
||||||
|
license = "AGPL-3.0-only"
|
||||||
|
repository = "https://github.com/warlock-architecture/stave-core"
|
||||||
|
readme = "README.md"
|
||||||
|
keywords = ["reverse-engineering", "telemetry", "disassembler", "heatmap", "evasion-detection"]
|
||||||
|
categories = ["development-tools::debugging", "visualization", "security"]
|
||||||
|
|
||||||
|
[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 host integration
|
||||||
|
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"] }
|
||||||
|
|
||||||
|
# Byte buffer utilities
|
||||||
|
bytes = "1.5.0"
|
||||||
|
|
||||||
|
# Structured logging facade (active — used via println! currently,
|
||||||
|
# retained for migration to tracing macros in a future release)
|
||||||
|
tracing = "0.1"
|
||||||
|
|
||||||
|
[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 telemetry bindings
|
||||||
|
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,21 @@
|
||||||
|
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.
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Affero General Public License as published
|
||||||
|
by the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU Affero General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Affero General Public License
|
||||||
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
@ -0,0 +1,64 @@
|
||||||
|
# Quick Start
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
|
||||||
|
| Component | Debian/Ubuntu | Arch Linux | Purpose |
|
||||||
|
|---|---|---|---|
|
||||||
|
| Rust toolchain | `rustup` | `rustup` | Core compilation |
|
||||||
|
| LLVM / Clang | `clang`, `llvm` | `clang`, `llvm` | eBPF bytecode compilation |
|
||||||
|
| MinGW-w64 | `g++-mingw-w64-x86-64` | `mingw-w64-gcc` | Wine plugin cross-compilation |
|
||||||
|
| libcap | `libcap2-bin` | `libcap` | Capability management |
|
||||||
|
| X11/Wayland | `libx11-dev`, `libwayland-dev` | `libx11`, `wayland` | egui rendering backend |
|
||||||
|
|
||||||
|
## Build
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git clone https://github.com/warlock-architecture/stave-core.git
|
||||||
|
cd stave-core
|
||||||
|
cargo run --bin environment_check # Verify tooling
|
||||||
|
chmod +x build.sh
|
||||||
|
./build.sh # Compile everything
|
||||||
|
```
|
||||||
|
|
||||||
|
## Optional: Enable Kernel Tracing
|
||||||
|
|
||||||
|
The eBPF probe requires elevated permissions. This step is **not** required for FFI, JNI, IPC, or UI-only usage:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo setcap cap_net_admin,cap_perfmon+ep ./target/release/libstave_core.so
|
||||||
|
```
|
||||||
|
|
||||||
|
## Verify
|
||||||
|
|
||||||
|
Open two terminals:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Terminal 1: Start the engine (your host application loads libstave_core)
|
||||||
|
cargo run --bin simulate_evasion_telemetry
|
||||||
|
|
||||||
|
# Terminal 2: Run the evasion simulator
|
||||||
|
cargo run --bin simulate_evasion_telemetry
|
||||||
|
```
|
||||||
|
|
||||||
|
## Hotkey Reference
|
||||||
|
|
||||||
|
| Key | Action |
|
||||||
|
|---|---|
|
||||||
|
| F1 | Help overlay |
|
||||||
|
| F2 | Load target binary / attach to PID |
|
||||||
|
| F3 | Inline micro-assembler (patch opcodes) |
|
||||||
|
| F4 | Cycle Q3 view mode (hex / assembly / headers) |
|
||||||
|
| F5 | Go to address / symbol |
|
||||||
|
| F6 | Search byte pattern or string |
|
||||||
|
| F7 | Step into (trace into CALL targets) |
|
||||||
|
| F8 | Step over (execute loops at native speed) |
|
||||||
|
| Alt+L | Toggle loop filter on hex grid |
|
||||||
|
| Alt+B | Toggle breakpoint filter on hex grid |
|
||||||
|
| Alt+D | Toggle disk I/O filter on hex grid |
|
||||||
|
| Alt+N | Toggle network I/O filter on hex grid |
|
||||||
|
| Ctrl+G | Follow pointer address in data viewport |
|
||||||
|
| Ctrl+T | Cast struct overlay onto hex view |
|
||||||
|
| Ctrl+Z | Undo last patch |
|
||||||
|
| F10 | Exit and flush telemetry |
|
||||||
|
|
||||||
|
> **Note:** Hotkeys are documented but not yet wired to the egui event loop. This is a planned feature.
|
||||||
|
|
@ -0,0 +1,179 @@
|
||||||
|
# Warlock's Stave
|
||||||
|
|
||||||
|
A lightweight, zero-allocation reverse engineering telemetry hub written in Rust. The library crate is `stave-core`.
|
||||||
|
|
||||||
|
Warlock's Stave compiles to a single dynamic system library (`libstave_core.so`, `stave_core.dll`, `libstave_core.dylib`) that exposes a stateless, C-compatible FFI and JNI interface. It is designed as a permanent analysis engine that communicates via standardized data pipelines, independent of any specific host UI or windowing toolkit.
|
||||||
|
|
||||||
|
**License:** [AGPL-3.0-only](LICENSE)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## What It Does
|
||||||
|
|
||||||
|
Warlock's Stave receives raw instruction execution frames from a host debugger or emulator, runs them through an analysis pipeline, and returns structured JSON-Lines telemetry. The host application (a disassembler, a GUI, a headless pipeline) renders the results.
|
||||||
|
|
||||||
|
It handles IPC transport automatically: Unix domain sockets on bare metal, TCP loopback in containers, and named-pipe-to-Unix-socket translation for compatibility-layer environments.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Core Engine
|
||||||
|
|
||||||
|
### Branch Prediction (Jump Oracle)
|
||||||
|
|
||||||
|
Decodes x86/x64 instructions via iced-x86 and evaluates conditional branches against the current EFLAGS register before the hardware commits. Supports JE, JNE, JG, JL, JMP, and CALL mnemonics. The decoder enforces a strict 15-byte clamp to prevent out-of-bounds reads on unmapped memory pages.
|
||||||
|
|
||||||
|
### Hexagonal Heatmap Timeline
|
||||||
|
|
||||||
|
Maps execution flow onto an axial hexagonal grid using f64-precision pixel raycasting. Each hex cell tracks hit count, I/O activity, breakpoint status, and semantic markers (loop, disk, network). The grid supports four filter toggles (Alt+L/B/D/N) to isolate specific activity types.
|
||||||
|
|
||||||
|
### Dictionary Scanner & Signature Database
|
||||||
|
|
||||||
|
A linear pattern-matching engine with two layers: a built-in hunting dictionary (HTTP/HTTPS URLs, anti-debug APIs, Base64 alphabets, PE headers) and a pluggable signature database designed to accept YARA-compatible and ClamAV-compatible backends via the `ExternalScannerProvider` trait.
|
||||||
|
|
||||||
|
### Tri-Tier Scope Engine
|
||||||
|
|
||||||
|
Classifies each execution frame at three analytical levels:
|
||||||
|
|
||||||
|
- **Global:** Cross-references, export footprints, file entropy.
|
||||||
|
- **Local:** Active function block boundaries from symbol tables.
|
||||||
|
- **Micro:** Predicted implicit register and memory side-effects before execution.
|
||||||
|
|
||||||
|
### Mirror Illusion Diff Engine
|
||||||
|
|
||||||
|
Section-aware binary comparison that aligns two files by ELF/PE section boundaries rather than raw byte offsets. This prevents code shifts from compiler changes from shattering the comparison. Operates on 16-byte grid lines with per-byte modified/identical status.
|
||||||
|
|
||||||
|
### State Decay System
|
||||||
|
|
||||||
|
Mutation highlights (registers flash red, memory bytes flash yellow) carry a configurable TTL counter that decrements each frame. Highlights fade smoothly back to the base theme color, communicating recent changes without permanent visual clutter.
|
||||||
|
|
||||||
|
### Self-Assembling IPC
|
||||||
|
|
||||||
|
Automatically detects the host environment at startup and selects the best transport:
|
||||||
|
|
||||||
|
| Environment | Transport |
|
||||||
|
|---|---|
|
||||||
|
| Bare metal (Linux) | Unix domain socket (`/tmp/stave_bridge_ipc.sock`) |
|
||||||
|
| Container (Docker, Podman, Kubernetes) | TCP loopback (`127.0.0.1:21860`) with `TCP_NODELAY` |
|
||||||
|
| Compatibility layer (Wine, Proton) | Named pipe (mapped to Unix socket by the translation bridge) |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Visualization
|
||||||
|
|
||||||
|
The immediate-mode UI (egui 0.27.0) renders a 4-quarter workspace at a target 60 FPS:
|
||||||
|
|
||||||
|
| Quarter | Content |
|
||||||
|
|---|---|
|
||||||
|
| Top panel | Hexagonal heatmap grid with pixel-raycaster mouse tracking |
|
||||||
|
| Q1 (bottom-left) | Disassembly stream from iced-x86 decoding |
|
||||||
|
| Q2 (bottom-right) | Register matrix with mutation highlighting + branch prediction outcome |
|
||||||
|
| Q3 (bottom-left, below Q1) | Dual-pane hex/ASCII data viewport |
|
||||||
|
| Q4 (bottom-right, below Q2) | Telemetry overlay: firmware alerts, IPC evasion status, entropy sparklines |
|
||||||
|
|
||||||
|
The UI is isolated from the core engine by design. It consumes computed data structures and renders them. The engine has zero dependencies on window layout toolkits.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Security Analysis
|
||||||
|
|
||||||
|
### Shellcode Sentinel
|
||||||
|
|
||||||
|
Monitors runtime memory segment permissions via `/proc/<pid>/maps`. Detects transitions that indicate shellcode injection:
|
||||||
|
|
||||||
|
- **Execute added to writable page** (RW- to RWX, or R-- to R-X)
|
||||||
|
- **Write added to executable page** (R-X to RWX)
|
||||||
|
- **Execute removed** (RWX to RW-, possibly post-exploitation cleanup)
|
||||||
|
|
||||||
|
Fires timed alerts that the UI renders as flashing warnings.
|
||||||
|
|
||||||
|
### Polymorphic IPC Evasion Detection
|
||||||
|
|
||||||
|
Audits processes for communication channel switching patterns. A process that drops its standard IPC connection while simultaneously creating unnamed pipes triggers an evasion alert. Includes Shannon entropy analysis for detecting encrypted channel activity.
|
||||||
|
|
||||||
|
### Firmware Analysis
|
||||||
|
|
||||||
|
Audits UEFI NVRAM variables for entries not belonging to known firmware vendors, and examines ACPI table entries for non-standard tables that could indicate bootkit persistence.
|
||||||
|
|
||||||
|
### Kernel Telemetry
|
||||||
|
|
||||||
|
- **Linux:** eBPF kprobe on `sys_enter_connect` via aya, capturing outbound connection events with PID and network namespace.
|
||||||
|
- **Windows:** Real-time ETW trace session for system event telemetry.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Plugin System
|
||||||
|
|
||||||
|
Warlock's Stave is not locked into a single frontend. Three integration paths are provided:
|
||||||
|
|
||||||
|
### C/C++ FFI (x64dbg / Wine)
|
||||||
|
|
||||||
|
A compiled plugin DLL (`warlock_bridge.dp64`) that hooks the debugger's step event callback, captures the current instruction context, and forwards it to the IPC daemon over a named pipe. See `bridges/stave_stub.cpp`.
|
||||||
|
|
||||||
|
### JNI (Java-based disassemblers)
|
||||||
|
|
||||||
|
A Java class (`WarlockStaveBridge`) that allocates a DirectByteBuffer, passes it to the native library with zero-copy overhead, and receives JSON telemetry in return. See `bridges/WarlockStaveBridge.java`.
|
||||||
|
|
||||||
|
### Direct Library Link
|
||||||
|
|
||||||
|
Any application that can call C FFI functions can link against `libstave_core` directly. The public API consists of four functions:
|
||||||
|
|
||||||
|
```c
|
||||||
|
void* initialize_warlock_stave();
|
||||||
|
const char* stave_ingest_frame(void* ctx, const uint8_t* buf, size_t len, uint64_t rip, uint32_t eflags);
|
||||||
|
void free_stave_string(const char* str);
|
||||||
|
void destroy_warlock_stave(void* ctx);
|
||||||
|
```
|
||||||
|
|
||||||
|
Run `cargo doc --open` for full rustdoc with safety documentation.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Future Work
|
||||||
|
|
||||||
|
- Hotkey-driven action HUD (F1-F10, Alt+L/B/D/N, Ctrl+G/T/Z) — currently documented but not wired to the egui event loop.
|
||||||
|
- Struct overlay parser for casting C-style struct definitions onto the hex viewport.
|
||||||
|
- Inline micro-assembler for patching opcodes directly from the UI.
|
||||||
|
- External scanner provider implementations (YARA-rust, ClamAV FFI).
|
||||||
|
- IPC response channel (currently sends structured analysis back to the host but the response path needs architecture decisions).
|
||||||
|
- Render-loop caching for firmware/IPC telemetry queries (currently queried every frame).
|
||||||
|
- macOS Endpoint Security Framework consumer.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Project Structure
|
||||||
|
|
||||||
|
```
|
||||||
|
stave-core/
|
||||||
|
├── Cargo.toml
|
||||||
|
├── build.sh
|
||||||
|
├── LICENSE
|
||||||
|
├── README.md
|
||||||
|
├── QuickStart.md
|
||||||
|
├── THIRD_PARTY_NOTICES.md
|
||||||
|
├── .gitignore
|
||||||
|
├── .editorconfig
|
||||||
|
├── .cargo/
|
||||||
|
│ └── config.toml
|
||||||
|
├── src/
|
||||||
|
│ ├── lib.rs # Core engine, FFI, JNI, all analysis modules
|
||||||
|
│ ├── ebpf.rs # Linux eBPF kernel tracing (aya)
|
||||||
|
│ ├── windows_etw.rs # Windows ETW telemetry
|
||||||
|
│ ├── polymorphic_ipc.rs # IPC evasion detection, Shannon entropy
|
||||||
|
│ ├── firmware.rs # UEFI NVRAM & ACPI table analysis
|
||||||
|
│ ├── stave_ui.rs # egui 4-quarter workspace
|
||||||
|
│ └── bin/
|
||||||
|
│ ├── environment_check.rs # Pre-flight dependency validator
|
||||||
|
│ └── simulate_evasion_telemetry.rs # IPC evasion simulation test
|
||||||
|
├── bridges/
|
||||||
|
│ ├── stave_stub.cpp # C++ plugin for x64dbg/Wine
|
||||||
|
│ └── WarlockStaveBridge.java # JNI bridge for Java-based hosts
|
||||||
|
└── ebpf_bin/ # Compiled eBPF bytecode (generated by build.sh)
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Legal Notices
|
||||||
|
|
||||||
|
Warlock's Stave is released under the GNU Affero General Public License v3.0 only. See [LICENSE](LICENSE) for the full text.
|
||||||
|
|
||||||
|
Certain product names mentioned in documentation and code comments are trademarks of their respective owners. These references are made for descriptive and compatibility purposes only and do not imply endorsement, sponsorship, or affiliation. See [THIRD_PARTY_NOTICES.md](THIRD_PARTY_NOTICES.md) for details.
|
||||||
|
|
@ -0,0 +1,69 @@
|
||||||
|
# Third-Party Notices and Trademark Acknowledgments
|
||||||
|
|
||||||
|
Warlock's Stave references certain third-party technologies, products, and
|
||||||
|
projects by name in its documentation, code comments, and build scripts.
|
||||||
|
These references are made solely for descriptive, compatibility, and
|
||||||
|
interoperability purposes. No endorsement, sponsorship, or affiliation
|
||||||
|
with any third party is intended or should be inferred.
|
||||||
|
|
||||||
|
## Trademarks
|
||||||
|
|
||||||
|
The following names are or may be trademarks or registered trademarks
|
||||||
|
of their respective owners. Warlock's Stave uses these names only to describe
|
||||||
|
compatibility targets, integration points, or runtime environments.
|
||||||
|
|
||||||
|
| Name | Owner | Context in This Project |
|
||||||
|
|---|---|---|
|
||||||
|
| Linux | Linus Torvalds (via Linux Foundation) | Target operating system |
|
||||||
|
| Windows | Microsoft Corporation | Target operating system, ETW API |
|
||||||
|
| macOS, OS X | Apple Inc. | Target operating system |
|
||||||
|
| Java, JVM, JNI | Oracle Corporation | Host integration via JNI bridge |
|
||||||
|
| Debian | Debian Project | Tested build environment |
|
||||||
|
| Arch Linux | Arch Linux Project | Tested build environment |
|
||||||
|
| Docker | Docker, Inc. (now Mirantis) | Container detection |
|
||||||
|
| Kubernetes | The Linux Foundation | Container detection |
|
||||||
|
| Podman | Red Hat, Inc. | Container detection |
|
||||||
|
| Wine, Proton | Wine project / Valve Corporation | Compatibility-layer IPC transport |
|
||||||
|
| ClamAV | Cisco Systems, Inc. | Referenced as a scanner backend option |
|
||||||
|
| YARA | VirusTotal (Google LLC) | Referenced as a scanner backend option |
|
||||||
|
| MinGW | The MinGW-w64 Project | Cross-compilation toolchain |
|
||||||
|
| LLVM, Clang | LLVM Foundation | eBPF bytecode compilation |
|
||||||
|
| Rust, cargo | Rust Foundation | Programming language and build tool |
|
||||||
|
| egui | Emil Ernerfeldt | UI framework |
|
||||||
|
| iced-x86 | vtto (GitHub) | Disassembly engine |
|
||||||
|
| Ghidra | National Security Agency | Referenced as a potential host application |
|
||||||
|
| x64dbg | Duncan Ogilvie | Referenced as a potential host application |
|
||||||
|
| ELF | UNIX System Laboratories (historical) | File format analyzed |
|
||||||
|
| Intel | Intel Corporation | CPU architecture, vendor GUID in firmware analysis |
|
||||||
|
| Microsoft | Microsoft Corporation | Vendor GUID in firmware analysis |
|
||||||
|
| UPX | Markus Oberhumer and Laszlo Molnar | Packer detection signature |
|
||||||
|
| VMProtect | Oreans Technologies | Packer detection signature |
|
||||||
|
| Petite | Ian Luck | Packer detection signature |
|
||||||
|
|
||||||
|
## Open Source Licenses
|
||||||
|
|
||||||
|
This project depends on the following open source crates, each
|
||||||
|
distributed under their own license. Crate versions are as specified
|
||||||
|
in `Cargo.toml`.
|
||||||
|
|
||||||
|
| Crate | License |
|
||||||
|
|---|---|
|
||||||
|
| iced-x86 | MIT |
|
||||||
|
| serde | MIT OR Apache-2.0 |
|
||||||
|
| serde_json | MIT OR Apache-2.0 |
|
||||||
|
| async-trait | MIT OR Apache-2.0 |
|
||||||
|
| jni | MIT OR Apache-2.0 |
|
||||||
|
| lazy_static | MIT OR Apache-2.0 |
|
||||||
|
| egui | Apache-2.0 |
|
||||||
|
| eframe | Apache-2.0 |
|
||||||
|
| bytes | MIT |
|
||||||
|
| tracing | MIT |
|
||||||
|
| aya | Apache-2.0 OR MIT |
|
||||||
|
| tokio | MIT |
|
||||||
|
| windows-sys | MIT OR Apache-2.0 |
|
||||||
|
|
||||||
|
## No Affiliation
|
||||||
|
|
||||||
|
The "Warlock Architecture Group" listed as the author in `Cargo.toml`
|
||||||
|
is a project author identifier. It is not a legal entity and does not
|
||||||
|
represent any company, organization, or institution.
|
||||||
|
|
@ -0,0 +1,62 @@
|
||||||
|
package org.stave;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Forms the native memory pipeline within a Java-based disassembler host.
|
||||||
|
* Manages execution events from an emulator or debug interface
|
||||||
|
* and passes raw byte arrays down to the compiled stave-core library
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
ByteBuffer directBuffer =
|
||||||
|
ByteBuffer.allocateDirect(memoryPageFrame.length);
|
||||||
|
directBuffer.put(memoryPageFrame);
|
||||||
|
directBuffer.flip();
|
||||||
|
|
||||||
|
String telemetryJsonOutput = staveIngestGhidraFrame(
|
||||||
|
this.nativeContextHandle,
|
||||||
|
directBuffer,
|
||||||
|
executionRip,
|
||||||
|
registerEflags
|
||||||
|
);
|
||||||
|
|
||||||
|
dispatchToWorkspace(telemetryJsonOutput);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void dispatchToWorkspace(String jsonStateFrame) {
|
||||||
|
// Enqueues the serialized tracking snapshot onto
|
||||||
|
// the main UI event stream for rendering.
|
||||||
|
}
|
||||||
|
|
||||||
|
public void terminateComponent() {
|
||||||
|
if (this.nativeContextHandle != 0) {
|
||||||
|
destroyWarlockStave(this.nativeContextHandle);
|
||||||
|
this.nativeContextHandle = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,87 @@
|
||||||
|
// ============================================================================
|
||||||
|
// x64dbg/Wine C++ Plugin Hook Module
|
||||||
|
// ============================================================================
|
||||||
|
//
|
||||||
|
// Forms the bridge between an x64dbg debug session (running under Wine)
|
||||||
|
// and the Warlock's Stave IPC daemon. Captures step events and forwards
|
||||||
|
// them as packed binary payloads over a named pipe (which Wine
|
||||||
|
// automatically maps to Unix sockets on Linux).
|
||||||
|
|
||||||
|
#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 named pipe routing and maps them
|
||||||
|
// to Unix sockets automatically on Linux.
|
||||||
|
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, "StaveCoreWineBridge");
|
||||||
|
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 on every 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,63 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
# ============================================================================
|
||||||
|
# WARLOCK'S STAVE PRODUCTION COMPILATION PIPELINE (v7.0)
|
||||||
|
# ============================================================================
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
log_step() { echo -e "\n [BUILD] $1"; }
|
||||||
|
|
||||||
|
log_step "Detecting host environment..."
|
||||||
|
if [ -f /etc/arch-release ]; then
|
||||||
|
echo " Profile: Arch Linux"
|
||||||
|
elif [ -f /etc/debian_version ]; then
|
||||||
|
echo " Profile: Debian/Ubuntu"
|
||||||
|
else
|
||||||
|
echo " Profile: Unknown (proceeding anyway)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
log_step "Validating dependency tooling..."
|
||||||
|
cargo check
|
||||||
|
|
||||||
|
log_step "Compiling core library (release)..."
|
||||||
|
cargo build --release
|
||||||
|
|
||||||
|
log_step "Compiling embedded eBPF bytecode..."
|
||||||
|
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 eBPF object..."
|
||||||
|
touch ebpf_bin/stave_probe.o
|
||||||
|
fi
|
||||||
|
|
||||||
|
if command -v x86_64-w64-mingw32-g++ &> /dev/null; then
|
||||||
|
log_step "Cross-compiling Wine plugin bridge..."
|
||||||
|
x86_64-w64-mingw32-g++ -shared -static -O3 \
|
||||||
|
-o bridges/warlock_bridge.dp64 bridges/stave_stub.cpp -lkernel32
|
||||||
|
echo " Plugin output: bridges/warlock_bridge.dp64"
|
||||||
|
else
|
||||||
|
echo " Info: MinGW not found. Skipping Wine plugin build."
|
||||||
|
fi
|
||||||
|
|
||||||
|
log_step "Build complete. Warlock's Stave v7.0 is ready."
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Optional post-build steps (do not run automatically)
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
TARGET_LIB="./target/release/libstave_core.so"
|
||||||
|
if [ -f "$TARGET_LIB" ]; then
|
||||||
|
echo ""
|
||||||
|
echo " Optional: To enable kernel-level eBPF tracing, run:"
|
||||||
|
echo " sudo setcap cap_net_admin,cap_perfmon+ep $TARGET_LIB"
|
||||||
|
echo ""
|
||||||
|
echo " This grants the library permission to attach eBPF probe programs."
|
||||||
|
echo " It is NOT required for FFI, JNI, IPC, or UI-only usage."
|
||||||
|
fi
|
||||||
|
|
@ -0,0 +1,4 @@
|
||||||
|
[toolchain]
|
||||||
|
channel = "stable"
|
||||||
|
components = ["rustfmt", "clippy"]
|
||||||
|
targets = ["x86_64-unknown-linux-gnu"]
|
||||||
|
|
@ -0,0 +1,50 @@
|
||||||
|
/// Pre-flight environment validator for Warlock's Stave (stave-core crate).
|
||||||
|
/// Checks that all required tooling and system interfaces are available.
|
||||||
|
|
||||||
|
use std::process::Command;
|
||||||
|
use std::path::Path;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
println!("===============================================================================");
|
||||||
|
println!(" WARLOCK'S STAVE: 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
match Command::new("clang").arg("--version").output() {
|
||||||
|
Ok(_) => println!(" [OK] LLVM Clang verified (eBPF ready)."),
|
||||||
|
Err(_) => println!(" [WARN] 'clang' missing. eBPF layers bypassed."),
|
||||||
|
}
|
||||||
|
|
||||||
|
match Command::new("x86_64-w64-mingw32-g++").arg("--version").output() {
|
||||||
|
Ok(_) => println!(" [OK] MinGW-w64 detected (Wine integration ready)."),
|
||||||
|
Err(_) => println!(" [WARN] MinGW missing. Windows plugin skipped."),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
{
|
||||||
|
if Path::new("/proc/net/unix").exists() {
|
||||||
|
println!(" [OK] Linux procfs readable (socket auditing ready).");
|
||||||
|
} else {
|
||||||
|
println!(" [FAIL] procfs not available.");
|
||||||
|
environment_ready = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
println!("-------------------------------------------------------------------------------");
|
||||||
|
if environment_ready {
|
||||||
|
println!(" RESULT: Environment validated. Ready to build.");
|
||||||
|
} else {
|
||||||
|
println!(" RESULT: Critical gaps detected. Resolve errors before building.");
|
||||||
|
std::process::exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,97 @@
|
||||||
|
/// 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");
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,67 @@
|
||||||
|
// ============================================================================
|
||||||
|
// WARLOCK'S STAVE: Linux eBPF Kernel Tracing Engine
|
||||||
|
// ============================================================================
|
||||||
|
//
|
||||||
|
// Provides kernel-level event tracing via eBPF kprobe programs.
|
||||||
|
// Requires: aya 0.11.0, clang for eBPF bytecode compilation,
|
||||||
|
// and elevated permissions (CAP_BPF or root).
|
||||||
|
|
||||||
|
#[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 {
|
||||||
|
/// Spawns eBPF kprobe on sys_enter_connect to intercept outbound
|
||||||
|
/// network connections. Requires a pre-compiled eBPF object at
|
||||||
|
/// `ebpf_bin/stave_probe.o` (built by `build.sh`).
|
||||||
|
#[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(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// No-op on non-Linux platforms.
|
||||||
|
#[cfg(not(target_os = "linux"))]
|
||||||
|
pub fn spawn_kernel_hooks() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,99 @@
|
||||||
|
// ============================================================================
|
||||||
|
// WARLOCK'S STAVE: Firmware & Hardware Analysis
|
||||||
|
// ============================================================================
|
||||||
|
//
|
||||||
|
// Analyzes UEFI NVRAM variables and ACPI table entries for stealth
|
||||||
|
// persistence mechanisms that survive OS-level analysis.
|
||||||
|
|
||||||
|
use std::path::Path;
|
||||||
|
|
||||||
|
use crate::polymorphic_ipc::{AdvancedTelemetryEvent, TelemetryEventCategory};
|
||||||
|
|
||||||
|
/// Analyzes UEFI NVRAM variables and firmware-level indicators
|
||||||
|
/// for stealth persistence mechanisms.
|
||||||
|
pub struct HardwareFirmwareAnalyzer;
|
||||||
|
|
||||||
|
impl HardwareFirmwareAnalyzer {
|
||||||
|
/// Audits Linux efivarfs for UEFI NVRAM variables that do not
|
||||||
|
/// belong to known firmware or OS vendors.
|
||||||
|
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 vendor GUID prefixes (simplified)
|
||||||
|
let known_vendors = [
|
||||||
|
"8be4df61", // Microsoft Corporation
|
||||||
|
"721c8b66", // Firmware vendor
|
||||||
|
"a1f02e8c", // Linux Foundation
|
||||||
|
"605dab50", // Intel Corporation
|
||||||
|
];
|
||||||
|
|
||||||
|
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();
|
||||||
|
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
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,148 @@
|
||||||
|
// ============================================================================
|
||||||
|
// WARLOCK'S STAVE: Polymorphic IPC Evasion Detection
|
||||||
|
// ============================================================================
|
||||||
|
//
|
||||||
|
// Audits processes for IPC channel switching patterns that indicate
|
||||||
|
// evasion — e.g., a process dropping its standard IPC connection and
|
||||||
|
// simultaneously creating an unnamed pipe to bypass monitoring.
|
||||||
|
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::sync::Mutex;
|
||||||
|
use lazy_static::lazy_static;
|
||||||
|
|
||||||
|
use crate::firmware::HardwareFirmwareAnalyzer;
|
||||||
|
|
||||||
|
/// Category of an evasion or 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.
|
||||||
|
#[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.
|
||||||
|
#[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>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Global IPC state matrix. The UI reads this via `IPC_STATE_MATRIX.lock()`.
|
||||||
|
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..=100 (scaled from bits-per-byte).
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(entropy / 8.0 * 100.0).round().min(100.0) as u8
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Audits /proc/self/maps for anonymous RWX memory regions
|
||||||
|
/// (indicator of shellcode injection or JIT-spray attacks).
|
||||||
|
pub fn audit_cache_abuse() -> Vec<AdvancedTelemetryEvent> {
|
||||||
|
let mut events = Vec::new();
|
||||||
|
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') {
|
||||||
|
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 /dev/shm for IPC channels not associated with any known
|
||||||
|
/// system service — potential hidden communication channels.
|
||||||
|
pub fn scan_hidden_ipc_channels() -> Vec<AdvancedTelemetryEvent> {
|
||||||
|
let mut events = Vec::new();
|
||||||
|
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();
|
||||||
|
if name.len() > 16 && name.chars().all(|c| c.is_alphanumeric()) {
|
||||||
|
events.push(AdvancedTelemetryEvent {
|
||||||
|
category: TelemetryEventCategory::HiddenChannelDiscovered,
|
||||||
|
message: format!("Suspicious shared-memory segment: /dev/shm/{}", name),
|
||||||
|
pid: 0,
|
||||||
|
severity: 2,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
events
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The primary auditor combining firmware, IPC evasion, and
|
||||||
|
/// hidden channel detection into a single full-spectrum pass.
|
||||||
|
pub struct AdvancedPlatformAuditor;
|
||||||
|
|
||||||
|
impl AdvancedPlatformAuditor {
|
||||||
|
/// Returns firmware-related alerts.
|
||||||
|
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.
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,344 @@
|
||||||
|
// ============================================================================
|
||||||
|
// WARLOCK'S STAVE: 4-Quarter High-Performance Presentation Engine (v7.0)
|
||||||
|
// ============================================================================
|
||||||
|
//
|
||||||
|
// Immediate-mode UI using egui. Organizes structural telemetry views
|
||||||
|
// into a 4-quarter grid: Disassembly, Registers, Data Viewport,
|
||||||
|
// and Architectural Telemetry.
|
||||||
|
|
||||||
|
use egui::{Color32, Pos2, Rect, Stroke, Ui, Vec2, Shape, RichText};
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
use crate::{HardwareFirmwareAnalyzer, IPC_STATE_MATRIX, SQRT_3};
|
||||||
|
|
||||||
|
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 development
|
||||||
|
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'S STAVE 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: 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.
|
||||||
|
|
||||||
|
let nvram = HardwareFirmwareAnalyzer::audit_uefi_nvram();
|
||||||
|
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),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
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 {}: {} \
|
||||||
|
switched 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,45 @@
|
||||||
|
// ============================================================================
|
||||||
|
// WARLOCK'S STAVE: Windows ETW Telemetry Engine
|
||||||
|
// ============================================================================
|
||||||
|
//
|
||||||
|
// Provides kernel-level event tracing via Event Tracing for Windows (ETW).
|
||||||
|
// This module is only compiled on Windows targets.
|
||||||
|
|
||||||
|
#[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 {
|
||||||
|
/// Creates a real-time ETW trace session for telemetry capture.
|
||||||
|
#[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
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// No-op on non-Windows platforms.
|
||||||
|
#[cfg(not(target_os = "windows"))]
|
||||||
|
pub unsafe fn spawn_windows_tap() {}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue