Git Product home page Git Product logo

vfsfitvnm / frida-il2cpp-bridge Goto Github PK

View Code? Open in Web Editor NEW
918.0 17.0 191.0 1.26 MB

A Frida module to dump, trace or hijack any Il2Cpp application at runtime, without needing the global-metadata.dat file.

Home Page: https://github.com/vfsfitvnm/frida-il2cpp-bridge/wiki

License: MIT License

TypeScript 81.59% C 1.66% Makefile 4.75% C# 0.46% JavaScript 11.54%
frida il2cpp frida-il2cpp-bridge global-metadata trace dump

frida-il2cpp-bridge's People

Contributors

drakota avatar flechaa avatar lukaszmigdalek avatar thinhbuzz avatar vfsfitvnm avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

frida-il2cpp-bridge's Issues

iOS error when initializing

TypeError: Cannot set property moduleName of class UnityBase {
    /** Gets the Unity module name. */
    static get moduleName() {
        switch (Process....<omitted>...
} which has only a getter
    at Function.initialize (node_modules/frida-il2cpp-bridge/dist/il2cpp/base.js:70:1)
    at Function.perform (node_modules/frida-il2cpp-bridge/dist/il2cpp/base.js:101:1)
    at Object.1.frida-il2cpp-bridge (index.ts:3:8)
    at o (node_modules/browser-pack/_prelude.js:1:1)
    at r (node_modules/browser-pack/_prelude.js:1:1)
    at node_modules/browser-pack/_prelude.js:1:1

Unity.moduleName = unityModuleName;
Il2Cpp.moduleName = il2cppModuleName;
Happens when you attempt to change their moduleName(s)
I tried to play around and see if I could fix it by adding a setter, but to no avail.

Doesn't play well woth grida-gadget

Wow I butchered that title. Eek.

Hello! I recently created a frida-gadget modded APK using this and it doesn't seem to play well at all. I've had 2 users who happen to be using Android 12 tell me that this library causes their graphics to look like this on load.

I went through basic tests. Extracted an APK and repacked it then told them to run it. No problems.
Injected frida-gadget with an empty script. No problems.
Gave them a script that looked like:

import "frida-il2cpp-bridge"; Il2Cpp.perform(() => {});

Graphics looked awful.

I asked them what architecture they're running and all of ours match. The biggest difference I can see is I run Android 10 and they both run 12. This app doesn't want to open in any form of emulator be it Android Studio or Bluestacks so I can't really test it.

Something in this library or a dependency is causing some kind of issue and I don't know what. I figured I'd come here first to see if you have any idea what might be causing this before I explore other avenues.

EDIT: I'm not actually running the latest version. Trying that right now first.

EDIT2: I've gotten them to try a version with the latest frida-il2cpp-bridge and the issue still occurs.

iOS Tester

Hey, I’m willing to try this for iOS and work with you so this script can be universal, do you have any outside contacts, you can add me on discord busmanl30#3931 thank you

Couldn't obtain the Unity version


/ _  |   Frida 14.2.2 - A world-class dynamic instrumentation toolkit                     

| (| |
> _ | Commands:
/
/ || help -> Displays the help system
. . . . object? -> Display information about 'object'
. . . . exit/quit -> Exit
. . . .
. . . . More info at https://www.frida.re/docs/home/
Spawning com.yunshi.leitingwinter...
[il2cpp] Frida's JavaScript runtime is not V8 (--runtime=v8). Proceed with caution.
Spawned com.yunshi.leitingwinter. Resuming main thread!
[MI 8::com.yunshi.leitingwinter]-> **
[il2cpp] Couldn't obtain the Unity version._**
at raise (/dumpcs.js:3786)
at getUnityVersion (/dumpcs.js:1892)

the game is:
https://www.taptap.com/app/183733

Create new ulong list Error: abort was called

When I try to create new ulong list using below code, When I try to create a new long list using the code below, I can call get_Count method but when I try to add item to list via Add or set_Item methods I always get the error as Error: abort was called

Please help me clarify it

const classes = Il2Cpp.Image.corlib.classes;
const Convert = classes['System.Convert'];
const SystemToUInt64 = classes['System.UInt64'];
const GenericList = classes['System.Collections.Generic.List<T>'];
const SystemToUInt64List = GenericList.inflate(SystemToUInt64);
const instance = Il2Cpp.Object.from(SystemToUInt64List);
// const ulongValue = Convert.methods['ToUInt64_____________'].invoke<any>(Il2Cpp.String.from('1000000000000'));
const ulongValue = new UInt64(1000000000000);
console.log('before', instance.methods.get_Count.invoke(), ulongValue);
// instance.methods.Add.invoke(ulongValue);
instance.methods.set_Item.invoke(0, ulongValue);
console.log('after', instance.methods.get_Count.invoke());

image

Cannot invoke overloaded constructor?

Hey, I am trying to invoke a constructor of class but I keep facing issues of invalid paramter length.

image

Here are the constructors of the said class,

image

and here is the code being used to access the constructor of said class,

    const UnityCoreModule = Il2Cpp.Domain.assemblies["UnityEngine.CoreModule"].image;
    const UnityImgui =  Il2Cpp.Domain.assemblies["UnityEngine.IMGUIModule"].image; 

    const GUIcontent = UnityImgui.classes["UnityEngine.GUIContent"];
    
    const guicnt = GUIcontent.alloc();
    guicnt.methods[".ctor"].invoke(Il2Cpp.String.from("Hellowwww!"));
    const guicntAsVal = new Il2Cpp.ValueType(guicnt.unbox(), GUIcontent.type);

I try to invoke the constructor with string argument but it fails to do so.

Memoization yields unexpected results

Hi,
after upgrading to 0.7.1 when using this code

Il2Cpp.Domain.assembly("Assembly").image.class("TestClass").method<void>("Method").implementation = function(p1: Il2Cpp.Object) : void{
    this.method<void>("Method").invoke(p1)
    this.method<void>("Method").invoke(p1)
}

I sometimes get this error

Error: already replaced this function at Object.value [as replace] (frida/runtime/core.js:373:1) at set implementation [as implementation] (node_modules/frida-il2cpp-bridge/dist/il2cpp/structs/method.js:87:1)

previous versions didn't have this. At the same time, the method does not work as I wrote

cannot return FlatBuffers.Offset<T> correctly

Q1: invoking Text.get_text method, return "undefined".
Q2: invoking Vec3.CreateVec3 method, return "undefined".

index.ts

import "frida-il2cpp-bridge";
async function main() {
    await Il2Cpp.initialize();

    const TestScene = Il2Cpp.Domain.reference.assemblies['Assembly-CSharp'].image.classes['TestScene'];
    TestScene.methods.OnBtnTest.implementation = function () {

        // QUESTION 1: invoking get_text method, return "undefined"
        const text = this.fields.infoText.value as Il2Cpp.Object;
        console.log('infoText.text =', text.methods.get_text.invoke<Il2Cpp.String>());  // "infoText.text = undefined"

        // QUESTION 2: invoking CreateVec3 method, return "undefined"
        const FlatBufferBuilder = Il2Cpp.Domain.reference.assemblies['FlatBuffers'].image.classes['FlatBuffers.FlatBufferBuilder'];
        const Vec3 = Il2Cpp.Domain.reference.assemblies['Assembly-CSharp'].image.classes['CompanyNamespaceWhatever.Vec3'];

        const fbb = Il2Cpp.Object.from(FlatBufferBuilder);
        fbb.methods['.ctor'].invoke(1);

        const offsetVec3 = Vec3.methods.CreateVec3.invoke<Il2Cpp.ValueType>(fbb, 1, 0, 0);
        console.log('offsetVec3 =', offsetVec3);    // "offsetVec3 = undefined"


    }
}
main().catch(error => console.log(error.stack));

TestScene.cs

using CompanyNamespaceWhatever;
using FlatBuffers;
using UnityEngine;
using UnityEngine.UI;

public class TestScene : MonoBehaviour
{
    public Text infoText;

    public void OnBtnTest()
    {
        FlatBufferBuilder fbb = new FlatBufferBuilder(1);
        Offset<Vec3> offset = Vec3.CreateVec3(fbb, 1, 2, 1);
        Debug.Log(offset.Value);

        infoText.text = "Vec3 offset is :" + offset.Value;
    }
}

Vec3.cs

public struct Vec3 : IFlatbufferObject
    {
        private Struct __p;
        public ByteBuffer ByteBuffer { get { return __p.bb; } }
        public void __init(int _i, ByteBuffer _bb) { __p.bb_pos = _i; __p.bb = _bb; }
        public Vec3 __assign(int _i, ByteBuffer _bb) { __init(_i, _bb); return this; }

        public float X { get { return __p.bb.GetFloat(__p.bb_pos + 0); } }
        public float Y { get { return __p.bb.GetFloat(__p.bb_pos + 4); } }
        public float Z { get { return __p.bb.GetFloat(__p.bb_pos + 8); } }

        public static Offset<Vec3> CreateVec3(FlatBufferBuilder builder, float X, float Y, float Z)
        {
            builder.Prep(4, 12);
            builder.PutFloat(Z);
            builder.PutFloat(Y);
            builder.PutFloat(X);
            return new Offset<Vec3>(builder.Offset);
        }
    };

Test Enviroment

frida-il2cpp-bridge version: 0.4.1
unity version: 2019.4.14.f1
test apk: https://drive.google.com/file/d/145p3JRDMxnAU06kgBEtWQk-JsRM6znbK/view?usp=sharing

Error: access violation accessing 0x0

Game Unity Version : 5.6.4p4
frida-il2cpp-bridge Version : 0.5.8

Log Error :

[il2cpp] Dumping methods from Assembly-CSharp...
Error: access violation accessing 0x0
    at NativePointer.writePointer (frida/runtime/core.js:144:1)
    at write (node_modules/frida-il2cpp-bridge/dist/il2cpp/utils.js:95:1)
    at Il2CppPointer.set (node_modules/frida-il2cpp-bridge/dist/il2cpp/structs/pointer.js:43:1)
    at Il2CppPointer.write (node_modules/frida-il2cpp-bridge/dist/il2cpp/structs/pointer.js:49:1)
    at Il2CppPointer.set values [as values] (node_modules/frida-il2cpp-bridge/dist/il2cpp/structs/pointer.js:19:1)   
    at Function.from (node_modules/frida-il2cpp-bridge/dist/il2cpp/structs/array.js:18:1)
    at getTypeArray (node_modules/frida-il2cpp-bridge/dist/il2cpp/dumper.js:58:1)
    at Il2CppDumper.#generator (node_modules/frida-il2cpp-bridge/dist/il2cpp/dumper.js:64:1)
    at #generator.next (<anonymous>)
    at Il2CppDumper.build (node_modules/frida-il2cpp-bridge/dist/il2cpp/dumper.js:85:1)

it was be able to dump some methods then this error appear

Implementation returning question

In the older days of frida-il2cpp-bridge, something like this was possible before you stopped using Interceptor.attach

method.intercept({
    onLeave(returnValue){
         returnValue.value += 5
    }
})

Is it still possible to return a value based on the "onLeave" return value now that method intercepting has been merged into method.implementation? The method is not static, so invoking it will not work.

Cannot read property 'address' of undefined in unityVersion

Hi @vfsfitvnm,
First off, congrats for the 0.5.0 release, there's some really nice features.

After updating to 0.5.0 from 0.2.4 , I'm unable to attach a script, I get this error:

Attaching...
TypeError: Cannot read property 'address' of undefined
 at Function.get unityVersion (node_modules/frida-il2cpp-bridge/dist/il2cpp/base.js:26:1
 at Function.descriptor.get (node_modules/decorator-cache-getter/dist/index.js:9:1
 at createMissingApi (node_modules/frida-il2cpp-bridge/dist/il2cpp/api.js:806:1
 at Function.get sources (node_modules/frida-il2cpp-bridge/dist/il2cpp/api.js:405:1
 at Function.descriptor.get (node_modules/decorator-cache-getter/dist/index.js:9:1
 at Function.r (node_modules/frida-il2cpp-bridge/dist/il2cpp/api.js:409:1
 at Function.get _getCorlib (node_modules/frida-il2cpp-bridge/dist/il2cpp/api.js:212:1
 at Function.descriptor.get (node_modules/decorator-cache-getter/dist/index.js:9:1
 at Function.initialize (node_modules/frida-il2cpp-bridge/dist/il2cpp/base.js:42:1) 

The problem lies here:

static get unityVersion(): UnityVersion {
const range = Process.getRangeByAddress(Process.getModuleByName(this.unityModuleName).base);
const address = Memory.scanSync(range.base, range.size, "45787065637465642076657273696f6e3a")[0].address;
const unityVersion = new UnityVersion(address.readUtf8String()!);
if (unityVersion == undefined) {
raise("Couldn't obtain the Unity version.");
} else if (unityVersion.isBelow("5.3.0") || unityVersion.isEqualOrAbove("2021.1.0")) {
raise(`Unity version "${unityVersion}" is not valid or supported.`);
}
return unityVersion;
}

scanSync doesn't find the pattern in the selected range and returns undefined.

I've modified it to look like the previous version like this and this works fine on 0.5.0

const unityLibraryName =
Process.platform == "linux" ? "libunity.so" : Process.platform == "windows" ? "UnityPlayer.dll" : platformNotSupported();
let unityVersion: UnityVersion | undefined;
const searchStringHex = "45787065637465642076657273696f6e3a"; // "Expected version: "
try {
const unityLibrary = await forModule(unityLibraryName);
for (const range of unityLibrary.enumerateRanges("r--")) {
const result = Memory.scanSync(range.base, range.size, searchStringHex)[0];
if (result !== undefined) {
unityVersion = new UnityVersion(result.address.readUtf8String()!);
break;
}
}
} catch (e) {
raise("Couldn't obtain the Unity version: " + e);
}
if (unityVersion == undefined) {
raise("Couldn't obtain the Unity version.");
} else if (unityVersion.isBelow("5.3.0") || unityVersion.isEqualOrAbove("2021.1.0")) {
raise(`Unity version "${unityVersion}" is not valid or supported.`);
}
return unityVersion;
}

Wanted to make a PR, but not sure why the change in this version.

Incorrect inflated method invocation

pointInString.implementation = function (format : Il2Cpp.String) : Il2Cpp.String
    {
        
        const PointValue = this.fields.Point.value as Il2Cpp.Object;
        
        const val = PointValue.methods.get_Item.invoke<number>(0);


        //log(JSON.stringify(state));
        return this.methods["ToString_"].invoke<Il2Cpp.String>(format);
    }

Generating Error:


Error: expected a NativePointer object
    at NativeFunction.<anonymous> (<anonymous>)
    at Il2CppMethod.invokeRaw (../../node_modules/frida-il2cpp-bridge/dist/il2cpp/structs/method.js:141:1)
    at Il2CppMethod.<anonymous> (../../node_modules/frida-il2cpp-bridge/dist/il2cpp/structs/method.js:149:1)
    at Il2CppObject.pointInString.implementation (index.ts:40:49)
    at InvocationContext.replaceCallback (../../node_modules/frida-il2cpp-bridge/dist/il2cpp/structs/method.js:95:1)

Originally posted by @afk-Legacy in #36 (comment)

Dlopen hook causes app crash on Android 12

Hello.
How i can get some logs or something else cause my Android 12 smarthone just force close game after spawn.

Android 12:
Use frida spawn command frida -U -f com.example.app -l _script.js --no-pause just spawn my Game and cause Crashing after a second. Even cannot finish dumping command.

Use frida attach frida -U -n Appname -l _script.js --no-pauseor frida -U Appname -l _script.js works great but i cannot intercept some initial functions of the Game because should to waint until attach to the procces. dump command works great by attaching.
Same thing with frida-gadget... my default frida JS script works good.. frida-il2cpp-bridge script still crashed the game.

Most stranger thing that script works good on a first second and replace some function without any issue but after one second game crashes without any log/error in command prompt

Android 11 & Android 10:
frida-Il2cpp-bridge my script works good with frida-server and frida-gadget

Maybe i can try to update to the latest frida version for your module but idk how

Generic handling error in unity 2017.4.39f1 and mscorlib 2.0.0.0

I encountered the following error when trying the generic handling example in version 2017.4.39f1:

[il2cpp] Couldn't find property "System.RuntimeType", did you mean "System.ValueType"?
    at Object.raise (node_modules/frida-il2cpp-bridge/dist/utils/console.js:10:1) 
    at Object.get (node_modules/frida-il2cpp-bridge/dist/utils/utils.js:28:1)     
    at Il2CppClass.inflate (node_modules/frida-il2cpp-bridge/dist/il2cpp/structs/class.js:136:1)
    at doHook (index.ts:17:42)
    at executor (node_modules/frida-il2cpp-bridge/dist/il2cpp/base.js:75:1)

I found that my mscorlib assembly is missing the System.RuntimeType class, so I modified the implementation of Il2CppClass.inflate() and Il2CppMethod.inflate() as follows:

// Il2CppClass.inflate()
inflate(...classes) {
        if (!this.isGeneric) {
            console_1.raise(`Cannot inflate ${this.type.name} because it's not generic.`);
        }
        const typeArray = Il2Cpp.Array.from(Il2Cpp.Image.corlib.classes["System.Type"], classes.map(klass => klass.type.object));
        //static System.Type MakeGenericType(System.Type gt, System.Type[] types);
        const inflatedType = Il2Cpp.Image.corlib.classes["System.Type"].methods.MakeGenericType.invoke(this.type.object, typeArray);
        return new Il2Cpp.Class(Il2Cpp.Api._classFromSystemType(inflatedType));
    }
//Il2CppMethod.inflate()
inflate(...classes) {
        if (!this.isGeneric) {
            console_1.raise(`Cannot inflate ${this.name} because it's not generic.`);
        }
        const typeArray = Il2Cpp.Array.from(Il2Cpp.Image.corlib.classes["System.Type"], classes.map(klass => klass.type.object));
        const inflatedMethodObject = this.object.methods.MakeGenericMethod.invoke(typeArray);
        return new Il2Cpp.Method(Il2Cpp.Api._methodGetFromReflection(inflatedMethodObject));
    }

Then the Il2CppClass.inflate() error disappears, but the Il2CppMethod.inflate() still has the error:

[il2cpp] Couldn't resolve export "il2cpp_method_get_from_reflection".
    at Object.raise (node_modules/frida-il2cpp-bridge/dist/utils/console.js:10:1) 
    at Function.r (node_modules/frida-il2cpp-bridge/dist/il2cpp/api.js:1344:1)    
    at Function.get _methodGetFromReflection (node_modules/frida-il2cpp-bridge/dist/il2cpp/api.js:335:1)
    at Function.descriptor.get (node_modules/decorator-cache-getter/dist/index.js:9:1)
    at Il2CppMethod.inflate (node_modules/frida-il2cpp-bridge/dist/il2cpp/structs/method.js:100:1)
    at doHook (index.ts:36:42)
    at executor (node_modules/frida-il2cpp-bridge/dist/il2cpp/base.js:75:1)

It looks like this method is not available in the Il2Cpp API in version 2017.4.39f1. Is there any way to get this version of Il2Cpp to support generic methods?

Here is my source code: https://paste.ubuntu.com/p/bdwqsQxQsV/
Here is the Il2Cpp API definition of 2017.4.39f1: https://paste.ubuntu.com/p/s25HQJNtVb/

some class can not show the fields value

the game url:
https://apkpure.com/cn/rocket-punch/com.Highscoregames.Drawrocket

import "frida-il2cpp-bridge";

Il2Cpp.perform(() =>
{

    const SystemString = Il2Cpp.Image.corlib.class("System.String");
    var AssemblyCSharp = Il2Cpp.Domain.assembly("Assembly-CSharp").image;

    //public class GameManager : MonoBehaviourSingleton<GameManager>
    //public class AppLovinManager : MonoBehaviourSingleton<AppLovinManager>
    var AppLovinManager = AssemblyCSharp.class("AppLovinManager");

    //can show the fields value in the SystemString class
    //can not show the fields value in the GameManager class and AppLovinManager class
    Il2Cpp.GC.choose(AppLovinManager).forEach((instance) =>
    {
        //var dynamicFields = instance.fields; //**int version 0.6.6 can get all fields in the class ,now can not get the fields**
        var dynamicFields = instance.class.fields;//should modify it this way to get it ?
        console.log("\n" + dynamicFields);
        for (var i in dynamicFields)
        {
            console.log("\n" + dynamicFields[i].name + "; // " + dynamicFields[i].offset, "\x1b[32m" + dynamicFields[i].value + "\x1B[0m");
        }
    });
});

Modify static field value

Hello.
Try to modify field value: static System.Int32 _maxTime = 11;

By following code:

const maxTime: Il2Cpp.Field = Controller.fields["_maxTime"];
(maxTime.value as number) = 4;

and get this output:
Controller._maxTime is a thread static or literal field, its value won't be modified.

It's possible to modify value in any other way?

Support for 2018.4.2f1

I have an Android app I'm trying to reverse engineer but it's using Unity 2018.4.2f1 as confirmed by il2cppinspector. I'm assuming there won't be any support for this?

image

image

I tried bypassing the issue by setting the Unity version to 2018.3.8 in variables.ts and rebuilding but I get the below error

image

how to process ref field

how to get data value

i try parse data to Il2Cpp.Array<number> but failed

i don't know how to convert that field

public static void EncDecBytes(ref byte[] data, byte[] key) { }

[QUESTION] Is it possible to get caller when entering a method?

I'm currently trying to get the text displayed in an app.
So I hooked TextGenerator.PopulateWithErrors. In this way I can get the text I want but....
When a sentence is "abcdefg", I got 7 separate method onEnter callback:

a
ab
abc
abcd
abcde
abcdef
abcdefg

The displayed characters are increased one at each time.
So I'm wondering how to get the original string "abcdefg" at once.
I think get the caller of TextGenerator.PopulateWithErrors may help.
By the way, I'm wondering how to monitor nested calls in a method. So I can know where these text really from?

Handle for "Il2CppType" cannot be NULL.

Hello @vfsfitvnm !
How to fix this error?

Error: Handle for "Il2CppType" cannot be NULL. at raise (/_.js:3496) at NativeStructNotNull (/_.js:3617) at Il2CppType (/_.js:3023) at get type (/_.js:2810) at call (native) at <anonymous> (/_.js:20) at toString (/_.js:2048) at dump (/_.js:1645)

Error: access violation accessing 0x86

Q1: invoking simpleTrace method, cause a "server terminated" crash.
Q2: invoking get_WeaponType method, cause an "access violation" error.

index.ts

async function main() {
    await Il2Cpp.initialize();

    const TestScene = Il2Cpp.Domain.reference.assemblies['Assembly-CSharp'].image.classes['TestScene'];
    const GameDataWhatever = Il2Cpp.Domain.reference.assemblies['Assembly-CSharp'].image.classes['CompanyNamespaceWhatever.GameDataWhatever'];
    const ByteBuffer = Il2Cpp.Domain.reference.assemblies['FlatBuffers'].image.classes['FlatBuffers.ByteBuffer'];

    // Question 1: will cause a crash.
    // Il2Cpp.Tracer.simpleTrace(GameDataWhatever);

    TestScene.methods.ReadClassFromMemory.implementation = function () {
        const gameDataWhateverBytes = this.fields.gameDataWhateverBytes.value as Il2Cpp.Array<number>;
        console.log(gameDataWhateverBytes.length);  // 120

        const bb = Il2Cpp.Object.from(ByteBuffer);
        bb.methods['.ctor'].invoke(gameDataWhateverBytes);
        console.log(bb.methods.get_Length.invoke<number>());    // 120

        const gameDataValueType = GameDataWhatever.methods.GetRootAsGameDataWhatever.invoke<Il2Cpp.ValueType>(bb);
        const gameData = gameDataValueType.box();
        console.log(gameData);  // CompanyNamespaceWhatever.GameDataWhatever

        // Question 2: Error: access violation accessing 0x86
        gameData.methods.get_WeaponType.invoke();
    }

    console.log('success.');
}

TestScene.cs

public class TestScene : MonoBehaviour
{
    public Text infoText;
    private byte[] gameDataWhateverBytes = { 28, 0, 0, 0, 87, 72, 65, 84, 20, 0, 28, 0, 12, 0, 0, 0, 0, 0, 24, 0, 0, 0, 11, 0, 10, 0, 4, 0, 20, 0, 0, 0, 76, 0, 0, 0, 0, 0, 1, 1, 0, 0, 128, 63, 0, 0, 0, 64, 0, 0, 128, 63, 4, 0, 0, 0, 37, 0, 0, 0, 84, 101, 115, 116, 32, 83, 116, 114, 105, 110, 103, 32, 33, 32, 116, 105, 109, 101, 58, 32, 50, 48, 50, 49, 47, 56, 47, 50, 32, 49, 53, 58, 49, 52, 58, 51, 56, 0, 0, 0, 8, 0, 12, 0, 8, 0, 6, 0, 8, 0, 0, 0, 0, 0, 231, 3, 123, 0, 0, 0 };

    public void OnBtnReadFromMemory()
    {
        ReadClassFromMemory();
    }

    void ReadClassFromMemory()
    {
        ByteBuffer bb = new ByteBuffer(gameDataWhateverBytes);
        GameDataWhatever data = GameDataWhatever.GetRootAsGameDataWhatever(bb);

        infoText.text = String.Format("type: {0}\n xyz: ({1},{2},{3})",
            data.WeaponType, data.Pos.Value.X, data.Pos.Value.Y, data.Pos.Value.Z);
    }
}

GameDataWhatever.cs

public struct GameDataWhatever : IFlatbufferObject
  {
      private Table __p;
      public ByteBuffer ByteBuffer { get { return __p.bb; } }
      public static GameDataWhatever GetRootAsGameDataWhatever(ByteBuffer _bb) { return GetRootAsGameDataWhatever(_bb, new GameDataWhatever()); }
      public static GameDataWhatever GetRootAsGameDataWhatever(ByteBuffer _bb, GameDataWhatever obj) { return (obj.__assign(_bb.GetInt(_bb.Position) + _bb.Position, _bb)); }
      // other functions......
}

Test Environments

frida-il2cpp-bridge: 0.4.3
unity version: 2019.4.14f1
test apk: https://drive.google.com/file/d/1S3Kzak7zzRf9UHUIoMptjLb48Bw8gbi0/view?usp=sharing

Setting wrong field value when it's a value type

To be fair I'm basically a frida noob but I don't understand what's happening here.

Given the following code:

console.log(first.fields.template_id.value, song.fields.template_id.value);
song.fields.template_id.value = first.fields.template_id.value;
console.log('TEMPLATE ID', first.fields.template_id.value, song.fields.template_id.value);

The output is:

57 null
TEMPLATE ID 57 2546596632

Both first and song are of the same type where template_id is System.Nullable<System.UInt32> template_id; // 0x18

I honestly have no idea what to even google or research to figure out what's happening. Why is setting the field to what I believe should be 57 instead giving 2546596632?

How to return null value in implementation?

Incase I want to return null value, I need to cast null to any, so we have any shortcut for avoid cast to any?

assemblyCsharp['class_name'].methods['method_name'].implementation = () => null as any

Problem with generics?

I updated to 0.7.5 today by running npm update and I am facing an error with generics:
il2cpp: couldn't find class System.Collections.Generic.List in mscorlib.dll, did you mean System.Collections.Generic.List`1?

npm list
[email protected] /home/ts
├── @types/[email protected]
├── @types/[email protected]
├─┬ [email protected]
...
└─┬ [email protected]
  ├── [email protected]
  ├── [email protected]
  └── [email protected]

This is the script I tested:

import "frida-il2cpp-bridge";
    Il2Cpp.perform(() => {

        const SystemObject = Il2Cpp.Image.corlib.class("System.Object");
        const SystemInt32 = Il2Cpp.Image.corlib.class("System.Int32");
    
    
        // +++ inflating a generic class +++
        const GenericList = Il2Cpp.Image.corlib.class("System.Collections.Generic.List<T>");
    
        // This class is shared among all reference types
        const SystemObjectList = GenericList.inflate(SystemObject);
    
        // This class is specific to System.Int32, because it's a value type
        const SystemInt32List = GenericList.inflate(SystemInt32);
        // --- inflating a generic class ---
    
    
        // +++ inflating a generic method +++
        const FindAll = Il2Cpp.Image.corlib.class("System.Array").method("FindAll");
        // FindAll is a generic method, its virtual address is null
    
        // This is the FindAll for every reference type
        const SystemObjectFindAll = FindAll.inflate(SystemObject);
    
        // This is the FindAll specific to System.Int32, because it's a value type
        const SystemInt32FindAll = FindAll.inflate(SystemInt32);
        // --- inflating a generic method ---

    });

"Error: expected array with fields" when trace a "public virtual AsyncUnaryCall<T>" method

(AsyncUnaryCall is from gRPC C#)
(All of them have two overloads like

seen

This error will be throwed when tracing (all of simpleTrace,fullTrace,fullWithValuesTrace) them.

Il2Cpp.Tracer.fullTrace(
    domain.assemblies["seen"].image.classes[
      "seen"
    ]
  );
Error: expected array with fields
    at NativeFunction.<anonymous> (<anonymous>)
    at Il2CppMethod.invokeRaw (node_modules/frida-il2cpp-bridge/dist/il2cpp/structs/method.js:104:1)
    at Il2CppMethod.<anonymous> (node_modules/frida-il2cpp-bridge/dist/il2cpp/structs/method.js:112:1)
    at Il2CppObject.domain.assemblies.seen.image.classes.seen.methods.seen.implementation (agent/index.ts:83:52)
    at InvocationContext.replaceCallback (node_modules/frida-il2cpp-bridge/dist/il2cpp/structs/method.js:77:1)
    at NativeFunction.<anonymous> (<anonymous>)
    at Il2CppMethod.invokeRaw (node_modules/frida-il2cpp-bridge/dist/il2cpp/structs/method.js:104:1)
    at Il2CppMethod.<anonymous> (node_modules/frida-il2cpp-bridge/dist/il2cpp/structs/method.js:112:1)
    at Il2CppObject.method.implementation (node_modules/frida-il2cpp-bridge/dist/il2cpp/tracer.js:80:1)
    at InvocationContext.replaceCallback (node_modules/frida-il2cpp-bridge/dist/il2cpp/structs/method.js:77:1)

This error will cause a in-game exception.

But if i use

  domain.assemblies["seen"].image.classes[
    "seen"
  ].methods.seen.implementation = function (
    request: Il2Cpp.Object,
    b: Il2Cpp.Object,
    c: any,
    d: any
  ): any {
    console.log("field: " + req.fields["field"].value);
    return this.methods.seen.invoke(request, b, c, d);
  };

instead, it works fine.
So is this a bug or incorrect tracer usage? I trace the whole class to intercept methods sequence, it works fine on other classes without overloads and generics.

Logging vector fields results in strange values

I have been playing with this for a while on a Pixel 2 XL (Android 9) however I tried some of the code in the readme and I am wondering if I am reading or misinterpreting the code somehow?

const Vector2Class = coreModule.classes["UnityEngine.Vector2"];
const vec = Il2Cpp.Object.from(Vector2Class);
vec.methods[".ctor"].invoke(36, 4);

log("X: " + vec.fields.x.value);
log("Y: " + vec.fields.y.value);

This results in different values logged everytime such as:

X: -8.035985385019588e+22
Y: -2.1116959453495674e+34

Any ideas what I am missing?

untiy function print too many times

some untiy function print too many times , if use Il2Cpp.Tracer.fullWithValuesTrace , can not control print max times,
how to control print the function max times?

Unable to properly hook or call virtual methods

I have method A :

public virtual void AddDialog(UIDialog screen)
{
      doStuff(screen);
}

And attempting to hook it does work, but the result of the hook does not change the outcome.
The implementation below will still be called, but it will not change what the function does and will always return the original result from the hooked function.

targetClass.methods.AddDialog.implementation = function (dialog: IL2CPP.Object) {
      //do nothing
}

Attempting to change the methods outcome I use this code:

targetClass.methods.AddDialog.implementation = function (dialog: IL2CPP.Object) {
     var Instance = new IL2CPP.Object(this.handle);
     var newDialog = myDialog;
     return Instance.methods.AddDialog.invoke(myDialog);
}

That will then throw an error like so:

Error: Couldn't find property "AddDialog", did you mean ".ctor"?
    at get (node_modules/frida-il2cpp-bridge/dist/utils/utils.js:29)
    at <anonymous> (agent/index.ts:187)
    at call (native)
    at replaceCallback (node_modules/frida-il2cpp-bridge/dist/il2cpp/structs/method.js:124)

Any idea how I can go about this?

Thank you and merry christmas! (If you're into the xmas stuff. If not... Happy holidays!)

"Already replaced this function" should be a warning

always have this error
the frida-il2cpp-bridge version is 0.7.3

Error: already replaced this function
at value (frida/runtime/core.js:315)
at set implementation (node_modules/frida-il2cpp-bridge/dist/il2cpp/structs/method.js:122)

at build (node_modules/frida-il2cpp-bridge/dist/il2cpp/tracer.js:207)

i use frida-il2cpp-bridge version is 0.6.6 dont have this error

Originally posted by @350030173 in #93

iOS support (easy fix)

Unfortunately I don't have a ios device!

PS: i just don't know how modules/exports work on ios

Error: illegal instruction on initialization step.

Currently for third.party.app you'll receive Error: illegal instruction when calling

Il2Cpp.perform(() => {
    // ... literally anything. 
   console.log('It works');
})

when spawning app with frida -U -f third.party.app -l _.js --no-pause --runtime=v8.

After debugging this error, I found that issues is with Il2Cpp.Api._getCorlib() call and for Il2Cpp.perform line 83 particularly:

await forModule(this.il2CppModuleName);
if (Il2Cpp.Api._getCorlib().isNull()) {
await new Promise<void>(resolve => {
const interceptor = Interceptor.attach(Il2Cpp.Api._init, {

Currently I fixed this with simple and ugly patch right before if statement

function wa(milis) {
    return new Promise(resolve => setTimeout(resolve, milis));
}

while (true) {
    try {
        Il2Cpp.Api._getCorlib()
        break;
    } catch (e) {
        console.log(e);
        await wa(100);
    }    
} 

Any suggestions what am I doing wrong?

OS: Android 9
Magisk: 23 (23000), App: 23 (23000)
Frida server: 15.1.1-1 (from magisk module). Tried with static binaries from frida/frida (this one exactly) as well

Timeout was reached

Hi,

when I use this code via frida-inject :

import "frida-il2cpp-bridge";

Il2Cpp.perform(() => {
	Il2Cpp.dump()
})

I get this error during the dump :

...
[il2cpp] dumping Assembly-CSharp...
Timeout was reached

I think it's important to add that the Timeout was reached error can occur at any point in the dump.

are there ways to solve this problem ?

What is the best way to instantiate an object?

Hi,

I cannot figure out how to instantiate a tuple.

class System.Tuple<T1,T2> : System.Object, System.Collections.IStructuralEquatable, System.Collections.IStructuralComparable, System.IComparable, System.ITupleInternal

I tried the following:

var tuple_class = corlibclasses['System.Tuple<T1,T2>'].inflate(corlibclasses['System.Int32'],corlibclasses['System.Int32'])
var data = tuple_class.alloc()
data.methods['.ctor'].invoke(this.fields['CurrentBattleId'].value, this.fields['CurrentDifficulty'].value)

but I got an error:

Error: expected an integer
    at <anonymous> (node_modules/frida-il2cpp-bridge/dist/il2cpp/structs/method.js:175)
    at try (node_modules/frida-il2cpp-bridge/dist/il2cpp/base.js:116)
    at invokeRaw (node_modules/frida-il2cpp-bridge/dist/il2cpp/structs/method.js:175)
    at <anonymous> (test.ts:199)
    at call (native)
    at replaceCallback (node_modules/frida-il2cpp-bridge/dist/il2cpp/structs/method.js:124)

How to use Il2Cpp.Reference ?

Hi , I came across a method using a reference

System.Void Method(System.Single& p1);

and I wondered how to use Il2Cpp.Reference
I wrote this code:

Assembly["Class"].methods["Method"].implementation = function (p1: Il2Cpp.Reference<number>) : void {
     p1.value = 0
}

And I got an error:
Error: expected a pointer

then I rewrote the code like this:

Assembly["Class"].methods["Method"].implementation = function (p1: Il2Cpp.Reference) : void {
     p1.value = ptr(0)
}

and there was no mistake, how do I write the number 1 , for example?

Error: abort was called.

In the new update, the issue of invoking List.get_Item() seems to have been fixed but now I am facing problem with List.set_Item():

    pointInString.implementation = function (format : Il2Cpp.String) : Il2Cpp.String
    {
        
        const PointValue = this.fields.Point.value as Il2Cpp.Object;
        const size = PointValue.methods.get_Count.invoke<number>();

        log("++ Array ++");
        log("Size: " + size.toString());

        PointValue.methods.set_Item.invoke<Int64>(size, 9999); // Code runs normally on commenting this line

        for (let a = 0; a < size; a++)
        {
            const val = PointValue.methods.get_Item.invoke<Int64>(a);    
            log(val.toString())
        }

        log("++ Array ++");
        //log(JSON.stringify(state));
        return this.methods["ToString_"].invoke<Il2Cpp.String>(format);
    }

which results in the error:

Error: abort was called
    at NativeFunction.<anonymous> (<anonymous>)
    at Il2CppMethod.invokeRaw (../../node_modules/frida-il2cpp-bridge/dist/il2cpp/structs/method.js:141:1)
    at Il2CppMethod.<anonymous> (../../node_modules/frida-il2cpp-bridge/dist/il2cpp/structs/method.js:149:1)
    at Il2CppObject.pointInString.implementation (index.ts:33:37)
    at InvocationContext.replaceCallback (../../node_modules/frida-il2cpp-bridge/dist/il2cpp/structs/method.js:95:1)

abort was called when trying to invoke method

I have a C# MonoBehaviour class "HelloWorld.cs" and a frida "index.ts".
When I try to invoke a method named "ChangeValue", an error shows as follow.

I think maybe it's because the javascript variable "instance" gets garbage-collected.
But I am not sure.

If so, is it possible to keep alive an instance from an Interceptor so I can use it later outside "onEnter" function?

Error: abort was called
    at _invoke (/index.js:2645)
    at invoke (/index.js:2632)
    at <anonymous> (/index.js:36)
    at apply (native)
    at <anonymous> (frida/runtime/core.js:53)
// HelloWorld.cs 
using UnityEngine;
using TMPro;

public class HelloWorld : MonoBehaviour
{
    public TextMeshProUGUI text;

    public void OnBtnChangeValue() {
        ChangeValue();
    }

    public void ChangeValue () {
        text.text = Random.Range(1, 10000).ToString();
    }
}
// index.ts
async function main() {
    await Il2Cpp.initialize();

    // Uncomment for REPL access
    (global as any).Il2Cpp = Il2Cpp;

    // define a global variable
    let globalInstance: Il2Cpp.Object | null;

    const HelloWorldClass = Il2Cpp.domain.assemblies['Assembly-CSharp'].image.classes['HelloWorld'];
    HelloWorldClass.methods.OnBtnChangeValue.intercept({
        onEnter (instance, parameters) {
            console.log('HelloWorld.OnBtnChangeValue enter...');

            // save as global
            globalInstance = instance;
        }
    });

    let timer = setInterval( () => {
        if (globalInstance) {
            console.log('here...');
            clearInterval(timer);

            // invoke "ChangeValue" by globalInstance
            globalInstance.methods.ChangeValue.invoke();
        }
    }, 2000);
}

main().catch(error => console.log(error.stack));

Method instance is lost when inflating a generic non-static method

Hi,
I have a method that I inflate

const obj =  ;//this Il2cpp Object
const c =  ;//this Il2cpp Class
obj.methods["Methods"].inflate(c).invoke<void>()

when I want to execute this code, I get a message
[il2cpp] l ("Methods") is not static.

how to call a generic method while having an object ?

vitualAddress of generic method

I've noticed that actualPointer of generic methods and all methods in generic classes are null and it is impossible to do anything with them.

As a workaround for methods of generic classes I look for any successor with specified types and take parent from it. This doesn't work if the class has no successors or for generic methods.

As per https://www.codeproject.com/Articles/22088/Reflecting-on-Generics, there is difference between open and closed generic methods and actualPointer is only valid for closed ones. There are System.Type.MakeGenericType and System.MethodInfo.MakeGenericMethod methods to get closed versions from open ones. But is unclear to me how to convert between Il2Cpp.Method/Il2Cpp.Type and Il2Cpp.Object of type System.MethodInfo/System.Type if this is even possible. System.Type has Il2CppType handle as an internal field, so it will be possible to convert this way, but the other way around is much harder without simple public constructor (I'm even not sure if it's supposed to be constructed or each type is a singleton and there is a global cache for them)

Alternatively it should be useful to just list all available closed instantiations and to be able to select one with Accessor.

Alternatively, as far as I can see, all different instantiations of a method has the same actualPointer value, so it would be very convenient to recognize the fact that the method is generic and just pick actualPointer value from any of instantiations automatically instead of returning null.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.