1mod handle;
2mod tlhelp32;
3mod module;
4
5use std::{process::Command, os::windows::process::CommandExt, mem::size_of};
6use regex::bytes::Regex;
7use crate::ProcMemError;
8use handle::Handle;
9use tlhelp32::*;
10pub use module::{Module, Signature};
11
12use winapi::{um::{tlhelp32::{TH32CS_SNAPPROCESS, TH32CS_SNAPMODULE, TH32CS_SNAPMODULE32},
13 winbase::CREATE_NO_WINDOW,
14 memoryapi::{ReadProcessMemory, WriteProcessMemory, VirtualProtect},
15 wow64apiset::IsWow64Process,
16},
17 shared::{minwindef::{FALSE, LPCVOID, LPVOID, BOOL, PBOOL}, basetsd::SIZE_T},
18};
19
20#[derive(Debug, Clone)]
21pub struct Process {
23 pub process_name: String,
24 pub process_id: u32,
26 pub process_base_address: usize,
28 pub process_handle: Handle,
30 pub iswow64: bool,
32}
33
34impl Process {
35 pub fn with_pid(pid: u32) -> Result<Self, ProcMemError> {
42 let h_snap = create_snapshot(TH32CS_SNAPPROCESS, 0)?;
43
44 let mut pe32 = new_pe32w();
45
46 if !process32first(&h_snap, &mut pe32) { return Err(ProcMemError::IterateSnapshotFailure); }
47
48 loop {
49 if pid.eq(&pe32.th32ProcessID) {
50 let process_name = String::from_utf16_lossy(&pe32.szExeFile).trim_end_matches('\u{0}').to_string();
51
52 let mut proc = Process {
53 process_name: String::from(&process_name),
54 process_id: pid,
55 process_base_address: 0,
56 process_handle: Handle::read_write(pid)?,
57 iswow64: false,
58 };
59
60 proc.process_base_address = proc.module(&process_name)?.base_address();
61 proc.iswow64 = proc.iswow64();
62
63 return Ok(proc);
64 }
65
66 if !process32next(&h_snap, &mut pe32) { break; }
67 }
68 Err(ProcMemError::ProcessNotFound)
69 }
70
71
72 pub fn with_name(name: &str) -> Result<Self, ProcMemError> {
79 let h_snap = create_snapshot(TH32CS_SNAPPROCESS, 0)?;
80
81 let mut pe32 = new_pe32w();
82
83 if !process32first(&h_snap, &mut pe32) { return Err(ProcMemError::IterateSnapshotFailure); }
84
85 loop {
86 let process_name = String::from_utf16_lossy(&pe32.szExeFile).trim_end_matches('\u{0}').to_string();
87 if process_name.eq(&name) {
88 let mut proc = Process {
89 process_name: String::from(&process_name),
90 process_id: pe32.th32ProcessID,
91 process_base_address: 0,
92 process_handle: Handle::read_write(pe32.th32ProcessID)?,
93 iswow64: false,
94 };
95
96 proc.process_base_address = proc.module(&process_name)?.base_address();
97 proc.iswow64 = proc.iswow64();
98
99 return Ok(proc);
100 }
101
102 if !process32next(&h_snap, &mut pe32) { break; }
103 }
104 Err(ProcMemError::ProcessNotFound)
105 }
106
107
108 pub fn all_with_name(name: &str) -> Result<Vec<Process>, ProcMemError> {
115 let mut results: Vec<Process> = Vec::new();
116
117 let h_snap = create_snapshot(TH32CS_SNAPPROCESS, 0)?;
118
119 let mut pe32 = new_pe32w();
120
121 if !process32first(&h_snap, &mut pe32) { return Err(ProcMemError::IterateSnapshotFailure); }
122
123 loop {
124 let process_name = String::from_utf16_lossy(&pe32.szExeFile).trim_end_matches('\u{0}').to_string();
125 if process_name.eq(&name) {
126 let mut proc = Process {
127 process_name: String::from(&process_name),
128 process_id: pe32.th32ProcessID,
129 process_base_address: 0,
130 process_handle: Handle::read_write(pe32.th32ProcessID)?,
131 iswow64: false,
132 };
133
134 proc.process_base_address = proc.module(&process_name)?.base_address();
135 proc.iswow64 = proc.iswow64();
136
137 results.push(proc);
138 }
139
140 if !process32next(&h_snap, &mut pe32) { break; }
141 }
142
143 match results.is_empty() {
144 true => return Err(ProcMemError::ProcessNotFound),
145 false => return Ok(results)
146 }
147 }
148
149
150 pub fn module(&self, name: &str) -> Result<Module, ProcMemError> {
158 let h_snap = create_snapshot(TH32CS_SNAPMODULE | TH32CS_SNAPMODULE32, *self.pid())?;
159
160 let mut me32 = new_me32w();
161
162 if !module32first(&h_snap, &mut me32) { return Err(ProcMemError::IterateSnapshotFailure); }
163
164 loop {
165 let module_name = String::from_utf16_lossy(&me32.szModule).trim_end_matches('\u{0}').to_string();
166
167 if module_name.eq(name) {
168 let module_path = String::from_utf16_lossy(&me32.szExePath).trim_end_matches('\u{0}').to_string();
169 return Ok(Module::new(
170 module_name,
171 module_path,
172 *self.pid(),
173 me32.modBaseAddr as usize,
174 me32.modBaseSize as usize,
175 &self,
176 ));
177 }
178
179 if !module32next(&h_snap, &mut me32) { break; }
180 }
181 Err(ProcMemError::ModuleNotFound)
182 }
183
184 pub fn modules(&self) -> Result<Vec<Module>, ProcMemError> {
192 let h_snap = create_snapshot(TH32CS_SNAPMODULE | TH32CS_SNAPMODULE32, *self.pid())?;
193
194 let mut me32 = new_me32w();
195
196 if !module32first(&h_snap, &mut me32) {
197 return Err(ProcMemError::IterateSnapshotFailure);
198 }
199
200 let mut modules = Vec::new();
201
202 loop {
203 let module_name = String::from_utf16_lossy(&me32.szModule).trim_end_matches('\u{0}').to_string();
204
205 let module_path = String::from_utf16_lossy(&me32.szExePath).trim_end_matches('\u{0}').to_string();
206
207 modules.push(Module::new(
208 module_name,
209 module_path,
210 *self.pid(),
211 me32.modBaseAddr as usize,
212 me32.modBaseSize as usize,
213 &self,
214 ));
215
216 if !module32next(&h_snap, &mut me32) { break; }
217 }
218
219 Ok(modules)
220 }
221
222 pub fn kill(&self) -> bool {
230 let output = Command::new("taskkill.exe").arg("/PID").arg(&self.process_id.to_string()).arg("/F").creation_flags(CREATE_NO_WINDOW).output().expect("");
231
232 if output.status.success() {
233 println!("Process with PID {} was terminated", &self.process_id);
234 true
235 } else {
236 println!(
237 "Error killing process with PID {}: {}",
238 &self.process_id,
239 String::from_utf8_lossy(&output.stderr)
240 );
241 false
242 }
243 }
244
245
246 pub fn read_mem<T: Default>(&self, address: usize) -> Result<T, ProcMemError> {
255 let mut out: T = Default::default();
256
257 unsafe {
258 return if ReadProcessMemory(
259 *self.process_handle,
260 address as *const _,
261 &mut out as *mut T as *mut _,
262 std::mem::size_of::<T>(),
263 std::ptr::null_mut::<SIZE_T>(),
264 ) == FALSE {
265 println!("ReadProcessMemory failed. Error: {:?}", std::io::Error::last_os_error());
266 return Err(ProcMemError::ReadMemoryError);
267 } else { Ok(out) };
268 }
269 }
270
271 pub fn read_mem_chain<T: Default>(&self, mut chain: Vec<usize>) -> Result<T, ProcMemError> {
282 let mut address = chain.remove(0);
283
284 while chain.len() != 1 {
285 address += chain.remove(0);
286 address = if self.iswow64 {
287 self.read_mem::<u32>(address)? as usize
288 } else {
289 self.read_mem::<u64>(address)? as usize
290 }
291 }
292
293 let ret = self.read_mem::<T>(address + chain.remove(0))?;
294
295 return Ok(ret);
296 }
297
298
299 pub fn read_ptr_chain(&self, mut chain: Vec<usize>) -> Result<usize, ProcMemError> {
310 let mut address = chain.remove(0);
311
312
313 while chain.len() != 1 {
314 address += chain.remove(0);
315 address = if self.iswow64 {
316 self.read_mem::<u32>(address)? as usize
317 } else {
318 self.read_mem::<u64>(address)? as usize
319 }
320 }
321
322 return Ok(address + chain.remove(0));
323 }
324
325
326 pub fn write_mem<T: Default>(&self, address: usize, mut value: T) -> bool {
336 unsafe {
337 WriteProcessMemory(
338 *self.process_handle,
339 address as *mut _,
340 &mut value as *mut T as *mut _,
341 std::mem::size_of::<T>(),
342 std::ptr::null_mut::<SIZE_T>(),
343 ) != FALSE
344 }
345 }
346
347 pub fn write_bytes(&self, address: usize, buf: *mut u8, size: usize) -> bool {
357 unsafe {
358 WriteProcessMemory(
359 *self.process_handle,
360 address as *mut _,
361 buf as *mut _,
362 size as SIZE_T,
363 std::ptr::null_mut::<SIZE_T>(),
364 ) != FALSE
365 }
366 }
367
368 pub fn read_ptr<T: Copy>(&self, buf: *mut T, address: usize) -> bool {
383 unsafe {
384 ReadProcessMemory(
385 *self.process_handle,
386 address as LPCVOID,
387 buf as *mut T as LPVOID,
388 std::mem::size_of::<T>() as SIZE_T,
389 std::ptr::null_mut::<SIZE_T>(),
390 ) != FALSE
391 }
392 }
393
394 pub fn read_bytes(&self, address: usize, buf: *mut u8, size: usize) -> bool {
409 unsafe {
410 ReadProcessMemory(
411 *self.process_handle,
412 address as LPCVOID,
413 buf as LPVOID,
414 size as SIZE_T,
415 std::ptr::null_mut::<SIZE_T>(),
416 ) != FALSE
417 }
418 }
419
420 pub fn name(&self) -> &str {
422 &self.process_name
423 }
424 pub fn pid(&self) -> &u32 {
426 &self.process_id
427 }
428 pub fn iswow64(&self) -> bool {
430 let mut tmp: BOOL = 0;
431 unsafe { IsWow64Process(*self.process_handle, &mut tmp as PBOOL) };
432 match tmp {
433 FALSE => false,
434 _ => true
435 }
436 }
437
438 pub fn protect_mem(&self, address: usize, size: usize, new_protect: u32, old_protect: *mut u32) -> bool {
440 let mut _result: BOOL = FALSE;
441 unsafe {
442 _result = VirtualProtect(address as LPVOID, size, new_protect, old_protect);
443 }
444 match _result {
445 FALSE => false,
446 _ => true
447 }
448 }
449
450 fn read_module(&self, address: usize, msize: usize) -> Result<Vec<u8>, ProcMemError> {
451 let mut out = vec![0u8; msize];
452 let out_ptr = out.as_mut_ptr();
453 unsafe {
454 if ReadProcessMemory(
455 *self.process_handle,
456 address as LPCVOID,
457 out_ptr as LPVOID,
458 size_of::<u8>() as SIZE_T * msize,
459 std::ptr::null_mut::<SIZE_T>(),
460 ) == FALSE {
461 Err(ProcMemError::ReadMemoryError)
462 } else {
463 Ok(out)
464 }
465 }
466 }
467
468 fn generate_regex(raw: &str) -> Option<Regex> {
469 let mut res = raw
470 .to_string()
471 .split_whitespace()
472 .map(|x| match &x {
473 &"?" => ".".to_string(),
474 x => format!("\\x{}", x),
475 })
476 .collect::<Vec<_>>()
477 .join("");
478 res.insert_str(0, "(?s-u)");
479 Regex::new(&res).ok()
480 }
481
482 pub fn find_pattern<T: Default>(&self, pattern: &str) -> Result<usize, ProcMemError> {
483 let size = ::std::mem::size_of::<T>();
484 let mut position: usize = 0;
485
486 while position < u32::MAX as usize {
487 let chunk: T = self.read_mem(position)
489 .unwrap_or_else(|_| T::default());
490 let data: &[u8] = unsafe {
491 std::slice::from_raw_parts(
492 &chunk as *const T as *const u8,
493 size,
494 )
495 };
496
497 if let Some(offset) = Self::generate_regex(pattern)
498 .and_then(|r| r.find(data))
499 .and_then(|m| Some(m.start())) {
500 return Ok(position + offset);
501 }
502
503 position += size;
504 }
505
506 Err(ProcMemError::SignatureNotFound)
507 }
508
509 pub fn find_signature<T: Default>(&self, sig: &Signature) -> Result<usize, ProcMemError> {
510 let mut addr = self.find_pattern::<T>(&sig.pattern)?;
511
512 for (_i,o) in sig.offsets.iter().enumerate() {
513 let pos = (addr as isize).wrapping_add(*o) as usize;
514 let raw: T = self.read_mem(pos)?;
515 let tmp = if self.iswow64 {
516 let data: u32 = unsafe {*((&raw as *const T as *const u32))};
517 data as usize
518 } else {
519 let data: u64 = unsafe {*((&raw as *const T as *const u64))};
520 data as usize
521 };
522 addr = tmp;
523 }
524
525 addr = (addr as isize).wrapping_add(sig.extra) as usize;
526
527 Ok(addr)
528 }
529}
530
531unsafe impl Send for Process {}
532unsafe impl Sync for Process {}