dll_syringe/process/
borrowed.rs1use std::{
2 borrow::Cow,
3 cmp,
4 hash::{Hash, Hasher},
5 io,
6 mem::{self, MaybeUninit},
7 os::windows::{
8 prelude::{AsHandle, AsRawHandle, BorrowedHandle, FromRawHandle},
9 raw::HANDLE,
10 },
11 path::Path,
12 time::Duration,
13};
14
15use winapi::{
16 shared::{
17 minwindef::{FALSE, HMODULE},
18 winerror::ERROR_PARTIAL_COPY,
19 },
20 um::{
21 handleapi::DuplicateHandle,
22 processthreadsapi::GetCurrentProcess,
23 psapi::{EnumProcessModulesEx, LIST_MODULES_ALL},
24 winnt::DUPLICATE_SAME_ACCESS,
25 },
26};
27
28use crate::{
29 process::{ModuleHandle, OwnedProcess, Process, ProcessModule},
30 utils::{retry_faillable_until_some_with_timeout, ArrayOrVecBuf},
31};
32
33#[repr(transparent)]
44#[derive(Debug, Clone, Copy)]
45pub struct BorrowedProcess<'a>(BorrowedHandle<'a>);
46
47unsafe impl Send for BorrowedProcess<'_> {}
48unsafe impl Sync for BorrowedProcess<'_> {}
49
50impl AsRawHandle for BorrowedProcess<'_> {
51 fn as_raw_handle(&self) -> HANDLE {
52 self.0.as_raw_handle()
53 }
54}
55
56impl AsHandle for BorrowedProcess<'_> {
57 fn as_handle(&self) -> BorrowedHandle<'_> {
58 self.0.as_handle()
59 }
60}
61
62impl<'a, 'b> PartialEq<BorrowedProcess<'a>> for BorrowedProcess<'b> {
63 fn eq(&self, other: &BorrowedProcess<'a>) -> bool {
64 self.as_raw_handle() == other.as_raw_handle()
67 || self.pid().map_or(0, |v| v.get()) == other.pid().map_or(0, |v| v.get())
68 }
69}
70
71impl PartialEq<OwnedProcess> for BorrowedProcess<'_> {
72 fn eq(&self, other: &OwnedProcess) -> bool {
73 self == &other.borrowed()
74 }
75}
76
77impl PartialEq<BorrowedProcess<'_>> for OwnedProcess {
78 fn eq(&self, other: &BorrowedProcess<'_>) -> bool {
79 &self.borrowed() == other
80 }
81}
82
83impl Eq for BorrowedProcess<'_> {}
84
85impl Hash for BorrowedProcess<'_> {
86 fn hash<H: Hasher>(&self, state: &mut H) {
87 self.as_raw_handle().hash(state);
88 }
89}
90
91impl<'a> From<&'a OwnedProcess> for BorrowedProcess<'a> {
92 fn from(process: &'a OwnedProcess) -> Self {
93 process.borrowed()
94 }
95}
96
97impl<'a> Process for BorrowedProcess<'a> {
98 type Handle = BorrowedHandle<'a>;
99
100 fn borrowed(&self) -> BorrowedProcess<'a> {
101 *self
102 }
103
104 fn into_handle(self) -> Self::Handle {
105 self.0
106 }
107
108 fn try_clone(&self) -> Result<Self, io::Error> {
109 Ok(*self)
110 }
111
112 unsafe fn from_handle_unchecked(handle: Self::Handle) -> Self {
113 Self(handle)
114 }
115
116 fn current_handle() -> Self::Handle {
117 unsafe { BorrowedHandle::borrow_raw(Self::raw_current_handle()) }
118 }
119
120 fn find_module_by_name(
121 &self,
122 module_name: impl AsRef<Path>,
123 ) -> Result<Option<ProcessModule<BorrowedProcess<'a>>>, io::Error> {
124 let target_module_name = module_name.as_ref();
125
126 let target_module_name = if target_module_name.extension().is_none() {
128 Cow::Owned(target_module_name.with_extension("dll").into_os_string())
129 } else {
130 Cow::Borrowed(target_module_name.as_os_str())
131 };
132
133 let modules = self.module_handles()?;
134
135 for module_handle in modules {
136 let module = unsafe { ProcessModule::new_unchecked(module_handle, *self) };
137 let module_name = module.base_name()?;
138
139 if module_name.eq_ignore_ascii_case(&target_module_name) {
140 return Ok(Some(module));
141 }
142 }
143
144 Ok(None)
145 }
146
147 fn find_module_by_path(
148 &self,
149 module_path: impl AsRef<Path>,
150 ) -> Result<Option<ProcessModule<BorrowedProcess<'a>>>, io::Error> {
151 let target_module_path = module_path.as_ref();
152
153 let target_module_path = if target_module_path.extension().is_none() {
155 Cow::Owned(target_module_path.with_extension("dll").into_os_string())
156 } else {
157 Cow::Borrowed(target_module_path.as_os_str())
158 };
159
160 let target_module_handle = same_file::Handle::from_path(&target_module_path)?;
161
162 let modules = self.module_handles()?;
163
164 for module_handle in modules {
165 let module = unsafe { ProcessModule::new_unchecked(module_handle, *self) };
166 let module_path = module.path()?.into_os_string();
167
168 match same_file::Handle::from_path(&module_path) {
169 Ok(module_handle) => {
170 if module_handle == target_module_handle {
171 return Ok(Some(module));
172 }
173 }
174 Err(_) => {
175 if target_module_path.eq_ignore_ascii_case(&module_path) {
176 return Ok(Some(module));
177 }
178 }
179 }
180 }
181
182 Ok(None)
183 }
184
185 fn wait_for_module_by_name(
186 &self,
187 module_name: impl AsRef<Path>,
188 timeout: Duration,
189 ) -> Result<Option<ProcessModule<BorrowedProcess<'a>>>, io::Error> {
190 retry_faillable_until_some_with_timeout(
191 || self.find_module_by_name(module_name.as_ref()),
192 timeout,
193 )
194 }
195
196 fn wait_for_module_by_path(
197 &self,
198 module_path: impl AsRef<Path>,
199 timeout: Duration,
200 ) -> Result<Option<ProcessModule<BorrowedProcess<'a>>>, io::Error> {
201 retry_faillable_until_some_with_timeout(
202 || self.find_module_by_path(module_path.as_ref()),
203 timeout,
204 )
205 }
206}
207
208impl<'a> BorrowedProcess<'a> {
209 pub fn try_to_owned(&self) -> Result<OwnedProcess, io::Error> {
211 let raw_handle = self.as_raw_handle();
212 let process = unsafe { GetCurrentProcess() };
213 let mut new_handle = MaybeUninit::uninit();
214 let result = unsafe {
215 DuplicateHandle(
216 process,
217 raw_handle.cast(),
218 process,
219 new_handle.as_mut_ptr(),
220 0,
221 FALSE,
222 DUPLICATE_SAME_ACCESS,
223 )
224 };
225 if result == 0 {
226 return Err(io::Error::last_os_error());
227 }
228 Ok(unsafe { OwnedProcess::from_raw_handle(new_handle.assume_init().cast()) })
229 }
230
231 pub fn module_handles(&self) -> Result<impl ExactSizeIterator<Item = ModuleHandle>, io::Error> {
237 let mut module_buf = ArrayOrVecBuf::<ModuleHandle, 1024>::new_uninit_array();
238 const HANDLE_SIZE: u32 = mem::size_of::<HMODULE>() as _;
239 let mut module_buf_byte_size = HANDLE_SIZE * module_buf.capacity() as u32;
240 let mut bytes_needed_new = MaybeUninit::uninit();
241 loop {
242 let result = unsafe {
243 EnumProcessModulesEx(
244 self.as_raw_handle().cast(),
245 module_buf.as_mut_ptr(),
246 module_buf_byte_size,
247 bytes_needed_new.as_mut_ptr(),
248 LIST_MODULES_ALL,
249 )
250 };
251 if result == 0 {
252 let err = io::Error::last_os_error();
253 if err.raw_os_error() == Some(ERROR_PARTIAL_COPY as _) && self.is_alive() {
254 continue;
255 }
256 return Err(err);
257 }
258
259 break;
260 }
261
262 let mut bytes_needed = unsafe { bytes_needed_new.assume_init() };
263
264 let modules = if bytes_needed <= module_buf_byte_size {
265 let module_buf_len = (bytes_needed / HANDLE_SIZE) as usize;
267 unsafe { module_buf.set_len(module_buf_len) };
268 module_buf
269 } else {
270 let mut module_buf_vec = Vec::new();
272
273 loop {
278 module_buf_byte_size =
279 cmp::max(bytes_needed, module_buf_byte_size.saturating_mul(2));
280 let mut module_buf_len = (module_buf_byte_size / HANDLE_SIZE) as usize;
281 if module_buf_len > module_buf_vec.capacity() {
282 module_buf_vec.reserve(module_buf_len - module_buf_vec.capacity());
283 }
284
285 let mut bytes_needed_new = MaybeUninit::uninit();
286 let result = unsafe {
287 EnumProcessModulesEx(
288 self.as_raw_handle().cast(),
289 module_buf_vec.as_mut_ptr(),
290 module_buf_byte_size,
291 bytes_needed_new.as_mut_ptr(),
292 LIST_MODULES_ALL,
293 )
294 };
295 if result == 0 {
296 return Err(io::Error::last_os_error());
297 }
298 bytes_needed = unsafe { bytes_needed_new.assume_init() };
299
300 if bytes_needed <= module_buf_byte_size {
301 module_buf_len = (bytes_needed / HANDLE_SIZE) as usize;
302 unsafe { module_buf_vec.set_len(module_buf_len) };
303 break ArrayOrVecBuf::from_vec(module_buf_vec);
304 }
305 }
306 };
307
308 debug_assert!(modules.iter().all(|module| !module.is_null()));
309
310 Ok(modules.into_iter())
311 }
312}