506 lines
19 KiB
Rust
506 lines
19 KiB
Rust
// ============================================================================
|
|
// 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};
|
|
|
|
/// Spacing between crow positions on the grid (pixels).
|
|
const CROW_SPACING: f32 = 42.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_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);
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Crow silhouette shapes (normalized coordinates, centered at origin)
|
|
// ---------------------------------------------------------------------------
|
|
|
|
/// Profile crow facing right — perched, watching the landscape.
|
|
/// Points trace beak-tip → crown → tail → belly → throat → beak-tip.
|
|
const CROW_PROFILE: &[(f32, f32)] = &[
|
|
( 0.52, -0.02), // beak tip
|
|
( 0.38, -0.10), // beak top
|
|
( 0.28, -0.18), // forehead
|
|
( 0.18, -0.24), // crown
|
|
( 0.02, -0.26), // back of head
|
|
(-0.15, -0.28), // upper back
|
|
(-0.32, -0.30), // wing peak
|
|
(-0.46, -0.22), // wing trailing edge
|
|
(-0.42, -0.08), // lower back
|
|
(-0.52, -0.06), // tail tip (upper)
|
|
(-0.48, 0.02), // tail tip (lower)
|
|
(-0.35, 0.06), // rump
|
|
(-0.15, 0.16), // belly
|
|
( 0.08, 0.14), // chest
|
|
( 0.22, 0.06), // throat
|
|
( 0.32, 0.00), // chin
|
|
( 0.38, -0.04), // beak bottom
|
|
];
|
|
|
|
/// Front-facing crow — head turned toward the viewer, wings half-spread.
|
|
/// Used for breakpoint / warning cells.
|
|
const CROW_FACING: &[(f32, f32)] = &[
|
|
(-0.52, -0.04), // left wing tip
|
|
(-0.42, -0.22), // left wing top
|
|
(-0.22, -0.30), // left shoulder
|
|
(-0.06, -0.32), // crown left
|
|
( 0.06, -0.32), // crown right
|
|
( 0.22, -0.30), // right shoulder
|
|
( 0.42, -0.22), // right wing top
|
|
( 0.52, -0.04), // right wing tip
|
|
( 0.38, 0.06), // right body
|
|
( 0.18, 0.16), // right lower
|
|
( 0.00, 0.20), // bottom center
|
|
(-0.18, 0.16), // left lower
|
|
(-0.38, 0.06), // left body
|
|
];
|
|
|
|
/// Beak triangle for front-facing crow (pointing downward at viewer).
|
|
const CROW_BEAK: &[(f32, f32)] = &[
|
|
( 0.00, -0.32), // base center (head bottom)
|
|
( 0.07, -0.20), // right corner
|
|
(-0.07, -0.20), // left corner
|
|
];
|
|
|
|
/// Maps heatmap hit count to an "aged crow" color.
|
|
/// Fresh crows are nearly invisible; ancient crows glow with the theme neon.
|
|
fn crow_heatmap_color(hits: u64) -> Color32 {
|
|
match hits {
|
|
0 => Color32::from_rgb(28, 24, 30), // ghost — barely materialized
|
|
1 => Color32::from_rgb(48, 40, 55), // fledgling — dark charcoal
|
|
2..=3 => Color32::from_rgb(68, 52, 85), // juvenile — deep plum
|
|
4..=6 => Color32::from_rgb(100, 68, 125), // adult — rich purple
|
|
7..=10 => Color32::from_rgb(145, 95, 175), // elder — bright plumage
|
|
_ => Color32::from_rgb(0, 210, 165), // ancient — neon raven
|
|
}
|
|
}
|
|
|
|
/// Scales crow size based on hit count. Crows grow as a cell is revisited.
|
|
fn crow_heatmap_scale(hits: u64) -> f32 {
|
|
0.55 + 0.12 * (hits as f32).min(12.0)
|
|
}
|
|
|
|
/// Build a Pos2 list from normalized shape coordinates, scaled and translated.
|
|
fn shape_at(pts: &[(f32, f32)], cx: f32, cy: f32, size: f32) -> Vec<Pos2> {
|
|
pts.iter()
|
|
.map(|&(x, y)| Pos2::new(cx + x * size, cy + y * size))
|
|
.collect()
|
|
}
|
|
|
|
#[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 -6i32..=6i32 {
|
|
for r in -6i32..=6i32 {
|
|
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::CubicBezier(egui::epaint::CubicBezierShape {
|
|
points: [
|
|
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: Stroke::new(1.5, Color32::from_rgb(0, 150, 255)),
|
|
fill: Color32::TRANSPARENT,
|
|
closed: false,
|
|
}));
|
|
}
|
|
});
|
|
}
|
|
|
|
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 to axial coordinate (same math, crow spacing)
|
|
if let Some(mouse) = response.hover_pos() {
|
|
let lx = (mouse.x - center.x) as f64;
|
|
let ly = (mouse.y - center.y) as f64;
|
|
let sp = CROW_SPACING as f64;
|
|
let fq = (2.0 / 3.0 * lx) / sp;
|
|
let fr = (-1.0 / 3.0 * lx + SQRT_3 / 3.0 * ly) / sp;
|
|
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 the murder of crows
|
|
let eye_color = Color32::from_rgb(255, 240, 180); // pale yellow
|
|
let beak_color = Color32::from_rgb(55, 40, 30);
|
|
|
|
for (&coord, cell) in &self.cell_database {
|
|
let cx = center.x
|
|
+ CROW_SPACING * (1.5 * coord.q as f32);
|
|
let cy = center.y
|
|
+ CROW_SPACING
|
|
* ((3.0f32).sqrt()
|
|
* (coord.r as f32 + coord.q as f32 * 0.5));
|
|
|
|
let is_hovered = self.active_hovered_coord == Some(coord);
|
|
|
|
// Determine color: aged-crow palette, hover glow, or warning tint
|
|
let body_color = if is_hovered {
|
|
COLOR_HEX_HOVER
|
|
} else if cell.is_breakpoint {
|
|
// Warning crow — blend the aged color with a red tint
|
|
let aged = crow_heatmap_color(cell.total_hits);
|
|
let r = (aged.r() as u16 + 120).min(255) as u8;
|
|
let g = aged.g() / 3;
|
|
let b = aged.b() / 3;
|
|
Color32::from_rgb(r, g, b)
|
|
} else {
|
|
crow_heatmap_color(cell.total_hits)
|
|
};
|
|
|
|
let size = CROW_SPACING * crow_heatmap_scale(cell.total_hits);
|
|
|
|
// Some crows face left, some face right (deterministic from coords)
|
|
let face_right = (coord.q + coord.r) % 2 != 0;
|
|
|
|
if cell.is_breakpoint {
|
|
// --- WARNING CROW: front-facing, looking at you ---
|
|
let body_pts = shape_at(CROW_FACING, cx, cy, size);
|
|
painter.add(Shape::Path(egui::epaint::PathShape {
|
|
points: body_pts,
|
|
closed: true,
|
|
fill: body_color,
|
|
stroke: Stroke::new(1.2, COLOR_HEX_MUTATED),
|
|
}));
|
|
|
|
// Beak pointing at viewer
|
|
let beak_pts = shape_at(CROW_BEAK, cx, cy, size);
|
|
painter.add(Shape::Path(egui::epaint::PathShape {
|
|
points: beak_pts,
|
|
closed: true,
|
|
fill: beak_color,
|
|
stroke: Stroke::NONE,
|
|
}));
|
|
|
|
// Eyes — two pale dots staring at you
|
|
let eye_r = (size * 0.035).max(1.2);
|
|
let eye_y = cy - size * 0.24;
|
|
painter.circle_filled(
|
|
Pos2::new(cx - size * 0.10, eye_y),
|
|
eye_r,
|
|
eye_color,
|
|
);
|
|
painter.circle_filled(
|
|
Pos2::new(cx + size * 0.10, eye_y),
|
|
eye_r,
|
|
eye_color,
|
|
);
|
|
|
|
// Pupils — tiny dark dots inside the eyes
|
|
let pupil_r = eye_r * 0.5;
|
|
painter.circle_filled(
|
|
Pos2::new(cx - size * 0.10, eye_y),
|
|
pupil_r,
|
|
Color32::BLACK,
|
|
);
|
|
painter.circle_filled(
|
|
Pos2::new(cx + size * 0.10, eye_y),
|
|
pupil_r,
|
|
Color32::BLACK,
|
|
);
|
|
} else {
|
|
// --- PROFILE CROW: perched, watching the landscape ---
|
|
let pts = if face_right {
|
|
shape_at(CROW_PROFILE, cx, cy, size)
|
|
} else {
|
|
// Mirror: negate x coordinates
|
|
CROW_PROFILE
|
|
.iter()
|
|
.map(|&(x, y)| Pos2::new(cx - x * size, cy + y * size))
|
|
.collect()
|
|
};
|
|
painter.add(Shape::Path(egui::epaint::PathShape {
|
|
points: pts,
|
|
closed: true,
|
|
fill: body_color,
|
|
stroke: Stroke::new(0.8, COLOR_GRID_LINE),
|
|
}));
|
|
|
|
// Small eye dot on profile crow
|
|
let eye_r = (size * 0.028).max(1.0);
|
|
let (ex, ey) = if face_right {
|
|
(cx + size * 0.22, cy - size * 0.18)
|
|
} else {
|
|
(cx - size * 0.22, cy - size * 0.18)
|
|
};
|
|
painter.circle_filled(Pos2::new(ex, ey), eye_r, eye_color);
|
|
}
|
|
|
|
// Hover glow: soft circle behind the crow
|
|
if is_hovered {
|
|
painter.circle_filled(
|
|
Pos2::new(cx, cy),
|
|
size * 0.55,
|
|
Color32::from_rgba_premultiplied(0, 255, 200, 25),
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
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),
|
|
);
|
|
}
|
|
}
|
|
} |