From dfcf21cccaefc35f83be17eb91f3872d68427701 Mon Sep 17 00:00:00 2001 From: tiann <923551233@qq.com> Date: Tue, 19 Jun 2018 14:11:01 +0800 Subject: [PATCH] 1. fix the Application.attach may be hooked multi-times. 2. reduce the log of Xposed. --- exposed-core/build.gradle | 2 +- .../de/robv/android/xposed/ExposedHelper.java | 16 +++- .../java/me/weishu/exposed/CHAHelper.java | 77 +++++++++++++++++++ .../java/me/weishu/exposed/ExposedBridge.java | 33 +++----- 4 files changed, 101 insertions(+), 27 deletions(-) create mode 100644 exposed-core/src/main/java/me/weishu/exposed/CHAHelper.java diff --git a/exposed-core/build.gradle b/exposed-core/build.gradle index d2b6fb0..9015e31 100644 --- a/exposed-core/build.gradle +++ b/exposed-core/build.gradle @@ -31,7 +31,7 @@ dependencies { } group = 'me.weishu.exposed' -version = '0.6.6' +version = '0.6.7' apply plugin: 'com.novoda.bintray-release' diff --git a/exposed-core/src/main/java/de/robv/android/xposed/ExposedHelper.java b/exposed-core/src/main/java/de/robv/android/xposed/ExposedHelper.java index 64747d0..a39cfe6 100644 --- a/exposed-core/src/main/java/de/robv/android/xposed/ExposedHelper.java +++ b/exposed-core/src/main/java/de/robv/android/xposed/ExposedHelper.java @@ -1,5 +1,7 @@ package de.robv.android.xposed; +import android.util.Log; + import java.lang.reflect.Member; /** @@ -7,14 +9,16 @@ */ public class ExposedHelper { + private static final String TAG = "ExposedHelper"; + public static void initSeLinux(String processName) { SELinuxHelper.initOnce(); SELinuxHelper.initForProcess(processName); } public static boolean isIXposedMod(Class moduleClass) { - XposedBridge.log("module's classLoader : " + moduleClass.getClassLoader() + ", super: " + moduleClass.getSuperclass()); - XposedBridge.log("IXposedMod's classLoader : " + IXposedMod.class.getClassLoader()); + Log.d(TAG, "module's classLoader : " + moduleClass.getClassLoader() + ", super: " + moduleClass.getSuperclass()); + Log.d(TAG, "IXposedMod's classLoader : " + IXposedMod.class.getClassLoader()); return IXposedMod.class.isAssignableFrom(moduleClass); } @@ -30,4 +34,12 @@ public static void callInitZygote(String modulePath, Object moduleInstance) thro param.startsSystemServer = false; ((IXposedHookZygoteInit) moduleInstance).initZygote(param); } + + public static void beforeHookedMethod(XC_MethodHook methodHook, XC_MethodHook.MethodHookParam param) throws Throwable{ + methodHook.beforeHookedMethod(param); + } + + public static void afterHookedMethod(XC_MethodHook methodHook, XC_MethodHook.MethodHookParam param) throws Throwable{ + methodHook.afterHookedMethod(param); + } } diff --git a/exposed-core/src/main/java/me/weishu/exposed/CHAHelper.java b/exposed-core/src/main/java/me/weishu/exposed/CHAHelper.java new file mode 100644 index 0000000..ff2cad6 --- /dev/null +++ b/exposed-core/src/main/java/me/weishu/exposed/CHAHelper.java @@ -0,0 +1,77 @@ +package me.weishu.exposed; + +import android.app.Application; +import android.content.Context; +import android.content.ContextWrapper; +import android.util.Log; + +import java.lang.reflect.Member; +import java.lang.reflect.Method; + +import de.robv.android.xposed.DexposedBridge; +import de.robv.android.xposed.ExposedHelper; +import de.robv.android.xposed.XC_MethodHook; +import de.robv.android.xposed.XposedBridge; +import de.robv.android.xposed.XposedHelpers; + +/** + * @author weishu + * @date 2018/6/19. + */ +public final class CHAHelper { + private static final String TAG = "CHAHelper"; + + static class ApplicationHookProxy extends XC_MethodHook { + + XC_MethodHook original; + + ApplicationHookProxy(XC_MethodHook original) { + this.original = original; + } + + @Override + protected void beforeHookedMethod(MethodHookParam param) throws Throwable { + super.beforeHookedMethod(param); + if (param.thisObject == null) { + throw new IllegalArgumentException("can not use static method!!"); + } + + if (param.thisObject instanceof Application) { + ExposedHelper.beforeHookedMethod(this.original, param); + } else { + Log.d(TAG, "ignore non-application of ContextWrapper: " + param.thisObject); + } + } + + @Override + protected void afterHookedMethod(MethodHookParam param) throws Throwable { + super.afterHookedMethod(param); + if (param.thisObject == null) { + throw new IllegalArgumentException("can not use static method!!"); + } + + if (param.thisObject instanceof Application) { + ExposedHelper.afterHookedMethod(this.original, param); + } else { + Log.d(TAG, "ignore non-application of ContextWrapper: " + param.thisObject); + } + } + } + + static XC_MethodHook.Unhook replaceForCHA(Member member, final XC_MethodHook callback) { + + if (member.getDeclaringClass() == Application.class && member.getName().equals("attach")) { + XposedBridge.log("replace Application.attach with ContextWrapper.attachBaseContext for CHA"); + Method m = XposedHelpers.findMethodExact(ContextWrapper.class, "attachBaseContext", Context.class); + return DexposedBridge.hookMethod(m, new ApplicationHookProxy(callback)); + } + + if (member.getDeclaringClass() == Application.class && member.getName().equals("onCreate")) { + XposedBridge.log("replace Application.onCreate with ContextWrapper.attachBaseContext for CHA"); + Method m = XposedHelpers.findMethodExact(ContextWrapper.class, "attachBaseContext", Context.class); + return DexposedBridge.hookMethod(m, new ApplicationHookProxy(callback)); + } + + return null; + } +} diff --git a/exposed-core/src/main/java/me/weishu/exposed/ExposedBridge.java b/exposed-core/src/main/java/me/weishu/exposed/ExposedBridge.java index 42843ef..9b2191c 100644 --- a/exposed-core/src/main/java/me/weishu/exposed/ExposedBridge.java +++ b/exposed-core/src/main/java/me/weishu/exposed/ExposedBridge.java @@ -1,10 +1,8 @@ package me.weishu.exposed; import android.annotation.SuppressLint; -import android.app.Application; import android.content.ComponentName; import android.content.Context; -import android.content.ContextWrapper; import android.content.Intent; import android.content.ServiceConnection; import android.content.SharedPreferences; @@ -36,7 +34,6 @@ import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Member; -import java.lang.reflect.Method; import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; @@ -205,11 +202,11 @@ public static ModuleLoadResult loadModule(final String moduleApkPath, String mod loadModuleConfig(rootDir, currentApplicationInfo.processName); if (lastModuleList.second == null || !lastModuleList.second.contains(moduleApkPath)) { - log("module:" + moduleApkPath + " is disabled, ignore"); + Log.i(TAG, "module:" + moduleApkPath + " is disabled, ignore"); return ModuleLoadResult.DISABLED; } - log("Loading modules from " + moduleApkPath + " for process: " + currentApplicationInfo.processName + " i s c: " + SYSTEM_CLASSLOADER_INJECT); + Log.i(TAG, "Loading modules from " + moduleApkPath + " for process: " + currentApplicationInfo.processName + " i s c: " + SYSTEM_CLASSLOADER_INJECT); if (!new File(moduleApkPath).exists()) { log(moduleApkPath + " does not exist"); @@ -249,7 +246,7 @@ public static ModuleLoadResult loadModule(final String moduleApkPath, String mod continue; } try { - log(" Loading class " + moduleClassName); + Log.i(TAG, " Loading class " + moduleClassName); Class moduleClass = mcl.loadClass(moduleClassName); sModuleLoadListener.onLoadingModule(moduleClassName, currentApplicationInfo, mcl); @@ -334,7 +331,10 @@ public static XC_MethodHook.Unhook hookMethod(Member method, XC_MethodHook callb return null; } - method = replaceForCHA(method); + XC_MethodHook.Unhook replaceUnhook = CHAHelper.replaceForCHA(method, callback); + if (replaceUnhook != null) { + return ExposedHelper.newUnHook(callback, replaceUnhook.getHookedMethod()); + } final XC_MethodHook.Unhook unhook = DexposedBridge.hookMethod(method, callback); return ExposedHelper.newUnHook(callback, unhook.getHookedMethod()); @@ -346,22 +346,7 @@ public static Object invokeOriginalMethod(Member method, Object thisObject, Obje return DexposedBridge.invokeOriginalMethod(method, thisObject, args); } - private static Member replaceForCHA(Member member) { - - if (member.getDeclaringClass() == Application.class && member.getName().equals("attach")) { - Method m = XposedHelpers.findMethodExact(ContextWrapper.class, "attachBaseContext", Context.class); - XposedBridge.log("replace Application.attach with ContextWrapper.attachBaseContext for CHA"); - return m; - } - - if (member.getDeclaringClass() == Application.class && member.getName().equals("onCreate")) { - Method m = XposedHelpers.findMethodExact(ContextWrapper.class, "attachBaseContext", Context.class); - XposedBridge.log("replace Application.onCreate with ContextWrapper.attachBaseContext for CHA"); - return m; - } - return member; - } private static void initForXposedModule(Context context, ApplicationInfo applicationInfo, ClassLoader appClassLoader) { InputStream inputStream = null; @@ -370,7 +355,7 @@ private static void initForXposedModule(Context context, ApplicationInfo applica inputStream = context.getAssets().open("xposed_init"); System.setProperty("epic.force", "true"); } catch (IOException e) { - log(applicationInfo.packageName + " is not a Xposed module"); + Log.i(TAG, applicationInfo.packageName + " is not a Xposed module, do not init epic.force"); } finally { closeSliently(inputStream); } @@ -440,7 +425,7 @@ private static void initForXposedInstaller(Context context, ApplicationInfo appl if (!fakeVersionString.equals(oldVersion)) { writeXposedProperty(xposedProp, fakeVersionString, true); } else { - log("xposed version keep same, continue."); + Log.i(TAG, "xposed version keep same, continue."); } }