asLody/AndHook

[help wanted] Hooking ClassLoader

Miha-x64 opened this issue · 4 comments

Hello. Thanks for your work!
I'm trying to instrument currently running ClassLoader to profile class loading time, but seeing very small number of loaded classes in logs. Looks like my code gets called only for reflectively loaded classes. What am I doing wrong?

final class ClassLoaderHooks {

    private static final String TAG = "ClassLoaderHooks";

    static void install() {
        try {
            AndHook.ensureNativeLibraryLoaded(null);
            XposedHelpers.findAndHookMethod(
                    ClassLoader.class, "loadClass", String.class, boolean.class,
              // or BaseDexClassLoader.class, "findClass", String.class,
                    new Hooks()
            );
        } catch (Throwable t) {
            throw new RuntimeException(t);
        }
    }

    private static final class Hooks extends XC_MethodHook {

        private final Map<String, Boolean> loadedClasses = new ConcurrentHashMap<>();
        private final ThreadLocal<Stack<Long>> time = new ThreadLocal<>();

        @Override
        protected void beforeHookedMethod(MethodHookParam param) {
            Stack<Long> stack = time.get();
            if (stack == null) {
                time.set(stack = new Stack<>());
            }
            stack.push(System.nanoTime());
        }

        @Override
        protected void afterHookedMethod(MethodHookParam param) {
            long start = time.get().pop();
            long diff = System.nanoTime() - start;
            String className = (String) param.args[0];
            if (loadedClasses.put(className, Boolean.TRUE) != null) {
                return; // already loaded
            }
            int diffUs = (int) (diff / 1000);
            Log.e(TAG, "spent " + (diffUs / 1000.0) + "ms loading type " + className);
        }

    }

}

Thank you.

Rprop commented

Note that ClassLoader.loadClass is not always necessary to load a class, you can try intercepting DexFile_defineClassNative or ClassLinker->DefineClass.

Thank you.
I've found defineClassNative in C++ source code, it is exposed to JNI, but there's no corresponding Java native method.

Rprop commented

Please consider dalvik/system/DexFile.defineClassNative

FYI, for ones who found this using search.

Found this method using reflection: private static native java.lang.Class dalvik.system.DexFile.defineClassNative(java.lang.String,java.lang.ClassLoader,java.lang.Object,dalvik.system.DexFile) throws java.lang.ClassNotFoundException,java.lang.NoClassDefFoundError.

Hooks are still getting called rarely.