Skip to content

Conversation

@hoo-dles
Copy link

@hoo-dles hoo-dles commented Jan 10, 2026

This is an attempt at a completion of #378 to resolve the issues mentioned by @oleavr.

As stated in the comments of the other PR, I'm not sure if this is even a valid approach. I initially was trying to call Class.ForName() with the explicit initialize bool, but I think it triggered a deadlock somewhere. Switching to the lighter instance method getName() doesn't seem to have this issue.

I'm able to build, run, and interact with frida-server on Android 16, but I'm 99% sure there's something wrong with this PR.

@hoo-dles
Copy link
Author

Got an error on app spawn with script:

Error: Unable to find copied methods in java/lang/Thread; please file a bug

@oleavr
Copy link
Member

oleavr commented Jan 10, 2026

Thank you for doing this! 🎉

Got an error on app spawn with script:

Error: Unable to find copied methods in java/lang/Thread; please file a bug

This is likely caused by frida-tools' bundled frida-java-bridge not having the changes needed.

With your changes, are you also seeing this crash when one of the system_server agent hooks gets hit? (One of the two in installLaunchTimeoutRemovalInstrumentation().)

#00 pc 000000000022e510  /apex/com.android.art/lib64/libart.so (art::StackVisitor::GetDexPc(bool) const+164) (BuildId: 6cac8d43981d3cdaec56bfd359a7c85c)
#01 pc 0000000000601fa0  /apex/com.android.art/lib64/libart.so (art::FetchStackTraceVisitor::VisitFrame()+272) (BuildId: 6cac8d43981d3cdaec56bfd359a7c85c)
#02 pc 00000000003538c4  /apex/com.android.art/lib64/libart.so (void art::StackVisitor::WalkStack<(art::StackVisitor::CountTransitions)0>(bool)+1316) (BuildId: 6cac8d43981d3cdaec56bfd359a7c85c)
#03 pc 00000000002eaa6c  /apex/com.android.art/lib64/libart.so (art::Thread::CreateInternalStackTrace(art::ScopedObjectAccessAlreadyRunnable const&) const+456) (BuildId: 6cac8d43981d3cdaec56bfd359a7c85c)
#04 pc 00000000005d23f8  /apex/com.android.art/lib64/libart.so (art::Throwable_nativeFillInStackTrace(_JNIEnv*, _jclass*) (.__uniq.282764230813858432628848516352795405182)+60) (BuildId: 6cac8d43981d3cdaec56bfd359a7c85c)
#05 pc 00000000002e5100  /apex/com.android.art/lib64/libart.so (art_quick_generic_jni_trampoline+144) (BuildId: 6cac8d43981d3cdaec56bfd359a7c85c)
#06 pc 00000000002ce060  /apex/com.android.art/lib64/libart.so (art_quick_invoke_static_stub+640) (BuildId: 6cac8d43981d3cdaec56bfd359a7c85c)

lib/android.js Outdated
Comment on lines 589 to 595
// Ensure class is loaded by prematurely calling Class::getName()
const jniClassName = className.replace(/\./g, '/');
const clazz = env.findClass(jniClassName);
const javaLangClass = env.findClass("java/lang/Class");
const getNameId = env.getMethodId(javaLangClass, "getName", "()Ljava/lang/String;");

env.callObjectMethodA(clazz, getNameId, ptr(0));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// Ensure class is loaded by prematurely calling Class::getName()
const jniClassName = className.replace(/\./g, '/');
const clazz = env.findClass(jniClassName);
const javaLangClass = env.findClass("java/lang/Class");
const getNameId = env.getMethodId(javaLangClass, "getName", "()Ljava/lang/String;");
env.callObjectMethodA(clazz, getNameId, ptr(0));
env.getClassName(classRef);

Should have the same effect, right?

Copy link
Author

@hoo-dles hoo-dles Jan 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yup, looks like it. I didn't even see that helper. I was wondering where all the JNI functions for method calls were 😅

@oleavr
Copy link
Member

oleavr commented Jan 10, 2026

By the way, just pushed the missing piece to get hooking working on my device, in 4a4970b.

@hoo-dles
Copy link
Author

hoo-dles commented Jan 10, 2026

Thank you for doing this! 🎉

Got an error on app spawn with script:
Error: Unable to find copied methods in java/lang/Thread; please file a bug

This is likely caused by frida-tools' bundled frida-java-bridge not having the changes needed.

With your changes, are you also seeing this crash when one of the system_server agent hooks gets hit? (One of the two in installLaunchTimeoutRemovalInstrumentation().)

#00 pc 000000000022e510  /apex/com.android.art/lib64/libart.so (art::StackVisitor::GetDexPc(bool) const+164) (BuildId: 6cac8d43981d3cdaec56bfd359a7c85c)
#01 pc 0000000000601fa0  /apex/com.android.art/lib64/libart.so (art::FetchStackTraceVisitor::VisitFrame()+272) (BuildId: 6cac8d43981d3cdaec56bfd359a7c85c)
#02 pc 00000000003538c4  /apex/com.android.art/lib64/libart.so (void art::StackVisitor::WalkStack<(art::StackVisitor::CountTransitions)0>(bool)+1316) (BuildId: 6cac8d43981d3cdaec56bfd359a7c85c)
#03 pc 00000000002eaa6c  /apex/com.android.art/lib64/libart.so (art::Thread::CreateInternalStackTrace(art::ScopedObjectAccessAlreadyRunnable const&) const+456) (BuildId: 6cac8d43981d3cdaec56bfd359a7c85c)
#04 pc 00000000005d23f8  /apex/com.android.art/lib64/libart.so (art::Throwable_nativeFillInStackTrace(_JNIEnv*, _jclass*) (.__uniq.282764230813858432628848516352795405182)+60) (BuildId: 6cac8d43981d3cdaec56bfd359a7c85c)
#05 pc 00000000002e5100  /apex/com.android.art/lib64/libart.so (art_quick_generic_jni_trampoline+144) (BuildId: 6cac8d43981d3cdaec56bfd359a7c85c)
#06 pc 00000000002ce060  /apex/com.android.art/lib64/libart.so (art_quick_invoke_static_stub+640) (BuildId: 6cac8d43981d3cdaec56bfd359a7c85c)

100% this was the problem, which I realized while I was in bed... 😅. Anyway, I'm not getting that crash, but now I'm getting this on app spawn with a frida script that actually does things:

Error: java.lang.NoClassDefFoundError: Class not found using the boot class loader; no stack trace available
    at <anonymous> (/frida/bridges/java.js:1)
    at <anonymous> (/frida/bridges/java.js:1)
    at apply (native)
    at <anonymous> (/frida/bridges/java.js:1)
    at ensureClassInitialized (/frida/bridges/java.js:1)
    at _make (/frida/bridges/java.js:8)
    at use (/frida/bridges/java.js:8)
    at use (/frida/bridges/java.js:8)

which makes me think my "fix" didn't actually fix things. My print debugging says that it gets through a handful of common Java classes, but fails when it hits a class specific to the APK I'm spawning (called from Java.use).

Edit: ignore the previous log, everything seems to work fine when swapping out env.callObjectMethodA with env.getClassName ??? I'm not sure why

@ExternalAddress4401
Copy link

ExternalAddress4401 commented Jan 10, 2026

I'm doing some tests with this too. This PR gets my gadget running again and hooking methods correctly printing results that look correct so far.

Edit: I've distributed it to the masses for further testing. So far no complaints.

@oleavr
Copy link
Member

oleavr commented Jan 10, 2026

Edit: ignore the previous log, everything seems to work fine when swapping out env.callObjectMethodA with env.getClassName ??? I'm not sure why

It's because env.findClass() may not find all classes when there are multiple class-loaders involved. But since you already have the jclass, there's no point in looking it up again, so this function should get the class handle instead of the name (like before).

@oleavr
Copy link
Member

oleavr commented Jan 11, 2026

Good news by the way: I've just removed the system_server agent from frida-core, so frida-java-bridge is no longer a dependency there. We now use frida-helper.dex, implemented in Java. It was previously only used on non-rooted Android, but I've split it out and added the extra functionality that we need on rooted Android.
So if you grab the latest frida-core it should make things a lot easier.

@hoo-dles
Copy link
Author

hoo-dles commented Jan 11, 2026

Good news by the way: I've just removed the system_server agent from frida-core, so frida-java-bridge is no longer a dependency there. We now use frida-helper.dex, implemented in Java. It was previously only used on non-rooted Android, but I've split it out and added the extra functionality that we need on rooted Android. So if you grab the latest frida-core it should make things a lot easier.

I pulled from main, merged, and rebuilt the server for aarch64 and tools for x86-64, but I'm getting unable to spawn Android helper. Am I doing something dumb?

edit: the helper process is definitely spawned

root         28209 15842   10934108  54460 do_sys_poll         0 S frida-server
root         28214 28209   15892740 156264 do_epoll_wait       0 S re.frida.helper

edit 2: working now? no idea, not going to question it at the moment

@oleavr
Copy link
Member

oleavr commented Jan 11, 2026

@hoo-dles Oops! I've pushed some improvements that should make it clear exactly why in case it fails on you again.

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

Successfully merging this pull request may close these issues.

3 participants