|
1 | | -pub fn scan(signature: &[Option<u8>]) -> Result<Option<usize>, std::io::Error> { |
2 | | - todo!("Unimplemented on windows"); |
| 1 | +pub struct Module { |
| 2 | + pub base_address: usize, |
| 3 | + pub size: usize, |
| 4 | + pub name: String, |
| 5 | +} |
| 6 | + |
| 7 | +fn get_module_list() -> Result<Vec<Module>, std::io::Error> { |
| 8 | + use windows::Win32::Foundation::HANDLE; |
| 9 | + use windows::Win32::System::Diagnostics::ToolHelp::{ |
| 10 | + CreateToolhelp32Snapshot, MODULEENTRY32, Module32First, Module32Next, TH32CS_SNAPMODULE, TH32CS_SNAPMODULE32, |
| 11 | + }; |
| 12 | + |
| 13 | + let snapshot: HANDLE = unsafe { CreateToolhelp32Snapshot(TH32CS_SNAPMODULE | TH32CS_SNAPMODULE32, 0).unwrap() }; |
| 14 | + if snapshot.is_invalid() { |
| 15 | + Err(std::io::Error::last_os_error()) |
| 16 | + } else { |
| 17 | + let mut modules = Vec::new(); |
| 18 | + let mut module_entry = MODULEENTRY32 { |
| 19 | + dwSize: std::mem::size_of::<MODULEENTRY32>() as u32, |
| 20 | + ..Default::default() |
| 21 | + }; |
| 22 | + |
| 23 | + let mut success = unsafe { Module32First(snapshot, &mut module_entry).is_ok() }; |
| 24 | + while success { |
| 25 | + let name = String::from_utf8( |
| 26 | + module_entry |
| 27 | + .szModule |
| 28 | + .iter() |
| 29 | + .take_while(|&&c| c != 0) |
| 30 | + .map(|&c| c as u8) |
| 31 | + .collect(), |
| 32 | + ) |
| 33 | + .unwrap_or_default(); |
| 34 | + |
| 35 | + modules.push(Module { |
| 36 | + base_address: module_entry.modBaseAddr as usize, |
| 37 | + size: module_entry.modBaseSize as usize, |
| 38 | + name, |
| 39 | + }); |
| 40 | + |
| 41 | + success = unsafe { Module32Next(snapshot, &mut module_entry).is_ok() }; |
| 42 | + } |
| 43 | + |
| 44 | + Ok(modules) |
| 45 | + } |
| 46 | +} |
| 47 | + |
| 48 | +fn find_signature(haystack: &[u8], needle: &[Option<u8>]) -> Option<usize> { |
| 49 | + if needle.is_empty() { |
| 50 | + return Some(0); |
| 51 | + } |
| 52 | + |
| 53 | + for i in 0..=(haystack.len() - needle.len()) { |
| 54 | + let mut found = true; |
| 55 | + for (j, &byte_opt) in needle.iter().enumerate() { |
| 56 | + if let Some(byte) = byte_opt { |
| 57 | + if haystack[i + j] != byte { |
| 58 | + found = false; |
| 59 | + break; |
| 60 | + } |
| 61 | + } |
| 62 | + } |
| 63 | + if found { |
| 64 | + return Some(i); |
| 65 | + } |
| 66 | + } |
| 67 | + |
| 68 | + None |
| 69 | +} |
| 70 | + |
| 71 | +pub fn scan(signature: &[Option<u8>], target_module: Option<&str>) -> Result<Option<usize>, std::io::Error> { |
| 72 | + let modules = get_module_list()?; |
| 73 | + for module in modules { |
| 74 | + // If no target module specified, scan all modules |
| 75 | + let target_module = target_module.unwrap_or(&module.name); |
| 76 | + if module.name.eq_ignore_ascii_case(target_module) { |
| 77 | + unsafe { |
| 78 | + let module_bytes = std::slice::from_raw_parts(module.base_address as *const u8, module.size); |
| 79 | + if let Some(offset) = find_signature(module_bytes, signature) { |
| 80 | + return Ok(Some(module.base_address + offset)); |
| 81 | + } |
| 82 | + } |
| 83 | + } |
| 84 | + } |
| 85 | + |
| 86 | + Ok(None) |
3 | 87 | } |
0 commit comments