Skip to main content

toy_arms/internal/
internal.rs

1use std::mem::{size_of, zeroed};
2use std::str::Utf8Error;
3use winapi::shared::minwindef::{DWORD, FARPROC, HMODULE, MAX_PATH};
4use winapi::um::libloaderapi::GetProcAddress;
5use winapi::um::processthreadsapi::GetCurrentProcess;
6use winapi::um::psapi::{EnumProcessModules, GetModuleBaseNameA, GetModuleInformation, MODULEINFO};
7use winapi::um::winnt::{CHAR, LPSTR};
8use crate::{cast};
9use crate::utils_common::read_null_terminated_string;
10use crate::internal::{
11    utils::get_module_handle,
12    pattern_scan::boyer_moore_horspool,
13};
14
15pub enum TAInternalError {
16    GetAllModuleHandlesFailed,
17}
18
19#[derive(Debug)]
20pub struct Module<'a> {
21    pub module_name: &'a str,
22    pub module_handle: HMODULE,
23    pub module_size: u32,
24    pub module_base_address: usize,
25}
26
27impl<'a> Default for Module<'a> {
28    fn default() -> Self {
29        Module {
30            module_name: "",
31            module_handle: 0x0 as HMODULE,
32            module_size: 0,
33            module_base_address: 0,
34        }
35    }
36}
37
38impl<'a> Module<'a> {
39    pub fn from_module_name(module_name: &'a str) -> Option<Self> {
40        let module_handle: HMODULE = match get_module_handle(module_name) {
41            Some(e) => e,
42            None => return None,
43        };
44        unsafe {
45            let mut module_info: MODULEINFO = zeroed::<MODULEINFO>();
46            GetModuleInformation(
47                GetCurrentProcess(),
48                module_handle,
49                &mut module_info,
50                size_of::<MODULEINFO>() as u32,
51            );
52            Some(Module {
53                module_name,
54                module_handle,
55                module_base_address: module_info.lpBaseOfDll as usize,
56                module_size: module_info.SizeOfImage,
57            })
58        }
59    }
60
61    /// read fetches the value that given address is holding.
62    /// * `base_address` - the address that is supposed to have the value you want
63    pub fn read<T>(&self, address: u32) -> *mut T {
64        cast!(mut self.module_handle as usize + address as usize, T)
65    }
66
67    /// read_string reads the string untill the null terminator that is in the given module
68    /// * `address` - relative address of the head of the string.
69    pub fn read_string(&self, address: i32) -> Result<String, Utf8Error> {
70        unsafe { read_null_terminated_string(self.module_handle as usize + address as usize) }
71    }
72
73    /// find_pattern scans over entire module and returns the address if there is matched byte pattern in module.
74    /// * `pattern` - pattern string you're looking for. format: "8D 34 85 ? ? ? ? 89 15 ? ? ? ? 8B 41 08 8B 48 04 83 F9 FF"
75    pub fn find_pattern(&self, pattern: &str) -> Option<usize> {
76        let base = self.module_base_address;
77        let end = self.module_base_address + self.module_size as usize;
78        unsafe { boyer_moore_horspool(pattern, base, end).map(|e| e as usize) }
79    }
80
81    /// pattern scan basically be for calculating offset of some value. It adds the offset to the pattern-matched address, dereferences, and add the `extra`.
82    /// * `pattern` - pattern string you're looking for. format: "8D 34 85 ? ? ? ? 89 15 ? ? ? ? 8B 41 08 8B 48 04 83 F9 FF"
83    /// * `offset` - offset of the address from pattern's base.
84    /// * `extra` - offset of the address from dereferenced address.
85    pub fn pattern_scan(&self, pattern: &str, offset: isize, extra: usize) -> Option<usize> {
86        unsafe {
87            let address = self.find_pattern(pattern)?;
88            let address = (address as *mut u8).offset(offset) as *mut usize;
89            // calculate relative address
90            Some(*address - self.module_base_address + extra)
91        }
92    }
93}
94
95/// This function is for when you don't know which module has the pattern. It returns the address and module name.
96/// * `pattern` - pattern string you're looking for. format: "8D 34 85 ? ? ? ? 89 15 ? ? ? ? 8B 41 08 8B 48 04 83 F9 FF"
97/// * `offset` - offset of the address from pattern's base.
98/// * `extra` - offset of the address from dereferenced address.
99pub fn pattern_scan_all_modules(pattern: &str) -> Option<(usize, String)> {
100    unsafe {
101        let all_handles = get_all_module_handles().ok()?;
102        let process_handle = GetCurrentProcess();
103        for handle in all_handles {
104            let mut module_info: MODULEINFO = std::mem::zeroed::<MODULEINFO>();
105            GetModuleInformation(
106                process_handle,
107                handle,
108                &mut module_info,
109                size_of::<MODULEINFO>() as u32,
110            );
111            let base = module_info.lpBaseOfDll as usize;
112            let end = module_info.lpBaseOfDll as usize + module_info.SizeOfImage as usize;
113            match boyer_moore_horspool(pattern, base, end) {
114                Some(e) => {
115                    let mut module_name: [CHAR; MAX_PATH] = [0; MAX_PATH];
116                    GetModuleBaseNameA(
117                        GetCurrentProcess(),
118                        handle,
119                        &mut module_name as LPSTR,
120                        std::mem::size_of_val(&module_name) as u32,
121                    );
122                    let module_name =
123                        read_null_terminated_string(&mut module_name as *mut i8 as usize).unwrap();
124                    return Some((e as usize, module_name));
125                }
126                None => continue,
127            }
128        }
129        None
130    }
131}
132
133pub fn pattern_scan_specific_range(pattern: &str, start: usize, end: usize) -> Option<*mut u8> {
134    unsafe { boyer_moore_horspool(pattern, start, end) }
135}
136
137/// * `module_name` - name of module that the desired function is in.
138/// * `function_name` - name of the function you want
139pub unsafe fn get_module_function_address(
140    module_name: &str,
141    function_name: &str,
142) -> Option<FARPROC> {
143    let module_handle = match get_module_handle(module_name) {
144        Some(e) => e,
145        None => return None,
146    };
147    Some(GetProcAddress(
148        module_handle,
149        crate::internal::utils::make_lpcstr(function_name),
150    ))
151}
152
153fn get_all_module_handles() -> Result<Vec<HMODULE>, TAInternalError> {
154    unsafe {
155        for size_indice in 3..=10 {
156            // Buffer size is size_indice * sizeof(HMODULE) * 100
157            let mut module_handles = vec![0 as HMODULE; size_indice * 100];
158            // Make a buffer for required_size[out] by zero initializing the DWORD space.
159            let mut required_size = std::mem::zeroed::<DWORD>();
160            // The last parameter is implicitly: &mut required_size as *mut DWORD
161            return if EnumProcessModules(
162                GetCurrentProcess(),
163                module_handles.as_mut_ptr(),
164                (module_handles.len() * size_of::<HMODULE>()) as u32,
165                &mut required_size,
166            ) != 0
167            {
168                let number_of_handles = required_size as usize / std::mem::size_of::<HMODULE>();
169                // If buffer is smaller than required, loop to call EnumProcessModules with bigger buffer.
170                if size_indice * 100 < number_of_handles {
171                    continue;
172                }
173                Ok(module_handles
174                    .iter()
175                    .filter(|e| **e != 0 as HMODULE)
176                    .map(|e| e.clone())
177                    .collect::<Vec<HMODULE>>())
178            } else {
179                Err(TAInternalError::GetAllModuleHandlesFailed)
180            };
181        }
182        Err(TAInternalError::GetAllModuleHandlesFailed)
183    }
184}