From 98baddd48b72b5ce24d6d898fc3d7804493453e1 Mon Sep 17 00:00:00 2001 From: Jujstme Date: Sat, 11 May 2024 20:51:21 +0200 Subject: [PATCH 01/13] UnityPointer bugfixing for IL2CPP --- src/game_engine/unity/il2cpp.rs | 92 ++++++++++----------------------- 1 file changed, 28 insertions(+), 64 deletions(-) diff --git a/src/game_engine/unity/il2cpp.rs b/src/game_engine/unity/il2cpp.rs index f6e55b8..120550d 100644 --- a/src/game_engine/unity/il2cpp.rs +++ b/src/game_engine/unity/il2cpp.rs @@ -3,7 +3,7 @@ use core::{array, cell::RefCell, iter}; use crate::{ - deep_pointer::DeepPointer, file_format::pe, future::retry, signature::Signature, + file_format::pe, future::retry, signature::Signature, string::ArrayCString, Address, Address64, Error, PointerSize, Process, }; @@ -545,7 +545,6 @@ struct UnityPointerCache { base_address: Address, offsets: [u64; CAP], resolved_offsets: usize, - current_instance_pointer: Option
, starting_class: Option, } @@ -565,9 +564,8 @@ impl UnityPointer { let cache = RefCell::new(UnityPointerCache { base_address: Address::default(), offsets: [u64::default(); CAP], - current_instance_pointer: None, - starting_class: None, resolved_offsets: usize::default(), + starting_class: None, }); Self { @@ -597,47 +595,48 @@ impl UnityPointer { let starting_class = match cache.starting_class { Some(starting_class) => starting_class, _ => { - let mut current_class = image - .get_class(process, module, self.class_name) - .ok_or(Error {})?; - + let mut current_class = image.get_class(process, module, self.class_name).ok_or(Error {})?; for _ in 0..self.nr_of_parents { current_class = current_class.get_parent(process, module).ok_or(Error {})?; } - cache.starting_class = Some(current_class); current_class - } + }, }; // Recovering the address of the static table is not very CPU intensive, // but it might be worth caching it as well if cache.base_address.is_null() { - let s_table = starting_class + cache.base_address = starting_class .get_static_table(process, module) .ok_or(Error {})?; - cache.base_address = s_table; + + if cache.base_address.is_null() { + return Err(Error{}); + } }; - // As we need to be able to find instances in a more reliable way, - // instead of the Class itself, we need the address pointing to an - // instance of that Class. If the cache is empty, we start from the - // pointer to the static table of the first class. - let mut current_instance_pointer = match cache.current_instance_pointer { - Some(val) => val, - _ => starting_class.get_static_table_pointer(module), + // If we already resolved some offsets, we need to traverse them again starting from the base address + // of the static table in order to recalculate the address of the farthest object we can reach. + // If no offsets have been resolved yet, we just need to read the base address instead. + let mut current_object = match cache.resolved_offsets { + 0 => cache.base_address, + x => { + let mut addr = cache.base_address; + for &i in &cache.offsets[..x] { + addr = process.read_pointer(addr + i, module.pointer_size)?; + } + addr + }, }; // We keep track of the already resolved offsets in order to skip resolving them again for i in cache.resolved_offsets..self.depth { - let class_instance = process - .read_pointer(current_instance_pointer, module.pointer_size) - .ok() - .filter(|val| !val.is_null()) - .ok_or(Error {})?; + let offset_from_string = match self.fields[i].strip_prefix("0x") { + Some(rem) => u32::from_str_radix(rem, 16).ok(), + _ => self.fields[i].parse().ok(), + }; - // Try to parse the offset, passed as a string, as an actual hex or decimal value - let offset_from_string = super::value_from_string(self.fields[i]); let current_offset = match offset_from_string { Some(offset) => offset as u64, @@ -646,7 +645,7 @@ impl UnityPointer { 0 => starting_class, _ => { let class = process - .read_pointer(class_instance, module.pointer_size) + .read_pointer(current_object, module.pointer_size) .ok() .filter(|val| !val.is_null()) .ok_or(Error {})?; @@ -672,32 +671,14 @@ impl UnityPointer { }; cache.offsets[i] = current_offset; - - current_instance_pointer = class_instance + current_offset; - cache.current_instance_pointer = Some(current_instance_pointer); cache.resolved_offsets += 1; + + current_object = process.read_pointer(current_object + current_offset, module.pointer_size)?; } Ok(()) } - /// Dereferences the pointer path, returning the memory address of the value of interest - pub fn deref_offsets( - &self, - process: &Process, - module: &Module, - image: &Image, - ) -> Result { - self.find_offsets(process, module, image)?; - let cache = self.cache.borrow(); - let mut address = cache.base_address; - let (&last, path) = cache.offsets[..self.depth].split_last().ok_or(Error {})?; - for &offset in path { - address = process.read_pointer(address + offset, module.pointer_size)?; - } - Ok(address + last) - } - /// Dereferences the pointer path, returning the value stored at the final memory address pub fn deref( &self, @@ -713,23 +694,6 @@ impl UnityPointer { &cache.offsets[..self.depth], ) } - - /// Generates a `DeepPointer` struct based on the offsets - /// recovered from this `UnityPointer`. - pub fn get_deep_pointer( - &self, - process: &Process, - module: &Module, - image: &Image, - ) -> Option> { - self.find_offsets(process, module, image).ok()?; - let cache = self.cache.borrow(); - Some(DeepPointer::::new( - cache.base_address, - module.pointer_size, - &cache.offsets[..self.depth], - )) - } } struct Offsets { From ad4c0c707b800cd28b8e6451011405b53ef824b8 Mon Sep 17 00:00:00 2001 From: Jujstme Date: Sat, 11 May 2024 21:17:32 +0200 Subject: [PATCH 02/13] Formatting + Fixing Mono --- src/game_engine/unity/il2cpp.rs | 18 +++++++----- src/game_engine/unity/mono.rs | 52 ++++++++++++++++----------------- 2 files changed, 36 insertions(+), 34 deletions(-) diff --git a/src/game_engine/unity/il2cpp.rs b/src/game_engine/unity/il2cpp.rs index 120550d..76c3e08 100644 --- a/src/game_engine/unity/il2cpp.rs +++ b/src/game_engine/unity/il2cpp.rs @@ -3,8 +3,8 @@ use core::{array, cell::RefCell, iter}; use crate::{ - file_format::pe, future::retry, signature::Signature, - string::ArrayCString, Address, Address64, Error, PointerSize, Process, + file_format::pe, future::retry, signature::Signature, string::ArrayCString, Address, Address64, + Error, PointerSize, Process, }; #[cfg(feature = "derive")] @@ -595,13 +595,15 @@ impl UnityPointer { let starting_class = match cache.starting_class { Some(starting_class) => starting_class, _ => { - let mut current_class = image.get_class(process, module, self.class_name).ok_or(Error {})?; + let mut current_class = image + .get_class(process, module, self.class_name) + .ok_or(Error {})?; for _ in 0..self.nr_of_parents { current_class = current_class.get_parent(process, module).ok_or(Error {})?; } cache.starting_class = Some(current_class); current_class - }, + } }; // Recovering the address of the static table is not very CPU intensive, @@ -612,7 +614,7 @@ impl UnityPointer { .ok_or(Error {})?; if cache.base_address.is_null() { - return Err(Error{}); + return Err(Error {}); } }; @@ -627,7 +629,7 @@ impl UnityPointer { addr = process.read_pointer(addr + i, module.pointer_size)?; } addr - }, + } }; // We keep track of the already resolved offsets in order to skip resolving them again @@ -637,7 +639,6 @@ impl UnityPointer { _ => self.fields[i].parse().ok(), }; - let current_offset = match offset_from_string { Some(offset) => offset as u64, _ => { @@ -673,7 +674,8 @@ impl UnityPointer { cache.offsets[i] = current_offset; cache.resolved_offsets += 1; - current_object = process.read_pointer(current_object + current_offset, module.pointer_size)?; + current_object = + process.read_pointer(current_object + current_offset, module.pointer_size)?; } Ok(()) diff --git a/src/game_engine/unity/mono.rs b/src/game_engine/unity/mono.rs index 3e63dc8..28b0036 100644 --- a/src/game_engine/unity/mono.rs +++ b/src/game_engine/unity/mono.rs @@ -591,7 +591,6 @@ struct UnityPointerCache { base_address: Address, offsets: [u64; CAP], resolved_offsets: usize, - current_instance_pointer: Option
, starting_class: Option, } @@ -611,9 +610,8 @@ impl UnityPointer { let cache = RefCell::new(UnityPointerCache { base_address: Address::default(), offsets: [u64::default(); CAP], - current_instance_pointer: None, - starting_class: None, resolved_offsets: usize::default(), + starting_class: None, }); Self { @@ -659,33 +657,35 @@ impl UnityPointer { // Recovering the address of the static table is not very CPU intensive, // but it might be worth caching it as well if cache.base_address.is_null() { - let s_table = starting_class + cache.base_address = starting_class .get_static_table(process, module) .ok_or(Error {})?; - cache.base_address = s_table; + + if cache.base_address.is_null() { + return Err(Error {}); + } }; - // As we need to be able to find instances in a more reliable way, - // instead of the Class itself, we need the address pointing to an - // instance of that Class. If the cache is empty, we start from the - // pointer to the static table of the first class. - let mut current_instance_pointer = match cache.current_instance_pointer { - Some(val) => val, - _ => starting_class - .get_static_table_pointer(process, module) - .ok_or(Error {})?, + // If we already resolved some offsets, we need to traverse them again starting from the base address + // of the static table in order to recalculate the address of the farthest object we can reach. + // If no offsets have been resolved yet, we just need to read the base address instead. + let mut current_object = match cache.resolved_offsets { + 0 => cache.base_address, + x => { + let mut addr = cache.base_address; + for &i in &cache.offsets[..x] { + addr = process.read_pointer(addr + i, module.pointer_size)?; + } + addr + } }; // We keep track of the already resolved offsets in order to skip resolving them again for i in cache.resolved_offsets..self.depth { - let class_instance = process - .read_pointer(current_instance_pointer, module.pointer_size) - .ok() - .filter(|val| !val.is_null()) - .ok_or(Error {})?; - - // Try to parse the offset, passed as a string, as an actual hex or decimal value - let offset_from_string = super::value_from_string(self.fields[i]); + let offset_from_string = match self.fields[i].strip_prefix("0x") { + Some(rem) => u32::from_str_radix(rem, 16).ok(), + _ => self.fields[i].parse().ok(), + }; let current_offset = match offset_from_string { Some(offset) => offset as u64, @@ -696,7 +696,7 @@ impl UnityPointer { let class = process .read_pointer( process - .read_pointer(class_instance, module.pointer_size) + .read_pointer(current_object, module.pointer_size) .ok() .filter(|val| !val.is_null()) .ok_or(Error {})?, @@ -728,10 +728,10 @@ impl UnityPointer { }; cache.offsets[i] = current_offset; - - current_instance_pointer = class_instance + current_offset; - cache.current_instance_pointer = Some(current_instance_pointer); cache.resolved_offsets += 1; + + current_object = + process.read_pointer(current_object + current_offset, module.pointer_size)?; } Ok(()) From e72f67e5f2915abb6f96be1646e072140c8ae8a4 Mon Sep 17 00:00:00 2001 From: Jujstme Date: Sat, 11 May 2024 21:18:00 +0200 Subject: [PATCH 03/13] Remove unused code --- src/game_engine/unity/mod.rs | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/game_engine/unity/mod.rs b/src/game_engine/unity/mod.rs index 277f97f..1d4b970 100644 --- a/src/game_engine/unity/mod.rs +++ b/src/game_engine/unity/mod.rs @@ -88,11 +88,3 @@ pub mod mono; mod scene; pub use self::scene::*; - -fn value_from_string(value: &str) -> Option { - if let Some(rem) = value.strip_prefix("0x") { - u32::from_str_radix(rem, 16).ok() - } else { - value.parse().ok() - } -} From b9328e1ca51099a3dca061446f19da0a25ec52af Mon Sep 17 00:00:00 2001 From: Jujstme Date: Sat, 11 May 2024 21:20:36 +0200 Subject: [PATCH 04/13] Cleanup --- src/game_engine/unity/mono.rs | 38 ++--------------------------------- 1 file changed, 2 insertions(+), 36 deletions(-) diff --git a/src/game_engine/unity/mono.rs b/src/game_engine/unity/mono.rs index 28b0036..47713b0 100644 --- a/src/game_engine/unity/mono.rs +++ b/src/game_engine/unity/mono.rs @@ -2,8 +2,8 @@ //! backend. use crate::{ - deep_pointer::DeepPointer, file_format::pe, future::retry, signature::Signature, - 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, cell::RefCell, iter}; @@ -737,23 +737,6 @@ impl UnityPointer { Ok(()) } - /// Dereferences the pointer path, returning the memory address of the value of interest - pub fn deref_offsets( - &self, - process: &Process, - module: &Module, - image: &Image, - ) -> Result { - self.find_offsets(process, module, image)?; - let cache = self.cache.borrow(); - let mut address = cache.base_address; - let (&last, path) = cache.offsets[..self.depth].split_last().ok_or(Error {})?; - for &offset in path { - address = process.read_pointer(address + offset, module.pointer_size)?; - } - Ok(address + last) - } - /// Dereferences the pointer path, returning the value stored at the final memory address pub fn deref( &self, @@ -769,23 +752,6 @@ impl UnityPointer { &cache.offsets[..self.depth], ) } - - /// Generates a `DeepPointer` struct based on the offsets - /// recovered from this `UnityPointer`. - pub fn get_deep_pointer( - &self, - process: &Process, - module: &Module, - image: &Image, - ) -> Option> { - self.find_offsets(process, module, image).ok()?; - let cache = self.cache.borrow(); - Some(DeepPointer::::new( - cache.base_address, - module.pointer_size, - &cache.offsets[..self.depth], - )) - } } struct Offsets { From f0649208623beaaa85d4917f5bd95ea1ff4e5198 Mon Sep 17 00:00:00 2001 From: Jujstme Date: Mon, 13 May 2024 17:15:36 +0200 Subject: [PATCH 05/13] Fixed assemblies list pointer being dereferenced too early in the code, leading sometimes to wrong behaviour --- src/game_engine/unity/mono.rs | 55 ++++++++++++++++------------------- 1 file changed, 25 insertions(+), 30 deletions(-) diff --git a/src/game_engine/unity/mono.rs b/src/game_engine/unity/mono.rs index 47713b0..ff4d11f 100644 --- a/src/game_engine/unity/mono.rs +++ b/src/game_engine/unity/mono.rs @@ -5,7 +5,11 @@ use crate::{ file_format::pe, future::retry, signature::Signature, string::ArrayCString, Address, Address32, Address64, Error, PointerSize, Process, }; -use core::{array, cell::RefCell, iter}; +use core::{ + array, + cell::RefCell, + iter::{self, FusedIterator}, +}; #[cfg(feature = "derive")] pub use asr_derive::MonoClass as Class; @@ -55,7 +59,7 @@ impl Module { })? .address; - let assemblies_pointer: Address = match pointer_size { + let assemblies: Address = match pointer_size { PointerSize::Bit64 => { const SIG_MONO_64: Signature<3> = Signature::new("48 8B 0D"); let scan_address: Address = SIG_MONO_64 @@ -76,11 +80,6 @@ impl Module { _ => return None, }; - let assemblies = process - .read_pointer(assemblies_pointer, pointer_size) - .ok() - .filter(|val| !val.is_null())?; - Some(Self { pointer_size, version, @@ -89,33 +88,29 @@ impl Module { }) } - fn assemblies<'a>(&'a self, process: &'a Process) -> impl Iterator + 'a { - let mut assembly = self.assemblies; - let mut iter_break = assembly.is_null(); + fn assemblies<'a>(&'a self, process: &'a Process) -> impl FusedIterator + 'a { + let mut assembly = process + .read_pointer(self.assemblies, self.pointer_size) + .ok() + .filter(|val| !val.is_null()); + iter::from_fn(move || { - if iter_break { - None - } else { - let [data, next_assembly]: [Address; 2] = match self.pointer_size { - PointerSize::Bit64 => process - .read::<[Address64; 2]>(assembly) - .ok()? - .map(|item| item.into()), - _ => process - .read::<[Address32; 2]>(assembly) - .ok()? - .map(|item| item.into()), - }; + let [data, next_assembly]: [Address; 2] = match self.pointer_size { + PointerSize::Bit64 => process + .read::<[Address64; 2]>(assembly?) + .ok()? + .map(|item| item.into()), + _ => process + .read::<[Address32; 2]>(assembly?) + .ok()? + .map(|item| item.into()), + }; - if next_assembly.is_null() { - iter_break = true; - } else { - assembly = next_assembly; - } + assembly = Some(next_assembly); - Some(Assembly { assembly: data }) - } + Some(Assembly { assembly: data }) }) + .fuse() } /// Looks for the specified binary [image](Image) inside the target process. From 9737db0cd19787fd2ef20f1c832e46eb98ed1238 Mon Sep 17 00:00:00 2001 From: Jujstme Date: Mon, 13 May 2024 17:29:49 +0200 Subject: [PATCH 06/13] Other minor code refinement --- src/game_engine/unity/mono.rs | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/game_engine/unity/mono.rs b/src/game_engine/unity/mono.rs index ff4d11f..4b1fcef 100644 --- a/src/game_engine/unity/mono.rs +++ b/src/game_engine/unity/mono.rs @@ -655,15 +655,19 @@ impl UnityPointer { cache.base_address = starting_class .get_static_table(process, module) .ok_or(Error {})?; - - if cache.base_address.is_null() { - return Err(Error {}); - } }; // If we already resolved some offsets, we need to traverse them again starting from the base address // of the static table in order to recalculate the address of the farthest object we can reach. // If no offsets have been resolved yet, we just need to read the base address instead. + let mut current_object = { + let mut addr = cache.base_address; + for &i in &cache.offsets[..cache.resolved_offsets] { + addr = process.read_pointer(addr + i, module.pointer_size)?; + } + addr + }; + /* let mut current_object = match cache.resolved_offsets { 0 => cache.base_address, x => { @@ -674,6 +678,7 @@ impl UnityPointer { addr } }; + */ // We keep track of the already resolved offsets in order to skip resolving them again for i in cache.resolved_offsets..self.depth { @@ -712,8 +717,7 @@ impl UnityPointer { .get_name::(process, module) .is_ok_and(|name| name.matches(self.fields[i])) }) - .ok_or(Error {})? - .get_offset(process, module) + .and_then(|val| val.get_offset(process, module)) .ok_or(Error {})? as u64; // Explicitly allowing this clippy because of borrowing rules shenanigans From ebbce1f0690b99f99bbeb5a679ee237bca702317 Mon Sep 17 00:00:00 2001 From: Jujstme Date: Mon, 13 May 2024 18:05:49 +0200 Subject: [PATCH 07/13] More mono code cleanup --- src/game_engine/unity/mono.rs | 58 +++++++++++++++-------------------- 1 file changed, 24 insertions(+), 34 deletions(-) diff --git a/src/game_engine/unity/mono.rs b/src/game_engine/unity/mono.rs index 4b1fcef..7dea419 100644 --- a/src/game_engine/unity/mono.rs +++ b/src/game_engine/unity/mono.rs @@ -351,58 +351,48 @@ impl Class { &'a self, process: &'a Process, module: &'a Module, - ) -> impl Iterator + 'a { - let mut this_class = Class { class: self.class }; - let mut iter_break = this_class.class.is_null(); + ) -> impl FusedIterator + 'a { + let mut this_class = Some(*self); iter::from_fn(move || { - if iter_break { - None - } else if !this_class.class.is_null() - && this_class - .get_name::(process, module) - .is_ok_and(|name| !name.matches("Object")) - && this_class + if this_class? + .get_name::(process, module) + .ok()? + .matches("Object") + || this_class? .get_name_space::(process, module) - .is_ok_and(|name| !name.matches("UnityEngine")) + .ok()? + .matches("UnityEngine") { + None + } else { let field_count = process - .read::(this_class.class + module.offsets.monoclassdef_field_count) - .ok() - .filter(|&val| val != 0); + .read::(this_class?.class + module.offsets.monoclassdef_field_count) + .unwrap_or_default() as u64; let fields = match field_count { - Some(_) => process + 0 => None, + _ => process .read_pointer( - this_class.class + this_class?.class + module.offsets.monoclassdef_klass + module.offsets.monoclass_fields, module.pointer_size, ) .ok(), - _ => None, }; - let monoclassfieldalignment = module.offsets.monoclassfieldalignment as u64; + this_class = this_class?.get_parent(process, module); - if let Some(x) = this_class.get_parent(process, module) { - this_class = x; - } else { - iter_break = true; - } - - Some( - (0..field_count.unwrap_or_default() as u64).filter_map(move |i| { - Some(Field { - field: fields? + i.wrapping_mul(monoclassfieldalignment), - }) - }), - ) - } else { - iter_break = true; - None + Some((0..field_count).filter_map(move |i| { + Some(Field { + field: fields? + + i.wrapping_mul(module.offsets.monoclassfieldalignment as u64), + }) + })) } }) + .fuse() .flatten() } From 98c573e0cc9a5d8fe9edffa82e139d6ec158623d Mon Sep 17 00:00:00 2001 From: Jujstme Date: Mon, 13 May 2024 18:36:16 +0200 Subject: [PATCH 08/13] Remove commended out code --- src/game_engine/unity/mono.rs | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/src/game_engine/unity/mono.rs b/src/game_engine/unity/mono.rs index 7dea419..07a9d6c 100644 --- a/src/game_engine/unity/mono.rs +++ b/src/game_engine/unity/mono.rs @@ -657,18 +657,6 @@ impl UnityPointer { } addr }; - /* - let mut current_object = match cache.resolved_offsets { - 0 => cache.base_address, - x => { - let mut addr = cache.base_address; - for &i in &cache.offsets[..x] { - addr = process.read_pointer(addr + i, module.pointer_size)?; - } - addr - } - }; - */ // We keep track of the already resolved offsets in order to skip resolving them again for i in cache.resolved_offsets..self.depth { From d36ac3730d36c6d1b3a20079c14ccee82b16ef1c Mon Sep 17 00:00:00 2001 From: Jujstme Date: Wed, 15 May 2024 01:13:15 +0200 Subject: [PATCH 09/13] Rewritten parts of the code in more idiomatic rust --- src/game_engine/unity/il2cpp.rs | 231 +++++++++++++++----------------- src/game_engine/unity/mono.rs | 164 +++++++++++------------ 2 files changed, 185 insertions(+), 210 deletions(-) diff --git a/src/game_engine/unity/il2cpp.rs b/src/game_engine/unity/il2cpp.rs index 76c3e08..4cb55d6 100644 --- a/src/game_engine/unity/il2cpp.rs +++ b/src/game_engine/unity/il2cpp.rs @@ -1,6 +1,10 @@ //! Support for attaching to Unity games that are using the IL2CPP backend. -use core::{array, cell::RefCell, iter}; +use core::{ + array, + cell::RefCell, + iter::{self, FusedIterator}, +}; use crate::{ file_format::pe, future::retry, signature::Signature, string::ArrayCString, Address, Address64, @@ -124,14 +128,13 @@ impl Module { }; (0..nr_of_assemblies).filter_map(move |i| { - Some(Assembly { - assembly: process - .read_pointer( - assemblies + i.wrapping_mul(self.size_of_ptr()), - self.pointer_size, - ) - .ok()?, - }) + process + .read_pointer( + assemblies + i.wrapping_mul(self.size_of_ptr()), + self.pointer_size, + ) + .ok() + .map(|assembly| Assembly { assembly }) }) } @@ -147,8 +150,8 @@ impl Module { assembly .get_name::(process, self) .is_ok_and(|name| name.matches(assembly_name)) - })? - .get_image(process, self) + }) + .and_then(|assembly| assembly.get_image(process, self)) } /// Looks for the `Assembly-CSharp` binary [image](Image) inside the target @@ -229,23 +232,24 @@ impl Assembly { process: &Process, module: &Module, ) -> Result, Error> { - process.read(process.read_pointer( - self.assembly - + module.offsets.monoassembly_aname - + module.offsets.monoassemblyname_name, - module.pointer_size, - )?) + process + .read_pointer( + self.assembly + + module.offsets.monoassembly_aname + + module.offsets.monoassemblyname_name, + module.pointer_size, + ) + .and_then(|addr| process.read(addr)) } fn get_image(&self, process: &Process, module: &Module) -> Option { - Some(Image { - image: process - .read_pointer( - self.assembly + module.offsets.monoassembly_image, - module.pointer_size, - ) - .ok()?, - }) + process + .read_pointer( + self.assembly + module.offsets.monoassembly_image, + module.pointer_size, + ) + .ok() + .map(|image| Image { image }) } } @@ -263,41 +267,40 @@ impl Image { process: &'a Process, module: &'a Module, ) -> impl DoubleEndedIterator + 'a { - let type_count = process.read::(self.image + module.offsets.monoimage_typecount); + let type_count = process + .read::(self.image + module.offsets.monoimage_typecount) + .ok() + .filter(|val| !val.eq(&0)); - let metadata_ptr = match type_count { - Ok(_) => match module.version { - Version::V2020 => process.read_pointer( + let metadata_ptr = type_count.and_then(|_| match module.version { + Version::V2020 => process + .read_pointer( self.image + module.offsets.monoimage_metadatahandle, module.pointer_size, - ), - _ => Ok(self.image + module.offsets.monoimage_metadatahandle), - }, - _ => Err(Error {}), - }; + ) + .ok(), + _ => Some(self.image + module.offsets.monoimage_metadatahandle), + }); - let metadata_handle = match type_count { - Ok(0) => None, - Ok(_) => match metadata_ptr { - Ok(x) => process.read::(x).ok(), - _ => None, - }, - _ => None, - }; + let metadata_handle = type_count + .and_then(|_| metadata_ptr) + .and_then(|x| process.read::(x).ok()); let ptr = metadata_handle.map(|val| { module.type_info_definition_table + (val as u64).wrapping_mul(module.size_of_ptr()) }); (0..type_count.unwrap_or_default() as u64).filter_map(move |i| { - let class = process - .read_pointer( - ptr? + i.wrapping_mul(module.size_of_ptr()), - module.pointer_size, - ) - .ok() - .filter(|val| !val.is_null())?; - Some(Class { class }) + ptr.and_then(|ptr| { + process + .read_pointer( + ptr + i.wrapping_mul(module.size_of_ptr()), + module.pointer_size, + ) + .ok() + }) + .filter(|val| !val.is_null()) + .map(|class| Class { class }) }) } @@ -335,12 +338,12 @@ impl Class { process: &Process, module: &Module, ) -> Result, Error> { - process.read_pointer_path( - self.class, - module.pointer_size, - &[module.offsets.monoclass_name.into(), 0x0], - ) - //process.read(module.read_pointer(process, self.class + module.offsets.monoclass_name)?) + process + .read_pointer( + self.class + module.offsets.monoclass_name, + module.pointer_size, + ) + .and_then(|addr| process.read(addr)) } fn get_name_space( @@ -348,65 +351,56 @@ impl Class { process: &Process, module: &Module, ) -> Result, Error> { - process.read_pointer_path( - self.class, - module.pointer_size, - &[module.offsets.monoclass_name_space.into(), 0x0], - ) + process + .read_pointer( + self.class + module.offsets.monoclass_name_space, + module.pointer_size, + ) + .and_then(|addr| process.read(addr)) } fn fields<'a>( &'a self, process: &'a Process, module: &'a Module, - ) -> impl Iterator + '_ { - let mut this_class = Class { class: self.class }; - let mut iter_break = this_class.class.is_null(); + ) -> impl FusedIterator + '_ { + let mut this_class = Some(*self); iter::from_fn(move || { - if iter_break { - None - } else if !this_class.class.is_null() - && this_class - .get_name::(process, module) - .is_ok_and(|name| !name.matches("Object")) - && this_class + if this_class? + .get_name::(process, module) + .is_ok_and(|name| !name.matches("Object")) + || this_class? .get_name_space::(process, module) .is_ok_and(|name| !name.matches("UnityEngine")) { + None + } else { let field_count = - process.read::(this_class.class + module.offsets.monoclass_field_count); + process.read::(this_class?.class + module.offsets.monoclass_field_count); - let fields = match field_count { - Ok(_) => process + let fields = field_count.as_ref().ok().and_then(|_| { + process .read_pointer( - this_class.class + module.offsets.monoclass_fields, + this_class?.class + module.offsets.monoclass_fields, module.pointer_size, ) - .ok(), - _ => None, - }; + .ok() + }); - let monoclassfield_structsize = module.offsets.monoclassfield_structsize as u64; - - if let Some(x) = this_class.get_parent(process, module) { - this_class = x; - } else { - iter_break = true; - } + this_class = this_class?.get_parent(process, module); Some( (0..field_count.unwrap_or_default() as u64).filter_map(move |i| { - Some(Field { - field: fields? + i.wrapping_mul(monoclassfield_structsize), + fields.map(|fields| Field { + field: fields + + i.wrapping_mul(module.offsets.monoclassfield_structsize as u64), }) }), ) - } else { - iter_break = true; - None } }) + .fuse() .flatten() } @@ -425,8 +419,8 @@ impl Class { field .get_name::(process, module) .is_ok_and(|name| name.matches(field_name)) - })? - .get_offset(process, module) + }) + .and_then(|field| field.get_offset(process, module)) } /// Tries to find the address of a static instance of the class based on its @@ -467,14 +461,14 @@ impl Class { /// Tries to find the parent class. pub fn get_parent(&self, process: &Process, module: &Module) -> Option { - let parent = process + process .read_pointer( self.class + module.offsets.monoclass_parent, module.pointer_size, ) .ok() - .filter(|val| !val.is_null())?; - Some(Class { class: parent }) + .filter(|val| !val.is_null()) + .map(|class| Class { class }) } /// Tries to find a field with the specified name in the class. This returns @@ -516,11 +510,12 @@ impl Field { process: &Process, module: &Module, ) -> Result, Error> { - process.read_pointer_path( - self.field, - module.pointer_size, - &[module.offsets.monoclassfield_name.into(), 0x0], - ) + process + .read_pointer( + self.field + module.offsets.monoclassfield_name, + module.pointer_size, + ) + .and_then(|addr| process.read(addr)) } fn get_offset(&self, process: &Process, module: &Module) -> Option { @@ -598,9 +593,11 @@ impl UnityPointer { let mut current_class = image .get_class(process, module, self.class_name) .ok_or(Error {})?; + for _ in 0..self.nr_of_parents { current_class = current_class.get_parent(process, module).ok_or(Error {})?; } + cache.starting_class = Some(current_class); current_class } @@ -612,24 +609,17 @@ impl UnityPointer { cache.base_address = starting_class .get_static_table(process, module) .ok_or(Error {})?; - - if cache.base_address.is_null() { - return Err(Error {}); - } }; // If we already resolved some offsets, we need to traverse them again starting from the base address // of the static table in order to recalculate the address of the farthest object we can reach. // If no offsets have been resolved yet, we just need to read the base address instead. - let mut current_object = match cache.resolved_offsets { - 0 => cache.base_address, - x => { - let mut addr = cache.base_address; - for &i in &cache.offsets[..x] { - addr = process.read_pointer(addr + i, module.pointer_size)?; - } - addr + let mut current_object = { + let mut addr = cache.base_address; + for &i in &cache.offsets[..cache.resolved_offsets] { + addr = process.read_pointer(addr + i, module.pointer_size)?; } + addr }; // We keep track of the already resolved offsets in order to skip resolving them again @@ -644,14 +634,12 @@ impl UnityPointer { _ => { let current_class = match i { 0 => starting_class, - _ => { - let class = process - .read_pointer(current_object, module.pointer_size) - .ok() - .filter(|val| !val.is_null()) - .ok_or(Error {})?; - Class { class } - } + _ => process + .read_pointer(current_object, module.pointer_size) + .ok() + .filter(|val| !val.is_null()) + .map(|class| Class { class }) + .ok_or(Error {})?, }; let val = current_class @@ -661,8 +649,7 @@ impl UnityPointer { .get_name::(process, module) .is_ok_and(|name| name.matches(self.fields[i])) }) - .ok_or(Error {})? - .get_offset(process, module) + .and_then(|val| val.get_offset(process, module)) .ok_or(Error {})? as u64; // Explicitly allowing this clippy because of borrowing rules shenanigans diff --git a/src/game_engine/unity/mono.rs b/src/game_engine/unity/mono.rs index 07a9d6c..9a18382 100644 --- a/src/game_engine/unity/mono.rs +++ b/src/game_engine/unity/mono.rs @@ -125,8 +125,8 @@ impl Module { assembly .get_name::(process, self) .is_ok_and(|name| name.matches(assembly_name)) - })? - .get_image(process, self) + }) + .and_then(|assembly| assembly.get_image(process, self)) } /// Looks for the `Assembly-CSharp` binary [image](Image) inside the target @@ -207,23 +207,23 @@ impl Assembly { process: &Process, module: &Module, ) -> Result, Error> { - process.read_pointer_path( - self.assembly, - module.pointer_size, - &[module.offsets.monoassembly_aname.into(), 0x0], - ) + process + .read_pointer( + self.assembly + module.offsets.monoassembly_aname, + module.pointer_size, + ) + .and_then(|addr| process.read(addr)) } fn get_image(&self, process: &Process, module: &Module) -> Option { - Some(Image { - image: process - .read_pointer( - self.assembly + module.offsets.monoassembly_image, - module.pointer_size, - ) - .ok() - .filter(|val| !val.is_null())?, - }) + process + .read_pointer( + self.assembly + module.offsets.monoassembly_image, + module.pointer_size, + ) + .ok() + .filter(|val| !val.is_null()) + .map(|image| Image { image }) } } @@ -240,7 +240,7 @@ impl Image { &self, process: &'a Process, module: &'a Module, - ) -> impl Iterator + 'a { + ) -> impl FusedIterator + 'a { let class_cache_size = process .read::( self.image @@ -250,26 +250,26 @@ impl Image { .ok() .filter(|&val| val != 0); - let table_addr = match class_cache_size { - Some(_) => process.read_pointer( - self.image - + module.offsets.monoimage_class_cache - + module.offsets.monointernalhashtable_table, - module.pointer_size, - ), - _ => Err(Error {}), - }; + let table_addr = class_cache_size.and_then(|_| { + process + .read_pointer( + self.image + + module.offsets.monoimage_class_cache + + module.offsets.monointernalhashtable_table, + module.pointer_size, + ) + .ok() + }); (0..class_cache_size.unwrap_or_default()).flat_map(move |i| { - let mut table = match table_addr { - Ok(table_addr) => process + let mut table = table_addr.and_then(|addr| { + process .read_pointer( - table_addr + (i as u64).wrapping_mul(module.size_of_ptr()), + addr + (i as u64).wrapping_mul(module.size_of_ptr()), module.pointer_size, ) - .ok(), - _ => None, - }; + .ok() + }); iter::from_fn(move || { let class = process.read_pointer(table?, module.pointer_size).ok()?; @@ -284,6 +284,7 @@ impl Image { Some(Class { class }) }) + .fuse() }) } @@ -321,14 +322,12 @@ impl Class { process: &Process, module: &Module, ) -> Result, Error> { - process.read_pointer_path( - self.class, - module.pointer_size, - &[ - module.offsets.monoclassdef_klass as u64 + module.offsets.monoclass_name as u64, - 0x0, - ], - ) + process + .read_pointer( + self.class + module.offsets.monoclassdef_klass + module.offsets.monoclass_name, + module.pointer_size, + ) + .and_then(|addr| process.read(addr)) } fn get_name_space( @@ -336,15 +335,14 @@ impl Class { process: &Process, module: &Module, ) -> Result, Error> { - process.read_pointer_path( - self.class, - module.pointer_size, - &[ - module.offsets.monoclassdef_klass as u64 - + module.offsets.monoclass_name_space as u64, - 0x0, - ], - ) + process + .read_pointer( + self.class + + module.offsets.monoclassdef_klass + + module.offsets.monoclass_name_space, + module.pointer_size, + ) + .and_then(|addr| process.read(addr)) } fn fields<'a>( @@ -368,28 +366,30 @@ impl Class { } else { let field_count = process .read::(this_class?.class + module.offsets.monoclassdef_field_count) - .unwrap_or_default() as u64; + .ok() + .filter(|val| !val.eq(&0)); - let fields = match field_count { - 0 => None, - _ => process + let fields = field_count.and_then(|_| { + process .read_pointer( this_class?.class + module.offsets.monoclassdef_klass + module.offsets.monoclass_fields, module.pointer_size, ) - .ok(), - }; + .ok() + }); this_class = this_class?.get_parent(process, module); - Some((0..field_count).filter_map(move |i| { - Some(Field { - field: fields? - + i.wrapping_mul(module.offsets.monoclassfieldalignment as u64), - }) - })) + Some( + (0..field_count.unwrap_or_default() as u64).filter_map(move |i| { + fields.map(|fields| Field { + field: fields + + i.wrapping_mul(module.offsets.monoclassfieldalignment as u64), + }) + }), + ) } }) .fuse() @@ -410,8 +410,8 @@ impl Class { field .get_name::(process, module) .is_ok_and(|name| name.matches(field_name)) - })? - .get_offset(process, module) + }) + .and_then(|field| field.get_offset(process, module)) } /// Tries to find the address of a static instance of the class based on its @@ -492,20 +492,16 @@ impl Class { /// Tries to find the parent class. pub fn get_parent(&self, process: &Process, module: &Module) -> Option { - let parent_addr = process + process .read_pointer( self.class + module.offsets.monoclassdef_klass + module.offsets.monoclass_parent, module.pointer_size, ) .ok() - .filter(|val| !val.is_null())?; - - Some(Class { - class: process - .read_pointer(parent_addr, module.pointer_size) - .ok() - .filter(|val| !val.is_null())?, - }) + .filter(|val| !val.is_null()) + .and_then(|parent_addr| process.read_pointer(parent_addr, module.pointer_size).ok()) + .filter(|val| !val.is_null()) + .map(|class| Class { class }) } /// Tries to find a field with the specified name in the class. This returns @@ -670,22 +666,14 @@ impl UnityPointer { _ => { let current_class = match i { 0 => starting_class, - _ => { - let class = process - .read_pointer( - process - .read_pointer(current_object, module.pointer_size) - .ok() - .filter(|val| !val.is_null()) - .ok_or(Error {})?, - module.pointer_size, - ) - .ok() - .filter(|val| !val.is_null()) - .ok_or(Error {})?; - - Class { class } - } + _ => process + .read_pointer(current_object, module.pointer_size) + .ok() + .filter(|val| !val.is_null()) + .and_then(|addr| process.read_pointer(addr, module.pointer_size).ok()) + .filter(|val| !val.is_null()) + .map(|class| Class { class }) + .ok_or(Error {})?, }; let val = current_class From 67aaffef2906aa127c2842f4512a409cb419a005 Mon Sep 17 00:00:00 2001 From: Jujstme Date: Sat, 18 May 2024 19:21:56 +0200 Subject: [PATCH 10/13] Minor stuff --- src/game_engine/unity/mono.rs | 11 ++++++----- src/game_engine/unity/scene.rs | 30 ++++++++++++++++-------------- 2 files changed, 22 insertions(+), 19 deletions(-) diff --git a/src/game_engine/unity/mono.rs b/src/game_engine/unity/mono.rs index 9a18382..1875287 100644 --- a/src/game_engine/unity/mono.rs +++ b/src/game_engine/unity/mono.rs @@ -543,11 +543,12 @@ impl Field { process: &Process, module: &Module, ) -> Result, Error> { - process.read_pointer_path( - self.field, - module.pointer_size, - &[module.offsets.monoclassfield_name.into(), 0x0], - ) + process + .read_pointer( + self.field + module.offsets.monoclassfield_name, + module.pointer_size, + ) + .and_then(|addr| process.read(addr)) } fn get_offset(&self, process: &Process, module: &Module) -> Option { diff --git a/src/game_engine/unity/scene.rs b/src/game_engine/unity/scene.rs index 51c3214..e011ec8 100644 --- a/src/game_engine/unity/scene.rs +++ b/src/game_engine/unity/scene.rs @@ -91,13 +91,12 @@ impl SceneManager { /// Tries to retrieve the current active scene. fn get_current_scene(&self, process: &Process) -> Result { - Ok(Scene { - address: process - .read_pointer(self.address + self.offsets.active_scene, self.pointer_size) - .ok() - .filter(|val| !val.is_null()) - .ok_or(Error {})?, - }) + process + .read_pointer(self.address + self.offsets.active_scene, self.pointer_size) + .ok() + .filter(|val| !val.is_null()) + .map(|address| Scene { address }) + .ok_or(Error {}) } /// `DontDestroyOnLoad` is a special Unity scene containing game objects @@ -115,7 +114,8 @@ impl SceneManager { /// The value returned is a [`i32`] because some games will show `-1` as their /// current scene until fully initialized. pub fn get_current_scene_index(&self, process: &Process) -> Result { - self.get_current_scene(process)?.index(process, self) + self.get_current_scene(process) + .and_then(|scene| scene.index(process, self)) } /// Returns the full path to the current scene. Use [`get_scene_name`] @@ -124,7 +124,8 @@ impl SceneManager { &self, process: &Process, ) -> Result, Error> { - self.get_current_scene(process)?.path(process, self) + self.get_current_scene(process) + .and_then(|scene| scene.path(process, self)) } /// Returns the number of currently loaded scenes in the attached game. @@ -505,11 +506,12 @@ impl Scene { process: &Process, scene_manager: &SceneManager, ) -> Result, Error> { - process.read_pointer_path( - self.address, - scene_manager.pointer_size, - &[scene_manager.offsets.asset_path as u64, 0x0], - ) + process + .read_pointer( + self.address + scene_manager.offsets.asset_path, + scene_manager.pointer_size, + ) + .and_then(|addr| process.read(addr)) } } From 2692f9f46d00eb50e5a1a5510de905df35c37ef9 Mon Sep 17 00:00:00 2001 From: Jujstme Date: Sat, 18 May 2024 21:49:06 +0200 Subject: [PATCH 11/13] Fixed scene manager For some reason the scene manager still used the get_module_range function, breaking compatibility with Proton/Wine --- src/game_engine/unity/scene.rs | 75 +++++++++++++++++++--------------- 1 file changed, 41 insertions(+), 34 deletions(-) diff --git a/src/game_engine/unity/scene.rs b/src/game_engine/unity/scene.rs index e011ec8..72625c2 100644 --- a/src/game_engine/unity/scene.rs +++ b/src/game_engine/unity/scene.rs @@ -6,7 +6,11 @@ // // Offsets and logic for Transforms and GameObjects taken from https://github.com/Micrologist/UnityInstanceDumper -use core::{array, iter, mem::MaybeUninit}; +use core::{ + array, + iter::{self, FusedIterator}, + mem::MaybeUninit, +}; use crate::{ file_format::pe, future::retry, signature::Signature, string::ArrayCString, Address, Address32, @@ -35,7 +39,12 @@ impl SceneManager { const SIG_32_2: Signature<6> = Signature::new("53 8D 41 ?? 33 DB"); const SIG_32_3: Signature<14> = Signature::new("55 8B EC 83 EC 18 A1 ???????? 33 C9 53"); - let unity_player = process.get_module_range("UnityPlayer.dll").ok()?; + let unity_player = process + .get_module_address("UnityPlayer.dll") + .ok() + .and_then(|address| { + Some((address, pe::read_size_of_image(process, address)? as u64)) + })?; let pointer_size = match pe::MachineType::read(process, unity_player.0)? { pe::MachineType::X86_64 => PointerSize::Bit64, @@ -154,15 +163,14 @@ impl SceneManager { }; (0..num_scenes).filter_map(move |index| { - Some(Scene { - address: process - .read_pointer( - addr + (index as u64).wrapping_mul(self.size_of_ptr()), - self.pointer_size, - ) - .ok() - .filter(|val| !val.is_null())?, - }) + process + .read_pointer( + addr + (index as u64).wrapping_mul(self.size_of_ptr()), + self.pointer_size, + ) + .ok() + .filter(|val| !val.is_null()) + .map(|address| Scene { address }) }) } @@ -178,41 +186,40 @@ impl SceneManager { &'a self, process: &'a Process, scene: &Scene, - ) -> impl Iterator + 'a { + ) -> impl FusedIterator + 'a { let list_first = process .read_pointer( scene.address + self.offsets.root_storage_container, self.pointer_size, ) - .unwrap_or_default(); + .ok() + .filter(|val| !val.is_null()); let mut current_list = list_first; - let mut iter_break = current_list.is_null(); iter::from_fn(move || { - if iter_break { - None - } else { - let [first, _, third]: [Address; 3] = match self.pointer_size { - PointerSize::Bit64 => process - .read::<[Address64; 3]>(current_list) - .ok()? - .map(|a| a.into()), - _ => process - .read::<[Address32; 3]>(current_list) - .ok()? - .map(|a| a.into()), - }; - - if first == list_first { - iter_break = true; - } else { - current_list = first; - } + let [first, _, third]: [Address; 3] = match self.pointer_size { + PointerSize::Bit64 => process + .read::<[Address64; 3]>(current_list?) + .ok() + .filter(|[first, _, third]| !first.is_null() && !third.is_null())? + .map(|a| a.into()), + _ => process + .read::<[Address32; 3]>(current_list?) + .ok() + .filter(|[first, _, third]| !first.is_null() && !third.is_null())? + .map(|a| a.into()), + }; - Some(Transform { address: third }) + if first == list_first? { + current_list = None; + } else { + current_list = Some(first); } + + Some(Transform { address: third }) }) + .fuse() } /// Tries to find the specified root [`Transform`] from the currently From ea60eafff1fb87af97ac952f6b296b801f39e360 Mon Sep 17 00:00:00 2001 From: Jujstme Date: Sat, 29 Jun 2024 16:34:58 +0200 Subject: [PATCH 12/13] Reintroduced deref_offsets --- src/game_engine/unity/il2cpp.rs | 25 ++++++++++++++++++------- src/game_engine/unity/mono.rs | 25 ++++++++++++++++++------- 2 files changed, 36 insertions(+), 14 deletions(-) diff --git a/src/game_engine/unity/il2cpp.rs b/src/game_engine/unity/il2cpp.rs index 4cb55d6..2b07170 100644 --- a/src/game_engine/unity/il2cpp.rs +++ b/src/game_engine/unity/il2cpp.rs @@ -668,6 +668,23 @@ impl UnityPointer { Ok(()) } + /// Dereferences the pointer path, returning the memory address of the value of interest + pub fn deref_offsets( + &self, + process: &Process, + module: &Module, + image: &Image, + ) -> Result { + self.find_offsets(process, module, image)?; + let cache = self.cache.borrow(); + let mut address = cache.base_address; + let (&last, path) = cache.offsets[..self.depth].split_last().ok_or(Error {})?; + for &offset in path { + address = process.read_pointer(address + offset, module.pointer_size)?; + } + Ok(address + last) + } + /// Dereferences the pointer path, returning the value stored at the final memory address pub fn deref( &self, @@ -675,13 +692,7 @@ impl UnityPointer { module: &Module, image: &Image, ) -> Result { - self.find_offsets(process, module, image)?; - let cache = self.cache.borrow(); - process.read_pointer_path( - cache.base_address, - module.pointer_size, - &cache.offsets[..self.depth], - ) + process.read(self.deref_offsets(process, module, image)?) } } diff --git a/src/game_engine/unity/mono.rs b/src/game_engine/unity/mono.rs index 1875287..170c27f 100644 --- a/src/game_engine/unity/mono.rs +++ b/src/game_engine/unity/mono.rs @@ -703,6 +703,23 @@ impl UnityPointer { Ok(()) } + /// Dereferences the pointer path, returning the memory address of the value of interest + pub fn deref_offsets( + &self, + process: &Process, + module: &Module, + image: &Image, + ) -> Result { + self.find_offsets(process, module, image)?; + let cache = self.cache.borrow(); + let mut address = cache.base_address; + let (&last, path) = cache.offsets[..self.depth].split_last().ok_or(Error {})?; + for &offset in path { + address = process.read_pointer(address + offset, module.pointer_size)?; + } + Ok(address + last) + } + /// Dereferences the pointer path, returning the value stored at the final memory address pub fn deref( &self, @@ -710,13 +727,7 @@ impl UnityPointer { module: &Module, image: &Image, ) -> Result { - self.find_offsets(process, module, image)?; - let cache = self.cache.borrow(); - process.read_pointer_path( - cache.base_address, - module.pointer_size, - &cache.offsets[..self.depth], - ) + process.read(self.deref_offsets(process, module, image)?) } } From 25185fad4042479e1ec5bd4dab39f85df69a34c2 Mon Sep 17 00:00:00 2001 From: Jujstme Date: Sat, 29 Jun 2024 23:11:06 +0200 Subject: [PATCH 13/13] Small oopsie in the conditional statement --- src/game_engine/unity/il2cpp.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/game_engine/unity/il2cpp.rs b/src/game_engine/unity/il2cpp.rs index 2b07170..a570d73 100644 --- a/src/game_engine/unity/il2cpp.rs +++ b/src/game_engine/unity/il2cpp.rs @@ -369,10 +369,10 @@ impl Class { iter::from_fn(move || { if this_class? .get_name::(process, module) - .is_ok_and(|name| !name.matches("Object")) + .is_ok_and(|name| name.matches("Object")) || this_class? .get_name_space::(process, module) - .is_ok_and(|name| !name.matches("UnityEngine")) + .is_ok_and(|name| name.matches("UnityEngine")) { None } else {