mirror of
https://github.com/Astatin3/unshell.git
synced 2026-06-08 22:38:01 -06:00
Get dynamic component loading working
This commit is contained in:
@@ -9,24 +9,24 @@ edition = "2024"
|
|||||||
crate-type = ["cdylib"]
|
crate-type = ["cdylib"]
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["client", "server"]
|
default = ["client", "server", "log_debug"]
|
||||||
|
|
||||||
client = ["unshell-lib/client"]
|
client = ["unshell-lib/client"]
|
||||||
server = ["unshell-lib/server"]
|
server = ["unshell-lib/server"]
|
||||||
|
|
||||||
|
log_debug = ["unshell-lib/log_debug"]
|
||||||
obfuscate = ["unshell-lib/obfuscate"]
|
obfuscate = ["unshell-lib/obfuscate"]
|
||||||
|
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
unshell-lib = {path = "../unshell-lib"}
|
unshell-lib = {path = "../unshell-lib", default-featues = false}
|
||||||
|
|
||||||
|
|
||||||
[profile.release]
|
[profile.release]
|
||||||
strip = true # Strip symbols from the binary
|
strip = true # Strip symbols from the binary
|
||||||
# strip = "debuginfo"
|
|
||||||
opt-level = "s" # Optimize for size
|
opt-level = "s" # Optimize for size
|
||||||
lto = true
|
lto = true
|
||||||
codegen-units = 1
|
codegen-units = 1
|
||||||
panic = "abort"
|
panic = "abort"
|
||||||
debug = false
|
debug = false
|
||||||
trim-paths = "all"
|
trim-paths = "all"
|
||||||
|
|
||||||
# crate-type = ["cdylib"]
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
|
// Behold! The world's most sophisticated shared library! (it has no code)
|
||||||
|
|
||||||
#![no_main]
|
#![no_main]
|
||||||
|
|
||||||
pub use unshell_lib::get_components;
|
pub use unshell_lib::get_components;
|
||||||
|
|
||||||
// Behold! The world's most sophisticated shared library!
|
|
||||||
|
|||||||
+30
-24
@@ -5,31 +5,37 @@ use unshell_lib::Announcement;
|
|||||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
let mut serverruntime = unshell_lib::server::ListenerRuntime::new();
|
let mut serverruntime = unshell_lib::server::ListenerRuntime::new();
|
||||||
|
|
||||||
loop {
|
// loop {
|
||||||
print!("> ");
|
// print!("> ");
|
||||||
stdout().flush().expect("Failed to flush stdout");
|
// stdout().flush().expect("Failed to flush stdout");
|
||||||
let mut input = String::new();
|
// let mut input = String::new();
|
||||||
stdin().read_line(&mut input).expect("Failed to read line");
|
// stdin().read_line(&mut input).expect("Failed to read line");
|
||||||
|
|
||||||
let args = input.trim().split(" ").collect::<Vec<&str>>();
|
// let args = input.trim().split(" ").collect::<Vec<&str>>();
|
||||||
|
|
||||||
match args[0] {
|
// match args[0] {
|
||||||
"" => {}
|
// "" => {}
|
||||||
"test" => {
|
// "test" => {
|
||||||
if let Some(arg) = args.get(1) {
|
// if let Some(arg) = args.get(1) {
|
||||||
println!("Test with argument: {}", arg);
|
// println!("Test with argument: {}", arg);
|
||||||
serverruntime
|
// serverruntime
|
||||||
.send(&Announcement::TestAnnouncement(arg.to_string()))
|
// .send(&Announcement::TestAnnouncement(arg.to_string()))
|
||||||
.unwrap();
|
// .unwrap();
|
||||||
} else {
|
// } else {
|
||||||
println!("Test without argument");
|
// println!("Test without argument");
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
_ => {
|
// _ => {
|
||||||
println!("Invalid Command: '{}'", args[0]);
|
// println!("Invalid Command: '{}'", args[0]);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
// println!("{:?}", args);
|
// // println!("{:?}", args);
|
||||||
}
|
// }
|
||||||
|
|
||||||
|
serverruntime.send(&Announcement::GetRuntimes)?;
|
||||||
|
|
||||||
|
// let response = serverruntime.
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,16 @@
|
|||||||
use bincode::{Decode, Encode};
|
use bincode::{Decode, Encode};
|
||||||
|
|
||||||
|
use crate::config::RuntimeConfig;
|
||||||
|
|
||||||
#[derive(Debug, Encode, Decode)]
|
#[derive(Debug, Encode, Decode)]
|
||||||
pub enum Announcement {
|
pub enum Announcement {
|
||||||
TestAnnouncement(String),
|
TestAnnouncement(String),
|
||||||
|
|
||||||
|
GetRuntimes,
|
||||||
|
GetRuntimesAck(usize),
|
||||||
|
|
||||||
|
StartRuntime(RuntimeConfig),
|
||||||
|
StartRuntimeAck(bool),
|
||||||
}
|
}
|
||||||
|
|
||||||
const BINCODE_CONFIG: bincode::config::Configuration = bincode::config::standard();
|
const BINCODE_CONFIG: bincode::config::Configuration = bincode::config::standard();
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ use std::{
|
|||||||
io::Read,
|
io::Read,
|
||||||
net::TcpStream,
|
net::TcpStream,
|
||||||
sync::{
|
sync::{
|
||||||
Arc,
|
Arc, Mutex,
|
||||||
atomic::{AtomicBool, Ordering},
|
atomic::{AtomicBool, Ordering},
|
||||||
},
|
},
|
||||||
thread::{self, JoinHandle},
|
thread::{self, JoinHandle},
|
||||||
@@ -43,16 +43,6 @@ impl ClientRuntime {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
info!("Connected");
|
info!("Connected");
|
||||||
// let reader = BufReader::new(stream.try_clone().unwrap());
|
|
||||||
// let mut writer = BufWriter::new(stream.try_clone().unwrap());
|
|
||||||
|
|
||||||
// let (a, b) = crossbeam_channel::unbounded();
|
|
||||||
|
|
||||||
// a.
|
|
||||||
|
|
||||||
// if join_receiver.len() == 0 {
|
|
||||||
// join_receiver.recv().unwrap();
|
|
||||||
// }
|
|
||||||
|
|
||||||
while !join_clone.load(Ordering::Relaxed) {
|
while !join_clone.load(Ordering::Relaxed) {
|
||||||
let mut size_buf = [0u8; 4];
|
let mut size_buf = [0u8; 4];
|
||||||
@@ -69,12 +59,29 @@ impl ClientRuntime {
|
|||||||
Announcement::TestAnnouncement(s) => {
|
Announcement::TestAnnouncement(s) => {
|
||||||
println!("Received test announcement: {}", s)
|
println!("Received test announcement: {}", s)
|
||||||
}
|
}
|
||||||
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
join_signal,
|
join_signal,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// pub fn send(&mut self, announcement: &Announcement) -> Result<(), ModuleError> {
|
||||||
|
// let bytes = announcement.encode();
|
||||||
|
|
||||||
|
// let mut streams = self.stream.lock().unwrap();
|
||||||
|
|
||||||
|
// for stream in streams.iter_mut() {
|
||||||
|
// stream.write_all(&u32::to_be_bytes(bytes.len() as u32))?;
|
||||||
|
// stream.write_all(&bytes)?;
|
||||||
|
// stream.flush()?;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// println!("Announcement {:?} sent", announcement);
|
||||||
|
|
||||||
|
// Ok(())
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ModuleRuntime for ClientRuntime {
|
impl ModuleRuntime for ClientRuntime {
|
||||||
|
|||||||
@@ -4,20 +4,8 @@ use crate::config::NamedComponent;
|
|||||||
|
|
||||||
#[obfuscated_symbol]
|
#[obfuscated_symbol]
|
||||||
pub fn get_components() -> Vec<NamedComponent> {
|
pub fn get_components() -> Vec<NamedComponent> {
|
||||||
// let mut components: HashMap<&'static str, Box<dyn Component>> = HashMap::new();
|
|
||||||
|
|
||||||
// let a = crate::client::get_interface;
|
|
||||||
|
|
||||||
return vec![
|
return vec![
|
||||||
#[cfg(feature = "client")]
|
#[cfg(feature = "client")]
|
||||||
crate::client::get_named_component(),
|
crate::client::get_named_component(),
|
||||||
];
|
];
|
||||||
|
|
||||||
// components
|
|
||||||
|
|
||||||
// vec![
|
|
||||||
// Feature::Client,
|
|
||||||
// #[cfg(feature = "server")]
|
|
||||||
// Feature::Server,
|
|
||||||
// ]
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,8 @@ use std::collections::HashMap;
|
|||||||
// use bincode::{Decode, Encode};
|
// use bincode::{Decode, Encode};
|
||||||
// use serde::{Deserialize, Serialize};
|
// use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
use bincode::{Decode, Encode};
|
||||||
|
|
||||||
use crate::{ModuleError, ModuleRuntime};
|
use crate::{ModuleError, ModuleRuntime};
|
||||||
|
|
||||||
// /// Payload config that is instantiated
|
// /// Payload config that is instantiated
|
||||||
@@ -19,11 +21,11 @@ pub struct PayloadConfig {
|
|||||||
pub runtime_config: Vec<RuntimeConfig>,
|
pub runtime_config: Vec<RuntimeConfig>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone, Encode, Decode)]
|
||||||
pub struct RuntimeConfig {
|
pub struct RuntimeConfig {
|
||||||
pub parent_component: &'static str,
|
pub parent_component: String,
|
||||||
pub name: &'static str,
|
pub name: String,
|
||||||
pub config: HashMap<&'static str, String>,
|
pub config: HashMap<String, String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
|
|||||||
@@ -10,15 +10,10 @@ mod components;
|
|||||||
pub use components::get_components;
|
pub use components::get_components;
|
||||||
|
|
||||||
mod announcement;
|
mod announcement;
|
||||||
use std::{
|
use std::fmt;
|
||||||
fmt,
|
|
||||||
// sync::{Arc, Mutex},
|
|
||||||
};
|
|
||||||
|
|
||||||
pub use announcement::Announcement;
|
pub use announcement::Announcement;
|
||||||
|
|
||||||
// use crate::module::{Interface, Manager};
|
|
||||||
|
|
||||||
///Generic error type for module-related operations.
|
///Generic error type for module-related operations.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum ModuleError {
|
pub enum ModuleError {
|
||||||
|
|||||||
@@ -19,18 +19,17 @@ pub struct Manager {
|
|||||||
pub modules: Vec<Module>,
|
pub modules: Vec<Module>,
|
||||||
|
|
||||||
active_runtimes: Vec<Box<dyn ModuleRuntime>>,
|
active_runtimes: Vec<Box<dyn ModuleRuntime>>,
|
||||||
// runtime_config: Vec<RuntimeConfig>,
|
|
||||||
components: HashMap<String, NamedComponent>,
|
components: HashMap<String, NamedComponent>,
|
||||||
}
|
}
|
||||||
|
|
||||||
// static mut MANAGER_RUNTIME: Option<Arc<Mutex<Manager>>> = None;
|
// static mut MANAGER_RUNTIME: Option<Arc<Mutex<Manager>>> = None;
|
||||||
|
|
||||||
impl Manager {
|
impl Manager {
|
||||||
fn new(id: &'static str, config: Vec<NamedComponent>, modules: Vec<Module>) -> Self {
|
fn new(id: &'static str, components: Vec<NamedComponent>, modules: Vec<Module>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
id,
|
id,
|
||||||
modules,
|
modules,
|
||||||
components: config
|
components: components
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|c| (c.name.to_string(), c))
|
.map(|c| (c.name.to_string(), c))
|
||||||
.collect(),
|
.collect(),
|
||||||
@@ -44,6 +43,9 @@ impl Manager {
|
|||||||
// Construct self
|
// Construct self
|
||||||
let mut this = Self::new(&config.id, config.components.clone(), modules);
|
let mut this = Self::new(&config.id, config.components.clone(), modules);
|
||||||
|
|
||||||
|
debug!("Imported {} base components", this.components.len());
|
||||||
|
debug!("Imported {} base runtimes", &config.runtime_config.len());
|
||||||
|
|
||||||
// Load each of the pre-prepared modules
|
// Load each of the pre-prepared modules
|
||||||
this.load_components();
|
this.load_components();
|
||||||
|
|
||||||
@@ -60,7 +62,7 @@ impl Manager {
|
|||||||
for module in &self.modules {
|
for module in &self.modules {
|
||||||
// Load get_components function from shared object library
|
// Load get_components function from shared object library
|
||||||
let component_func = match module
|
let component_func = match module
|
||||||
.get_symbol::<fn() -> Vec<NamedComponent>>(symbol!(b"get_components"))
|
.get_symbol::<fn() -> Vec<NamedComponent>>(symbol!("get_components").as_bytes())
|
||||||
{
|
{
|
||||||
Ok(func) => func,
|
Ok(func) => func,
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
@@ -70,7 +72,7 @@ impl Manager {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let components = component_func();
|
let components = component_func();
|
||||||
let component_name = "TODO";
|
let component_name = "TODO"; //TODO: Make this actually load component name
|
||||||
|
|
||||||
debug!("{} - Retrieved payload metadata", component_name);
|
debug!("{} - Retrieved payload metadata", component_name);
|
||||||
|
|
||||||
@@ -88,11 +90,11 @@ impl Manager {
|
|||||||
for runtime in runtimes {
|
for runtime in runtimes {
|
||||||
let mut this_lock = this.lock().unwrap();
|
let mut this_lock = this.lock().unwrap();
|
||||||
|
|
||||||
let component = match this_lock.components.get(runtime.parent_component) {
|
let component = match this_lock.components.get(&runtime.parent_component) {
|
||||||
Some(component) => component,
|
Some(component) => component,
|
||||||
None => {
|
None => {
|
||||||
warn!(
|
warn!(
|
||||||
"Could not find component {} which is referenced by runtime {}",
|
"Could not find component '{}' which is referenced by runtime: {}",
|
||||||
runtime.parent_component, runtime.name
|
runtime.parent_component, runtime.name
|
||||||
);
|
);
|
||||||
continue;
|
continue;
|
||||||
@@ -119,12 +121,18 @@ impl Manager {
|
|||||||
let mut this_lock = this.lock().unwrap();
|
let mut this_lock = this.lock().unwrap();
|
||||||
|
|
||||||
if this_lock.active_runtimes.len() <= 0 {
|
if this_lock.active_runtimes.len() <= 0 {
|
||||||
|
debug!("There are no more runtimes! Exiting...");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
this_lock
|
this_lock.active_runtimes.retain(|runtime| {
|
||||||
.active_runtimes
|
if runtime.is_running() {
|
||||||
.retain(|runtime| runtime.is_running());
|
true
|
||||||
|
} else {
|
||||||
|
debug!("Runtime exited!"); //TODO: Make this better
|
||||||
|
false
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
drop(this_lock);
|
drop(this_lock);
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
use std::{
|
use std::{
|
||||||
io::Write,
|
io::{Read, Write},
|
||||||
net::{TcpListener, TcpStream},
|
net::{TcpListener, TcpStream},
|
||||||
sync::{Arc, Mutex},
|
sync::{Arc, Mutex},
|
||||||
thread::{self, JoinHandle},
|
thread::{self, JoinHandle},
|
||||||
@@ -52,6 +52,24 @@ impl ListenerRuntime {
|
|||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn recv(&mut self) -> Result<Announcement, ModuleError> {
|
||||||
|
let stream = &mut self.streams.lock().unwrap()[0];
|
||||||
|
|
||||||
|
let mut size_buf = [0u8; 4];
|
||||||
|
stream.read_exact(&mut size_buf).unwrap();
|
||||||
|
let size = u32::from_be_bytes(size_buf);
|
||||||
|
|
||||||
|
let mut buf = vec![0u8; size as usize];
|
||||||
|
|
||||||
|
stream.read_exact(&mut buf).unwrap();
|
||||||
|
|
||||||
|
if let Some(announcement) = Announcement::decode(&buf) {
|
||||||
|
Ok(announcement)
|
||||||
|
} else {
|
||||||
|
Err(ModuleError::Error("Failed to decode announcement".into()))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ModuleRuntime for ListenerRuntime {
|
impl ModuleRuntime for ListenerRuntime {
|
||||||
|
|||||||
@@ -7,7 +7,10 @@ edition = "2024"
|
|||||||
[features]
|
[features]
|
||||||
obfuscate = ["unshell-obfuscate/obfuscate"]
|
obfuscate = ["unshell-obfuscate/obfuscate"]
|
||||||
log_debug = ["unshell-lib/log_debug"]
|
log_debug = ["unshell-lib/log_debug"]
|
||||||
# default = ["obfuscate"]
|
|
||||||
|
client = ["unshell-lib/client"]
|
||||||
|
server = ["unshell-lib/server"]
|
||||||
|
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
env_logger = "0.11.8"
|
env_logger = "0.11.8"
|
||||||
@@ -15,7 +18,7 @@ lazy_static = "1.5.0"
|
|||||||
libloading = "0.8.9"
|
libloading = "0.8.9"
|
||||||
proc-macro2 = "1.0.103"
|
proc-macro2 = "1.0.103"
|
||||||
|
|
||||||
unshell-lib = {path = "../unshell-lib"}
|
unshell-lib = {path = "../unshell-lib", default-features = false}
|
||||||
unshell-obfuscate = {path = "../unshell-obfuscate"}
|
unshell-obfuscate = {path = "../unshell-obfuscate"}
|
||||||
|
|
||||||
[profile.release]
|
[profile.release]
|
||||||
@@ -26,4 +29,3 @@ codegen-units = 1
|
|||||||
panic = "abort"
|
panic = "abort"
|
||||||
debug = false # Remove debug
|
debug = false # Remove debug
|
||||||
trim-paths="all"
|
trim-paths="all"
|
||||||
# panic=immediate-abort
|
|
||||||
|
|||||||
Executable
+3
@@ -0,0 +1,3 @@
|
|||||||
|
OBFUSCATION_KEY=abc123abc \
|
||||||
|
RUST_LOG=info \
|
||||||
|
cargo run --no-default-features $@ --release # $(ls ../*/target/release/*.so)
|
||||||
@@ -16,15 +16,15 @@ lazy_static! {
|
|||||||
id: symbol!("Test ID"),
|
id: symbol!("Test ID"),
|
||||||
components: unshell_lib::get_components(),
|
components: unshell_lib::get_components(),
|
||||||
runtime_config: vec![RuntimeConfig {
|
runtime_config: vec![RuntimeConfig {
|
||||||
parent_component: symbol!("client"),
|
parent_component: symbol!("client").to_string(),
|
||||||
name: symbol!("client runtime"),
|
name: symbol!("client runtime").to_string(),
|
||||||
config: HashMap::from([(symbol!("host"), obs!("localhost:1234"))]),
|
config: HashMap::from([(symbol!("host").to_string(), obs!("localhost:1234"))]),
|
||||||
}],
|
}],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
// #[cfg(not(feature = "obfuscate"))]
|
#[cfg(not(feature = "obfuscate"))]
|
||||||
unshell_lib::logger::PrettyLogger::init();
|
unshell_lib::logger::PrettyLogger::init();
|
||||||
|
|
||||||
debug!("Initialized");
|
debug!("Initialized");
|
||||||
|
|||||||
Reference in New Issue
Block a user