frida / frida-java-bridge

Java runtime interop from Frida
325 stars 123 forks source link

Crash when hooking a class obtained from a class factory created via Java.ClassFactory.get(loader) #227

Open fvrmatteo opened 3 years ago

fvrmatteo commented 3 years ago

The following details refer to a hooking attempt executed using the early instrumentation.

If the following code is used to intercept the creation of a new BaseDexClassLoader and hook the attachBaseContext method of a class available in the new class loader namespace, Frida hits a crash when the hook is triggered because of an invalid JNI jobject:

if (Java.available) {
  Java.performNow(function() {
    var dalvik_system_BaseDexClassLoader = Java.use('dalvik.system.BaseDexClassLoader');
    dalvik_system_BaseDexClassLoader.$init.overload('java.lang.String', 'java.lang.String', 'java.lang.ClassLoader', '[Ljava.lang.ClassLoader;', 'boolean').implementation = function(dexPath, librarySearchPath, parent, sharedLibraryLoaders, isTrusted) {
      console.log('BaseDexClassLoader: ' + dexPath);
      this.$init(dexPath, librarySearchPath, parent, sharedLibraryLoaders, isTrusted);
      try {
        classFactory = Java.ClassFactory.get(this);
        var classReference = classFactory.use('class.present.in.new.class.loader');
        var methodReference = classReference.attachBaseContext.overload('android.content.Context');
        methodReference.implementation = function(Context) {
          console.log('Hooked attachBaseContext(Context)!');
          this.attachBaseContext(Context);
        }
      } catch (Exception) {
        console.log('Exception: ' + Exception);
      }
    }
  });
}

The crash log is the following: crash.log

fvrmatteo commented 3 years ago

A similar solution (which I have memory has been deemed deprecated in some other GitHub issue) works fine, so I think the same should be achievable using Java.ClassFactory.get(this).

The working snippet is:

if (Java.available) {
  Java.performNow(function() {
    var dalvik_system_BaseDexClassLoader = Java.use('dalvik.system.BaseDexClassLoader');
    dalvik_system_BaseDexClassLoader.$init.overload('java.lang.String', 'java.lang.String', 'java.lang.ClassLoader', '[Ljava.lang.ClassLoader;', 'boolean').implementation = function(dexPath, librarySearchPath, parent, sharedLibraryLoaders, isTrusted) {
      console.log('BaseDexClassLoader: ' + dexPath);
      this.$init(dexPath, librarySearchPath, parent, sharedLibraryLoaders, isTrusted);
      // Save the old class loader reference
      var oldLoader = Java.classFactory.loader;
      try {
        Java.classFactory.loader = this;
        var classReference = Java.use('class.present.in.new.class.loader');
        var methodReference = classReference.attachBaseContext.overload('android.content.Context');
        methodReference.implementation = function(Context) {
          console.log('Hooked attachBaseContext(Context)!');
          this.attachBaseContext(Context);
        }
      } catch (Exception) {
        console.log('Exception: ' + Exception);
      }
      // Restore the old class loader reference
      Java.classFactory.loader = oldLoader;
    }
  });
}