Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Tracing an assembly seems to override all custom implementation of Il2cpp methods of said assembly #585

Open
UnknownAPI opened this issue Jan 8, 2025 · 2 comments

Comments

@UnknownAPI
Copy link

UnknownAPI commented Jan 8, 2025

const ExampleAssembly = Il2Cpp.domain.assembly("ExampleAssembly").image;
const ExampleClass = ExampleAssembly.class("Example.Class")
const Invoke = ExampleClass.method("Invoke")
Invoke.implementation = function (...parameters: Il2Cpp.Parameter.Type[]): boolean {
    return true
}  
Il2Cpp.trace().assemblies(ExampleAssembly).and().attach()

this would result in the original implementation of Invoke being called in the execution flow

@UnknownAPI
Copy link
Author

after some investigation the faulty code seems to be

function trace(parameters = false) {
        const applier = () => (method, state, threadId) => {
            const paddedVirtualAddress = method.relativeVirtualAddress.toString(16).padStart(8, "0");
            Interceptor.attach(method.virtualAddress, {
                onEnter() {

                        state.buffer.push(`\x1b[2m0x${paddedVirtualAddress}\x1b[0m THREAD[${this.threadId}] ${`│ `.repeat(state.depth++)}┌─\x1b[35m${method.class.type.name}::\x1b[1m${method.name}\x1b[0m\x1b[0m`);
                    
                },
                onLeave() {
                        // prettier-ignore
                        state.buffer.push(`\x1b[2m0x${paddedVirtualAddress}\x1b[0m THREAD[${this.threadId}] ${`│ `.repeat(--state.depth)}└─\x1b[33m${method.class.type.name}::\x1b[1m${method.name}\x1b[0m\x1b[0m`);
                        state.flush();
                    
                }
            });
        };
        const applierWithParameters = () => (method, state, threadId) => {
            const paddedVirtualAddress = method.relativeVirtualAddress.toString(16).padStart(8, "0");
            const startIndex = +!method.isStatic | +Il2Cpp.unityVersionIsBelow201830;
            const callback = function (...args) {

                    const thisParameter = method.isStatic ? undefined : new Il2Cpp.Parameter("this", -1, method.class.type);
                    const parameters = thisParameter ? [thisParameter].concat(method.parameters) : method.parameters;
                    // prettier-ignore
                    state.buffer.push(`\x1b[2m0x${paddedVirtualAddress}\x1b[0m THREAD[${this.threadId}] ${`│ `.repeat(state.depth++)}┌─\x1b[35m${method.class.type.name}::\x1b[1m${method.name}\x1b[0m\x1b[0m(${parameters.map(e => `\x1b[32m${e.name}\x1b[0m = \x1b[31m${Il2Cpp.fromFridaValue(args[e.position + startIndex], e.type)}\x1b[0m`).join(", ")})`);
                
                const returnValue = method.nativeFunction(...args);
                    // prettier-ignore
                    state.buffer.push(`\x1b[2m0x${paddedVirtualAddress}\x1b[0m THREAD[${this.threadId}] ${`│ `.repeat(--state.depth)}└─\x1b[33m${method.class.type.name}::\x1b[1m${method.name}\x1b[0m\x1b[0m${returnValue == undefined ? "" : ` = \x1b[36m${Il2Cpp.fromFridaValue(returnValue, method.returnType)}`}\x1b[0m`);
                    state.flush();
                
                return returnValue;
            };
            method.revert(); // <------ Reverts the original method implementation
            const nativeCallback = new NativeCallback(callback, method.returnType.fridaAlias, method.fridaSignature);
            Interceptor.replace(method.virtualAddress, nativeCallback);
        };
        return new Il2Cpp.Tracer(parameters ? applierWithParameters() : applier());
    }

Is this behaviour expected ? If not can the modified method behaviour be preserved in the tracing process

@vfsfitvnm
Copy link
Owner

Yes, it is expected. There is no way to have two implementations at the same time. Tracing with parameters requires Interceptor::replace to be used instead of Interceptor.attach (this is a Frida limitation)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants