Hello everyone, this is my first post here.
I am having trouble spawning a windows process from the API. I want to spawn a process, insert my own bytes into the process and then restart it so my original bytes are ran. I tried with .exe and .bin file. Its a simple dialogue box and i am 100% sure the file is valid and runnable.
this is the error:
error: process didn't exit successfully: target\debug\windows_rust_bytes.exe
(exit code: 0xc0000005, STATUS_ACCESS_VIOLATION)
Process finished with exit code -1073741819 (0xC0000005)
and this is my code:
use std::ffi::OsStr;
use std::io::Read;
use std::mem;
use std::os::windows::ffi::OsStrExt;
use std::ptr;
use windows::core::{PCWSTR, PWSTR};
use windows::Win32::Foundation::{BOOL, CloseHandle, GetLastError};
use windows::Win32::System::Diagnostics::Debug::WriteProcessMemory;
use windows::Win32::System::Memory::{MEM_COMMIT, MEM_RELEASE, MEM_RESERVE, PAGE_EXECUTE_READWRITE, PAGE_PROTECTION_FLAGS, PAGE_READWRITE, VirtualAllocEx, VirtualFree, VirtualProtect};
use windows::Win32::System::Threading::{
CREATE_SUSPENDED, CreateProcessW, CreateRemoteThread, INFINITE, PROCESS_INFORMATION, STARTUPINFOW, WaitForSingleObject,
};
fn execute_file(file_path: &str) -> Result<(), Box<dyn std::error::Error>> {
// Step 1: Read the file contents
let mut file = std::fs::File::open(file_path)?;
let mut file_contents = Vec::new();
file.read_to_end(&mut file_contents)?;
unsafe {
// Convert file path to wide string
let exe_wide: Vec<u16> = OsStr::new(file_path).encode_wide().chain(Some(0)).collect();
let cmd_line_wide: Vec<u16> = exe_wide.clone();
// Step 2: Create the process in a suspended state
let mut startup_info: STARTUPINFOW = mem::zeroed();
startup_info.cb = mem::size_of::<STARTUPINFOW>() as u32;
let mut process_info: PROCESS_INFORMATION = mem::zeroed();
let success = CreateProcessW(
PCWSTR(exe_wide.as_ptr()),
PWSTR(cmd_line_wide.as_ptr() as *mut _),
Some(ptr::null_mut()),
Some(ptr::null_mut()),
BOOL(0),
CREATE_SUSPENDED,
Some(ptr::null_mut()),
PCWSTR(ptr::null()),
&startup_info,
&mut process_info,
);
if success.is_err() {
return Err(format!("Failed to create process: {}", success.err().unwrap()).into());
}
// Step 3: Allocate memory in the new process
let size = file_contents.len();
let mem = VirtualAllocEx(
process_info.hProcess,
*ptr::null_mut(),
size,
MEM_COMMIT | MEM_RESERVE,
PAGE_READWRITE,
);
if mem.is_null() {
CloseHandle(process_info.hProcess);
CloseHandle(process_info.hThread);
return Err(format!("Failed to allocate memory in the process: {}", GetLastError().0).into());
}
// Step 4: Write the file contents to the allocated memory
let mut bytes_written: usize = 0;
let write_result = WriteProcessMemory(
process_info.hProcess,
mem,
file_contents.as_ptr() as *const _,
size,
Some(&mut bytes_written),
);
if write_result.is_err() {
VirtualFree(mem, 0, MEM_RELEASE);
CloseHandle(process_info.hProcess);
CloseHandle(process_info.hThread);
return Err(format!("Failed to write to memory: {}", write_result.err().unwrap()).into());
}
// Step 5: Change memory protection to executable
let mut old_protect: PAGE_PROTECTION_FLAGS = PAGE_PROTECTION_FLAGS(0);
let protect_result = VirtualProtect(
mem,
size,
PAGE_EXECUTE_READWRITE,
&mut old_protect,
);
if protect_result.is_err() {
VirtualFree(mem, 0, MEM_RELEASE);
CloseHandle(process_info.hProcess);
CloseHandle(process_info.hThread);
return Err(format!("Failed to change memory protection: {}", protect_result.err().unwrap()).into());
}
// Step 6: Create a remote thread to execute the code
let thread_handle = CreateRemoteThread(
process_info.hProcess,
*ptr::null_mut(),
0,
Some(std::mem::transmute(mem as *const ())),
*ptr::null_mut(),
0,
*ptr::null_mut(),
);
if thread_handle.is_err() {
VirtualFree(mem, 0, MEM_RELEASE).expect("Virtual Free did not work");
CloseHandle(process_info.hProcess).expect("Close handle process did not work");
CloseHandle(process_info.hThread).expect("Close handle thread did not work");
return Err(format!("Failed to create remote thread: {}", thread_handle.err().unwrap()).into());
}
let thread_handle = thread_handle.unwrap();
// Wait for the thread to finish
WaitForSingleObject(thread_handle, INFINITE);
// Free the allocated memory
VirtualFree(mem, 0, MEM_RELEASE).expect("Virtual free for final thing did not work");
// Clean up
CloseHandle(thread_handle).expect("Final Close Handle did not work");
CloseHandle(process_info.hProcess).expect("Final Close Handle for process did not work");
CloseHandle(process_info.hThread).expect("Final Close Handle for thread did not work");
Ok(())
}
}
fn main() {
match execute_file("C:\\Users\\Kris\\Desktop\\windows_rust_bytes\\decrypted.bin") {
Ok(_) => println!("File executed successfully."),
Err(e) => eprintln!("Error executing file: {}", e),
}
}