use crate::{Error, Handle, Process, WinResult};
use std::{
ffi::{CString, OsString},
mem,
os::windows::{io::AsRawHandle, prelude::*},
path::PathBuf,
};
use winapi::{
ctypes::c_void,
shared::minwindef::{DWORD, HMODULE, MAX_PATH},
um::{
libloaderapi::GetProcAddress,
psapi::{GetModuleBaseNameW, GetModuleFileNameExW, GetModuleInformation, MODULEINFO},
tlhelp32::{Module32NextW, MODULEENTRY32W},
winnt::{self, WCHAR},
},
};
#[derive(Debug)]
pub struct Module<'a> {
pub(crate) handle: HMODULE,
pub(crate) process: &'a Process,
}
impl<'a> Module<'a> {
pub fn handle(&self) -> HMODULE {
self.handle
}
pub fn name(&self) -> WinResult<String> {
unsafe {
let mut buffer: [WCHAR; MAX_PATH] = mem::zeroed();
let ret = GetModuleBaseNameW(
self.process.as_raw_handle() as winnt::HANDLE,
self.handle,
buffer.as_mut_ptr(),
MAX_PATH as _,
);
if ret == 0 {
Err(Error::last_os_error())
} else {
Ok(OsString::from_wide(&buffer[0..ret as usize])
.to_string_lossy()
.into_owned())
}
}
}
pub fn path(&self) -> WinResult<PathBuf> {
unsafe {
let mut buffer: [WCHAR; MAX_PATH] = mem::zeroed();
let ret = GetModuleFileNameExW(
self.process.as_raw_handle() as winnt::HANDLE,
self.handle,
buffer.as_mut_ptr(),
MAX_PATH as _,
);
if ret == 0 {
Err(Error::last_os_error())
} else {
Ok(OsString::from_wide(&buffer[0..ret as usize]).into())
}
}
}
pub fn info(&self) -> WinResult<ModuleInfo> {
unsafe {
let mut c_info: MODULEINFO = mem::zeroed();
let ret = GetModuleInformation(
self.process.as_raw_handle() as winnt::HANDLE,
self.handle,
&mut c_info,
mem::size_of::<MODULEINFO>() as _,
);
if ret == 0 {
Err(Error::last_os_error())
} else {
Ok(c_info.into())
}
}
}
pub fn proc_address(&self, proc_name: &str) -> WinResult<*mut c_void> {
unsafe {
let ret = GetProcAddress(self.handle, CString::new(proc_name)?.as_ptr() as _);
if ret.is_null() {
Err(Error::last_os_error())
} else {
Ok(ret as *mut c_void)
}
}
}
}
#[derive(Debug, Clone)]
pub struct ModuleInfo {
pub address: *mut c_void,
pub size: usize,
pub entry_point: *mut c_void,
}
impl From<MODULEINFO> for ModuleInfo {
fn from(mi: MODULEINFO) -> ModuleInfo {
ModuleInfo {
address: mi.lpBaseOfDll,
size: mi.SizeOfImage as usize,
entry_point: mi.EntryPoint,
}
}
}
#[derive(Debug, Clone)]
pub struct ModuleEntry {
pub id: u32,
pub name: String,
pub path: PathBuf,
pub hmodule: HMODULE,
pub process_id: u32,
pub global_load_count: u32,
pub proc_load_count: u32,
pub mod_base_addr: *mut u8,
pub mod_base_size: u32,
}
impl From<MODULEENTRY32W> for ModuleEntry {
fn from(me: MODULEENTRY32W) -> ModuleEntry {
let name_end = me
.szModule
.iter()
.position(|&b| b == 0)
.unwrap_or_else(|| me.szModule.len());
let name = OsString::from_wide(&me.szModule[..name_end])
.to_string_lossy()
.into_owned();
let path_end = me
.szExePath
.iter()
.position(|&b| b == 0)
.unwrap_or_else(|| me.szModule.len());
let path = OsString::from_wide(&me.szExePath[..path_end]).into();
ModuleEntry {
id: me.th32ModuleID,
name,
path,
hmodule: me.hModule,
process_id: me.th32ProcessID,
global_load_count: me.GlblcntUsage,
proc_load_count: me.ProccntUsage,
mod_base_addr: me.modBaseAddr,
mod_base_size: me.modBaseSize,
}
}
}
#[derive(Debug)]
pub struct ModuleEntryIter<'a> {
pub(crate) process: &'a Process,
pub(crate) snapshot: Handle,
}
impl<'a> Iterator for ModuleEntryIter<'a> {
type Item = ModuleEntry;
fn next(&mut self) -> Option<ModuleEntry> {
unsafe {
let mut entry: MODULEENTRY32W = mem::zeroed();
entry.dwSize = mem::size_of::<MODULEENTRY32W>() as DWORD;
let ret = Module32NextW(self.snapshot.as_raw_handle() as winnt::HANDLE, &mut entry);
if ret == 0 {
None
} else {
Some(entry.into())
}
}
}
}