how to fix Error: java.lang.ClassNotFoundException on frida

I'm trying to bypass a root detection mechanism on an android app using Frida, I've tried so many different scripts (frida code share) and different approaches (like hiding root) with no luck!

So I tried to locate the class and method responsible for checking if the device is rooted or not and changing it's return value.

This is my script :

setTimeout(function() { // avoid java.lang.ClassNotFoundException
  Java.perform(function() {
    var hook = Java.use("app.name.RootUtils");
    console.log("info: hooking target class");

    hook.isRooted.overload().implementation = function() {
      console.log("info: entered target method");
      return Java.use("java.lang.Boolean").$new(false);
    }
  });
},0);

If I inject this code normally it won't work because it looks like the isRooted method will get called before it

If I use spawn to run the app and change this method return value it fails with error :

frida.core.RPCException: Error: java.lang.ClassNotFoundException: Didn't find class ...

I've also tried spawning the app and then using objection to run "android root disable" but it will return this error :

frida.core.RPCException: TypeError: cannot read property 'getApplicationContext' of null at getApplicationContext (src/android/lib/libjava.ts:21)

I'm not sure if this is a problem with Frida or my system or ...

I think if I was able to make my main code runs at exactly after the class gets loaded (like using a loop to check or using a hook) the problem would be fixed but I don't know how to write that kind of code in js for frida.

I'm on macOS 11.5.1 using python 3.9 and installed latest version of frida and objection

I've tested on one rooted phone with android 10 and an emulator with android 6


Solution 1:

Class not found

How do you know the class is app.name.RootUtils have you decompiled to app using Jadx or apktool? How about the method where RootUtils.isRooted() is called? Is there any special code that loads the RootUtils class e.g. from a non-standard dex file included in the app? If the class is loaded from a special dex file you could hook this dex loading mechanism and first execute it and then install your hook for RootUtils.isRooted().

Alternatively assuming RootUtils.isRooted() is called only from one other method and does not use special code for loading the RootUtils class you could hook that method and use the this hook to install install your RootUtils.isRooted() hook.

Error handling

The correct way to handle errors in JavaScript is using try catch block, not the setTimeout function:

Java.perform(() => {
    try {
        var hook = Java.use("app.name.RootUtils");
        ...
    } catch (e) {
        console.log("Failed to hook root detection" + e);
    }
}

Regarding your problems hooking the class

Solution 2:

I was able to solve this issue with a simple yet not very technical solution.

I used a setInteval to run my hooking over and over until it gets to work, (as @Robert mentioned, I also needed to wrap hooking inside a try catch to prevent the code from stoping after first try)

This may not work for everyone but since it worked for me I will post the final code, may it helps someone else in the future :)

Java.perform(function() {
  var it = setInterval(function(){
    try{
      var hook = Java.use("app.name.RootUtils");
      console.log("info: hooking target class");

      hook.isRooted.overload().implementation = function() {
        console.log("info: entered target method");
        clearInterval(it);
        return Java.use("java.lang.Boolean").$new(false);
      }
    } catch(e) {
      console.log("failed!");
    }
  },200); // runs every 200milisecods
});

PS : you may need to change interval time to match your app needs, it worked for me with 200 miliseconds.