process_memory_reader/
windows.rs1use crate::{MemoryReadError, Process};
2use std::ffi::OsString;
3use std::mem::{size_of, size_of_val, MaybeUninit};
4use std::os::windows::ffi::OsStringExt;
5use std::ptr;
6use winapi::ctypes::c_void;
7use winapi::shared::minwindef::{DWORD, HMODULE, MAX_PATH, TRUE};
8use winapi::um::handleapi::CloseHandle;
9use winapi::um::memoryapi::ReadProcessMemory;
10use winapi::um::processthreadsapi::OpenProcess;
11use winapi::um::psapi::{EnumProcessModules, GetModuleBaseNameA};
12use winapi::um::tlhelp32::PROCESSENTRY32W;
13use winapi::um::tlhelp32::{
14 CreateToolhelp32Snapshot, Process32FirstW, Process32NextW, TH32CS_SNAPPROCESS,
15};
16use winapi::um::winnt::{PROCESS_QUERY_INFORMATION, PROCESS_VM_READ};
17
18pub fn open_process(pid: u32) -> Option<WindowsProcess> {
22 let handle = unsafe { OpenProcess(PROCESS_VM_READ | PROCESS_QUERY_INFORMATION, 0, pid) };
23
24 if handle.is_null() {
25 return None;
26 }
27
28 Some(WindowsProcess { pid, handle })
29}
30
31pub fn find_by_name(name: &str) -> Vec<WindowsProcess> {
33 let handle = unsafe { CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0) };
34 let mut processes = Vec::new();
35
36 if handle.is_null() {
37 return processes;
38 }
39
40 let mut maybe_entry = MaybeUninit::<PROCESSENTRY32W>::uninit();
41
42 unsafe {
43 ptr::write(
44 &mut (*maybe_entry.as_mut_ptr()).dwSize,
45 size_of::<PROCESSENTRY32W>() as u32,
46 );
47 }
48
49 if unsafe { Process32FirstW(handle, maybe_entry.as_mut_ptr()) } == TRUE {
50 while unsafe { Process32NextW(handle, maybe_entry.as_mut_ptr()) } == TRUE {
51 let entry = unsafe { maybe_entry.assume_init() };
52
53 let process_name_full = &entry.szExeFile;
54 let process_name_length = process_name_full.iter().take_while(|&&c| c != 0).count();
55 let process_name = &OsString::from_wide(&process_name_full[..process_name_length]);
56
57 if process_name != name {
58 continue;
59 }
60
61 open_process(entry.th32ProcessID).map(|process| processes.push(process));
62 }
63 }
64
65 unsafe {
66 CloseHandle(handle);
67 }
68
69 processes
70}
71
72#[derive(Debug)]
73pub struct WindowsProcess {
74 pid: u32,
75 handle: *mut c_void,
76}
77
78impl Process for WindowsProcess {
79 fn base_address(&self, module_name: &str) -> Option<usize> {
80 let mut maybe_hmod = MaybeUninit::<HMODULE>::uninit();
81 let mut maybe_cb_needed = MaybeUninit::<DWORD>::uninit();
82
83 let result = unsafe {
84 EnumProcessModules(
85 self.handle,
86 maybe_hmod.as_mut_ptr(),
87 size_of_val(&maybe_hmod) as u32,
88 maybe_cb_needed.as_mut_ptr(),
89 )
90 };
91
92 if result != TRUE {
93 return None;
94 }
95
96 let mut base_name_vec: Vec<u8> = Vec::with_capacity(MAX_PATH);
97
98 unsafe {
99 let base_name_length = GetModuleBaseNameA(
100 self.handle,
101 maybe_hmod.assume_init(),
102 base_name_vec.as_mut_ptr() as *mut _,
103 base_name_vec.capacity() as u32,
104 );
105
106 base_name_vec.set_len(base_name_length as usize)
107 }
108
109 let base_name = String::from_utf8_lossy(&base_name_vec);
110
111 if base_name.to_lowercase() == module_name.to_lowercase() {
112 unsafe { Some(maybe_hmod.assume_init() as usize) }
113 } else {
114 None
115 }
116 }
117
118 fn read_bytes(&self, address: usize, buffer: &mut [u8]) -> Result<(), MemoryReadError> {
119 let mut maybe_read = MaybeUninit::<usize>::uninit();
120
121 let result = unsafe {
122 ReadProcessMemory(
123 self.handle,
124 address as *const _,
125 buffer.as_mut_ptr() as *mut _,
126 buffer.len(),
127 maybe_read.as_mut_ptr(),
128 )
129 };
130
131 if result != TRUE {
132 return Err(MemoryReadError::InaccessibleMemoryAddress { address });
133 }
134
135 let read = unsafe { maybe_read.assume_init() };
136
137 if read != buffer.len() {
138 return Err(MemoryReadError::LessBytesRead {
139 expected: buffer.len(),
140 actual: read,
141 });
142 }
143
144 Ok(())
145 }
146}
147
148impl Drop for WindowsProcess {
149 fn drop(&mut self) {
150 unsafe {
151 CloseHandle(self.handle);
152 }
153 }
154}