diff --git a/.github/workflows/core.yml b/.github/workflows/core.yml index 0077b0319..6a23ad902 100644 --- a/.github/workflows/core.yml +++ b/.github/workflows/core.yml @@ -45,7 +45,6 @@ jobs: with: repository: libxposed/api path: libxposed/api - ref: 54582730315ba4a3d7cfaf9baf9d23c419e07006 - name: Checkout libxposed/service uses: actions/checkout@v4 diff --git a/core/proguard-rules.pro b/core/proguard-rules.pro index 4638bb630..332be3a63 100644 --- a/core/proguard-rules.pro +++ b/core/proguard-rules.pro @@ -1,6 +1,7 @@ -keep class android.** { *; } -keep class de.robv.android.xposed.** {*;} -keep class io.github.libxposed.** {*;} +-keep class org.lsposed.lspd.annotation.* {*;} -keep class org.lsposed.lspd.core.* {*;} -keep class org.lsposed.lspd.hooker.HandleSystemServerProcessHooker {*;} -keep class org.lsposed.lspd.hooker.HandleSystemServerProcessHooker$Callback {*;} @@ -22,9 +23,13 @@ -keepclassmembers class org.lsposed.lspd.impl.LSPosedHookCallback { public ; } +-keepclassmembers,allowoptimization class ** implements io.github.libxposed.api.XposedInterface$Hooker { + public *** before(***); + public *** after(***); +} -keep,allowoptimization,allowobfuscation @io.github.libxposed.api.annotations.* class * { - @io.github.libxposed.api.annotations.BeforeInvocation ; - @io.github.libxposed.api.annotations.AfterInvocation ; + public *** before(***); + public *** after(***); } -assumenosideeffects class android.util.Log { public static *** v(...); diff --git a/core/src/main/java/de/robv/android/xposed/callbacks/XC_InitPackageResources.java b/core/src/main/java/de/robv/android/xposed/callbacks/XC_InitPackageResources.java index 5c39ec968..dd8e42d72 100644 --- a/core/src/main/java/de/robv/android/xposed/callbacks/XC_InitPackageResources.java +++ b/core/src/main/java/de/robv/android/xposed/callbacks/XC_InitPackageResources.java @@ -21,15 +21,10 @@ package de.robv.android.xposed.callbacks; import android.content.res.XResources; -import android.os.Bundle; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; import java.util.concurrent.CopyOnWriteArraySet; import de.robv.android.xposed.IXposedHookInitPackageResources; -import io.github.libxposed.api.XposedModuleInterface; /** * This class is only used for internal purposes, except for the {@link InitPackageResourcesParam} diff --git a/core/src/main/java/de/robv/android/xposed/callbacks/XC_LoadPackage.java b/core/src/main/java/de/robv/android/xposed/callbacks/XC_LoadPackage.java index 848e3eeb3..e428d6cad 100644 --- a/core/src/main/java/de/robv/android/xposed/callbacks/XC_LoadPackage.java +++ b/core/src/main/java/de/robv/android/xposed/callbacks/XC_LoadPackage.java @@ -21,16 +21,10 @@ package de.robv.android.xposed.callbacks; import android.content.pm.ApplicationInfo; -import android.os.Bundle; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; import java.util.concurrent.CopyOnWriteArraySet; import de.robv.android.xposed.IXposedHookLoadPackage; -import de.robv.android.xposed.XposedBridge.CopyOnWriteSortedSet; -import io.github.libxposed.api.XposedModuleInterface; /** * This class is only used for internal purposes, except for the {@link LoadPackageParam} diff --git a/core/src/main/java/io/github/libxposed/api/annotations/AfterInvocation.java b/core/src/main/java/io/github/libxposed/api/annotations/AfterInvocation.java new file mode 100644 index 000000000..e26b3188b --- /dev/null +++ b/core/src/main/java/io/github/libxposed/api/annotations/AfterInvocation.java @@ -0,0 +1,11 @@ +package io.github.libxposed.api.annotations; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +public @interface AfterInvocation { +} diff --git a/core/src/main/java/io/github/libxposed/api/annotations/BeforeInvocation.java b/core/src/main/java/io/github/libxposed/api/annotations/BeforeInvocation.java new file mode 100644 index 000000000..7b4a17b8a --- /dev/null +++ b/core/src/main/java/io/github/libxposed/api/annotations/BeforeInvocation.java @@ -0,0 +1,11 @@ +package io.github.libxposed.api.annotations; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +public @interface BeforeInvocation { +} diff --git a/core/src/main/java/io/github/libxposed/api/annotations/XposedHooker.java b/core/src/main/java/io/github/libxposed/api/annotations/XposedHooker.java new file mode 100644 index 000000000..acff8c038 --- /dev/null +++ b/core/src/main/java/io/github/libxposed/api/annotations/XposedHooker.java @@ -0,0 +1,11 @@ +package io.github.libxposed.api.annotations; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.TYPE, ElementType.TYPE_USE}) +public @interface XposedHooker { +} diff --git a/core/src/main/java/org/lsposed/lspd/core/ApplicationServiceClient.java b/core/src/main/java/org/lsposed/lspd/core/ApplicationServiceClient.java index 6eb01d0b3..1184852a3 100644 --- a/core/src/main/java/org/lsposed/lspd/core/ApplicationServiceClient.java +++ b/core/src/main/java/org/lsposed/lspd/core/ApplicationServiceClient.java @@ -19,7 +19,6 @@ package org.lsposed.lspd.core; -import android.os.Bundle; import android.os.IBinder; import android.os.ParcelFileDescriptor; import android.os.RemoteException; diff --git a/core/src/main/java/org/lsposed/lspd/core/Startup.java b/core/src/main/java/org/lsposed/lspd/core/Startup.java index e4d08b96d..499c7ca2e 100644 --- a/core/src/main/java/org/lsposed/lspd/core/Startup.java +++ b/core/src/main/java/org/lsposed/lspd/core/Startup.java @@ -31,8 +31,8 @@ import org.lsposed.lspd.hooker.AttachHooker; import org.lsposed.lspd.hooker.CrashDumpHooker; import org.lsposed.lspd.hooker.HandleSystemServerProcessHooker; -import org.lsposed.lspd.hooker.LoadedApkCtorHooker; import org.lsposed.lspd.hooker.LoadedApkCreateCLHooker; +import org.lsposed.lspd.hooker.LoadedApkCtorHooker; import org.lsposed.lspd.hooker.OpenDexFileHooker; import org.lsposed.lspd.impl.LSPosedContext; import org.lsposed.lspd.impl.LSPosedHelper; diff --git a/core/src/main/java/org/lsposed/lspd/hooker/AttachHooker.java b/core/src/main/java/org/lsposed/lspd/hooker/AttachHooker.java index b003ac2f5..0579c275e 100644 --- a/core/src/main/java/org/lsposed/lspd/hooker/AttachHooker.java +++ b/core/src/main/java/org/lsposed/lspd/hooker/AttachHooker.java @@ -2,16 +2,16 @@ import android.app.ActivityThread; +import androidx.annotation.NonNull; + import de.robv.android.xposed.XposedInit; import io.github.libxposed.api.XposedInterface; -import io.github.libxposed.api.annotations.AfterInvocation; import io.github.libxposed.api.annotations.XposedHooker; @XposedHooker public class AttachHooker implements XposedInterface.Hooker { - @AfterInvocation - public static void afterHookedMethod(XposedInterface.AfterHookCallback callback) { + public static void after(@NonNull XposedInterface.AfterHookCallback callback) { XposedInit.loadModules((ActivityThread) callback.getThisObject()); } } diff --git a/core/src/main/java/org/lsposed/lspd/hooker/CrashDumpHooker.java b/core/src/main/java/org/lsposed/lspd/hooker/CrashDumpHooker.java index ea94b132c..935af66cb 100644 --- a/core/src/main/java/org/lsposed/lspd/hooker/CrashDumpHooker.java +++ b/core/src/main/java/org/lsposed/lspd/hooker/CrashDumpHooker.java @@ -1,17 +1,17 @@ package org.lsposed.lspd.hooker; +import androidx.annotation.NonNull; + import org.lsposed.lspd.impl.LSPosedBridge; import org.lsposed.lspd.util.Utils.Log; import io.github.libxposed.api.XposedInterface; -import io.github.libxposed.api.annotations.BeforeInvocation; import io.github.libxposed.api.annotations.XposedHooker; @XposedHooker public class CrashDumpHooker implements XposedInterface.Hooker { - @BeforeInvocation - public static void beforeHookedMethod(XposedInterface.BeforeHookCallback callback) { + public static void before(@NonNull XposedInterface.BeforeHookCallback callback) { try { var e = (Throwable) callback.getArgs()[0]; LSPosedBridge.log("Crash unexpectedly: " + Log.getStackTraceString(e)); diff --git a/core/src/main/java/org/lsposed/lspd/hooker/HandleSystemServerProcessHooker.java b/core/src/main/java/org/lsposed/lspd/hooker/HandleSystemServerProcessHooker.java index 4552153e3..af76acb93 100644 --- a/core/src/main/java/org/lsposed/lspd/hooker/HandleSystemServerProcessHooker.java +++ b/core/src/main/java/org/lsposed/lspd/hooker/HandleSystemServerProcessHooker.java @@ -27,7 +27,6 @@ import org.lsposed.lspd.util.Hookers; import io.github.libxposed.api.XposedInterface; -import io.github.libxposed.api.annotations.AfterInvocation; import io.github.libxposed.api.annotations.XposedHooker; // system_server initialization @@ -42,8 +41,7 @@ public interface Callback { public static volatile Callback callback = null; @SuppressLint("PrivateApi") - @AfterInvocation - public static void afterHookedMethod() { + public static void after() { Hookers.logD("ZygoteInit#handleSystemServerProcess() starts"); try { // get system_server classLoader diff --git a/core/src/main/java/org/lsposed/lspd/hooker/LoadedApkCreateCLHooker.java b/core/src/main/java/org/lsposed/lspd/hooker/LoadedApkCreateCLHooker.java index 161c730eb..ddd3cd186 100644 --- a/core/src/main/java/org/lsposed/lspd/hooker/LoadedApkCreateCLHooker.java +++ b/core/src/main/java/org/lsposed/lspd/hooker/LoadedApkCreateCLHooker.java @@ -51,7 +51,6 @@ import de.robv.android.xposed.callbacks.XC_LoadPackage; import io.github.libxposed.api.XposedInterface; import io.github.libxposed.api.XposedModuleInterface; -import io.github.libxposed.api.annotations.AfterInvocation; import io.github.libxposed.api.annotations.XposedHooker; @SuppressLint("BlockedPrivateApi") @@ -77,8 +76,7 @@ static void addLoadedApk(LoadedApk loadedApk) { loadedApks.add(loadedApk); } - @AfterInvocation - public static void afterHookedMethod(XposedInterface.AfterHookCallback callback) { + public static void after(@NonNull XposedInterface.AfterHookCallback callback) { LoadedApk loadedApk = (LoadedApk) callback.getThisObject(); if (callback.getArgs()[0] != null || !loadedApks.contains(loadedApk)) { diff --git a/core/src/main/java/org/lsposed/lspd/hooker/LoadedApkCtorHooker.java b/core/src/main/java/org/lsposed/lspd/hooker/LoadedApkCtorHooker.java index e84e3d1d6..e52fcd348 100644 --- a/core/src/main/java/org/lsposed/lspd/hooker/LoadedApkCtorHooker.java +++ b/core/src/main/java/org/lsposed/lspd/hooker/LoadedApkCtorHooker.java @@ -29,15 +29,13 @@ import de.robv.android.xposed.XposedHelpers; import de.robv.android.xposed.XposedInit; import io.github.libxposed.api.XposedInterface; -import io.github.libxposed.api.annotations.AfterInvocation; import io.github.libxposed.api.annotations.XposedHooker; // when a package is loaded for an existing process, trigger the callbacks as well @XposedHooker public class LoadedApkCtorHooker implements XposedInterface.Hooker { - @AfterInvocation - public static void afterHookedMethod(XposedInterface.AfterHookCallback callback) { + public static void after(XposedInterface.AfterHookCallback callback) { Hookers.logD("LoadedApk# starts"); try { diff --git a/core/src/main/java/org/lsposed/lspd/hooker/OpenDexFileHooker.java b/core/src/main/java/org/lsposed/lspd/hooker/OpenDexFileHooker.java index af6f70a2d..f0462493b 100644 --- a/core/src/main/java/org/lsposed/lspd/hooker/OpenDexFileHooker.java +++ b/core/src/main/java/org/lsposed/lspd/hooker/OpenDexFileHooker.java @@ -2,18 +2,18 @@ import android.os.Build; +import androidx.annotation.NonNull; + import org.lsposed.lspd.impl.LSPosedBridge; import org.lsposed.lspd.nativebridge.HookBridge; import io.github.libxposed.api.XposedInterface; -import io.github.libxposed.api.annotations.AfterInvocation; import io.github.libxposed.api.annotations.XposedHooker; @XposedHooker public class OpenDexFileHooker implements XposedInterface.Hooker { - @AfterInvocation - public static void afterHookedMethod(XposedInterface.AfterHookCallback callback) { + public static void after(@NonNull XposedInterface.AfterHookCallback callback) { ClassLoader classLoader = null; for (var arg : callback.getArgs()) { if (arg instanceof ClassLoader) { diff --git a/core/src/main/java/org/lsposed/lspd/hooker/StartBootstrapServicesHooker.java b/core/src/main/java/org/lsposed/lspd/hooker/StartBootstrapServicesHooker.java index 30bf835d3..423264450 100644 --- a/core/src/main/java/org/lsposed/lspd/hooker/StartBootstrapServicesHooker.java +++ b/core/src/main/java/org/lsposed/lspd/hooker/StartBootstrapServicesHooker.java @@ -32,14 +32,12 @@ import de.robv.android.xposed.callbacks.XC_LoadPackage; import io.github.libxposed.api.XposedInterface; import io.github.libxposed.api.XposedModuleInterface; -import io.github.libxposed.api.annotations.BeforeInvocation; import io.github.libxposed.api.annotations.XposedHooker; @XposedHooker public class StartBootstrapServicesHooker implements XposedInterface.Hooker { - @BeforeInvocation - public static void beforeHookedMethod() { + public static void before(@NonNull XposedInterface.BeforeHookCallback callback) { logD("SystemServer#startBootstrapServices() starts"); try { diff --git a/core/src/main/java/org/lsposed/lspd/impl/LSPosedBridge.java b/core/src/main/java/org/lsposed/lspd/impl/LSPosedBridge.java index 27c7ce8ce..1480e2312 100644 --- a/core/src/main/java/org/lsposed/lspd/impl/LSPosedBridge.java +++ b/core/src/main/java/org/lsposed/lspd/impl/LSPosedBridge.java @@ -225,7 +225,7 @@ public static void dummyCallback() { Method beforeInvocation = null, afterInvocation = null; var modifiers = Modifier.PUBLIC | Modifier.STATIC; for (var method : hooker.getDeclaredMethods()) { - if (method.getAnnotation(BeforeInvocation.class) != null) { + if (method.getAnnotation(BeforeInvocation.class) != null || "before".equals(method.getName()) || "beforeHookedMethod".equals(method.getName())) { if (beforeInvocation != null) { throw new IllegalArgumentException("More than one method annotated with @BeforeInvocation"); } @@ -241,7 +241,7 @@ public static void dummyCallback() { } beforeInvocation = method; } - if (method.getAnnotation(AfterInvocation.class) != null) { + if (method.getAnnotation(AfterInvocation.class) != null || "after".equals(method.getName()) || "afterHookedMethod".equals(method.getName())) { if (afterInvocation != null) { throw new IllegalArgumentException("More than one method annotated with @AfterInvocation"); } 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 9c6b19634..e175461a1 100644 --- a/core/src/main/java/org/lsposed/lspd/impl/LSPosedContext.java +++ b/core/src/main/java/org/lsposed/lspd/impl/LSPosedContext.java @@ -38,6 +38,7 @@ import io.github.libxposed.api.XposedInterface; import io.github.libxposed.api.XposedModule; import io.github.libxposed.api.XposedModuleInterface; +import io.github.libxposed.api.errors.HookFailedError; import io.github.libxposed.api.errors.XposedFrameworkError; import io.github.libxposed.api.utils.DexParser; @@ -170,6 +171,32 @@ public MethodUnhooker hook(@NonNull Method origin, @NonNull Class MethodUnhooker> hookClassInitializer(@NonNull Class origin, @NonNull Class hooker) { + return hookClassInitializer(origin, PRIORITY_DEFAULT, hooker); + } + + @NonNull + @Override + public MethodUnhooker> hookClassInitializer(@NonNull Class origin, int priority, @NonNull Class hooker) { + try { + final var typeParams = hooker.getTypeParameters(); + final Class[] typeParamsArray = new Class[typeParams.length]; + for (int i = 0; i < typeParams.length; i++) { + try { + typeParamsArray[i] = origin.getClassLoader().loadClass(typeParams[i].getTypeName()); + } catch (Throwable e) { + typeParamsArray[i] = Object.class; + } + } + + return LSPosedBridge.doHook(origin.getDeclaredConstructor(typeParamsArray), priority, hooker); + } catch (Throwable e) { + throw new HookFailedError(e); + } + } + @Override @NonNull public MethodUnhooker hook(@NonNull Method origin, int priority, @NonNull Class hooker) { @@ -213,6 +240,11 @@ public Object invokeOrigin(@NonNull Method method, @Nullable Object thisObject, return HookBridge.invokeOriginalMethod(method, thisObject, args); } + @Override + public void invokeOrigin(@NonNull Constructor constructor, @NonNull T thisObject, Object... args) throws InvocationTargetException, IllegalArgumentException, IllegalAccessException { + HookBridge.invokeOriginalMethod(constructor, thisObject, args); + } + private static char getTypeShorty(Class type) { if (type == int.class) { return 'I'; @@ -256,6 +288,11 @@ public Object invokeSpecial(@NonNull Method method, @NonNull Object thisObject, return HookBridge.invokeSpecialMethod(method, getExecutableShorty(method), method.getDeclaringClass(), thisObject, args); } + @Override + public void invokeSpecial(@NonNull Constructor constructor, @NonNull T thisObject, Object... args) throws InvocationTargetException, IllegalArgumentException, IllegalAccessException { + HookBridge.invokeSpecialMethod(constructor, getExecutableShorty(constructor), constructor.getDeclaringClass(), thisObject, args); + } + @NonNull @Override public T newInstanceOrigin(@NonNull Constructor constructor, Object... args) throws InvocationTargetException, IllegalAccessException, InstantiationException { diff --git a/core/src/main/java/org/lsposed/lspd/util/LspModuleClassLoader.java b/core/src/main/java/org/lsposed/lspd/util/LspModuleClassLoader.java index 56f60b7e6..9e51de964 100644 --- a/core/src/main/java/org/lsposed/lspd/util/LspModuleClassLoader.java +++ b/core/src/main/java/org/lsposed/lspd/util/LspModuleClassLoader.java @@ -11,6 +11,8 @@ import androidx.annotation.NonNull; import androidx.annotation.RequiresApi; +import org.lsposed.lspd.util.Utils.Log; + import java.io.File; import java.io.IOException; import java.net.URL; @@ -24,8 +26,6 @@ import java.util.jar.JarFile; import java.util.zip.ZipEntry; -import org.lsposed.lspd.util.Utils.Log; - import hidden.ByteBufferDexClassLoader; import sun.misc.CompoundEnumeration; diff --git a/magisk-loader/src/main/java/org/lsposed/lspd/util/ParasiticManagerSystemHooker.java b/magisk-loader/src/main/java/org/lsposed/lspd/util/ParasiticManagerSystemHooker.java index 578627a85..1baed910c 100644 --- a/magisk-loader/src/main/java/org/lsposed/lspd/util/ParasiticManagerSystemHooker.java +++ b/magisk-loader/src/main/java/org/lsposed/lspd/util/ParasiticManagerSystemHooker.java @@ -9,13 +9,10 @@ import org.lsposed.lspd.hooker.HandleSystemServerProcessHooker; import org.lsposed.lspd.impl.LSPosedHelper; import org.lsposed.lspd.service.BridgeService; -import org.lsposed.lspd.util.Utils; import io.github.libxposed.api.XposedInterface; -import io.github.libxposed.api.annotations.AfterInvocation; import io.github.libxposed.api.annotations.XposedHooker; - public class ParasiticManagerSystemHooker implements HandleSystemServerProcessHooker.Callback { public static void start() { HandleSystemServerProcessHooker.callback = new ParasiticManagerSystemHooker(); @@ -35,8 +32,7 @@ public static void beforeHookedMethod(XposedInterface.BeforeHookCallback callbac @XposedHooker private static class Hooker implements XposedInterface.Hooker { - @AfterInvocation - public static void afterHookedMethod(XposedInterface.AfterHookCallback callback) throws Throwable { + public static void after(XposedInterface.AfterHookCallback callback) throws Throwable { var intent = (Intent) callback.getArgs()[0]; if (intent == null) return; if (!intent.hasCategory("org.lsposed.manager.LAUNCH_MANAGER")) return;