From 030b767880c7942720d54a035569c2702cc4d9de Mon Sep 17 00:00:00 2001 From: Jujstme Date: Tue, 1 Oct 2024 20:42:39 +0200 Subject: [PATCH 1/5] Allow signature scanning to cross page boundaries --- src/signature.rs | 61 ++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 51 insertions(+), 10 deletions(-) diff --git a/src/signature.rs b/src/signature.rs index cc11593..4f487f6 100644 --- a/src/signature.rs +++ b/src/signature.rs @@ -1,6 +1,6 @@ //! Support for finding patterns in a process's memory. -use core::mem::{self, MaybeUninit}; +use core::{mem, slice}; use bytemuck::AnyBitPattern; @@ -194,22 +194,63 @@ impl Signature { process: &Process, (addr, len): (impl Into
, u64), ) -> Option
{ + const MEM_SIZE: usize = 0x1000; let mut addr: Address = Into::into(addr); - // TODO: Handle the case where a signature may be cut in half by a page - // boundary. let overall_end = addr.value() + len; - let mut buf = [MaybeUninit::uninit(); 4 << 10]; + + // The sigscan essentially works by reading one memory page (0x1000 bytes) + // at a time and looking for the signature in each page. + // We create a buffer sligthly larger than 0x1000 bytes in order to keep + // the very first bytes as the tail of the previous memory page. + // This allows to scan across the memory page boundaries. + #[repr(packed)] + struct Buffer { + _head: [u8; N], + _buffer: [u8; MEM_SIZE] + } + + let buf = + // SAFETY: Using mem::zeroed is safe in this instance as the Buffer struct + // only contains u8, for which zeroed data represent a valid bit pattern. + unsafe { + let mut global_buffer = mem::zeroed::>(); + slice::from_raw_parts_mut(&mut global_buffer as *mut _ as *mut u8, N + MEM_SIZE) + }; + + let first = { + // SAFETY: The buffer is guaranteed to be initialized due + // to using mem::zeroed() so we can safely return an u8 slice of it. + unsafe { slice::from_raw_parts_mut(buf.as_mut_ptr(), N) } + }; + + let last = { + // SAFETY: The buffer is guaranteed to be initialized due + // to using mem::zeroed() so we can safely return an u8 slice of it. + unsafe { slice::from_raw_parts_mut(buf.as_mut_ptr().add(MEM_SIZE), N) } + }; + + let mut last_page_success = false; while addr.value() < overall_end { // We round up to the 4 KiB address boundary as that's a single // page, which is safe to read either fully or not at all. We do - // this to do a single read rather than many small ones as the - // syscall overhead is a quite high. + // this to reduce the number of syscalls as much as possible, as the + // syscall overhead is quite high. let end = (addr.value() & !((4 << 10) - 1)) + (4 << 10).min(overall_end); let len = end - addr.value(); - let current_read_buf = &mut buf[..len as usize]; - if let Ok(current_read_buf) = process.read_into_uninit_buf(addr, current_read_buf) { - if let Some(pos) = self.scan(current_read_buf) { - return Some(addr.add(pos as u64)); + + // If we read the previous memory page successfully, then we can copy the last + // elements to the start of the buffer. Otherwise, we just fill it with zeroes. + if last_page_success { + first.copy_from_slice(last); + last_page_success = false; + } else { + first.fill(0); + } + + if process.read_into_buf(addr, &mut buf[N..][..len as usize]).is_ok() { + last_page_success = true; + if let Some(pos) = self.scan(&mut buf[..len as usize + N]) { + return Some(addr.add(pos as u64).add_signed(-(N as i64))); } }; addr = Address::new(end); From 8af2c3e241802cc4a3af3922798751d50cd4c87c Mon Sep 17 00:00:00 2001 From: Jujstme Date: Mon, 7 Oct 2024 23:01:24 +0200 Subject: [PATCH 2/5] Fix This commit fixes an oversight that would've resulted in UB, and fixed the previously mentioned "issue" with signatures consisting of zeroes. --- src/signature.rs | 64 ++++++++++++++++++++++++++++++++---------------- 1 file changed, 43 insertions(+), 21 deletions(-) diff --git a/src/signature.rs b/src/signature.rs index 4f487f6..8589a7e 100644 --- a/src/signature.rs +++ b/src/signature.rs @@ -199,59 +199,81 @@ impl Signature { let overall_end = addr.value() + len; // The sigscan essentially works by reading one memory page (0x1000 bytes) - // at a time and looking for the signature in each page. - // We create a buffer sligthly larger than 0x1000 bytes in order to keep - // the very first bytes as the tail of the previous memory page. + // at a time and looking for the signature in each page. We create a buffer + // sligthly larger than 0x1000 bytes in order to accomodate the size of + // the memory page + the signature - 1. The very first bytes of the + // buffer are intended to be used as the tail of the previous memory page. // This allows to scan across the memory page boundaries. + + // We should use N - 1 but we resort to MEM_SIZE - 1 to avoid using [feature(generic_const_exprs)] #[repr(packed)] struct Buffer { - _head: [u8; N], - _buffer: [u8; MEM_SIZE] + _head: [u8; N], + _buffer: [u8; MEM_SIZE - 1] } - let buf = + let mut global_buffer = // SAFETY: Using mem::zeroed is safe in this instance as the Buffer struct // only contains u8, for which zeroed data represent a valid bit pattern. unsafe { - let mut global_buffer = mem::zeroed::>(); - slice::from_raw_parts_mut(&mut global_buffer as *mut _ as *mut u8, N + MEM_SIZE) + mem::zeroed::>() }; - let first = { + let buf = // SAFETY: The buffer is guaranteed to be initialized due // to using mem::zeroed() so we can safely return an u8 slice of it. - unsafe { slice::from_raw_parts_mut(buf.as_mut_ptr(), N) } + unsafe { + slice::from_raw_parts_mut(&mut global_buffer as *mut _ as *mut u8, size_of::>()) }; - let last = { + let first = // SAFETY: The buffer is guaranteed to be initialized due // to using mem::zeroed() so we can safely return an u8 slice of it. - unsafe { slice::from_raw_parts_mut(buf.as_mut_ptr().add(MEM_SIZE), N) } + unsafe { + slice::from_raw_parts_mut(buf.as_mut_ptr(), N - 1) }; + let last = + // SAFETY: The buffer is guaranteed to be initialized due + // to using mem::zeroed() so we can safely return an u8 slice of it. + unsafe { + slice::from_raw_parts_mut(buf.as_mut_ptr().add(MEM_SIZE), N - 1) + }; + let mut last_page_success = false; while addr.value() < overall_end { // We round up to the 4 KiB address boundary as that's a single // page, which is safe to read either fully or not at all. We do // this to reduce the number of syscalls as much as possible, as the // syscall overhead is quite high. - let end = (addr.value() & !((4 << 10) - 1)) + (4 << 10).min(overall_end); - let len = end - addr.value(); + let end = ((addr.value() & !((4 << 10) - 1)) + (4 << 10)).min(overall_end); + let len = end.saturating_sub(addr.value()) as usize; // If we read the previous memory page successfully, then we can copy the last // elements to the start of the buffer. Otherwise, we just fill it with zeroes. if last_page_success { first.copy_from_slice(last); - last_page_success = false; - } else { - first.fill(0); } - if process.read_into_buf(addr, &mut buf[N..][..len as usize]).is_ok() { - last_page_success = true; - if let Some(pos) = self.scan(&mut buf[..len as usize + N]) { - return Some(addr.add(pos as u64).add_signed(-(N as i64))); + if process.read_into_buf(addr, &mut buf[N - 1..][..len]).is_ok() { + // If the previous memory page has been read successfully, then we have copied + // the last N - 1 bytes to the start of the buf array, and we need to check + // starting from those in order to correctly identify possible signatures crossing + // memory page boundaries + if last_page_success { + if let Some(pos) = self.scan(&mut buf[..len + N - 1]) { + return Some(addr.add(pos as u64).add_signed(-(N as i64 - 1))); + } + // If the prevbious memory page wasn't read successfully, the first N - 1 + // bytes are excluded from the signature verification + } else { + if let Some(pos) = self.scan(&mut buf[N - 1..][..len]) { + return Some(addr.add(pos as u64)); + } } + + last_page_success = true; + }; addr = Address::new(end); } From d7228779a99c64d28400fe41954960d7884afb4e Mon Sep 17 00:00:00 2001 From: Jujstme Date: Sat, 12 Oct 2024 15:29:09 +0200 Subject: [PATCH 3/5] Reimplemented to return an iterator --- src/emulator/gba/mednafen.rs | 14 +- src/emulator/gba/nocashgba.rs | 7 +- src/emulator/gba/retroarch.rs | 22 +- src/emulator/gba/vba.rs | 28 +- src/emulator/genesis/blastem.rs | 11 +- src/emulator/genesis/fusion.rs | 7 +- src/emulator/genesis/gens.rs | 7 +- src/emulator/genesis/retroarch.rs | 33 +- src/emulator/genesis/segaclassics.rs | 9 +- src/emulator/ps1/duckstation.rs | 8 +- src/emulator/ps1/epsxe.rs | 7 +- src/emulator/ps1/mednafen.rs | 10 +- src/emulator/ps1/pcsx_redux.rs | 13 +- src/emulator/ps1/psxfin.rs | 29 +- src/emulator/ps1/retroarch.rs | 36 +-- src/emulator/ps1/xebra.rs | 7 +- src/emulator/ps2/pcsx2.rs | 12 +- src/emulator/ps2/retroarch.rs | 10 +- src/emulator/sms/blastem.rs | 11 +- src/emulator/sms/fusion.rs | 7 +- src/emulator/sms/mednafen.rs | 10 +- src/emulator/sms/retroarch.rs | 20 +- src/future/mod.rs | 18 -- src/game_engine/unity/il2cpp.rs | 30 +- src/game_engine/unity/mono.rs | 22 +- src/game_engine/unity/scene.rs | 15 +- src/game_engine/unreal/mod.rs | 15 +- src/signature.rs | 449 +++++++++++++++++---------- 28 files changed, 519 insertions(+), 348 deletions(-) diff --git a/src/emulator/gba/mednafen.rs b/src/emulator/gba/mednafen.rs index 6b9e4c3..a96fcfa 100644 --- a/src/emulator/gba/mednafen.rs +++ b/src/emulator/gba/mednafen.rs @@ -1,4 +1,8 @@ -use crate::{file_format::pe, signature::Signature, Address, Address32, Address64, Error, Process}; +use crate::{ + file_format::pe, + signature::{Signature, SignatureScanner}, + Address, Address32, Address64, Error, Process, +}; #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub struct State { @@ -20,7 +24,7 @@ impl State { if self.is_64_bit { self.cached_ewram_pointer = { const SIG: Signature<13> = Signature::new("48 8B 05 ?? ?? ?? ?? 81 E1 FF FF 03 00"); - let ptr: Address = SIG.scan_process_range(game, main_module_range)? + 3; + let ptr: Address = SIG.scan(game, main_module_range.0, main_module_range.1)? + 3; let mut addr: Address = ptr + 0x4 + game.read::(ptr).ok()?; if game.read::(ptr + 10).ok()? == 0x48 { @@ -36,7 +40,7 @@ impl State { self.cached_iwram_pointer = { const SIG2: Signature<13> = Signature::new("48 8B 05 ?? ?? ?? ?? 81 E1 FF 7F 00 00"); - let ptr: Address = SIG2.scan_process_range(game, main_module_range)? + 3; + let ptr: Address = SIG2.scan(game, main_module_range.0, main_module_range.1)? + 3; let mut addr: Address = ptr + 0x4 + game.read::(ptr).ok()?; if game.read::(ptr + 10).ok()? == 0x48 { @@ -56,13 +60,13 @@ impl State { } else { self.cached_ewram_pointer = { const SIG: Signature<11> = Signature::new("A1 ?? ?? ?? ?? 81 ?? FF FF 03 00"); - let ptr = SIG.scan_process_range(game, main_module_range)?; + let ptr = SIG.scan(game, main_module_range.0, main_module_range.1)?; game.read::(ptr + 1).ok()?.into() }; self.cached_iwram_pointer = { const SIG2: Signature<11> = Signature::new("A1 ?? ?? ?? ?? 81 ?? FF 7F 00 00"); - let ptr = SIG2.scan_process_range(game, main_module_range)?; + let ptr = SIG2.scan(game, main_module_range.0, main_module_range.1)?; game.read::(ptr + 1).ok()?.into() }; diff --git a/src/emulator/gba/nocashgba.rs b/src/emulator/gba/nocashgba.rs index a7d2a4c..4ef124e 100644 --- a/src/emulator/gba/nocashgba.rs +++ b/src/emulator/gba/nocashgba.rs @@ -1,4 +1,7 @@ -use crate::{signature::Signature, Address, Address32, Process}; +use crate::{ + signature::{Signature, SignatureScanner}, + Address, Address32, Process, +}; #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub struct State { @@ -16,7 +19,7 @@ impl State { .find_map(|(name, _)| game.get_module_range(name).ok())?; self.base_addr = game - .read::(SIG.scan_process_range(game, main_module_range)? + 0x2) + .read::(SIG.scan(game, main_module_range.0, main_module_range.1)? + 0x2) .ok()? .into(); diff --git a/src/emulator/gba/retroarch.rs b/src/emulator/gba/retroarch.rs index c708ce7..446e54f 100644 --- a/src/emulator/gba/retroarch.rs +++ b/src/emulator/gba/retroarch.rs @@ -1,4 +1,8 @@ -use crate::{file_format::pe, signature::Signature, Address, Address32, Address64, Process}; +use crate::{ + file_format::pe, + signature::{Signature, SignatureScanner}, + Address, Address32, Address64, Process, +}; #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub struct State { @@ -47,7 +51,7 @@ impl State { const SIG2: Signature<13> = Signature::new("48 8B 05 ?? ?? ?? ?? 81 E1 FF 7F 00 00"); let ewram_pointer = { - let ptr: Address = SIG.scan_process_range(game, module_range)? + 3; + let ptr: Address = SIG.scan(game, module_range.0, module_range.1)? + 3; let mut addr: Address = ptr + 0x4 + game.read::(ptr).ok()?; if game.read::(ptr + 10).ok()? == 0x48 { @@ -61,7 +65,7 @@ impl State { }; let iwram_pointer = { - let ptr: Address = SIG2.scan_process_range(game, module_range)? + 3; + let ptr: Address = SIG2.scan(game, module_range.0, module_range.1)? + 3; let mut addr: Address = ptr + 0x4 + game.read::(ptr).ok()?; if game.read::(ptr + 10).ok()? == 0x48 { @@ -85,12 +89,12 @@ impl State { } else { let ewram_pointer: Address = { const SIG: Signature<11> = Signature::new("A1 ?? ?? ?? ?? 81 ?? FF FF 03 00"); - let ptr = SIG.scan_process_range(game, module_range)?; + let ptr = SIG.scan(game, module_range.0, module_range.1)?; game.read::(ptr + 1).ok()?.into() }; let iwram_pointer: Address = { const SIG2: Signature<11> = Signature::new("A1 ?? ?? ?? ?? 81 ?? FF 7F 00 00"); - let ptr = SIG2.scan_process_range(game, module_range)?; + let ptr = SIG2.scan(game, module_range.0, module_range.1)?; game.read::(ptr + 1).ok()?.into() }; @@ -114,24 +118,24 @@ impl State { let base_addr: Address = match is_64_bit { true => { const SIG: Signature<10> = Signature::new("48 8B 15 ?? ?? ?? ?? 8B 42 40"); - let ptr = SIG.scan_process_range(game, (self.core_base, module_size))? + 3; + let ptr = SIG.scan(game, self.core_base, module_size)? + 3; let ptr: Address = ptr + 0x4 + game.read::(ptr).ok()?; game.read::(ptr).ok()?.into() } false => { const SIG: Signature<11> = Signature::new("A3 ?? ?? ?? ?? F7 C5 02 00 00 00"); - let ptr = SIG.scan_process_range(game, (self.core_base, module_size))? + 1; + let ptr = SIG.scan(game, self.core_base, module_size)? + 1; game.read::(ptr).ok()?.into() } }; let ewram = { - let offset = SIG_EWRAM.scan_process_range(game, (self.core_base, module_size))? + 8; + let offset = SIG_EWRAM.scan(game, self.core_base, module_size)? + 8; base_addr + game.read::(offset).ok()? }; let iwram = { - let offset = SIG_IWRAM.scan_process_range(game, (self.core_base, module_size))? + 9; + let offset = SIG_IWRAM.scan(game, self.core_base, module_size)? + 9; base_addr + game.read::(offset).ok()? }; diff --git a/src/emulator/gba/vba.rs b/src/emulator/gba/vba.rs index 62f05e8..d4b2172 100644 --- a/src/emulator/gba/vba.rs +++ b/src/emulator/gba/vba.rs @@ -1,4 +1,8 @@ -use crate::{file_format::pe, signature::Signature, Address, Address32, Address64, Error, Process}; +use crate::{ + file_format::pe, + signature::{Signature, SignatureScanner}, + Address, Address32, Address64, Error, Process, +}; #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub struct State { @@ -25,7 +29,7 @@ impl State { const SIG2: Signature<13> = Signature::new("48 8B 05 ?? ?? ?? ?? 81 E3 FF 7F 00 00"); self.cached_ewram_pointer = { - let ptr: Address = SIG.scan_process_range(game, main_module_range)? + 3; + let ptr: Address = SIG.scan(game, main_module_range.0, main_module_range.1)? + 3; let mut addr: Address = ptr + 0x4 + game.read::(ptr).ok()?; if game.read::(ptr + 10).ok()? == 0x48 { @@ -39,7 +43,7 @@ impl State { }; self.cached_iwram_pointer = { - let ptr: Address = SIG2.scan_process_range(game, main_module_range)? + 3; + let ptr: Address = SIG2.scan(game, main_module_range.0, main_module_range.1)? + 3; let mut addr: Address = ptr + 0x4 + game.read::(ptr).ok()?; if game.read::(ptr + 10).ok()? == 0x48 { @@ -58,11 +62,13 @@ impl State { const SIG_RUNNING2: Signature<16> = Signature::new("48 8B 15 ?? ?? ?? ?? 31 C0 8B 12 85 D2 74 ?? 48"); - if let Some(ptr) = SIG_RUNNING.scan_process_range(game, main_module_range) { + if let Some(ptr) = SIG_RUNNING.scan(game, main_module_range.0, main_module_range.1) + { let ptr = ptr + 2; ptr + 0x4 + game.read::(ptr).ok()? + 0x1 } else { - let ptr = SIG_RUNNING2.scan_process_range(game, main_module_range)? + 3; + let ptr = + SIG_RUNNING2.scan(game, main_module_range.0, main_module_range.1)? + 3; let ptr = ptr + 0x4 + game.read::(ptr).ok()?; game.read::(ptr).ok()?.into() } @@ -76,11 +82,11 @@ impl State { const SIG: Signature<11> = Signature::new("A1 ?? ?? ?? ?? 81 ?? FF FF 03 00"); const SIG_OLD: Signature<12> = Signature::new("81 E6 FF FF 03 00 8B 15 ?? ?? ?? ??"); - if let Some(ptr) = SIG.scan_process_range(game, main_module_range) { + if let Some(ptr) = SIG.scan(game, main_module_range.0, main_module_range.1) { self.cached_ewram_pointer = game.read::(ptr + 1).ok()?.into(); self.cached_iwram_pointer = { const SIG2: Signature<11> = Signature::new("A1 ?? ?? ?? ?? 81 ?? FF 7F 00 00"); - let ptr = SIG2.scan_process_range(game, main_module_range)?; + let ptr = SIG2.scan(game, main_module_range.0, main_module_range.1)?; game.read::(ptr + 1).ok()?.into() }; @@ -91,8 +97,8 @@ impl State { Signature::new("8B 15 ?? ?? ?? ?? 31 C0 85 D2 74 ?? 0F"); let ptr = SIG - .scan_process_range(game, main_module_range) - .or_else(|| SIG_OLD.scan_process_range(game, main_module_range))?; + .scan(game, main_module_range.0, main_module_range.1) + .or_else(|| SIG_OLD.scan(game, main_module_range.0, main_module_range.1))?; game.read::(ptr + 2).ok()?.into() }; @@ -101,7 +107,7 @@ impl State { let iwram = game.read::(self.cached_iwram_pointer).ok()?; Some([ewram.into(), iwram.into()]) - } else if let Some(ptr) = SIG_OLD.scan_process_range(game, main_module_range) { + } else if let Some(ptr) = SIG_OLD.scan(game, main_module_range.0, main_module_range.1) { // This code is for very old versions of VisualBoyAdvance (1.8.0-beta 3) self.cached_ewram_pointer = game.read::(ptr + 8).ok()?.into(); self.cached_iwram_pointer = self.cached_ewram_pointer.add_signed(0x4); @@ -109,7 +115,7 @@ impl State { self.is_emulating = { const SIG_RUNNING: Signature<11> = Signature::new("8B 0D ?? ?? ?? ?? 85 C9 74 ?? 8A"); - let ptr = SIG_RUNNING.scan_process_range(game, main_module_range)? + 2; + let ptr = SIG_RUNNING.scan(game, main_module_range.0, main_module_range.1)? + 2; game.read::(ptr).ok()?.into() }; diff --git a/src/emulator/genesis/blastem.rs b/src/emulator/genesis/blastem.rs index b996af4..712da2d 100644 --- a/src/emulator/genesis/blastem.rs +++ b/src/emulator/genesis/blastem.rs @@ -1,4 +1,8 @@ -use crate::{runtime::MemoryRangeFlags, signature::Signature, Address, Address32, Endian, Process}; +use crate::{ + runtime::MemoryRangeFlags, + signature::{Signature, SignatureScanner}, + Address, Address32, Endian, Process, +}; #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub struct State; @@ -18,7 +22,10 @@ impl State { .contains(MemoryRangeFlags::WRITE) && m.size().unwrap_or_default() == 0x101000 }) - .find_map(|m| SIG.scan_process_range(game, m.range().ok()?))? + .find_map(|m| { + let (base, size) = m.range().ok()?; + SIG.scan(game, base, size) + })? + 11; let wram = game.read::(scanned_address).ok()?; diff --git a/src/emulator/genesis/fusion.rs b/src/emulator/genesis/fusion.rs index c1a0582..582343b 100644 --- a/src/emulator/genesis/fusion.rs +++ b/src/emulator/genesis/fusion.rs @@ -1,4 +1,7 @@ -use crate::{signature::Signature, Address, Address32, Endian, Process}; +use crate::{ + signature::{Signature, SignatureScanner}, + Address, Address32, Endian, Process, +}; #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub struct State { @@ -14,7 +17,7 @@ impl State { .filter(|(_, state)| matches!(state, super::State::Fusion(_))) .find_map(|(name, _)| game.get_module_range(name).ok())?; - let ptr = SIG.scan_process_range(game, main_module)? + 1; + let ptr = SIG.scan(game, main_module.0, main_module.1)? + 1; let addr = ptr + game.read::(ptr).ok()? as u64 + 3; let addr = game.read::(addr).ok()?; diff --git a/src/emulator/genesis/gens.rs b/src/emulator/genesis/gens.rs index c8440a5..e8e5a99 100644 --- a/src/emulator/genesis/gens.rs +++ b/src/emulator/genesis/gens.rs @@ -1,4 +1,7 @@ -use crate::{signature::Signature, Address, Address32, Endian, Process}; +use crate::{ + signature::{Signature, SignatureScanner}, + Address, Address32, Endian, Process, +}; #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub struct State; @@ -12,7 +15,7 @@ impl State { .filter(|(_, state)| matches!(state, super::State::Gens(_))) .find_map(|(name, _)| game.get_module_range(name).ok())?; - let ptr = SIG.scan_process_range(game, main_module)? + 11; + let ptr = SIG.scan(game, main_module.0, main_module.1)? + 11; *endian = if game.read::(ptr + 4).ok()? == 0x86 { Endian::Big diff --git a/src/emulator/genesis/retroarch.rs b/src/emulator/genesis/retroarch.rs index eedfd22..17bc6ed 100644 --- a/src/emulator/genesis/retroarch.rs +++ b/src/emulator/genesis/retroarch.rs @@ -1,5 +1,7 @@ use crate::{ - file_format::pe, signature::Signature, Address, Address32, Endian, MemoryRangeFlags, Process, + file_format::pe, + signature::{Signature, SignatureScanner}, + Address, Address32, Endian, MemoryRangeFlags, Process, }; #[derive(Copy, Clone, Debug, PartialEq, Eq)] @@ -45,7 +47,10 @@ impl State { .contains(MemoryRangeFlags::WRITE) && m.size().unwrap_or_default() == 0x101000 }) - .find_map(|m| SIG.scan_process_range(game, m.range().ok()?))? + .find_map(|m| { + let (base, size) = m.range().ok()?; + SIG.scan(game, base, size) + })? + 11; let wram = game.read::(scanned_address).ok()?; @@ -58,10 +63,8 @@ impl State { if is_x86_64 { const SIG_64: Signature<10> = Signature::new("48 8D 0D ?? ?? ?? ?? 4C 8B 2D"); - let addr = SIG_64.scan_process_range( - game, - (core_address, game.get_module_size(core_name).ok()?), - )? + 3; + let addr = + SIG_64.scan(game, core_address, game.get_module_size(core_name).ok()?)? + 3; let wram = addr + 0x4 + game.read::(addr).ok()?; @@ -69,10 +72,8 @@ impl State { } else { const SIG_32: Signature<7> = Signature::new("A3 ?? ?? ?? ?? 29 F9"); - let ptr = SIG_32.scan_process_range( - game, - (core_address, game.get_module_size(core_name).ok()?), - )? + 1; + let ptr = + SIG_32.scan(game, core_address, game.get_module_size(core_name).ok()?)? + 1; let wram = game.read::(ptr).ok()?; @@ -85,10 +86,8 @@ impl State { if is_x86_64 { const SIG_64: Signature<9> = Signature::new("48 8D 0D ?? ?? ?? ?? 41 B8"); - let addr = SIG_64.scan_process_range( - game, - (core_address, game.get_module_size(core_name).ok()?), - )? + 3; + let addr = + SIG_64.scan(game, core_address, game.get_module_size(core_name).ok()?)? + 3; let wram = addr + 0x4 + game.read::(addr).ok()?; @@ -96,10 +95,8 @@ impl State { } else { const SIG_32: Signature<8> = Signature::new("B9 ?? ?? ?? ?? C1 EF 10"); - let ptr = SIG_32.scan_process_range( - game, - (core_address, game.get_module_size(core_name).ok()?), - )? + 1; + let ptr = + SIG_32.scan(game, core_address, game.get_module_size(core_name).ok()?)? + 1; let wram = game.read::(ptr).ok()?; diff --git a/src/emulator/genesis/segaclassics.rs b/src/emulator/genesis/segaclassics.rs index 49b4473..d591af7 100644 --- a/src/emulator/genesis/segaclassics.rs +++ b/src/emulator/genesis/segaclassics.rs @@ -1,4 +1,7 @@ -use crate::{signature::Signature, Address, Address32, Endian, Process}; +use crate::{ + signature::{Signature, SignatureScanner}, + Address, Address32, Endian, Process, +}; #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub struct State { @@ -13,14 +16,14 @@ impl State { const GENESISWRAPPERDLL: &str = "GenesisEmuWrapper.dll"; let mut ptr = if let Ok(module) = game.get_module_range(GENESISWRAPPERDLL) { - SIG_GAMEROOM.scan_process_range(game, module)? + 2 + SIG_GAMEROOM.scan(game, module.0, module.1)? + 2 } else { let main_module = super::PROCESS_NAMES .iter() .filter(|(_, state)| matches!(state, super::State::SegaClassics(_))) .find_map(|(name, _)| game.get_module_range(name).ok())?; - SIG_SEGACLASSICS.scan_process_range(game, main_module)? + 8 + SIG_SEGACLASSICS.scan(game, main_module.0, main_module.1)? + 8 }; ptr = game.read::(ptr).ok()?.into(); diff --git a/src/emulator/ps1/duckstation.rs b/src/emulator/ps1/duckstation.rs index 2967a4a..4f8ad62 100644 --- a/src/emulator/ps1/duckstation.rs +++ b/src/emulator/ps1/duckstation.rs @@ -1,4 +1,8 @@ -use crate::{file_format::pe, signature::Signature, Address, Address64, Process}; +use crate::{ + file_format::pe, + signature::{Signature, SignatureScanner}, + Address, Address64, Process, +}; #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub struct State { @@ -24,7 +28,7 @@ impl State { self.addr = debug_symbol.address; } else { // For older versions of Duckstation, we fall back to regular sigscanning - let addr = SIG.scan_process_range(game, main_module_range)? + 3; + let addr = SIG.scan(game, main_module_range.0, main_module_range.1)? + 3; self.addr = addr + 0x4 + game.read::(addr).ok()?; } diff --git a/src/emulator/ps1/epsxe.rs b/src/emulator/ps1/epsxe.rs index d7461fc..38ff85e 100644 --- a/src/emulator/ps1/epsxe.rs +++ b/src/emulator/ps1/epsxe.rs @@ -1,4 +1,7 @@ -use crate::{signature::Signature, Address, Address32, Process}; +use crate::{ + signature::{Signature, SignatureScanner}, + Address, Address32, Process, +}; #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub struct State; @@ -12,7 +15,7 @@ impl State { .filter(|(_, state)| matches!(state, super::State::Epsxe(_))) .find_map(|(name, _)| game.get_module_range(name).ok())?; - let ptr = SIG.scan_process_range(game, main_module_range)? + 5; + let ptr = SIG.scan(game, main_module_range.0, main_module_range.1)? + 5; Some(game.read::(ptr).ok()?.into()) } diff --git a/src/emulator/ps1/mednafen.rs b/src/emulator/ps1/mednafen.rs index 9d351bb..5dadb60 100644 --- a/src/emulator/ps1/mednafen.rs +++ b/src/emulator/ps1/mednafen.rs @@ -1,4 +1,8 @@ -use crate::{file_format::pe, signature::Signature, Address, Address32, Process}; +use crate::{ + file_format::pe, + signature::{Signature, SignatureScanner}, + Address, Address32, Process, +}; #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub struct State; @@ -17,8 +21,8 @@ impl State { pe::MachineType::read(game, main_module_range.0) == Some(pe::MachineType::X86_64); let ptr = match is_64_bit { - true => SIG_64.scan_process_range(game, main_module_range)?, - false => SIG_32.scan_process_range(game, main_module_range)?, + true => SIG_64.scan(game, main_module_range.0, main_module_range.1)?, + false => SIG_32.scan(game, main_module_range.0, main_module_range.1)?, } + 0x5; Some(game.read::(ptr).ok()?.into()) diff --git a/src/emulator/ps1/pcsx_redux.rs b/src/emulator/ps1/pcsx_redux.rs index b193c0a..327be8b 100644 --- a/src/emulator/ps1/pcsx_redux.rs +++ b/src/emulator/ps1/pcsx_redux.rs @@ -1,5 +1,7 @@ use crate::{ - file_format::pe, signature::Signature, Address, Address32, Address64, MemoryRangeFlags, Process, + file_format::pe, + signature::{Signature, SignatureScanner}, + Address, Address32, Address64, MemoryRangeFlags, Process, }; #[derive(Copy, Clone, Debug, PartialEq, Eq)] @@ -25,10 +27,10 @@ impl State { ); const SIG_OFFSET: Signature<9> = Signature::new("89 D1 C1 E9 10 48 8B ?? ??"); - self.addr_base = SIG_BASE.scan_process_range(game, main_module_range)? + 2; + self.addr_base = SIG_BASE.scan(game, main_module_range.0, main_module_range.1)? + 2; self.addr = game.read::(self.addr_base).ok()?.into(); - let offset = SIG_OFFSET.scan_process_range(game, main_module_range)? + 8; + let offset = SIG_OFFSET.scan(game, main_module_range.0, main_module_range.1)? + 8; let offset = game.read::(offset).ok()? as u64; let addr = game.read::(self.addr + offset).ok()?; @@ -45,7 +47,10 @@ impl State { .unwrap_or_default() .contains(MemoryRangeFlags::WRITE) }) - .find_map(|m| SIG.scan_process_range(game, m.range().ok()?))? + .find_map(|m| { + let (base, size) = m.range().ok()?; + SIG.scan(game, base, size) + })? + 2; self.addr = game.read::(self.addr_base).ok()?.into(); diff --git a/src/emulator/ps1/psxfin.rs b/src/emulator/ps1/psxfin.rs index 73fc5f0..7e3fe1e 100644 --- a/src/emulator/ps1/psxfin.rs +++ b/src/emulator/ps1/psxfin.rs @@ -1,4 +1,7 @@ -use crate::{signature::Signature, Address, Address32, Process}; +use crate::{ + signature::{Signature, SignatureScanner}, + Address, Address32, Process, +}; #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub struct State; @@ -15,18 +18,18 @@ impl State { .filter(|(_, state)| matches!(state, super::State::PsxFin(_))) .find_map(|(name, _)| game.get_module_range(name).ok())?; - let mut ptr: Address32 = if let Some(sig) = SIG.scan_process_range(game, main_module_range) - { - game.read(sig + 2).ok()? - } else if let Some(sig) = SIG_0.scan_process_range(game, main_module_range) { - game.read(sig + 1).ok()? - } else if let Some(sig) = SIG_1.scan_process_range(game, main_module_range) { - game.read(sig + 1).ok()? - } else if let Some(sig) = SIG_2.scan_process_range(game, main_module_range) { - game.read(sig + 1).ok()? - } else { - return None; - }; + let mut ptr: Address32 = + if let Some(sig) = SIG.scan(game, main_module_range.0, main_module_range.1) { + game.read(sig + 2).ok()? + } else if let Some(sig) = SIG_0.scan(game, main_module_range.0, main_module_range.1) { + game.read(sig + 1).ok()? + } else if let Some(sig) = SIG_1.scan(game, main_module_range.0, main_module_range.1) { + game.read(sig + 1).ok()? + } else if let Some(sig) = SIG_2.scan(game, main_module_range.0, main_module_range.1) { + game.read(sig + 1).ok()? + } else { + return None; + }; ptr = game.read::(ptr).ok()?; diff --git a/src/emulator/ps1/retroarch.rs b/src/emulator/ps1/retroarch.rs index 50b7c42..4d061af 100644 --- a/src/emulator/ps1/retroarch.rs +++ b/src/emulator/ps1/retroarch.rs @@ -1,4 +1,8 @@ -use crate::{file_format::pe, signature::Signature, Address, Address32, Address64, Process}; +use crate::{ + file_format::pe, + signature::{Signature, SignatureScanner}, + Address, Address32, Address64, Process, +}; #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub struct State { @@ -33,18 +37,12 @@ impl State { if is_64_bit { const SIG: Signature<14> = Signature::new("48 8B 05 ?? ?? ?? ?? 41 81 E4 FF FF 1F 00"); - let ptr = SIG.scan_process_range( - game, - (core_address, game.get_module_size(core_name).ok()?), - )? + 3; + let ptr = SIG.scan(game, core_address, game.get_module_size(core_name).ok()?)? + 3; let ptr = ptr + 0x4 + game.read::(ptr).ok()?; Some(game.read::(ptr).ok()?.into()) } else { const SIG: Signature<11> = Signature::new("A1 ?? ?? ?? ?? 81 E3 FF FF 1F 00"); - let ptr = SIG.scan_process_range( - game, - (core_address, game.get_module_size(core_name).ok()?), - )? + 1; + let ptr = SIG.scan(game, core_address, game.get_module_size(core_name).ok()?)? + 1; let ptr = game.read::(ptr).ok()?; Some(game.read::(ptr).ok()?.into()) } @@ -53,18 +51,12 @@ impl State { if is_64_bit { const SIG: Signature<15> = Signature::new("48 89 0D ?? ?? ?? ?? 89 35 ?? ?? ?? ?? 89 3D"); - let addr = SIG.scan_process_range( - game, - (core_address, game.get_module_size(core_name).ok()?), - )? + 3; + let addr = SIG.scan(game, core_address, game.get_module_size(core_name).ok()?)? + 3; let ptr = addr + 0x4 + game.read::(addr).ok()?; Some(game.read::(ptr).ok()?.into()) } else { const SIG: Signature<8> = Signature::new("A1 ?? ?? ?? ?? 23 CB 8B"); - let ptr = SIG.scan_process_range( - game, - (core_address, game.get_module_size(core_name).ok()?), - )? + 1; + let ptr = SIG.scan(game, core_address, game.get_module_size(core_name).ok()?)? + 1; let ptr = game.read::(ptr).ok()?; Some(game.read::(ptr).ok()?.into()) } @@ -72,19 +64,13 @@ impl State { // PCSX ReARMed if is_64_bit { const SIG: Signature<9> = Signature::new("48 8B 35 ?? ?? ?? ?? 81 E2"); - let addr = SIG.scan_process_range( - game, - (core_address, game.get_module_size(core_name).ok()?), - )? + 3; + let addr = SIG.scan(game, core_address, game.get_module_size(core_name).ok()?)? + 3; let ptr = addr + 0x4 + game.read::(addr).ok()?; let ptr = game.read::(ptr).ok()?; Some(game.read::(ptr).ok()?.into()) } else { const SIG: Signature<9> = Signature::new("FF FF 1F 00 89 ?? ?? ?? A1"); - let ptr = SIG.scan_process_range( - game, - (core_address, game.get_module_size(core_name).ok()?), - )? + 9; + let ptr = SIG.scan(game, core_address, game.get_module_size(core_name).ok()?)? + 9; let ptr = game.read::(ptr).ok()?; Some(game.read::(ptr).ok()?.into()) } diff --git a/src/emulator/ps1/xebra.rs b/src/emulator/ps1/xebra.rs index 5cbae53..89f9068 100644 --- a/src/emulator/ps1/xebra.rs +++ b/src/emulator/ps1/xebra.rs @@ -1,4 +1,7 @@ -use crate::{signature::Signature, Address, Address32, Process}; +use crate::{ + signature::{Signature, SignatureScanner}, + Address, Address32, Process, +}; #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub struct State; @@ -12,7 +15,7 @@ impl State { .filter(|(_, state)| matches!(state, super::State::Xebra(_))) .find_map(|(name, _)| game.get_module_range(name).ok())?; - let ptr = SIG.scan_process_range(game, main_module_range)? + 1; + let ptr = SIG.scan(game, main_module_range.0, main_module_range.1)? + 1; let addr = ptr + 0x4 + game.read::(ptr).ok()?; let addr = game.read::(addr + 0x16A).ok()?; let addr = game.read::(addr).ok()?; diff --git a/src/emulator/ps2/pcsx2.rs b/src/emulator/ps2/pcsx2.rs index 96b36ab..f60e94c 100644 --- a/src/emulator/ps2/pcsx2.rs +++ b/src/emulator/ps2/pcsx2.rs @@ -1,4 +1,8 @@ -use crate::{file_format::pe, signature::Signature, Address, Address32, Address64, Error, Process}; +use crate::{ + file_format::pe, + signature::{Signature, SignatureScanner}, + Address, Address32, Address64, Error, Process, +}; #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub struct State { @@ -18,15 +22,15 @@ impl State { self.addr_base = if self.is_64_bit { const SIG: Signature<12> = Signature::new("48 8B ?? ?? ?? ?? ?? 25 F0 3F 00 00"); - let ptr = SIG.scan_process_range(game, main_module_range)? + 3; + let ptr = SIG.scan(game, main_module_range.0, main_module_range.1)? + 3; ptr + 0x4 + game.read::(ptr).ok()? } else { const SIG: Signature<11> = Signature::new("8B ?? ?? ?? ?? ?? 25 F0 3F 00 00"); const SIG_ALT: Signature<12> = Signature::new("8B ?? ?? ?? ?? ?? 81 ?? F0 3F 00 00"); - let ptr = if let Some(addr) = SIG.scan_process_range(game, main_module_range) { + let ptr = if let Some(addr) = SIG.scan(game, main_module_range.0, main_module_range.1) { addr + 2 } else { - SIG_ALT.scan_process_range(game, main_module_range)? + 2 + SIG_ALT.scan(game, main_module_range.0, main_module_range.1)? + 2 }; self.read_pointer(game, ptr).ok()? }; diff --git a/src/emulator/ps2/retroarch.rs b/src/emulator/ps2/retroarch.rs index 5b38c76..1aa4f7a 100644 --- a/src/emulator/ps2/retroarch.rs +++ b/src/emulator/ps2/retroarch.rs @@ -1,4 +1,8 @@ -use crate::{file_format::pe, signature::Signature, Address, Address64, Process}; +use crate::{ + file_format::pe, + signature::{Signature, SignatureScanner}, + Address, Address64, Process, +}; #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub struct State { @@ -31,9 +35,7 @@ impl State { let base_addr = { const SIG: Signature<13> = Signature::new("48 8B ?? ?? ?? ?? ?? 81 ?? F0 3F 00 00"); - let ptr = SIG - .scan_process_range(game, (core_address, game.get_module_size(core_name).ok()?))? - + 3; + let ptr = SIG.scan(game, core_address, game.get_module_size(core_name).ok()?)? + 3; ptr + 0x4 + game.read::(ptr).ok()? }; diff --git a/src/emulator/sms/blastem.rs b/src/emulator/sms/blastem.rs index 5a00aef..ef15464 100644 --- a/src/emulator/sms/blastem.rs +++ b/src/emulator/sms/blastem.rs @@ -1,4 +1,8 @@ -use crate::{runtime::MemoryRangeFlags, signature::Signature, Address, Address32, Process}; +use crate::{ + runtime::MemoryRangeFlags, + signature::{Signature, SignatureScanner}, + Address, Address32, Process, +}; #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub struct State; @@ -15,7 +19,10 @@ impl State { .contains(MemoryRangeFlags::WRITE) && m.size().unwrap_or_default() == 0x101000 }) - .find_map(|m| SIG.scan_process_range(game, m.range().ok()?))? + .find_map(|m| { + let (base, size) = m.range().ok()?; + SIG.scan(game, base, size) + })? + 10; let wram: Address = game.read::(scanned_address).ok()?.into(); diff --git a/src/emulator/sms/fusion.rs b/src/emulator/sms/fusion.rs index da4b7c0..f903825 100644 --- a/src/emulator/sms/fusion.rs +++ b/src/emulator/sms/fusion.rs @@ -1,4 +1,7 @@ -use crate::{signature::Signature, Address, Address32, Process}; +use crate::{ + signature::{Signature, SignatureScanner}, + Address, Address32, Process, +}; #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub struct State { @@ -14,7 +17,7 @@ impl State { .filter(|(_, state)| matches!(state, super::State::Fusion(_))) .find_map(|(name, _)| game.get_module_range(name).ok())?; - let ptr = SIG.scan_process_range(game, main_module)? + 4; + let ptr = SIG.scan(game, main_module.0, main_module.1)? + 4; self.addr = game.read::(ptr).ok()?.into(); Some(game.read::(self.addr).ok()?.add(0xC000).into()) diff --git a/src/emulator/sms/mednafen.rs b/src/emulator/sms/mednafen.rs index 569359d..120efaa 100644 --- a/src/emulator/sms/mednafen.rs +++ b/src/emulator/sms/mednafen.rs @@ -1,4 +1,8 @@ -use crate::{file_format::pe, signature::Signature, Address, Address32, Process}; +use crate::{ + file_format::pe, + signature::{Signature, SignatureScanner}, + Address, Address32, Process, +}; #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub struct State; @@ -17,8 +21,8 @@ impl State { pe::MachineType::read(game, main_module_range.0) == Some(pe::MachineType::X86_64); let ptr = match is_64_bit { - true => SIG_64.scan_process_range(game, main_module_range)? + 8, - false => SIG_32.scan_process_range(game, main_module_range)? + 7, + true => SIG_64.scan(game, main_module_range.0, main_module_range.1)? + 8, + false => SIG_32.scan(game, main_module_range.0, main_module_range.1)? + 7, }; Some(game.read::(ptr).ok()?.into()) diff --git a/src/emulator/sms/retroarch.rs b/src/emulator/sms/retroarch.rs index 81db41d..6af64c5 100644 --- a/src/emulator/sms/retroarch.rs +++ b/src/emulator/sms/retroarch.rs @@ -1,5 +1,7 @@ use crate::{ - file_format::pe, signature::Signature, Address, Address32, Address64, PointerSize, Process, + file_format::pe, + signature::{Signature, SignatureScanner}, + Address, Address32, Address64, PointerSize, Process, }; #[derive(Copy, Clone, Debug, PartialEq, Eq)] @@ -48,11 +50,11 @@ impl State { Some( if is_64_bit { const SIG: Signature<9> = Signature::new("48 8D 0D ?? ?? ?? ?? 41 B8"); - let ptr = SIG.scan_process_range(game, (self.core_base, module_size))? + 3; + let ptr = SIG.scan(game, self.core_base, module_size)? + 3; ptr + 0x4 + game.read::(ptr).ok()? } else { const SIG: Signature<8> = Signature::new("B9 ?? ?? ?? ?? C1 EF 10"); - let ptr = SIG.scan_process_range(game, (self.core_base, module_size))? + 1; + let ptr = SIG.scan(game, self.core_base, module_size)? + 1; game.read::(ptr).ok()?.into() } + 0x20000, ) @@ -63,11 +65,11 @@ impl State { Some(if is_64_bit { const SIG: Signature<10> = Signature::new("48 8D 0D ?? ?? ?? ?? 4C 8B 2D"); - let ptr = SIG.scan_process_range(game, (self.core_base, module_size))? + 3; + let ptr = SIG.scan(game, self.core_base, module_size)? + 3; ptr + 0x4 + game.read::(ptr).ok()? } else { const SIG: Signature<7> = Signature::new("A3 ?? ?? ?? ?? 29 F9"); - let ptr = SIG.scan_process_range(game, (self.core_base, module_size))? + 1; + let ptr = SIG.scan(game, self.core_base, module_size)? + 1; game.read::(ptr).ok()?.into() }) } @@ -77,11 +79,11 @@ impl State { Some(if is_64_bit { const SIG: Signature<5> = Signature::new("31 F6 48 C7 05"); - let ptr = SIG.scan_process_range(game, (self.core_base, module_size))? + 5; + let ptr = SIG.scan(game, self.core_base, module_size)? + 5; ptr + 0x8 + game.read::(ptr).ok()? } else { const SIG: Signature<4> = Signature::new("83 FA 02 B8"); - let ptr = SIG.scan_process_range(game, (self.core_base, module_size))? + 4; + let ptr = SIG.scan(game, self.core_base, module_size)? + 4; game.read::(ptr).ok()?.into() }) } @@ -91,7 +93,7 @@ impl State { Some(if is_64_bit { const SIG: Signature<13> = Signature::new("83 ?? 02 75 ?? 48 8B 0D ?? ?? ?? ?? E8"); - let ptr = SIG.scan_process_range(game, (self.core_base, module_size))? + 8; + let ptr = SIG.scan(game, self.core_base, module_size)? + 8; let offset = game .read::(ptr + 13 + 0x4 + game.read::(ptr + 13).ok()? + 3) .ok()?; @@ -109,7 +111,7 @@ impl State { } } else { const SIG: Signature<12> = Signature::new("83 ?? 02 75 ?? 8B ?? ?? ?? ?? ?? E8"); - let ptr = SIG.scan_process_range(game, (self.core_base, module_size))? + 7; + let ptr = SIG.scan(game, self.core_base, module_size)? + 7; let offset = game .read::(ptr + 12 + 0x4 + game.read::(ptr + 12).ok()? + 2) .ok()?; diff --git a/src/future/mod.rs b/src/future/mod.rs index f255429..af0d0ff 100644 --- a/src/future/mod.rs +++ b/src/future/mod.rs @@ -109,8 +109,6 @@ use core::{ task::{Context, Poll}, }; -#[cfg(feature = "signature")] -use crate::signature::Signature; use crate::{Address, Process}; #[cfg(target_os = "wasi")] @@ -254,22 +252,6 @@ impl Process { } } -#[cfg(feature = "signature")] -impl Signature { - /// Asynchronously awaits scanning a process for the signature until it is - /// found. This will scan the address range of the process given. Once the - /// signature is found, the address of the start of the signature is - /// returned. - pub async fn wait_scan_process_range( - &self, - process: &Process, - (addr, len): (impl Into
, u64), - ) -> Address { - let addr = addr.into(); - retry(|| self.scan_process_range(process, (addr, len))).await - } -} - /// A future that executes a future until the process closes. pub struct UntilProcessCloses<'a, F> { process: &'a Process, diff --git a/src/game_engine/unity/il2cpp.rs b/src/game_engine/unity/il2cpp.rs index f6e55b8..b744b4c 100644 --- a/src/game_engine/unity/il2cpp.rs +++ b/src/game_engine/unity/il2cpp.rs @@ -3,8 +3,12 @@ use core::{array, cell::RefCell, iter}; use crate::{ - deep_pointer::DeepPointer, file_format::pe, future::retry, signature::Signature, - string::ArrayCString, Address, Address64, Error, PointerSize, Process, + deep_pointer::DeepPointer, + file_format::pe, + future::retry, + signature::{Signature, SignatureScanner}, + string::ArrayCString, + Address, Address64, Error, PointerSize, Process, }; #[cfg(feature = "derive")] @@ -55,14 +59,14 @@ impl Module { const ASSEMBLIES_TRG_SIG: Signature<12> = Signature::new("48 FF C5 80 3C ?? 00 75 ?? 48 8B 1D"); - let addr = ASSEMBLIES_TRG_SIG.scan_process_range(process, mono_module)? + 12; + let addr = ASSEMBLIES_TRG_SIG.scan(process, mono_module.0, mono_module.1)? + 12; addr + 0x4 + process.read::(addr).ok()? } PointerSize::Bit32 => { const ASSEMBLIES_TRG_SIG: Signature<9> = Signature::new("8A 07 47 84 C0 75 ?? 8B 35"); - let addr = ASSEMBLIES_TRG_SIG.scan_process_range(process, mono_module)? + 9; + let addr = ASSEMBLIES_TRG_SIG.scan(process, mono_module.0, mono_module.1)? + 9; process.read_pointer(addr, pointer_size).ok()? } _ => return None, @@ -73,7 +77,7 @@ impl Module { Signature::new("48 83 3C ?? 00 75 ?? 8B C? E8"); let addr = TYPE_INFO_DEFINITION_TABLE_TRG_SIG - .scan_process_range(process, mono_module)? + .scan(process, mono_module.0, mono_module.1)? .add_signed(-4); process @@ -85,7 +89,7 @@ impl Module { Signature::new("C3 A1 ?? ?? ?? ?? 83 3C ?? 00"); let addr = - TYPE_INFO_DEFINITION_TABLE_TRG_SIG.scan_process_range(process, mono_module)? + 2; + TYPE_INFO_DEFINITION_TABLE_TRG_SIG.scan(process, mono_module.0, mono_module.1)? + 2; process .read_pointer(process.read_pointer(addr, pointer_size).ok()?, pointer_size) @@ -359,7 +363,7 @@ impl Class { &'a self, process: &'a Process, module: &'a Module, - ) -> impl Iterator + '_ { + ) -> impl Iterator + 'a { let mut this_class = Class { class: self.class }; let mut iter_break = this_class.class.is_null(); @@ -835,14 +839,17 @@ fn detect_version(process: &Process) -> Option { const SIG_202X: Signature<6> = Signature::new("00 32 30 32 ?? 2E"); const SIG_2019: Signature<6> = Signature::new("00 32 30 31 39 2E"); - if SIG_202X.scan_process_range(process, unity_module).is_some() { + if SIG_202X + .scan(process, unity_module.0, unity_module.1) + .is_some() + { let il2cpp_version = { const SIG: Signature<14> = Signature::new("48 2B ?? 48 2B ?? ?? ?? ?? ?? 48 F7 ?? 48"); let address = process.get_module_address("GameAssembly.dll").ok()?; let size = pe::read_size_of_image(process, address)? as u64; let ptr = { - let addr = SIG.scan_process_range(process, (address, size))? + 6; + let addr = SIG.scan(process, address, size)? + 6; addr + 0x4 + process.read::(addr).ok()? }; @@ -855,7 +862,10 @@ fn detect_version(process: &Process) -> Option { } else { Version::V2019 }) - } else if SIG_2019.scan_process_range(process, unity_module).is_some() { + } else if SIG_2019 + .scan(process, unity_module.0, unity_module.1) + .is_some() + { Some(Version::V2019) } else { Some(Version::Base) diff --git a/src/game_engine/unity/mono.rs b/src/game_engine/unity/mono.rs index 3e63dc8..fdb282e 100644 --- a/src/game_engine/unity/mono.rs +++ b/src/game_engine/unity/mono.rs @@ -2,8 +2,12 @@ //! backend. use crate::{ - deep_pointer::DeepPointer, file_format::pe, future::retry, signature::Signature, - string::ArrayCString, Address, Address32, Address64, Error, PointerSize, Process, + deep_pointer::DeepPointer, + file_format::pe, + future::retry, + signature::{Signature, SignatureScanner}, + string::ArrayCString, + Address, Address32, Address64, Error, PointerSize, Process, }; use core::{array, cell::RefCell, iter}; @@ -58,18 +62,18 @@ impl Module { let assemblies_pointer: Address = match pointer_size { PointerSize::Bit64 => { const SIG_MONO_64: Signature<3> = Signature::new("48 8B 0D"); - let scan_address: Address = SIG_MONO_64 - .scan_process_range(process, (root_domain_function_address, 0x100))? - + 3; + let scan_address: Address = + SIG_MONO_64.scan(process, root_domain_function_address, 0x100)? + 3; scan_address + 0x4 + process.read::(scan_address).ok()? } PointerSize::Bit32 => { const SIG_32_1: Signature<2> = Signature::new("FF 35"); const SIG_32_2: Signature<2> = Signature::new("8B 0D"); - let ptr = [SIG_32_1, SIG_32_2].iter().find_map(|sig| { - sig.scan_process_range(process, (root_domain_function_address, 0x100)) - })? + 2; + let ptr = [SIG_32_1, SIG_32_2] + .iter() + .find_map(|sig| sig.scan(process, root_domain_function_address, 0x100))? + + 2; process.read::(ptr).ok()?.into() } @@ -973,7 +977,7 @@ fn detect_version(process: &Process) -> Option { const SIG_202X: Signature<6> = Signature::new("00 32 30 32 ?? 2E"); - let Some(addr) = SIG_202X.scan_process_range(process, unity_module) else { + let Some(addr) = SIG_202X.scan(process, unity_module.0, unity_module.1) else { return Some(Version::V2); }; diff --git a/src/game_engine/unity/scene.rs b/src/game_engine/unity/scene.rs index 51c3214..5370bae 100644 --- a/src/game_engine/unity/scene.rs +++ b/src/game_engine/unity/scene.rs @@ -9,8 +9,11 @@ use core::{array, iter, mem::MaybeUninit}; use crate::{ - file_format::pe, future::retry, signature::Signature, string::ArrayCString, Address, Address32, - Address64, Error, PointerSize, Process, + file_format::pe, + future::retry, + signature::{Signature, SignatureScanner}, + string::ArrayCString, + Address, Address32, Address64, Error, PointerSize, Process, }; const CSTR: usize = 128; @@ -47,13 +50,13 @@ impl SceneManager { // There are multiple signatures that can be used, depending on the version of Unity // used in the target game. let base_address: Address = if pointer_size == PointerSize::Bit64 { - let addr = SIG_64_BIT.scan_process_range(process, unity_player)? + 7; + let addr = SIG_64_BIT.scan(process, unity_player.0, unity_player.1)? + 7; addr + 0x4 + process.read::(addr).ok()? - } else if let Some(addr) = SIG_32_1.scan_process_range(process, unity_player) { + } else if let Some(addr) = SIG_32_1.scan(process, unity_player.0, unity_player.1) { process.read::(addr + 5).ok()?.into() - } else if let Some(addr) = SIG_32_2.scan_process_range(process, unity_player) { + } else if let Some(addr) = SIG_32_2.scan(process, unity_player.0, unity_player.1) { process.read::(addr.add_signed(-4)).ok()?.into() - } else if let Some(addr) = SIG_32_3.scan_process_range(process, unity_player) { + } else if let Some(addr) = SIG_32_3.scan(process, unity_player.0, unity_player.1) { process.read::(addr + 7).ok()?.into() } else { return None; diff --git a/src/game_engine/unreal/mod.rs b/src/game_engine/unreal/mod.rs index 761ae08..b651a8f 100644 --- a/src/game_engine/unreal/mod.rs +++ b/src/game_engine/unreal/mod.rs @@ -10,8 +10,11 @@ use core::{ use bytemuck::CheckedBitPattern; use crate::{ - file_format::pe, future::retry, signature::Signature, string::ArrayCString, Address, Error, - PointerSize, Process, + file_format::pe, + future::retry, + signature::{Signature, SignatureScanner}, + string::ArrayCString, + Address, Error, PointerSize, Process, }; const CSTR: usize = 128; @@ -50,7 +53,7 @@ impl Module { ]; let addr = GENGINE.iter().find_map(|(sig, offset)| { - Some(sig.scan_process_range(process, module_range)? + *offset) + Some(sig.scan(process, module_range.0, module_range.1)? + *offset) })?; addr + 0x8 + process.read::(addr).ok()? }; @@ -62,7 +65,7 @@ impl Module { )]; let addr = GWORLD.iter().find_map(|(sig, offset)| { - Some(sig.scan_process_range(process, module_range)? + *offset) + Some(sig.scan(process, module_range.0, module_range.1)? + *offset) })?; addr + 0x4 + process.read::(addr).ok()? }; @@ -75,7 +78,7 @@ impl Module { ]; let addr = FNAME_POOL.iter().find_map(|(sig, offset)| { - Some(sig.scan_process_range(process, module_range)? + *offset) + Some(sig.scan(process, module_range.0, module_range.1)? + *offset) })?; addr + 0x4 + process.read::(addr).ok()? }; @@ -217,7 +220,7 @@ impl UClass { &'a self, process: &'a Process, module: &'a Module, - ) -> impl FusedIterator + '_ { + ) -> impl FusedIterator + 'a { // Logic: properties are contained in a linked list that can be accessed directly // through the `property_link` field, from the most derived to the least derived class. // Source: https://gist.github.com/apple1417/b23f91f7a9e3b834d6d052d35a0010ff#object-structure diff --git a/src/signature.rs b/src/signature.rs index 8589a7e..879c8d9 100644 --- a/src/signature.rs +++ b/src/signature.rs @@ -1,18 +1,18 @@ //! Support for finding patterns in a process's memory. -use core::{mem, slice}; - -use bytemuck::AnyBitPattern; - -use crate::{Address, Process}; +use crate::{future::retry, Address, Process}; +use core::{ + iter, + mem::{self, MaybeUninit}, + slice, +}; type Offset = u8; -/// A signature that can be used to find a pattern in a process. It is -/// recommended to store this in a `static` or `const` variable to ensure that -/// the signature is parsed at compile time, which enables the code to be -/// optimized a lot more. Additionally it is recommend to compile the code with -/// the `simd128` target feature to enable the use of SIMD instructions. +/// A signature that can be used to find a pattern in a process's memory. +/// It is recommended to store this in a `static` or `const` variable to ensure +/// that the signature is parsed at compile time, which allows optimizations. +/// Also, compiling with the `simd128` feature is recommended for SIMD support. #[allow(clippy::large_enum_variant)] #[derive(Debug)] pub enum Signature { @@ -29,6 +29,7 @@ pub enum Signature { }, } +/// A helper struct to parse a hexadecimal signature string into bytes. struct Parser<'a> { bytes: &'a [u8], } @@ -41,12 +42,12 @@ impl Parser<'_> { let b: u8 = *b; return ( Some(match b { - b'0'..=b'9' => b - b'0', - b'a'..=b'f' => b - b'a' + 0xA, - b'A'..=b'F' => b - b'A' + 0xA, - b'?' => 0x10, - b' ' | b'\r' | b'\n' | b'\t' => continue, - _ => panic!("Invalid byte"), + b'0'..=b'9' => b - b'0', // Convert '0'-'9' to their numeric value + b'a'..=b'f' => b - b'a' + 0xA, // Convert 'a'-'f' to their numeric value + b'A'..=b'F' => b - b'A' + 0xA, // Convert 'A'-'F' to their numeric value + b'?' => 0x10, // Treat wildcard ('?') as a special byte + b' ' | b'\r' | b'\n' | b'\t' => continue, // Skip whitespace + _ => panic!("Invalid byte"), // Invalid characters cause a panic }), self, ); @@ -55,6 +56,7 @@ impl Parser<'_> { } } +/// Checks if a slice of bytes contains the specified `search_byte`. #[inline] const fn contains(mut bytes: &[u8], search_byte: u8) -> bool { while let [b, rem @ ..] = bytes { @@ -69,13 +71,13 @@ const fn contains(mut bytes: &[u8], search_byte: u8) -> bool { impl Signature { /// Creates a new signature from a string. The string must be a hexadecimal /// string with `?` as wildcard. It is recommended to store this in a - /// `static` or `const` variable to ensure that the signature is parsed at - /// compile time, which enables the code to be optimized a lot more. + /// `static` or `const` variable to ensure that the signature is parted + /// at compile time, which allows optimizations. /// /// # Panics /// - /// This function panics if the signature is invalid. It also panics if the - /// signature is longer than 255 bytes. + /// This function panics if the signature is invalid or if its length + /// exceeds 255 bytes. /// /// # Example /// @@ -92,6 +94,7 @@ impl Signature { bytes: signature.as_bytes(), }; + // Check if the signature contains wildcards if contains(signature.as_bytes(), b'?') { let mut needle = [0; N]; let mut mask = [0; N]; @@ -109,13 +112,15 @@ impl Signature { mask[i] = mask_byte; i += 1; } - assert!(i == N); + assert!(i == N); // Ensure we parsed the correct number of bytes + // Initialize skip_offsets with all zeros let mut skip_offsets = [0; 256]; let mut unknown = 0; let end = N - 1; let mut i = 0; + while i < end { let byte = needle[i]; let mask = mask[i]; @@ -131,6 +136,7 @@ impl Signature { unknown = N as Offset; } + // Set the skip offsets for any byte that wasn't explicitly set i = 0; while i < skip_offsets.len() { if unknown < skip_offsets[i] || skip_offsets[i] == 0 { @@ -145,6 +151,7 @@ impl Signature { skip_offsets, } } else { + // If the provided string has no wildcards, treat as a Simple signature let mut needle = [0; N]; let mut i = 0; @@ -164,42 +171,201 @@ impl Signature { } } - fn scan(&self, haystack: &[u8]) -> Option { - match self { - Signature::Simple(needle) => memchr::memmem::find(haystack, needle), - Signature::Complex { - needle, - mask, - skip_offsets, - } => { - let mut current = 0; - let end = N - 1; - while let Some(scan) = strip_pod::<[u8; N]>(&mut &haystack[current..]) { - if matches(scan, needle, mask) { - return Some(current); + /// Performs a signature scan over a provided slice. + /// Returns an iterator over the positions where the signature matches. + fn scan_internal<'a>(&'a self, haystack: &'a [u8]) -> impl Iterator + 'a { + let mut cursor = 0; + let end = haystack.len().saturating_sub(N.saturating_sub(1)); + + iter::from_fn(move || 'outer: loop { + if cursor >= end { + return None; + } + + match self { + Signature::Simple(needle) => { + match memchr::memmem::find(&haystack[cursor..], needle) { + Some(offset) => { + let current_cursor = cursor; + cursor += offset + 1; + return Some(offset + current_cursor); + } + None => return None, + }; + } + Signature::Complex { + needle, + mask, + skip_offsets, + } => { + let mut i = 0; + + unsafe { + let (scan, mut needle, mut mask) = ( + haystack.as_ptr().add(cursor), + needle.as_ptr(), + mask.as_ptr(), + ); + + #[cfg(target_feature = "simd128")] + while i + 16 <= N { + use core::arch::wasm32::{u8x16_ne, v128, v128_and, v128_any_true}; + + if v128_any_true(u8x16_ne( + v128_and( + scan.add(i).cast::().read_unaligned(), + mask.cast::().read_unaligned(), + ), + needle.cast::().read_unaligned(), + )) { + cursor += + skip_offsets[*scan.add(N.saturating_sub(1)) as usize] as usize; + continue 'outer; + } else { + mask = mask.add(16); + needle = needle.add(16); + i += 16; + } + } + + while i + 8 <= N { + if scan.add(i).cast::().read_unaligned() + & mask.cast::().read_unaligned() + != needle.cast::().read_unaligned() + { + cursor += + skip_offsets[*scan.add(N.saturating_sub(1)) as usize] as usize; + continue 'outer; + } else { + mask = mask.add(8); + needle = needle.add(8); + i += 8; + } + } + + while i + 4 <= N { + if scan.add(i).cast::().read_unaligned() + & mask.cast::().read_unaligned() + != needle.cast::().read_unaligned() + { + cursor += + skip_offsets[*scan.add(N.saturating_sub(1)) as usize] as usize; + continue 'outer; + } else { + mask = mask.add(4); + needle = needle.add(4); + i += 4; + } + } + + while i + 2 <= N { + if scan.add(i).cast::().read_unaligned() + & mask.cast::().read_unaligned() + != needle.cast::().read_unaligned() + { + cursor += + skip_offsets[*scan.add(N.saturating_sub(1)) as usize] as usize; + continue 'outer; + } else { + mask = mask.add(2); + needle = needle.add(2); + i += 2; + } + } + + while i < N { + if *scan.add(i) & *mask != *needle { + cursor += + skip_offsets[*scan.add(N.saturating_sub(1)) as usize] as usize; + continue 'outer; + } else { + mask = mask.add(1); + needle = needle.add(1); + i += 1; + } + } + + let current_cursor = cursor; + cursor = cursor + 1; + return Some(current_cursor); } - let offset = skip_offsets[scan[end] as usize]; - current += offset as usize; } - None } - } + }) + .fuse() } +} + +/// Trait that provides scanning methods for the `Signature` type. +pub trait SignatureScanner { + /// Scans a process's memory in the given range for the first occurrence of the signature. + /// + /// # Arguments + /// + /// * `process` - A reference to the `Process` in which the scan occurs. + /// * `addr` - The starting address of the memory range. + /// * `len` - The length of the memory range to scan. + /// + /// Returns `Some(Address)` of the first match if found, otherwise `None`. + fn scan<'a>(&'a self, process: &Process, addr: impl Into
, len: u64) + -> Option
; - /// Scans a process for the signature. This will scan the address range of - /// the process given. If the signature is found, the address of the start - /// of the signature is returned. - pub fn scan_process_range( + /// Returns an iterator over all occurrences of the signature in the process's memory range. + /// + /// # Arguments + /// + /// * `process` - A reference to the `Process` in which the scan occurs. + /// * `addr` - The starting address of the memory range. + /// * `len` - The length of the memory range to scan. + /// + /// Returns an iterator that yields each matching address. + fn scan_process_range<'a>( + &'a self, + process: &'a Process, + addr: impl Into
, + len: u64, + ) -> impl Iterator + 'a; + + /// Asynchronously awaits scanning a process for the signature until a match + /// is found. + /// + /// # Arguments + /// + /// * `process` - A reference to the `Process` in which the scan occurs. + /// * `addr` - The starting address of the memory range. + /// * `len` - The length of the memory range to scan. + #[allow(async_fn_in_trait)] + async fn wait_scan_process_range( &self, process: &Process, - (addr, len): (impl Into
, u64), + addr: impl Into
, + len: u64, + ) -> Address; +} + +impl SignatureScanner for Signature { + fn scan<'a>( + &'a self, + process: &'a Process, + addr: impl Into
, + len: u64, ) -> Option
{ + self.scan_process_range(process, addr, len).next() + } + + fn scan_process_range<'a>( + &'a self, + process: &'a Process, + addr: impl Into
, + len: u64, + ) -> impl Iterator + 'a { const MEM_SIZE: usize = 0x1000; + let mut addr: Address = Into::into(addr); let overall_end = addr.value() + len; // The sigscan essentially works by reading one memory page (0x1000 bytes) - // at a time and looking for the signature in each page. We create a buffer + // at a time and looking for the signature in each page. We will create a buffer // sligthly larger than 0x1000 bytes in order to accomodate the size of // the memory page + the signature - 1. The very first bytes of the // buffer are intended to be used as the tail of the previous memory page. @@ -208,40 +374,31 @@ impl Signature { // We should use N - 1 but we resort to MEM_SIZE - 1 to avoid using [feature(generic_const_exprs)] #[repr(packed)] struct Buffer { - _head: [u8; N], - _buffer: [u8; MEM_SIZE - 1] + _head: [u8; N], + _buffer: [u8; MEM_SIZE - 1], } - let mut global_buffer = - // SAFETY: Using mem::zeroed is safe in this instance as the Buffer struct - // only contains u8, for which zeroed data represent a valid bit pattern. - unsafe { - mem::zeroed::>() - }; + // The tail of the previous memory page, if read correctly, is stored here + let mut tail = [0; N]; + let mut last_page_success = false; - let buf = - // SAFETY: The buffer is guaranteed to be initialized due - // to using mem::zeroed() so we can safely return an u8 slice of it. - unsafe { - slice::from_raw_parts_mut(&mut global_buffer as *mut _ as *mut u8, size_of::>()) - }; + iter::from_fn(move || { + if addr.value() >= overall_end { + return None; + } - let first = - // SAFETY: The buffer is guaranteed to be initialized due - // to using mem::zeroed() so we can safely return an u8 slice of it. - unsafe { - slice::from_raw_parts_mut(buf.as_mut_ptr(), N - 1) - }; + let mut global_buffer = MaybeUninit::>::uninit(); + + let buf = { + // SAFETY: The buffer is not initialized, but we are returning a slice of MaybeUninit, which do not require initialization + unsafe { + slice::from_raw_parts_mut( + &mut global_buffer as *mut _ as *mut MaybeUninit, + size_of::>(), + ) + } + }; - let last = - // SAFETY: The buffer is guaranteed to be initialized due - // to using mem::zeroed() so we can safely return an u8 slice of it. - unsafe { - slice::from_raw_parts_mut(buf.as_mut_ptr().add(MEM_SIZE), N - 1) - }; - - let mut last_page_success = false; - while addr.value() < overall_end { // We round up to the 4 KiB address boundary as that's a single // page, which is safe to read either fully or not at all. We do // this to reduce the number of syscalls as much as possible, as the @@ -250,113 +407,65 @@ impl Signature { let len = end.saturating_sub(addr.value()) as usize; // If we read the previous memory page successfully, then we can copy the last - // elements to the start of the buffer. Otherwise, we just fill it with zeroes. + // elements to the start of the buffer. if last_page_success { - first.copy_from_slice(last); + unsafe { + (buf.as_mut_ptr() as *mut u8).copy_from(tail.as_ptr(), tail.len() - 1); + } } - if process.read_into_buf(addr, &mut buf[N - 1..][..len]).is_ok() { - // If the previous memory page has been read successfully, then we have copied - // the last N - 1 bytes to the start of the buf array, and we need to check - // starting from those in order to correctly identify possible signatures crossing - // memory page boundaries - if last_page_success { - if let Some(pos) = self.scan(&mut buf[..len + N - 1]) { - return Some(addr.add(pos as u64).add_signed(-(N as i64 - 1))); + let current_page_success = process + .read_into_uninit_buf(addr, &mut buf[N - 1..][..len]) + .is_ok(); + + // We define the final slice on which to perform the memory scan into. If we failed to read the memory page, + // this returns an empty slice so the subsequent iterator will result into an empty iterator. + // If we managed to read the current memory page, instead, we check if we have the data from the previous + // memory page if it got read successfully. + let scan_buf = unsafe { + let ptr = if current_page_success { + if last_page_success { + &buf[..len + N - 1] + } else { + &buf[N - 1..][..len] } - // If the prevbious memory page wasn't read successfully, the first N - 1 - // bytes are excluded from the signature verification } else { - if let Some(pos) = self.scan(&mut buf[N - 1..][..len]) { - return Some(addr.add(pos as u64)); - } - } - - last_page_success = true; + &[] + }; + mem::transmute::<&[MaybeUninit], &[u8]>(ptr) }; - addr = Address::new(end); - } - None - } -} -fn matches(scan: &[u8; N], needle: &[u8; N], mask: &[u8; N]) -> bool { - // SAFETY: Before reading individual chunks from the arrays, we check that - // we can still read values of that size. We also read them unaligned as the - // original arrays are entirely unaligned. - unsafe { - let mut i = 0; - let (mut scan, mut needle, mut mask) = (scan.as_ptr(), needle.as_ptr(), mask.as_ptr()); - #[cfg(target_feature = "simd128")] - while i + 16 <= N { - use core::arch::wasm32::{u8x16_ne, v128, v128_and, v128_any_true}; - - if v128_any_true(u8x16_ne( - v128_and( - scan.cast::().read_unaligned(), - mask.cast::().read_unaligned(), - ), - needle.cast::().read_unaligned(), - )) { - return false; - } - scan = scan.add(16); - mask = mask.add(16); - needle = needle.add(16); - i += 16; - } - while i + 8 <= N { - if scan.cast::().read_unaligned() & mask.cast::().read_unaligned() - != needle.cast::().read_unaligned() - { - return false; - } - scan = scan.add(8); - mask = mask.add(8); - needle = needle.add(8); - i += 8; - } - while i + 4 <= N { - if scan.cast::().read_unaligned() & mask.cast::().read_unaligned() - != needle.cast::().read_unaligned() - { - return false; - } - scan = scan.add(4); - mask = mask.add(4); - needle = needle.add(4); - i += 4; - } - while i + 2 <= N { - if scan.cast::().read_unaligned() & mask.cast::().read_unaligned() - != needle.cast::().read_unaligned() - { - return false; - } - scan = scan.add(2); - mask = mask.add(2); - needle = needle.add(2); - i += 2; - } - while i < N { - if *scan & *mask != *needle { - return false; + if current_page_success { + (&mut tail[..N - 1]).copy_from_slice(&scan_buf[scan_buf.len() - (N - 1)..]); } - scan = scan.add(1); - mask = mask.add(1); - needle = needle.add(1); - i += 1; - } - true + + let cur_addr = addr; + let cur_suc = last_page_success; + + addr = Address::new(end); + last_page_success = current_page_success; + + Some(self.scan_internal(&scan_buf).map(move |pos| { + let mut address = cur_addr.add(pos as u64); + + if cur_suc { + address = address.add_signed(-(N as i64 - 1)) + } + + address + })) + }) + .flatten() } -} -fn strip_pod<'a, T: AnyBitPattern>(cursor: &mut &'a [u8]) -> Option<&'a T> { - if cursor.len() < mem::size_of::() { - return None; + async fn wait_scan_process_range( + &self, + process: &Process, + addr: impl Into
, + len: u64, + ) -> Address { + let addr = addr.into(); + retry(|| self.scan_process_range(process, addr, len).next()).await } - let (before, after) = cursor.split_at(mem::size_of::()); - *cursor = after; - Some(bytemuck::from_bytes(before)) } From da55c6c35cfea6c396583a6037c5242cbb849f30 Mon Sep 17 00:00:00 2001 From: Jujstme Date: Fri, 8 Nov 2024 20:42:45 +0100 Subject: [PATCH 4/5] Reimplemented use of ranges in the scan method --- src/emulator/gba/mednafen.rs | 8 ++++---- src/emulator/gba/nocashgba.rs | 2 +- src/emulator/gba/retroarch.rs | 16 +++++++-------- src/emulator/gba/vba.rs | 22 ++++++++++---------- src/emulator/genesis/blastem.rs | 5 +---- src/emulator/genesis/fusion.rs | 2 +- src/emulator/genesis/gens.rs | 2 +- src/emulator/genesis/retroarch.rs | 13 +++++------- src/emulator/genesis/segaclassics.rs | 4 ++-- src/emulator/ps1/duckstation.rs | 2 +- src/emulator/ps1/epsxe.rs | 2 +- src/emulator/ps1/mednafen.rs | 4 ++-- src/emulator/ps1/pcsx_redux.rs | 9 +++------ src/emulator/ps1/psxfin.rs | 23 ++++++++++----------- src/emulator/ps1/retroarch.rs | 18 +++++++++++------ src/emulator/ps1/xebra.rs | 2 +- src/emulator/ps2/pcsx2.rs | 6 +++--- src/emulator/ps2/retroarch.rs | 2 +- src/emulator/sms/blastem.rs | 5 +---- src/emulator/sms/fusion.rs | 2 +- src/emulator/sms/mednafen.rs | 4 ++-- src/emulator/sms/retroarch.rs | 16 +++++++-------- src/game_engine/unity/il2cpp.rs | 30 ++++++++++++---------------- src/game_engine/unity/mono.rs | 13 +++++++----- src/game_engine/unity/scene.rs | 8 ++++---- src/game_engine/unreal/mod.rs | 18 ++++++++--------- src/signature.rs | 28 ++++++++++---------------- 27 files changed, 125 insertions(+), 141 deletions(-) diff --git a/src/emulator/gba/mednafen.rs b/src/emulator/gba/mednafen.rs index a96fcfa..8032df0 100644 --- a/src/emulator/gba/mednafen.rs +++ b/src/emulator/gba/mednafen.rs @@ -24,7 +24,7 @@ impl State { if self.is_64_bit { self.cached_ewram_pointer = { const SIG: Signature<13> = Signature::new("48 8B 05 ?? ?? ?? ?? 81 E1 FF FF 03 00"); - let ptr: Address = SIG.scan(game, main_module_range.0, main_module_range.1)? + 3; + let ptr: Address = SIG.scan(game, main_module_range)? + 3; let mut addr: Address = ptr + 0x4 + game.read::(ptr).ok()?; if game.read::(ptr + 10).ok()? == 0x48 { @@ -40,7 +40,7 @@ impl State { self.cached_iwram_pointer = { const SIG2: Signature<13> = Signature::new("48 8B 05 ?? ?? ?? ?? 81 E1 FF 7F 00 00"); - let ptr: Address = SIG2.scan(game, main_module_range.0, main_module_range.1)? + 3; + let ptr: Address = SIG2.scan(game, main_module_range)? + 3; let mut addr: Address = ptr + 0x4 + game.read::(ptr).ok()?; if game.read::(ptr + 10).ok()? == 0x48 { @@ -60,13 +60,13 @@ impl State { } else { self.cached_ewram_pointer = { const SIG: Signature<11> = Signature::new("A1 ?? ?? ?? ?? 81 ?? FF FF 03 00"); - let ptr = SIG.scan(game, main_module_range.0, main_module_range.1)?; + let ptr = SIG.scan(game, main_module_range)?; game.read::(ptr + 1).ok()?.into() }; self.cached_iwram_pointer = { const SIG2: Signature<11> = Signature::new("A1 ?? ?? ?? ?? 81 ?? FF 7F 00 00"); - let ptr = SIG2.scan(game, main_module_range.0, main_module_range.1)?; + let ptr = SIG2.scan(game, main_module_range)?; game.read::(ptr + 1).ok()?.into() }; diff --git a/src/emulator/gba/nocashgba.rs b/src/emulator/gba/nocashgba.rs index 4ef124e..a6b2c77 100644 --- a/src/emulator/gba/nocashgba.rs +++ b/src/emulator/gba/nocashgba.rs @@ -19,7 +19,7 @@ impl State { .find_map(|(name, _)| game.get_module_range(name).ok())?; self.base_addr = game - .read::(SIG.scan(game, main_module_range.0, main_module_range.1)? + 0x2) + .read::(SIG.scan(game, main_module_range)? + 0x2) .ok()? .into(); diff --git a/src/emulator/gba/retroarch.rs b/src/emulator/gba/retroarch.rs index 446e54f..9186127 100644 --- a/src/emulator/gba/retroarch.rs +++ b/src/emulator/gba/retroarch.rs @@ -51,7 +51,7 @@ impl State { const SIG2: Signature<13> = Signature::new("48 8B 05 ?? ?? ?? ?? 81 E1 FF 7F 00 00"); let ewram_pointer = { - let ptr: Address = SIG.scan(game, module_range.0, module_range.1)? + 3; + let ptr: Address = SIG.scan(game, module_range)? + 3; let mut addr: Address = ptr + 0x4 + game.read::(ptr).ok()?; if game.read::(ptr + 10).ok()? == 0x48 { @@ -65,7 +65,7 @@ impl State { }; let iwram_pointer = { - let ptr: Address = SIG2.scan(game, module_range.0, module_range.1)? + 3; + let ptr: Address = SIG2.scan(game, module_range)? + 3; let mut addr: Address = ptr + 0x4 + game.read::(ptr).ok()?; if game.read::(ptr + 10).ok()? == 0x48 { @@ -89,12 +89,12 @@ impl State { } else { let ewram_pointer: Address = { const SIG: Signature<11> = Signature::new("A1 ?? ?? ?? ?? 81 ?? FF FF 03 00"); - let ptr = SIG.scan(game, module_range.0, module_range.1)?; + let ptr = SIG.scan(game, module_range)?; game.read::(ptr + 1).ok()?.into() }; let iwram_pointer: Address = { const SIG2: Signature<11> = Signature::new("A1 ?? ?? ?? ?? 81 ?? FF 7F 00 00"); - let ptr = SIG2.scan(game, module_range.0, module_range.1)?; + let ptr = SIG2.scan(game, module_range)?; game.read::(ptr + 1).ok()?.into() }; @@ -118,24 +118,24 @@ impl State { let base_addr: Address = match is_64_bit { true => { const SIG: Signature<10> = Signature::new("48 8B 15 ?? ?? ?? ?? 8B 42 40"); - let ptr = SIG.scan(game, self.core_base, module_size)? + 3; + let ptr = SIG.scan(game, (self.core_base, module_size))? + 3; let ptr: Address = ptr + 0x4 + game.read::(ptr).ok()?; game.read::(ptr).ok()?.into() } false => { const SIG: Signature<11> = Signature::new("A3 ?? ?? ?? ?? F7 C5 02 00 00 00"); - let ptr = SIG.scan(game, self.core_base, module_size)? + 1; + let ptr = SIG.scan(game, (self.core_base, module_size))? + 1; game.read::(ptr).ok()?.into() } }; let ewram = { - let offset = SIG_EWRAM.scan(game, self.core_base, module_size)? + 8; + let offset = SIG_EWRAM.scan(game, (self.core_base, module_size))? + 8; base_addr + game.read::(offset).ok()? }; let iwram = { - let offset = SIG_IWRAM.scan(game, self.core_base, module_size)? + 9; + let offset = SIG_IWRAM.scan(game, (self.core_base, module_size))? + 9; base_addr + game.read::(offset).ok()? }; diff --git a/src/emulator/gba/vba.rs b/src/emulator/gba/vba.rs index d4b2172..a421919 100644 --- a/src/emulator/gba/vba.rs +++ b/src/emulator/gba/vba.rs @@ -29,7 +29,7 @@ impl State { const SIG2: Signature<13> = Signature::new("48 8B 05 ?? ?? ?? ?? 81 E3 FF 7F 00 00"); self.cached_ewram_pointer = { - let ptr: Address = SIG.scan(game, main_module_range.0, main_module_range.1)? + 3; + let ptr: Address = SIG.scan(game, main_module_range)? + 3; let mut addr: Address = ptr + 0x4 + game.read::(ptr).ok()?; if game.read::(ptr + 10).ok()? == 0x48 { @@ -43,7 +43,7 @@ impl State { }; self.cached_iwram_pointer = { - let ptr: Address = SIG2.scan(game, main_module_range.0, main_module_range.1)? + 3; + let ptr: Address = SIG2.scan(game, main_module_range)? + 3; let mut addr: Address = ptr + 0x4 + game.read::(ptr).ok()?; if game.read::(ptr + 10).ok()? == 0x48 { @@ -62,13 +62,11 @@ impl State { const SIG_RUNNING2: Signature<16> = Signature::new("48 8B 15 ?? ?? ?? ?? 31 C0 8B 12 85 D2 74 ?? 48"); - if let Some(ptr) = SIG_RUNNING.scan(game, main_module_range.0, main_module_range.1) - { + if let Some(ptr) = SIG_RUNNING.scan(game, main_module_range) { let ptr = ptr + 2; ptr + 0x4 + game.read::(ptr).ok()? + 0x1 } else { - let ptr = - SIG_RUNNING2.scan(game, main_module_range.0, main_module_range.1)? + 3; + let ptr = SIG_RUNNING2.scan(game, main_module_range)? + 3; let ptr = ptr + 0x4 + game.read::(ptr).ok()?; game.read::(ptr).ok()?.into() } @@ -82,11 +80,11 @@ impl State { const SIG: Signature<11> = Signature::new("A1 ?? ?? ?? ?? 81 ?? FF FF 03 00"); const SIG_OLD: Signature<12> = Signature::new("81 E6 FF FF 03 00 8B 15 ?? ?? ?? ??"); - if let Some(ptr) = SIG.scan(game, main_module_range.0, main_module_range.1) { + if let Some(ptr) = SIG.scan(game, main_module_range) { self.cached_ewram_pointer = game.read::(ptr + 1).ok()?.into(); self.cached_iwram_pointer = { const SIG2: Signature<11> = Signature::new("A1 ?? ?? ?? ?? 81 ?? FF 7F 00 00"); - let ptr = SIG2.scan(game, main_module_range.0, main_module_range.1)?; + let ptr = SIG2.scan(game, main_module_range)?; game.read::(ptr + 1).ok()?.into() }; @@ -97,8 +95,8 @@ impl State { Signature::new("8B 15 ?? ?? ?? ?? 31 C0 85 D2 74 ?? 0F"); let ptr = SIG - .scan(game, main_module_range.0, main_module_range.1) - .or_else(|| SIG_OLD.scan(game, main_module_range.0, main_module_range.1))?; + .scan(game, main_module_range) + .or_else(|| SIG_OLD.scan(game, main_module_range))?; game.read::(ptr + 2).ok()?.into() }; @@ -107,7 +105,7 @@ impl State { let iwram = game.read::(self.cached_iwram_pointer).ok()?; Some([ewram.into(), iwram.into()]) - } else if let Some(ptr) = SIG_OLD.scan(game, main_module_range.0, main_module_range.1) { + } else if let Some(ptr) = SIG_OLD.scan(game, main_module_range) { // This code is for very old versions of VisualBoyAdvance (1.8.0-beta 3) self.cached_ewram_pointer = game.read::(ptr + 8).ok()?.into(); self.cached_iwram_pointer = self.cached_ewram_pointer.add_signed(0x4); @@ -115,7 +113,7 @@ impl State { self.is_emulating = { const SIG_RUNNING: Signature<11> = Signature::new("8B 0D ?? ?? ?? ?? 85 C9 74 ?? 8A"); - let ptr = SIG_RUNNING.scan(game, main_module_range.0, main_module_range.1)? + 2; + let ptr = SIG_RUNNING.scan(game, main_module_range)? + 2; game.read::(ptr).ok()?.into() }; diff --git a/src/emulator/genesis/blastem.rs b/src/emulator/genesis/blastem.rs index 712da2d..e4ebe13 100644 --- a/src/emulator/genesis/blastem.rs +++ b/src/emulator/genesis/blastem.rs @@ -22,10 +22,7 @@ impl State { .contains(MemoryRangeFlags::WRITE) && m.size().unwrap_or_default() == 0x101000 }) - .find_map(|m| { - let (base, size) = m.range().ok()?; - SIG.scan(game, base, size) - })? + .find_map(|m| SIG.scan(game, m.range().ok()?))? + 11; let wram = game.read::(scanned_address).ok()?; diff --git a/src/emulator/genesis/fusion.rs b/src/emulator/genesis/fusion.rs index 582343b..021b608 100644 --- a/src/emulator/genesis/fusion.rs +++ b/src/emulator/genesis/fusion.rs @@ -17,7 +17,7 @@ impl State { .filter(|(_, state)| matches!(state, super::State::Fusion(_))) .find_map(|(name, _)| game.get_module_range(name).ok())?; - let ptr = SIG.scan(game, main_module.0, main_module.1)? + 1; + let ptr = SIG.scan(game, main_module)? + 1; let addr = ptr + game.read::(ptr).ok()? as u64 + 3; let addr = game.read::(addr).ok()?; diff --git a/src/emulator/genesis/gens.rs b/src/emulator/genesis/gens.rs index e8e5a99..231f3c8 100644 --- a/src/emulator/genesis/gens.rs +++ b/src/emulator/genesis/gens.rs @@ -15,7 +15,7 @@ impl State { .filter(|(_, state)| matches!(state, super::State::Gens(_))) .find_map(|(name, _)| game.get_module_range(name).ok())?; - let ptr = SIG.scan(game, main_module.0, main_module.1)? + 11; + let ptr = SIG.scan(game, main_module)? + 11; *endian = if game.read::(ptr + 4).ok()? == 0x86 { Endian::Big diff --git a/src/emulator/genesis/retroarch.rs b/src/emulator/genesis/retroarch.rs index 17bc6ed..f967972 100644 --- a/src/emulator/genesis/retroarch.rs +++ b/src/emulator/genesis/retroarch.rs @@ -47,10 +47,7 @@ impl State { .contains(MemoryRangeFlags::WRITE) && m.size().unwrap_or_default() == 0x101000 }) - .find_map(|m| { - let (base, size) = m.range().ok()?; - SIG.scan(game, base, size) - })? + .find_map(|m| SIG.scan(game, m.range().ok()?))? + 11; let wram = game.read::(scanned_address).ok()?; @@ -64,7 +61,7 @@ impl State { const SIG_64: Signature<10> = Signature::new("48 8D 0D ?? ?? ?? ?? 4C 8B 2D"); let addr = - SIG_64.scan(game, core_address, game.get_module_size(core_name).ok()?)? + 3; + SIG_64.scan(game, (core_address, game.get_module_size(core_name).ok()?))? + 3; let wram = addr + 0x4 + game.read::(addr).ok()?; @@ -73,7 +70,7 @@ impl State { const SIG_32: Signature<7> = Signature::new("A3 ?? ?? ?? ?? 29 F9"); let ptr = - SIG_32.scan(game, core_address, game.get_module_size(core_name).ok()?)? + 1; + SIG_32.scan(game, (core_address, game.get_module_size(core_name).ok()?))? + 1; let wram = game.read::(ptr).ok()?; @@ -87,7 +84,7 @@ impl State { const SIG_64: Signature<9> = Signature::new("48 8D 0D ?? ?? ?? ?? 41 B8"); let addr = - SIG_64.scan(game, core_address, game.get_module_size(core_name).ok()?)? + 3; + SIG_64.scan(game, (core_address, game.get_module_size(core_name).ok()?))? + 3; let wram = addr + 0x4 + game.read::(addr).ok()?; @@ -96,7 +93,7 @@ impl State { const SIG_32: Signature<8> = Signature::new("B9 ?? ?? ?? ?? C1 EF 10"); let ptr = - SIG_32.scan(game, core_address, game.get_module_size(core_name).ok()?)? + 1; + SIG_32.scan(game, (core_address, game.get_module_size(core_name).ok()?))? + 1; let wram = game.read::(ptr).ok()?; diff --git a/src/emulator/genesis/segaclassics.rs b/src/emulator/genesis/segaclassics.rs index d591af7..87ce6ac 100644 --- a/src/emulator/genesis/segaclassics.rs +++ b/src/emulator/genesis/segaclassics.rs @@ -16,14 +16,14 @@ impl State { const GENESISWRAPPERDLL: &str = "GenesisEmuWrapper.dll"; let mut ptr = if let Ok(module) = game.get_module_range(GENESISWRAPPERDLL) { - SIG_GAMEROOM.scan(game, module.0, module.1)? + 2 + SIG_GAMEROOM.scan(game, module)? + 2 } else { let main_module = super::PROCESS_NAMES .iter() .filter(|(_, state)| matches!(state, super::State::SegaClassics(_))) .find_map(|(name, _)| game.get_module_range(name).ok())?; - SIG_SEGACLASSICS.scan(game, main_module.0, main_module.1)? + 8 + SIG_SEGACLASSICS.scan(game, main_module)? + 8 }; ptr = game.read::(ptr).ok()?.into(); diff --git a/src/emulator/ps1/duckstation.rs b/src/emulator/ps1/duckstation.rs index 4f8ad62..1ed9ce5 100644 --- a/src/emulator/ps1/duckstation.rs +++ b/src/emulator/ps1/duckstation.rs @@ -28,7 +28,7 @@ impl State { self.addr = debug_symbol.address; } else { // For older versions of Duckstation, we fall back to regular sigscanning - let addr = SIG.scan(game, main_module_range.0, main_module_range.1)? + 3; + let addr = SIG.scan(game, main_module_range)? + 3; self.addr = addr + 0x4 + game.read::(addr).ok()?; } diff --git a/src/emulator/ps1/epsxe.rs b/src/emulator/ps1/epsxe.rs index 38ff85e..c7c3875 100644 --- a/src/emulator/ps1/epsxe.rs +++ b/src/emulator/ps1/epsxe.rs @@ -15,7 +15,7 @@ impl State { .filter(|(_, state)| matches!(state, super::State::Epsxe(_))) .find_map(|(name, _)| game.get_module_range(name).ok())?; - let ptr = SIG.scan(game, main_module_range.0, main_module_range.1)? + 5; + let ptr = SIG.scan(game, main_module_range)? + 5; Some(game.read::(ptr).ok()?.into()) } diff --git a/src/emulator/ps1/mednafen.rs b/src/emulator/ps1/mednafen.rs index 5dadb60..4304571 100644 --- a/src/emulator/ps1/mednafen.rs +++ b/src/emulator/ps1/mednafen.rs @@ -21,8 +21,8 @@ impl State { pe::MachineType::read(game, main_module_range.0) == Some(pe::MachineType::X86_64); let ptr = match is_64_bit { - true => SIG_64.scan(game, main_module_range.0, main_module_range.1)?, - false => SIG_32.scan(game, main_module_range.0, main_module_range.1)?, + true => SIG_64.scan(game, main_module_range)?, + false => SIG_32.scan(game, main_module_range)?, } + 0x5; Some(game.read::(ptr).ok()?.into()) diff --git a/src/emulator/ps1/pcsx_redux.rs b/src/emulator/ps1/pcsx_redux.rs index 327be8b..2761823 100644 --- a/src/emulator/ps1/pcsx_redux.rs +++ b/src/emulator/ps1/pcsx_redux.rs @@ -27,10 +27,10 @@ impl State { ); const SIG_OFFSET: Signature<9> = Signature::new("89 D1 C1 E9 10 48 8B ?? ??"); - self.addr_base = SIG_BASE.scan(game, main_module_range.0, main_module_range.1)? + 2; + self.addr_base = SIG_BASE.scan(game, main_module_range)? + 2; self.addr = game.read::(self.addr_base).ok()?.into(); - let offset = SIG_OFFSET.scan(game, main_module_range.0, main_module_range.1)? + 8; + let offset = SIG_OFFSET.scan(game, main_module_range)? + 8; let offset = game.read::(offset).ok()? as u64; let addr = game.read::(self.addr + offset).ok()?; @@ -47,10 +47,7 @@ impl State { .unwrap_or_default() .contains(MemoryRangeFlags::WRITE) }) - .find_map(|m| { - let (base, size) = m.range().ok()?; - SIG.scan(game, base, size) - })? + .find_map(|m| SIG.scan(game, m.range().ok()?))? + 2; self.addr = game.read::(self.addr_base).ok()?.into(); diff --git a/src/emulator/ps1/psxfin.rs b/src/emulator/ps1/psxfin.rs index 7e3fe1e..42b6090 100644 --- a/src/emulator/ps1/psxfin.rs +++ b/src/emulator/ps1/psxfin.rs @@ -18,18 +18,17 @@ impl State { .filter(|(_, state)| matches!(state, super::State::PsxFin(_))) .find_map(|(name, _)| game.get_module_range(name).ok())?; - let mut ptr: Address32 = - if let Some(sig) = SIG.scan(game, main_module_range.0, main_module_range.1) { - game.read(sig + 2).ok()? - } else if let Some(sig) = SIG_0.scan(game, main_module_range.0, main_module_range.1) { - game.read(sig + 1).ok()? - } else if let Some(sig) = SIG_1.scan(game, main_module_range.0, main_module_range.1) { - game.read(sig + 1).ok()? - } else if let Some(sig) = SIG_2.scan(game, main_module_range.0, main_module_range.1) { - game.read(sig + 1).ok()? - } else { - return None; - }; + let mut ptr: Address32 = if let Some(sig) = SIG.scan(game, main_module_range) { + game.read(sig + 2).ok()? + } else if let Some(sig) = SIG_0.scan(game, main_module_range) { + game.read(sig + 1).ok()? + } else if let Some(sig) = SIG_1.scan(game, main_module_range) { + game.read(sig + 1).ok()? + } else if let Some(sig) = SIG_2.scan(game, main_module_range) { + game.read(sig + 1).ok()? + } else { + return None; + }; ptr = game.read::(ptr).ok()?; diff --git a/src/emulator/ps1/retroarch.rs b/src/emulator/ps1/retroarch.rs index 4d061af..565fe74 100644 --- a/src/emulator/ps1/retroarch.rs +++ b/src/emulator/ps1/retroarch.rs @@ -37,12 +37,14 @@ impl State { if is_64_bit { const SIG: Signature<14> = Signature::new("48 8B 05 ?? ?? ?? ?? 41 81 E4 FF FF 1F 00"); - let ptr = SIG.scan(game, core_address, game.get_module_size(core_name).ok()?)? + 3; + let ptr = + SIG.scan(game, (core_address, game.get_module_size(core_name).ok()?))? + 3; let ptr = ptr + 0x4 + game.read::(ptr).ok()?; Some(game.read::(ptr).ok()?.into()) } else { const SIG: Signature<11> = Signature::new("A1 ?? ?? ?? ?? 81 E3 FF FF 1F 00"); - let ptr = SIG.scan(game, core_address, game.get_module_size(core_name).ok()?)? + 1; + let ptr = + SIG.scan(game, (core_address, game.get_module_size(core_name).ok()?))? + 1; let ptr = game.read::(ptr).ok()?; Some(game.read::(ptr).ok()?.into()) } @@ -51,12 +53,14 @@ impl State { if is_64_bit { const SIG: Signature<15> = Signature::new("48 89 0D ?? ?? ?? ?? 89 35 ?? ?? ?? ?? 89 3D"); - let addr = SIG.scan(game, core_address, game.get_module_size(core_name).ok()?)? + 3; + let addr = + SIG.scan(game, (core_address, game.get_module_size(core_name).ok()?))? + 3; let ptr = addr + 0x4 + game.read::(addr).ok()?; Some(game.read::(ptr).ok()?.into()) } else { const SIG: Signature<8> = Signature::new("A1 ?? ?? ?? ?? 23 CB 8B"); - let ptr = SIG.scan(game, core_address, game.get_module_size(core_name).ok()?)? + 1; + let ptr = + SIG.scan(game, (core_address, game.get_module_size(core_name).ok()?))? + 1; let ptr = game.read::(ptr).ok()?; Some(game.read::(ptr).ok()?.into()) } @@ -64,13 +68,15 @@ impl State { // PCSX ReARMed if is_64_bit { const SIG: Signature<9> = Signature::new("48 8B 35 ?? ?? ?? ?? 81 E2"); - let addr = SIG.scan(game, core_address, game.get_module_size(core_name).ok()?)? + 3; + let addr = + SIG.scan(game, (core_address, game.get_module_size(core_name).ok()?))? + 3; let ptr = addr + 0x4 + game.read::(addr).ok()?; let ptr = game.read::(ptr).ok()?; Some(game.read::(ptr).ok()?.into()) } else { const SIG: Signature<9> = Signature::new("FF FF 1F 00 89 ?? ?? ?? A1"); - let ptr = SIG.scan(game, core_address, game.get_module_size(core_name).ok()?)? + 9; + let ptr = + SIG.scan(game, (core_address, game.get_module_size(core_name).ok()?))? + 9; let ptr = game.read::(ptr).ok()?; Some(game.read::(ptr).ok()?.into()) } diff --git a/src/emulator/ps1/xebra.rs b/src/emulator/ps1/xebra.rs index 89f9068..a27987b 100644 --- a/src/emulator/ps1/xebra.rs +++ b/src/emulator/ps1/xebra.rs @@ -15,7 +15,7 @@ impl State { .filter(|(_, state)| matches!(state, super::State::Xebra(_))) .find_map(|(name, _)| game.get_module_range(name).ok())?; - let ptr = SIG.scan(game, main_module_range.0, main_module_range.1)? + 1; + let ptr = SIG.scan(game, main_module_range)? + 1; let addr = ptr + 0x4 + game.read::(ptr).ok()?; let addr = game.read::(addr + 0x16A).ok()?; let addr = game.read::(addr).ok()?; diff --git a/src/emulator/ps2/pcsx2.rs b/src/emulator/ps2/pcsx2.rs index f60e94c..dd35420 100644 --- a/src/emulator/ps2/pcsx2.rs +++ b/src/emulator/ps2/pcsx2.rs @@ -22,15 +22,15 @@ impl State { self.addr_base = if self.is_64_bit { const SIG: Signature<12> = Signature::new("48 8B ?? ?? ?? ?? ?? 25 F0 3F 00 00"); - let ptr = SIG.scan(game, main_module_range.0, main_module_range.1)? + 3; + let ptr = SIG.scan(game, main_module_range)? + 3; ptr + 0x4 + game.read::(ptr).ok()? } else { const SIG: Signature<11> = Signature::new("8B ?? ?? ?? ?? ?? 25 F0 3F 00 00"); const SIG_ALT: Signature<12> = Signature::new("8B ?? ?? ?? ?? ?? 81 ?? F0 3F 00 00"); - let ptr = if let Some(addr) = SIG.scan(game, main_module_range.0, main_module_range.1) { + let ptr = if let Some(addr) = SIG.scan(game, main_module_range) { addr + 2 } else { - SIG_ALT.scan(game, main_module_range.0, main_module_range.1)? + 2 + SIG_ALT.scan(game, main_module_range)? + 2 }; self.read_pointer(game, ptr).ok()? }; diff --git a/src/emulator/ps2/retroarch.rs b/src/emulator/ps2/retroarch.rs index 1aa4f7a..cca62d6 100644 --- a/src/emulator/ps2/retroarch.rs +++ b/src/emulator/ps2/retroarch.rs @@ -35,7 +35,7 @@ impl State { let base_addr = { const SIG: Signature<13> = Signature::new("48 8B ?? ?? ?? ?? ?? 81 ?? F0 3F 00 00"); - let ptr = SIG.scan(game, core_address, game.get_module_size(core_name).ok()?)? + 3; + let ptr = SIG.scan(game, (core_address, game.get_module_size(core_name).ok()?))? + 3; ptr + 0x4 + game.read::(ptr).ok()? }; diff --git a/src/emulator/sms/blastem.rs b/src/emulator/sms/blastem.rs index ef15464..4dcc67d 100644 --- a/src/emulator/sms/blastem.rs +++ b/src/emulator/sms/blastem.rs @@ -19,10 +19,7 @@ impl State { .contains(MemoryRangeFlags::WRITE) && m.size().unwrap_or_default() == 0x101000 }) - .find_map(|m| { - let (base, size) = m.range().ok()?; - SIG.scan(game, base, size) - })? + .find_map(|m| SIG.scan(game, m.range().ok()?))? + 10; let wram: Address = game.read::(scanned_address).ok()?.into(); diff --git a/src/emulator/sms/fusion.rs b/src/emulator/sms/fusion.rs index f903825..6c21e94 100644 --- a/src/emulator/sms/fusion.rs +++ b/src/emulator/sms/fusion.rs @@ -17,7 +17,7 @@ impl State { .filter(|(_, state)| matches!(state, super::State::Fusion(_))) .find_map(|(name, _)| game.get_module_range(name).ok())?; - let ptr = SIG.scan(game, main_module.0, main_module.1)? + 4; + let ptr = SIG.scan(game, main_module)? + 4; self.addr = game.read::(ptr).ok()?.into(); Some(game.read::(self.addr).ok()?.add(0xC000).into()) diff --git a/src/emulator/sms/mednafen.rs b/src/emulator/sms/mednafen.rs index 120efaa..00cb563 100644 --- a/src/emulator/sms/mednafen.rs +++ b/src/emulator/sms/mednafen.rs @@ -21,8 +21,8 @@ impl State { pe::MachineType::read(game, main_module_range.0) == Some(pe::MachineType::X86_64); let ptr = match is_64_bit { - true => SIG_64.scan(game, main_module_range.0, main_module_range.1)? + 8, - false => SIG_32.scan(game, main_module_range.0, main_module_range.1)? + 7, + true => SIG_64.scan(game, main_module_range)? + 8, + false => SIG_32.scan(game, main_module_range)? + 7, }; Some(game.read::(ptr).ok()?.into()) diff --git a/src/emulator/sms/retroarch.rs b/src/emulator/sms/retroarch.rs index 6af64c5..5f4d6dc 100644 --- a/src/emulator/sms/retroarch.rs +++ b/src/emulator/sms/retroarch.rs @@ -50,11 +50,11 @@ impl State { Some( if is_64_bit { const SIG: Signature<9> = Signature::new("48 8D 0D ?? ?? ?? ?? 41 B8"); - let ptr = SIG.scan(game, self.core_base, module_size)? + 3; + let ptr = SIG.scan(game, (self.core_base, module_size))? + 3; ptr + 0x4 + game.read::(ptr).ok()? } else { const SIG: Signature<8> = Signature::new("B9 ?? ?? ?? ?? C1 EF 10"); - let ptr = SIG.scan(game, self.core_base, module_size)? + 1; + let ptr = SIG.scan(game, (self.core_base, module_size))? + 1; game.read::(ptr).ok()?.into() } + 0x20000, ) @@ -65,11 +65,11 @@ impl State { Some(if is_64_bit { const SIG: Signature<10> = Signature::new("48 8D 0D ?? ?? ?? ?? 4C 8B 2D"); - let ptr = SIG.scan(game, self.core_base, module_size)? + 3; + let ptr = SIG.scan(game, (self.core_base, module_size))? + 3; ptr + 0x4 + game.read::(ptr).ok()? } else { const SIG: Signature<7> = Signature::new("A3 ?? ?? ?? ?? 29 F9"); - let ptr = SIG.scan(game, self.core_base, module_size)? + 1; + let ptr = SIG.scan(game, (self.core_base, module_size))? + 1; game.read::(ptr).ok()?.into() }) } @@ -79,11 +79,11 @@ impl State { Some(if is_64_bit { const SIG: Signature<5> = Signature::new("31 F6 48 C7 05"); - let ptr = SIG.scan(game, self.core_base, module_size)? + 5; + let ptr = SIG.scan(game, (self.core_base, module_size))? + 5; ptr + 0x8 + game.read::(ptr).ok()? } else { const SIG: Signature<4> = Signature::new("83 FA 02 B8"); - let ptr = SIG.scan(game, self.core_base, module_size)? + 4; + let ptr = SIG.scan(game, (self.core_base, module_size))? + 4; game.read::(ptr).ok()?.into() }) } @@ -93,7 +93,7 @@ impl State { Some(if is_64_bit { const SIG: Signature<13> = Signature::new("83 ?? 02 75 ?? 48 8B 0D ?? ?? ?? ?? E8"); - let ptr = SIG.scan(game, self.core_base, module_size)? + 8; + let ptr = SIG.scan(game, (self.core_base, module_size))? + 8; let offset = game .read::(ptr + 13 + 0x4 + game.read::(ptr + 13).ok()? + 3) .ok()?; @@ -111,7 +111,7 @@ impl State { } } else { const SIG: Signature<12> = Signature::new("83 ?? 02 75 ?? 8B ?? ?? ?? ?? ?? E8"); - let ptr = SIG.scan(game, self.core_base, module_size)? + 7; + let ptr = SIG.scan(game, (self.core_base, module_size))? + 7; let offset = game .read::(ptr + 12 + 0x4 + game.read::(ptr + 12).ok()? + 2) .ok()?; diff --git a/src/game_engine/unity/il2cpp.rs b/src/game_engine/unity/il2cpp.rs index 1d0c8cf..fbaf22d 100644 --- a/src/game_engine/unity/il2cpp.rs +++ b/src/game_engine/unity/il2cpp.rs @@ -7,8 +7,11 @@ use core::{ }; use crate::{ - file_format::pe, future::retry, signature::Signature, string::ArrayCString, Address, Address64, - Error, PointerSize, Process, + file_format::pe, + future::retry, + signature::{Signature, SignatureScanner}, + string::ArrayCString, + Address, Address64, Error, PointerSize, Process, }; #[cfg(feature = "derive")] @@ -59,14 +62,14 @@ impl Module { const ASSEMBLIES_TRG_SIG: Signature<12> = Signature::new("48 FF C5 80 3C ?? 00 75 ?? 48 8B 1D"); - let addr = ASSEMBLIES_TRG_SIG.scan(process, mono_module.0, mono_module.1)? + 12; + let addr = ASSEMBLIES_TRG_SIG.scan(process, mono_module)? + 12; addr + 0x4 + process.read::(addr).ok()? } PointerSize::Bit32 => { const ASSEMBLIES_TRG_SIG: Signature<9> = Signature::new("8A 07 47 84 C0 75 ?? 8B 35"); - let addr = ASSEMBLIES_TRG_SIG.scan(process, mono_module.0, mono_module.1)? + 9; + let addr = ASSEMBLIES_TRG_SIG.scan(process, mono_module)? + 9; process.read_pointer(addr, pointer_size).ok()? } _ => return None, @@ -77,7 +80,7 @@ impl Module { Signature::new("48 83 3C ?? 00 75 ?? 8B C? E8"); let addr = TYPE_INFO_DEFINITION_TABLE_TRG_SIG - .scan(process, mono_module.0, mono_module.1)? + .scan(process, mono_module)? .add_signed(-4); process @@ -88,8 +91,7 @@ impl Module { const TYPE_INFO_DEFINITION_TABLE_TRG_SIG: Signature<10> = Signature::new("C3 A1 ?? ?? ?? ?? 83 3C ?? 00"); - let addr = - TYPE_INFO_DEFINITION_TABLE_TRG_SIG.scan(process, mono_module.0, mono_module.1)? + 2; + let addr = TYPE_INFO_DEFINITION_TABLE_TRG_SIG.scan(process, mono_module)? + 2; process .read_pointer(process.read_pointer(addr, pointer_size).ok()?, pointer_size) @@ -363,7 +365,7 @@ impl Class { &'a self, process: &'a Process, module: &'a Module, - ) -> impl FusedIterator + '_ { + ) -> impl FusedIterator + 'a { let mut this_class = Some(*self); iter::from_fn(move || { @@ -799,17 +801,14 @@ fn detect_version(process: &Process) -> Option { const SIG_202X: Signature<6> = Signature::new("00 32 30 32 ?? 2E"); const SIG_2019: Signature<6> = Signature::new("00 32 30 31 39 2E"); - if SIG_202X - .scan(process, unity_module.0, unity_module.1) - .is_some() - { + if SIG_202X.scan(process, unity_module).is_some() { let il2cpp_version = { const SIG: Signature<14> = Signature::new("48 2B ?? 48 2B ?? ?? ?? ?? ?? 48 F7 ?? 48"); let address = process.get_module_address("GameAssembly.dll").ok()?; let size = pe::read_size_of_image(process, address)? as u64; let ptr = { - let addr = SIG.scan(process, address, size)? + 6; + let addr = SIG.scan(process, (address, size))? + 6; addr + 0x4 + process.read::(addr).ok()? }; @@ -822,10 +821,7 @@ fn detect_version(process: &Process) -> Option { } else { Version::V2019 }) - } else if SIG_2019 - .scan(process, unity_module.0, unity_module.1) - .is_some() - { + } else if SIG_2019.scan(process, unity_module).is_some() { Some(Version::V2019) } else { Some(Version::Base) diff --git a/src/game_engine/unity/mono.rs b/src/game_engine/unity/mono.rs index 8c7e2bd..c8791b3 100644 --- a/src/game_engine/unity/mono.rs +++ b/src/game_engine/unity/mono.rs @@ -2,8 +2,11 @@ //! backend. use crate::{ - file_format::pe, future::retry, signature::Signature, string::ArrayCString, Address, Address32, - Address64, Error, PointerSize, Process, + file_format::pe, + future::retry, + signature::{Signature, SignatureScanner}, + string::ArrayCString, + Address, Address32, Address64, Error, PointerSize, Process, }; use core::{ array, @@ -63,7 +66,7 @@ impl Module { PointerSize::Bit64 => { const SIG_MONO_64: Signature<3> = Signature::new("48 8B 0D"); let scan_address: Address = - SIG_MONO_64.scan(process, root_domain_function_address, 0x100)? + 3; + SIG_MONO_64.scan(process, (root_domain_function_address, 0x100))? + 3; scan_address + 0x4 + process.read::(scan_address).ok()? } PointerSize::Bit32 => { @@ -72,7 +75,7 @@ impl Module { let ptr = [SIG_32_1, SIG_32_2] .iter() - .find_map(|sig| sig.scan(process, root_domain_function_address, 0x100))? + .find_map(|sig| sig.scan(process, (root_domain_function_address, 0x100)))? + 2; process.read::(ptr).ok()?.into() @@ -916,7 +919,7 @@ fn detect_version(process: &Process) -> Option { const SIG_202X: Signature<6> = Signature::new("00 32 30 32 ?? 2E"); - let Some(addr) = SIG_202X.scan(process, unity_module.0, unity_module.1) else { + let Some(addr) = SIG_202X.scan(process, unity_module) else { return Some(Version::V2); }; diff --git a/src/game_engine/unity/scene.rs b/src/game_engine/unity/scene.rs index 21e8d6f..d7c9e2f 100644 --- a/src/game_engine/unity/scene.rs +++ b/src/game_engine/unity/scene.rs @@ -59,13 +59,13 @@ impl SceneManager { // There are multiple signatures that can be used, depending on the version of Unity // used in the target game. let base_address: Address = if pointer_size == PointerSize::Bit64 { - let addr = SIG_64_BIT.scan(process, unity_player.0, unity_player.1)? + 7; + let addr = SIG_64_BIT.scan(process, unity_player)? + 7; addr + 0x4 + process.read::(addr).ok()? - } else if let Some(addr) = SIG_32_1.scan(process, unity_player.0, unity_player.1) { + } else if let Some(addr) = SIG_32_1.scan(process, unity_player) { process.read::(addr + 5).ok()?.into() - } else if let Some(addr) = SIG_32_2.scan(process, unity_player.0, unity_player.1) { + } else if let Some(addr) = SIG_32_2.scan(process, unity_player) { process.read::(addr.add_signed(-4)).ok()?.into() - } else if let Some(addr) = SIG_32_3.scan(process, unity_player.0, unity_player.1) { + } else if let Some(addr) = SIG_32_3.scan(process, unity_player) { process.read::(addr + 7).ok()?.into() } else { return None; diff --git a/src/game_engine/unreal/mod.rs b/src/game_engine/unreal/mod.rs index b651a8f..95799ed 100644 --- a/src/game_engine/unreal/mod.rs +++ b/src/game_engine/unreal/mod.rs @@ -52,9 +52,9 @@ impl Module { (Signature::new("A8 01 75 ?? C7 05 ??"), 6), ]; - let addr = GENGINE.iter().find_map(|(sig, offset)| { - Some(sig.scan(process, module_range.0, module_range.1)? + *offset) - })?; + let addr = GENGINE + .iter() + .find_map(|(sig, offset)| Some(sig.scan(process, module_range)? + *offset))?; addr + 0x8 + process.read::(addr).ok()? }; @@ -64,9 +64,9 @@ impl Module { 3, )]; - let addr = GWORLD.iter().find_map(|(sig, offset)| { - Some(sig.scan(process, module_range.0, module_range.1)? + *offset) - })?; + let addr = GWORLD + .iter() + .find_map(|(sig, offset)| Some(sig.scan(process, module_range)? + *offset))?; addr + 0x4 + process.read::(addr).ok()? }; @@ -77,9 +77,9 @@ impl Module { (Signature::new("57 0F B7 F8 74 ?? B8 ?? ?? ?? ?? 8B 44"), 7), ]; - let addr = FNAME_POOL.iter().find_map(|(sig, offset)| { - Some(sig.scan(process, module_range.0, module_range.1)? + *offset) - })?; + let addr = FNAME_POOL + .iter() + .find_map(|(sig, offset)| Some(sig.scan(process, module_range)? + *offset))?; addr + 0x4 + process.read::(addr).ok()? }; diff --git a/src/signature.rs b/src/signature.rs index 879c8d9..9fd6fd9 100644 --- a/src/signature.rs +++ b/src/signature.rs @@ -307,8 +307,7 @@ pub trait SignatureScanner { /// * `len` - The length of the memory range to scan. /// /// Returns `Some(Address)` of the first match if found, otherwise `None`. - fn scan<'a>(&'a self, process: &Process, addr: impl Into
, len: u64) - -> Option
; + fn scan<'a>(&'a self, process: &Process, range: (impl Into
, u64)) -> Option
; /// Returns an iterator over all occurrences of the signature in the process's memory range. /// @@ -322,8 +321,7 @@ pub trait SignatureScanner { fn scan_process_range<'a>( &'a self, process: &'a Process, - addr: impl Into
, - len: u64, + range: (impl Into
, u64), ) -> impl Iterator + 'a; /// Asynchronously awaits scanning a process for the signature until a match @@ -338,8 +336,7 @@ pub trait SignatureScanner { async fn wait_scan_process_range( &self, process: &Process, - addr: impl Into
, - len: u64, + range: (impl Into
, u64), ) -> Address; } @@ -347,22 +344,20 @@ impl SignatureScanner for Signature { fn scan<'a>( &'a self, process: &'a Process, - addr: impl Into
, - len: u64, + range: (impl Into
, u64), ) -> Option
{ - self.scan_process_range(process, addr, len).next() + self.scan_process_range(process, range).next() } fn scan_process_range<'a>( &'a self, process: &'a Process, - addr: impl Into
, - len: u64, + range: (impl Into
, u64), ) -> impl Iterator + 'a { const MEM_SIZE: usize = 0x1000; - let mut addr: Address = Into::into(addr); - let overall_end = addr.value() + len; + let mut addr: Address = Into::into(range.0); + let overall_end = addr.value() + range.1; // The sigscan essentially works by reading one memory page (0x1000 bytes) // at a time and looking for the signature in each page. We will create a buffer @@ -462,10 +457,9 @@ impl SignatureScanner for Signature { async fn wait_scan_process_range( &self, process: &Process, - addr: impl Into
, - len: u64, + range: (impl Into
, u64), ) -> Address { - let addr = addr.into(); - retry(|| self.scan_process_range(process, addr, len).next()).await + let addr = range.0.into(); + retry(|| self.scan_process_range(process, (addr, range.1)).next()).await } } From d344ec0c02ffbbbf8c6dab49c10ac382697afa6f Mon Sep 17 00:00:00 2001 From: Jujstme Date: Wed, 22 Jan 2025 23:45:20 +0100 Subject: [PATCH 5/5] Fixed code according to the suggestions provided --- src/emulator/gba/mednafen.rs | 14 +++--- src/emulator/gba/nocashgba.rs | 7 +-- src/emulator/gba/retroarch.rs | 22 ++++----- src/emulator/gba/vba.rs | 26 +++++------ src/emulator/genesis/blastem.rs | 8 +--- src/emulator/genesis/fusion.rs | 7 +-- src/emulator/genesis/gens.rs | 7 +-- src/emulator/genesis/retroarch.rs | 26 ++++++----- src/emulator/genesis/segaclassics.rs | 9 ++-- src/emulator/ps1/duckstation.rs | 8 +--- src/emulator/ps1/epsxe.rs | 7 +-- src/emulator/ps1/mednafen.rs | 10 ++--- src/emulator/ps1/pcsx_redux.rs | 10 ++--- src/emulator/ps1/psxfin.rs | 13 +++--- src/emulator/ps1/retroarch.rs | 18 +++----- src/emulator/ps1/xebra.rs | 7 +-- src/emulator/ps2/pcsx2.rs | 12 ++--- src/emulator/ps2/retroarch.rs | 9 ++-- src/emulator/sms/blastem.rs | 8 +--- src/emulator/sms/fusion.rs | 7 +-- src/emulator/sms/mednafen.rs | 10 ++--- src/emulator/sms/retroarch.rs | 20 ++++----- src/game_engine/unity/il2cpp.rs | 21 ++++----- src/game_engine/unity/mono.rs | 18 +++----- src/game_engine/unity/scene.rs | 15 +++---- src/game_engine/unreal/mod.rs | 15 +++---- src/signature.rs | 67 +++++++++++----------------- 27 files changed, 151 insertions(+), 250 deletions(-) diff --git a/src/emulator/gba/mednafen.rs b/src/emulator/gba/mednafen.rs index 8032df0..e40cb64 100644 --- a/src/emulator/gba/mednafen.rs +++ b/src/emulator/gba/mednafen.rs @@ -1,8 +1,4 @@ -use crate::{ - file_format::pe, - signature::{Signature, SignatureScanner}, - Address, Address32, Address64, Error, Process, -}; +use crate::{file_format::pe, signature::Signature, Address, Address32, Address64, Error, Process}; #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub struct State { @@ -24,7 +20,7 @@ impl State { if self.is_64_bit { self.cached_ewram_pointer = { const SIG: Signature<13> = Signature::new("48 8B 05 ?? ?? ?? ?? 81 E1 FF FF 03 00"); - let ptr: Address = SIG.scan(game, main_module_range)? + 3; + let ptr: Address = SIG.scan_once(game, main_module_range)? + 3; let mut addr: Address = ptr + 0x4 + game.read::(ptr).ok()?; if game.read::(ptr + 10).ok()? == 0x48 { @@ -40,7 +36,7 @@ impl State { self.cached_iwram_pointer = { const SIG2: Signature<13> = Signature::new("48 8B 05 ?? ?? ?? ?? 81 E1 FF 7F 00 00"); - let ptr: Address = SIG2.scan(game, main_module_range)? + 3; + let ptr: Address = SIG2.scan_once(game, main_module_range)? + 3; let mut addr: Address = ptr + 0x4 + game.read::(ptr).ok()?; if game.read::(ptr + 10).ok()? == 0x48 { @@ -60,13 +56,13 @@ impl State { } else { self.cached_ewram_pointer = { const SIG: Signature<11> = Signature::new("A1 ?? ?? ?? ?? 81 ?? FF FF 03 00"); - let ptr = SIG.scan(game, main_module_range)?; + let ptr = SIG.scan_once(game, main_module_range)?; game.read::(ptr + 1).ok()?.into() }; self.cached_iwram_pointer = { const SIG2: Signature<11> = Signature::new("A1 ?? ?? ?? ?? 81 ?? FF 7F 00 00"); - let ptr = SIG2.scan(game, main_module_range)?; + let ptr = SIG2.scan_once(game, main_module_range)?; game.read::(ptr + 1).ok()?.into() }; diff --git a/src/emulator/gba/nocashgba.rs b/src/emulator/gba/nocashgba.rs index a6b2c77..27845d9 100644 --- a/src/emulator/gba/nocashgba.rs +++ b/src/emulator/gba/nocashgba.rs @@ -1,7 +1,4 @@ -use crate::{ - signature::{Signature, SignatureScanner}, - Address, Address32, Process, -}; +use crate::{signature::Signature, Address, Address32, Process}; #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub struct State { @@ -19,7 +16,7 @@ impl State { .find_map(|(name, _)| game.get_module_range(name).ok())?; self.base_addr = game - .read::(SIG.scan(game, main_module_range)? + 0x2) + .read::(SIG.scan_once(game, main_module_range)? + 0x2) .ok()? .into(); diff --git a/src/emulator/gba/retroarch.rs b/src/emulator/gba/retroarch.rs index 9186127..282758f 100644 --- a/src/emulator/gba/retroarch.rs +++ b/src/emulator/gba/retroarch.rs @@ -1,8 +1,4 @@ -use crate::{ - file_format::pe, - signature::{Signature, SignatureScanner}, - Address, Address32, Address64, Process, -}; +use crate::{file_format::pe, signature::Signature, Address, Address32, Address64, Process}; #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub struct State { @@ -51,7 +47,7 @@ impl State { const SIG2: Signature<13> = Signature::new("48 8B 05 ?? ?? ?? ?? 81 E1 FF 7F 00 00"); let ewram_pointer = { - let ptr: Address = SIG.scan(game, module_range)? + 3; + let ptr: Address = SIG.scan_once(game, module_range)? + 3; let mut addr: Address = ptr + 0x4 + game.read::(ptr).ok()?; if game.read::(ptr + 10).ok()? == 0x48 { @@ -65,7 +61,7 @@ impl State { }; let iwram_pointer = { - let ptr: Address = SIG2.scan(game, module_range)? + 3; + let ptr: Address = SIG2.scan_once(game, module_range)? + 3; let mut addr: Address = ptr + 0x4 + game.read::(ptr).ok()?; if game.read::(ptr + 10).ok()? == 0x48 { @@ -89,12 +85,12 @@ impl State { } else { let ewram_pointer: Address = { const SIG: Signature<11> = Signature::new("A1 ?? ?? ?? ?? 81 ?? FF FF 03 00"); - let ptr = SIG.scan(game, module_range)?; + let ptr = SIG.scan_once(game, module_range)?; game.read::(ptr + 1).ok()?.into() }; let iwram_pointer: Address = { const SIG2: Signature<11> = Signature::new("A1 ?? ?? ?? ?? 81 ?? FF 7F 00 00"); - let ptr = SIG2.scan(game, module_range)?; + let ptr = SIG2.scan_once(game, module_range)?; game.read::(ptr + 1).ok()?.into() }; @@ -118,24 +114,24 @@ impl State { let base_addr: Address = match is_64_bit { true => { const SIG: Signature<10> = Signature::new("48 8B 15 ?? ?? ?? ?? 8B 42 40"); - let ptr = SIG.scan(game, (self.core_base, module_size))? + 3; + let ptr = SIG.scan_once(game, (self.core_base, module_size))? + 3; let ptr: Address = ptr + 0x4 + game.read::(ptr).ok()?; game.read::(ptr).ok()?.into() } false => { const SIG: Signature<11> = Signature::new("A3 ?? ?? ?? ?? F7 C5 02 00 00 00"); - let ptr = SIG.scan(game, (self.core_base, module_size))? + 1; + let ptr = SIG.scan_once(game, (self.core_base, module_size))? + 1; game.read::(ptr).ok()?.into() } }; let ewram = { - let offset = SIG_EWRAM.scan(game, (self.core_base, module_size))? + 8; + let offset = SIG_EWRAM.scan_once(game, (self.core_base, module_size))? + 8; base_addr + game.read::(offset).ok()? }; let iwram = { - let offset = SIG_IWRAM.scan(game, (self.core_base, module_size))? + 9; + let offset = SIG_IWRAM.scan_once(game, (self.core_base, module_size))? + 9; base_addr + game.read::(offset).ok()? }; diff --git a/src/emulator/gba/vba.rs b/src/emulator/gba/vba.rs index a421919..82448f2 100644 --- a/src/emulator/gba/vba.rs +++ b/src/emulator/gba/vba.rs @@ -1,8 +1,4 @@ -use crate::{ - file_format::pe, - signature::{Signature, SignatureScanner}, - Address, Address32, Address64, Error, Process, -}; +use crate::{file_format::pe, signature::Signature, Address, Address32, Address64, Error, Process}; #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub struct State { @@ -29,7 +25,7 @@ impl State { const SIG2: Signature<13> = Signature::new("48 8B 05 ?? ?? ?? ?? 81 E3 FF 7F 00 00"); self.cached_ewram_pointer = { - let ptr: Address = SIG.scan(game, main_module_range)? + 3; + let ptr: Address = SIG.scan_once(game, main_module_range)? + 3; let mut addr: Address = ptr + 0x4 + game.read::(ptr).ok()?; if game.read::(ptr + 10).ok()? == 0x48 { @@ -43,7 +39,7 @@ impl State { }; self.cached_iwram_pointer = { - let ptr: Address = SIG2.scan(game, main_module_range)? + 3; + let ptr: Address = SIG2.scan_once(game, main_module_range)? + 3; let mut addr: Address = ptr + 0x4 + game.read::(ptr).ok()?; if game.read::(ptr + 10).ok()? == 0x48 { @@ -62,11 +58,11 @@ impl State { const SIG_RUNNING2: Signature<16> = Signature::new("48 8B 15 ?? ?? ?? ?? 31 C0 8B 12 85 D2 74 ?? 48"); - if let Some(ptr) = SIG_RUNNING.scan(game, main_module_range) { + if let Some(ptr) = SIG_RUNNING.scan_once(game, main_module_range) { let ptr = ptr + 2; ptr + 0x4 + game.read::(ptr).ok()? + 0x1 } else { - let ptr = SIG_RUNNING2.scan(game, main_module_range)? + 3; + let ptr = SIG_RUNNING2.scan_once(game, main_module_range)? + 3; let ptr = ptr + 0x4 + game.read::(ptr).ok()?; game.read::(ptr).ok()?.into() } @@ -80,11 +76,11 @@ impl State { const SIG: Signature<11> = Signature::new("A1 ?? ?? ?? ?? 81 ?? FF FF 03 00"); const SIG_OLD: Signature<12> = Signature::new("81 E6 FF FF 03 00 8B 15 ?? ?? ?? ??"); - if let Some(ptr) = SIG.scan(game, main_module_range) { + if let Some(ptr) = SIG.scan_once(game, main_module_range) { self.cached_ewram_pointer = game.read::(ptr + 1).ok()?.into(); self.cached_iwram_pointer = { const SIG2: Signature<11> = Signature::new("A1 ?? ?? ?? ?? 81 ?? FF 7F 00 00"); - let ptr = SIG2.scan(game, main_module_range)?; + let ptr = SIG2.scan_once(game, main_module_range)?; game.read::(ptr + 1).ok()?.into() }; @@ -95,8 +91,8 @@ impl State { Signature::new("8B 15 ?? ?? ?? ?? 31 C0 85 D2 74 ?? 0F"); let ptr = SIG - .scan(game, main_module_range) - .or_else(|| SIG_OLD.scan(game, main_module_range))?; + .scan_once(game, main_module_range) + .or_else(|| SIG_OLD.scan_once(game, main_module_range))?; game.read::(ptr + 2).ok()?.into() }; @@ -105,7 +101,7 @@ impl State { let iwram = game.read::(self.cached_iwram_pointer).ok()?; Some([ewram.into(), iwram.into()]) - } else if let Some(ptr) = SIG_OLD.scan(game, main_module_range) { + } else if let Some(ptr) = SIG_OLD.scan_once(game, main_module_range) { // This code is for very old versions of VisualBoyAdvance (1.8.0-beta 3) self.cached_ewram_pointer = game.read::(ptr + 8).ok()?.into(); self.cached_iwram_pointer = self.cached_ewram_pointer.add_signed(0x4); @@ -113,7 +109,7 @@ impl State { self.is_emulating = { const SIG_RUNNING: Signature<11> = Signature::new("8B 0D ?? ?? ?? ?? 85 C9 74 ?? 8A"); - let ptr = SIG_RUNNING.scan(game, main_module_range)? + 2; + let ptr = SIG_RUNNING.scan_once(game, main_module_range)? + 2; game.read::(ptr).ok()?.into() }; diff --git a/src/emulator/genesis/blastem.rs b/src/emulator/genesis/blastem.rs index e4ebe13..f5b0990 100644 --- a/src/emulator/genesis/blastem.rs +++ b/src/emulator/genesis/blastem.rs @@ -1,8 +1,4 @@ -use crate::{ - runtime::MemoryRangeFlags, - signature::{Signature, SignatureScanner}, - Address, Address32, Endian, Process, -}; +use crate::{runtime::MemoryRangeFlags, signature::Signature, Address, Address32, Endian, Process}; #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub struct State; @@ -22,7 +18,7 @@ impl State { .contains(MemoryRangeFlags::WRITE) && m.size().unwrap_or_default() == 0x101000 }) - .find_map(|m| SIG.scan(game, m.range().ok()?))? + .find_map(|m| SIG.scan_once(game, m.range().ok()?))? + 11; let wram = game.read::(scanned_address).ok()?; diff --git a/src/emulator/genesis/fusion.rs b/src/emulator/genesis/fusion.rs index 021b608..9036a4e 100644 --- a/src/emulator/genesis/fusion.rs +++ b/src/emulator/genesis/fusion.rs @@ -1,7 +1,4 @@ -use crate::{ - signature::{Signature, SignatureScanner}, - Address, Address32, Endian, Process, -}; +use crate::{signature::Signature, Address, Address32, Endian, Process}; #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub struct State { @@ -17,7 +14,7 @@ impl State { .filter(|(_, state)| matches!(state, super::State::Fusion(_))) .find_map(|(name, _)| game.get_module_range(name).ok())?; - let ptr = SIG.scan(game, main_module)? + 1; + let ptr = SIG.scan_once(game, main_module)? + 1; let addr = ptr + game.read::(ptr).ok()? as u64 + 3; let addr = game.read::(addr).ok()?; diff --git a/src/emulator/genesis/gens.rs b/src/emulator/genesis/gens.rs index 231f3c8..2a3e847 100644 --- a/src/emulator/genesis/gens.rs +++ b/src/emulator/genesis/gens.rs @@ -1,7 +1,4 @@ -use crate::{ - signature::{Signature, SignatureScanner}, - Address, Address32, Endian, Process, -}; +use crate::{signature::Signature, Address, Address32, Endian, Process}; #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub struct State; @@ -15,7 +12,7 @@ impl State { .filter(|(_, state)| matches!(state, super::State::Gens(_))) .find_map(|(name, _)| game.get_module_range(name).ok())?; - let ptr = SIG.scan(game, main_module)? + 11; + let ptr = SIG.scan_once(game, main_module)? + 11; *endian = if game.read::(ptr + 4).ok()? == 0x86 { Endian::Big diff --git a/src/emulator/genesis/retroarch.rs b/src/emulator/genesis/retroarch.rs index f967972..75367c2 100644 --- a/src/emulator/genesis/retroarch.rs +++ b/src/emulator/genesis/retroarch.rs @@ -1,7 +1,5 @@ use crate::{ - file_format::pe, - signature::{Signature, SignatureScanner}, - Address, Address32, Endian, MemoryRangeFlags, Process, + file_format::pe, signature::Signature, Address, Address32, Endian, MemoryRangeFlags, Process, }; #[derive(Copy, Clone, Debug, PartialEq, Eq)] @@ -47,7 +45,7 @@ impl State { .contains(MemoryRangeFlags::WRITE) && m.size().unwrap_or_default() == 0x101000 }) - .find_map(|m| SIG.scan(game, m.range().ok()?))? + .find_map(|m| SIG.scan_once(game, m.range().ok()?))? + 11; let wram = game.read::(scanned_address).ok()?; @@ -60,8 +58,9 @@ impl State { if is_x86_64 { const SIG_64: Signature<10> = Signature::new("48 8D 0D ?? ?? ?? ?? 4C 8B 2D"); - let addr = - SIG_64.scan(game, (core_address, game.get_module_size(core_name).ok()?))? + 3; + let addr = SIG_64 + .scan_once(game, (core_address, game.get_module_size(core_name).ok()?))? + + 3; let wram = addr + 0x4 + game.read::(addr).ok()?; @@ -69,8 +68,9 @@ impl State { } else { const SIG_32: Signature<7> = Signature::new("A3 ?? ?? ?? ?? 29 F9"); - let ptr = - SIG_32.scan(game, (core_address, game.get_module_size(core_name).ok()?))? + 1; + let ptr = SIG_32 + .scan_once(game, (core_address, game.get_module_size(core_name).ok()?))? + + 1; let wram = game.read::(ptr).ok()?; @@ -83,8 +83,9 @@ impl State { if is_x86_64 { const SIG_64: Signature<9> = Signature::new("48 8D 0D ?? ?? ?? ?? 41 B8"); - let addr = - SIG_64.scan(game, (core_address, game.get_module_size(core_name).ok()?))? + 3; + let addr = SIG_64 + .scan_once(game, (core_address, game.get_module_size(core_name).ok()?))? + + 3; let wram = addr + 0x4 + game.read::(addr).ok()?; @@ -92,8 +93,9 @@ impl State { } else { const SIG_32: Signature<8> = Signature::new("B9 ?? ?? ?? ?? C1 EF 10"); - let ptr = - SIG_32.scan(game, (core_address, game.get_module_size(core_name).ok()?))? + 1; + let ptr = SIG_32 + .scan_once(game, (core_address, game.get_module_size(core_name).ok()?))? + + 1; let wram = game.read::(ptr).ok()?; diff --git a/src/emulator/genesis/segaclassics.rs b/src/emulator/genesis/segaclassics.rs index 87ce6ac..acf6df2 100644 --- a/src/emulator/genesis/segaclassics.rs +++ b/src/emulator/genesis/segaclassics.rs @@ -1,7 +1,4 @@ -use crate::{ - signature::{Signature, SignatureScanner}, - Address, Address32, Endian, Process, -}; +use crate::{signature::Signature, Address, Address32, Endian, Process}; #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub struct State { @@ -16,14 +13,14 @@ impl State { const GENESISWRAPPERDLL: &str = "GenesisEmuWrapper.dll"; let mut ptr = if let Ok(module) = game.get_module_range(GENESISWRAPPERDLL) { - SIG_GAMEROOM.scan(game, module)? + 2 + SIG_GAMEROOM.scan_once(game, module)? + 2 } else { let main_module = super::PROCESS_NAMES .iter() .filter(|(_, state)| matches!(state, super::State::SegaClassics(_))) .find_map(|(name, _)| game.get_module_range(name).ok())?; - SIG_SEGACLASSICS.scan(game, main_module)? + 8 + SIG_SEGACLASSICS.scan_once(game, main_module)? + 8 }; ptr = game.read::(ptr).ok()?.into(); diff --git a/src/emulator/ps1/duckstation.rs b/src/emulator/ps1/duckstation.rs index 1ed9ce5..90c873f 100644 --- a/src/emulator/ps1/duckstation.rs +++ b/src/emulator/ps1/duckstation.rs @@ -1,8 +1,4 @@ -use crate::{ - file_format::pe, - signature::{Signature, SignatureScanner}, - Address, Address64, Process, -}; +use crate::{file_format::pe, signature::Signature, Address, Address64, Process}; #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub struct State { @@ -28,7 +24,7 @@ impl State { self.addr = debug_symbol.address; } else { // For older versions of Duckstation, we fall back to regular sigscanning - let addr = SIG.scan(game, main_module_range)? + 3; + let addr = SIG.scan_once(game, main_module_range)? + 3; self.addr = addr + 0x4 + game.read::(addr).ok()?; } diff --git a/src/emulator/ps1/epsxe.rs b/src/emulator/ps1/epsxe.rs index c7c3875..bd23a16 100644 --- a/src/emulator/ps1/epsxe.rs +++ b/src/emulator/ps1/epsxe.rs @@ -1,7 +1,4 @@ -use crate::{ - signature::{Signature, SignatureScanner}, - Address, Address32, Process, -}; +use crate::{signature::Signature, Address, Address32, Process}; #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub struct State; @@ -15,7 +12,7 @@ impl State { .filter(|(_, state)| matches!(state, super::State::Epsxe(_))) .find_map(|(name, _)| game.get_module_range(name).ok())?; - let ptr = SIG.scan(game, main_module_range)? + 5; + let ptr = SIG.scan_once(game, main_module_range)? + 5; Some(game.read::(ptr).ok()?.into()) } diff --git a/src/emulator/ps1/mednafen.rs b/src/emulator/ps1/mednafen.rs index 4304571..e947c81 100644 --- a/src/emulator/ps1/mednafen.rs +++ b/src/emulator/ps1/mednafen.rs @@ -1,8 +1,4 @@ -use crate::{ - file_format::pe, - signature::{Signature, SignatureScanner}, - Address, Address32, Process, -}; +use crate::{file_format::pe, signature::Signature, Address, Address32, Process}; #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub struct State; @@ -21,8 +17,8 @@ impl State { pe::MachineType::read(game, main_module_range.0) == Some(pe::MachineType::X86_64); let ptr = match is_64_bit { - true => SIG_64.scan(game, main_module_range)?, - false => SIG_32.scan(game, main_module_range)?, + true => SIG_64.scan_once(game, main_module_range)?, + false => SIG_32.scan_once(game, main_module_range)?, } + 0x5; Some(game.read::(ptr).ok()?.into()) diff --git a/src/emulator/ps1/pcsx_redux.rs b/src/emulator/ps1/pcsx_redux.rs index 2761823..188c10b 100644 --- a/src/emulator/ps1/pcsx_redux.rs +++ b/src/emulator/ps1/pcsx_redux.rs @@ -1,7 +1,5 @@ use crate::{ - file_format::pe, - signature::{Signature, SignatureScanner}, - Address, Address32, Address64, MemoryRangeFlags, Process, + file_format::pe, signature::Signature, Address, Address32, Address64, MemoryRangeFlags, Process, }; #[derive(Copy, Clone, Debug, PartialEq, Eq)] @@ -27,10 +25,10 @@ impl State { ); const SIG_OFFSET: Signature<9> = Signature::new("89 D1 C1 E9 10 48 8B ?? ??"); - self.addr_base = SIG_BASE.scan(game, main_module_range)? + 2; + self.addr_base = SIG_BASE.scan_once(game, main_module_range)? + 2; self.addr = game.read::(self.addr_base).ok()?.into(); - let offset = SIG_OFFSET.scan(game, main_module_range)? + 8; + let offset = SIG_OFFSET.scan_once(game, main_module_range)? + 8; let offset = game.read::(offset).ok()? as u64; let addr = game.read::(self.addr + offset).ok()?; @@ -47,7 +45,7 @@ impl State { .unwrap_or_default() .contains(MemoryRangeFlags::WRITE) }) - .find_map(|m| SIG.scan(game, m.range().ok()?))? + .find_map(|m| SIG.scan_once(game, m.range().ok()?))? + 2; self.addr = game.read::(self.addr_base).ok()?.into(); diff --git a/src/emulator/ps1/psxfin.rs b/src/emulator/ps1/psxfin.rs index 42b6090..0d0c00b 100644 --- a/src/emulator/ps1/psxfin.rs +++ b/src/emulator/ps1/psxfin.rs @@ -1,7 +1,4 @@ -use crate::{ - signature::{Signature, SignatureScanner}, - Address, Address32, Process, -}; +use crate::{signature::Signature, Address, Address32, Process}; #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub struct State; @@ -18,13 +15,13 @@ impl State { .filter(|(_, state)| matches!(state, super::State::PsxFin(_))) .find_map(|(name, _)| game.get_module_range(name).ok())?; - let mut ptr: Address32 = if let Some(sig) = SIG.scan(game, main_module_range) { + let mut ptr: Address32 = if let Some(sig) = SIG.scan_once(game, main_module_range) { game.read(sig + 2).ok()? - } else if let Some(sig) = SIG_0.scan(game, main_module_range) { + } else if let Some(sig) = SIG_0.scan_once(game, main_module_range) { game.read(sig + 1).ok()? - } else if let Some(sig) = SIG_1.scan(game, main_module_range) { + } else if let Some(sig) = SIG_1.scan_once(game, main_module_range) { game.read(sig + 1).ok()? - } else if let Some(sig) = SIG_2.scan(game, main_module_range) { + } else if let Some(sig) = SIG_2.scan_once(game, main_module_range) { game.read(sig + 1).ok()? } else { return None; diff --git a/src/emulator/ps1/retroarch.rs b/src/emulator/ps1/retroarch.rs index 565fe74..8153154 100644 --- a/src/emulator/ps1/retroarch.rs +++ b/src/emulator/ps1/retroarch.rs @@ -1,8 +1,4 @@ -use crate::{ - file_format::pe, - signature::{Signature, SignatureScanner}, - Address, Address32, Address64, Process, -}; +use crate::{file_format::pe, signature::Signature, Address, Address32, Address64, Process}; #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub struct State { @@ -38,13 +34,13 @@ impl State { const SIG: Signature<14> = Signature::new("48 8B 05 ?? ?? ?? ?? 41 81 E4 FF FF 1F 00"); let ptr = - SIG.scan(game, (core_address, game.get_module_size(core_name).ok()?))? + 3; + SIG.scan_once(game, (core_address, game.get_module_size(core_name).ok()?))? + 3; let ptr = ptr + 0x4 + game.read::(ptr).ok()?; Some(game.read::(ptr).ok()?.into()) } else { const SIG: Signature<11> = Signature::new("A1 ?? ?? ?? ?? 81 E3 FF FF 1F 00"); let ptr = - SIG.scan(game, (core_address, game.get_module_size(core_name).ok()?))? + 1; + SIG.scan_once(game, (core_address, game.get_module_size(core_name).ok()?))? + 1; let ptr = game.read::(ptr).ok()?; Some(game.read::(ptr).ok()?.into()) } @@ -54,13 +50,13 @@ impl State { const SIG: Signature<15> = Signature::new("48 89 0D ?? ?? ?? ?? 89 35 ?? ?? ?? ?? 89 3D"); let addr = - SIG.scan(game, (core_address, game.get_module_size(core_name).ok()?))? + 3; + SIG.scan_once(game, (core_address, game.get_module_size(core_name).ok()?))? + 3; let ptr = addr + 0x4 + game.read::(addr).ok()?; Some(game.read::(ptr).ok()?.into()) } else { const SIG: Signature<8> = Signature::new("A1 ?? ?? ?? ?? 23 CB 8B"); let ptr = - SIG.scan(game, (core_address, game.get_module_size(core_name).ok()?))? + 1; + SIG.scan_once(game, (core_address, game.get_module_size(core_name).ok()?))? + 1; let ptr = game.read::(ptr).ok()?; Some(game.read::(ptr).ok()?.into()) } @@ -69,14 +65,14 @@ impl State { if is_64_bit { const SIG: Signature<9> = Signature::new("48 8B 35 ?? ?? ?? ?? 81 E2"); let addr = - SIG.scan(game, (core_address, game.get_module_size(core_name).ok()?))? + 3; + SIG.scan_once(game, (core_address, game.get_module_size(core_name).ok()?))? + 3; let ptr = addr + 0x4 + game.read::(addr).ok()?; let ptr = game.read::(ptr).ok()?; Some(game.read::(ptr).ok()?.into()) } else { const SIG: Signature<9> = Signature::new("FF FF 1F 00 89 ?? ?? ?? A1"); let ptr = - SIG.scan(game, (core_address, game.get_module_size(core_name).ok()?))? + 9; + SIG.scan_once(game, (core_address, game.get_module_size(core_name).ok()?))? + 9; let ptr = game.read::(ptr).ok()?; Some(game.read::(ptr).ok()?.into()) } diff --git a/src/emulator/ps1/xebra.rs b/src/emulator/ps1/xebra.rs index a27987b..78f5066 100644 --- a/src/emulator/ps1/xebra.rs +++ b/src/emulator/ps1/xebra.rs @@ -1,7 +1,4 @@ -use crate::{ - signature::{Signature, SignatureScanner}, - Address, Address32, Process, -}; +use crate::{signature::Signature, Address, Address32, Process}; #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub struct State; @@ -15,7 +12,7 @@ impl State { .filter(|(_, state)| matches!(state, super::State::Xebra(_))) .find_map(|(name, _)| game.get_module_range(name).ok())?; - let ptr = SIG.scan(game, main_module_range)? + 1; + let ptr = SIG.scan_once(game, main_module_range)? + 1; let addr = ptr + 0x4 + game.read::(ptr).ok()?; let addr = game.read::(addr + 0x16A).ok()?; let addr = game.read::(addr).ok()?; diff --git a/src/emulator/ps2/pcsx2.rs b/src/emulator/ps2/pcsx2.rs index dd35420..88f754f 100644 --- a/src/emulator/ps2/pcsx2.rs +++ b/src/emulator/ps2/pcsx2.rs @@ -1,8 +1,4 @@ -use crate::{ - file_format::pe, - signature::{Signature, SignatureScanner}, - Address, Address32, Address64, Error, Process, -}; +use crate::{file_format::pe, signature::Signature, Address, Address32, Address64, Error, Process}; #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub struct State { @@ -22,15 +18,15 @@ impl State { self.addr_base = if self.is_64_bit { const SIG: Signature<12> = Signature::new("48 8B ?? ?? ?? ?? ?? 25 F0 3F 00 00"); - let ptr = SIG.scan(game, main_module_range)? + 3; + let ptr = SIG.scan_once(game, main_module_range)? + 3; ptr + 0x4 + game.read::(ptr).ok()? } else { const SIG: Signature<11> = Signature::new("8B ?? ?? ?? ?? ?? 25 F0 3F 00 00"); const SIG_ALT: Signature<12> = Signature::new("8B ?? ?? ?? ?? ?? 81 ?? F0 3F 00 00"); - let ptr = if let Some(addr) = SIG.scan(game, main_module_range) { + let ptr = if let Some(addr) = SIG.scan_once(game, main_module_range) { addr + 2 } else { - SIG_ALT.scan(game, main_module_range)? + 2 + SIG_ALT.scan_once(game, main_module_range)? + 2 }; self.read_pointer(game, ptr).ok()? }; diff --git a/src/emulator/ps2/retroarch.rs b/src/emulator/ps2/retroarch.rs index cca62d6..61a8581 100644 --- a/src/emulator/ps2/retroarch.rs +++ b/src/emulator/ps2/retroarch.rs @@ -1,8 +1,4 @@ -use crate::{ - file_format::pe, - signature::{Signature, SignatureScanner}, - Address, Address64, Process, -}; +use crate::{file_format::pe, signature::Signature, Address, Address64, Process}; #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub struct State { @@ -35,7 +31,8 @@ impl State { let base_addr = { const SIG: Signature<13> = Signature::new("48 8B ?? ?? ?? ?? ?? 81 ?? F0 3F 00 00"); - let ptr = SIG.scan(game, (core_address, game.get_module_size(core_name).ok()?))? + 3; + let ptr = + SIG.scan_once(game, (core_address, game.get_module_size(core_name).ok()?))? + 3; ptr + 0x4 + game.read::(ptr).ok()? }; diff --git a/src/emulator/sms/blastem.rs b/src/emulator/sms/blastem.rs index 4dcc67d..ec6281c 100644 --- a/src/emulator/sms/blastem.rs +++ b/src/emulator/sms/blastem.rs @@ -1,8 +1,4 @@ -use crate::{ - runtime::MemoryRangeFlags, - signature::{Signature, SignatureScanner}, - Address, Address32, Process, -}; +use crate::{runtime::MemoryRangeFlags, signature::Signature, Address, Address32, Process}; #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub struct State; @@ -19,7 +15,7 @@ impl State { .contains(MemoryRangeFlags::WRITE) && m.size().unwrap_or_default() == 0x101000 }) - .find_map(|m| SIG.scan(game, m.range().ok()?))? + .find_map(|m| SIG.scan_once(game, m.range().ok()?))? + 10; let wram: Address = game.read::(scanned_address).ok()?.into(); diff --git a/src/emulator/sms/fusion.rs b/src/emulator/sms/fusion.rs index 6c21e94..2e58414 100644 --- a/src/emulator/sms/fusion.rs +++ b/src/emulator/sms/fusion.rs @@ -1,7 +1,4 @@ -use crate::{ - signature::{Signature, SignatureScanner}, - Address, Address32, Process, -}; +use crate::{signature::Signature, Address, Address32, Process}; #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub struct State { @@ -17,7 +14,7 @@ impl State { .filter(|(_, state)| matches!(state, super::State::Fusion(_))) .find_map(|(name, _)| game.get_module_range(name).ok())?; - let ptr = SIG.scan(game, main_module)? + 4; + let ptr = SIG.scan_once(game, main_module)? + 4; self.addr = game.read::(ptr).ok()?.into(); Some(game.read::(self.addr).ok()?.add(0xC000).into()) diff --git a/src/emulator/sms/mednafen.rs b/src/emulator/sms/mednafen.rs index 00cb563..46f139f 100644 --- a/src/emulator/sms/mednafen.rs +++ b/src/emulator/sms/mednafen.rs @@ -1,8 +1,4 @@ -use crate::{ - file_format::pe, - signature::{Signature, SignatureScanner}, - Address, Address32, Process, -}; +use crate::{file_format::pe, signature::Signature, Address, Address32, Process}; #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub struct State; @@ -21,8 +17,8 @@ impl State { pe::MachineType::read(game, main_module_range.0) == Some(pe::MachineType::X86_64); let ptr = match is_64_bit { - true => SIG_64.scan(game, main_module_range)? + 8, - false => SIG_32.scan(game, main_module_range)? + 7, + true => SIG_64.scan_once(game, main_module_range)? + 8, + false => SIG_32.scan_once(game, main_module_range)? + 7, }; Some(game.read::(ptr).ok()?.into()) diff --git a/src/emulator/sms/retroarch.rs b/src/emulator/sms/retroarch.rs index 5f4d6dc..1858a7a 100644 --- a/src/emulator/sms/retroarch.rs +++ b/src/emulator/sms/retroarch.rs @@ -1,7 +1,5 @@ use crate::{ - file_format::pe, - signature::{Signature, SignatureScanner}, - Address, Address32, Address64, PointerSize, Process, + file_format::pe, signature::Signature, Address, Address32, Address64, PointerSize, Process, }; #[derive(Copy, Clone, Debug, PartialEq, Eq)] @@ -50,11 +48,11 @@ impl State { Some( if is_64_bit { const SIG: Signature<9> = Signature::new("48 8D 0D ?? ?? ?? ?? 41 B8"); - let ptr = SIG.scan(game, (self.core_base, module_size))? + 3; + let ptr = SIG.scan_once(game, (self.core_base, module_size))? + 3; ptr + 0x4 + game.read::(ptr).ok()? } else { const SIG: Signature<8> = Signature::new("B9 ?? ?? ?? ?? C1 EF 10"); - let ptr = SIG.scan(game, (self.core_base, module_size))? + 1; + let ptr = SIG.scan_once(game, (self.core_base, module_size))? + 1; game.read::(ptr).ok()?.into() } + 0x20000, ) @@ -65,11 +63,11 @@ impl State { Some(if is_64_bit { const SIG: Signature<10> = Signature::new("48 8D 0D ?? ?? ?? ?? 4C 8B 2D"); - let ptr = SIG.scan(game, (self.core_base, module_size))? + 3; + let ptr = SIG.scan_once(game, (self.core_base, module_size))? + 3; ptr + 0x4 + game.read::(ptr).ok()? } else { const SIG: Signature<7> = Signature::new("A3 ?? ?? ?? ?? 29 F9"); - let ptr = SIG.scan(game, (self.core_base, module_size))? + 1; + let ptr = SIG.scan_once(game, (self.core_base, module_size))? + 1; game.read::(ptr).ok()?.into() }) } @@ -79,11 +77,11 @@ impl State { Some(if is_64_bit { const SIG: Signature<5> = Signature::new("31 F6 48 C7 05"); - let ptr = SIG.scan(game, (self.core_base, module_size))? + 5; + let ptr = SIG.scan_once(game, (self.core_base, module_size))? + 5; ptr + 0x8 + game.read::(ptr).ok()? } else { const SIG: Signature<4> = Signature::new("83 FA 02 B8"); - let ptr = SIG.scan(game, (self.core_base, module_size))? + 4; + let ptr = SIG.scan_once(game, (self.core_base, module_size))? + 4; game.read::(ptr).ok()?.into() }) } @@ -93,7 +91,7 @@ impl State { Some(if is_64_bit { const SIG: Signature<13> = Signature::new("83 ?? 02 75 ?? 48 8B 0D ?? ?? ?? ?? E8"); - let ptr = SIG.scan(game, (self.core_base, module_size))? + 8; + let ptr = SIG.scan_once(game, (self.core_base, module_size))? + 8; let offset = game .read::(ptr + 13 + 0x4 + game.read::(ptr + 13).ok()? + 3) .ok()?; @@ -111,7 +109,7 @@ impl State { } } else { const SIG: Signature<12> = Signature::new("83 ?? 02 75 ?? 8B ?? ?? ?? ?? ?? E8"); - let ptr = SIG.scan(game, (self.core_base, module_size))? + 7; + let ptr = SIG.scan_once(game, (self.core_base, module_size))? + 7; let offset = game .read::(ptr + 12 + 0x4 + game.read::(ptr + 12).ok()? + 2) .ok()?; diff --git a/src/game_engine/unity/il2cpp.rs b/src/game_engine/unity/il2cpp.rs index fbaf22d..ca078bc 100644 --- a/src/game_engine/unity/il2cpp.rs +++ b/src/game_engine/unity/il2cpp.rs @@ -7,11 +7,8 @@ use core::{ }; use crate::{ - file_format::pe, - future::retry, - signature::{Signature, SignatureScanner}, - string::ArrayCString, - Address, Address64, Error, PointerSize, Process, + file_format::pe, future::retry, signature::Signature, string::ArrayCString, Address, Address64, + Error, PointerSize, Process, }; #[cfg(feature = "derive")] @@ -62,14 +59,14 @@ impl Module { const ASSEMBLIES_TRG_SIG: Signature<12> = Signature::new("48 FF C5 80 3C ?? 00 75 ?? 48 8B 1D"); - let addr = ASSEMBLIES_TRG_SIG.scan(process, mono_module)? + 12; + let addr = ASSEMBLIES_TRG_SIG.scan_once(process, mono_module)? + 12; addr + 0x4 + process.read::(addr).ok()? } PointerSize::Bit32 => { const ASSEMBLIES_TRG_SIG: Signature<9> = Signature::new("8A 07 47 84 C0 75 ?? 8B 35"); - let addr = ASSEMBLIES_TRG_SIG.scan(process, mono_module)? + 9; + let addr = ASSEMBLIES_TRG_SIG.scan_once(process, mono_module)? + 9; process.read_pointer(addr, pointer_size).ok()? } _ => return None, @@ -80,7 +77,7 @@ impl Module { Signature::new("48 83 3C ?? 00 75 ?? 8B C? E8"); let addr = TYPE_INFO_DEFINITION_TABLE_TRG_SIG - .scan(process, mono_module)? + .scan_once(process, mono_module)? .add_signed(-4); process @@ -91,7 +88,7 @@ impl Module { const TYPE_INFO_DEFINITION_TABLE_TRG_SIG: Signature<10> = Signature::new("C3 A1 ?? ?? ?? ?? 83 3C ?? 00"); - let addr = TYPE_INFO_DEFINITION_TABLE_TRG_SIG.scan(process, mono_module)? + 2; + let addr = TYPE_INFO_DEFINITION_TABLE_TRG_SIG.scan_once(process, mono_module)? + 2; process .read_pointer(process.read_pointer(addr, pointer_size).ok()?, pointer_size) @@ -801,14 +798,14 @@ fn detect_version(process: &Process) -> Option { const SIG_202X: Signature<6> = Signature::new("00 32 30 32 ?? 2E"); const SIG_2019: Signature<6> = Signature::new("00 32 30 31 39 2E"); - if SIG_202X.scan(process, unity_module).is_some() { + if SIG_202X.scan_once(process, unity_module).is_some() { let il2cpp_version = { const SIG: Signature<14> = Signature::new("48 2B ?? 48 2B ?? ?? ?? ?? ?? 48 F7 ?? 48"); let address = process.get_module_address("GameAssembly.dll").ok()?; let size = pe::read_size_of_image(process, address)? as u64; let ptr = { - let addr = SIG.scan(process, (address, size))? + 6; + let addr = SIG.scan_once(process, (address, size))? + 6; addr + 0x4 + process.read::(addr).ok()? }; @@ -821,7 +818,7 @@ fn detect_version(process: &Process) -> Option { } else { Version::V2019 }) - } else if SIG_2019.scan(process, unity_module).is_some() { + } else if SIG_2019.scan_once(process, unity_module).is_some() { Some(Version::V2019) } else { Some(Version::Base) diff --git a/src/game_engine/unity/mono.rs b/src/game_engine/unity/mono.rs index 8b8c488..b65aca9 100644 --- a/src/game_engine/unity/mono.rs +++ b/src/game_engine/unity/mono.rs @@ -2,11 +2,8 @@ //! backend. use crate::{ - file_format::pe, - future::retry, - signature::{Signature, SignatureScanner}, - string::ArrayCString, - Address, Address32, Address64, Error, PointerSize, Process, + file_format::pe, future::retry, signature::Signature, string::ArrayCString, Address, Address32, + Address64, Error, PointerSize, Process, }; use core::{ array, @@ -66,17 +63,16 @@ impl Module { PointerSize::Bit64 => { const SIG_MONO_64: Signature<3> = Signature::new("48 8B 0D"); let scan_address: Address = - SIG_MONO_64.scan(process, (root_domain_function_address, 0x100))? + 3; + SIG_MONO_64.scan_once(process, (root_domain_function_address, 0x100))? + 3; scan_address + 0x4 + process.read::(scan_address).ok()? } PointerSize::Bit32 => { const SIG_32_1: Signature<2> = Signature::new("FF 35"); const SIG_32_2: Signature<2> = Signature::new("8B 0D"); - let ptr = [SIG_32_1, SIG_32_2] - .iter() - .find_map(|sig| sig.scan(process, (root_domain_function_address, 0x100)))? - + 2; + let ptr = [SIG_32_1, SIG_32_2].iter().find_map(|sig| { + sig.scan_once(process, (root_domain_function_address, 0x100)) + })? + 2; process.read::(ptr).ok()?.into() } @@ -983,7 +979,7 @@ fn detect_version(process: &Process) -> Option { const SIG_202X: Signature<6> = Signature::new("00 32 30 32 ?? 2E"); - let Some(addr) = SIG_202X.scan(process, unity_module) else { + let Some(addr) = SIG_202X.scan_once(process, unity_module) else { return Some(Version::V2); }; diff --git a/src/game_engine/unity/scene.rs b/src/game_engine/unity/scene.rs index d7c9e2f..0025808 100644 --- a/src/game_engine/unity/scene.rs +++ b/src/game_engine/unity/scene.rs @@ -13,11 +13,8 @@ use core::{ }; use crate::{ - file_format::pe, - future::retry, - signature::{Signature, SignatureScanner}, - string::ArrayCString, - Address, Address32, Address64, Error, PointerSize, Process, + file_format::pe, future::retry, signature::Signature, string::ArrayCString, Address, Address32, + Address64, Error, PointerSize, Process, }; const CSTR: usize = 128; @@ -59,13 +56,13 @@ impl SceneManager { // There are multiple signatures that can be used, depending on the version of Unity // used in the target game. let base_address: Address = if pointer_size == PointerSize::Bit64 { - let addr = SIG_64_BIT.scan(process, unity_player)? + 7; + let addr = SIG_64_BIT.scan_once(process, unity_player)? + 7; addr + 0x4 + process.read::(addr).ok()? - } else if let Some(addr) = SIG_32_1.scan(process, unity_player) { + } else if let Some(addr) = SIG_32_1.scan_once(process, unity_player) { process.read::(addr + 5).ok()?.into() - } else if let Some(addr) = SIG_32_2.scan(process, unity_player) { + } else if let Some(addr) = SIG_32_2.scan_once(process, unity_player) { process.read::(addr.add_signed(-4)).ok()?.into() - } else if let Some(addr) = SIG_32_3.scan(process, unity_player) { + } else if let Some(addr) = SIG_32_3.scan_once(process, unity_player) { process.read::(addr + 7).ok()?.into() } else { return None; diff --git a/src/game_engine/unreal/mod.rs b/src/game_engine/unreal/mod.rs index e2db8dd..f93905b 100644 --- a/src/game_engine/unreal/mod.rs +++ b/src/game_engine/unreal/mod.rs @@ -10,11 +10,8 @@ use core::{ use bytemuck::CheckedBitPattern; use crate::{ - file_format::pe, - future::retry, - signature::{Signature, SignatureScanner}, - string::ArrayCString, - Address, Error, PointerSize, Process, + file_format::pe, future::retry, signature::Signature, string::ArrayCString, Address, Error, + PointerSize, Process, }; const CSTR: usize = 128; @@ -54,7 +51,7 @@ impl Module { let addr = GENGINE .iter() - .find_map(|(sig, offset)| Some(sig.scan(process, module_range)? + *offset))?; + .find_map(|(sig, offset)| Some(sig.scan_once(process, module_range)? + *offset))?; addr + 0x8 + process.read::(addr).ok()? }; @@ -76,7 +73,7 @@ impl Module { let addr = GWORLD .iter() - .find_map(|(sig, offset)| Some(sig.scan(process, module_range)? + *offset))?; + .find_map(|(sig, offset)| Some(sig.scan_once(process, module_range)? + *offset))?; addr + 0x4 + process.read::(addr).ok()? }; @@ -89,7 +86,7 @@ impl Module { let addr = FNAME_POOL .iter() - .find_map(|(sig, offset)| Some(sig.scan(process, module_range)? + *offset))?; + .find_map(|(sig, offset)| Some(sig.scan_once(process, module_range)? + *offset))?; addr + 0x4 + process.read::(addr).ok()? }; @@ -230,7 +227,7 @@ impl UClass { &'a self, process: &'a Process, module: &'a Module, - ) -> impl FusedIterator + 'a { + ) -> impl FusedIterator + '_ { // Logic: properties are contained in a linked list that can be accessed directly // through the `property_link` field, from the most derived to the least derived class. // Source: https://gist.github.com/apple1417/b23f91f7a9e3b834d6d052d35a0010ff#object-structure diff --git a/src/signature.rs b/src/signature.rs index 9fd6fd9..f4a2a51 100644 --- a/src/signature.rs +++ b/src/signature.rs @@ -294,62 +294,36 @@ impl Signature { }) .fuse() } -} -/// Trait that provides scanning methods for the `Signature` type. -pub trait SignatureScanner { /// Scans a process's memory in the given range for the first occurrence of the signature. /// /// # Arguments /// /// * `process` - A reference to the `Process` in which the scan occurs. - /// * `addr` - The starting address of the memory range. - /// * `len` - The length of the memory range to scan. + /// * `range` - A tuple containing: + /// - The starting address of the memory range + /// - The length of the memory range to scan /// /// Returns `Some(Address)` of the first match if found, otherwise `None`. - fn scan<'a>(&'a self, process: &Process, range: (impl Into
, u64)) -> Option
; - - /// Returns an iterator over all occurrences of the signature in the process's memory range. - /// - /// # Arguments - /// - /// * `process` - A reference to the `Process` in which the scan occurs. - /// * `addr` - The starting address of the memory range. - /// * `len` - The length of the memory range to scan. - /// - /// Returns an iterator that yields each matching address. - fn scan_process_range<'a>( + pub fn scan_once<'a>( &'a self, process: &'a Process, range: (impl Into
, u64), - ) -> impl Iterator + 'a; + ) -> Option
{ + self.scan_iter(process, range).next() + } - /// Asynchronously awaits scanning a process for the signature until a match - /// is found. + /// Returns an iterator over all occurrences of the signature in the process's memory range. /// /// # Arguments /// /// * `process` - A reference to the `Process` in which the scan occurs. - /// * `addr` - The starting address of the memory range. - /// * `len` - The length of the memory range to scan. - #[allow(async_fn_in_trait)] - async fn wait_scan_process_range( - &self, - process: &Process, - range: (impl Into
, u64), - ) -> Address; -} - -impl SignatureScanner for Signature { - fn scan<'a>( - &'a self, - process: &'a Process, - range: (impl Into
, u64), - ) -> Option
{ - self.scan_process_range(process, range).next() - } - - fn scan_process_range<'a>( + /// * `range` - A tuple containing: + /// - The starting address of the memory range + /// - The length of the memory range to scan + /// + /// Returns an iterator that yields each matching address. + pub fn scan_iter<'a>( &'a self, process: &'a Process, range: (impl Into
, u64), @@ -454,12 +428,21 @@ impl SignatureScanner for Signature { .flatten() } - async fn wait_scan_process_range( + /// Asynchronously awaits scanning a process for the signature until a match + /// is found. + /// + /// # Arguments + /// + /// * `process` - A reference to the `Process` in which the scan occurs. + /// * `range` - A tuple containing: + /// - The starting address of the memory range + /// - The length of the memory range to scan + pub async fn wait_scan_once( &self, process: &Process, range: (impl Into
, u64), ) -> Address { let addr = range.0.into(); - retry(|| self.scan_process_range(process, (addr, range.1)).next()).await + retry(|| self.scan_iter(process, (addr, range.1)).next()).await } }