mod strategy;
pub(crate) mod parallel;
pub use scan_engine::aob_scan_internal;
mod scan_engine {
use windows::Win32::Foundation::HANDLE;
use crate::memory::MemoryError;
use crate::memory_aobscan::pattern::Pattern;
use crate::memory_aobscan::pattern::anchor::find_rarest_byte_index;
use crate::memory_aobscan::cache::region::get_valid_memory_regions;
use super::strategy::AnchorInfo;
use super::parallel;
use std::sync::atomic::AtomicBool;
use rayon::prelude::*;
pub fn calculate_optimal_chunk_size(pattern_len: usize) -> usize {
match pattern_len {
0..=4 => 4 * 1024 * 1024, 5..=16 => 2 * 1024 * 1024, 17..=64 => 512 * 1024, _ => 128 * 1024, }
}
pub fn aob_scan_internal(handle: HANDLE, pattern: &Pattern, start_address: usize, length: usize, find_all: bool, use_cache: bool) -> Result<Vec<usize>, MemoryError> {
let regions = get_valid_memory_regions(handle, use_cache);
if regions.is_empty() {
return Ok(vec![]);
}
let (use_multi_byte, anchor_info) = if let Some(ref seq) = pattern.anchor_sequence {
(true, AnchorInfo::MultiByte(seq.clone()))
} else {
let anchor_idx = find_rarest_byte_index(&pattern.bytes, &pattern.mask).ok_or_else(|| {
MemoryError::InvalidAddress("Pattern contains only wildcards".to_string())
})?;
let anchor_byte = pattern.bytes[anchor_idx];
(false, AnchorInfo::SingleByte(anchor_idx, anchor_byte))
};
let chunk_size = calculate_optimal_chunk_size(pattern.bytes.len());
let found_first = AtomicBool::new(false);
let results = std::sync::Mutex::new(Vec::new());
let safe_handle = parallel::SafeHandle::new(handle);
regions.par_iter().for_each(|(region_addr, region_size)| {
parallel::process_region(
region_addr,
region_size,
start_address,
length,
chunk_size,
&safe_handle,
&anchor_info,
use_multi_byte,
pattern,
&results,
&found_first,
find_all,
);
});
let mut final_results = results.lock().unwrap();
if !find_all && !final_results.is_empty() {
final_results.sort();
final_results.truncate(1);
} else {
final_results.sort();
}
Ok(final_results.drain(..).collect())
}
}