Closed Chensem closed 1 year ago
Hi!
if (Il2Cpp.Api._getCorlib().isNull()) {
await new Promise<void>(resolve => {
const interceptor = Interceptor.attach(Il2Cpp.Api._init, {
onLeave() {
interceptor.detach();
setImmediate(resolve);
}
});
});
}
This snippet waits for Il2Cpp to be initialized. When libil2cpp.so
(or whatever) is loaded into memory and its library constructors are invoked, we still need to wait for the call to il2cpp_init
to finish.
int il2cpp_init(const char* domain_name)
{
// Use environment's default locale
setlocale(LC_ALL, "");
return Runtime::Init(domain_name);
}
Runtime::Init
initializes the Il2Cpp world (metadata, types and other things). If we try to invoke a il2cpp_*
function before the initialization process finishes, we'll mostly run into problems or errors.
Il2Cpp.Api._getCorlib().isNull()
is a workaround to check whether the call to il2cpp_init
is already finished. If it's not, we hook il2cpp_init
and wait. When the invocation finishes, we are here:
onLeave() {
interceptor.detach();
setImmediate(resolve);
}
We detach the interceptor and call resolve
so the await
for the Promise
ends. We must use setImmediate
, otherwise our code will keep executing in the same thread who called il2cpp_init
(we don't want that to happen).
let thread = this.currentThread;
const isForeignThread = thread == null;
if (thread == null) {
thread = Il2Cpp.Domain.attach();
}
try {
const result = block();
return result instanceof Promise ? await result : result;
} catch (e: any) {
(globalThis as any).console.log(e);
throw e;
} finally {
if (isForeignThread) {
thread.detach();
}
}
This snippet makes sure block
is invoked in a Il2Cpp thread.
this.currentThread
(which calls il2cpp_thread_current
) returns a null pointer if the caller thread is not attached to Il2Cpp (= it's not a Il2Cpp thread). So, if the caller thread isn't attached to Il2Cpp, isForeignThread
is true.
When isForeignThread
is true, we are responsible to attach the caller thread to Il2Cpp (Il2Cpp.Domain.attach()
) and to detach it later (thread.detach()
). This ensures block
is executed in a thread attached to Il2Cpp
.
oh , thank you so much , i understand the code via debug the snippet and another question
static attach() {
return new Il2Cpp.Thread(Il2Cpp.Api._threadAttach(this));
}
why here _threadAttach
function can pass an object ? _threadAttach
function is NativeFunction and the argument shoule be nativePointer ? can replace by this.handle
the NativeFunction detect the argument internal ? if the argument is an object , it will pick up the object's handle ?
oh , thank you so much , i understand the code via debug the snippet and another question
static attach() { return new Il2Cpp.Thread(Il2Cpp.Api._threadAttach(this)); }
why here
_threadAttach
function can pass an object ?_threadAttach
function is NativeFunction and the argument shoule be nativePointer ? can replace bythis.handle
the NativeFunction internal detect the argument ? if the argument is an object , it will pick up the object's handle ?
I see get object()
method
You can pass a NativePointerValue
, which is a NativePointer
or ObjectWrapper
.
https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/frida-gum/index.d.ts#L1624
https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/frida-gum/index.d.ts#L1597
I want to know some deep theory about il2cpp-bridge
https://github.com/vfsfitvnm/frida-il2cpp-bridge/blob/e99fb8a2d4812a52e40e6cf2f8ceb5a6b4db6e14/src/il2cpp/base.ts#L204
especially this line , the line run on il2cpp thread ? if this line run on il2cpp thread , i can under stand to code below this line , if not , i can't understand
wish to get your reply