windows_erg/process/
modules.rs1use windows::Win32::Foundation::HMODULE;
4use windows::Win32::System::ProcessStatus::{
5 EnumProcessModules, GetModuleBaseNameW, GetModuleFileNameExW, GetModuleInformation, MODULEINFO,
6};
7
8use super::processes::Process;
9use super::types::{ImagePath, ModuleInfo};
10use crate::error::{Error, ProcessError, ProcessOpenError, Result};
11
12impl Process {
13 pub fn modules(&self) -> Result<Vec<ModuleInfo>> {
15 let mut out_modules = Vec::with_capacity(32);
16 let mut work_buffer = Vec::with_capacity(8192);
17 self.modules_with_buffer(&mut out_modules, &mut work_buffer)?;
18 Ok(out_modules)
19 }
20
21 pub fn modules_with_buffer(
27 &self,
28 out_modules: &mut Vec<ModuleInfo>,
29 work_buffer: &mut Vec<u8>,
30 ) -> Result<usize> {
31 self.modules_with_filter_impl(out_modules, work_buffer, |_| true)
32 }
33
34 pub fn modules_with_filter<F>(
47 &self,
48 out_modules: &mut Vec<ModuleInfo>,
49 work_buffer: &mut Vec<u8>,
50 filter: F,
51 ) -> Result<usize>
52 where
53 F: Fn(&ModuleInfo) -> bool,
54 {
55 self.modules_with_filter_impl(out_modules, work_buffer, filter)
56 }
57
58 fn modules_with_filter_impl<F>(
60 &self,
61 out_modules: &mut Vec<ModuleInfo>,
62 work_buffer: &mut Vec<u8>,
63 filter: F,
64 ) -> Result<usize>
65 where
66 F: Fn(&ModuleInfo) -> bool,
67 {
68 out_modules.clear();
69
70 if work_buffer.capacity() < 8192 {
72 work_buffer.reserve(8192 - work_buffer.capacity());
73 }
74 unsafe {
75 work_buffer.set_len(8192);
76 }
77
78 let mut bytes_needed = 0u32;
79
80 unsafe {
82 EnumProcessModules(
83 self.as_raw_handle(),
84 work_buffer.as_mut_ptr() as *mut HMODULE,
85 work_buffer.len() as u32,
86 &mut bytes_needed,
87 )
88 }
89 .map_err(|e| {
90 Error::Process(ProcessError::OpenFailed(ProcessOpenError::with_code(
91 self.id().as_u32(),
92 "Failed to enumerate modules (first call)",
93 e.code().0,
94 )))
95 })?;
96
97 if bytes_needed as usize > work_buffer.len() {
99 work_buffer.clear();
100 if work_buffer.capacity() < bytes_needed as usize {
101 work_buffer.reserve(bytes_needed as usize - work_buffer.capacity());
102 }
103 unsafe {
104 work_buffer.set_len(bytes_needed as usize);
105 }
106 }
107
108 unsafe {
110 EnumProcessModules(
111 self.as_raw_handle(),
112 work_buffer.as_mut_ptr() as *mut HMODULE,
113 work_buffer.len() as u32,
114 &mut bytes_needed,
115 )
116 }
117 .map_err(|e| {
118 Error::Process(ProcessError::OpenFailed(ProcessOpenError::with_code(
119 self.id().as_u32(),
120 "Failed to enumerate modules (second call)",
121 e.code().0,
122 )))
123 })?;
124
125 let module_count = bytes_needed as usize / std::mem::size_of::<HMODULE>();
126 let module_handles = unsafe {
127 std::slice::from_raw_parts(work_buffer.as_ptr() as *const HMODULE, module_count)
128 };
129
130 let string_buffer_start = bytes_needed as usize;
133 if work_buffer.len() < string_buffer_start + 2048 {
134 let needed = string_buffer_start + 2048;
135 if work_buffer.capacity() < needed {
136 work_buffer.reserve(needed - work_buffer.capacity());
137 }
138 unsafe {
139 work_buffer.set_len(needed);
140 }
141 }
142
143 let string_buffer_ptr =
144 unsafe { work_buffer.as_mut_ptr().add(string_buffer_start) as *mut u16 };
145 let string_buffer_len = (work_buffer.len() - string_buffer_start) / 2;
146 let string_buffer_slice =
147 unsafe { std::slice::from_raw_parts_mut(string_buffer_ptr, string_buffer_len) };
148
149 for &hmodule in module_handles {
150 let name_len =
152 unsafe { GetModuleBaseNameW(self.as_raw_handle(), hmodule, string_buffer_slice) }
153 as usize;
154
155 let name = if name_len > 0 {
156 String::from_utf16_lossy(&string_buffer_slice[..name_len])
157 } else {
158 continue;
159 };
160
161 let path_len =
163 unsafe { GetModuleFileNameExW(self.as_raw_handle(), hmodule, string_buffer_slice) }
164 as usize;
165
166 let path = if path_len > 0 {
167 ImagePath::from_utf16(&string_buffer_slice[..path_len])
169 } else {
170 ImagePath::from_str(&name)
171 };
172
173 let mut mod_info = MODULEINFO::default();
175 let (base_address, size) = if unsafe {
176 GetModuleInformation(
177 self.as_raw_handle(),
178 hmodule,
179 &mut mod_info,
180 std::mem::size_of::<MODULEINFO>() as u32,
181 )
182 }
183 .is_ok()
184 {
185 (mod_info.lpBaseOfDll as usize, mod_info.SizeOfImage)
186 } else {
187 (0, 0)
188 };
189
190 let module_info = ModuleInfo {
191 name,
192 path,
193 base_address,
194 size,
195 };
196
197 if filter(&module_info) {
199 out_modules.push(module_info);
200 }
201 }
202
203 Ok(out_modules.len())
204 }
205}