Skip to content

Commit 756b966

Browse files
committed
Make process/module enumeration stateless and resolve lookups from fresh snapshots
1 parent 6c36e9e commit 756b966

1 file changed

Lines changed: 50 additions & 50 deletions

File tree

src/windows/mod.rs

Lines changed: 50 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,7 @@ use windows::Win32::Security::{
2020
TOKEN_ADJUST_PRIVILEGES, TOKEN_PRIVILEGES,
2121
};
2222

23-
use core::mem::{align_of, size_of, MaybeUninit};
24-
use core::ptr;
23+
use core::mem::{align_of, size_of};
2524
use std::ffi::OsString;
2625
use std::os::windows::ffi::OsStringExt;
2726

@@ -170,8 +169,6 @@ unsafe fn enable_debug_privilege() -> Result<()> {
170169

171170
pub struct WindowsOs {
172171
info: OsInfo,
173-
cached_processes: Vec<ProcessInfo>,
174-
cached_modules: Vec<KernelModule>,
175172
}
176173

177174
impl WindowsOs {
@@ -270,8 +267,6 @@ impl Clone for WindowsOs {
270267
fn clone(&self) -> Self {
271268
Self {
272269
info: self.info.clone(),
273-
cached_processes: vec![],
274-
cached_modules: vec![],
275270
}
276271
}
277272
}
@@ -284,11 +279,7 @@ impl Default for WindowsOs {
284279
arch: ArchitectureIdent::X86(64, false),
285280
};
286281

287-
Self {
288-
info,
289-
cached_modules: vec![],
290-
cached_processes: vec![],
291-
}
282+
Self { info }
292283
}
293284
}
294285

@@ -299,39 +290,55 @@ impl Os for WindowsOs {
299290
/// Walks a process list and calls a callback for each process structure address
300291
///
301292
/// The callback is fully opaque. We need this style so that C FFI can work seamlessly.
302-
fn process_address_list_callback(&mut self, callback: AddressCallback) -> Result<()> {
293+
fn process_address_list_callback(&mut self, mut callback: AddressCallback) -> Result<()> {
303294
let handle =
304295
Handle(unsafe { CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0) }.map_err(conv_err)?);
305296

306-
let mut maybe_entry = MaybeUninit::<PROCESSENTRY32W>::uninit();
297+
let mut entry = PROCESSENTRY32W::default();
298+
entry.dwSize = size_of::<PROCESSENTRY32W>() as u32;
299+
300+
if unsafe { Process32FirstW(*handle, &mut entry) }.is_err() {
301+
return Ok(());
302+
}
307303

308-
unsafe {
309-
ptr::write(
310-
&mut (*maybe_entry.as_mut_ptr()).dwSize,
311-
size_of::<PROCESSENTRY32W>() as u32,
312-
);
304+
loop {
305+
if !callback.call(Address::from(entry.th32ProcessID as umem)) {
306+
break;
307+
}
308+
309+
if unsafe { Process32NextW(*handle, &mut entry) }.is_err() {
310+
break;
311+
}
313312
}
314313

315-
let ptr = maybe_entry.as_mut_ptr();
314+
Ok(())
315+
}
316+
317+
/// Find process information by its internal address
318+
fn process_info_by_address(&mut self, address: Address) -> Result<ProcessInfo> {
319+
let pid = address.to_umem() as Pid;
320+
let handle =
321+
Handle(unsafe { CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0) }.map_err(conv_err)?);
322+
323+
let mut entry = PROCESSENTRY32W::default();
324+
entry.dwSize = size_of::<PROCESSENTRY32W>() as u32;
325+
326+
if unsafe { Process32FirstW(*handle, &mut entry) }.is_err() {
327+
return Err(Error(ErrorOrigin::OsLayer, ErrorKind::NotFound));
328+
}
316329

317-
std::iter::once(unsafe { Process32FirstW(*handle, ptr) })
318-
.chain(std::iter::repeat_with(|| unsafe {
319-
Process32NextW(*handle, ptr)
320-
}))
321-
.take_while(|b| b.is_ok())
322-
.map(|_| unsafe { maybe_entry.assume_init() })
323-
.map(|p| {
324-
let address = Address::from(p.th32ProcessID as umem);
325-
let len = p.szExeFile.iter().take_while(|&&c| c != 0).count();
330+
loop {
331+
if entry.th32ProcessID as Pid == pid {
332+
let len = entry.szExeFile.iter().take_while(|&&c| c != 0).count();
326333

327-
let path = OsString::from_wide(&p.szExeFile[..len]);
334+
let path = OsString::from_wide(&entry.szExeFile[..len]);
328335
let path = path.to_string_lossy();
329336
let path = &*path;
330337
let name = path.rsplit_once('\\').map(|(_, end)| end).unwrap_or(path);
331338

332-
self.cached_processes.push(ProcessInfo {
339+
return Ok(ProcessInfo {
333340
address,
334-
pid: address.to_umem() as _,
341+
pid,
335342
state: ProcessState::Alive,
336343
name: name.into(),
337344
path: path.into(),
@@ -342,21 +349,14 @@ impl Os for WindowsOs {
342349
dtb1: Address::invalid(),
343350
dtb2: Address::invalid(),
344351
});
352+
}
345353

346-
address
347-
})
348-
.feed_into(callback);
349-
350-
Ok(())
351-
}
354+
if unsafe { Process32NextW(*handle, &mut entry) }.is_err() {
355+
break;
356+
}
357+
}
352358

353-
/// Find process information by its internal address
354-
fn process_info_by_address(&mut self, address: Address) -> Result<ProcessInfo> {
355-
self.cached_processes
356-
.iter()
357-
.find(|p| p.address == address)
358-
.cloned()
359-
.ok_or(Error(ErrorOrigin::OsLayer, ErrorKind::NotFound))
359+
Err(Error(ErrorOrigin::OsLayer, ErrorKind::NotFound))
360360
}
361361

362362
/// Construct a process by its info, borrowing the OS
@@ -379,10 +379,9 @@ impl Os for WindowsOs {
379379
/// # Arguments
380380
/// * `callback` - where to pass each matching module to. This is an opaque callback.
381381
fn module_address_list_callback(&mut self, mut callback: AddressCallback) -> Result<()> {
382-
self.cached_modules = Self::query_kernel_modules()?;
383-
384-
(0..self.cached_modules.len())
385-
.map(Address::from)
382+
Self::query_kernel_modules()?
383+
.into_iter()
384+
.map(|m| m.base)
386385
.take_while(|a| callback.call(*a))
387386
.for_each(|_| {});
388387

@@ -394,8 +393,9 @@ impl Os for WindowsOs {
394393
/// # Arguments
395394
/// * `address` - address where module's information resides in
396395
fn module_by_address(&mut self, address: Address) -> Result<ModuleInfo> {
397-
self.cached_modules
398-
.get(address.to_umem() as usize)
396+
Self::query_kernel_modules()?
397+
.into_iter()
398+
.find(|km| km.base == address)
399399
.map(|km| ModuleInfo {
400400
address,
401401
size: km.size,

0 commit comments

Comments
 (0)