diff --git a/src/emulator/ps1/duckstation.rs b/src/emulator/ps1/duckstation.rs index 2967a4a3..ebd4de7e 100644 --- a/src/emulator/ps1/duckstation.rs +++ b/src/emulator/ps1/duckstation.rs @@ -1,4 +1,4 @@ -use crate::{file_format::pe, signature::Signature, Address, Address64, Process}; +use crate::{file_format::pe, signature::Signature, Address, Address64, PointerSize, Process}; #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub struct State { @@ -7,13 +7,16 @@ pub struct State { impl State { pub fn find_ram(&mut self, game: &Process) -> Option
{ - const SIG: Signature<8> = Signature::new("48 89 0D ?? ?? ?? ?? B8"); - let main_module_range = super::PROCESS_NAMES .iter() .filter(|(_, state)| matches!(state, super::State::Duckstation(_))) .find_map(|(name, _)| game.get_module_range(name).ok())?; + // 32bit versions of Duckstation are not supported (nor developed) + if pe::MachineType::read(game, main_module_range.0)?.pointer_size()? != PointerSize::Bit64 { + return None; + } + // Recent Duckstation releases include a debug symbol that can be used to easily retrieve the address of the emulated RAM // Info: https://github.com/stenzek/duckstation/commit/c98e0bd0969abdd82589bfc565aea52119fd0f19 if let Some(debug_symbol) = pe::symbols(game, main_module_range.0).find(|symbol| { @@ -24,20 +27,19 @@ 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; - self.addr = addr + 0x4 + game.read::(addr).ok()?; + const SIG: Signature<8> = Signature::new("48 89 0D ?? ?? ?? ?? B8"); + self.addr = SIG + .scan_process_range(game, main_module_range) + .map(|val| val + 3) + .and_then(|addr| Some(addr + 0x4 + game.read::(addr).ok()?))?; } - Some(game.read::(self.addr).ok()?.into()) + Some(game.read::(self.addr).unwrap_or_default().into()) } pub fn keep_alive(&self, game: &Process, wram_base: &mut Option
) -> bool { - if let Ok(addr) = game.read::(self.addr) { - *wram_base = Some(addr.into()); - true - } else { - false - } + *wram_base = Some(game.read::(self.addr).unwrap_or_default().into()); + true } pub const fn new() -> Self { diff --git a/src/emulator/ps1/epsxe.rs b/src/emulator/ps1/epsxe.rs index d7461fc0..bbcc9444 100644 --- a/src/emulator/ps1/epsxe.rs +++ b/src/emulator/ps1/epsxe.rs @@ -12,9 +12,10 @@ 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; - - Some(game.read::(ptr).ok()?.into()) + SIG.scan_process_range(game, main_module_range) + .map(|val| val + 5) + .and_then(|addr| game.read::(addr).ok()) + .map(|val| val.into()) } pub const fn keep_alive(&self) -> bool { diff --git a/src/emulator/ps1/mednafen.rs b/src/emulator/ps1/mednafen.rs index 9d351bbe..1b15ae93 100644 --- a/src/emulator/ps1/mednafen.rs +++ b/src/emulator/ps1/mednafen.rs @@ -1,4 +1,4 @@ -use crate::{file_format::pe, signature::Signature, Address, Address32, Process}; +use crate::{file_format::pe, signature::Signature, Address, Address32, PointerSize, Process}; #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub struct State; @@ -14,14 +14,15 @@ impl State { .find_map(|(name, _)| game.get_module_range(name).ok())?; let is_64_bit = - pe::MachineType::read(game, main_module_range.0) == Some(pe::MachineType::X86_64); + pe::MachineType::read(game, main_module_range.0)?.pointer_size()? == PointerSize::Bit64; - 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)?, - } + 0x5; - - Some(game.read::(ptr).ok()?.into()) + match is_64_bit { + true => SIG_64.scan_process_range(game, main_module_range), + false => SIG_32.scan_process_range(game, main_module_range), + } + .map(|val| val + 0x5) + .and_then(|addr| game.read::(addr).ok()) + .map(|val| val.into()) } pub const fn keep_alive(&self) -> bool { diff --git a/src/emulator/ps1/mod.rs b/src/emulator/ps1/mod.rs index 3112630c..ae891222 100644 --- a/src/emulator/ps1/mod.rs +++ b/src/emulator/ps1/mod.rs @@ -112,7 +112,7 @@ impl Emulator { State::PsxFin(x) => x.keep_alive(), State::Duckstation(x) => x.keep_alive(&self.process, &mut ram_base), State::Retroarch(x) => x.keep_alive(&self.process), - State::PcsxRedux(x) => x.keep_alive(&self.process), + State::PcsxRedux(x) => x.keep_alive(&self.process, &mut ram_base), State::Xebra(x) => x.keep_alive(), State::Mednafen(x) => x.keep_alive(), }; @@ -132,10 +132,14 @@ impl Emulator { /// /// Valid addresses for the PS1 range from `0x80000000` to `0x817FFFFF`. pub fn get_address(&self, offset: u32) -> Result { + let addr = self + .ram_base + .get() + .filter(|addr| !addr.is_null()) + .ok_or(Error {})?; + match offset { - (0x80000000..=0x817FFFFF) => { - Ok(self.ram_base.get().ok_or(Error {})? + offset.sub(0x80000000)) - } + (0x80000000..=0x817FFFFF) => Ok(addr + offset.sub(0x80000000)), _ => Err(Error {}), } } diff --git a/src/emulator/ps1/pcsx_redux.rs b/src/emulator/ps1/pcsx_redux.rs index b193c0a4..cbd59217 100644 --- a/src/emulator/ps1/pcsx_redux.rs +++ b/src/emulator/ps1/pcsx_redux.rs @@ -1,12 +1,9 @@ -use crate::{ - file_format::pe, signature::Signature, Address, Address32, Address64, MemoryRangeFlags, Process, -}; +use crate::{file_format::pe, signature::Signature, Address, Address64, PointerSize, Process}; #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub struct State { - is_64_bit: bool, addr_base: Address, - addr: Address, + offsets: [u64; 3], } impl State { @@ -16,58 +13,43 @@ impl State { .filter(|(_, state)| matches!(state, super::State::PcsxRedux(_))) .find_map(|(name, _)| game.get_module_range(name).ok())?; - self.is_64_bit = - pe::MachineType::read(game, main_module_range.0) == Some(pe::MachineType::X86_64); - - if self.is_64_bit { - const SIG_BASE: Signature<25> = Signature::new( - "48 B9 ?? ?? ?? ?? ?? ?? ?? ?? E8 ?? ?? ?? ?? C7 85 ?? ?? ?? ?? 00 00 00 00", - ); - 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 = game.read::(self.addr_base).ok()?.into(); + if pe::MachineType::read(game, main_module_range.0)?.pointer_size()? != PointerSize::Bit64 { + return None; + } - let offset = SIG_OFFSET.scan_process_range(game, main_module_range)? + 8; - let offset = game.read::(offset).ok()? as u64; + const SIG_BASE: Signature<19> = + Signature::new("48 8B 05 ?? ?? ?? ?? 48 8B 80 ?? ?? ?? ?? 48 8B 50 ?? E8"); - let addr = game.read::(self.addr + offset).ok()?; + let addr = SIG_BASE.scan_process_range(game, main_module_range)? + 3; - Some(game.read::(addr).ok()?.into()) - } else { - const SIG: Signature<18> = - Signature::new("8B 3D 20 ?? ?? ?? 0F B7 D3 8B 04 95 ?? ?? ?? ?? 21 05"); + self.addr_base = addr + 0x4 + game.read::(addr).ok()?; - self.addr_base = game - .memory_ranges() - .filter(|m| { - m.flags() - .unwrap_or_default() - .contains(MemoryRangeFlags::WRITE) - }) - .find_map(|m| SIG.scan_process_range(game, m.range().ok()?))? - + 2; + self.offsets = [ + 0, + game.read::(addr + 7).ok()? as u64, + game.read::(addr + 14).ok()?.into(), + ]; - self.addr = game.read::(self.addr_base).ok()?.into(); - Some(self.addr) - } + Some( + game.read_pointer_path::(self.addr_base, PointerSize::Bit64, &self.offsets) + .unwrap_or_default() + .into(), + ) } - pub fn keep_alive(&self, game: &Process) -> bool { - if self.is_64_bit { - game.read::(self.addr_base) - .is_ok_and(|addr| self.addr == addr.into()) - } else { - game.read::(self.addr_base) - .is_ok_and(|addr| self.addr == addr.into()) - } + pub fn keep_alive(&self, game: &Process, ram_base: &mut Option
) -> bool { + *ram_base = Some( + game.read_pointer_path::(self.addr_base, PointerSize::Bit64, &self.offsets) + .unwrap_or_default() + .into(), + ); + true } pub const fn new() -> Self { Self { - is_64_bit: true, addr_base: Address::NULL, - addr: Address::NULL, + offsets: [0; 3], } } } diff --git a/src/emulator/ps1/psxfin.rs b/src/emulator/ps1/psxfin.rs index 73fc5f02..f6d5d723 100644 --- a/src/emulator/ps1/psxfin.rs +++ b/src/emulator/ps1/psxfin.rs @@ -15,26 +15,26 @@ 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 ptr: Address = SIG + .scan_process_range(game, main_module_range) + .and_then(|addr| { + game.read::(addr + 2) + .ok() + .map(|addr| addr.into()) + }) + .or_else(|| SIG_0.scan_process_range(game, main_module_range)) + .or_else(|| SIG_1.scan_process_range(game, main_module_range)) + .or_else(|| SIG_2.scan_process_range(game, main_module_range)) + .and_then(|addr| { + game.read::(addr + 1) + .ok() + .map(|addr| addr.into()) + })?; - ptr = game.read::(ptr).ok()?; - - if ptr.is_null() { - None - } else { - Some(ptr.into()) - } + game.read::(ptr) + .ok() + .filter(|val| !val.is_null()) + .map(|addr| addr.into()) } pub const fn keep_alive(&self) -> bool { diff --git a/src/emulator/ps1/retroarch.rs b/src/emulator/ps1/retroarch.rs index 50b7c42b..ccf18ac1 100644 --- a/src/emulator/ps1/retroarch.rs +++ b/src/emulator/ps1/retroarch.rs @@ -1,4 +1,6 @@ -use crate::{file_format::pe, signature::Signature, Address, Address32, Address64, Process}; +use crate::{ + file_format::pe, signature::Signature, Address, Address32, Address64, PointerSize, Process, +}; #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub struct State { @@ -20,7 +22,7 @@ impl State { .find_map(|(name, _)| game.get_module_address(name).ok())?; let is_64_bit = - pe::MachineType::read(game, main_module_address) == Some(pe::MachineType::X86_64); + pe::MachineType::read(game, main_module_address)?.pointer_size()? == PointerSize::Bit64; let (core_name, core_address) = SUPPORTED_CORES .iter() @@ -28,65 +30,79 @@ impl State { self.core_base = core_address; + let base_scan = pe::symbols(game, core_address) + .find(|symbol| { + symbol + .get_name::<22>(game) + .is_ok_and(|name| name.matches(b"retro_get_memory_data")) + })? + .address; + if core_name == SUPPORTED_CORES[0] || core_name == SUPPORTED_CORES[1] { // Mednafen 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 = ptr + 0x4 + game.read::(ptr).ok()?; - Some(game.read::(ptr).ok()?.into()) + const SIG: Signature<4> = Signature::new("48 0F 44 05"); + SIG.scan_process_range(game, (base_scan, 0x100)) + .map(|addr| addr + 4) + .and_then(|addr| { + game.read::(addr + 0x4 + game.read::(addr).ok()?) + .ok() + }) + .map(|addr| addr.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 = game.read::(ptr).ok()?; - Some(game.read::(ptr).ok()?.into()) + const SIG: Signature<3> = Signature::new("0F 44 05"); + SIG.scan_process_range(game, (base_scan, 0x100)) + .map(|addr| addr + 3) + .and_then(|addr| { + game.read::(game.read::(addr).ok()?) + .ok() + }) + .map(|addr| addr.into()) } } else if core_name == SUPPORTED_CORES[2] { // Swanstation 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 ptr = addr + 0x4 + game.read::(addr).ok()?; - Some(game.read::(ptr).ok()?.into()) + const SIG: Signature<8> = Signature::new("48 8B 05 ?? ?? ?? ?? C3"); + SIG.scan_process_range(game, (base_scan, 0x100)) + .map(|addr| addr + 3) + .and_then(|addr| { + game.read::(addr + 0x4 + game.read::(addr).ok()?) + .ok() + }) + .map(|addr| addr.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 = game.read::(ptr).ok()?; - Some(game.read::(ptr).ok()?.into()) + const SIG: Signature<3> = Signature::new("74 ?? A1"); + SIG.scan_process_range(game, (base_scan, 0x100)) + .map(|addr| addr + 3) + .and_then(|addr| { + game.read::(game.read::(addr).ok()?) + .ok() + }) + .map(|addr| addr.into()) } } else if core_name == SUPPORTED_CORES[3] { // 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 ptr = addr + 0x4 + game.read::(addr).ok()?; - let ptr = game.read::(ptr).ok()?; - Some(game.read::(ptr).ok()?.into()) + const SIG: Signature<10> = Signature::new("48 8B 05 ?? ?? ?? ?? 48 8B 00"); + SIG.scan_process_range(game, (base_scan, 0x100)) + .map(|addr| addr + 3) + .and_then(|addr| { + game.read::( + game.read::(addr + 0x4 + game.read::(addr).ok()?) + .ok()?, + ) + .ok() + }) + .map(|addr| addr.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 = game.read::(ptr).ok()?; - Some(game.read::(ptr).ok()?.into()) + const SIG: Signature<8> = Signature::new("0F 44 05 ?? ?? ?? ?? C3"); + SIG.scan_process_range(game, (base_scan, 0x100)) + .map(|addr| addr + 3) + .and_then(|addr| { + game.read::(game.read::(addr).ok()?) + .ok() + }) + .map(|addr| addr.into()) } } else { None diff --git a/src/emulator/ps1/xebra.rs b/src/emulator/ps1/xebra.rs index 5cbae53d..74ea079d 100644 --- a/src/emulator/ps1/xebra.rs +++ b/src/emulator/ps1/xebra.rs @@ -12,11 +12,12 @@ 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 addr = ptr + 0x4 + game.read::(ptr).ok()?; - let addr = game.read::(addr + 0x16A).ok()?; - let addr = game.read::(addr).ok()?; - Some(addr.into()) + SIG.scan_process_range(game, main_module_range) + .map(|addr| addr + 1) + .and_then(|addr| Some(addr + 0x4 + game.read::(addr).ok()?)) + .and_then(|addr| game.read::(addr + 0x16A).ok()) + .and_then(|addr| game.read::(addr).ok()) + .map(|addr| addr.into()) } pub const fn keep_alive(&self) -> bool {