Skip to content

Commit

Permalink
Add automatic version detection
Browse files Browse the repository at this point in the history
  • Loading branch information
CryZe committed Dec 24, 2023
1 parent 5558f68 commit 900d3fc
Show file tree
Hide file tree
Showing 5 changed files with 261 additions and 112 deletions.
152 changes: 152 additions & 0 deletions src/engine.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
use asr::{future::retry, signature::Signature, Address, Address64, Process};

/// sub rsp,28
/// mov rcx,??
/// call ??
/// test rax,rax
/// je +7
/// mov eax,[rax]
/// add rsp,28
/// ret
/// mov eax,FFFFFFFF
/// add rsp,28
/// ret
const MOV_INST_MONDEALY_OFFSET: u64 = 7;
static VAR_LOOKUP_SIG_MONDEALY: Signature<38> = Signature::new(
"
48 83 ec 28
48 8b 0d ????????
e8 ????????
48 85 c0
74 07
8b 00
48 83 c4 28
c3
b8 ffffffff
48 83 c4 28
c3
",
);

// mov [rsp+08],rbx
// mov [rsp+10],rbp
// mov [rsp+18],rsi
// push rdi
// push r14
// push r15
// sub rsp,20
// mov r14,?
// mov rcx,rdx
// mov r15,rdx
// call ?
// mov r11d,[r14+08]
// mov ebp,eax
// mov rsi,[r14+10]
// btr ebp,1F
const MOV_INST_NOV_2023_OFFSET: u64 = 27;
static VAR_LOOKUP_SIG_NOV_2023: Signature<56> = Signature::new(
"
48 89 5C 24 08
48 89 6C 24 10
48 89 74 24 18
57
41 56
41 57
48 83 EC 20
4C 8B 35 ????????
48 8B CA
4C 8B FA
E8 ????????
45 8B 5E 08
8B E8
49 8B 76 10
0FBA F5 1F
",
);

static RUN_ROOM_SIG: Signature<35> = Signature::new("48 b8 00 00 00 00 00 00 10 c0 41 c7 40 0c 00 00 00 00 49 89 00 48 8b 05 ?? ?? ?? ?? 48 85 c0 74 48 85 d2");
// static GP_GLOBAL_SIG: Signature<23> =
// Signature::new("e8 ?? ?? ?? ?? 48 8b 3d ?? ?? ?? ?? 33 ed 48 8b c8 48 89 2b 89 6b 08");

pub struct Engine {
pub instance_var_lookup: Address,
pub run_room: Address,
pub version_specific: &'static VersionSpecific,
}

pub struct VersionSpecific {
pub slot_to_var_map_uses_complex_hash: bool,
/// On CInstance: CInstance* m_pNext
pub c_instance_p_next_offset: u16,
}

impl Engine {
pub async fn attach(process: &Process, process_name: &str) -> Self {
let module_range = process.wait_module_range(process_name).await;

// let gp_global_sig = GP_GLOBAL_SIG
// .scan_process_range(&process, module_range)
// .unwrap();

// let var_lookup_sig = VAR_LOOKUP_SIG_MONDEALY
// .scan_process_range(&process, module_range)
// .unwrap();

// let instance_var_lookup_ptr = var_lookup_sig
// + (MOV_RCX_MONDEALY_OFFSET + 4)
// + process
// .read::<u32>(var_lookup_sig + MOV_RCX_MONDEALY_OFFSET)
// .unwrap();
// let instance_var_lookup =
// process.read::<Address64>(instance_var_lookup_ptr).unwrap();

let (var_lookup_sig, version_specific) = retry(|| {
if let Some(addr) = VAR_LOOKUP_SIG_NOV_2023.scan_process_range(process, module_range) {
return Some((
addr + MOV_INST_NOV_2023_OFFSET,
&VersionSpecific {
slot_to_var_map_uses_complex_hash: false,
c_instance_p_next_offset: 0x1A0,
},
));
}
if let Some(addr) = VAR_LOOKUP_SIG_MONDEALY.scan_process_range(process, module_range) {
return Some((
addr + MOV_INST_MONDEALY_OFFSET,
&VersionSpecific {
slot_to_var_map_uses_complex_hash: true,
c_instance_p_next_offset: 0x198,
},
));
}
None
})
.await;

let instance_var_lookup = retry(|| {
let instance_var_lookup_ptr =
var_lookup_sig + 4 + process.read::<u32>(var_lookup_sig)?;

process.read::<Address64>(instance_var_lookup_ptr)
})
.await;

let run_room_sig = retry(|| RUN_ROOM_SIG.scan_process_range(process, module_range)).await;

let run_room = retry(|| {
let run_room_ptr = run_room_sig + 28 + process.read::<u32>(run_room_sig + 24)?;
process.read::<Address64>(run_room_ptr)
})
.await;

// let gp_global_ptr =
// gp_global_sig + 12 + process.read::<u32>(gp_global_sig + 8).unwrap();
// let _gp_global = process.read::<Address64>(gp_global_ptr).unwrap();

Self {
instance_var_lookup: instance_var_lookup.into(),
run_room: run_room.into(),
version_specific,
}
}
}
19 changes: 10 additions & 9 deletions src/hash_map/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use core::mem;

use asr::{Address64, Error, Process};
use asr::{Address, Address64, Error, Process};
use bytemuck::{Pod, Zeroable};

use crate::SmallStr;
Expand Down Expand Up @@ -35,24 +35,24 @@ impl Hash for SmallStr {

impl Hash for i32 {
type SlotKey = i32;
type CompareKey = i32;
type CompareKey = (i32, bool);

fn hash(compare_key: &Self::CompareKey) -> u32 {
(*compare_key as u32)
.wrapping_mul(0x9E3779B1)
fn hash(&(compare_key, is_complex): &Self::CompareKey) -> u32 {
(compare_key as u32)
.wrapping_mul(is_complex as u32 * 0x9E3779B0 + 1)
.wrapping_add(1)
}

fn read_from_slot(slot_key: &Self::SlotKey, _process: &Process) -> Result<Self, Error> {
Ok(*slot_key)
}

fn matches(&self, compare_key: &Self::CompareKey) -> bool {
fn matches(&self, (compare_key, _): &Self::CompareKey) -> bool {
self == compare_key
}
}

#[derive(Copy, Clone, Pod, Zeroable)]
#[derive(Debug, Copy, Clone, Pod, Zeroable)]
#[repr(C)]
struct CHashMap {
cur_size: u32,
Expand All @@ -73,9 +73,10 @@ struct Slot<K, V> {
unsafe impl<K: Pod, V: Pod> Pod for Slot<K, V> {}
unsafe impl<K: Zeroable, V: Zeroable> Zeroable for Slot<K, V> {}

/// Based on Code_Variable_Find_Slot_From_Name
pub fn lookup<K: Hash, V: Pod>(
process: &Process,
hash_map: Address64,
hash_map: Address,
key: &K::CompareKey,
) -> Result<Option<V>, Error> {
let hash = K::hash(key) & 0x7fffffff;
Expand Down Expand Up @@ -115,7 +116,7 @@ pub fn lookup<K: Hash, V: Pod>(

pub fn iter<K: Hash + 'static, V: Pod>(
process: &Process,
hash_map: Address64,
hash_map: Address,
) -> Result<impl Iterator<Item = (K, V)> + '_, Error> {
let hash_map = process.read::<CHashMap>(hash_map)?;

Expand Down
91 changes: 37 additions & 54 deletions src/instance.rs
Original file line number Diff line number Diff line change
@@ -1,39 +1,9 @@
use core::iter;

use asr::{Address64, Error, Process};
use asr::{Address, Address64, Error, Process};
use bytemuck::{Pod, Zeroable};

use crate::{hash_map, variable::Variable, SmallStr};

/// CInstance
mod c_instance {
/// CObjectGM* m_pObject
pub const P_OBJECT_OFFSET: u64 = 0x90;
/// int i_id
pub const ID_OFFSET: u64 = 0xb4;
}

/// CObjectGM
mod c_object_gm {
/// char* m_pName
pub const P_NAME_OFFSET: u64 = 0x00;
}

/// YYObjectBase
mod yy_object_base {
/// CHashMap<int,_RValue_*,_3>* m_yyvarsMap
pub const YY_VARS_MAP_OFFSET: u64 = 0x48;
}

/// RValue
mod r_value {
// /// union field_0
// pub const FIELD_0_OFFSET: u64 = 0x0;
// /// uint flags
// pub const FLAGS_OFFSET: u64 = 0x8;
/// uint kind
pub const KIND_OFFSET: u64 = 0xc;
}
use crate::{engine::Engine, hash_map, offset, variable::Variable, SmallStr};

#[derive(Copy, Clone, Pod, Zeroable)]
#[repr(transparent)]
Expand All @@ -43,33 +13,42 @@ pub struct Instance {

impl Instance {
pub fn read_id(self, process: &Process) -> Result<i32, Error> {

Check warning on line 15 in src/instance.rs

View workflow job for this annotation

GitHub Actions / Build

methods `read_id` and `read_variable` are never used

Check warning on line 15 in src/instance.rs

View workflow job for this annotation

GitHub Actions / Check clippy lints

methods `read_id` and `read_variable` are never used
process.read::<i32>(self.addr + c_instance::ID_OFFSET)
process.read::<i32>(self.addr + offset::c_instance::ID)
}

pub fn read_object_name(self, process: &Process) -> Result<SmallStr, Error> {
let obj_ptr = process.read::<Address64>(self.addr + c_instance::P_OBJECT_OFFSET)?;
process.read(process.read::<Address64>(obj_ptr + c_object_gm::P_NAME_OFFSET)?)
let obj_ptr = process.read::<Address64>(self.addr + offset::c_instance::P_OBJECT)?;
process.read(process.read::<Address64>(obj_ptr + offset::c_object_gm::P_NAME)?)
}

pub fn read_variable(
self,
process: &Process,
instance_var_lookup: Address64,
name: &str,
engine: &Engine,
) -> Result<(Address64, Option<Variable>), Error> {
let slot = hash_map::lookup::<SmallStr, i32>(process, instance_var_lookup, name)?.unwrap();
self.read_variable_by_slot(process, slot)
let slot =
hash_map::lookup::<SmallStr, i32>(process, engine.instance_var_lookup, name)?.unwrap();
self.read_variable_by_slot(process, slot, engine)
}

fn read_variable_by_slot(
self,
process: &Process,
slot: i32,
engine: &Engine,
) -> Result<(Address64, Option<Variable>), Error> {
let yy_vars_map_ptr =
process.read::<Address64>(self.addr + yy_object_base::YY_VARS_MAP_OFFSET)?;

let Some(rv_ptr) = hash_map::lookup::<i32, Address64>(process, yy_vars_map_ptr, &slot)?
process.read::<Address64>(self.addr + offset::yy_object_base::YY_VARS_MAP)?;

let Some(rv_ptr) = hash_map::lookup::<i32, Address64>(
process,
yy_vars_map_ptr.into(),
&(
slot,
engine.version_specific.slot_to_var_map_uses_complex_hash,
),
)?
else {
return Ok((Address64::NULL, None));
};
Expand All @@ -78,7 +57,7 @@ impl Instance {
return Ok((rv_ptr, None));
}

let kind = process.read::<i32>(rv_ptr + r_value::KIND_OFFSET)? & 0x0ffffff;
let kind = process.read::<i32>(rv_ptr + offset::r_value::KIND)? & 0x0ffffff;
let variable = match kind {
0 => Variable::Real(process.read(rv_ptr)?),
1 => {
Expand All @@ -104,15 +83,15 @@ impl Instance {
Ok((rv_ptr, Some(variable)))
}

pub fn iter_variables(
pub fn iter_variables<'both>(
self,
process: &Process,
instance_var_lookup: Address64,
) -> Result<impl Iterator<Item = (SmallStr, Variable)> + '_, Error> {
process: &'both Process,
engine: &'both Engine,
) -> Result<impl Iterator<Item = (SmallStr, Variable)> + 'both, Error> {
Ok(
hash_map::iter::<SmallStr, i32>(process, instance_var_lookup)?.flat_map(
hash_map::iter::<SmallStr, i32>(process, engine.instance_var_lookup)?.flat_map(
move |(var_name, slot)| {
if let Ok((_, Some(var))) = self.read_variable_by_slot(process, slot) {
if let Ok((_, Some(var))) = self.read_variable_by_slot(process, slot, engine) {
Some((var_name, var))
} else {
None
Expand All @@ -123,17 +102,21 @@ impl Instance {
}
}

pub fn iter_all(process: &Process, run_room: Address64) -> impl Iterator<Item = Instance> + '_ {
const RUN_ROOM_LINKED_LIST_OFFSET: u64 = 216;
const P_NEXT_PTR_OFFSET: u64 = 0x198;

pub fn iter_all<'both>(
process: &'both Process,
engine: &'both Engine,
) -> impl Iterator<Item = Instance> + 'both {
let instance = process
.read::<Instance>(run_room + RUN_ROOM_LINKED_LIST_OFFSET)
.read::<Instance>(
engine.run_room + (offset::c_room::M_ACTIVE + offset::o_linked_list::M_P_FIRST),
)
.ok();

iter::successors(instance, move |&instance| {
process
.read::<Instance>(instance.addr + P_NEXT_PTR_OFFSET)
.read::<Instance>(
Address::from(instance.addr) + engine.version_specific.c_instance_p_next_offset,
)
.ok()
.filter(|instance| !instance.addr.is_null())
})
Expand Down
Loading

0 comments on commit 900d3fc

Please sign in to comment.