From 36ff2eb88edf4adec240d61f38ee2ad9fd984f01 Mon Sep 17 00:00:00 2001 From: VHSgunzo Date: Mon, 21 Oct 2024 19:11:42 +0300 Subject: [PATCH] v0.0.7 --- .github/workflows/ci.yml | 8 +-- Cargo.toml | 4 +- PKGBUILD | 2 +- src/main.rs | 133 ++++++++++++++++++++++----------------- 4 files changed, 84 insertions(+), 63 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8ff07f7..a669be7 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -39,10 +39,10 @@ jobs: upx --force -9 --best target/x86_64-pc-windows-gnu/release/ulexec.exe -o target/x86_64-pc-windows-gnu/release/ulexec-upx.exe; cp target/x86_64-pc-windows-gnu/release/{ulexec,ulexec-upx}.exe . ; - - name: Build archlinux package - uses: countstarlight/arch-makepkg-action@master - with: - scripts: "makepkg -fsCc --noconfirm" + # - name: Build archlinux package + # uses: countstarlight/arch-makepkg-action@master + # with: + # scripts: "makepkg -fsCc --noconfirm" - name: Release uses: softprops/action-gh-release@v1 diff --git a/Cargo.toml b/Cargo.toml index 1b55da0..31176f6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ulexec" -version = "0.0.6" +version = "0.0.7" edition = "2021" license = "MIT" readme = "README.md" @@ -24,7 +24,7 @@ memexec = "0.2.0" reqwest = { version = "0.12.8", features = ["blocking", "rustls-tls"] } [target.'cfg(target_os = "linux")'.dependencies] -goblin = "0.8.2" +goblin = "0.9.0" memfd-exec = "0.2.1" userland-execve = "0.2.0" nix = { version = "0.29.0", features = [ "fs", "process" ] } diff --git a/PKGBUILD b/PKGBUILD index fe56372..cb33c4a 100644 --- a/PKGBUILD +++ b/PKGBUILD @@ -1,7 +1,7 @@ # Maintainer: VHSgunzo pkgname='ulexec-bin' binname="${pkgname%-bin}" -pkgver='0.0.6' +pkgver='0.0.7' pkgrel='1' pkgdesc='A tool for loading and executing PE on Windows and ELF on Linux from memory' arch=("x86_64") diff --git a/src/main.rs b/src/main.rs index e370d2d..3656544 100644 --- a/src/main.rs +++ b/src/main.rs @@ -164,6 +164,7 @@ fn main() { let mut args: Args; let is_child = get_env_var("ULEXEC_CHILD") == "1"; + #[cfg(target_os = "windows")] { if is_child { @@ -235,12 +236,11 @@ fn main() { exec_file = data; #[cfg(target_os = "linux")] if args.reexec && is_child { - let _ = std::fs::remove_file(&file_path); file_path = PathBuf::new(); + env::remove_var("ULEXEC_URL"); + env::remove_var("ULEXEC_FILE"); env::remove_var("ULEXEC_CHILD"); env::remove_var("ULEXEC_REEXEC"); - env::remove_var("ULEXEC_FILE"); - env::remove_var("ULEXEC_URL"); } } Err(err) => { @@ -277,11 +277,15 @@ fn main() { #[cfg(target_os = "linux")] { use std::time; + use std::process; + use std::fs::File; use std::ffi::CString; use std::os::fd::AsRawFd; - use nix::unistd::{write, close}; use std::thread::{spawn, sleep}; + + use nix::sys::stat::Mode; use goblin::elf::{Elf, program_header}; + use nix::unistd::{write, close, mkfifo}; use memfd_exec::{Stdio, MemFdExecutable}; use nix::sys::memfd::{memfd_create, MemFdCreateFlag}; @@ -301,23 +305,55 @@ fn main() { } } - if args.reexec && !is_child { - let tmp_file = env::temp_dir().join(std::process::id().to_string()); - match std::fs::File::create(tmp_file.clone()) { - Ok(mut file) => { - if let Err(err) = file.write_all(&exec_file) { - eprintln!("Failed to write the binary file: {err}: {:?}", file_path); + fn ul_exec(file_path: PathBuf, exec_args: Vec) { + let mut args_cstrs: Vec = exec_args.iter() + .map(|arg| + CString::new(arg.clone()).unwrap() + ).collect(); + + let file_cstr = CString::new( + file_path.to_str().unwrap() + ).unwrap(); + args_cstrs.insert(0, file_cstr); + + let envs: Vec = env::vars() + .map(|(key, value)| + CString::new(format!("{}={}", key, value)).unwrap() + ).collect(); + + userland_execve::exec( + &file_path, + &args_cstrs, + &envs, + ) + } + + if args.reexec && !is_child && !args.mfdexec { + let fifo_path = &env::temp_dir().join(process::id().to_string()); + if let Err(err) = mkfifo(fifo_path, Mode::S_IRWXU) { + eprintln!("Failed to create fifo: {err}: {:?}", fifo_path); + exit(1) + } + env::set_var("ULEXEC_CHILD", "1"); + env::set_var("ULEXEC_REEXEC", "1"); + env::set_var("ULEXEC_FILE", fifo_path); + let fifo_path = fifo_path.clone(); + let exec_file = exec_file.clone(); + spawn(move || { + match File::create(&fifo_path) { + Ok(mut fifo) => { + if let Err(err) = fifo.write_all(&exec_file) { + eprintln!("Failed to write the binary file to fifo: {err}: {:?}", fifo_path); + exit(1) + } + let _ = std::fs::remove_file(&fifo_path); + } + Err(err) => { + eprintln!("Failed to open fifo: {err}: {:?}", fifo_path); exit(1) } - env::set_var("ULEXEC_CHILD", "1"); - env::set_var("ULEXEC_REEXEC", "1"); - env::set_var("ULEXEC_FILE", tmp_file.clone()); - } - Err(err) => { - eprintln!("Failed to create the binary file: {err}: {:?}", file_path); - exit(1) } - } + }); } let memfd_name = "exec"; @@ -330,54 +366,39 @@ fn main() { .envs(env::vars()) .status().unwrap().code().unwrap()) } else { - let mut args_cstrs: Vec = args.exec_args.iter() - .map(|arg| - CString::new(arg.clone()).unwrap() - ).collect(); + if file_path.to_str().unwrap().is_empty() && !exec_file.is_empty() { + match &memfd_create( + CString::new(memfd_name).unwrap().as_c_str(), + MemFdCreateFlag::MFD_CLOEXEC, + ) { + Ok(memfd) => { + let memfd_raw = memfd.as_raw_fd(); - match &memfd_create( - CString::new(memfd_name).unwrap().as_c_str(), - MemFdCreateFlag::MFD_CLOEXEC, - ) { - Ok(memfd) => { - let memfd_raw = memfd.as_raw_fd(); - - if file_path.to_str().unwrap().is_empty() && !exec_file.is_empty() { file_path = PathBuf::from( format!("/proc/self/fd/{}", memfd_raw.to_string()) ); + if let Err(err) = write(memfd, &exec_file) { eprintln!("Failed to write the binary file to memfd: {err}: {:?}", file_path); exit(1) } + drop(exec_file); + + spawn(move || { + sleep(time::Duration::from_millis(1)); + close(memfd_raw).unwrap() + }); + + ul_exec(file_path, args.exec_args) + } + Err(err) => { + eprintln!("Failed to create memfd: {err}"); + exit(1) } - drop(exec_file); - - let file_cstr = CString::new( - file_path.to_str().unwrap() - ).unwrap(); - args_cstrs.insert(0, file_cstr); - - let envs: Vec = env::vars() - .map(|(key, value)| - CString::new(format!("{}={}", key, value)).unwrap() - ).collect(); - - spawn(move || { - sleep(time::Duration::from_millis(1)); - close(memfd_raw).unwrap() - }); - - userland_execve::exec( - &file_path, - &args_cstrs, - &envs, - ) - } - Err(err) => { - eprintln!("Failed to create memfd: {err}"); - exit(1) } + } else { + drop(exec_file); + ul_exec(file_path, args.exec_args) } } }