From 899a13c1f47958b5250e59858775f7f2de6d3561 Mon Sep 17 00:00:00 2001 From: Glenn Van Loon Date: Tue, 14 Apr 2026 14:13:06 +0200 Subject: [PATCH 1/3] Add devcontainer --- .devcontainer/devcontainer.json | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 .devcontainer/devcontainer.json diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 0000000..00728e0 --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,20 @@ +{ + "name": "runfromprocess-rs-devcontainer", + "image": "mcr.microsoft.com/devcontainers/base:debian", + "features": { + "ghcr.io/MartinAskestad/features/mingw": {}, + "ghcr.io/devcontainers/features/rust": { + "targets": "x86_64-pc-windows-gnu" + } + }, + "customizations": { + "vscode": { + "extensions": [ + "vadimcn.vscode-lldb", + "rust-lang.rust-analyzer", + "tamasfe.even-better-toml" + ] + } + }, + "remoteUser": "vscode" +} From f74920cdfdfbdea67112cc53c8ca9fd86f8e850d Mon Sep 17 00:00:00 2001 From: Glenn Van Loon Date: Tue, 14 Apr 2026 14:13:13 +0200 Subject: [PATCH 2/3] Update ignore list See https://github.com/github/gitignore/blob/main/Rust.gitignore. --- .gitignore | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index d787b70..ad67955 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,21 @@ -/target -/result +# Generated by Cargo +# will have compiled files and executables +debug +target + +# These are backup files generated by rustfmt +**/*.rs.bk + +# MSVC Windows builds of rustc generate these, which store debugging information +*.pdb + +# Generated by cargo mutants +# Contains mutation testing data +**/mutants.out*/ + +# RustRover +# JetBrains specific template is maintained in a separate JetBrains.gitignore that can +# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore +# and can be added to the global gitignore or merged into this file. For a more nuclear +# option (not recommended) you can uncomment the following to ignore the entire idea folder. +#.idea/ From cac5dba6515995cd4490df697f237d599d6620d5 Mon Sep 17 00:00:00 2001 From: Glenn Van Loon Date: Tue, 14 Apr 2026 14:13:49 +0200 Subject: [PATCH 3/3] Update Rust version and windows crate --- Cargo.lock | 147 ++++++++++++++++++++++++++++++++++++++-------------- Cargo.toml | 22 ++++---- src/main.rs | 117 +++++++++++++++++++++-------------------- 3 files changed, 182 insertions(+), 104 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c9c8fae..832f4ba 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,86 +1,155 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 + +[[package]] +name = "proc-macro2" +version = "1.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" +dependencies = [ + "proc-macro2", +] [[package]] name = "runfromprocess-rs" -version = "0.1.0" +version = "0.2.0" dependencies = [ "windows", ] +[[package]] +name = "syn" +version = "2.0.117" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "unicode-ident" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" + [[package]] name = "windows" -version = "0.51.1" +version = "0.62.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "527fadee13e0c05939a6a05d5bd6eec6cd2e3dbd648b9f8e447c6518133d8580" +dependencies = [ + "windows-collections", + "windows-core", + "windows-future", + "windows-numerics", +] + +[[package]] +name = "windows-collections" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca229916c5ee38c2f2bc1e9d8f04df975b4bd93f9955dc69fabb5d91270045c9" +checksum = "23b2d95af1a8a14a3c7367e1ed4fc9c20e0a26e79551b1454d72583c97cc6610" dependencies = [ "windows-core", - "windows-targets", ] [[package]] name = "windows-core" -version = "0.51.1" +version = "0.62.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1f8cf84f35d2db49a46868f947758c7a1138116f7fac3bc844f43ade1292e64" +checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" dependencies = [ - "windows-targets", + "windows-implement", + "windows-interface", + "windows-link", + "windows-result", + "windows-strings", ] [[package]] -name = "windows-targets" -version = "0.48.5" +name = "windows-future" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +checksum = "e1d6f90251fe18a279739e78025bd6ddc52a7e22f921070ccdc67dde84c605cb" dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "windows-core", + "windows-link", + "windows-threading", ] [[package]] -name = "windows_aarch64_gnullvm" -version = "0.48.5" +name = "windows-implement" +version = "0.60.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" +checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] [[package]] -name = "windows_aarch64_msvc" -version = "0.48.5" +name = "windows-interface" +version = "0.59.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" +checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] [[package]] -name = "windows_i686_gnu" -version = "0.48.5" +name = "windows-link" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" [[package]] -name = "windows_i686_msvc" -version = "0.48.5" +name = "windows-numerics" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" +checksum = "6e2e40844ac143cdb44aead537bbf727de9b044e107a0f1220392177d15b0f26" +dependencies = [ + "windows-core", + "windows-link", +] [[package]] -name = "windows_x86_64_gnu" -version = "0.48.5" +name = "windows-result" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" +checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" +dependencies = [ + "windows-link", +] [[package]] -name = "windows_x86_64_gnullvm" -version = "0.48.5" +name = "windows-strings" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" +checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" +dependencies = [ + "windows-link", +] [[package]] -name = "windows_x86_64_msvc" -version = "0.48.5" +name = "windows-threading" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" +checksum = "3949bd5b99cafdf1c7ca86b43ca564028dfe27d66958f2470940f73d86d75b37" +dependencies = [ + "windows-link", +] diff --git a/Cargo.toml b/Cargo.toml index ac305d6..8ec2e30 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,24 +1,28 @@ [package] name = "runfromprocess-rs" -version = "0.1.0" -edition = "2021" +version = "0.2.0" +authors = ["quietvoid"] +description = "Start a process as child from a given parent process" +readme = "README.md" +repository = "https://github.com/quietvoid/runfromprocess-rs" +edition = "2024" [dependencies.windows] -version = "0.51" +version = ">=0.62.2" features = [ "Win32_Foundation", "Win32_Security", "Win32_System_Threading", "Win32_System_Memory", "Win32_System_SystemInformation", - "Win32_UI_WindowsAndMessaging" + "Win32_UI_WindowsAndMessaging", ] [dependencies] [profile.release] -opt-level = 'z' # Optimize for size -lto = true # Enable link-time optimization -codegen-units = 1 # Reduce number of codegen units to increase optimizations -panic = 'abort' # Abort on panic -strip = true # Strip symbols from binary* +opt-level = 'z' # Optimize for size +lto = true # Enable link-time optimization +codegen-units = 1 # Reduce number of codegen units to increase optimizations +panic = 'abort' # Abort on panic +strip = true # Strip symbols from binary* diff --git a/src/main.rs b/src/main.rs index 032cba0..8f31184 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,21 +1,21 @@ use std::mem::{size_of, zeroed}; use windows::{ - core::PWSTR, Win32::{ Foundation::{CloseHandle, ERROR_INSUFFICIENT_BUFFER, HANDLE}, System::{ - Memory::{GetProcessHeap, HeapAlloc, HeapFree, HEAP_NONE, HEAP_ZERO_MEMORY}, + Memory::{GetProcessHeap, HEAP_NONE, HEAP_ZERO_MEMORY, HeapAlloc, HeapFree}, Threading::{ - CreateProcessW, DeleteProcThreadAttributeList, InitializeProcThreadAttributeList, - OpenProcess, UpdateProcThreadAttribute, CREATE_UNICODE_ENVIRONMENT, - EXTENDED_STARTUPINFO_PRESENT, LPPROC_THREAD_ATTRIBUTE_LIST, PROCESS_ALL_ACCESS, - PROCESS_INFORMATION, PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, STARTF_USESHOWWINDOW, - STARTUPINFOEXW, + CREATE_UNICODE_ENVIRONMENT, CreateProcessW, DeleteProcThreadAttributeList, + EXTENDED_STARTUPINFO_PRESENT, InitializeProcThreadAttributeList, + LPPROC_THREAD_ATTRIBUTE_LIST, OpenProcess, PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, + PROCESS_ALL_ACCESS, PROCESS_INFORMATION, STARTF_USESHOWWINDOW, STARTUPINFOEXW, + UpdateProcThreadAttribute, }, }, UI::WindowsAndMessaging::SW_SHOW, }, + core::PWSTR, }; fn main() { @@ -34,53 +34,50 @@ fn main() { let ppid: u32 = args[1].parse().unwrap(); - // open target process - let phandle = unsafe { OpenProcess(PROCESS_ALL_ACCESS, false, ppid).unwrap() }; - // parent process spoofing + let phandle = unsafe { OpenProcess(PROCESS_ALL_ACCESS, false, ppid).unwrap() }; + create_process_with_handle(phandle, &args[2..]).unwrap(); unsafe { - create_process_with_handle(phandle, &args[2..]).unwrap(); CloseHandle(phandle).expect("Failed closing handle"); - }; + } } -/// # Safety -/// -/// Unsafe -pub unsafe fn create_process_with_handle( +pub fn create_process_with_handle( handle: HANDLE, args: &[String], ) -> Result { - let mut si: STARTUPINFOEXW = zeroed(); - let mut pi: PROCESS_INFORMATION = zeroed(); + let mut si: STARTUPINFOEXW = unsafe { zeroed() }; + let mut pi: PROCESS_INFORMATION = unsafe { zeroed() }; let mut size: usize = 0x30; loop { if size > 1024 { - return Err(windows::core::Error::from_win32()); + return Err(windows::core::Error::from_thread()); } si.StartupInfo.cb = size_of::() as u32; - si.lpAttributeList = LPPROC_THREAD_ATTRIBUTE_LIST(HeapAlloc( - GetProcessHeap().unwrap(), - HEAP_ZERO_MEMORY, - size, - )); + si.lpAttributeList = LPPROC_THREAD_ATTRIBUTE_LIST(unsafe { + HeapAlloc(GetProcessHeap().unwrap(), HEAP_ZERO_MEMORY, size) + }); if si.lpAttributeList.is_invalid() { - return Err(windows::core::Error::from_win32()); + return Err(windows::core::Error::from_thread()); } - let ret = match InitializeProcThreadAttributeList(si.lpAttributeList, 1, 0, &mut size) { + let ret = match unsafe { + InitializeProcThreadAttributeList(Some(si.lpAttributeList), 1, Some(0), &mut size) + } { Ok(()) => { - UpdateProcThreadAttribute( - si.lpAttributeList, - 0, - PROC_THREAD_ATTRIBUTE_PARENT_PROCESS as usize, - Some(&handle as *const _ as *mut _), - size_of::(), - None, - None, - )?; + unsafe { + UpdateProcThreadAttribute( + si.lpAttributeList, + 0, + PROC_THREAD_ATTRIBUTE_PARENT_PROCESS as usize, + Some(&handle as *const _ as *mut _), + size_of::(), + None, + None, + )?; + } si.StartupInfo.dwFlags = STARTF_USESHOWWINDOW; si.StartupInfo.wShowWindow = SW_SHOW.0 as _; @@ -90,21 +87,25 @@ pub unsafe fn create_process_with_handle( // println!("CMD len {}", cmdline.len()); - CreateProcessW( - None, - PWSTR::from_raw(cmdline.as_mut_ptr()), - None, - None, - false, - CREATE_UNICODE_ENVIRONMENT | EXTENDED_STARTUPINFO_PRESENT, - None, - None, - &si.StartupInfo, - &mut pi, - )?; - - CloseHandle(pi.hThread)?; - CloseHandle(pi.hProcess)?; + unsafe { + CreateProcessW( + None, + Some(PWSTR::from_raw(cmdline.as_mut_ptr())), + None, + None, + false, + CREATE_UNICODE_ENVIRONMENT | EXTENDED_STARTUPINFO_PRESENT, + None, + None, + &si.StartupInfo, + &mut pi, + )?; + } + + unsafe { + CloseHandle(pi.hThread)?; + CloseHandle(pi.hProcess)?; + } Ok(pi.dwProcessId) } @@ -119,13 +120,17 @@ pub unsafe fn create_process_with_handle( }; if !si.lpAttributeList.is_invalid() { - DeleteProcThreadAttributeList(si.lpAttributeList); + unsafe { + DeleteProcThreadAttributeList(si.lpAttributeList); + } + } + unsafe { + HeapFree( + GetProcessHeap().unwrap(), + HEAP_NONE, + Some(si.lpAttributeList.0), + )? } - HeapFree( - GetProcessHeap().unwrap(), - HEAP_NONE, - Some(si.lpAttributeList.0), - )?; match ret { Ok(0) => {