From 7988c363608a2eca9de365265134f57a2dbeee66 Mon Sep 17 00:00:00 2001 From: Mitchell Merry Date: Sun, 19 Apr 2026 19:10:02 +1000 Subject: [PATCH 01/10] first pass - no monov2 support --- src/game_engine/unity/mono/class.rs | 36 +++- src/game_engine/unity/mono/offsets.rs | 258 +++++++++++++++----------- 2 files changed, 180 insertions(+), 114 deletions(-) diff --git a/src/game_engine/unity/mono/class.rs b/src/game_engine/unity/mono/class.rs index 2ffe93c..f44fa74 100644 --- a/src/game_engine/unity/mono/class.rs +++ b/src/game_engine/unity/mono/class.rs @@ -36,6 +36,38 @@ impl Class { .and_then(|addr| process.read(addr)) } + fn field_count(&self, process: &Process, module: &Module) -> Result { + match module.version { + Version::V1 | Version::V1Cattrs => { + process.read::(self.class + module.offsets.class.field_count) + } + Version::V3 => { + // https://github.com/mono/mono/blob/0f53e9e151d92944cacab3e24ac359410c606df6/mono/metadata/class-accessors.c#L216 + let class_kind = + process.read::(self.class + module.offsets.class.class_kind)?; + + match class_kind { + 1 | 2 => process.read::(self.class + module.offsets.class.field_count), + // Handle generic class types + 3 => { + let generic_class = process.read_pointer( + self.class + module.offsets.class.generic_class, + module.get_pointer_size(), + )?; + let container_class = Class { + class: process + .read_pointer(generic_class + 0x0, module.get_pointer_size())?, + }; + + container_class.field_count(process, module) + } + _ => Err(Error {}), + } + } + _ => Err(Error {}), + } + } + fn fields<'a>( &'a self, process: &'a Process, @@ -61,8 +93,8 @@ impl Class { // Prepare for next iteration this_class = class.get_parent(process, module); - let field_count = process - .read::(class.class + module.offsets.class.field_count) + let field_count = class + .field_count(process, module) .ok() .filter(|&val| val > 0) .unwrap_or_default(); diff --git a/src/game_engine/unity/mono/offsets.rs b/src/game_engine/unity/mono/offsets.rs index dbfb5e5..8187af6 100644 --- a/src/game_engine/unity/mono/offsets.rs +++ b/src/game_engine/unity/mono/offsets.rs @@ -35,7 +35,9 @@ impl MonoOffsets { vtable_size: 0x5C, fields: 0x98, runtime_info: 0xD0, + class_kind: 0x1B, field_count: 0x100, + generic_class: 0xB0, next_class_cache: 0x108, }, field: FieldInfoOffsets { @@ -63,7 +65,9 @@ impl MonoOffsets { vtable_size: 0x38, fields: 0x60, runtime_info: 0x7C, + class_kind: 0x1B, field_count: 0x9C, + generic_class: 0xB0, next_class_cache: 0xA0, }, field: FieldInfoOffsets { @@ -91,7 +95,9 @@ impl MonoOffsets { vtable_size: 0x5C, fields: 0x98, runtime_info: 0xD0, + class_kind: 0x1B, field_count: 0x100, + generic_class: 0xB0, next_class_cache: 0x108, }, field: FieldInfoOffsets { @@ -119,7 +125,9 @@ impl MonoOffsets { vtable_size: 0x38, fields: 0x60, runtime_info: 0x84, + class_kind: 0x1B, field_count: 0xA4, + generic_class: 0xB0, next_class_cache: 0xA8, }, field: FieldInfoOffsets { @@ -147,7 +155,9 @@ impl MonoOffsets { vtable_size: 0x18, fields: 0xB0, runtime_info: 0x100, + class_kind: 0x1B, field_count: 0x9C, + generic_class: 0xB0, next_class_cache: 0x108, }, field: FieldInfoOffsets { @@ -175,7 +185,9 @@ impl MonoOffsets { vtable_size: 0xC, fields: 0x78, runtime_info: 0xA8, + class_kind: 0x1B, field_count: 0x68, + generic_class: 0xB0, next_class_cache: 0xAC, }, field: FieldInfoOffsets { @@ -203,7 +215,9 @@ impl MonoOffsets { vtable_size: 0x18, fields: 0xA8, runtime_info: 0xF8, + class_kind: 0x1B, field_count: 0x94, + generic_class: 0xB0, next_class_cache: 0x100, }, field: FieldInfoOffsets { @@ -231,7 +245,9 @@ impl MonoOffsets { vtable_size: 0xC, fields: 0x74, runtime_info: 0xA4, + class_kind: 0x1B, field_count: 0x64, + generic_class: 0xB0, next_class_cache: 0xA8, }, field: FieldInfoOffsets { @@ -241,118 +257,134 @@ impl MonoOffsets { }, v_table: MonoVTableOffsets { vtable: 0x28 }, }), - (BinaryFormat::ELF | BinaryFormat::MachO, Version::V3, PointerSize::Bit64) => Some(&Self { - assembly: AssemblyOffsets { - aname: 0x10, - image: 0x60, - }, - image: ImageOffsets { class_cache: 0x4D0 }, - hash_table: HashTableOffsets { - size: 0x18, - table: 0x20, - }, - class: ClassOffsets { - parent: 0x28, - image: 0x38, - name: 0x40, - namespace: 0x48, - vtable_size: 0x54, - fields: 0x90, - runtime_info: 0xC8, - field_count: 0xF8, - next_class_cache: 0x100, - }, - field: FieldInfoOffsets { - name: 0x8, - offset: 0x18, - alignment: 0x20, - }, - v_table: MonoVTableOffsets { vtable: 0x48 }, - }), - (BinaryFormat::ELF | BinaryFormat::MachO, Version::V2, PointerSize::Bit64) => Some(&Self { - assembly: AssemblyOffsets { - aname: 0x10, - image: 0x60, - }, - image: ImageOffsets { class_cache: 0x4C0 }, - hash_table: HashTableOffsets { - size: 0x18, - table: 0x20, - }, - class: ClassOffsets { - parent: 0x28, - image: 0x38, - name: 0x40, - namespace: 0x48, - vtable_size: 0x54, - fields: 0x90, - runtime_info: 0xC8, - field_count: 0xF8, - next_class_cache: 0x100, - }, - field: FieldInfoOffsets { - name: 0x8, - offset: 0x18, - alignment: 0x20, - }, - v_table: MonoVTableOffsets { vtable: 0x40 }, - }), - (BinaryFormat::ELF | BinaryFormat::MachO, Version::V1Cattrs, PointerSize::Bit64) => Some(&Self { - assembly: AssemblyOffsets { - aname: 0x10, - image: 0x58, - }, - image: ImageOffsets { class_cache: 0x3D0 }, - hash_table: HashTableOffsets { - size: 0x18, - table: 0x20, - }, - class: ClassOffsets { - parent: 0x28, - image: 0x40, - name: 0x48, - namespace: 0x50, - vtable_size: 0x18, - fields: 0xA8, - runtime_info: 0xF8, - field_count: 0x94, - next_class_cache: 0x100, - }, - field: FieldInfoOffsets { - name: 0x8, - offset: 0x18, - alignment: 0x20, - }, - v_table: MonoVTableOffsets { vtable: 0x48 }, - }), - (BinaryFormat::ELF | BinaryFormat::MachO, Version::V1, PointerSize::Bit64) => Some(&Self { - assembly: AssemblyOffsets { - aname: 0x10, - image: 0x58, - }, - image: ImageOffsets { class_cache: 0x3D0 }, - hash_table: HashTableOffsets { - size: 0x18, - table: 0x20, - }, - class: ClassOffsets { - parent: 0x28, - image: 0x38, - name: 0x40, - namespace: 0x48, - vtable_size: 0x18, - fields: 0xA0, - runtime_info: 0xF0, - field_count: 0x8C, - next_class_cache: 0xF8, - }, - field: FieldInfoOffsets { - name: 0x8, - offset: 0x18, - alignment: 0x20, - }, - v_table: MonoVTableOffsets { vtable: 0x48 }, - }), + (BinaryFormat::ELF | BinaryFormat::MachO, Version::V3, PointerSize::Bit64) => { + Some(&Self { + assembly: AssemblyOffsets { + aname: 0x10, + image: 0x60, + }, + image: ImageOffsets { class_cache: 0x4D0 }, + hash_table: HashTableOffsets { + size: 0x18, + table: 0x20, + }, + class: ClassOffsets { + parent: 0x28, + image: 0x38, + name: 0x40, + namespace: 0x48, + vtable_size: 0x54, + fields: 0x90, + runtime_info: 0xC8, + class_kind: 0x1B, + field_count: 0xF8, + generic_class: 0xB0, + next_class_cache: 0x100, + }, + field: FieldInfoOffsets { + name: 0x8, + offset: 0x18, + alignment: 0x20, + }, + v_table: MonoVTableOffsets { vtable: 0x48 }, + }) + } + (BinaryFormat::ELF | BinaryFormat::MachO, Version::V2, PointerSize::Bit64) => { + Some(&Self { + assembly: AssemblyOffsets { + aname: 0x10, + image: 0x60, + }, + image: ImageOffsets { class_cache: 0x4C0 }, + hash_table: HashTableOffsets { + size: 0x18, + table: 0x20, + }, + class: ClassOffsets { + parent: 0x28, + image: 0x38, + name: 0x40, + namespace: 0x48, + vtable_size: 0x54, + fields: 0x90, + runtime_info: 0xC8, + class_kind: 0x1B, + field_count: 0xF8, + generic_class: 0xB0, + next_class_cache: 0x100, + }, + field: FieldInfoOffsets { + name: 0x8, + offset: 0x18, + alignment: 0x20, + }, + v_table: MonoVTableOffsets { vtable: 0x40 }, + }) + } + (BinaryFormat::ELF | BinaryFormat::MachO, Version::V1Cattrs, PointerSize::Bit64) => { + Some(&Self { + assembly: AssemblyOffsets { + aname: 0x10, + image: 0x58, + }, + image: ImageOffsets { class_cache: 0x3D0 }, + hash_table: HashTableOffsets { + size: 0x18, + table: 0x20, + }, + class: ClassOffsets { + parent: 0x28, + image: 0x40, + name: 0x48, + namespace: 0x50, + vtable_size: 0x18, + fields: 0xA8, + runtime_info: 0xF8, + class_kind: 0x1B, + field_count: 0x94, + generic_class: 0xB0, + next_class_cache: 0x100, + }, + field: FieldInfoOffsets { + name: 0x8, + offset: 0x18, + alignment: 0x20, + }, + v_table: MonoVTableOffsets { vtable: 0x48 }, + }) + } + (BinaryFormat::ELF | BinaryFormat::MachO, Version::V1, PointerSize::Bit64) => { + Some(&Self { + assembly: AssemblyOffsets { + aname: 0x10, + image: 0x58, + }, + image: ImageOffsets { class_cache: 0x3D0 }, + hash_table: HashTableOffsets { + size: 0x18, + table: 0x20, + }, + class: ClassOffsets { + parent: 0x28, + image: 0x38, + name: 0x40, + namespace: 0x48, + vtable_size: 0x18, + fields: 0xA0, + runtime_info: 0xF0, + class_kind: 0x1B, + field_count: 0x8C, + generic_class: 0xB0, + next_class_cache: 0xF8, + }, + field: FieldInfoOffsets { + name: 0x8, + offset: 0x18, + alignment: 0x20, + }, + v_table: MonoVTableOffsets { vtable: 0x48 }, + }) + } _ => None, } } @@ -381,7 +413,9 @@ pub(super) struct ClassOffsets { pub(super) vtable_size: u8, // On mono V1 and V1_cattrs, this offset represents MonoVTable.data pub(super) fields: u8, pub(super) runtime_info: u16, + pub(super) class_kind: u8, pub(super) field_count: u16, + pub(super) generic_class: u8, pub(super) next_class_cache: u16, } From f224c66147126ebf90c4cef367f5022426ccc945 Mon Sep 17 00:00:00 2001 From: Mitchell Merry Date: Sun, 10 May 2026 14:51:43 +1000 Subject: [PATCH 02/10] pull v2 changes over --- src/game_engine/unity/mono/class.rs | 67 +++++++++++++++++++++++---- src/game_engine/unity/mono/offsets.rs | 51 ++++++++++---------- 2 files changed, 86 insertions(+), 32 deletions(-) diff --git a/src/game_engine/unity/mono/class.rs b/src/game_engine/unity/mono/class.rs index f44fa74..456d438 100644 --- a/src/game_engine/unity/mono/class.rs +++ b/src/game_engine/unity/mono/class.rs @@ -5,6 +5,31 @@ use crate::{future::retry, string::ArrayCString, Address, Error, Process}; #[cfg(feature = "derive")] pub use asr_derive::MonoClass as Class; +use bytemuck::CheckedBitPattern; + +/// The kind of MonoClass. +/// See https://github.com/mono/mono/blob/0f53e9e151d92944cacab3e24ac359410c606df6/mono/metadata/class-internals.h#L267 +#[derive(CheckedBitPattern, Copy, Clone, Debug, Default, PartialEq, Eq)] +#[repr(u8)] +#[allow(unused)] +enum MonoTypeKind { + /// Non-generic type + DEF = 1, + /// Generic type definition + GTD = 2, + /// Generic instantiation + GINST = 3, + /// Generic parameter + GPARAM = 4, + /// vector or array + ARRAY = 5, + /// pointer or function pointer + POINTER = 6, + GC_FILTER = 0xAC, + + #[default] + Unknown, +} /// A .NET class that is part of an [`Image`](Image). #[derive(Copy, Clone)] @@ -36,20 +61,46 @@ impl Class { .and_then(|addr| process.read(addr)) } + fn class_kind(&self, process: &Process, module: &Module) -> Result { + match module.version { + // https://github.com/mono/mono/blob/337052f86112fc0dc8435c5c4a2de43b399a14bb/mono/metadata/class-internals.h#L327 Version::V3 => process.read::(self.class + module.offsets.class.class_kind), + Version::V2 => { + // TODO I feel like I'm doing this very poorly + + let byte = + process.read::(self.class + module.offsets.class.class_kind)? & 0x7u8; + + if !MonoTypeKind::is_valid_bit_pattern(&byte) { + return Err(Error {}); + } + + // SAFETY: We just checked if this was valid + let kind: MonoTypeKind = unsafe { (&raw const byte).cast::().read() }; + + Ok(kind) + } + // https://github.com/mono/mono/blob/0f53e9e151d92944cacab3e24ac359410c606df6/mono/metadata/class-private-definition.h#L28_ => Err(Error {}), + Version::V3 => { + process.read::(self.class + module.offsets.class.class_kind) + } + _ => Err(Error {}), + } + } + fn field_count(&self, process: &Process, module: &Module) -> Result { match module.version { Version::V1 | Version::V1Cattrs => { process.read::(self.class + module.offsets.class.field_count) } - Version::V3 => { - // https://github.com/mono/mono/blob/0f53e9e151d92944cacab3e24ac359410c606df6/mono/metadata/class-accessors.c#L216 - let class_kind = - process.read::(self.class + module.offsets.class.class_kind)?; + Version::V2 | Version::V3 => { + let class_kind = self.class_kind(process, module)?; + // https://github.com/mono/mono/blob/0f53e9e151d92944cacab3e24ac359410c606df6/mono/metadata/class-accessors.c#L216 match class_kind { - 1 | 2 => process.read::(self.class + module.offsets.class.field_count), - // Handle generic class types - 3 => { + MonoTypeKind::DEF | MonoTypeKind::GTD => { + process.read::(self.class + module.offsets.class.field_count) + } + MonoTypeKind::GINST => { let generic_class = process.read_pointer( self.class + module.offsets.class.generic_class, module.get_pointer_size(), @@ -61,7 +112,7 @@ impl Class { container_class.field_count(process, module) } - _ => Err(Error {}), + _ => Ok(0), } } _ => Err(Error {}), diff --git a/src/game_engine/unity/mono/offsets.rs b/src/game_engine/unity/mono/offsets.rs index 8187af6..30964f4 100644 --- a/src/game_engine/unity/mono/offsets.rs +++ b/src/game_engine/unity/mono/offsets.rs @@ -35,10 +35,10 @@ impl MonoOffsets { vtable_size: 0x5C, fields: 0x98, runtime_info: 0xD0, - class_kind: 0x1B, field_count: 0x100, - generic_class: 0xB0, next_class_cache: 0x108, + class_kind: 0x1B, + generic_class: 0xB0, }, field: FieldInfoOffsets { name: 0x8, @@ -65,10 +65,11 @@ impl MonoOffsets { vtable_size: 0x38, fields: 0x60, runtime_info: 0x7C, - class_kind: 0x1B, field_count: 0x9C, - generic_class: 0xB0, next_class_cache: 0xA0, + // TODO + class_kind: 0x0, + generic_class: 0x0, }, field: FieldInfoOffsets { name: 0x4, @@ -95,10 +96,10 @@ impl MonoOffsets { vtable_size: 0x5C, fields: 0x98, runtime_info: 0xD0, - class_kind: 0x1B, field_count: 0x100, - generic_class: 0xB0, next_class_cache: 0x108, + class_kind: 0x2A, + generic_class: 0xF0, }, field: FieldInfoOffsets { name: 0x8, @@ -125,10 +126,11 @@ impl MonoOffsets { vtable_size: 0x38, fields: 0x60, runtime_info: 0x84, - class_kind: 0x1B, field_count: 0xA4, - generic_class: 0xB0, next_class_cache: 0xA8, + // TODO + class_kind: 0x0, + generic_class: 0x0, }, field: FieldInfoOffsets { name: 0x4, @@ -155,10 +157,10 @@ impl MonoOffsets { vtable_size: 0x18, fields: 0xB0, runtime_info: 0x100, - class_kind: 0x1B, field_count: 0x9C, - generic_class: 0xB0, next_class_cache: 0x108, + class_kind: 0x0, + generic_class: 0x0, }, field: FieldInfoOffsets { name: 0x8, @@ -185,10 +187,10 @@ impl MonoOffsets { vtable_size: 0xC, fields: 0x78, runtime_info: 0xA8, - class_kind: 0x1B, field_count: 0x68, - generic_class: 0xB0, next_class_cache: 0xAC, + class_kind: 0x0, + generic_class: 0x0, }, field: FieldInfoOffsets { name: 0x4, @@ -215,10 +217,10 @@ impl MonoOffsets { vtable_size: 0x18, fields: 0xA8, runtime_info: 0xF8, - class_kind: 0x1B, field_count: 0x94, - generic_class: 0xB0, next_class_cache: 0x100, + class_kind: 0x0, + generic_class: 0x0, }, field: FieldInfoOffsets { name: 0x8, @@ -245,10 +247,10 @@ impl MonoOffsets { vtable_size: 0xC, fields: 0x74, runtime_info: 0xA4, - class_kind: 0x1B, field_count: 0x64, - generic_class: 0xB0, next_class_cache: 0xA8, + class_kind: 0x0, + generic_class: 0x0, }, field: FieldInfoOffsets { name: 0x4, @@ -276,10 +278,10 @@ impl MonoOffsets { vtable_size: 0x54, fields: 0x90, runtime_info: 0xC8, - class_kind: 0x1B, field_count: 0xF8, - generic_class: 0xB0, next_class_cache: 0x100, + class_kind: 0x1B, + generic_class: 0xB0, }, field: FieldInfoOffsets { name: 0x8, @@ -308,10 +310,11 @@ impl MonoOffsets { vtable_size: 0x54, fields: 0x90, runtime_info: 0xC8, - class_kind: 0x1B, field_count: 0xF8, - generic_class: 0xB0, next_class_cache: 0x100, + // TODO + class_kind: 0x2A, + generic_class: 0xF0, }, field: FieldInfoOffsets { name: 0x8, @@ -340,10 +343,10 @@ impl MonoOffsets { vtable_size: 0x18, fields: 0xA8, runtime_info: 0xF8, - class_kind: 0x1B, field_count: 0x94, - generic_class: 0xB0, next_class_cache: 0x100, + class_kind: 0x0, + generic_class: 0x0, }, field: FieldInfoOffsets { name: 0x8, @@ -372,10 +375,10 @@ impl MonoOffsets { vtable_size: 0x18, fields: 0xA0, runtime_info: 0xF0, - class_kind: 0x1B, field_count: 0x8C, - generic_class: 0xB0, next_class_cache: 0xF8, + class_kind: 0x0, + generic_class: 0x0, }, field: FieldInfoOffsets { name: 0x8, From 93df9f269abefdd193b4ce30f301ec58eec10abc Mon Sep 17 00:00:00 2001 From: Mitchell Merry Date: Sun, 10 May 2026 15:55:01 +1000 Subject: [PATCH 03/10] fix mono v2 mac offset --- src/game_engine/unity/mono/class.rs | 5 ++++- src/game_engine/unity/mono/mod.rs | 8 ++++++++ src/game_engine/unity/mono/offsets.rs | 2 +- 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/src/game_engine/unity/mono/class.rs b/src/game_engine/unity/mono/class.rs index 456d438..885e3f7 100644 --- a/src/game_engine/unity/mono/class.rs +++ b/src/game_engine/unity/mono/class.rs @@ -1,7 +1,8 @@ +use alloc::format; use core::iter::{self, FusedIterator}; use super::{super::get_backing_name, Field, Module, Version, CSTR}; -use crate::{future::retry, string::ArrayCString, Address, Error, Process}; +use crate::{future::retry, print_message, string::ArrayCString, Address, Error, Process}; #[cfg(feature = "derive")] pub use asr_derive::MonoClass as Class; @@ -94,6 +95,7 @@ impl Class { } Version::V2 | Version::V3 => { let class_kind = self.class_kind(process, module)?; + print_message(&format!("ck {:?} (class: {})", class_kind, self.class)); // https://github.com/mono/mono/blob/0f53e9e151d92944cacab3e24ac359410c606df6/mono/metadata/class-accessors.c#L216 match class_kind { @@ -149,6 +151,7 @@ impl Class { .ok() .filter(|&val| val > 0) .unwrap_or_default(); + print_message(&format!("fc {:?}", field_count)); let fields = match field_count { 0 => None, diff --git a/src/game_engine/unity/mono/mod.rs b/src/game_engine/unity/mono/mod.rs index 56b44f4..64d9f45 100644 --- a/src/game_engine/unity/mono/mod.rs +++ b/src/game_engine/unity/mono/mod.rs @@ -6,6 +6,7 @@ use crate::file_format::macho; use crate::{ file_format::{elf, pe}, future::retry, + print_message, signature::Signature, Address, Address32, Address64, PointerSize, Process, }; @@ -110,6 +111,8 @@ impl Module { _ => return None, }; + print_message("a"); + let assemblies: Address = match (pointer_size, format) { (PointerSize::Bit64, BinaryFormat::PE) => { const SIG_MONO_64: Signature<3> = Signature::new("48 8B 0D"); @@ -146,14 +149,18 @@ impl Module { check_pos: Some(7), check_byte: 0xF9, }; + print_message("b"); + if let Some(scan_address) = SIG_MONO_X86_64_MACHO .scan_process_range(process, (root_domain_function_address, 0x100)) .map(|a| a + 3) { + print_message("c"); scan_address + 0x4 + process.read::(scan_address).ok()? } else if let Some(scan_address) = SIG_MONO_ARM_64_MACHO .scan_process_range(process, (root_domain_function_address, 0x100)) { + print_message("d"); let page = scan_address.value() & 0xfffffffffffff000; let bs = process.read::<[u8; 8]>(scan_address).ok()?; // adrp @@ -183,6 +190,7 @@ impl Module { } _ => return None, }; + print_message("e"); Some(Self { assemblies, diff --git a/src/game_engine/unity/mono/offsets.rs b/src/game_engine/unity/mono/offsets.rs index 30964f4..9b3434d 100644 --- a/src/game_engine/unity/mono/offsets.rs +++ b/src/game_engine/unity/mono/offsets.rs @@ -313,7 +313,7 @@ impl MonoOffsets { field_count: 0xF8, next_class_cache: 0x100, // TODO - class_kind: 0x2A, + class_kind: 0x24, generic_class: 0xF0, }, field: FieldInfoOffsets { From d6d3695c55537fa3c2ad575e023ce2b36645cf9f Mon Sep 17 00:00:00 2001 From: Mitchell Merry Date: Sun, 10 May 2026 16:56:40 +1000 Subject: [PATCH 04/10] mono v3 pe fix --- src/game_engine/unity/mono/offsets.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/game_engine/unity/mono/offsets.rs b/src/game_engine/unity/mono/offsets.rs index 9b3434d..17a3e4b 100644 --- a/src/game_engine/unity/mono/offsets.rs +++ b/src/game_engine/unity/mono/offsets.rs @@ -38,7 +38,7 @@ impl MonoOffsets { field_count: 0x100, next_class_cache: 0x108, class_kind: 0x1B, - generic_class: 0xB0, + generic_class: 0xF0, }, field: FieldInfoOffsets { name: 0x8, @@ -312,7 +312,6 @@ impl MonoOffsets { runtime_info: 0xC8, field_count: 0xF8, next_class_cache: 0x100, - // TODO class_kind: 0x24, generic_class: 0xF0, }, From b8aca862e7c461a4e1ee6bc38d915905ceebfe8a Mon Sep 17 00:00:00 2001 From: Mitchell Merry Date: Sun, 10 May 2026 18:19:37 +1000 Subject: [PATCH 05/10] add supposed offsets for v2 mono 32 bit, remove prints --- src/game_engine/unity/mono/class.rs | 2 +- src/game_engine/unity/mono/mod.rs | 10 ++-------- src/game_engine/unity/mono/offsets.rs | 10 +++++----- 3 files changed, 8 insertions(+), 14 deletions(-) diff --git a/src/game_engine/unity/mono/class.rs b/src/game_engine/unity/mono/class.rs index 885e3f7..6d0ff5f 100644 --- a/src/game_engine/unity/mono/class.rs +++ b/src/game_engine/unity/mono/class.rs @@ -82,6 +82,7 @@ impl Class { } // https://github.com/mono/mono/blob/0f53e9e151d92944cacab3e24ac359410c606df6/mono/metadata/class-private-definition.h#L28_ => Err(Error {}), Version::V3 => { + print_message(&format!("class: {}", self.class)); process.read::(self.class + module.offsets.class.class_kind) } _ => Err(Error {}), @@ -151,7 +152,6 @@ impl Class { .ok() .filter(|&val| val > 0) .unwrap_or_default(); - print_message(&format!("fc {:?}", field_count)); let fields = match field_count { 0 => None, diff --git a/src/game_engine/unity/mono/mod.rs b/src/game_engine/unity/mono/mod.rs index 64d9f45..7bd9658 100644 --- a/src/game_engine/unity/mono/mod.rs +++ b/src/game_engine/unity/mono/mod.rs @@ -5,8 +5,8 @@ use crate::file_format::macho; use crate::{ file_format::{elf, pe}, - future::retry, - print_message, + future::retry + , signature::Signature, Address, Address32, Address64, PointerSize, Process, }; @@ -111,8 +111,6 @@ impl Module { _ => return None, }; - print_message("a"); - let assemblies: Address = match (pointer_size, format) { (PointerSize::Bit64, BinaryFormat::PE) => { const SIG_MONO_64: Signature<3> = Signature::new("48 8B 0D"); @@ -149,18 +147,15 @@ impl Module { check_pos: Some(7), check_byte: 0xF9, }; - print_message("b"); if let Some(scan_address) = SIG_MONO_X86_64_MACHO .scan_process_range(process, (root_domain_function_address, 0x100)) .map(|a| a + 3) { - print_message("c"); scan_address + 0x4 + process.read::(scan_address).ok()? } else if let Some(scan_address) = SIG_MONO_ARM_64_MACHO .scan_process_range(process, (root_domain_function_address, 0x100)) { - print_message("d"); let page = scan_address.value() & 0xfffffffffffff000; let bs = process.read::<[u8; 8]>(scan_address).ok()?; // adrp @@ -190,7 +185,6 @@ impl Module { } _ => return None, }; - print_message("e"); Some(Self { assemblies, diff --git a/src/game_engine/unity/mono/offsets.rs b/src/game_engine/unity/mono/offsets.rs index 17a3e4b..b174f14 100644 --- a/src/game_engine/unity/mono/offsets.rs +++ b/src/game_engine/unity/mono/offsets.rs @@ -68,8 +68,8 @@ impl MonoOffsets { field_count: 0x9C, next_class_cache: 0xA0, // TODO - class_kind: 0x0, - generic_class: 0x0, + class_kind: 0xF, + generic_class: 0x70, }, field: FieldInfoOffsets { name: 0x4, @@ -128,9 +128,9 @@ impl MonoOffsets { runtime_info: 0x84, field_count: 0xA4, next_class_cache: 0xA8, - // TODO - class_kind: 0x0, - generic_class: 0x0, + // TODO Test + class_kind: 0x1E, + generic_class: 0x94, }, field: FieldInfoOffsets { name: 0x4, From 9569dbd2ac5eb947b5d7d1711d5b3ddf0b22090e Mon Sep 17 00:00:00 2001 From: Mitchell Merry Date: Sun, 10 May 2026 18:27:03 +1000 Subject: [PATCH 06/10] clean up some comments --- src/game_engine/unity/mono/class.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/game_engine/unity/mono/class.rs b/src/game_engine/unity/mono/class.rs index 6d0ff5f..c92668c 100644 --- a/src/game_engine/unity/mono/class.rs +++ b/src/game_engine/unity/mono/class.rs @@ -64,7 +64,7 @@ impl Class { fn class_kind(&self, process: &Process, module: &Module) -> Result { match module.version { - // https://github.com/mono/mono/blob/337052f86112fc0dc8435c5c4a2de43b399a14bb/mono/metadata/class-internals.h#L327 Version::V3 => process.read::(self.class + module.offsets.class.class_kind), + // See https://github.com/mono/mono/blob/337052f86112fc0dc8435c5c4a2de43b399a14bb/mono/metadata/class-internals.h#L327 Version::V2 => { // TODO I feel like I'm doing this very poorly @@ -80,7 +80,7 @@ impl Class { Ok(kind) } - // https://github.com/mono/mono/blob/0f53e9e151d92944cacab3e24ac359410c606df6/mono/metadata/class-private-definition.h#L28_ => Err(Error {}), + // See https://github.com/mono/mono/blob/0f53e9e151d92944cacab3e24ac359410c606df6/mono/metadata/class-private-definition.h#L28 Version::V3 => { print_message(&format!("class: {}", self.class)); process.read::(self.class + module.offsets.class.class_kind) @@ -98,7 +98,7 @@ impl Class { let class_kind = self.class_kind(process, module)?; print_message(&format!("ck {:?} (class: {})", class_kind, self.class)); - // https://github.com/mono/mono/blob/0f53e9e151d92944cacab3e24ac359410c606df6/mono/metadata/class-accessors.c#L216 + // See https://github.com/mono/mono/blob/0f53e9e151d92944cacab3e24ac359410c606df6/mono/metadata/class-accessors.c#L216 match class_kind { MonoTypeKind::DEF | MonoTypeKind::GTD => { process.read::(self.class + module.offsets.class.field_count) From 8767f40a6b9e75ed1dbb2326ce3a3d8bf83e2c48 Mon Sep 17 00:00:00 2001 From: Mitchell Merry Date: Sun, 10 May 2026 18:28:42 +1000 Subject: [PATCH 07/10] clean up some more prints --- src/game_engine/unity/mono/class.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/game_engine/unity/mono/class.rs b/src/game_engine/unity/mono/class.rs index c92668c..206974a 100644 --- a/src/game_engine/unity/mono/class.rs +++ b/src/game_engine/unity/mono/class.rs @@ -1,8 +1,7 @@ -use alloc::format; use core::iter::{self, FusedIterator}; use super::{super::get_backing_name, Field, Module, Version, CSTR}; -use crate::{future::retry, print_message, string::ArrayCString, Address, Error, Process}; +use crate::{future::retry, string::ArrayCString, Address, Error, Process}; #[cfg(feature = "derive")] pub use asr_derive::MonoClass as Class; @@ -82,7 +81,6 @@ impl Class { } // See https://github.com/mono/mono/blob/0f53e9e151d92944cacab3e24ac359410c606df6/mono/metadata/class-private-definition.h#L28 Version::V3 => { - print_message(&format!("class: {}", self.class)); process.read::(self.class + module.offsets.class.class_kind) } _ => Err(Error {}), @@ -96,7 +94,6 @@ impl Class { } Version::V2 | Version::V3 => { let class_kind = self.class_kind(process, module)?; - print_message(&format!("ck {:?} (class: {})", class_kind, self.class)); // See https://github.com/mono/mono/blob/0f53e9e151d92944cacab3e24ac359410c606df6/mono/metadata/class-accessors.c#L216 match class_kind { From 1a5e036f3f27b081ee7cd9d6b961665457847b41 Mon Sep 17 00:00:00 2001 From: Mitchell Merry Date: Sun, 10 May 2026 18:29:17 +1000 Subject: [PATCH 08/10] fmt + cleaning stuff --- src/game_engine/unity/mono/class.rs | 1 - src/game_engine/unity/mono/mod.rs | 3 +-- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/game_engine/unity/mono/class.rs b/src/game_engine/unity/mono/class.rs index 206974a..be2b76f 100644 --- a/src/game_engine/unity/mono/class.rs +++ b/src/game_engine/unity/mono/class.rs @@ -115,7 +115,6 @@ impl Class { _ => Ok(0), } } - _ => Err(Error {}), } } diff --git a/src/game_engine/unity/mono/mod.rs b/src/game_engine/unity/mono/mod.rs index 7bd9658..338caa7 100644 --- a/src/game_engine/unity/mono/mod.rs +++ b/src/game_engine/unity/mono/mod.rs @@ -5,8 +5,7 @@ use crate::file_format::macho; use crate::{ file_format::{elf, pe}, - future::retry - , + future::retry, signature::Signature, Address, Address32, Address64, PointerSize, Process, }; From dc14769db421e493a98b626e8bac6865c6a3de85 Mon Sep 17 00:00:00 2001 From: Mitchell Merry Date: Sun, 10 May 2026 18:30:03 +1000 Subject: [PATCH 09/10] further cleaning/commenting --- src/game_engine/unity/mono/offsets.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/game_engine/unity/mono/offsets.rs b/src/game_engine/unity/mono/offsets.rs index b174f14..f6733cf 100644 --- a/src/game_engine/unity/mono/offsets.rs +++ b/src/game_engine/unity/mono/offsets.rs @@ -128,7 +128,6 @@ impl MonoOffsets { runtime_info: 0x84, field_count: 0xA4, next_class_cache: 0xA8, - // TODO Test class_kind: 0x1E, generic_class: 0x94, }, @@ -159,6 +158,7 @@ impl MonoOffsets { runtime_info: 0x100, field_count: 0x9C, next_class_cache: 0x108, + // Not a thing in V1/V1Cattrs class_kind: 0x0, generic_class: 0x0, }, @@ -189,6 +189,7 @@ impl MonoOffsets { runtime_info: 0xA8, field_count: 0x68, next_class_cache: 0xAC, + // Not a thing in V1/V1Cattrs class_kind: 0x0, generic_class: 0x0, }, @@ -219,6 +220,7 @@ impl MonoOffsets { runtime_info: 0xF8, field_count: 0x94, next_class_cache: 0x100, + // Not a thing in V1/V1Cattrs class_kind: 0x0, generic_class: 0x0, }, @@ -249,6 +251,7 @@ impl MonoOffsets { runtime_info: 0xA4, field_count: 0x64, next_class_cache: 0xA8, + // Not a thing in V1/V1Cattrs class_kind: 0x0, generic_class: 0x0, }, From 4f63667607347d7fc3e12578ec1a2ccf98dd876e Mon Sep 17 00:00:00 2001 From: Mitchell Merry Date: Sun, 10 May 2026 18:30:38 +1000 Subject: [PATCH 10/10] another one --- src/game_engine/unity/mono/offsets.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/game_engine/unity/mono/offsets.rs b/src/game_engine/unity/mono/offsets.rs index f6733cf..cb5767d 100644 --- a/src/game_engine/unity/mono/offsets.rs +++ b/src/game_engine/unity/mono/offsets.rs @@ -67,7 +67,6 @@ impl MonoOffsets { runtime_info: 0x7C, field_count: 0x9C, next_class_cache: 0xA0, - // TODO class_kind: 0xF, generic_class: 0x70, },