From 661a675a090aca525f206281f46206d2140d33ee Mon Sep 17 00:00:00 2001 From: solohsu Date: Mon, 17 Jun 2019 16:13:21 +0800 Subject: [PATCH] Black/White mode: postpone initZygote callbacks in case some modules hook methods in zygote, which would be propagated into blacklisted processes --- appveyor.yml | 2 +- .../riru/edxp/config/BaseEdxpConfig.java | 31 +++++++++++++++ .../riru/edxp/proxy/BlackWhiteListProxy.java | 4 ++ edxp-core/build.gradle | 2 +- .../sandhook/config/SandHookEdxpConfig.java | 25 +----------- .../edxp/whale/config/WhaleEdxpConfig.java | 27 ++----------- .../edxp/yahfa/config/YahfaEdxpConfig.java | 25 +----------- .../riru/edxp/config/EdXpConfigGlobal.java | 4 +- .../{EdXpConfig.java => EdxpConfig.java} | 3 +- .../android/xposed/IXposedHookZygoteInit.java | 33 +++++++++++++++- .../de/robv/android/xposed/XposedBridge.java | 19 +++++++++ .../de/robv/android/xposed/XposedInit.java | 12 +++++- .../xposed/callbacks/XC_InitZygote.java | 39 +++++++++++++++++++ 13 files changed, 149 insertions(+), 77 deletions(-) create mode 100644 edxp-common/src/main/java/com/elderdrivers/riru/edxp/config/BaseEdxpConfig.java rename xposed-bridge/src/main/java/com/elderdrivers/riru/edxp/config/{EdXpConfig.java => EdxpConfig.java} (75%) create mode 100644 xposed-bridge/src/main/java/de/robv/android/xposed/callbacks/XC_InitZygote.java diff --git a/appveyor.yml b/appveyor.yml index 7dad0777..c149e1ef 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,4 +1,4 @@ -version: '0.4.4.5_alpha({build})' +version: '0.4.4.6_alpha({build})' environment: ANDROID_HOME: C:\android-sdk-windows diff --git a/edxp-common/src/main/java/com/elderdrivers/riru/edxp/config/BaseEdxpConfig.java b/edxp-common/src/main/java/com/elderdrivers/riru/edxp/config/BaseEdxpConfig.java new file mode 100644 index 00000000..a05c399f --- /dev/null +++ b/edxp-common/src/main/java/com/elderdrivers/riru/edxp/config/BaseEdxpConfig.java @@ -0,0 +1,31 @@ +package com.elderdrivers.riru.edxp.config; + +import com.elderdrivers.riru.edxp.hooker.XposedBlackListHooker; + +public class BaseEdxpConfig implements EdxpConfig { + + @Override + public String getInstallerBaseDir() { + return InstallerChooser.INSTALLER_DATA_BASE_DIR; + } + + @Override + public String getBlackListModulePackageName() { + return XposedBlackListHooker.BLACK_LIST_PACKAGE_NAME; + } + + @Override + public boolean isDynamicModulesMode() { + return ConfigManager.isDynamicModulesEnabled(); + } + + @Override + public boolean isResourcesHookEnabled() { + return ConfigManager.isResourcesHookEnabled(); + } + + @Override + public boolean isBlackWhiteListMode() { + return ConfigManager.isBlackWhiteListEnabled(); + } +} diff --git a/edxp-common/src/main/java/com/elderdrivers/riru/edxp/proxy/BlackWhiteListProxy.java b/edxp-common/src/main/java/com/elderdrivers/riru/edxp/proxy/BlackWhiteListProxy.java index 88bd5a11..217a48d1 100644 --- a/edxp-common/src/main/java/com/elderdrivers/riru/edxp/proxy/BlackWhiteListProxy.java +++ b/edxp-common/src/main/java/com/elderdrivers/riru/edxp/proxy/BlackWhiteListProxy.java @@ -106,6 +106,9 @@ public class BlackWhiteListProxy extends BaseProxy { mRouter.installBootstrapHooks(isSystemServer); if (isDynamicModulesMode) { mRouter.loadModulesSafely(false); + } else { + XposedBridge.callInitZygotes(); + XposedBridge.clearInitZygotes(); // one-time use } mRouter.onForkFinish(); } @@ -130,5 +133,6 @@ public class BlackWhiteListProxy extends BaseProxy { private static void onBlackListed() { XposedBridge.clearLoadedPackages(); XposedBridge.clearInitPackageResources(); + XposedBridge.clearInitZygotes(); } } diff --git a/edxp-core/build.gradle b/edxp-core/build.gradle index 58d6045c..72a04dcc 100644 --- a/edxp-core/build.gradle +++ b/edxp-core/build.gradle @@ -4,7 +4,7 @@ import org.gradle.internal.os.OperatingSystem apply plugin: 'com.android.library' // Values set here will be overriden by AppVeyor, feel free to modify during development. -def buildVersionName = 'v0.4.4.5_alpha' +def buildVersionName = 'v0.4.4.6_alpha' def buildVersionCode = 10000 if (System.env.APPVEYOR_BUILD_VERSION != null) { diff --git a/edxp-sandhook/src/main/java/com/elderdrivers/riru/edxp/sandhook/config/SandHookEdxpConfig.java b/edxp-sandhook/src/main/java/com/elderdrivers/riru/edxp/sandhook/config/SandHookEdxpConfig.java index 8d52e411..e79224b2 100644 --- a/edxp-sandhook/src/main/java/com/elderdrivers/riru/edxp/sandhook/config/SandHookEdxpConfig.java +++ b/edxp-sandhook/src/main/java/com/elderdrivers/riru/edxp/sandhook/config/SandHookEdxpConfig.java @@ -1,28 +1,7 @@ package com.elderdrivers.riru.edxp.sandhook.config; -import com.elderdrivers.riru.edxp.config.ConfigManager; -import com.elderdrivers.riru.edxp.config.EdXpConfig; -import com.elderdrivers.riru.edxp.config.InstallerChooser; -import com.elderdrivers.riru.edxp.hooker.XposedBlackListHooker; +import com.elderdrivers.riru.edxp.config.BaseEdxpConfig; -public class SandHookEdxpConfig implements EdXpConfig { - @Override - public String getInstallerBaseDir() { - return InstallerChooser.INSTALLER_DATA_BASE_DIR; - } +public class SandHookEdxpConfig extends BaseEdxpConfig { - @Override - public String getBlackListModulePackageName() { - return XposedBlackListHooker.BLACK_LIST_PACKAGE_NAME; - } - - @Override - public boolean isDynamicModulesMode() { - return ConfigManager.isDynamicModulesEnabled(); - } - - @Override - public boolean isResourcesHookEnabled() { - return ConfigManager.isResourcesHookEnabled(); - } } diff --git a/edxp-whale/src/main/java/com/elderdrivers/riru/edxp/whale/config/WhaleEdxpConfig.java b/edxp-whale/src/main/java/com/elderdrivers/riru/edxp/whale/config/WhaleEdxpConfig.java index f3172399..6237cd7f 100644 --- a/edxp-whale/src/main/java/com/elderdrivers/riru/edxp/whale/config/WhaleEdxpConfig.java +++ b/edxp-whale/src/main/java/com/elderdrivers/riru/edxp/whale/config/WhaleEdxpConfig.java @@ -1,28 +1,7 @@ package com.elderdrivers.riru.edxp.whale.config; -import com.elderdrivers.riru.edxp.config.ConfigManager; -import com.elderdrivers.riru.edxp.config.EdXpConfig; -import com.elderdrivers.riru.edxp.config.InstallerChooser; -import com.elderdrivers.riru.edxp.hooker.XposedBlackListHooker; +import com.elderdrivers.riru.edxp.config.BaseEdxpConfig; -public class WhaleEdxpConfig implements EdXpConfig { - @Override - public String getInstallerBaseDir() { - return InstallerChooser.INSTALLER_DATA_BASE_DIR; - } - - @Override - public String getBlackListModulePackageName() { - return XposedBlackListHooker.BLACK_LIST_PACKAGE_NAME; - } - - @Override - public boolean isDynamicModulesMode() { - return ConfigManager.isDynamicModulesEnabled(); - } - - @Override - public boolean isResourcesHookEnabled() { - return ConfigManager.isResourcesHookEnabled(); - } +public class WhaleEdxpConfig extends BaseEdxpConfig { + } diff --git a/edxp-yahfa/src/main/java/com/elderdrivers/riru/edxp/yahfa/config/YahfaEdxpConfig.java b/edxp-yahfa/src/main/java/com/elderdrivers/riru/edxp/yahfa/config/YahfaEdxpConfig.java index 8ea68550..e051a47e 100644 --- a/edxp-yahfa/src/main/java/com/elderdrivers/riru/edxp/yahfa/config/YahfaEdxpConfig.java +++ b/edxp-yahfa/src/main/java/com/elderdrivers/riru/edxp/yahfa/config/YahfaEdxpConfig.java @@ -1,28 +1,7 @@ package com.elderdrivers.riru.edxp.yahfa.config; -import com.elderdrivers.riru.edxp.config.ConfigManager; -import com.elderdrivers.riru.edxp.config.EdXpConfig; -import com.elderdrivers.riru.edxp.config.InstallerChooser; -import com.elderdrivers.riru.edxp.hooker.XposedBlackListHooker; +import com.elderdrivers.riru.edxp.config.BaseEdxpConfig; -public class YahfaEdxpConfig implements EdXpConfig { - @Override - public String getInstallerBaseDir() { - return InstallerChooser.INSTALLER_DATA_BASE_DIR; - } +public class YahfaEdxpConfig extends BaseEdxpConfig { - @Override - public String getBlackListModulePackageName() { - return XposedBlackListHooker.BLACK_LIST_PACKAGE_NAME; - } - - @Override - public boolean isDynamicModulesMode() { - return ConfigManager.isDynamicModulesEnabled(); - } - - @Override - public boolean isResourcesHookEnabled() { - return ConfigManager.isResourcesHookEnabled(); - } } diff --git a/xposed-bridge/src/main/java/com/elderdrivers/riru/edxp/config/EdXpConfigGlobal.java b/xposed-bridge/src/main/java/com/elderdrivers/riru/edxp/config/EdXpConfigGlobal.java index 0d94ae2d..6cb93ac5 100644 --- a/xposed-bridge/src/main/java/com/elderdrivers/riru/edxp/config/EdXpConfigGlobal.java +++ b/xposed-bridge/src/main/java/com/elderdrivers/riru/edxp/config/EdXpConfigGlobal.java @@ -4,10 +4,10 @@ import com.elderdrivers.riru.edxp.hook.HookProvider; public class EdXpConfigGlobal { - public static volatile EdXpConfig sConfig; + public static volatile EdxpConfig sConfig; public static volatile HookProvider sHookProvider; - public static EdXpConfig getConfig() { + public static EdxpConfig getConfig() { if (sConfig == null) { throw new IllegalArgumentException("sConfig should not be null."); } diff --git a/xposed-bridge/src/main/java/com/elderdrivers/riru/edxp/config/EdXpConfig.java b/xposed-bridge/src/main/java/com/elderdrivers/riru/edxp/config/EdxpConfig.java similarity index 75% rename from xposed-bridge/src/main/java/com/elderdrivers/riru/edxp/config/EdXpConfig.java rename to xposed-bridge/src/main/java/com/elderdrivers/riru/edxp/config/EdxpConfig.java index 39882a25..4a12da20 100644 --- a/xposed-bridge/src/main/java/com/elderdrivers/riru/edxp/config/EdXpConfig.java +++ b/xposed-bridge/src/main/java/com/elderdrivers/riru/edxp/config/EdxpConfig.java @@ -1,6 +1,6 @@ package com.elderdrivers.riru.edxp.config; -public interface EdXpConfig { +public interface EdxpConfig { String getInstallerBaseDir(); @@ -10,4 +10,5 @@ public interface EdXpConfig { boolean isResourcesHookEnabled(); + boolean isBlackWhiteListMode(); } diff --git a/xposed-bridge/src/main/java/de/robv/android/xposed/IXposedHookZygoteInit.java b/xposed-bridge/src/main/java/de/robv/android/xposed/IXposedHookZygoteInit.java index dc130a76..4f159774 100644 --- a/xposed-bridge/src/main/java/de/robv/android/xposed/IXposedHookZygoteInit.java +++ b/xposed-bridge/src/main/java/de/robv/android/xposed/IXposedHookZygoteInit.java @@ -1,5 +1,8 @@ package de.robv.android.xposed; +import de.robv.android.xposed.callbacks.XC_InitZygote; +import de.robv.android.xposed.callbacks.XCallback; + /** * Hook the initialization of Zygote process(es), from which all the apps are forked. * @@ -20,9 +23,17 @@ public interface IXposedHookZygoteInit extends IXposedMod { void initZygote(StartupParam startupParam) throws Throwable; /** Data holder for {@link #initZygote}. */ - final class StartupParam { + final class StartupParam extends XCallback.Param { /*package*/ StartupParam() {} + /** + * @param callbacks + * @hide + */ + public StartupParam(XposedBridge.CopyOnWriteSortedSet callbacks) { + super(callbacks); + } + /** The path to the module's APK. */ public String modulePath; @@ -32,4 +43,24 @@ public interface IXposedHookZygoteInit extends IXposedMod { */ public boolean startsSystemServer; } + + /** + * @hide + */ + final class Wrapper extends XC_InitZygote { + private final IXposedHookZygoteInit instance; + private final StartupParam startupParam; + + public Wrapper(IXposedHookZygoteInit instance, StartupParam startupParam) { + this.instance = instance; + this.startupParam = startupParam; + } + + @Override + public void initZygote(StartupParam startupParam) throws Throwable { + // NOTE: parameter startupParam not used + // cause startupParam info is generated and saved along with instance here + instance.initZygote(this.startupParam); + } + } } diff --git a/xposed-bridge/src/main/java/de/robv/android/xposed/XposedBridge.java b/xposed-bridge/src/main/java/de/robv/android/xposed/XposedBridge.java index 9be482d2..76e9a826 100644 --- a/xposed-bridge/src/main/java/de/robv/android/xposed/XposedBridge.java +++ b/xposed-bridge/src/main/java/de/robv/android/xposed/XposedBridge.java @@ -22,7 +22,9 @@ import java.util.Set; import dalvik.system.InMemoryDexClassLoader; import de.robv.android.xposed.XC_MethodHook.MethodHookParam; import de.robv.android.xposed.callbacks.XC_InitPackageResources; +import de.robv.android.xposed.callbacks.XC_InitZygote; import de.robv.android.xposed.callbacks.XC_LoadPackage; +import de.robv.android.xposed.callbacks.XCallback; import external.com.android.dx.DexMaker; import external.com.android.dx.TypeId; @@ -67,6 +69,7 @@ public final class XposedBridge { public static final Map> sHookedMethodCallbacks = new HashMap<>(); public static final CopyOnWriteSortedSet sLoadedPackageCallbacks = new CopyOnWriteSortedSet<>(); /*package*/ static final CopyOnWriteSortedSet sInitPackageResourcesCallbacks = new CopyOnWriteSortedSet<>(); + /*package*/ static final CopyOnWriteSortedSet sInitZygoteCallbacks = new CopyOnWriteSortedSet<>(); private XposedBridge() {} @@ -427,6 +430,22 @@ public final class XposedBridge { } } + public static void hookInitZygote(XC_InitZygote callback) { + synchronized (sInitZygoteCallbacks) { + sInitZygoteCallbacks.add(callback); + } + } + + public static void clearInitZygotes() { + synchronized (sInitZygoteCallbacks) { + sInitZygoteCallbacks.clear(); + } + } + + public static void callInitZygotes() { + XCallback.callAll(new IXposedHookZygoteInit.StartupParam(sInitZygoteCallbacks)); + } + /** * Intercept every call to the specified method and call a handler function instead. * @param method The method to intercept diff --git a/xposed-bridge/src/main/java/de/robv/android/xposed/XposedInit.java b/xposed-bridge/src/main/java/de/robv/android/xposed/XposedInit.java index 19936fa8..14dd7b87 100644 --- a/xposed-bridge/src/main/java/de/robv/android/xposed/XposedInit.java +++ b/xposed-bridge/src/main/java/de/robv/android/xposed/XposedInit.java @@ -414,7 +414,17 @@ public final class XposedInit { IXposedHookZygoteInit.StartupParam param = new IXposedHookZygoteInit.StartupParam(); param.modulePath = apk; param.startsSystemServer = startsSystemServer; - ((IXposedHookZygoteInit) moduleInstance).initZygote(param); + if (EdXpConfigGlobal.getConfig().isBlackWhiteListMode() + && !EdXpConfigGlobal.getConfig().isDynamicModulesMode()) { + // postpone initZygote callbacks under black/white list mode + // if dynamic modules mode is on, callback directly cause we + // are already in app process here + XposedBridge.hookInitZygote(new IXposedHookZygoteInit.Wrapper( + (IXposedHookZygoteInit) moduleInstance, param)); + } else { + // FIXME under dynamic modules mode, initZygote is called twice + ((IXposedHookZygoteInit) moduleInstance).initZygote(param); + } } if (moduleInstance instanceof IXposedHookLoadPackage) diff --git a/xposed-bridge/src/main/java/de/robv/android/xposed/callbacks/XC_InitZygote.java b/xposed-bridge/src/main/java/de/robv/android/xposed/callbacks/XC_InitZygote.java new file mode 100644 index 00000000..60c05252 --- /dev/null +++ b/xposed-bridge/src/main/java/de/robv/android/xposed/callbacks/XC_InitZygote.java @@ -0,0 +1,39 @@ +package de.robv.android.xposed.callbacks; + +import de.robv.android.xposed.IXposedHookZygoteInit; + +/** + * This class is only used for internal purposes, except for the {@link StartupParam} + * subclass. + */ +public abstract class XC_InitZygote extends XCallback implements IXposedHookZygoteInit { + + /** + * Creates a new callback with default priority. + * + * @hide + */ + @SuppressWarnings("deprecation") + public XC_InitZygote() { + super(); + } + + /** + * Creates a new callback with a specific priority. + * + * @param priority See {@link XCallback#priority}. + * @hide + */ + public XC_InitZygote(int priority) { + super(priority); + } + + /** + * @hide + */ + @Override + protected void call(Param param) throws Throwable { + if (param instanceof StartupParam) + initZygote((StartupParam) param); + } +}