use super::RAIIHandle;
use std::io;
use std::path::Path;
use winapi::shared::minwindef::TRUE;
use winapi::um::handleapi::INVALID_HANDLE_VALUE;
use winapi::um::tlhelp32::{
CreateToolhelp32Snapshot, Module32First, Module32Next, MODULEENTRY32, TH32CS_SNAPMODULE,
};
pub fn for_each_module<F>(process_id: u32, mut f: F) -> io::Result<()>
where
F: FnMut((usize, usize), &Path),
{
let handle = unsafe { CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, process_id) };
debug!(
"Called CreateToolHelp32Snapshot with return value {}",
handle as usize
);
if handle == INVALID_HANDLE_VALUE {
let error = io::Error::last_os_error();
error!("CreateToolHelp32Snapshot failed with error {:?}", error);
return Err(error);
}
let _guard = RAIIHandle::new(handle);
debug!("Handle is {}", handle as usize);
let mut pe32: MODULEENTRY32 = unsafe { std::mem::zeroed() };
pe32.dwSize = std::mem::size_of::<MODULEENTRY32>() as u32;
debug!("dwSize is {}", pe32.dwSize);
let v = unsafe { Module32First(handle, &mut pe32) };
if v != TRUE {
let error = io::Error::last_os_error();
error!(
"Module32First returned {}, failed with error {:?}",
v, error
);
return Err(error);
}
match get_module_data(&pe32) {
Ok((address_size, name)) => f(address_size, name),
Err(address) => warn!(
"The module with address {:016X} didn't have an UTF8 valid name.",
address
),
}
trace!("Cleaning back module name.");
pe32.szExePath
.iter_mut()
.take_while(|c| **c != 0)
.for_each(|c| *c = 0);
while unsafe { Module32Next(handle, &mut pe32) } != 0 {
match get_module_data(&pe32) {
Ok((address_size, name)) => f(address_size, name),
Err(address) => warn!(
"The module with address {:016X} didn't have an UTF8 valid name.",
address
),
}
trace!("Cleaning back module name.");
pe32.szExePath
.iter_mut()
.take_while(|c| **c != 0)
.for_each(|c| *c = 0);
}
Ok(())
}
fn get_module_data(module: &MODULEENTRY32) -> Result<((usize, usize), &Path), usize> {
let address = module.modBaseAddr as usize;
let size = module.modBaseSize as usize;
let name = super::get_winstring(&module.szExePath).map_err(|_| address)?;
trace!(
"get_module_data: address = {:016X}, name = {}",
address,
name
);
Ok(((address, size), Path::new(name)))
}