diff --git a/Cargo.toml b/Cargo.toml index b86b0c3..0a2d8e4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,7 +16,7 @@ [package] name = "mem-rs" -version = "0.1.3" +version = "0.1.4" edition = "2021" readme = "README.md" homepage = "https://github.com/FrankvdStam/mem-rs" @@ -30,7 +30,7 @@ description = "pattern scanning and abstraction for pointers in memory of runnin [dependencies] [dependencies.windows] -version = "0.42.0" +version = "0.56.0" features = [ "Win32_Foundation", "Win32_System_Memory", diff --git a/examples/dsr.rs b/examples/dsr.rs index f88cd53..d38e90c 100644 --- a/examples/dsr.rs +++ b/examples/dsr.rs @@ -16,6 +16,7 @@ use std::thread::sleep; use std::time::Duration; +use mem_rs::helpers::{get_w32str_from_str, vec_u16_to_u8}; use mem_rs::prelude::*; struct Ds1 @@ -61,15 +62,34 @@ impl Ds1 } Ok(()) } + + #[allow(dead_code)] + pub fn inject_soulmemory_rs(&self) + { + //self.process.inject_dll(r#"C:\soulmemory\soulmemory_rs.dll"#); + //self.process.inject_dll(r#"C:\projects\soulmemory-rs\target\x86_64-pc-windows-msvc\release\soulmemory_rs.dll"#); + self.process.inject_dll(r#"C:\projects\soulmemory-rs\target\x86_64-pc-windows-msvc\å\soulmemory_rs.dll"#).expect("TODO: panic message"); + } } fn main() { - //let processes = Process::get_running_process_names(); - //for p in &processes - //{ - // println!("{}", p); - //} + let str = r#"C:\soulmemory\soulmemory_rs.dll"#; + let w32_str = get_w32str_from_str(str); + println!("{:?}", w32_str); + println!("{:?}", vec_u16_to_u8(&w32_str)); + + let alloated_str = String::from(str); + let collected: Vec = alloated_str.encode_utf16().collect(); + println!("{:?}", collected); + unsafe { println!("{:?}", collected.align_to::()); } + + + let processes = Process::get_running_process_names(); + for p in &processes + { + println!("{}", p); + } let mut ds1 = Ds1::new(); @@ -81,17 +101,10 @@ fn main() Err(e) => println!("{}", e) } + //ds1.inject_soulmemory_rs(); + println!("igt: {}", ds1.get_in_game_time_milliseconds()); println!("ai: {}", ds1.get_ai_timer()); sleep(Duration::from_secs(1)); } -} - -#[allow(dead_code)] -fn inject() -{ - let mut process = Process::new("DarkSoulsRemastered.exe"); - process.refresh().unwrap(); - process.inject_dll(r#"C:\projects\soulmemory-rs\target\x86_64-pc-windows-msvc\debug\soulmemory_rs.dll"#); -} - +} \ No newline at end of file diff --git a/src/helpers.rs b/src/helpers.rs index 2d2c493..17746d9 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -14,6 +14,9 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . +use std::path::Path; +use windows::core::{PCSTR, PCWSTR}; + pub fn scan(code: &[u8], pattern: &[Option]) -> Option { if code.len() == 0 @@ -58,4 +61,34 @@ pub fn to_pattern(str: &str) -> Vec> } } return vec; +} + +pub fn vec_u16_to_u8(vec_u16: &Vec) -> Vec +{ + return unsafe { vec_u16.align_to::().1.to_vec() }; +} + +pub fn w32str_to_string(w32str: &Vec) -> String +{ + return w32str.iter().map(|&v| (v & 0xFF) as u8).take_while(|&c| c != 0).map(|c| c as char).collect(); +} + +pub fn get_file_name_from_string(str: &String) -> String +{ + return String::from(Path::new(&str).file_name().unwrap().to_str().unwrap()); +} + +pub fn get_w32str_from_str(str: &str) -> Vec +{ + return str.encode_utf16().collect(); +} +pub fn get_pcwstr_from_str(str: &str) -> PCWSTR +{ + let vec: Vec = str.encode_utf16().collect(); + return PCWSTR(vec.as_ptr()); +} + +pub fn get_pcstr_from_str(str: &str) -> PCSTR +{ + return PCSTR(str.as_ptr()); } \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index eb1fc45..27bf11b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -16,7 +16,7 @@ mod process_data; mod process_module; -mod helpers; +pub mod helpers; pub mod read_write; pub mod process; pub mod pointer; diff --git a/src/process.rs b/src/process.rs deleted file mode 100644 index 522838c..0000000 --- a/src/process.rs +++ /dev/null @@ -1,386 +0,0 @@ -// This file is part of the mem-rs distribution (https://github.com/FrankvdStam/mem-rs). -// Copyright (c) 2022 Frank van der Stam. -// https://github.com/FrankvdStam/mem-rs/blob/main/LICENSE -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 3. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -use std::cell::RefCell; -use std::ffi::c_void; -use std::mem::size_of; -use std::path::Path; -use std::rc::Rc; -use windows::Win32::Foundation::{BOOL, CloseHandle, HANDLE, HINSTANCE, MAX_PATH}; -use windows::Win32::System::Memory::{MEM_COMMIT, MEM_RELEASE, MEM_RESERVE, PAGE_READWRITE, VirtualAllocEx, VirtualFreeEx}; -use windows::Win32::System::ProcessStatus::{K32EnumProcesses, K32EnumProcessModules, K32GetModuleFileNameExA, K32GetModuleInformation, MODULEINFO}; -use windows::Win32::System::Threading::{GetCurrentProcess, GetExitCodeProcess, OpenProcess, PROCESS_QUERY_INFORMATION, PROCESS_VM_OPERATION, PROCESS_VM_READ, PROCESS_VM_WRITE}; -use crate::helpers::{scan, to_pattern}; -use crate::pointer::Pointer; -use crate::process_data::ProcessData; -use crate::process_module::ProcessModule; -use crate::read_write::{BaseReadWrite, ReadWrite}; - -#[link(name = "kernel32")] -extern "stdcall" -{ - fn GetProcAddress(h_module: *const c_void, lp_proc_name: *const u8) -> *const c_void; - fn GetModuleHandleA(lp_module_name: *const u8) -> HINSTANCE; - fn CreateRemoteThread(h_process: *const c_void, lp_thread_attributes: *const c_void, dw_stack_size: u32, lp_start_address: *const c_void, lp_parameter: *const c_void, dw_creation_flags: u32, lp_thread_id: *const c_void) -> *const c_void; - fn WaitForSingleObject(handle: *const c_void, dw_milliseconds: u32) -> u32; -} - -const STILL_ACTIVE: u32 = 259; - - -pub struct Process -{ - process_data: Rc> -} - -impl Process -{ - ///Create a new process where name is the name of the executable - pub fn new(name: &str) -> Self - { - Process - { - process_data: Rc::new(RefCell::new(ProcessData - { - name: String::from(name), - attached: false, - id: 0, - handle: HANDLE::default(), - filename: String::new(), - path: String::new(), - main_module: ProcessModule::default(), - modules: Vec::new(), - })) - } - } - - pub fn is_attached(&self) -> bool {return self.process_data.borrow().attached;} - - pub fn scan_abs(&self, error_name: &str, pattern: &str, scan_offset: usize, pointer_offsets: Vec) -> Result - { - let byte_pattern = to_pattern(pattern); - let scan_result = scan(&self.process_data.borrow().main_module.memory, &byte_pattern); - if scan_result.is_none() - { - return Err(String::from(format!("Scan failed: {}", error_name))); - } - - let mut address = scan_result.unwrap(); - address += self.process_data.borrow().main_module.base_address; - address += scan_offset; - return Ok(Pointer::new(self.process_data.clone(), true, address, pointer_offsets)); - } - - pub fn scan_rel(&self, error_name: &str, pattern: &str, scan_offset: usize, instruction_size: usize, pointer_offsets: Vec) -> Result - { - let byte_pattern = to_pattern(pattern); - let scan_result = scan(&self.process_data.borrow().main_module.memory, &byte_pattern); - if scan_result.is_none() - { - return Err(String::from(format!("Scan failed: {}", error_name))); - } - - let address = scan_result.unwrap(); - let address_value = self.read_u32_rel(Some(address + scan_offset)); - let result = self.process_data.borrow().main_module.base_address + address + instruction_size + address_value as usize; //Relative jump - - return Ok(Pointer::new(self.process_data.clone(), true, result, pointer_offsets)); - } - - pub fn inject_dll(&self, dll_path: &str) - { - let mut temp = dll_path.to_string(); - temp.push('\0'); - let dll_path_null_terminated = temp.as_str(); - - unsafe - { - if self.is_attached() - { - let process_handle = OpenProcess( - windows::Win32::System::Threading::PROCESS_CREATE_THREAD | - windows::Win32::System::Threading::PROCESS_QUERY_INFORMATION | - windows::Win32::System::Threading::PROCESS_VM_OPERATION | - windows::Win32::System::Threading::PROCESS_VM_WRITE | - windows::Win32::System::Threading::PROCESS_VM_READ, false, self.process_data.borrow().id).unwrap(); - - //println!("{:?}", process_handle); - - //Allocate a chunk of memory inside a process and write the path to the dll in this chunk - let allocated_dll_path_str = VirtualAllocEx( - process_handle, - None, - dll_path_null_terminated.len() * size_of::(), - MEM_COMMIT | MEM_RESERVE, - PAGE_READWRITE); - - //println!("{:?}", allocated_dll_path_str as *const ()); - - self.write_memory_abs( - allocated_dll_path_str as usize, - dll_path_null_terminated.as_bytes() - ); - - //Get a ptr to LoadLibraryA via kernel32.dll - //let kernel32_str = "KERNEL32.DLL\0"; - let kernel32_str = "kernel32.dll\0"; - let load_library_a_str = "LoadLibraryA\0"; - - let kernel_32_handle = GetModuleHandleA(kernel32_str.as_ptr()); - let load_library_a = GetProcAddress(kernel_32_handle.0 as *const c_void, load_library_a_str.as_ptr()); - - //Call LoadLibraryA with our allocated and wait for it to return 10 seconds - let thread = CreateRemoteThread( - process_handle.0 as *const c_void, - 0 as *const c_void, - 0, - load_library_a as *const c_void, - allocated_dll_path_str, - 0, - 0 as *const c_void); - WaitForSingleObject(thread, 10000); - - VirtualFreeEx(process_handle, allocated_dll_path_str, 0, MEM_RELEASE); - } - } - } - - - ///Cling to a running process - pub fn refresh(&mut self) -> Result<(), String> - { - unsafe - { - //Check if a previously attached process has exited - let mut lp_exit_code: u32 = 0; - if self.process_data.borrow().attached && (!GetExitCodeProcess(self.process_data.borrow().handle, &mut lp_exit_code).as_bool() || lp_exit_code != STILL_ACTIVE) - { - let mut process_data = self.process_data.borrow_mut(); - - process_data.attached = false; - process_data.id = 0; - process_data.handle = HANDLE::default(); - process_data.filename = String::new(); - process_data.path = String::new(); - process_data.main_module = ProcessModule::default(); - process_data.modules = Vec::new(); - - return Err(String::from("Process exited")); - } - - if self.process_data.borrow().attached - { - return Ok(()); - } - - //Look for a running process with the correct name and attach to it - let mut process_ids = [0u32; 2048]; - let mut out_size = 0; - - if !K32EnumProcesses(process_ids.as_mut_ptr(), (process_ids.len() * size_of::()) as u32, &mut out_size).as_bool() - { - return Err(String::from("Failed to get running processes")); - } - - let count = out_size as usize / std::mem::size_of::(); - for i in 0..count - { - let pid = process_ids[i]; - - match OpenProcess( - PROCESS_QUERY_INFORMATION - | PROCESS_VM_READ - | PROCESS_VM_WRITE - | PROCESS_VM_OPERATION, - BOOL(0), - pid, - ) - { - Ok(handle) => - { - let mut mod_name = [0; windows::Win32::Foundation::MAX_PATH as usize]; - - if K32GetModuleFileNameExA(handle, HINSTANCE(0), &mut mod_name) != 0 - { - let len = mod_name.iter().position(|&r| r == 0).unwrap(); - let path = String::from_utf8(mod_name[0..len].iter().map(|&c| c as u8).collect()).unwrap(); - let filename = String::from(Path::new(&path).file_name().unwrap().to_str().unwrap()); - - //println!("{}", filename); - - if self.process_data.borrow().name.to_lowercase() == filename.to_lowercase() - { - let mut modules = Process::get_process_modules(handle); - - let mut process_data = self.process_data.borrow_mut(); - - process_data.id = pid; - process_data.handle = handle; - process_data.filename = filename; - process_data.path = path; - process_data.attached = true; - process_data.main_module = modules.remove(0); - process_data.main_module.dump_memory(handle); - process_data.modules = modules; - - return Ok(()); - } - } - - CloseHandle(handle); - } - _ => {}, - } - } - return Err(String::from("Process not running")); - } - } - - fn get_process_modules(process_handle: HANDLE) -> Vec - { - unsafe - { - let mut result = Vec::new(); - - //Get amount of hmodules in current process - let mut required_size: u32 = 0; - K32EnumProcessModules(process_handle, 0 as *mut HINSTANCE, 0, &mut required_size); - let size = (required_size / size_of::() as u32) as u32; - - //Get modules - let mut modules: Vec = vec![HINSTANCE(0); size as usize]; - K32EnumProcessModules(process_handle, modules.as_mut_ptr(), required_size.clone(), &mut required_size); - - for i in 0..modules.len() - { - let mut mod_name = [0; MAX_PATH as usize]; - - if K32GetModuleFileNameExA(process_handle, modules[i as usize], &mut mod_name) != 0 - { - let len = mod_name.iter().position(|&r| r == 0).unwrap(); - let file_path = String::from_utf8(mod_name[0..len].iter().map(|&c| c as u8).collect()).unwrap(); - let file_name = Path::new(&file_path).file_name().unwrap().to_os_string().into_string().unwrap(); - - let mut info: MODULEINFO = MODULEINFO - { - lpBaseOfDll: 0 as *mut c_void, - SizeOfImage: 0, - EntryPoint: 0 as *mut c_void, - }; - - if K32GetModuleInformation(process_handle, modules[i as usize], &mut info, size_of::() as u32).as_bool() - { - let module_base = info.lpBaseOfDll as usize; - let module_size = info.SizeOfImage as usize; - result.push(ProcessModule::new(modules[i as usize].0 as usize, file_path, file_name, module_base, module_size)); - } - } - } - return result; - } - } - - pub fn get_current_process_name() -> Result - { - unsafe - { - let handle = GetCurrentProcess(); - let mut mod_name = [0; MAX_PATH as usize]; - if K32GetModuleFileNameExA(handle, HINSTANCE(0), &mut mod_name) != 0 - { - let len = mod_name.iter().position(|&r| r == 0).unwrap(); - let path = String::from_utf8(mod_name[0..len].iter().map(|&c| c as u8).collect()).unwrap(); - let filename = String::from(Path::new(&path).file_name().unwrap().to_str().unwrap()); - return Ok(filename); - } - Err(()) - } - } - - pub fn get_running_process_names() -> Vec - { - unsafe - { - let mut process_names = Vec::new(); - let mut process_ids = [0u32; 2048]; - let mut bytes_needed = 0u32; - K32EnumProcesses(process_ids.as_mut_ptr(), (process_ids.len() * size_of::()) as u32, &mut bytes_needed); - let count = bytes_needed as usize / std::mem::size_of::(); - - for i in 0..count - { - let pid = process_ids[i]; - - let mut mod_name = [0; MAX_PATH as usize]; - - if let Ok(handle) = OpenProcess( - PROCESS_QUERY_INFORMATION - | PROCESS_VM_READ - | PROCESS_VM_WRITE - | PROCESS_VM_OPERATION, - false, - pid, - ) - { - if K32GetModuleFileNameExA(handle, HINSTANCE(0), &mut mod_name) != 0 - { - let len = mod_name.iter().position(|&r| r == 0).unwrap(); - let path = String::from_utf8(mod_name[0..len].iter().map(|&c| c as u8).collect()).unwrap(); - let filename = String::from(Path::new(&path).file_name().unwrap().to_str().unwrap()); - process_names.push(filename); - } - CloseHandle(handle); - } - } - return process_names; - } - } -} - -impl BaseReadWrite for Process -{ - fn read_memory_rel(&self, offset: Option, buffer: &mut [u8]) -> bool - { - let mut address = self.process_data.borrow().main_module.base_address; - if offset.is_some() - { - address += offset.unwrap(); - } - return self.read_with_handle(self.process_data.borrow().handle, address, buffer); - } - - fn write_memory_rel(&self, offset: Option, buffer: &[u8]) -> bool - { - let mut address = self.process_data.borrow().main_module.base_address; - if offset.is_some() - { - address += offset.unwrap(); - } - return self.write_with_handle(self.process_data.borrow().handle, address, buffer); - } - - fn read_memory_abs(&self, address: usize, buffer: &mut [u8]) -> bool - { - return self.read_with_handle(self.process_data.borrow().handle, address, buffer); - } - - fn write_memory_abs(&self, address: usize, buffer: &[u8]) -> bool - { - return self.write_with_handle(self.process_data.borrow().handle, address, buffer); - } -} - -impl ReadWrite for Process{} \ No newline at end of file diff --git a/src/process/inject_dll.rs b/src/process/inject_dll.rs new file mode 100644 index 0000000..43e7180 --- /dev/null +++ b/src/process/inject_dll.rs @@ -0,0 +1,81 @@ +use std::ffi::c_void; +use std::mem::size_of; +use windows::Win32::System::LibraryLoader::{GetModuleHandleW, GetProcAddress}; +use windows::Win32::System::Memory::{MEM_COMMIT, MEM_RELEASE, MEM_RESERVE, PAGE_READWRITE, VirtualAllocEx, VirtualFreeEx}; +use windows::Win32::System::Threading::{CreateRemoteThread, OpenProcess, PROCESS_CREATE_THREAD, PROCESS_QUERY_INFORMATION, PROCESS_VM_OPERATION, PROCESS_VM_READ, PROCESS_VM_WRITE, WaitForSingleObject}; +use crate::helpers::{get_pcstr_from_str, get_pcwstr_from_str, vec_u16_to_u8}; +use crate::prelude::*; + + +impl Process +{ + pub fn inject_dll(&self, dll_path: &str) -> Result<(), String> + { + let mut path_w32_str: Vec = dll_path.encode_utf16().collect(); + path_w32_str.push(0); + + unsafe + { + if self.is_attached() + { + let process_handle_result = OpenProcess( + PROCESS_CREATE_THREAD | + PROCESS_QUERY_INFORMATION | + PROCESS_VM_OPERATION | + PROCESS_VM_WRITE | + PROCESS_VM_READ, false, self.process_data.borrow().id); + + if process_handle_result.is_err() + { + return Err(String::from("process handle invalid")); + } + + let process_handle = process_handle_result.unwrap(); + + //Allocate a chunk of memory inside a process and write the path to the dll in this chunk + let allocated_dll_path_str = VirtualAllocEx( + process_handle, + None, + path_w32_str.len() * size_of::(), + MEM_COMMIT | MEM_RESERVE, + PAGE_READWRITE); + + self.write_memory_abs(allocated_dll_path_str as usize, &vec_u16_to_u8(&path_w32_str)); + + //Get a ptr to LoadLibraryW via kernel32.dll + let kernel32_pcwstr = get_pcwstr_from_str(&"kernel32.dll\0"); + + let kernel_32_handle = GetModuleHandleW(kernel32_pcwstr); + if kernel_32_handle.is_err() + { + return Err(String::from("failed to load module kernel32.dll")); + } + + let load_library_w_pcstr = get_pcstr_from_str(&"LoadLibraryW\0"); + let load_library_w = GetProcAddress(kernel_32_handle.unwrap(), load_library_w_pcstr); + if load_library_w.is_none() + { + return Err(String::from("Failed to find LoadLibraryW")); + } + + let thread = CreateRemoteThread( + process_handle, + None, + 0, + Some(*(&load_library_w.unwrap() as *const _ as *const extern "system" fn(*mut c_void) -> u32)), + Some(allocated_dll_path_str), + 0, + None); + + if thread.is_err() + { + return Err(String::from("Failed to start remote thread")); + } + + let _ = WaitForSingleObject(thread.unwrap(), 10000); + let _ = VirtualFreeEx(process_handle, allocated_dll_path_str, 0, MEM_RELEASE); + } + return Ok(()); + } + } +} \ No newline at end of file diff --git a/src/process/mod.rs b/src/process/mod.rs new file mode 100644 index 0000000..395c248 --- /dev/null +++ b/src/process/mod.rs @@ -0,0 +1,62 @@ +// This file is part of the mem-rs distribution (https://github.com/FrankvdStam/mem-rs). +// Copyright (c) 2022 Frank van der Stam. +// https://github.com/FrankvdStam/mem-rs/blob/main/LICENSE +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 3. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +use std::cell::RefCell; +use std::rc::Rc; + +use windows::Win32::Foundation::HANDLE; + +use crate::process_data::ProcessData; +use crate::process_module::ProcessModule; +mod inject_dll; +mod scanning; +mod read_write; +mod refresh; +mod process_modules; +mod process_name; + +const STILL_ACTIVE: u32 = 259; + + +pub struct Process +{ + process_data: Rc> +} + +impl Process +{ + ///Create a new process where name is the name of the executable + pub fn new(name: &str) -> Self + { + Process + { + process_data: Rc::new(RefCell::new(ProcessData + { + name: String::from(name), + attached: false, + id: 0, + handle: HANDLE::default(), + filename: String::new(), + path: String::new(), + main_module: ProcessModule::default(), + modules: Vec::new(), + })) + } + } + + pub fn is_attached(&self) -> bool {return self.process_data.borrow().attached;} +} + diff --git a/src/process/process_modules.rs b/src/process/process_modules.rs new file mode 100644 index 0000000..1b38eb1 --- /dev/null +++ b/src/process/process_modules.rs @@ -0,0 +1,53 @@ +use std::ffi::c_void; +use std::mem::size_of; +use windows::Win32::Foundation::{HANDLE, HINSTANCE, HMODULE, MAX_PATH}; +use windows::Win32::System::ProcessStatus::{K32EnumProcessModules, K32GetModuleFileNameExW, K32GetModuleInformation, MODULEINFO}; +use crate::helpers::{get_file_name_from_string, w32str_to_string}; +use crate::process::Process; +use crate::process_module::ProcessModule; + +impl Process +{ + pub(crate) fn get_process_modules(process_handle: HANDLE) -> Vec + { + unsafe + { + let mut result = Vec::new(); + + //Get amount of hmodules in current process + let mut required_size: u32 = 0; + let _ = K32EnumProcessModules(process_handle, 0 as *mut HMODULE, 0, &mut required_size); + let size = (required_size / size_of::() as u32) as u32; + + //Get modules + let mut modules: Vec = vec![HMODULE(0); size as usize]; + let _ = K32EnumProcessModules(process_handle, modules.as_mut_ptr(), required_size.clone(), &mut required_size).unwrap(); + + for i in 0..modules.len() + { + let mut mod_name = [0; MAX_PATH as usize]; + + if K32GetModuleFileNameExW(process_handle, modules[i as usize], &mut mod_name) != 0 + { + let file_path = w32str_to_string(&mod_name.to_vec()); + let file_name = get_file_name_from_string(&file_path); + + let mut info: MODULEINFO = MODULEINFO + { + lpBaseOfDll: 0 as *mut c_void, + SizeOfImage: 0, + EntryPoint: 0 as *mut c_void, + }; + + if K32GetModuleInformation(process_handle, modules[i as usize], &mut info, size_of::() as u32).as_bool() + { + let module_base = info.lpBaseOfDll as usize; + let module_size = info.SizeOfImage as usize; + result.push(ProcessModule::new(modules[i as usize].0 as usize, file_path, file_name, module_base, module_size)); + } + } + } + return result; + } + } +} \ No newline at end of file diff --git a/src/process/process_name.rs b/src/process/process_name.rs new file mode 100644 index 0000000..2f38998 --- /dev/null +++ b/src/process/process_name.rs @@ -0,0 +1,63 @@ +use std::mem::size_of; +use windows::Win32::Foundation::{CloseHandle, HINSTANCE, MAX_PATH}; +use windows::Win32::System::ProcessStatus::{K32EnumProcesses, K32GetModuleFileNameExW}; +use windows::Win32::System::Threading::{GetCurrentProcess, OpenProcess, PROCESS_QUERY_INFORMATION, PROCESS_VM_OPERATION, PROCESS_VM_READ, PROCESS_VM_WRITE}; +use crate::helpers::{get_file_name_from_string, w32str_to_string}; +use crate::process::Process; + +impl Process +{ + pub fn get_current_process_name() -> Result + { + unsafe + { + let handle = GetCurrentProcess(); + let mut mod_name = [0; MAX_PATH as usize]; + if K32GetModuleFileNameExW(handle, HINSTANCE(0), &mut mod_name) != 0 + { + let file_path = w32str_to_string(&mod_name.to_vec()); + let file_name = get_file_name_from_string(&file_path); + return Ok(file_name); + } + Err(()) + } + } + + pub fn get_running_process_names() -> Vec + { + unsafe + { + let mut process_names = Vec::new(); + let mut process_ids = [0u32; 2048]; + let mut bytes_needed = 0u32; + let _ = K32EnumProcesses(process_ids.as_mut_ptr(), (process_ids.len() * size_of::()) as u32, &mut bytes_needed); + let count = bytes_needed as usize / std::mem::size_of::(); + + for i in 0..count + { + let pid = process_ids[i]; + + let mut mod_name = [0; MAX_PATH as usize]; + + if let Ok(handle) = OpenProcess( + PROCESS_QUERY_INFORMATION + | PROCESS_VM_READ + | PROCESS_VM_WRITE + | PROCESS_VM_OPERATION, + false, + pid, + ) + { + if K32GetModuleFileNameExW(handle, HINSTANCE(0), &mut mod_name) != 0 + { + let file_path = w32str_to_string(&mod_name.to_vec()); + let file_name = get_file_name_from_string(&file_path); + process_names.push(file_name); + } + let _ = CloseHandle(handle); + } + } + return process_names; + } + } +} \ No newline at end of file diff --git a/src/process/read_write.rs b/src/process/read_write.rs new file mode 100644 index 0000000..92a756e --- /dev/null +++ b/src/process/read_write.rs @@ -0,0 +1,36 @@ +use crate::prelude::{BaseReadWrite, Process, ReadWrite}; + +impl BaseReadWrite for Process +{ + fn read_memory_rel(&self, offset: Option, buffer: &mut [u8]) -> bool + { + let mut address = self.process_data.borrow().main_module.base_address; + if offset.is_some() + { + address += offset.unwrap(); + } + return self.read_with_handle(self.process_data.borrow().handle, address, buffer); + } + + fn write_memory_rel(&self, offset: Option, buffer: &[u8]) -> bool + { + let mut address = self.process_data.borrow().main_module.base_address; + if offset.is_some() + { + address += offset.unwrap(); + } + return self.write_with_handle(self.process_data.borrow().handle, address, buffer); + } + + fn read_memory_abs(&self, address: usize, buffer: &mut [u8]) -> bool + { + return self.read_with_handle(self.process_data.borrow().handle, address, buffer); + } + + fn write_memory_abs(&self, address: usize, buffer: &[u8]) -> bool + { + return self.write_with_handle(self.process_data.borrow().handle, address, buffer); + } +} + +impl ReadWrite for Process{} \ No newline at end of file diff --git a/src/process/refresh.rs b/src/process/refresh.rs new file mode 100644 index 0000000..36fa586 --- /dev/null +++ b/src/process/refresh.rs @@ -0,0 +1,100 @@ +use std::mem::size_of; +use windows::Win32::Foundation::{BOOL, CloseHandle, HANDLE, HINSTANCE}; +use windows::Win32::System::ProcessStatus::{K32EnumProcesses, K32GetModuleFileNameExW}; +use windows::Win32::System::Threading::{GetExitCodeProcess, OpenProcess, PROCESS_QUERY_INFORMATION, PROCESS_VM_OPERATION, PROCESS_VM_READ, PROCESS_VM_WRITE}; +use crate::helpers::{get_file_name_from_string, w32str_to_string}; +use crate::prelude::Process; +use crate::process::STILL_ACTIVE; +use crate::process_module::ProcessModule; + +impl Process +{ + ///Cling to a running process + pub fn refresh(&mut self) -> Result<(), String> + { + unsafe + { + //Check if a previously attached process has exited + let mut lp_exit_code: u32 = 0; + if self.process_data.borrow().attached && (!GetExitCodeProcess(self.process_data.borrow().handle, &mut lp_exit_code).is_ok() || lp_exit_code != STILL_ACTIVE) + { + let mut process_data = self.process_data.borrow_mut(); + + process_data.attached = false; + process_data.id = 0; + process_data.handle = HANDLE::default(); + process_data.filename = String::new(); + process_data.path = String::new(); + process_data.main_module = ProcessModule::default(); + process_data.modules = Vec::new(); + + return Err(String::from("Process exited")); + } + + if self.process_data.borrow().attached + { + return Ok(()); + } + + //Look for a running process with the correct name and attach to it + let mut process_ids = [0u32; 2048]; + let mut out_size = 0; + + if !K32EnumProcesses(process_ids.as_mut_ptr(), (process_ids.len() * size_of::()) as u32, &mut out_size).as_bool() + { + return Err(String::from("Failed to get running processes")); + } + + let count = out_size as usize / std::mem::size_of::(); + for i in 0..count + { + let pid = process_ids[i]; + + match OpenProcess( + PROCESS_QUERY_INFORMATION + | PROCESS_VM_READ + | PROCESS_VM_WRITE + | PROCESS_VM_OPERATION, + BOOL(0), + pid, + ) + { + Ok(handle) => + { + let mut mod_name = [0; windows::Win32::Foundation::MAX_PATH as usize]; + + if K32GetModuleFileNameExW(handle, HINSTANCE(0), &mut mod_name) != 0 + { + let file_path = w32str_to_string(&mod_name.to_vec()); + let file_name = get_file_name_from_string(&file_path); + + //println!("{}", filename); + + if self.process_data.borrow().name.to_lowercase() == file_name.to_lowercase() + { + let mut modules = Process::get_process_modules(handle); + + let mut process_data = self.process_data.borrow_mut(); + + process_data.id = pid; + process_data.handle = handle; + process_data.filename = file_name; + process_data.path = file_path; + process_data.attached = true; + process_data.main_module = modules.remove(0); + process_data.main_module.dump_memory(handle); + process_data.modules = modules; + + return Ok(()); + } + } + + let _ = CloseHandle(handle); + } + _ => {}, + } + } + return Err(String::from("Process not running")); + } + } +} \ No newline at end of file diff --git a/src/process/scanning.rs b/src/process/scanning.rs new file mode 100644 index 0000000..5b38d96 --- /dev/null +++ b/src/process/scanning.rs @@ -0,0 +1,37 @@ +use crate::helpers::{scan, to_pattern}; +use crate::pointer::Pointer; +use crate::prelude::*; + +impl Process +{ + pub fn scan_abs(&self, error_name: &str, pattern: &str, scan_offset: usize, pointer_offsets: Vec) -> Result + { + let byte_pattern = to_pattern(pattern); + let scan_result = scan(&self.process_data.borrow().main_module.memory, &byte_pattern); + if scan_result.is_none() + { + return Err(String::from(format!("Scan failed: {}", error_name))); + } + + let mut address = scan_result.unwrap(); + address += self.process_data.borrow().main_module.base_address; + address += scan_offset; + return Ok(Pointer::new(self.process_data.clone(), true, address, pointer_offsets)); + } + + pub fn scan_rel(&self, error_name: &str, pattern: &str, scan_offset: usize, instruction_size: usize, pointer_offsets: Vec) -> Result + { + let byte_pattern = to_pattern(pattern); + let scan_result = scan(&self.process_data.borrow().main_module.memory, &byte_pattern); + if scan_result.is_none() + { + return Err(String::from(format!("Scan failed: {}", error_name))); + } + + let address = scan_result.unwrap(); + let address_value = self.read_u32_rel(Some(address + scan_offset)); + let result = self.process_data.borrow().main_module.base_address + address + instruction_size + address_value as usize; //Relative jump + + return Ok(Pointer::new(self.process_data.clone(), true, result, pointer_offsets)); + } +} \ No newline at end of file diff --git a/src/process_module.rs b/src/process_module.rs index 7265fda..bec0585 100644 --- a/src/process_module.rs +++ b/src/process_module.rs @@ -59,7 +59,7 @@ impl ProcessModule let mut buffer: Vec = vec![0; self.size]; let mut read_bytes = 0; - if !ReadProcessMemory(process_handle as HANDLE, self.base_address as *mut c_void, buffer.as_mut_ptr() as *mut c_void, buffer.capacity(), Some(&mut read_bytes)).as_bool() + if ReadProcessMemory(process_handle as HANDLE, self.base_address as *mut c_void, buffer.as_mut_ptr() as *mut c_void, buffer.capacity(), Some(&mut read_bytes)).is_err() { return; } diff --git a/src/read_write.rs b/src/read_write.rs index 432221d..e7f992d 100644 --- a/src/read_write.rs +++ b/src/read_write.rs @@ -36,7 +36,7 @@ pub trait BaseReadWrite fn read_with_handle(&self, handle: HANDLE, address: usize, buffer: &mut [u8]) -> bool { let mut read_bytes = 0; - if !unsafe {ReadProcessMemory(handle, address as *mut c_void, buffer.as_mut_ptr() as *mut c_void, buffer.len(), Some(&mut read_bytes)).as_bool() } + if unsafe {ReadProcessMemory(handle, address as *mut c_void, buffer.as_mut_ptr() as *mut c_void, buffer.len(), Some(&mut read_bytes)).is_err() } { return false; } @@ -47,7 +47,7 @@ pub trait BaseReadWrite fn write_with_handle(&self, handle: HANDLE, address: usize, buffer: &[u8]) -> bool { let mut wrote_bytes = 0; - if !unsafe { WriteProcessMemory(handle, address as *mut c_void, buffer.as_ptr() as *mut c_void, buffer.len(), Some(&mut wrote_bytes)).as_bool() } + if unsafe { WriteProcessMemory(handle, address as *mut c_void, buffer.as_ptr() as *mut c_void, buffer.len(), Some(&mut wrote_bytes)).is_err() } { return false; }