1use memflow::cglue;
2use memflow::os::process::*;
3use memflow::prelude::v1::*;
4use memflow::types::gap_remover::GapRemover;
5
6use super::{conv_err, ProcessVirtualMemory};
7
8use windows::Wdk::System::Threading::{NtQueryInformationProcess, ProcessBasicInformation};
9use windows::Win32::Foundation::{HINSTANCE, HMODULE, STILL_ACTIVE};
10
11use windows::Win32::System::Memory::{
12 VirtualQueryEx, MEMORY_BASIC_INFORMATION, MEM_FREE, MEM_RESERVE, PAGE_EXECUTE,
13 PAGE_EXECUTE_READ, PAGE_EXECUTE_READWRITE, PAGE_EXECUTE_WRITECOPY, PAGE_READONLY,
14 PAGE_READWRITE, PAGE_WRITECOPY,
15};
16
17use windows::Win32::System::ProcessStatus::{
18 K32EnumProcessModulesEx, K32GetModuleFileNameExA, K32GetModuleInformation, LIST_MODULES_32BIT,
19 LIST_MODULES_64BIT,
20};
21
22use windows::Win32::System::Threading::PROCESS_BASIC_INFORMATION;
23
24use core::mem::{size_of, size_of_val};
25use core::ptr;
26
27#[derive(Clone)]
28pub struct WindowsProcess {
29 virt_mem: ProcessVirtualMemory,
30 info: ProcessInfo,
31 cached_modules: Vec<HMODULE>,
32}
33unsafe impl Send for WindowsProcess {}
34unsafe impl Sync for WindowsProcess {}
35
36impl WindowsProcess {
37 pub fn try_new(info: ProcessInfo) -> Result<Self> {
38 Ok(Self {
39 virt_mem: ProcessVirtualMemory::try_new(&info)?,
40 info,
41 cached_modules: vec![],
42 })
43 }
44}
45
46cglue_impl_group!(WindowsProcess, ProcessInstance, {});
47cglue_impl_group!(WindowsProcess, IntoProcessInstance, {});
48
49impl Process for WindowsProcess {
50 fn state(&mut self) -> ProcessState {
52 let mut info = PROCESS_BASIC_INFORMATION::default();
53
54 if unsafe {
55 NtQueryInformationProcess(
56 **self.virt_mem.handle,
57 ProcessBasicInformation,
58 &mut info as *mut _ as _,
59 size_of_val(&info) as _,
60 ptr::null_mut(),
61 )
62 }
63 .ok()
64 .is_err()
65 {
66 return ProcessState::Unknown;
67 }
68
69 if info.ExitStatus == STILL_ACTIVE {
70 ProcessState::Alive
71 } else {
72 ProcessState::Dead(info.ExitStatus.0)
73 }
74 }
75
76 fn set_dtb(&mut self, _dtb1: Address, _dtb2: Address) -> Result<()> {
79 Ok(())
80 }
81
82 fn module_address_list_callback(
90 &mut self,
91 target_arch: Option<&ArchitectureIdent>,
92 mut callback: ModuleAddressCallback,
93 ) -> Result<()> {
94 let filter_flags = match target_arch {
95 Some(ident) => match ident.into_obj().bits() {
96 32 => [Some(LIST_MODULES_32BIT), None],
97 64 => [Some(LIST_MODULES_64BIT), None],
98 _ => [Some(LIST_MODULES_32BIT), Some(LIST_MODULES_64BIT)],
99 },
100 None => [Some(LIST_MODULES_32BIT), Some(LIST_MODULES_64BIT)],
101 };
102
103 for f in IntoIterator::into_iter(filter_flags).flatten() {
104 self.cached_modules.clear();
105 self.cached_modules.resize(1024, HMODULE::default());
106
107 let mut needed = 0;
108
109 loop {
110 unsafe {
111 K32EnumProcessModulesEx(
112 **self.virt_mem.handle,
113 self.cached_modules.as_mut_ptr(),
114 (self.cached_modules.len() * size_of::<HMODULE>()) as _,
115 &mut needed,
116 f.0,
117 )
118 .ok()
119 .map_err(conv_err)?
120 }
121
122 needed /= size_of::<HINSTANCE>() as u32;
123
124 if needed as usize <= self.cached_modules.len() {
125 break;
126 }
127
128 self.cached_modules
129 .resize(self.cached_modules.len() * 2, HMODULE::default());
130 }
131
132 self.cached_modules.resize(needed as _, HMODULE::default());
133
134 let arch = match f {
136 LIST_MODULES_32BIT => ArchitectureIdent::X86(32, false),
137 LIST_MODULES_64BIT => ArchitectureIdent::X86(64, false),
138 _ => ArchitectureIdent::Unknown(0),
139 };
140
141 callback.extend(self.cached_modules.iter().map(|&m| ModuleAddressInfo {
142 address: Address::from(m.0 as umem),
143 arch,
144 }));
145 }
146
147 Ok(())
148 }
149
150 fn module_by_address(
156 &mut self,
157 address: Address,
158 arch: ArchitectureIdent,
159 ) -> Result<ModuleInfo> {
160 let mut path = [0u8; 128];
161
162 if unsafe {
163 K32GetModuleFileNameExA(
164 **self.virt_mem.handle,
165 HINSTANCE(address.to_umem() as _),
166 &mut path,
167 )
168 } == 0
169 {
170 return Err(Error(ErrorOrigin::OsLayer, ErrorKind::Unknown));
171 }
172
173 let mut info = Default::default();
174
175 unsafe {
176 K32GetModuleInformation(
177 **self.virt_mem.handle,
178 HINSTANCE(address.to_umem() as _),
179 &mut info,
180 size_of_val(&info) as _,
181 )
182 }
183 .ok()
184 .map_err(conv_err)?;
185
186 let path = String::from_utf8_lossy(&path);
187 let path = &*path;
188 let path = path.split_once('\0').map(|(i, _)| i).unwrap_or(path);
189 let name = path.rsplit_once('\\').map(|(_, i)| i).unwrap_or(path);
190
191 Ok(ModuleInfo {
192 address,
193 parent_process: self.info.address,
194 arch,
195 base: address,
196 size: info.SizeOfImage as _,
197 name: name.into(),
198 path: path.into(),
199 })
200 }
201
202 fn primary_module_address(&mut self) -> Result<Address> {
206 let mut info = PROCESS_BASIC_INFORMATION::default();
207
208 unsafe {
209 NtQueryInformationProcess(
210 **self.virt_mem.handle,
211 ProcessBasicInformation,
212 &mut info as *mut _ as _,
213 size_of_val(&info) as _,
214 ptr::null_mut(),
215 )
216 }
217 .ok()
218 .map_err(conv_err)?;
219
220 self.read_addr64(Address::from(info.PebBaseAddress as umem + 0x10))
222 .data_part()
223 }
224
225 fn module_import_list_callback(
226 &mut self,
227 info: &ModuleInfo,
228 callback: ImportCallback,
229 ) -> Result<()> {
230 memflow::os::util::module_import_list_callback(&mut self.virt_mem, info, callback)
231 }
232
233 fn module_export_list_callback(
234 &mut self,
235 info: &ModuleInfo,
236 callback: ExportCallback,
237 ) -> Result<()> {
238 memflow::os::util::module_export_list_callback(&mut self.virt_mem, info, callback)
239 }
240
241 fn module_section_list_callback(
242 &mut self,
243 info: &ModuleInfo,
244 callback: SectionCallback,
245 ) -> Result<()> {
246 memflow::os::util::module_section_list_callback(&mut self.virt_mem, info, callback)
247 }
248
249 fn info(&self) -> &ProcessInfo {
251 &self.info
252 }
253
254 fn mapped_mem_range(
255 &mut self,
256 gap_size: imem,
257 start: Address,
258 end: Address,
259 out: MemoryRangeCallback,
260 ) {
261 let mut gap_remover = GapRemover::new(out, gap_size, start, end);
262
263 let mut region = Default::default();
264
265 let mut cur_addr = start;
266
267 while unsafe {
268 VirtualQueryEx(
269 **self.virt_mem.handle,
270 Some(cur_addr.to_umem() as *mut _),
271 &mut region,
272 size_of::<MEMORY_BASIC_INFORMATION>(),
273 )
274 } > 0
275 && cur_addr < end
276 {
277 cur_addr = Address::from(
278 (region.BaseAddress as umem).saturating_add(region.RegionSize as umem),
279 );
280
281 if region.State == MEM_FREE || region.State == MEM_RESERVE || region.RegionSize == 0 {
282 continue;
283 }
284
285 let page_type = PageType::empty();
286
287 let page_type = match region.Protect {
288 PAGE_EXECUTE | PAGE_EXECUTE_READ => page_type.noexec(false),
289 PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY => {
290 page_type.noexec(false).write(true)
291 }
292 PAGE_READWRITE | PAGE_WRITECOPY => page_type.write(true),
293 PAGE_READONLY => page_type.write(false),
294 _ => page_type,
295 };
296
297 let range = CTup3(
298 Address::from(region.BaseAddress as umem),
299 region.RegionSize as _,
300 page_type,
301 );
302
303 gap_remover.push_range(range);
304 }
305 }
306}
307
308impl MemoryView for WindowsProcess {
309 fn read_raw_iter(&mut self, data: ReadRawMemOps) -> Result<()> {
310 self.virt_mem.read_raw_iter(data)
311 }
312
313 fn write_raw_iter(&mut self, data: WriteRawMemOps) -> Result<()> {
314 self.virt_mem.write_raw_iter(data)
315 }
316
317 fn metadata(&self) -> MemoryViewMetadata {
318 self.virt_mem.metadata()
319 }
320}