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

[Android] Method Instrumentation Causes StackOverflow and App Crash #303

Open
Vishalsng112 opened this issue Nov 12, 2023 · 2 comments
Open

Comments

@Vishalsng112
Copy link

System Information:

Operating System: Linux, Ubuntu 22.04
Device: Android Studio Emulator
Android Version: 10

App Information:

App Name: Clock
App Link: https://f-droid.org/en/packages/com.chen.deskclock/
App Version: 1.2.2

Issue Description:
I am trying to instrument the Clock app to log function entry and exit messages. However, I've encountered an issue where the app crashes due to stack overflow, particularly when trying to perform actions on an enabled alarm. Below is function of instrumentation. This behavior is found in some other apps too. If someone already knows the solution to this issue, please help me out.

Note: I think overloads. implementation is not able to resolve overloaded functions

function tracefunction(func) {
    //  Input example: com.chen.deskclock.data.WidgetModel.updateWidgetCount
    //  extract function name and class name
    var javaFunc = func.split(".")[func.split(".").length - 1];
    var javaClass = func.replace("." + javaFunc, "");
    try {
        var hook = Java.use(javaClass);
    }
    catch (e) {
        console.log("trace class failed");
        return;
    }

    if (typeof hook[javaFunc] != "undefined") {
        //  get method overload count of the method
        var overloadCount = hook[javaFunc].overloads.length;
        for (var i=0; i<overloadCount; i++) {
            hook[javaFunc].overloads[i].implementation = function () {
            var retval;
            console.log("\n*** entered " + func);
            retval = this[javaFunc].apply(this, arguments); // sometimes causes recursive call infinitly and causes app to crash.
            console.log("\n*** exiting " + func);
            return retval;
            }
        }
    }
}

The link to download the Frida-script and apk is here

Steps to Reproduce:

Instrument the app using Frida (latest version 16.1.4).
Create an alarm within the app.
Attempt to perform any action on the alarm, such as enabling or disabling it.

Expected Behavior:
The app should allow instrumentation to log function entry and exit messages without crashing.

Actual Behavior:
When instrumented, some functions within the app are causing a stack overflow, leading to an app crash. This issue does not occur without instrumentation.

I appreciate any guidance or solutions to address this issue, as I aim to instrument the Clock app without causing it to crash.

@Vishalsng112
Copy link
Author

Vishalsng112 commented Nov 14, 2023

A particular issue has been identified in the overload function within class-factory.js. Specifically, when multiple functions share the same signature and the argument type matches, the code currently returns the first match. This alteration in the program's execution order has been discovered during testing on 30 applications. Notably, 22 of these applications are experiencing crashes as a result of this bug.

How to deal with this problem?

    value (...args) {
      const overloads = this._o;

      const numArgs = args.length;
      const signature = args.join(':');

      for (let i = 0; i !== overloads.length; i++) {
        const method = overloads[i];
        const { argumentTypes } = method;

        if (argumentTypes.length !== numArgs) {
          continue;
        }

        const s = argumentTypes.map(t => t.className).join(':');
        if (s === signature) {
          return method;
        }
      }

      throwOverloadError(this.methodName, this.overloads, 'specified argument types do not match any of:');
    }
  }

@oleavr
Copy link
Member

oleavr commented Nov 14, 2023

This is a user error, not a bug. You are using .overload() when replacing the method, but inside your replacement, you are not doing this when calling the original.

You should call .overload() and assign the returned value to a variable. Then you should use this variable both when assigning to .implementation, and when calling it inside the replacement.

For example:

const method = SomeClass.someMethod.overload(…);
method.implementation = function (...args) {
  return method.call(this, ...args);
};

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