vfsfitvnm / frida-il2cpp-bridge

A Frida module to dump, trace or hijack any Il2Cpp application at runtime, without needing the global-metadata.dat file.
https://github.com/vfsfitvnm/frida-il2cpp-bridge/wiki
MIT License
974 stars 199 forks source link

Trouble creating new instance of class #223

Closed leonitousconforti closed 1 year ago

leonitousconforti commented 1 year ago

Here is the stub for the class that is giving me some trouble:

public class SomeKlass {
  public static SomeKlass instance = new SomeKlass();
  public static Dictionary<int, DSO> someField;
  public SomeKlass() {
    instance = this;
    // add some entries to the someField dictionary
    // ...
  }
}

I want to access the someField property of the someKlass. The trouble is that SomeKlass is not instantiated by the app right away, so I have to do some user action in order to get it to create an instance of the class. The source code of the app (I have it) only ever accesses somefield via SomeKlass.instance.someField. I have tested and can confirm that I can access someField after doing some user input on the app, but I would like to be able to access someField without having to do user input on the app.

Things I have tried to access someField without having to do the user input to have the app access SomeKlass.instance.someField to create the instance:

  1. creating a new instance of SomeClass
    
    const csharpAssembly = Il2Cpp.Domain.assembly("Assembly-CSharp");
    const SomeClass = csharpAssembly.image.class("SomeClass");
    const SomeClassInstance = SomeClass.new();

// Always null const someField = SomeClassInstance.field("someField").value;

// Prints: {"SomeClass":{"handle":"0x70caa357d0"},"SomeClassInstance":{"handle":"0x6f769dbf60"},"someField":{"handle":"0x0"}} console.log(JSON.stringify({ SomeClass, SomeClassInstance, someField }));


2. accessing static instance field
```js
const csharpAssembly = Il2Cpp.Domain.assembly("Assembly-CSharp");
const SomeClass = csharpAssembly.image.class("SomeClass");
const SomeClassInstance = SomeClass.field<Il2Cpp.Object>("instance").value;

// Always null
const someField = SomeClassInstance.field<Il2Cpp.Object>("someField").value;

// Prints: (Doesn't reach print statement)
// Error: access violation accessing 0x0 (sometime before the print statement)
console.log(JSON.stringify({ SomeClass, SomeClassInstance, someField }));
  1. creating a new instance and then accessing the instance field
    
    const csharpAssembly = Il2Cpp.Domain.assembly("Assembly-CSharp");
    const SomeClass = csharpAssembly.image.class("SomeClass");
    const SomeClassInstance = SomeClass.new();
    const SomeClassInstance1 = SomeClass.field<Il2Cpp.Object>("instance").value;

// Always null const someField = SomeClassInstance1.field("someField").value;

// Prints: {"SomeClass":{"handle":"0x78b1893190"},"SomeClassInstance":{"handle":"0x7640838ca0"},"SomeClassInstance1":{"handle":"0x7640838ca0"},"someField":{"handle":"0x0"}} console.log(JSON.stringify({ SomeClass, SomeClassInstance, SomeClassInstance1, someField }));



No matter how long I wait (up to 30 seconds after the app fully loads) or how many times I retry after the app fully loads (up to 5 reties, waiting 30 seconds in between) the console.log prints are always the same. Any input on what I might be doing wrong?
vfsfitvnm commented 1 year ago

Uhm, I don't know honestly. Your code looks correct. Two things that come in my mind right now are trying to call the staric constructor of that class first:

SomeClass.initialize();

or make sure those static fields are not per-thread ([ThreadStatic]). You can try to run to run the relvant snippet using:

Il2Cpp.attachedThreads[0].schedule(...);
leonitousconforti commented 1 year ago

Thanks so much for the speedy suggestions!

This is what ended up working for me:

const csharpAssembly = Il2Cpp.Domain.assembly("Assembly-CSharp");
const SomeClass = csharpAssembly.image.class("SomeClass");
SomeClass.initialize();
const someField = SomeClassInstance.field<Il2Cpp.Object>("someField").value;