use rustmorphism::polymorphic_fn;
use serde::Deserialize;
use std::collections::HashMap;
use std::sync::Mutex;
use once_cell::sync::Lazy;
use log::{info, error};
use rand::prelude::*;
use std::env;
use std::fmt;
use std::fs;
use toml;
#[derive(Debug)]
pub struct StageContext {
pub payload: Option<Vec<u8>>,
pub metadata: HashMap<String, String>,
}
#[derive(Debug)]
pub enum FrameworkError {
Generic(String),
}
impl fmt::Display for FrameworkError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
FrameworkError::Generic(msg) => write!(f, "{}", msg),
}
}
}
pub trait PersistenceStage {
fn establish_persistence(&self, ctx: &StageContext) -> Result<(), FrameworkError>;
}
pub trait ExecutionStage {
fn execute_code(&self, ctx: &StageContext) -> Result<Vec<u8>, FrameworkError>;
}
pub trait C2Stage {
fn communicate_c2(&self, ctx: &StageContext) -> Result<(), FrameworkError>;
}
pub trait AntiAnalysisStage {
fn perform_anti_analysis(&self, ctx: &StageContext) -> Result<bool, FrameworkError>;
}
pub static PERSISTENCE_REGISTRY: Lazy<Mutex<HashMap<String, fn() -> Box<dyn PersistenceStage>>>> = Lazy::new(|| Mutex::new(HashMap::new()));
pub static EXECUTION_REGISTRY: Lazy<Mutex<HashMap<String, fn() -> Box<dyn ExecutionStage>>>> = Lazy::new(|| Mutex::new(HashMap::new()));
pub static C2_REGISTRY: Lazy<Mutex<HashMap<String, fn() -> Box<dyn C2Stage>>>> = Lazy::new(|| Mutex::new(HashMap::new()));
pub static ANTI_ANALYSIS_REGISTRY: Lazy<Mutex<HashMap<String, fn() -> Box<dyn AntiAnalysisStage>>>> = Lazy::new(|| Mutex::new(HashMap::new()));
pub fn register_persistence(name: &str, constructor: fn() -> Box<dyn PersistenceStage>) {
PERSISTENCE_REGISTRY.lock().unwrap().insert(name.to_string(), constructor);
}
pub fn register_execution(name: &str, constructor: fn() -> Box<dyn ExecutionStage>) {
EXECUTION_REGISTRY.lock().unwrap().insert(name.to_string(), constructor);
}
pub fn register_c2(name: &str, constructor: fn() -> Box<dyn C2Stage>) {
C2_REGISTRY.lock().unwrap().insert(name.to_string(), constructor);
}
pub fn register_anti_analysis(name: &str, constructor: fn() -> Box<dyn AntiAnalysisStage>) {
ANTI_ANALYSIS_REGISTRY.lock().unwrap().insert(name.to_string(), constructor);
}
pub struct RegistryRunKeys;
impl PersistenceStage for RegistryRunKeys {
fn establish_persistence(&self, ctx: &StageContext) -> Result<(), FrameworkError> {
info!("[Persistence] RegistryRunKeys: Attempting to establish persistence");
let result = Ok(());
match &result {
Ok(_) => {
info!("[Persistence] RegistryRunKeys: Success");
emit_telemetry("Persistence", "RegistryRunKeys", "Success");
},
Err(e) => error!("[Persistence] RegistryRunKeys: Error: {}", e),
}
result
}
}
pub struct ScheduledTasks;
impl PersistenceStage for ScheduledTasks {
fn establish_persistence(&self, ctx: &StageContext) -> Result<(), FrameworkError> {
info!("[Persistence] ScheduledTasks: Attempting to establish persistence");
let result = Ok(());
match &result {
Ok(_) => {
info!("[Persistence] ScheduledTasks: Success");
emit_telemetry("Persistence", "ScheduledTasks", "Success");
},
Err(e) => error!("[Persistence] ScheduledTasks: Error: {}", e),
}
result
}
}
pub struct WMIEventSubscription;
impl PersistenceStage for WMIEventSubscription {
fn establish_persistence(&self, ctx: &StageContext) -> Result<(), FrameworkError> {
info!("[Persistence] WMIEventSubscription: Attempting to establish persistence");
let result = Ok(());
match &result {
Ok(_) => {
info!("[Persistence] WMIEventSubscription: Success");
emit_telemetry("Persistence", "WMIEventSubscription", "Success");
},
Err(e) => error!("[Persistence] WMIEventSubscription: Error: {}", e),
}
result
}
}
polymorphic_fn! {
pub fn establish_persistence_poly() -> Box<dyn PersistenceStage> {
{ Box::new(RegistryRunKeys) },
{ Box::new(ScheduledTasks) },
{ Box::new(WMIEventSubscription) }
}
}
pub struct ClassicProcessInjection;
impl ExecutionStage for ClassicProcessInjection {
fn execute_code(&self, ctx: &StageContext) -> Result<Vec<u8>, FrameworkError> {
info!("[Execution] ClassicProcessInjection: Attempting to execute code");
let result = Ok(Vec::new());
match &result {
Ok(_) => {
info!("[Execution] ClassicProcessInjection: Success");
emit_telemetry("Execution", "ClassicProcessInjection", "Success");
},
Err(e) => error!("[Execution] ClassicProcessInjection: Error: {}", e),
}
result
}
}
pub struct MappingInjection;
impl ExecutionStage for MappingInjection {
fn execute_code(&self, ctx: &StageContext) -> Result<Vec<u8>, FrameworkError> {
info!("[Execution] MappingInjection: Attempting to execute code");
let result = Ok(Vec::new());
match &result {
Ok(_) => {
info!("[Execution] MappingInjection: Success");
emit_telemetry("Execution", "MappingInjection", "Success");
},
Err(e) => error!("[Execution] MappingInjection: Error: {}", e),
}
result
}
}
pub struct ThreadHijacking;
impl ExecutionStage for ThreadHijacking {
fn execute_code(&self, ctx: &StageContext) -> Result<Vec<u8>, FrameworkError> {
info!("[Execution] ThreadHijacking: Attempting to execute code");
let result = Ok(Vec::new());
match &result {
Ok(_) => {
info!("[Execution] ThreadHijacking: Success");
emit_telemetry("Execution", "ThreadHijacking", "Success");
},
Err(e) => error!("[Execution] ThreadHijacking: Error: {}", e),
}
result
}
}
pub struct DirectSyscallExecution;
impl ExecutionStage for DirectSyscallExecution {
fn execute_code(&self, ctx: &StageContext) -> Result<Vec<u8>, FrameworkError> {
info!("[Execution] DirectSyscallExecution: Attempting to execute code");
let result = Ok(Vec::new());
match &result {
Ok(_) => {
info!("[Execution] DirectSyscallExecution: Success");
emit_telemetry("Execution", "DirectSyscallExecution", "Success");
},
Err(e) => error!("[Execution] DirectSyscallExecution: Error: {}", e),
}
result
}
}
polymorphic_fn! {
pub fn execute_code_poly() -> Box<dyn ExecutionStage> {
{ Box::new(ClassicProcessInjection) },
{ Box::new(MappingInjection) },
{ Box::new(ThreadHijacking) },
{ Box::new(DirectSyscallExecution) }
}
}
pub struct HTTPSCommunication;
impl C2Stage for HTTPSCommunication {
fn communicate_c2(&self, ctx: &StageContext) -> Result<(), FrameworkError> {
info!("[C2] HTTPSCommunication: Attempting to communicate");
let result = Ok(());
match &result {
Ok(_) => {
info!("[C2] HTTPSCommunication: Success");
emit_telemetry("C2", "HTTPSCommunication", "Success");
},
Err(e) => error!("[C2] HTTPSCommunication: Error: {}", e),
}
result
}
}
pub struct DNSTunneling;
impl C2Stage for DNSTunneling {
fn communicate_c2(&self, ctx: &StageContext) -> Result<(), FrameworkError> {
info!("[C2] DNSTunneling: Attempting to communicate");
let result = Ok(());
match &result {
Ok(_) => {
info!("[C2] DNSTunneling: Success");
emit_telemetry("C2", "DNSTunneling", "Success");
},
Err(e) => error!("[C2] DNSTunneling: Error: {}", e),
}
result
}
}
pub struct ICMPCommunication;
impl C2Stage for ICMPCommunication {
fn communicate_c2(&self, ctx: &StageContext) -> Result<(), FrameworkError> {
info!("[C2] ICMPCommunication: Attempting to communicate");
let result = Ok(());
match &result {
Ok(_) => {
info!("[C2] ICMPCommunication: Success");
emit_telemetry("C2", "ICMPCommunication", "Success");
},
Err(e) => error!("[C2] ICMPCommunication: Error: {}", e),
}
result
}
}
pub struct RawSocketsCommunication;
impl C2Stage for RawSocketsCommunication {
fn communicate_c2(&self, ctx: &StageContext) -> Result<(), FrameworkError> {
info!("[C2] RawSocketsCommunication: Attempting to communicate");
let result = Ok(());
match &result {
Ok(_) => {
info!("[C2] RawSocketsCommunication: Success");
emit_telemetry("C2", "RawSocketsCommunication", "Success");
},
Err(e) => error!("[C2] RawSocketsCommunication: Error: {}", e),
}
result
}
}
polymorphic_fn! {
pub fn communicate_c2_poly() -> Box<dyn C2Stage> {
{ Box::new(HTTPSCommunication) },
{ Box::new(DNSTunneling) },
{ Box::new(ICMPCommunication) },
{ Box::new(RawSocketsCommunication) }
}
}
pub struct AntiDebugging;
impl AntiAnalysisStage for AntiDebugging {
fn perform_anti_analysis(&self, ctx: &StageContext) -> Result<bool, FrameworkError> {
info!("[AntiAnalysis] AntiDebugging: Attempting anti-debugging");
let result = Ok(true);
match &result {
Ok(_) => {
info!("[AntiAnalysis] AntiDebugging: Success");
emit_telemetry("AntiAnalysis", "AntiDebugging", "Success");
},
Err(e) => error!("[AntiAnalysis] AntiDebugging: Error: {}", e),
}
result
}
}
pub struct VMDetection;
impl AntiAnalysisStage for VMDetection {
fn perform_anti_analysis(&self, ctx: &StageContext) -> Result<bool, FrameworkError> {
info!("[AntiAnalysis] VMDetection: Attempting VM detection");
let result = Ok(true);
match &result {
Ok(_) => {
info!("[AntiAnalysis] VMDetection: Success");
emit_telemetry("AntiAnalysis", "VMDetection", "Success");
},
Err(e) => error!("[AntiAnalysis] VMDetection: Error: {}", e),
}
result
}
}
pub struct SandboxEvasion;
impl AntiAnalysisStage for SandboxEvasion {
fn perform_anti_analysis(&self, ctx: &StageContext) -> Result<bool, FrameworkError> {
info!("[AntiAnalysis] SandboxEvasion: Attempting sandbox evasion");
let result = Ok(true);
match &result {
Ok(_) => {
info!("[AntiAnalysis] SandboxEvasion: Success");
emit_telemetry("AntiAnalysis", "SandboxEvasion", "Success");
},
Err(e) => error!("[AntiAnalysis] SandboxEvasion: Error: {}", e),
}
result
}
}
polymorphic_fn! {
pub fn perform_anti_analysis_poly() -> Box<dyn AntiAnalysisStage> {
{ Box::new(AntiDebugging) },
{ Box::new(VMDetection) },
{ Box::new(SandboxEvasion) }
}
}
#[derive(Debug, Deserialize)]
pub struct FrameworkConfig {
pub persistence: Option<String>,
pub execution: Option<String>,
pub c2: Option<String>,
pub anti_analysis: Option<String>,
}
impl FrameworkConfig {
pub fn from_file(path: &str) -> Option<Self> {
fs::read_to_string(path)
.ok()
.and_then(|content| toml::from_str(&content).ok())
}
}
pub fn get_persistence_by_name(name: &str) -> Option<Box<dyn PersistenceStage>> {
PERSISTENCE_REGISTRY.lock().unwrap().get(name).map(|ctor| ctor())
}
pub fn get_execution_by_name(name: &str) -> Option<Box<dyn ExecutionStage>> {
EXECUTION_REGISTRY.lock().unwrap().get(name).map(|ctor| ctor())
}
pub fn get_c2_by_name(name: &str) -> Option<Box<dyn C2Stage>> {
C2_REGISTRY.lock().unwrap().get(name).map(|ctor| ctor())
}
pub fn get_anti_analysis_by_name(name: &str) -> Option<Box<dyn AntiAnalysisStage>> {
ANTI_ANALYSIS_REGISTRY.lock().unwrap().get(name).map(|ctor| ctor())
}
pub trait TelemetryEvent: Send + Sync {
fn on_event(&self, stage: &str, technique: &str, status: &str);
}
static TELEMETRY_CALLBACK: once_cell::sync::Lazy<Mutex<Option<Box<dyn TelemetryEvent>>>> = once_cell::sync::Lazy::new(|| Mutex::new(None));
pub fn set_telemetry_callback(cb: Box<dyn TelemetryEvent>) {
*TELEMETRY_CALLBACK.lock().unwrap() = Some(cb);
}
fn emit_telemetry(stage: &str, technique: &str, status: &str) {
if let Some(cb) = &*TELEMETRY_CALLBACK.lock().unwrap() {
cb.on_event(stage, technique, status);
}
}
pub fn weighted_random_choice<'a, T>(choices: &'a [(&T, u32)]) -> Option<&'a T> {
let total_weight: u32 = choices.iter().map(|(_, w)| *w).sum();
if total_weight == 0 { return None; }
let mut rng = rand::thread_rng();
let mut roll = rng.gen_range(0..total_weight);
for (item, weight) in choices {
if roll < *weight {
return Some(item);
}
roll -= *weight;
}
None
}
fn select_technique_by_condition<'a, T>(choices: &'a [T], env_var: &str) -> Option<&'a T>
where T: std::fmt::Debug
{
if let Ok(val) = env::var(env_var) {
for item in choices {
if format!("{:?}", item).contains(&val) {
return Some(item);
}
}
}
choices.get(0)
}
pub fn run_persistence_chain(names: &[&str]) -> Result<(), Vec<String>> {
let mut errors = Vec::new();
for &name in names {
let stage = get_persistence_by_name(name).unwrap_or_else(establish_persistence_poly);
if let Err(e) = stage.establish_persistence(&StageContext { payload: None, metadata: HashMap::new() }) {
errors.push(format!("Persistence {} failed: {}", name, e));
}
}
if errors.is_empty() { Ok(()) } else { Err(errors) }
}
pub fn run_execution_chain(names: &[&str]) -> Result<(), Vec<String>> {
let mut errors = Vec::new();
for &name in names {
let exec = get_execution_by_name(name).unwrap_or_else(execute_code_poly);
if let Err(e) = exec.execute_code(&StageContext { payload: None, metadata: HashMap::new() }) {
errors.push(format!("Execution {} failed: {}", name, e));
}
}
if errors.is_empty() { Ok(()) } else { Err(errors) }
}
pub fn run_c2_chain(names: &[&str]) -> Result<(), Vec<String>> {
let mut errors = Vec::new();
for &name in names {
let c2 = get_c2_by_name(name).unwrap_or_else(communicate_c2_poly);
if let Err(e) = c2.communicate_c2(&StageContext { payload: None, metadata: HashMap::new() }) {
errors.push(format!("C2 {} failed: {}", name, e));
}
}
if errors.is_empty() { Ok(()) } else { Err(errors) }
}
pub fn run_anti_analysis_chain(names: &[&str]) -> Result<(), Vec<String>> {
let mut errors = Vec::new();
for &name in names {
let anti = get_anti_analysis_by_name(name).unwrap_or_else(perform_anti_analysis_poly);
if let Err(e) = anti.perform_anti_analysis(&StageContext { payload: None, metadata: HashMap::new() }) {
errors.push(format!("AntiAnalysis {} failed: {}", name, e));
}
}
if errors.is_empty() { Ok(()) } else { Err(errors) }
}