frida / frida-java-bridge

Java runtime interop from Frida
318 stars 118 forks source link

global references used in enumerateLoadedClassesArt #312

Open thushw opened 3 months ago

thushw commented 3 months ago

Thanks so much for this helpful toolset, love what you all do ❤️

I was having some trouble running out of global reference memory table on my android and I'm fairly certain it is to do with the global references being created here ->

https://github.com/frida/frida-java-bridge/blob/f22a5f2f8207f8cc0a5b4d65b59b138fd00340fa/index.js#L167

This is the message I get from frida Abort message: 'JNI ERROR (app bug): global reference table overflow (max=51200)

It happens upon the invocation of Java.enumerateLoadedClassesSync() and running down the execution, it is likely here. I can see that the references are being re-claimed in the method, but since the memory in the Android is limited, it crashes before reaching https://github.com/frida/frida-java-bridge/blob/f22a5f2f8207f8cc0a5b4d65b59b138fd00340fa/index.js#L189

Is there a way I can increase the memory used for global refs on the android, or is there some work-around?

thushw commented 3 months ago

I might be able to help with a potential fix - pl let me know if that is ok. I think, rather than holding on to the class, we can hold on to the name, since that is all we need here :

function enumerateLoadedClassesArt (callbacks) {
    const env = vm.getEnv();

    const classNames = [];
    const addGlobalReference = api['art::JavaVMExt::AddGlobalRef'];
    const vmHandle = api.vm;
    withRunnableArtThread(vm, env, thread => {
      const collectClassNames = makeArtClassVisitor(klass => {
        classHandle = addGlobalReference(vmHandle, thread, klass);
        const className = env.getClassName(classHandle);
        env.deleteGlobalRef(classHandle);
        classNames.push(className);
        return true;
      });

      api['art::ClassLinker::VisitClasses'](api.artClassLinker, collectClassNames);
    });

    try {
      classNames.forEach(className => {
        callbacks.onMatch(className);
      });
    } finally {
    }

    callbacks.onComplete();
  }