diff --git a/core/src/main/java/org/lsposed/lspd/impl/LSPosedContext.java b/core/src/main/java/org/lsposed/lspd/impl/LSPosedContext.java index 9551bbac7..a4f64d142 100644 --- a/core/src/main/java/org/lsposed/lspd/impl/LSPosedContext.java +++ b/core/src/main/java/org/lsposed/lspd/impl/LSPosedContext.java @@ -189,6 +189,27 @@ public MethodUnhooker> hook(@NonNull Constructor origin, i return LSPosedBridge.doHook(origin, priority, hooker); } + @Override + @NonNull + public MethodUnhooker> hookClassInitializer(@NonNull Class origin, @NonNull Class hooker) { + return hookClassInitializer(origin, PRIORITY_DEFAULT, hooker); + } + + @Override + @NonNull + @SuppressWarnings({"unchecked", "rawtypes"}) + public MethodUnhooker> hookClassInitializer(@NonNull Class origin, int priority, @NonNull Class hooker) { + Method staticInitializer = HookBridge.getStaticInitializer(origin); + + // The class might not have a static initializer block + if (staticInitializer == null) { + throw new IllegalArgumentException("Class " + origin.getName() + " has no static initializer"); + } + + // Use the existing doHook logic. It will return a MethodUnhooker. + return (MethodUnhooker) LSPosedBridge.doHook(staticInitializer, priority, hooker); + } + private static boolean doDeoptimize(@NonNull Executable method) { if (Modifier.isAbstract(method.getModifiers())) { throw new IllegalArgumentException("Cannot deoptimize abstract methods: " + method); diff --git a/core/src/main/java/org/lsposed/lspd/nativebridge/HookBridge.java b/core/src/main/java/org/lsposed/lspd/nativebridge/HookBridge.java index e07caa0ee..1c1e8da87 100644 --- a/core/src/main/java/org/lsposed/lspd/nativebridge/HookBridge.java +++ b/core/src/main/java/org/lsposed/lspd/nativebridge/HookBridge.java @@ -1,6 +1,7 @@ package org.lsposed.lspd.nativebridge; import java.lang.reflect.Executable; +import java.lang.reflect.Method; import java.lang.reflect.InvocationTargetException; import dalvik.annotation.optimization.FastNative; @@ -25,4 +26,12 @@ public class HookBridge { public static native boolean setTrusted(Object cookie); public static native Object[][] callbackSnapshot(Class hooker_callback, Executable method); + + /** + * Retrieves the static initializer () of a class as a Method object. + * Standard Java reflection cannot access this. + * @param clazz The class to inspect. + * @return A Method object for the static initializer, or null if it doesn't exist. + */ + public static native Method getStaticInitializer(Class clazz); } diff --git a/core/src/main/jni/src/jni/hook_bridge.cpp b/core/src/main/jni/src/jni/hook_bridge.cpp index 104ed2840..1d78f3c1d 100644 --- a/core/src/main/jni/src/jni/hook_bridge.cpp +++ b/core/src/main/jni/src/jni/hook_bridge.cpp @@ -322,6 +322,21 @@ LSP_DEF_NATIVE_METHOD(jobjectArray, HookBridge, callbackSnapshot, jclass callbac return res; } +LSP_DEF_NATIVE_METHOD(jobject, HookBridge, getStaticInitializer, jclass target_class) { + // is the internal name for a static initializer. + // Its signature is always ()V (no arguments, void return). + jmethodID mid = env->GetStaticMethodID(target_class, "", "()V"); + if (!mid) { + // If GetStaticMethodID fails, it throws an exception. + // We clear it and return null to let the Java side handle it gracefully. + env->ExceptionClear(); + return nullptr; + } + // Convert the method ID to a java.lang.reflect.Method object. + // The last parameter must be JNI_TRUE because it's a static method. + return env->ToReflectedMethod(target_class, mid, JNI_TRUE); +} + static JNINativeMethod gMethods[] = { LSP_NATIVE_METHOD(HookBridge, hookMethod, "(ZLjava/lang/reflect/Executable;Ljava/lang/Class;ILjava/lang/Object;)Z"), LSP_NATIVE_METHOD(HookBridge, unhookMethod, "(ZLjava/lang/reflect/Executable;Ljava/lang/Object;)Z"), @@ -332,6 +347,7 @@ static JNINativeMethod gMethods[] = { LSP_NATIVE_METHOD(HookBridge, instanceOf, "(Ljava/lang/Object;Ljava/lang/Class;)Z"), LSP_NATIVE_METHOD(HookBridge, setTrusted, "(Ljava/lang/Object;)Z"), LSP_NATIVE_METHOD(HookBridge, callbackSnapshot, "(Ljava/lang/Class;Ljava/lang/reflect/Executable;)[[Ljava/lang/Object;"), + LSP_NATIVE_METHOD(HookBridge, getStaticInitializer, "(Ljava/lang/Class;)Ljava/lang/reflect/Method;"), }; void RegisterHookBridge(JNIEnv *env) { diff --git a/xposed/libxposed b/xposed/libxposed index 64e29bd65..b896dbcda 160000 --- a/xposed/libxposed +++ b/xposed/libxposed @@ -1 +1 @@ -Subproject commit 64e29bd657ef4d2540b34402f5a988778f29e676 +Subproject commit b896dbcda3fa1550d04d43d962923318ed5a61a8