memory_rs/external/
process.rs

1use std::ffi::{c_void, CStr};
2use std::io::Error;
3
4use windows_sys::Win32::Foundation::{CloseHandle, HANDLE, INVALID_HANDLE_VALUE};
5use windows_sys::Win32::System::Diagnostics::Debug::{ReadProcessMemory, WriteProcessMemory};
6use windows_sys::Win32::System::Diagnostics::ToolHelp::{
7    CreateToolhelp32Snapshot, Module32First, Module32Next, Process32First, Process32Next,
8    MODULEENTRY32, PROCESSENTRY32, TH32CS_SNAPMODULE, TH32CS_SNAPMODULE32, TH32CS_SNAPPROCESS,
9};
10use windows_sys::Win32::System::Threading::{OpenProcess, PROCESS_ALL_ACCESS};
11
12pub struct Process {
13    pub h_process: HANDLE,
14    pub module_base_address: usize,
15}
16
17impl Process {
18    pub fn new(process_name: &str) -> Result<Process, Error> {
19        let process_id = get_process_id(process_name)?;
20        let module_base_address = get_module_base(process_id, process_name)?;
21
22        let h_process = unsafe { OpenProcess(PROCESS_ALL_ACCESS, false as i32, process_id) };
23
24        if h_process == 0 {
25            return Err(Error::last_os_error());
26        }
27
28        Ok(Process {
29            h_process,
30            module_base_address,
31        })
32    }
33
34    /// Writes an array of bytes (as vectors) into the desired address.
35    /// It can take relative or absolute values.
36    pub fn write_aob(&self, ptr: usize, data: &[u8], absolute: bool) {
37        let addr = if absolute {
38            ptr as _
39        } else {
40            self.module_base_address + ptr
41        };
42
43        crate::external::memory::write_aob(self.h_process, addr as _, &data);
44    }
45
46    /// Writes `n` nops into the desired address
47    /// It can take relative or absolute values.
48    pub fn write_nops(&self, ptr: usize, n: usize, absolute: bool) {
49        let addr = if absolute {
50            ptr as _
51        } else {
52            self.module_base_address + ptr
53        };
54
55        crate::external::memory::write_nops(self.h_process, addr as _, n);
56    }
57
58    /// Reads `n` bytes from the desired address
59    /// It can take relative or absolute values.
60    pub fn get_aob(&self, ptr: usize, n: usize, absolute: bool) -> Vec<u8> {
61        let addr = if absolute {
62            ptr as _
63        } else {
64            self.module_base_address + ptr
65        };
66
67        let output: Vec<u8> = crate::external::memory::get_aob(self.h_process, addr as _, n);
68
69        output
70    }
71
72    // TODO: Move this function out of process because it should be in
73    // memory/mod.rs.
74    pub fn read_value<OutputType>(&self, ptr: usize, absolute: bool) -> OutputType {
75        let addr = if absolute {
76            ptr as _
77        } else {
78            self.module_base_address + ptr
79        };
80
81        let mut buffer: OutputType = unsafe { std::mem::zeroed() };
82        let s_buffer: usize = std::mem::size_of::<OutputType>();
83        let mut read: usize = 0;
84
85        unsafe {
86            ReadProcessMemory(
87                self.h_process,
88                addr as *const c_void,
89                &mut buffer as *mut OutputType as *mut c_void,
90                s_buffer,
91                &mut read,
92            );
93        };
94
95        assert_eq!(read, s_buffer);
96        buffer
97    }
98
99    pub fn write_value<InputType>(&self, ptr: usize, output: InputType, absolute: bool) {
100        let addr = if absolute {
101            ptr
102        } else {
103            self.module_base_address + ptr
104        };
105
106        let s: usize = std::mem::size_of::<InputType>();
107        let mut written: usize = 0;
108
109        unsafe {
110            WriteProcessMemory(
111                self.h_process,
112                addr as *const c_void,
113                (&output as *const InputType) as *mut c_void,
114                s,
115                &mut written,
116            );
117        };
118
119        assert!(written != 0);
120    }
121
122    /// Inject an an ASM function which requires the labels start and
123    /// end as an input, and an entry point where the position will
124    /// be injected.
125    /// # Safety
126    /// This function is highly unsafe. It can fails for so many reasons
127    /// that the user should be aware when using it. The function
128    /// maybe could not find a code cave, it could not write the
129    /// bytes correctly, or it could just simply fail because OS reasons.
130    pub unsafe fn inject_shellcode(
131        &self,
132        entry_point: *const u32,
133        instruction_size: usize,
134        f_start: *const u8,
135        f_end: *const u8,
136    ) -> *const c_void {
137        crate::external::memory::inject_shellcode(
138            self.h_process,
139            self.module_base_address as _,
140            entry_point as _,
141            instruction_size,
142            f_start,
143            f_end,
144        )
145    }
146
147    // pub fn read_string_array(
148    //     &self,
149    //     address: *const u32,
150    //     starting_index: usize,
151    //     ending: &[u8],
152    // ) -> Vec<(usize, String)> {
153    //     let mut c_address = address;
154
155    //     let mut data: Vec<(usize, String)> = vec![];
156
157    //     let mut c_index = starting_index;
158
159    //     let mut c_string = String::from("");
160    //     loop {
161    //         let current_read: Vec<u8> = self.get_aob(c_address, 2, true);
162
163    //         if current_read[..] == *ending {
164    //             break;
165    //         }
166    //         if current_read[0] == 0x00 {
167    //             data.push((c_index, c_string));
168    //             c_string = String::from("");
169    //             c_index += 1;
170    //             c_address += 1;
171    //             continue;
172    //         }
173
174    //         c_string.push(current_read[0] as char);
175    //         c_address += 1;
176    //     }
177
178    //     data
179    // }
180}
181
182pub fn get_process_id(process_name: &str) -> Result<u32, Error> {
183    let mut process_id: u32 = 0;
184    let h_snap = unsafe { CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0) };
185
186    if h_snap == INVALID_HANDLE_VALUE {
187        return Err(Error::last_os_error());
188    }
189
190    let mut process_entry: PROCESSENTRY32 = unsafe { std::mem::zeroed() };
191    process_entry.dwSize = std::mem::size_of::<PROCESSENTRY32> as _;
192
193    unsafe {
194        if Process32First(h_snap, &mut process_entry) == 1 {
195            process_id = loop {
196                let current_name = CStr::from_ptr(process_entry.szExeFile.as_ptr() as _)
197                    .to_str()
198                    .expect("No string found");
199
200                if current_name == process_name {
201                    break process_entry.th32ProcessID;
202                }
203
204                if Process32Next(h_snap, &mut process_entry) == 0 {
205                    break 0;
206                }
207            }
208        }
209
210        CloseHandle(h_snap);
211    }
212
213    if process_id == 0 {
214        return Err(Error::last_os_error());
215    }
216
217    Ok(process_id)
218}
219
220pub fn get_module_base(process_id: u32, module_name: &str) -> Result<usize, Error> {
221    let mut module_base_address = 0;
222    let h_snap =
223        unsafe { CreateToolhelp32Snapshot(TH32CS_SNAPMODULE | TH32CS_SNAPMODULE32, process_id) };
224
225    if h_snap == INVALID_HANDLE_VALUE {
226        return Err(Error::last_os_error());
227    }
228
229    let mut module_entry: MODULEENTRY32 = unsafe { std::mem::zeroed() };
230    module_entry.dwSize = std::mem::size_of::<MODULEENTRY32> as _;
231
232    unsafe {
233        if Module32First(h_snap, &mut module_entry) != 0 {
234            module_base_address = loop {
235                let current_name = CStr::from_ptr(module_entry.szModule.as_ptr() as _)
236                    .to_str()
237                    .expect("No string found");
238
239                if current_name == module_name {
240                    break module_entry.modBaseAddr as usize;
241                }
242
243                if Module32Next(h_snap, &mut module_entry) == 0 {
244                    break 0;
245                }
246            }
247        }
248
249        CloseHandle(h_snap);
250    }
251
252    if module_base_address == 0 {
253        return Err(Error::last_os_error());
254    }
255
256    Ok(module_base_address)
257}