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.06k stars 204 forks source link

How to invoke the original method implementation in case of non-static methods? #569

Closed hieupva closed 2 days ago

hieupva commented 5 days ago

I want to hook this method, but only for url and method. It keeps throwing an error and duplicate. How can I fix it?

// UnityEngine.UnityWebRequestModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
// UnityEngine.Networking.UnityWebRequest
using System;
using System.Runtime.CompilerServices;
using Il2CppDummyDll;

[Token(Token = "0x6000027")]
[Address(RVA = "0x62EA098", Offset = "0x62EA098", VA = "0xC41D4098")]
public UnityWebRequest(string url, string method, DownloadHandler downloadHandler, UploadHandler uploadHandler)
{
}

My Hooking Code:

import "frida-il2cpp-bridge";

Il2Cpp.perform(() => {
    console.log("Script Load!");
    const UnityWebRequest = Il2Cpp.domain.assembly("UnityEngine.UnityWebRequestModule").image.class("UnityEngine.Networking.UnityWebRequest");
    // Hook the constructor
    const UnityWebRequestB = UnityWebRequest.method(".ctor", 4);

    UnityWebRequestB.implementation = function(url, method, downloadHandler, uploadHandler) {
        const result = UnityWebRequestB.invoke(url, method, downloadHandler, uploadHandler);
        console.log(`[UnityWebRequestB] URL: ${url}, Method: ${method}`);
        return result;
    };

});

Error Message i got after loading script


Script Load!
il2cpp: cannot invoke non-static method .ctor as it must be invoked throught a Il2Cpp.Object, 
not a Il2Cpp.Class
    at invoke (/node_modules/frida-il2cpp-bridge/dist/index.js:2608)
    at <anonymous> (HookBundle.ts:10)
    at call (native)
    at <anonymous> (/node_modules/frida-il2cpp-bridge/dist/index.js:2731)
il2cpp: cannot invoke non-static method .ctor as it must be invoked throught a Il2Cpp.Object, 
not a Il2Cpp.Class
    at invoke (/node_modules/frida-il2cpp-bridge/dist/index.js:2608)
    at <anonymous> (HookBundle.ts:10)
    at call (native)
    at <anonymous> (/node_modules/frida-il2cpp-bridge/dist/index.js:2731)
... 
vfsfitvnm commented 4 days ago

How did you come out with invokeConstructor? Il2Cpp.Object and Il2Cpp.Class have no such method

hieupva commented 4 days ago

Apologies, it seems the code/method above I sent was copied incorrectly and incomplete. So I edit the post. The code above was copied from other method. I only changed the name and pasted it again. It work with below method.

I thought the methods were similar, so the approach would be the same. But that is not the case.

// CommonLibs, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
// FileModule.LMN.FileUtil
using Il2CppDummyDll;

[Token(Token = "0x601A4CF")]
[Address(RVA = "0x2B52F64", Offset = "0x2B52F64", VA = "0xC0A3CF64")]
[Attribute(Name = "IDTagAttribute", RVA = "0xC8BCA0", Offset = "0xC8BCA0")]
public static byte[] ReadAllBytesByPath(PathType inPathType, string inPath, bool inUseHashIfShould, bool tryGetFromStreammingAssetsPath)
{
    return null;
}

Code

const FileUtil = Il2Cpp.domain.assembly("CommonLibs").image.class("FileModule.LMN.FileUtil");

    const ReadAllBytesByPathB = FileUtil.method("ReadAllBytesByPath", 4);
    ReadAllBytesByPathB.implementation = function(pathType, inPath, useHash, tryStream) {
        const result = ReadAllBytesByPathB.invoke(pathType, inPath, useHash, tryStream);
        console.log(`[ReadAllBytesByPathB] Type: ${pathType}, Path: ${inPath}\nuseHash: ${useHash} `);
        return result;
    };
vfsfitvnm commented 4 days ago

FileUtil::ReadAllBytesByPath is static, whereas UnityWebRequest::.ctor is not. Whithin your implementation, this is a Il2Cpp.Class if the method is static, or Il2Cpp.Object if it isn't.

Here you are invoking an instance method, but you are not providing the instance:

const result = UnityWebRequestB.invoke(url, method, downloadHandler, uploadHandler);

So, this is how you should do it:

const result = this.method(".ctor", 4).invoke(url, method, downloadHandler, uploadHandler);

And it works for static methods as well:

const result = this.method("ReadAllBytesByPath", 4).invoke(pathType, inPath, useHash, tryStream);
hieupva commented 3 days ago

Ah, I understand. I didn’t notice that UnityWebRequest doesn’t have a static method. And it really works. Thank you for taking the time to help me.