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

Is there any way to deal with race condition? #183

Closed qingpengchen2011 closed 2 years ago

qingpengchen2011 commented 2 years ago

The question is: I hook two functions that are from different threads. But they access the same global variable which is a javascript array I define global. Is there any way to cope with this? I don't know how to use Il2CppObject.enter() and Il2CppObject.exit(). Any example will be good.

vfsfitvnm commented 2 years ago

I never used those api, however the idea is to declare a lock object (or use whatever Il2Cpp.Object you have):

const lock = Il2Cpp.Image.corlib.class("System.Object").new();

And then call the monitor methods you need (e.g. https://stackoverflow.com/a/6029829/16885569)

vfsfitvnm commented 2 years ago

Uhm, however the solution above may have a problem. If you create the lock object within the frida thread, it may be garbage collected after the call to Il2Cpp.perform ends (because the frida thread gets detached from il2cpp), so, in theory, you could either:

pin the lock:

const lock = Il2Cpp.Image.corlib.class("System.Object").new();
lock.ref(true);

create the lock within the main thread:

Il2Cpp.perform(async () => { // <-- notice the async
    const lock = await Il2Cpp.attachedThreads[0].schedule(() => Il2Cpp.Image.corlib.class("System.Object").new());

    // ...
});
qingpengchen2011 commented 2 years ago

Thanks for the solution. I'll try it out.

qingpengchen2011 commented 2 years ago

Sorry. I haven't succeeded to create an appropriate environment to determine whether the solution is working. It's hard to simulate.

vfsfitvnm commented 2 years ago

This is sufficient:

Il2Cpp.perform(() => {
    const lock = Il2Cpp.Image.corlib.class("System.Object").new();
    lock.ref(true);

    const SystemBooelan = Il2Cpp.Image.corlib.class("System.Boolean");

    const str = Il2Cpp.String.from("true");

    let c = 0;

    const promise = Il2Cpp.scheduleOnInitializerThread(() => {
        for (let i = 0; i < 500; i++) {
            // lock.enter();
            c += +SystemBooelan.method<boolean>("Parse").invoke(str);
            console.log(`il2cpp[${i}] = ${c}`); 
            // lock.exit();
        }
    });

    for (let i = 0; i < 500; i++) {
        // lock.enter();
        c += +SystemBooelan.method<boolean>("Parse").invoke(str);
        console.log(`frida[${i}] = ${c}`); 
        // lock.exit();
    };

    promise.then(() => {
        console.log(`c = ${c}`);
    });
});

Uncomment the commented lines to make it print the correct value