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
1.03k stars 202 forks source link

Generic Return value Convert Problem #218

Closed Chensem closed 2 years ago

Chensem commented 2 years ago

Hey , I am some problem about return value convert the target function return value type is generic , can you show me snippet

  1. i want to conver return value to target object image
  2. for example image

image

vfsfitvnm commented 2 years ago

Sure, you need to call inflate:

const obj = JsonMapper.method("ToObject").overload("System.String").inflate(MessageClass).invoke(Return);
Chensem commented 2 years ago

i think you misunderstand my meanings ? the function ToObject return generic value and paramer's type is System.String , in frida-il2cpp-bridge is Il2Cpp.String const obj = JsonMapper.method("ToObject").overload("System.String").inflate(MessageClass).invoke(Return); i think this snippet , represent the input paramter is generic ? i want to turn the return object to another object , like type cast ?

i evaluate your snippet and get the error below ? image In dump.cs , there are two functions i used image one is ToJson , which serialize the System.Object to Json string the another ToObject , which deserialize the Json String to System.Object

so I Intercept a function that the input paramter is System.Object , so i use ToJson to serialize object to json string , then i do something in this json string , then i use ToObject function to turn this json string to the object that i intercept .

vfsfitvnm commented 2 years ago

As you can see, ToObject doesn't have an offset (there's no // 0x....), which means it cannot be called as it is (as expected, because it's generic). So you need to inflate it first (i.e. pass an actual type, so it's not generic anymore). But that error is definitely unexpected.

i want to turn the return object to another object , like type cast ?

This is what the inflate is for. Type casting is not a thing and it doesn't make sense in this scenario (the deserializer needs to now the type, right?).

the another ToObject , which deserialize the Json String to System.Object

I can't see such function, the one you highlighted returns a LitJson.JsonData.

What's the application id/name? So I can take a look

Chensem commented 2 years ago

The apk download link : https://download.link

the snippets i used

var AssemblyCSharp = Il2Cpp.Domain.assembly("Assembly-CSharp").image;
var JsonMapper = AssemblyCSharp.class("LitJson.JsonMapper");

AssemblyCSharp.class("GameXX").method("SendMessage").implementation = function(message : Il2Cpp.Object) : void{ 
    var tpe = message.method("GetType").invoke() as Il2Cpp.Object;
    var MessageId = AssemblyCSharp.class("LiteNet.MessageMapping").method("GetMessageID").overload("System.Type").invoke(tpe) as Il2Cpp.Object;
    if(MessageId.toString() == "XX"){
        this.method("SendMessage").invoke(message) 
    }else{
        // object to json string
        var Return = JsonMapper.method<Il2Cpp.String>("ToJson").invoke(message)

        console.warn(`return json string is ${Return}`)

        // here want to convert json string to message 
        const Obj = JsonMapper.method("ToObject").overload("System.String").inflate(AssemblyCSharp.class("LiteNet.IMessage")).invoke(Return) 
        console.log(Obj) // want to convert to message object
        this.method("SendMsg").invoke(Obj) // converted object

    }

}
vfsfitvnm commented 2 years ago

Thanks, but would you tell me the apk id (i.e. com.example.application) instead of a direct apk download?

Chensem commented 2 years ago

com.xxx.application

vfsfitvnm commented 2 years ago

Ok, I got it.

This line

JsonMapper.method("ToObject").overload("System.String")

selects this method:

static LitJson.JsonData ToObject(System.String json); // 0x0126c040

That's why it complains it's not generic. Unfortunately there's an overload clash. So, to select this one:

static T ToObject(System.String json);

you can do:

const ToObject = JsonMapper.methods.find(candidate => candidate.toString() == "static T ToObject(System.String json);");

Full code:

import "frida-il2cpp-bridge";

Il2Cpp.perform(() => {
    const AssemblyCSharp = Il2Cpp.Domain.assembly("Assembly-CSharp").image;
    const JsonMapper = AssemblyCSharp.class("LitJson.JsonMapper");

    const GetMessageID = AssemblyCSharp.class("LiteNet.MessageMapping").method<Il2Cpp.Object>("GetMessageID").overload("System.Type");
    const ToObject = JsonMapper.methods.find(candidate => candidate.toString() == "static T ToObject(System.String json);")!.inflate<Il2Cpp.Object>(AssemblyCSharp.class("LiteNet.IMessage"));

    console.log(ToObject);

    AssemblyCSharp.class("GameNet").method("SendMsg").implementation = function (message: Il2Cpp.Object): void {
        const type = message.method<Il2Cpp.Object>("GetType").invoke();
        const messageId = GetMessageID.invoke(type);

        if (messageId.toString() == "XX_RESPONSE_HEARTBEAT") {
            this.method("SendMsg").invoke(message);
        } else {
            const result = JsonMapper.method<Il2Cpp.String>("ToJson").invoke(message);

            console.log(`return json string is ${result}`);

            const object = ToObject.invoke(result);

            console.log(object);

            this.method("SendMsg").invoke(object);
        }
    }
});
Chensem commented 2 years ago

on my machine , abort was called ? when invoke const object = ToObject.invoke(result);

image
Chensem commented 2 years ago

I seem to know the reason LiteNet.IMessage is a interface

vfsfitvnm commented 2 years ago

I didn't run the code because I needed to play the game. "Abort was called" means an exception occurred (you can put Il2Cpp.installExceptionListener("all"); somewhere so it will print that exception).

vfsfitvnm commented 2 years ago

Yeah, indeed that may be the reason.

Chensem commented 2 years ago

thank you quickly reply , it solved my problem , thank you so much .