Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Unity] Various improvements #67

Merged
merged 15 commits into from
Oct 16, 2023
Merged

[Unity] Various improvements #67

merged 15 commits into from
Oct 16, 2023

Conversation

Jujstme
Copy link
Contributor

@Jujstme Jujstme commented Oct 15, 2023

Several improvements were made to the Mono and IL2CPP code that should allow for easier mantainance and less spaghetti code:

  • Mono was already using the mono_assembly_foreach symbol to find the game assemblies. This code is now part of the crate itself so the relative call has been changed
  • PE module sizes are now queried using pe::read_size_of_image in order to avoid issues with Proton/Wine under linux
  • The function to automatically detect the IL2CPP stuct version to use was broken. It has been fixed now, although there is no guarantee this will work fine on every game, so help by experienced Unity hackers might be appreciated anyway
  • A CSTR const is now used instead of manually defining a capacity of 128 every time an ArrayCString is read from memory. This way, in case of need, the capacity of the ArrayCStrings can be changed as needed
  • A (private) Assembly struct has been added, as a MonoImage is technically loaded from the assembly. There is no need to make this struct public, but it allows to streamline some code. Also, if more functions are needed that rely on an Assembly instead of a Image, this should allow for easier future implementations
  • A Field struct has been added in order to use some functions specific for MonoField (get_name() and get_offset()). Class::get_field has been renamed to Class:get_field_offset for better clarity. As for Assembly, this struct is not exposed publicly
  • Code has been slightly modified and optimized, for example by using iterators instead of standard loops
  • Some functions have now a simpler syntax
  • Empty iterators now properly return as empty iterators, instead of returning Error
  • A UnityPointer struct has been added to allow for automatic pointer path resolution. It internally uses DeepPointer, wrapped into a OnceCell to allow for lazy evaluation of the pointer path with interior mutability when trying to deref() it. Example:
    let is_loading = UnityPointer::<5>::new("SceneManager", 1, &["s_sInstance", "m_bProcessing"]);

    ...

    watcher.is_loading.update(is_loading.deref::<bool>(&process, &module, &image).ok());

Some processes do export useful symbols that can be used to recover memory addresses or other useful values. The newly added `symbols()` function allows to iterate over them in order to recover, if needed, the addresses of interest.

For example, Duckstation (a PS1 emulator) exports the address of the emulated RAM as a symbol, so it can be easily recovered by simply querying:

```rust
let pointer: Address = pe::symbols::<5>(&process, main_module).find(|symbol| symbol.name.matches(b"RAM"));
```
Several improvements were made to the Mono and IL2CPP code that should allow for easier mantainance and less spaghetti code:
- Mono was already using the `mono_assembly_foreach` symbol to find the game assemblies. This code is now part of the crate itself so the relative call has been changed
- PE module sizes are now queried using `pe::read_size_of_image` in order to avoid issues with Proton/Wine under linux
- The function to automatically detect the IL2CPP stuct version to use was broken. It has been fixed now, although there is no guarantee this will work fine on every game, so help by experienced Unity hackers might be appreciated anyway
- A `CSTR` const is now used instead of manually defining a capacity of 128 every time an `ArrayCString` is read from memory. This way, in case of need, the capacity of the `ArrayCString`s can be changed as needed
- A (private) `Assembly` struct has been added, as a `MonoImage` is technically loaded from the assembly. There is no need to make this struct public, but it allows to streamline some code. Also, if more functions are needed that rely on an `Assembly` instead of a `Image`, this should allow for easier future implementations
- A `Field` struct has been added in order to use some functions specific for `MonoField` (`get_name()` and `get_offset()`). `Class::get_field` has been renamed to `Class:get_field_offset` for better clarity. As for `Assembly`, this struct is not exposed publicly
- Code has been slightly modified and optimized, for example by using iterators instead of standard loops
- Some functions have now a simpler syntax
- Empty iterators now properly return as empty iterators, instead of returning Error
- A `UnityPointer` struct has been added to allow for automatic pointer path resolution. It internally uses `DeepPointer`, wrapped into a `OnceCell` to allow for lazy evaluation of the pointer path with interior mutability when trying to `deref()` it. Example:

```rust
    let is_loading = UnityPointer::<5>::new("SceneManager", 1, &["s_sInstance", "m_bProcessing"]);

    ...

    watcher.is_loading.update(is_loading.deref::<bool>(&process, &module, &image).ok());

```
src/game_engine/unity/il2cpp.rs Outdated Show resolved Hide resolved
@CryZe CryZe merged commit 479b854 into LiveSplit:master Oct 16, 2023
4 checks passed
@Jujstme Jujstme deleted the pe_symbols branch October 16, 2023 21:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants