use std::mem::{size_of, zeroed};
use std::str::Utf8Error;
use thiserror::Error;
use winapi::shared::minwindef::{DWORD, FARPROC, HMODULE};
use winapi::um::libloaderapi::GetProcAddress;
use winapi::um::processthreadsapi::GetCurrentProcess;
use winapi::um::psapi::{EnumProcessModules, GetModuleBaseNameA, GetModuleInformation, MODULEINFO};
use winapi::um::winnt::{CHAR, LPSTR};
use crate::{cast};
use crate::utils_common::read_null_terminated_string;
use crate::internal::{
utils::get_module_handle,
pattern_scan::boyer_moore_horspool,
};
#[derive(Error, Debug)]
pub enum ToyArmsInternalError {
#[error("get_all_module_handles failed")]
GetAllModuleHandlesFailed,
#[error("pattern_scan_all_modules failed")]
PatternScanALLModulesFailed,
}
pub struct Module<'a> {
pub module_name: &'a str,
pub module_handle: HMODULE,
pub module_size: u32,
pub module_base_address: usize,
}
impl<'a> Module<'a> {
pub fn from_module_name(module_name: &'a str) -> Option<Self> {
let module_handle: HMODULE = match get_module_handle(module_name) {
Some(e) => e,
None => return None,
};
unsafe {
let mut module_info: MODULEINFO = zeroed::<MODULEINFO>();
GetModuleInformation(
GetCurrentProcess(),
module_handle,
&mut module_info,
size_of::<MODULEINFO>() as u32,
);
Some(Module {
module_name,
module_handle,
module_base_address: module_info.lpBaseOfDll as usize,
module_size: module_info.SizeOfImage,
})
}
}
pub fn read<T>(&self, address: i32) -> *mut T {
cast!(mut self.module_handle as usize + address as usize, T)
}
pub fn read_string(&self, address: i32) -> Result<String, Utf8Error> {
unsafe { read_null_terminated_string(self.module_handle as usize + address as usize) }
}
pub fn find_pattern(&self, pattern: &str) -> Option<usize> {
let base = self.module_base_address;
let end = self.module_base_address + self.module_size as usize;
unsafe { boyer_moore_horspool(pattern, base, end).map(|e| e as usize) }
}
pub fn pattern_scan(&self, pattern: &str, offset: isize, extra: usize) -> Option<usize> {
unsafe {
let address = self.find_pattern(pattern)?;
let address = (address as *mut u8).offset(offset) as *mut usize;
Some(*address - self.module_base_address + extra)
}
}
}
pub fn pattern_scan_all_modules(pattern: &str) -> Option<(usize, String)> {
unsafe {
let all_handles = get_all_module_handles().ok()?;
let process_handle = GetCurrentProcess();
for handle in all_handles {
let mut module_info: MODULEINFO = std::mem::zeroed::<MODULEINFO>();
GetModuleInformation(
process_handle,
handle,
&mut module_info,
size_of::<MODULEINFO>() as u32,
);
let base = module_info.lpBaseOfDll as usize;
let end = module_info.lpBaseOfDll as usize + module_info.SizeOfImage as usize;
match boyer_moore_horspool(pattern, base, end) {
Some(e) => {
let mut module_name: [CHAR; 100] = [0; 100];
GetModuleBaseNameA(
GetCurrentProcess(),
handle,
&mut module_name as LPSTR,
std::mem::size_of_val(&module_name) as u32,
);
let module_name =
read_null_terminated_string(&mut module_name as *mut i8 as usize).unwrap();
return Some((e as usize, module_name));
}
None => continue,
}
}
None
}
}
pub fn pattern_scan_specific_range(pattern: &str, start: usize, end: usize) -> Option<*mut u8> {
unsafe { boyer_moore_horspool(pattern, start, end) }
}
pub unsafe fn get_module_function_address(
module_name: &str,
function_name: &str,
) -> Option<FARPROC> {
let module_handle = match get_module_handle(module_name) {
Some(e) => e,
None => return None,
};
Some(GetProcAddress(
module_handle,
crate::internal::utils::make_lpcstr(function_name),
))
}
fn get_all_module_handles() -> Result<Vec<HMODULE>, ToyArmsInternalError> {
unsafe {
for size_indice in 3..=10 {
let mut module_handles = vec![0 as HMODULE; size_indice * 100];
let mut required_size = std::mem::zeroed::<DWORD>();
return if EnumProcessModules(
GetCurrentProcess(),
module_handles.as_mut_ptr(),
(module_handles.len() * size_of::<HMODULE>()) as u32,
&mut required_size,
) != 0
{
let number_of_handles = required_size as usize / std::mem::size_of::<HMODULE>();
if size_indice * 100 < number_of_handles {
continue;
}
Ok(module_handles
.iter()
.filter(|e| **e != 0 as HMODULE)
.map(|e| e.clone())
.collect::<Vec<HMODULE>>())
} else {
Err(ToyArmsInternalError::GetAllModuleHandlesFailed)
};
}
Err(ToyArmsInternalError::GetAllModuleHandlesFailed)
}
}