Refactor Java code
This commit is contained in:
parent
c362449e33
commit
c38affbf3a
|
|
@ -23,6 +23,7 @@ dependencies {
|
|||
compileOnly project(':hiddenapi-stubs')
|
||||
implementation project(':xposed-bridge')
|
||||
compileOnly project(':dexmaker')
|
||||
api "androidx.annotation:annotation:1.1.0-rc01"
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
package com.elderdrivers.riru.edxp.whale._hooker;
|
||||
package com.elderdrivers.riru.edxp._hooker.impl;
|
||||
|
||||
import android.app.ActivityThread;
|
||||
import android.app.LoadedApk;
|
||||
|
|
@ -6,14 +6,14 @@ import android.content.ComponentName;
|
|||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.res.CompatibilityInfo;
|
||||
|
||||
import com.elderdrivers.riru.common.KeepMembers;
|
||||
import com.elderdrivers.riru.edxp.Main;
|
||||
import com.elderdrivers.riru.edxp.config.ConfigManager;
|
||||
import com.elderdrivers.riru.edxp.hooker.SliceProviderFix;
|
||||
import com.elderdrivers.riru.edxp.hooker.XposedBlackListHooker;
|
||||
import com.elderdrivers.riru.edxp.hooker.XposedInstallerHooker;
|
||||
import com.elderdrivers.riru.edxp.util.Hookers;
|
||||
import com.elderdrivers.riru.edxp.util.Utils;
|
||||
import com.elderdrivers.riru.edxp.whale.entry.Router;
|
||||
|
||||
import de.robv.android.xposed.XC_MethodHook;
|
||||
import de.robv.android.xposed.XposedBridge;
|
||||
import de.robv.android.xposed.XposedHelpers;
|
||||
import de.robv.android.xposed.XposedInit;
|
||||
|
|
@ -25,26 +25,23 @@ import static com.elderdrivers.riru.edxp.hooker.XposedBlackListHooker.BLACK_LIST
|
|||
import static com.elderdrivers.riru.edxp.util.ClassLoaderUtils.replaceParentClassLoader;
|
||||
|
||||
// normal process initialization (for new Activity, Service, BroadcastReceiver etc.)
|
||||
public class HandleBindAppHooker implements KeepMembers {
|
||||
public class HandleBindApp extends XC_MethodHook {
|
||||
|
||||
public static String className = "android.app.ActivityThread";
|
||||
public static String methodName = "handleBindApplication";
|
||||
public static String methodSig = "(Landroid/app/ActivityThread$AppBindData;)V";
|
||||
|
||||
public static void hook(Object thiz, Object bindData) {
|
||||
@Override
|
||||
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
|
||||
if (XposedBlackListHooker.shouldDisableHooks("")) {
|
||||
backup(thiz, bindData);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
Router.logD("ActivityThread#handleBindApplication() starts");
|
||||
ActivityThread activityThread = (ActivityThread) thiz;
|
||||
Hookers.logD("ActivityThread#handleBindApplication() starts");
|
||||
ActivityThread activityThread = (ActivityThread) param.thisObject;
|
||||
Object bindData = param.args[0];
|
||||
ApplicationInfo appInfo = (ApplicationInfo) XposedHelpers.getObjectField(bindData, "appInfo");
|
||||
// save app process name here for later use
|
||||
Main.appProcessName = (String) XposedHelpers.getObjectField(bindData, "processName");
|
||||
ConfigManager.appProcessName = (String) XposedHelpers.getObjectField(bindData, "processName");
|
||||
String reportedPackageName = appInfo.packageName.equals("android") ? "system" : appInfo.packageName;
|
||||
Utils.logD("processName=" + Main.appProcessName +
|
||||
", packageName=" + reportedPackageName + ", appDataDir=" + Main.appDataDir);
|
||||
Utils.logD("processName=" + ConfigManager.appProcessName +
|
||||
", packageName=" + reportedPackageName + ", appDataDir=" + ConfigManager.appDataDir);
|
||||
|
||||
if (XposedBlackListHooker.shouldDisableHooks(reportedPackageName)) {
|
||||
return;
|
||||
|
|
@ -52,7 +49,7 @@ public class HandleBindAppHooker implements KeepMembers {
|
|||
|
||||
ComponentName instrumentationName = (ComponentName) XposedHelpers.getObjectField(bindData, "instrumentationName");
|
||||
if (instrumentationName != null) {
|
||||
Router.logD("Instrumentation detected, disabling framework for");
|
||||
Hookers.logD("Instrumentation detected, disabling framework for");
|
||||
XposedBridge.disableHooks = true;
|
||||
return;
|
||||
}
|
||||
|
|
@ -85,12 +82,7 @@ public class HandleBindAppHooker implements KeepMembers {
|
|||
SliceProviderFix.hook();
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
Router.logE("error when hooking bindApp", t);
|
||||
} finally {
|
||||
backup(thiz, bindData);
|
||||
Hookers.logE("error when hooking bindApp", t);
|
||||
}
|
||||
}
|
||||
|
||||
public static void backup(Object thiz, Object bindData) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,76 @@
|
|||
package com.elderdrivers.riru.edxp._hooker.impl;
|
||||
|
||||
import android.app.AndroidAppHelper;
|
||||
import android.app.LoadedApk;
|
||||
import android.util.Log;
|
||||
|
||||
import com.elderdrivers.riru.edxp.hooker.XposedBlackListHooker;
|
||||
import com.elderdrivers.riru.edxp.util.Hookers;
|
||||
|
||||
import de.robv.android.xposed.XC_MethodHook;
|
||||
import de.robv.android.xposed.XposedBridge;
|
||||
import de.robv.android.xposed.XposedHelpers;
|
||||
import de.robv.android.xposed.XposedInit;
|
||||
import de.robv.android.xposed.callbacks.XC_LoadPackage;
|
||||
|
||||
import static com.elderdrivers.riru.edxp.util.ClassLoaderUtils.replaceParentClassLoader;
|
||||
|
||||
// when a package is loaded for an existing process, trigger the callbacks as well
|
||||
// ed: remove resources related hooking
|
||||
public class LoadedApkCstr extends XC_MethodHook {
|
||||
|
||||
@Override
|
||||
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
|
||||
if (XposedBlackListHooker.shouldDisableHooks("")) {
|
||||
return;
|
||||
}
|
||||
|
||||
Hookers.logD("LoadedApk#<init> starts");
|
||||
|
||||
try {
|
||||
LoadedApk loadedApk = (LoadedApk) param.thisObject;
|
||||
String packageName = loadedApk.getPackageName();
|
||||
Object mAppDir = XposedHelpers.getObjectField(loadedApk, "mAppDir");
|
||||
Hookers.logD("LoadedApk#<init> ends: " + mAppDir);
|
||||
|
||||
if (XposedBlackListHooker.shouldDisableHooks(packageName)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (packageName.equals("android")) {
|
||||
Hookers.logD("LoadedApk#<init> is android, skip: " + mAppDir);
|
||||
return;
|
||||
}
|
||||
|
||||
// mIncludeCode checking should go ahead of loadedPackagesInProcess added checking
|
||||
if (!XposedHelpers.getBooleanField(loadedApk, "mIncludeCode")) {
|
||||
Hookers.logD("LoadedApk#<init> mIncludeCode == false: " + mAppDir);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!XposedInit.loadedPackagesInProcess.add(packageName)) {
|
||||
Hookers.logD("LoadedApk#<init> has been loaded before, skip: " + mAppDir);
|
||||
return;
|
||||
}
|
||||
|
||||
// OnePlus magic...
|
||||
if (Log.getStackTraceString(new Throwable()).
|
||||
contains("android.app.ActivityThread$ApplicationThread.schedulePreload")) {
|
||||
Hookers.logD("LoadedApk#<init> maybe oneplus's custom opt, skip");
|
||||
return;
|
||||
}
|
||||
|
||||
replaceParentClassLoader(loadedApk.getClassLoader());
|
||||
|
||||
XC_LoadPackage.LoadPackageParam lpparam = new XC_LoadPackage.LoadPackageParam(XposedBridge.sLoadedPackageCallbacks);
|
||||
lpparam.packageName = packageName;
|
||||
lpparam.processName = AndroidAppHelper.currentProcessName();
|
||||
lpparam.classLoader = loadedApk.getClassLoader();
|
||||
lpparam.appInfo = loadedApk.getApplicationInfo();
|
||||
lpparam.isFirstApplication = false;
|
||||
XC_LoadPackage.callAll(lpparam);
|
||||
} catch (Throwable t) {
|
||||
Hookers.logE("error when hooking LoadedApk.<init>", t);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,13 +1,14 @@
|
|||
package com.elderdrivers.riru.edxp.yahfa._hooker;
|
||||
package com.elderdrivers.riru.edxp._hooker.impl;
|
||||
|
||||
import com.elderdrivers.riru.common.KeepMembers;
|
||||
import com.elderdrivers.riru.edxp.Main;
|
||||
import com.elderdrivers.riru.edxp.yahfa.entry.Router;
|
||||
import com.elderdrivers.riru.edxp.core.Main;
|
||||
import com.elderdrivers.riru.edxp.util.Hookers;
|
||||
|
||||
import dalvik.system.BaseDexClassLoader;
|
||||
import de.robv.android.xposed.XC_MethodHook;
|
||||
import de.robv.android.xposed.XposedBridge;
|
||||
|
||||
/**
|
||||
* On OnePlus stock roms (Android Pie), {@link dalvik.system.BaseDexClassLoader#findClass(String)}
|
||||
* On OnePlus stock roms (Android Pie), {@link BaseDexClassLoader#findClass(String)}
|
||||
* will open /dev/binder to communicate with PackageManagerService to check whether
|
||||
* current package name inCompatConfigList, which is an OnePlus OEM feature enabled only when
|
||||
* system prop "persist.sys.oem.region" set to "CN".(detail of related source code:
|
||||
|
|
@ -21,21 +22,15 @@ import de.robv.android.xposed.XposedBridge;
|
|||
* open of /dev/binder and we haven't found side effects yet.
|
||||
* Other roms might share the same problems but not reported too.
|
||||
*/
|
||||
public class OnePlusWorkAroundHooker implements KeepMembers {
|
||||
public class OneplusWorkaround extends XC_MethodHook {
|
||||
|
||||
public static String className = "dalvik.system.BaseDexClassLoader";
|
||||
public static String methodName = "inCompatConfigList";
|
||||
public static String methodSig = "(ILjava/lang/String;)Z";
|
||||
|
||||
public static boolean hook(int type, String packageName) {
|
||||
if (XposedBridge.disableHooks || Router.forkCompleted) {
|
||||
return backup(type, packageName);
|
||||
@Override
|
||||
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
|
||||
if (XposedBridge.disableHooks || Main.getEdxpImpl().getRouter().isForkCompleted()) {
|
||||
return;
|
||||
}
|
||||
Router.logD("BaseDexClassLoader#inCompatConfigList() starts");
|
||||
return false;
|
||||
Hookers.logD("BaseDexClassLoader#inCompatConfigList() starts");
|
||||
param.setResult(false);
|
||||
}
|
||||
|
||||
public static boolean backup(int type, String packageName) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,10 +1,10 @@
|
|||
package com.elderdrivers.riru.edxp.yahfa._hooker;
|
||||
package com.elderdrivers.riru.edxp._hooker.impl;
|
||||
|
||||
import android.os.Build;
|
||||
|
||||
import com.elderdrivers.riru.common.KeepMembers;
|
||||
import com.elderdrivers.riru.edxp.yahfa.entry.Router;
|
||||
import com.elderdrivers.riru.edxp.util.Hookers;
|
||||
|
||||
import de.robv.android.xposed.XC_MethodHook;
|
||||
import de.robv.android.xposed.XC_MethodReplacement;
|
||||
import de.robv.android.xposed.XposedBridge;
|
||||
import de.robv.android.xposed.XposedHelpers;
|
||||
|
|
@ -15,15 +15,11 @@ import static com.elderdrivers.riru.edxp.util.ClassLoaderUtils.replaceParentClas
|
|||
import static com.elderdrivers.riru.edxp.util.Utils.logD;
|
||||
import static de.robv.android.xposed.XposedHelpers.findAndHookMethod;
|
||||
|
||||
public class StartBootstrapServicesHooker implements KeepMembers {
|
||||
public static String className = "com.android.server.SystemServer";
|
||||
public static String methodName = "startBootstrapServices";
|
||||
public static String methodSig = "()V";
|
||||
|
||||
public static void hook(Object systemServer) {
|
||||
public class StartBootstrapServices extends XC_MethodHook {
|
||||
|
||||
@Override
|
||||
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
|
||||
if (XposedBridge.disableHooks) {
|
||||
backup(systemServer);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -32,35 +28,33 @@ public class StartBootstrapServicesHooker implements KeepMembers {
|
|||
try {
|
||||
XposedInit.loadedPackagesInProcess.add("android");
|
||||
|
||||
replaceParentClassLoader(SystemMainHooker.systemServerCL);
|
||||
replaceParentClassLoader(SystemMain.systemServerCL);
|
||||
|
||||
XC_LoadPackage.LoadPackageParam lpparam = new XC_LoadPackage.LoadPackageParam(XposedBridge.sLoadedPackageCallbacks);
|
||||
lpparam.packageName = "android";
|
||||
lpparam.processName = "android"; // it's actually system_server, but other functions return this as well
|
||||
lpparam.classLoader = SystemMainHooker.systemServerCL;
|
||||
lpparam.classLoader = SystemMain.systemServerCL;
|
||||
lpparam.appInfo = null;
|
||||
lpparam.isFirstApplication = true;
|
||||
XC_LoadPackage.callAll(lpparam);
|
||||
|
||||
// Huawei
|
||||
try {
|
||||
findAndHookMethod("com.android.server.pm.HwPackageManagerService", SystemMainHooker.systemServerCL, "isOdexMode", XC_MethodReplacement.returnConstant(false));
|
||||
findAndHookMethod("com.android.server.pm.HwPackageManagerService",
|
||||
SystemMain.systemServerCL, "isOdexMode",
|
||||
XC_MethodReplacement.returnConstant(false));
|
||||
} catch (XposedHelpers.ClassNotFoundError | NoSuchMethodError ignored) {
|
||||
}
|
||||
|
||||
try {
|
||||
String className = "com.android.server.pm." + (Build.VERSION.SDK_INT >= 23 ? "PackageDexOptimizer" : "PackageManagerService");
|
||||
findAndHookMethod(className, SystemMainHooker.systemServerCL, "dexEntryExists", String.class, XC_MethodReplacement.returnConstant(true));
|
||||
findAndHookMethod(className, SystemMain.systemServerCL,
|
||||
"dexEntryExists", String.class,
|
||||
XC_MethodReplacement.returnConstant(true));
|
||||
} catch (XposedHelpers.ClassNotFoundError | NoSuchMethodError ignored) {
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
Router.logE("error when hooking startBootstrapServices", t);
|
||||
} finally {
|
||||
backup(systemServer);
|
||||
Hookers.logE("error when hooking startBootstrapServices", t);
|
||||
}
|
||||
}
|
||||
|
||||
public static void backup(Object systemServer) {
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
package com.elderdrivers.riru.edxp._hooker.impl;
|
||||
|
||||
import com.elderdrivers.riru.edxp.core.Main;
|
||||
import com.elderdrivers.riru.edxp.deopt.PrebuiltMethodsDeopter;
|
||||
import com.elderdrivers.riru.edxp.util.Hookers;
|
||||
|
||||
import de.robv.android.xposed.XC_MethodHook;
|
||||
import de.robv.android.xposed.XposedBridge;
|
||||
|
||||
// system_server initialization
|
||||
// ed: only support sdk >= 21 for now
|
||||
public class SystemMain extends XC_MethodHook {
|
||||
|
||||
public static volatile ClassLoader systemServerCL;
|
||||
|
||||
@Override
|
||||
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
|
||||
if (XposedBridge.disableHooks) {
|
||||
return;
|
||||
}
|
||||
Hookers.logD("ActivityThread#systemMain() starts");
|
||||
try {
|
||||
// get system_server classLoader
|
||||
systemServerCL = Thread.currentThread().getContextClassLoader();
|
||||
// deopt methods in SYSTEMSERVERCLASSPATH
|
||||
PrebuiltMethodsDeopter.deoptSystemServerMethods(systemServerCL);
|
||||
Main.getEdxpImpl().getRouter().startSystemServerHook();
|
||||
} catch (Throwable t) {
|
||||
Hookers.logE("error when hooking systemMain", t);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
package com.elderdrivers.riru.edxp._hooker.yahfa;
|
||||
|
||||
import com.elderdrivers.riru.common.KeepMembers;
|
||||
import com.elderdrivers.riru.edxp._hooker.impl.HandleBindApp;
|
||||
|
||||
import de.robv.android.xposed.XC_MethodHook;
|
||||
|
||||
public class HandleBindAppHooker implements KeepMembers {
|
||||
|
||||
public static String className = "android.app.ActivityThread";
|
||||
public static String methodName = "handleBindApplication";
|
||||
public static String methodSig = "(Landroid/app/ActivityThread$AppBindData;)V";
|
||||
|
||||
public static void hook(final Object thiz, final Object bindData) throws Throwable {
|
||||
final XC_MethodHook methodHook = new HandleBindApp();
|
||||
final XC_MethodHook.MethodHookParam param = new XC_MethodHook.MethodHookParam();
|
||||
param.thisObject = thiz;
|
||||
param.args = new Object[]{bindData};
|
||||
methodHook.callBeforeHookedMethod(param);
|
||||
if (!param.returnEarly) {
|
||||
backup(thiz, bindData);
|
||||
}
|
||||
methodHook.callAfterHookedMethod(param);
|
||||
}
|
||||
|
||||
public static void backup(Object thiz, Object bindData) {
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
package com.elderdrivers.riru.edxp._hooker.yahfa;
|
||||
|
||||
import android.app.ActivityThread;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.res.CompatibilityInfo;
|
||||
|
||||
import com.elderdrivers.riru.common.KeepMembers;
|
||||
import com.elderdrivers.riru.edxp._hooker.impl.LoadedApkCstr;
|
||||
|
||||
import de.robv.android.xposed.XC_MethodHook;
|
||||
|
||||
public class LoadedApkConstructorHooker implements KeepMembers {
|
||||
public static String className = "android.app.LoadedApk";
|
||||
public static String methodName = "<init>";
|
||||
public static String methodSig = "(Landroid/app/ActivityThread;" +
|
||||
"Landroid/content/pm/ApplicationInfo;" +
|
||||
"Landroid/content/res/CompatibilityInfo;" +
|
||||
"Ljava/lang/ClassLoader;ZZZ)V";
|
||||
|
||||
public static void hook(Object thiz, ActivityThread activityThread,
|
||||
ApplicationInfo aInfo, CompatibilityInfo compatInfo,
|
||||
ClassLoader baseLoader, boolean securityViolation,
|
||||
boolean includeCode, boolean registerPackage) throws Throwable {
|
||||
|
||||
final XC_MethodHook methodHook = new LoadedApkCstr();
|
||||
final XC_MethodHook.MethodHookParam param = new XC_MethodHook.MethodHookParam();
|
||||
param.thisObject = thiz;
|
||||
param.args = new Object[]{activityThread, aInfo, compatInfo, baseLoader, securityViolation,
|
||||
includeCode, registerPackage};
|
||||
methodHook.callBeforeHookedMethod(param);
|
||||
if (!param.returnEarly) {
|
||||
backup(thiz, activityThread, aInfo, compatInfo, baseLoader, securityViolation,
|
||||
includeCode, registerPackage);
|
||||
}
|
||||
methodHook.callAfterHookedMethod(param);
|
||||
}
|
||||
|
||||
public static void backup(Object thiz, ActivityThread activityThread,
|
||||
ApplicationInfo aInfo, CompatibilityInfo compatInfo,
|
||||
ClassLoader baseLoader, boolean securityViolation,
|
||||
boolean includeCode, boolean registerPackage) {
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
package com.elderdrivers.riru.edxp._hooker.yahfa;
|
||||
|
||||
import com.elderdrivers.riru.common.KeepMembers;
|
||||
import com.elderdrivers.riru.edxp._hooker.impl.OneplusWorkaround;
|
||||
import com.elderdrivers.riru.edxp.core.yahfa.HookMain;
|
||||
|
||||
import de.robv.android.xposed.XC_MethodHook;
|
||||
|
||||
public class OnePlusWorkAroundHooker implements KeepMembers {
|
||||
|
||||
static {
|
||||
HookMain.addHookItemWhiteList(OnePlusWorkAroundHooker.class.getName());
|
||||
}
|
||||
|
||||
public static String className = "dalvik.system.BaseDexClassLoader";
|
||||
public static String methodName = "inCompatConfigList";
|
||||
public static String methodSig = "(ILjava/lang/String;)Z";
|
||||
|
||||
public static boolean hook(int type, String packageName) throws Throwable {
|
||||
final XC_MethodHook methodHook = new OneplusWorkaround();
|
||||
final XC_MethodHook.MethodHookParam param = new XC_MethodHook.MethodHookParam();
|
||||
param.thisObject = null;
|
||||
param.args = new Object[]{type, packageName};
|
||||
methodHook.callBeforeHookedMethod(param);
|
||||
if (!param.returnEarly) {
|
||||
param.setResult(backup(type, packageName));
|
||||
}
|
||||
methodHook.callAfterHookedMethod(param);
|
||||
return (boolean) param.getResult();
|
||||
}
|
||||
|
||||
public static boolean backup(int type, String packageName) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
package com.elderdrivers.riru.edxp._hooker.yahfa;
|
||||
|
||||
import com.elderdrivers.riru.common.KeepMembers;
|
||||
import com.elderdrivers.riru.edxp._hooker.impl.StartBootstrapServices;
|
||||
|
||||
import de.robv.android.xposed.XC_MethodHook;
|
||||
|
||||
public class StartBootstrapServicesHooker implements KeepMembers {
|
||||
public static String className = "com.android.server.SystemServer";
|
||||
public static String methodName = "startBootstrapServices";
|
||||
public static String methodSig = "()V";
|
||||
|
||||
public static void hook(Object systemServer) throws Throwable {
|
||||
final XC_MethodHook methodHook = new StartBootstrapServices();
|
||||
final XC_MethodHook.MethodHookParam param = new XC_MethodHook.MethodHookParam();
|
||||
param.thisObject = systemServer;
|
||||
param.args = new Object[]{};
|
||||
methodHook.callBeforeHookedMethod(param);
|
||||
if (!param.returnEarly) {
|
||||
backup(systemServer);
|
||||
}
|
||||
methodHook.callAfterHookedMethod(param);
|
||||
}
|
||||
|
||||
public static void backup(Object systemServer) {
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
package com.elderdrivers.riru.edxp._hooker.yahfa;
|
||||
|
||||
import android.app.ActivityThread;
|
||||
|
||||
import com.elderdrivers.riru.common.KeepMembers;
|
||||
import com.elderdrivers.riru.edxp._hooker.impl.OneplusWorkaround;
|
||||
|
||||
import de.robv.android.xposed.XC_MethodHook;
|
||||
|
||||
public class SystemMainHooker implements KeepMembers {
|
||||
|
||||
public static String className = "android.app.ActivityThread";
|
||||
public static String methodName = "systemMain";
|
||||
public static String methodSig = "()Landroid/app/ActivityThread;";
|
||||
|
||||
public static ClassLoader systemServerCL;
|
||||
|
||||
public static ActivityThread hook() throws Throwable {
|
||||
final XC_MethodHook methodHook = new OneplusWorkaround();
|
||||
final XC_MethodHook.MethodHookParam param = new XC_MethodHook.MethodHookParam();
|
||||
param.thisObject = null;
|
||||
param.args = new Object[]{};
|
||||
methodHook.callBeforeHookedMethod(param);
|
||||
if (!param.returnEarly) {
|
||||
param.setResult(backup());
|
||||
}
|
||||
methodHook.callAfterHookedMethod(param);
|
||||
return (ActivityThread) param.getResult();
|
||||
}
|
||||
|
||||
public static ActivityThread backup() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,27 +1,19 @@
|
|||
package com.elderdrivers.riru.edxp.config;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Set;
|
||||
|
||||
import de.robv.android.xposed.SELinuxHelper;
|
||||
|
||||
import static com.elderdrivers.riru.edxp.config.InstallerChooser.INSTALLER_DATA_BASE_DIR;
|
||||
import static com.elderdrivers.riru.edxp.config.InstallerChooser.INSTALLER_PACKAGE_NAME;
|
||||
|
||||
public class ConfigManager {
|
||||
|
||||
private static final String BLACK_LIST_PATH = INSTALLER_DATA_BASE_DIR + "conf/blacklist/";
|
||||
private static final String WHITE_LIST_PATH = INSTALLER_DATA_BASE_DIR + "conf/whitelist/";
|
||||
private static final String COMPAT_LIST_PATH = INSTALLER_DATA_BASE_DIR + "conf/compatlist/";
|
||||
private static final String USE_WHITE_LIST = INSTALLER_DATA_BASE_DIR + "conf/usewhitelist";
|
||||
private static final String DYNAMIC_MODULES = INSTALLER_DATA_BASE_DIR + "conf/dynamicmodules";
|
||||
private static final Set<String> WHITE_LIST = Collections.singleton(INSTALLER_PACKAGE_NAME);
|
||||
private static final HashMap<String, Boolean> compatModeCache = new HashMap<>();
|
||||
public static String appDataDir = "";
|
||||
public static String niceName = "";
|
||||
public static String appProcessName = "";
|
||||
|
||||
public static boolean shouldUseWhitelist() {
|
||||
return isFileExists(USE_WHITE_LIST);
|
||||
}
|
||||
private static final String COMPAT_LIST_PATH = INSTALLER_DATA_BASE_DIR + "conf/compatlist/";
|
||||
private static final HashMap<String, Boolean> compatModeCache = new HashMap<>();
|
||||
|
||||
public static boolean shouldUseCompatMode(String packageName) {
|
||||
Boolean result;
|
||||
|
|
@ -34,17 +26,6 @@ public class ConfigManager {
|
|||
return result;
|
||||
}
|
||||
|
||||
public static boolean shouldHook(String packageName) {
|
||||
if (WHITE_LIST.contains(packageName)) {
|
||||
return true;
|
||||
}
|
||||
if (shouldUseWhitelist()) {
|
||||
return isFileExists(WHITE_LIST_PATH + packageName);
|
||||
} else {
|
||||
return !isFileExists(BLACK_LIST_PATH + packageName);
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isFileExists(String path) {
|
||||
return SELinuxHelper.getAppDataFileService().checkFileExists(path);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,62 @@
|
|||
package com.elderdrivers.riru.edxp.core;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.elderdrivers.riru.edxp.proxy.BlackWhiteListProxy;
|
||||
import com.elderdrivers.riru.edxp.proxy.NormalProxy;
|
||||
import com.elderdrivers.riru.edxp.proxy.Router;
|
||||
|
||||
public abstract class BaseEdxpImpl implements EdxpImpl {
|
||||
|
||||
protected Proxy mBlackWhiteListProxy;
|
||||
protected Proxy mNormalProxy;
|
||||
protected Router mRouter;
|
||||
|
||||
protected boolean mInitialized = false;
|
||||
|
||||
protected void setInitialized() {
|
||||
mInitialized = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInitialized() {
|
||||
return mInitialized;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Proxy getBlackWhiteListProxy() {
|
||||
if (mBlackWhiteListProxy == null) {
|
||||
mBlackWhiteListProxy = createBlackWhiteListProxy();
|
||||
}
|
||||
return mBlackWhiteListProxy;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Proxy getNormalProxy() {
|
||||
if (mNormalProxy == null) {
|
||||
mNormalProxy = createNormalProxy();
|
||||
}
|
||||
return mNormalProxy;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Router getRouter() {
|
||||
if (mRouter == null) {
|
||||
mRouter = createRouter();
|
||||
}
|
||||
return mRouter;
|
||||
}
|
||||
|
||||
protected Proxy createBlackWhiteListProxy() {
|
||||
return new BlackWhiteListProxy(getRouter());
|
||||
}
|
||||
|
||||
protected Proxy createNormalProxy() {
|
||||
return new NormalProxy(getRouter());
|
||||
}
|
||||
|
||||
protected abstract Router createRouter();
|
||||
}
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
package com.elderdrivers.riru.edxp.core;
|
||||
|
||||
import androidx.annotation.IntDef;
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.elderdrivers.riru.common.KeepAll;
|
||||
import com.elderdrivers.riru.edxp.proxy.Router;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
|
||||
import static java.lang.annotation.RetentionPolicy.SOURCE;
|
||||
|
||||
public interface EdxpImpl extends KeepAll {
|
||||
|
||||
int NONE = 0;
|
||||
int YAHFA = 1;
|
||||
int SANDHOOK = 2;
|
||||
int WHALE = 3;
|
||||
|
||||
@NonNull
|
||||
Proxy getNormalProxy();
|
||||
|
||||
@NonNull
|
||||
Proxy getBlackWhiteListProxy();
|
||||
|
||||
@NonNull
|
||||
Router getRouter();
|
||||
|
||||
@Variant
|
||||
int getVariant();
|
||||
|
||||
void init();
|
||||
|
||||
boolean isInitialized();
|
||||
|
||||
@Retention(SOURCE)
|
||||
@IntDef({NONE, YAHFA, SANDHOOK, WHALE})
|
||||
@interface Variant {
|
||||
}
|
||||
}
|
||||
|
|
@ -1,44 +1,30 @@
|
|||
package com.elderdrivers.riru.edxp;
|
||||
package com.elderdrivers.riru.edxp.core;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.os.Build;
|
||||
import android.os.Process;
|
||||
|
||||
import com.elderdrivers.riru.common.KeepAll;
|
||||
import com.elderdrivers.riru.edxp.BuildConfig;
|
||||
import com.elderdrivers.riru.edxp.config.ConfigManager;
|
||||
import com.elderdrivers.riru.edxp.config.InstallerChooser;
|
||||
import com.elderdrivers.riru.edxp.core.Yahfa;
|
||||
import com.elderdrivers.riru.edxp.sandhook.BuildConfig;
|
||||
import com.elderdrivers.riru.edxp.sandhook.core.HookMethodResolver;
|
||||
import com.elderdrivers.riru.edxp.sandhook.entry.Router;
|
||||
import com.elderdrivers.riru.edxp.sandhook.proxy.BlackWhiteListProxy;
|
||||
import com.elderdrivers.riru.edxp.sandhook.proxy.NormalProxy;
|
||||
import com.elderdrivers.riru.edxp.util.Utils;
|
||||
import com.swift.sandhook.xposedcompat.XposedCompat;
|
||||
import com.swift.sandhook.xposedcompat.methodgen.SandHookXposedBridge;
|
||||
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.util.Arrays;
|
||||
import java.util.Iterator;
|
||||
import java.util.ServiceLoader;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
@SuppressLint("DefaultLocale")
|
||||
public class Main implements KeepAll {
|
||||
|
||||
public static String appDataDir = "";
|
||||
public static String niceName = "";
|
||||
public static String appProcessName = "";
|
||||
private static String forkAndSpecializePramsStr = "";
|
||||
private static String forkSystemServerPramsStr = "";
|
||||
|
||||
static {
|
||||
Yahfa.init(Build.VERSION.SDK_INT);
|
||||
HookMethodResolver.init();
|
||||
Router.injectConfig();
|
||||
InstallerChooser.setInstallerPackageName(ConfigManager.getInstallerPackageName());
|
||||
SandHookXposedBridge.init();
|
||||
}
|
||||
private static final AtomicReference<EdxpImpl> edxpImplRef = new AtomicReference<>(null);
|
||||
|
||||
public static void setAppDataDir(String appDataDir) {
|
||||
Main.appDataDir = appDataDir;
|
||||
XposedCompat.appDataDir = appDataDir;
|
||||
static {
|
||||
loadEdxpImpls();
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -50,6 +36,10 @@ public class Main implements KeepAll {
|
|||
String niceName, int[] fdsToClose, int[] fdsToIgnore,
|
||||
boolean startChildZygote, String instructionSet,
|
||||
String appDataDir) {
|
||||
final EdxpImpl edxp = getEdxpImpl();
|
||||
if (edxp == null || !edxp.isInitialized()) {
|
||||
return;
|
||||
}
|
||||
if (BuildConfig.DEBUG) {
|
||||
forkAndSpecializePramsStr = String.format(
|
||||
"Zygote#forkAndSpecialize(%d, %d, %s, %d, %s, %d, %s, %s, %s, %s, %s, %s, %s)",
|
||||
|
|
@ -57,24 +47,29 @@ public class Main implements KeepAll {
|
|||
mountExternal, seInfo, niceName, Arrays.toString(fdsToClose),
|
||||
Arrays.toString(fdsToIgnore), startChildZygote, instructionSet, appDataDir);
|
||||
}
|
||||
|
||||
if (ConfigManager.isBlackWhiteListEnabled()) {
|
||||
BlackWhiteListProxy.forkAndSpecializePre(uid, gid, gids, debugFlags, rlimits,
|
||||
edxp.getBlackWhiteListProxy().forkAndSpecializePre(uid, gid, gids, debugFlags, rlimits,
|
||||
mountExternal, seInfo, niceName, fdsToClose, fdsToIgnore, startChildZygote,
|
||||
instructionSet, appDataDir);
|
||||
} else {
|
||||
NormalProxy.forkAndSpecializePre(uid, gid, gids, debugFlags, rlimits, mountExternal,
|
||||
edxp.getNormalProxy().forkAndSpecializePre(uid, gid, gids, debugFlags, rlimits, mountExternal,
|
||||
seInfo, niceName, fdsToClose, fdsToIgnore, startChildZygote, instructionSet,
|
||||
appDataDir);
|
||||
}
|
||||
}
|
||||
|
||||
public static void forkAndSpecializePost(int pid, String appDataDir, String niceName) {
|
||||
final EdxpImpl edxp = getEdxpImpl();
|
||||
if (edxp == null || !edxp.isInitialized()) {
|
||||
return;
|
||||
}
|
||||
if (pid == 0) {
|
||||
Utils.logD(forkAndSpecializePramsStr + " = " + Process.myPid());
|
||||
if (ConfigManager.isBlackWhiteListEnabled()) {
|
||||
BlackWhiteListProxy.forkAndSpecializePost(pid, appDataDir, niceName);
|
||||
edxp.getBlackWhiteListProxy().forkAndSpecializePost(pid, appDataDir, niceName);
|
||||
} else {
|
||||
NormalProxy.forkAndSpecializePost(pid, appDataDir, niceName);
|
||||
edxp.getNormalProxy().forkAndSpecializePost(pid, appDataDir, niceName);
|
||||
}
|
||||
} else {
|
||||
// in zygote process, res is child zygote pid
|
||||
|
|
@ -84,27 +79,35 @@ public class Main implements KeepAll {
|
|||
|
||||
public static void forkSystemServerPre(int uid, int gid, int[] gids, int debugFlags, int[][] rlimits,
|
||||
long permittedCapabilities, long effectiveCapabilities) {
|
||||
final EdxpImpl edxp = getEdxpImpl();
|
||||
if (edxp == null || !edxp.isInitialized()) {
|
||||
return;
|
||||
}
|
||||
if (BuildConfig.DEBUG) {
|
||||
forkSystemServerPramsStr = String.format("Zygote#forkSystemServer(%d, %d, %s, %d, %s, %d, %d)",
|
||||
uid, gid, Arrays.toString(gids), debugFlags, Arrays.toString(rlimits),
|
||||
permittedCapabilities, effectiveCapabilities);
|
||||
}
|
||||
if (ConfigManager.isBlackWhiteListEnabled()) {
|
||||
BlackWhiteListProxy.forkSystemServerPre(uid, gid, gids, debugFlags, rlimits,
|
||||
edxp.getBlackWhiteListProxy().forkSystemServerPre(uid, gid, gids, debugFlags, rlimits,
|
||||
permittedCapabilities, effectiveCapabilities);
|
||||
} else {
|
||||
NormalProxy.forkSystemServerPre(uid, gid, gids, debugFlags, rlimits,
|
||||
edxp.getNormalProxy().forkSystemServerPre(uid, gid, gids, debugFlags, rlimits,
|
||||
permittedCapabilities, effectiveCapabilities);
|
||||
}
|
||||
}
|
||||
|
||||
public static void forkSystemServerPost(int pid) {
|
||||
final EdxpImpl edxp = getEdxpImpl();
|
||||
if (edxp == null || !edxp.isInitialized()) {
|
||||
return;
|
||||
}
|
||||
if (pid == 0) {
|
||||
Utils.logD(forkSystemServerPramsStr + " = " + Process.myPid());
|
||||
if (ConfigManager.isBlackWhiteListEnabled()) {
|
||||
BlackWhiteListProxy.forkSystemServerPost(pid);
|
||||
edxp.getBlackWhiteListProxy().forkSystemServerPost(pid);
|
||||
} else {
|
||||
NormalProxy.forkSystemServerPost(pid);
|
||||
edxp.getNormalProxy().forkSystemServerPost(pid);
|
||||
}
|
||||
} else {
|
||||
// in zygote process, res is child zygote pid
|
||||
|
|
@ -112,4 +115,29 @@ public class Main implements KeepAll {
|
|||
}
|
||||
}
|
||||
|
||||
public static synchronized boolean setEdxpImpl(EdxpImpl edxp) {
|
||||
return edxpImplRef.compareAndSet(null, edxp);
|
||||
}
|
||||
|
||||
public static synchronized EdxpImpl getEdxpImpl() {
|
||||
return edxpImplRef.get();
|
||||
}
|
||||
|
||||
private static void loadEdxpImpls() {
|
||||
AccessController.doPrivileged(new PrivilegedAction<Void>() {
|
||||
public Void run() {
|
||||
Iterator<EdxpImpl> iterator = ServiceLoader.load(
|
||||
EdxpImpl.class, Main.class.getClassLoader()).iterator();
|
||||
try {
|
||||
while (iterator.hasNext()) {
|
||||
iterator.next();
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
// Do nothing
|
||||
}
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
package com.elderdrivers.riru.edxp.core;
|
||||
|
||||
import com.elderdrivers.riru.common.KeepAll;
|
||||
|
||||
public interface Proxy extends KeepAll {
|
||||
|
||||
boolean init();
|
||||
|
||||
void forkAndSpecializePre(int uid, int gid, int[] gids, int debugFlags,
|
||||
int[][] rlimits, int mountExternal, String seInfo,
|
||||
String niceName, int[] fdsToClose, int[] fdsToIgnore,
|
||||
boolean startChildZygote, String instructionSet,
|
||||
String appDataDir);
|
||||
|
||||
void forkAndSpecializePost(int pid, String appDataDir, String niceName);
|
||||
|
||||
void forkSystemServerPre(int uid, int gid, int[] gids, int debugFlags, int[][] rlimits,
|
||||
long permittedCapabilities, long effectiveCapabilities);
|
||||
|
||||
void forkSystemServerPost(int pid);
|
||||
}
|
||||
|
|
@ -1,23 +1,26 @@
|
|||
package com.elderdrivers.riru.edxp.yahfa.core;
|
||||
package com.elderdrivers.riru.edxp.core.yahfa;
|
||||
|
||||
import com.elderdrivers.riru.edxp.art.Heap;
|
||||
import com.elderdrivers.riru.edxp.core.Yahfa;
|
||||
import com.elderdrivers.riru.edxp.util.Utils;
|
||||
import com.elderdrivers.riru.edxp.yahfa._hooker.OnePlusWorkAroundHooker;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import de.robv.android.xposed.XposedHelpers;
|
||||
|
||||
public class HookMain {
|
||||
|
||||
private static Set<String> hookItemWhiteList = Collections.singleton(OnePlusWorkAroundHooker.class.getName());
|
||||
private static final Set<String> hookItemWhiteList = new HashSet<String>();
|
||||
|
||||
public static void addHookItemWhiteList(String className) {
|
||||
hookItemWhiteList.add(className);
|
||||
}
|
||||
|
||||
public static void doHookDefault(ClassLoader patchClassLoader, ClassLoader originClassLoader, String hookInfoClassName) {
|
||||
try {
|
||||
|
|
@ -1,8 +1,7 @@
|
|||
package com.elderdrivers.riru.edxp.whale.core;
|
||||
package com.elderdrivers.riru.edxp.core.yahfa;
|
||||
|
||||
import android.os.Build;
|
||||
|
||||
import com.elderdrivers.riru.edxp.Main;
|
||||
import com.elderdrivers.riru.edxp.core.Yahfa;
|
||||
import com.elderdrivers.riru.edxp.util.Utils;
|
||||
|
||||
|
|
@ -113,12 +112,12 @@ public class HookMethodResolver {
|
|||
Object artMethod = artMethodField.get(backup);
|
||||
int dexMethodIndex = (int) dexMethodIndexField.get(artMethod);
|
||||
Object resolvedMethods = resolvedMethodsField.get(dexCache);
|
||||
((Object[])resolvedMethods)[dexMethodIndex] = artMethod;
|
||||
((Object[]) resolvedMethods)[dexMethodIndex] = artMethod;
|
||||
} else {
|
||||
int dexMethodIndex = (int) dexMethodIndexField.get(backup);
|
||||
Object resolvedMethods = resolvedMethodsField.get(dexCache);
|
||||
long artMethod = (long) artMethodField.get(backup);
|
||||
((long[])resolvedMethods)[dexMethodIndex] = artMethod;
|
||||
((long[]) resolvedMethods)[dexMethodIndex] = artMethod;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
package com.elderdrivers.riru.edxp.entry;
|
||||
|
||||
public interface Hook {
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
package com.elderdrivers.riru.edxp.entry;
|
||||
|
||||
public class HookImpl<T> implements Hook {
|
||||
|
||||
}
|
||||
|
|
@ -1,9 +1,9 @@
|
|||
package com.elderdrivers.riru.edxp.whale.entry.bootstrap;
|
||||
package com.elderdrivers.riru.edxp.entry.yahfa;
|
||||
|
||||
import com.elderdrivers.riru.common.KeepMembers;
|
||||
import com.elderdrivers.riru.edxp.whale._hooker.HandleBindAppHooker;
|
||||
import com.elderdrivers.riru.edxp.whale._hooker.LoadedApkConstructorHooker;
|
||||
import com.elderdrivers.riru.edxp.whale._hooker.OnePlusWorkAroundHooker;
|
||||
import com.elderdrivers.riru.edxp._hooker.yahfa.HandleBindAppHooker;
|
||||
import com.elderdrivers.riru.edxp._hooker.yahfa.LoadedApkConstructorHooker;
|
||||
import com.elderdrivers.riru.edxp._hooker.yahfa.OnePlusWorkAroundHooker;
|
||||
|
||||
public class AppBootstrapHookInfo implements KeepMembers {
|
||||
public static String[] hookItemNames = {
|
||||
|
|
@ -1,10 +1,10 @@
|
|||
package com.elderdrivers.riru.edxp.yahfa.entry.bootstrap;
|
||||
package com.elderdrivers.riru.edxp.entry.yahfa;
|
||||
|
||||
import com.elderdrivers.riru.common.KeepMembers;
|
||||
import com.elderdrivers.riru.edxp.yahfa._hooker.HandleBindAppHooker;
|
||||
import com.elderdrivers.riru.edxp.yahfa._hooker.LoadedApkConstructorHooker;
|
||||
import com.elderdrivers.riru.edxp.yahfa._hooker.OnePlusWorkAroundHooker;
|
||||
import com.elderdrivers.riru.edxp.yahfa._hooker.SystemMainHooker;
|
||||
import com.elderdrivers.riru.edxp._hooker.yahfa.HandleBindAppHooker;
|
||||
import com.elderdrivers.riru.edxp._hooker.yahfa.LoadedApkConstructorHooker;
|
||||
import com.elderdrivers.riru.edxp._hooker.yahfa.OnePlusWorkAroundHooker;
|
||||
import com.elderdrivers.riru.edxp._hooker.yahfa.SystemMainHooker;
|
||||
|
||||
public class SysBootstrapHookInfo implements KeepMembers {
|
||||
public static String[] hookItemNames = {
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
package com.elderdrivers.riru.edxp.yahfa.entry.bootstrap;
|
||||
package com.elderdrivers.riru.edxp.entry.yahfa;
|
||||
|
||||
import com.elderdrivers.riru.common.KeepMembers;
|
||||
import com.elderdrivers.riru.edxp.yahfa._hooker.StartBootstrapServicesHooker;
|
||||
import com.elderdrivers.riru.edxp._hooker.yahfa.StartBootstrapServicesHooker;
|
||||
|
||||
public class SysInnerHookInfo implements KeepMembers {
|
||||
public static String[] hookItemNames = {
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
package com.elderdrivers.riru.edxp.whale.entry.bootstrap;
|
||||
package com.elderdrivers.riru.edxp.entry.yahfa;
|
||||
|
||||
import com.elderdrivers.riru.common.KeepMembers;
|
||||
import com.elderdrivers.riru.edxp.whale._hooker.OnePlusWorkAroundHooker;
|
||||
import com.elderdrivers.riru.edxp._hooker.yahfa.OnePlusWorkAroundHooker;
|
||||
|
||||
public class WorkAroundHookInfo implements KeepMembers {
|
||||
public static String[] hookItemNames = {
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
package com.elderdrivers.riru.edxp.proxy;
|
||||
|
||||
import com.elderdrivers.riru.edxp.core.Proxy;
|
||||
|
||||
public abstract class BaseProxy implements Proxy {
|
||||
|
||||
protected Router mRouter;
|
||||
|
||||
public BaseProxy(Router router) {
|
||||
mRouter = router;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean init() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,110 @@
|
|||
package com.elderdrivers.riru.edxp.proxy;
|
||||
|
||||
import android.text.TextUtils;
|
||||
|
||||
import com.elderdrivers.riru.edxp._hooker.yahfa.SystemMainHooker;
|
||||
import com.elderdrivers.riru.edxp.core.yahfa.HookMain;
|
||||
import com.elderdrivers.riru.edxp.entry.yahfa.AppBootstrapHookInfo;
|
||||
import com.elderdrivers.riru.edxp.entry.yahfa.SysBootstrapHookInfo;
|
||||
import com.elderdrivers.riru.edxp.entry.yahfa.SysInnerHookInfo;
|
||||
import com.elderdrivers.riru.edxp.entry.yahfa.WorkAroundHookInfo;
|
||||
import com.elderdrivers.riru.edxp.util.Utils;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import de.robv.android.xposed.XposedBridge;
|
||||
import de.robv.android.xposed.XposedInit;
|
||||
|
||||
public abstract class BaseRouter implements Router {
|
||||
|
||||
protected volatile boolean forkCompleted = false;
|
||||
|
||||
protected volatile AtomicBoolean bootstrapHooked = new AtomicBoolean(false);
|
||||
|
||||
public void initResourcesHook() {
|
||||
startWorkAroundHook(); // for OnePlus devices
|
||||
XposedBridge.initXResources();
|
||||
}
|
||||
|
||||
public void prepare(boolean isSystem) {
|
||||
// this flag is needed when loadModules
|
||||
XposedInit.startsSystemServer = isSystem;
|
||||
}
|
||||
|
||||
public void onForkStart() {
|
||||
forkCompleted = false;
|
||||
}
|
||||
|
||||
public void onForkFinish() {
|
||||
forkCompleted = true;
|
||||
}
|
||||
|
||||
public boolean isForkCompleted() {
|
||||
return forkCompleted;
|
||||
}
|
||||
|
||||
public void installBootstrapHooks(boolean isSystem) {
|
||||
// Initialize the Xposed framework
|
||||
try {
|
||||
if (!bootstrapHooked.compareAndSet(false, true)) {
|
||||
return;
|
||||
}
|
||||
startBootstrapHook(isSystem);
|
||||
XposedInit.initForZygote(isSystem);
|
||||
} catch (Throwable t) {
|
||||
Utils.logE("error during Xposed initialization", t);
|
||||
XposedBridge.disableHooks = true;
|
||||
}
|
||||
}
|
||||
|
||||
public void loadModulesSafely(boolean isInZygote) {
|
||||
try {
|
||||
// FIXME some coredomain app can't reading modules.list
|
||||
XposedInit.loadModules(isInZygote);
|
||||
} catch (Exception exception) {
|
||||
Utils.logE("error loading module list", exception);
|
||||
}
|
||||
}
|
||||
|
||||
public String parsePackageName(String appDataDir) {
|
||||
if (TextUtils.isEmpty(appDataDir)) {
|
||||
return "";
|
||||
}
|
||||
int lastIndex = appDataDir.lastIndexOf("/");
|
||||
if (lastIndex < 1) {
|
||||
return "";
|
||||
}
|
||||
return appDataDir.substring(lastIndex + 1);
|
||||
}
|
||||
|
||||
|
||||
public void startBootstrapHook(boolean isSystem) {
|
||||
Utils.logD("startBootstrapHook starts: isSystem = " + isSystem);
|
||||
ClassLoader classLoader = XposedBridge.BOOTCLASSLOADER;
|
||||
if (isSystem) {
|
||||
HookMain.doHookDefault(
|
||||
BaseRouter.class.getClassLoader(),
|
||||
classLoader,
|
||||
SysBootstrapHookInfo.class.getName());
|
||||
} else {
|
||||
HookMain.doHookDefault(
|
||||
BaseRouter.class.getClassLoader(),
|
||||
classLoader,
|
||||
AppBootstrapHookInfo.class.getName());
|
||||
}
|
||||
}
|
||||
|
||||
public void startSystemServerHook() {
|
||||
HookMain.doHookDefault(
|
||||
BaseRouter.class.getClassLoader(),
|
||||
SystemMainHooker.systemServerCL,
|
||||
SysInnerHookInfo.class.getName());
|
||||
}
|
||||
|
||||
public void startWorkAroundHook() {
|
||||
HookMain.doHookDefault(
|
||||
BaseRouter.class.getClassLoader(),
|
||||
XposedBridge.BOOTCLASSLOADER,
|
||||
WorkAroundHookInfo.class.getName());
|
||||
}
|
||||
}
|
||||
|
|
@ -1,14 +1,12 @@
|
|||
package com.elderdrivers.riru.edxp.whale.proxy;
|
||||
package com.elderdrivers.riru.edxp.proxy;
|
||||
|
||||
import android.text.TextUtils;
|
||||
|
||||
import com.elderdrivers.riru.edxp.Main;
|
||||
import com.elderdrivers.riru.edxp.config.ConfigManager;
|
||||
import com.elderdrivers.riru.edxp.deopt.PrebuiltMethodsDeopter;
|
||||
import com.elderdrivers.riru.edxp.framework.Zygote;
|
||||
import com.elderdrivers.riru.edxp.util.ProcessUtils;
|
||||
import com.elderdrivers.riru.edxp.util.Utils;
|
||||
import com.elderdrivers.riru.edxp.whale.entry.Router;
|
||||
|
||||
import de.robv.android.xposed.XposedBridge;
|
||||
|
||||
|
|
@ -33,13 +31,17 @@ import static com.elderdrivers.riru.edxp.util.FileUtils.getDataPathPrefix;
|
|||
* 2. Dynamic mode:
|
||||
* to be continued
|
||||
*/
|
||||
public class BlackWhiteListProxy {
|
||||
public class BlackWhiteListProxy extends BaseProxy {
|
||||
|
||||
public static void forkAndSpecializePre(int uid, int gid, int[] gids, int debugFlags,
|
||||
int[][] rlimits, int mountExternal, String seInfo,
|
||||
String niceName, int[] fdsToClose, int[] fdsToIgnore,
|
||||
boolean startChildZygote, String instructionSet,
|
||||
String appDataDir) {
|
||||
public BlackWhiteListProxy(Router router) {
|
||||
super(router);
|
||||
}
|
||||
|
||||
public void forkAndSpecializePre(int uid, int gid, int[] gids, int debugFlags,
|
||||
int[][] rlimits, int mountExternal, String seInfo,
|
||||
String niceName, int[] fdsToClose, int[] fdsToIgnore,
|
||||
boolean startChildZygote, String instructionSet,
|
||||
String appDataDir) {
|
||||
final boolean isDynamicModulesMode = ConfigManager.isDynamicModulesEnabled();
|
||||
if (isDynamicModulesMode) {
|
||||
// should never happen
|
||||
|
|
@ -49,13 +51,13 @@ public class BlackWhiteListProxy {
|
|||
onForkPreForNonDynamicMode(false);
|
||||
}
|
||||
|
||||
public static void forkAndSpecializePost(int pid, String appDataDir, String niceName) {
|
||||
public void forkAndSpecializePost(int pid, String appDataDir, String niceName) {
|
||||
onForkPostCommon(false, appDataDir, niceName);
|
||||
}
|
||||
|
||||
public static void forkSystemServerPre(int uid, int gid, int[] gids, int debugFlags,
|
||||
int[][] rlimits, long permittedCapabilities,
|
||||
long effectiveCapabilities) {
|
||||
public void forkSystemServerPre(int uid, int gid, int[] gids, int debugFlags,
|
||||
int[][] rlimits, long permittedCapabilities,
|
||||
long effectiveCapabilities) {
|
||||
final boolean isDynamicModulesMode = ConfigManager.isDynamicModulesEnabled();
|
||||
if (isDynamicModulesMode) {
|
||||
// should never happen
|
||||
|
|
@ -65,59 +67,59 @@ public class BlackWhiteListProxy {
|
|||
onForkPreForNonDynamicMode(true);
|
||||
}
|
||||
|
||||
public static void forkSystemServerPost(int pid) {
|
||||
public void forkSystemServerPost(int pid) {
|
||||
onForkPostCommon(true, getDataPathPrefix() + "android", "system_server");
|
||||
}
|
||||
|
||||
/**
|
||||
* Some details are different between main zygote and secondary zygote.
|
||||
*/
|
||||
private static void onForkPreForNonDynamicMode(boolean isSystemServer) {
|
||||
Router.onForkStart();
|
||||
Router.initResourcesHook();
|
||||
private void onForkPreForNonDynamicMode(boolean isSystemServer) {
|
||||
mRouter.onForkStart();
|
||||
mRouter.initResourcesHook();
|
||||
// set startsSystemServer flag used when loadModules
|
||||
Router.prepare(isSystemServer);
|
||||
mRouter.prepare(isSystemServer);
|
||||
// deoptBootMethods once for all child processes of zygote
|
||||
PrebuiltMethodsDeopter.deoptBootMethods();
|
||||
// we never install bootstrap hooks here in black/white list mode except workaround hooks
|
||||
// because installed hooks would be propagated to all child processes of zygote
|
||||
Router.startWorkAroundHook();
|
||||
mRouter.startWorkAroundHook();
|
||||
// loadModules once for all child processes of zygote
|
||||
// TODO maybe just save initZygote callbacks and call them when whitelisted process forked?
|
||||
Router.loadModulesSafely(true);
|
||||
mRouter.loadModulesSafely(true);
|
||||
Zygote.closeFilesBeforeFork();
|
||||
}
|
||||
|
||||
private static void onForkPostCommon(boolean isSystemServer, String appDataDir, String niceName) {
|
||||
Main.appDataDir = appDataDir;
|
||||
Main.niceName = niceName;
|
||||
private void onForkPostCommon(boolean isSystemServer, String appDataDir, String niceName) {
|
||||
ConfigManager.appDataDir = appDataDir;
|
||||
ConfigManager.niceName = niceName;
|
||||
final boolean isDynamicModulesMode = ConfigManager.isDynamicModulesEnabled();
|
||||
if (!isDynamicModulesMode) {
|
||||
Zygote.reopenFilesAfterFork();
|
||||
}
|
||||
Router.onEnterChildProcess();
|
||||
mRouter.onEnterChildProcess();
|
||||
if (!checkNeedHook(appDataDir, niceName)) {
|
||||
// if is blacklisted, just stop here
|
||||
Router.onForkFinish();
|
||||
mRouter.onForkFinish();
|
||||
return;
|
||||
}
|
||||
if (isDynamicModulesMode) {
|
||||
Router.initResourcesHook();
|
||||
mRouter.initResourcesHook();
|
||||
}
|
||||
Router.prepare(isSystemServer);
|
||||
mRouter.prepare(isSystemServer);
|
||||
PrebuiltMethodsDeopter.deoptBootMethods();
|
||||
Router.installBootstrapHooks(isSystemServer);
|
||||
mRouter.installBootstrapHooks(isSystemServer);
|
||||
if (isDynamicModulesMode) {
|
||||
Router.loadModulesSafely(false);
|
||||
mRouter.loadModulesSafely(false);
|
||||
}
|
||||
Router.onForkFinish();
|
||||
mRouter.onForkFinish();
|
||||
}
|
||||
|
||||
private static boolean checkNeedHook(String appDataDir, String niceName) {
|
||||
private boolean checkNeedHook(String appDataDir, String niceName) {
|
||||
boolean needHook;
|
||||
if (TextUtils.isEmpty(appDataDir)) {
|
||||
Utils.logE("niceName:" + niceName + ", procName:"
|
||||
+ ProcessUtils.getCurrentProcessName(Main.appProcessName) + ", appDataDir is null, blacklisted!");
|
||||
+ ProcessUtils.getCurrentProcessName(ConfigManager.appProcessName) + ", appDataDir is null, blacklisted!");
|
||||
needHook = false;
|
||||
} else {
|
||||
// FIXME some process cannot read app_data_file because of MLS, e.g. bluetooth
|
||||
|
|
@ -0,0 +1,75 @@
|
|||
package com.elderdrivers.riru.edxp.proxy;
|
||||
|
||||
import com.elderdrivers.riru.edxp.config.ConfigManager;
|
||||
import com.elderdrivers.riru.edxp.deopt.PrebuiltMethodsDeopter;
|
||||
import com.elderdrivers.riru.edxp.framework.Zygote;
|
||||
|
||||
import static com.elderdrivers.riru.edxp.util.FileUtils.getDataPathPrefix;
|
||||
|
||||
public class NormalProxy extends BaseProxy {
|
||||
|
||||
public NormalProxy(Router router) {
|
||||
super(router);
|
||||
}
|
||||
|
||||
public void forkAndSpecializePre(int uid, int gid, int[] gids, int debugFlags,
|
||||
int[][] rlimits, int mountExternal, String seInfo,
|
||||
String niceName, int[] fdsToClose, int[] fdsToIgnore,
|
||||
boolean startChildZygote, String instructionSet,
|
||||
String appDataDir) {
|
||||
// mainly for secondary zygote
|
||||
mRouter.onForkStart();
|
||||
mRouter.initResourcesHook();
|
||||
// call this to ensure the flag is set to false ASAP
|
||||
mRouter.prepare(false);
|
||||
PrebuiltMethodsDeopter.deoptBootMethods(); // do it once for secondary zygote
|
||||
// install bootstrap hooks for secondary zygote
|
||||
mRouter.installBootstrapHooks(false);
|
||||
// only load modules for secondary zygote
|
||||
mRouter.loadModulesSafely(true);
|
||||
Zygote.closeFilesBeforeFork();
|
||||
}
|
||||
|
||||
public void forkAndSpecializePost(int pid, String appDataDir, String niceName) {
|
||||
// TODO consider processes without forkAndSpecializePost called
|
||||
ConfigManager.appDataDir = appDataDir;
|
||||
ConfigManager.niceName = niceName;
|
||||
mRouter.prepare(false);
|
||||
Zygote.reopenFilesAfterFork();
|
||||
mRouter.onEnterChildProcess();
|
||||
// load modules for each app process on its forked if dynamic modules mode is on
|
||||
mRouter.loadModulesSafely(false);
|
||||
mRouter.onForkFinish();
|
||||
}
|
||||
|
||||
public void forkSystemServerPre(int uid, int gid, int[] gids, int debugFlags, int[][] rlimits,
|
||||
long permittedCapabilities, long effectiveCapabilities) {
|
||||
mRouter.onForkStart();
|
||||
mRouter.initResourcesHook();
|
||||
// set startsSystemServer flag used when loadModules
|
||||
mRouter.prepare(true);
|
||||
PrebuiltMethodsDeopter.deoptBootMethods(); // do it once for main zygote
|
||||
// install bootstrap hooks for main zygote as early as possible
|
||||
// in case we miss some processes not forked via forkAndSpecialize
|
||||
// for instance com.android.phone
|
||||
mRouter.installBootstrapHooks(true);
|
||||
// loadModules have to be executed in zygote even isDynamicModules is false
|
||||
// because if not global hooks installed in initZygote might not be
|
||||
// propagated to processes not forked via forkAndSpecialize
|
||||
mRouter.loadModulesSafely(true);
|
||||
Zygote.closeFilesBeforeFork();
|
||||
}
|
||||
|
||||
public void forkSystemServerPost(int pid) {
|
||||
// in system_server process
|
||||
ConfigManager.appDataDir = getDataPathPrefix() + "android";
|
||||
ConfigManager.niceName = "system_server";
|
||||
mRouter.prepare(true);
|
||||
Zygote.reopenFilesAfterFork();
|
||||
mRouter.onEnterChildProcess();
|
||||
// reload module list if dynamic mode is on
|
||||
mRouter.loadModulesSafely(false);
|
||||
mRouter.onForkFinish();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
package com.elderdrivers.riru.edxp.proxy;
|
||||
|
||||
public interface Router {
|
||||
|
||||
void initResourcesHook();
|
||||
|
||||
void prepare(boolean isSystem);
|
||||
|
||||
String parsePackageName(String appDataDir);
|
||||
|
||||
void installBootstrapHooks(boolean isSystem);
|
||||
|
||||
void loadModulesSafely(boolean isInZygote);
|
||||
|
||||
void startBootstrapHook(boolean isSystem);
|
||||
|
||||
void startSystemServerHook();
|
||||
|
||||
void startWorkAroundHook();
|
||||
|
||||
void onForkStart();
|
||||
|
||||
void onForkFinish();
|
||||
|
||||
void onEnterChildProcess();
|
||||
|
||||
void injectConfig();
|
||||
|
||||
boolean isForkCompleted();
|
||||
}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
package com.elderdrivers.riru.edxp.util;
|
||||
|
||||
import android.app.AndroidAppHelper;
|
||||
|
||||
public class Hookers {
|
||||
|
||||
public static void logD(String prefix) {
|
||||
Utils.logD(String.format("%s: pkg=%s, prc=%s", prefix, AndroidAppHelper.currentPackageName(),
|
||||
AndroidAppHelper.currentProcessName()));
|
||||
}
|
||||
|
||||
public static void logE(String prefix, Throwable throwable) {
|
||||
Utils.logE(String.format("%s: pkg=%s, prc=%s", prefix, AndroidAppHelper.currentPackageName(),
|
||||
AndroidAppHelper.currentProcessName()), throwable);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -3,10 +3,10 @@ import org.gradle.internal.os.OperatingSystem
|
|||
|
||||
apply plugin: 'com.android.library'
|
||||
|
||||
version "v0.4.3.0_alpha"
|
||||
version "v0.4.3.2_alpha"
|
||||
|
||||
ext {
|
||||
versionCode = "4300"
|
||||
versionCode = "4320"
|
||||
module_name = "EdXposed"
|
||||
jar_dest_dir = "${projectDir}/template_override/system/framework/"
|
||||
is_windows = OperatingSystem.current().isWindows()
|
||||
|
|
|
|||
|
|
@ -3,10 +3,15 @@
|
|||
|
||||
#include <jni.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void Java_lab_galaxy_yahfa_HookMain_init(JNIEnv *env, jclass clazz, jint sdkVersion);
|
||||
|
||||
jobject Java_lab_galaxy_yahfa_HookMain_findMethodNative(JNIEnv *env, jclass clazz,
|
||||
jclass targetClass, jstring methodName, jstring methodSig);
|
||||
jclass targetClass, jstring methodName,
|
||||
jstring methodSig);
|
||||
|
||||
jboolean Java_lab_galaxy_yahfa_HookMain_backupAndHookNative(JNIEnv *env, jclass clazz,
|
||||
jobject target, jobject hook,
|
||||
|
|
@ -18,6 +23,10 @@ void Java_lab_galaxy_yahfa_HookMain_ensureMethodCached(JNIEnv *env, jclass clazz
|
|||
|
||||
void setNonCompilable(void *method);
|
||||
|
||||
static void* getResolvedMethodsAddr(JNIEnv*, jobject);
|
||||
static void *getResolvedMethodsAddr(JNIEnv *, jobject);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // HOOK_MAIN_H
|
||||
|
|
@ -20,7 +20,7 @@ namespace edxp {
|
|||
static constexpr const char *kInjectDexPath = "/system/framework/edxp.jar:"
|
||||
"/system/framework/eddalvikdx.jar:"
|
||||
"/system/framework/eddexmaker.jar";
|
||||
static constexpr const char *kEntryClassName = "com.elderdrivers.riru.edxp.Main";
|
||||
static constexpr const char *kEntryClassName = "com.elderdrivers.riru.edxp.core.Main";
|
||||
static constexpr const char *kSandHookClassName = "com.swift.sandhook.SandHook";
|
||||
static constexpr const char *kSandHookNeverCallClassName = "com.swift.sandhook.ClassNeverCall";
|
||||
|
||||
|
|
|
|||
|
|
@ -1,9 +1,5 @@
|
|||
|
||||
extern "C"
|
||||
{
|
||||
#include "HookMain.h"
|
||||
}
|
||||
|
||||
#include <nativehelper/jni_macros.h>
|
||||
#include "jni.h"
|
||||
#include "native_util.h"
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#!/system/bin/sh
|
||||
|
||||
EDXP_VERSION="0.4.3.0_alpha (4300)"
|
||||
EDXP_VERSION="0.4.3.2_alpha (4320)"
|
||||
ANDROID_SDK=`getprop ro.build.version.sdk`
|
||||
BUILD_DESC=`getprop ro.build.description`
|
||||
PRODUCT=`getprop ro.build.product`
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ android {
|
|||
targetSdkVersion 28
|
||||
versionCode 1
|
||||
versionName "1.0"
|
||||
multiDexEnabled true
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
|
|
@ -61,7 +62,8 @@ afterEvaluate {
|
|||
|
||||
task("makeAndCopy${variantNameCapped}", type: Jar, dependsOn: "assemble${variantNameCapped}") {
|
||||
dependsOn tasks.getByPath(":edxp-common:copyCommonProperties")
|
||||
from "${buildDir}/intermediates/transforms/dexMerger/${variantNameLowered}/0/"
|
||||
from "${buildDir}/intermediates/transforms/dexMerger/${variantNameLowered}/0/",
|
||||
"${projectDir}/src/main/resources/"
|
||||
destinationDir file(myTemplatePath + "system/framework/")
|
||||
baseName "edxp"
|
||||
doLast {
|
||||
|
|
|
|||
|
|
@ -1,112 +0,0 @@
|
|||
package com.elderdrivers.riru.edxp.sandhook._hooker;
|
||||
|
||||
import android.app.ActivityThread;
|
||||
import android.app.LoadedApk;
|
||||
import android.content.ComponentName;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.res.CompatibilityInfo;
|
||||
|
||||
import com.elderdrivers.riru.common.KeepMembers;
|
||||
import com.elderdrivers.riru.edxp.Main;
|
||||
import com.elderdrivers.riru.edxp.hooker.SliceProviderFix;
|
||||
import com.elderdrivers.riru.edxp.hooker.XposedBlackListHooker;
|
||||
import com.elderdrivers.riru.edxp.hooker.XposedInstallerHooker;
|
||||
import com.elderdrivers.riru.edxp.sandhook.entry.Router;
|
||||
import com.elderdrivers.riru.edxp.util.Utils;
|
||||
import com.swift.sandhook.SandHook;
|
||||
import com.swift.sandhook.annotation.HookClass;
|
||||
import com.swift.sandhook.annotation.HookMethod;
|
||||
import com.swift.sandhook.annotation.HookMethodBackup;
|
||||
import com.swift.sandhook.annotation.Param;
|
||||
import com.swift.sandhook.annotation.SkipParamCheck;
|
||||
import com.swift.sandhook.annotation.ThisObject;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import de.robv.android.xposed.XposedBridge;
|
||||
import de.robv.android.xposed.XposedHelpers;
|
||||
import de.robv.android.xposed.XposedInit;
|
||||
import de.robv.android.xposed.callbacks.XC_LoadPackage;
|
||||
|
||||
import static com.elderdrivers.riru.edxp.config.InstallerChooser.INSTALLER_PACKAGE_NAME;
|
||||
import static com.elderdrivers.riru.edxp.hooker.SliceProviderFix.SYSTEMUI_PACKAGE_NAME;
|
||||
import static com.elderdrivers.riru.edxp.hooker.XposedBlackListHooker.BLACK_LIST_PACKAGE_NAME;
|
||||
import static com.elderdrivers.riru.edxp.util.ClassLoaderUtils.replaceParentClassLoader;
|
||||
|
||||
// normal process initialization (for new Activity, Service, BroadcastReceiver etc.)
|
||||
@HookClass(ActivityThread.class)
|
||||
public class HandleBindAppHooker implements KeepMembers {
|
||||
|
||||
public static String className = "android.app.ActivityThread";
|
||||
public static String methodName = "handleBindApplication";
|
||||
public static String methodSig = "(Landroid/app/ActivityThread$AppBindData;)V";
|
||||
|
||||
@HookMethodBackup("handleBindApplication")
|
||||
@SkipParamCheck
|
||||
static Method backup;
|
||||
|
||||
@HookMethod("handleBindApplication")
|
||||
public static void hook(@ThisObject ActivityThread thiz, @Param("android.app.ActivityThread$AppBindData") Object bindData) throws Throwable {
|
||||
if (XposedBlackListHooker.shouldDisableHooks("")) {
|
||||
backup(thiz, bindData);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
Router.logD("ActivityThread#handleBindApplication() starts");
|
||||
ActivityThread activityThread = (ActivityThread) thiz;
|
||||
ApplicationInfo appInfo = (ApplicationInfo) XposedHelpers.getObjectField(bindData, "appInfo");
|
||||
// save app process name here for later use
|
||||
Main.appProcessName = (String) XposedHelpers.getObjectField(bindData, "processName");
|
||||
String reportedPackageName = appInfo.packageName.equals("android") ? "system" : appInfo.packageName;
|
||||
Utils.logD("processName=" + Main.appProcessName +
|
||||
", packageName=" + reportedPackageName + ", appDataDir=" + Main.appDataDir);
|
||||
|
||||
if (XposedBlackListHooker.shouldDisableHooks(reportedPackageName)) {
|
||||
return;
|
||||
}
|
||||
|
||||
ComponentName instrumentationName = (ComponentName) XposedHelpers.getObjectField(bindData, "instrumentationName");
|
||||
if (instrumentationName != null) {
|
||||
Router.logD("Instrumentation detected, disabling framework for");
|
||||
XposedBridge.disableHooks = true;
|
||||
return;
|
||||
}
|
||||
CompatibilityInfo compatInfo = (CompatibilityInfo) XposedHelpers.getObjectField(bindData, "compatInfo");
|
||||
if (appInfo.sourceDir == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
XposedHelpers.setObjectField(activityThread, "mBoundApplication", bindData);
|
||||
XposedInit.loadedPackagesInProcess.add(reportedPackageName);
|
||||
LoadedApk loadedApk = activityThread.getPackageInfoNoCheck(appInfo, compatInfo);
|
||||
|
||||
replaceParentClassLoader(loadedApk.getClassLoader());
|
||||
|
||||
XC_LoadPackage.LoadPackageParam lpparam = new XC_LoadPackage.LoadPackageParam(XposedBridge.sLoadedPackageCallbacks);
|
||||
lpparam.packageName = reportedPackageName;
|
||||
lpparam.processName = (String) XposedHelpers.getObjectField(bindData, "processName");
|
||||
lpparam.classLoader = loadedApk.getClassLoader();
|
||||
lpparam.appInfo = appInfo;
|
||||
lpparam.isFirstApplication = true;
|
||||
XC_LoadPackage.callAll(lpparam);
|
||||
|
||||
if (reportedPackageName.equals(INSTALLER_PACKAGE_NAME)) {
|
||||
XposedInstallerHooker.hookXposedInstaller(lpparam.classLoader);
|
||||
}
|
||||
if (reportedPackageName.equals(BLACK_LIST_PACKAGE_NAME)) {
|
||||
XposedBlackListHooker.hook(lpparam.classLoader);
|
||||
}
|
||||
if (reportedPackageName.equals(SYSTEMUI_PACKAGE_NAME)) {
|
||||
SliceProviderFix.hook();
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
Router.logE("error when hooking bindApp", t);
|
||||
} finally {
|
||||
backup(thiz, bindData);
|
||||
}
|
||||
}
|
||||
|
||||
public static void backup(Object thiz, Object bindData) throws Throwable {
|
||||
SandHook.callOriginByBackup(backup, thiz, bindData);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,111 +0,0 @@
|
|||
package com.elderdrivers.riru.edxp.sandhook._hooker;
|
||||
|
||||
import android.app.ActivityThread;
|
||||
import android.app.AndroidAppHelper;
|
||||
import android.app.LoadedApk;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.res.CompatibilityInfo;
|
||||
import android.util.Log;
|
||||
|
||||
import com.elderdrivers.riru.common.KeepMembers;
|
||||
import com.elderdrivers.riru.edxp.hooker.XposedBlackListHooker;
|
||||
import com.elderdrivers.riru.edxp.sandhook.entry.Router;
|
||||
import com.swift.sandhook.SandHook;
|
||||
import com.swift.sandhook.annotation.HookClass;
|
||||
import com.swift.sandhook.annotation.HookMethod;
|
||||
import com.swift.sandhook.annotation.HookMethodBackup;
|
||||
import com.swift.sandhook.annotation.SkipParamCheck;
|
||||
import com.swift.sandhook.annotation.ThisObject;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import de.robv.android.xposed.XposedBridge;
|
||||
import de.robv.android.xposed.XposedHelpers;
|
||||
import de.robv.android.xposed.XposedInit;
|
||||
import de.robv.android.xposed.callbacks.XC_LoadPackage;
|
||||
|
||||
import static com.elderdrivers.riru.edxp.util.ClassLoaderUtils.replaceParentClassLoader;
|
||||
|
||||
// when a package is loaded for an existing process, trigger the callbacks as well
|
||||
// ed: remove resources related hooking
|
||||
@HookClass(LoadedApk.class)
|
||||
public class LoadedApkConstructorHooker implements KeepMembers {
|
||||
public static String className = "android.app.LoadedApk";
|
||||
public static String methodName = "<init>";
|
||||
public static String methodSig = "(Landroid/app/ActivityThread;" +
|
||||
"Landroid/content/pm/ApplicationInfo;" +
|
||||
"Landroid/content/res/CompatibilityInfo;" +
|
||||
"Ljava/lang/ClassLoader;ZZZ)V";
|
||||
|
||||
@HookMethodBackup
|
||||
@SkipParamCheck
|
||||
static Method backup;
|
||||
|
||||
@HookMethod
|
||||
public static void hook(@ThisObject Object thiz, ActivityThread activityThread,
|
||||
ApplicationInfo aInfo, CompatibilityInfo compatInfo,
|
||||
ClassLoader baseLoader, boolean securityViolation,
|
||||
boolean includeCode, boolean registerPackage) throws Throwable {
|
||||
|
||||
if (XposedBlackListHooker.shouldDisableHooks("")) {
|
||||
backup(thiz, activityThread, aInfo, compatInfo, baseLoader, securityViolation, includeCode, registerPackage);
|
||||
return;
|
||||
}
|
||||
|
||||
Router.logD("LoadedApk#<init> starts");
|
||||
backup(thiz, activityThread, aInfo, compatInfo, baseLoader, securityViolation, includeCode, registerPackage);
|
||||
|
||||
try {
|
||||
LoadedApk loadedApk = (LoadedApk) thiz;
|
||||
String packageName = loadedApk.getPackageName();
|
||||
Object mAppDir = XposedHelpers.getObjectField(thiz, "mAppDir");
|
||||
Router.logD("LoadedApk#<init> ends: " + mAppDir);
|
||||
|
||||
if (XposedBlackListHooker.shouldDisableHooks(packageName)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (packageName.equals("android")) {
|
||||
Router.logD("LoadedApk#<init> is android, skip: " + mAppDir);
|
||||
return;
|
||||
}
|
||||
|
||||
// mIncludeCode checking should go ahead of loadedPackagesInProcess added checking
|
||||
if (!XposedHelpers.getBooleanField(loadedApk, "mIncludeCode")) {
|
||||
Router.logD("LoadedApk#<init> mIncludeCode == false: " + mAppDir);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!XposedInit.loadedPackagesInProcess.add(packageName)) {
|
||||
Router.logD("LoadedApk#<init> has been loaded before, skip: " + mAppDir);
|
||||
return;
|
||||
}
|
||||
|
||||
// OnePlus magic...
|
||||
if (Log.getStackTraceString(new Throwable()).
|
||||
contains("android.app.ActivityThread$ApplicationThread.schedulePreload")) {
|
||||
Router.logD("LoadedApk#<init> maybe oneplus's custom opt, skip");
|
||||
return;
|
||||
}
|
||||
|
||||
replaceParentClassLoader(loadedApk.getClassLoader());
|
||||
|
||||
XC_LoadPackage.LoadPackageParam lpparam = new XC_LoadPackage.LoadPackageParam(XposedBridge.sLoadedPackageCallbacks);
|
||||
lpparam.packageName = packageName;
|
||||
lpparam.processName = AndroidAppHelper.currentProcessName();
|
||||
lpparam.classLoader = loadedApk.getClassLoader();
|
||||
lpparam.appInfo = loadedApk.getApplicationInfo();
|
||||
lpparam.isFirstApplication = false;
|
||||
XC_LoadPackage.callAll(lpparam);
|
||||
} catch (Throwable t) {
|
||||
Router.logE("error when hooking LoadedApk.<init>", t);
|
||||
}
|
||||
}
|
||||
|
||||
public static void backup(Object thiz, ActivityThread activityThread,
|
||||
ApplicationInfo aInfo, CompatibilityInfo compatInfo,
|
||||
ClassLoader baseLoader, boolean securityViolation,
|
||||
boolean includeCode, boolean registerPackage) throws Throwable {
|
||||
SandHook.callOriginByBackup(backup, thiz, activityThread, aInfo, compatInfo, baseLoader, securityViolation, includeCode, registerPackage);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,55 +0,0 @@
|
|||
package com.elderdrivers.riru.edxp.sandhook._hooker;
|
||||
|
||||
import com.elderdrivers.riru.common.KeepMembers;
|
||||
import com.elderdrivers.riru.edxp.Main;
|
||||
import com.elderdrivers.riru.edxp.sandhook.entry.Router;
|
||||
import com.swift.sandhook.SandHook;
|
||||
import com.swift.sandhook.annotation.HookClass;
|
||||
import com.swift.sandhook.annotation.HookMethod;
|
||||
import com.swift.sandhook.annotation.HookMethodBackup;
|
||||
import com.swift.sandhook.annotation.SkipParamCheck;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import dalvik.system.BaseDexClassLoader;
|
||||
import de.robv.android.xposed.XposedBridge;
|
||||
|
||||
/**
|
||||
* On OnePlus stock roms (Android Pie), {@link dalvik.system.BaseDexClassLoader#findClass(String)}
|
||||
* will open /dev/binder to communicate with PackageManagerService to check whether
|
||||
* current package name inCompatConfigList, which is an OnePlus OEM feature enabled only when
|
||||
* system prop "persist.sys.oem.region" set to "CN".(detail of related source code:
|
||||
* https://gist.github.com/solohsu/ecc07141759958fc096ba0781fac0a5f)
|
||||
* If we invoke intZygoteCallbacks in
|
||||
* {@link Main#forkAndSpecializePre}, where in zygote process,
|
||||
* we would get a chance to invoke findclass, leaving fd of /dev/binder open in zygote process,
|
||||
* which is not allowed because /dev/binder is not in predefined whitelist here:
|
||||
* http://androidxref.com/9.0.0_r3/xref/frameworks/base/core/jni/fd_utils.cpp#35
|
||||
* So we just hook BaseDexClassLoader#inCompatConfigList to return false to prevent
|
||||
* open of /dev/binder and we haven't found side effects yet.
|
||||
* Other roms might share the same problems but not reported too.
|
||||
*/
|
||||
@HookClass(BaseDexClassLoader.class)
|
||||
public class OnePlusWorkAroundHooker implements KeepMembers {
|
||||
|
||||
public static String className = "dalvik.system.BaseDexClassLoader";
|
||||
public static String methodName = "inCompatConfigList";
|
||||
public static String methodSig = "(ILjava/lang/String;)Z";
|
||||
|
||||
@HookMethodBackup("inCompatConfigList")
|
||||
@SkipParamCheck
|
||||
static Method backup;
|
||||
|
||||
@HookMethod("inCompatConfigList")
|
||||
public static boolean hook(int type, String packageName) throws Throwable {
|
||||
if (XposedBridge.disableHooks || Router.forkCompleted) {
|
||||
return backup(type, packageName);
|
||||
}
|
||||
Router.logD("BaseDexClassLoader#inCompatConfigList() starts");
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean backup(int type, String packageName) throws Throwable {
|
||||
return (boolean) SandHook.callOriginByBackup(backup, null, type, packageName);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,80 +0,0 @@
|
|||
package com.elderdrivers.riru.edxp.sandhook._hooker;
|
||||
|
||||
import android.os.Build;
|
||||
|
||||
import com.elderdrivers.riru.common.KeepMembers;
|
||||
import com.elderdrivers.riru.edxp.sandhook.entry.Router;
|
||||
import com.swift.sandhook.SandHook;
|
||||
import com.swift.sandhook.annotation.HookMethod;
|
||||
import com.swift.sandhook.annotation.HookMethodBackup;
|
||||
import com.swift.sandhook.annotation.HookReflectClass;
|
||||
import com.swift.sandhook.annotation.SkipParamCheck;
|
||||
import com.swift.sandhook.annotation.ThisObject;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import de.robv.android.xposed.XC_MethodReplacement;
|
||||
import de.robv.android.xposed.XposedBridge;
|
||||
import de.robv.android.xposed.XposedHelpers;
|
||||
import de.robv.android.xposed.XposedInit;
|
||||
import de.robv.android.xposed.callbacks.XC_LoadPackage;
|
||||
|
||||
import static com.elderdrivers.riru.edxp.util.ClassLoaderUtils.replaceParentClassLoader;
|
||||
import static com.elderdrivers.riru.edxp.util.Utils.logD;
|
||||
import static de.robv.android.xposed.XposedHelpers.findAndHookMethod;
|
||||
|
||||
@HookReflectClass("com.android.server.SystemServer")
|
||||
public class StartBootstrapServicesHooker implements KeepMembers {
|
||||
public static String className = "com.android.server.SystemServer";
|
||||
public static String methodName = "startBootstrapServices";
|
||||
public static String methodSig = "()V";
|
||||
|
||||
@HookMethodBackup("startBootstrapServices")
|
||||
@SkipParamCheck
|
||||
static Method backup;
|
||||
|
||||
@HookMethod("startBootstrapServices")
|
||||
public static void hook(@ThisObject Object systemServer) throws Throwable {
|
||||
|
||||
if (XposedBridge.disableHooks) {
|
||||
backup(systemServer);
|
||||
return;
|
||||
}
|
||||
|
||||
logD("SystemServer#startBootstrapServices() starts");
|
||||
|
||||
try {
|
||||
XposedInit.loadedPackagesInProcess.add("android");
|
||||
|
||||
replaceParentClassLoader(SystemMainHooker.systemServerCL);
|
||||
|
||||
XC_LoadPackage.LoadPackageParam lpparam = new XC_LoadPackage.LoadPackageParam(XposedBridge.sLoadedPackageCallbacks);
|
||||
lpparam.packageName = "android";
|
||||
lpparam.processName = "android"; // it's actually system_server, but other functions return this as well
|
||||
lpparam.classLoader = SystemMainHooker.systemServerCL;
|
||||
lpparam.appInfo = null;
|
||||
lpparam.isFirstApplication = true;
|
||||
XC_LoadPackage.callAll(lpparam);
|
||||
|
||||
// Huawei
|
||||
try {
|
||||
findAndHookMethod("com.android.server.pm.HwPackageManagerService", SystemMainHooker.systemServerCL, "isOdexMode", XC_MethodReplacement.returnConstant(false));
|
||||
} catch (XposedHelpers.ClassNotFoundError | NoSuchMethodError ignored) {
|
||||
}
|
||||
|
||||
try {
|
||||
String className = "com.android.server.pm." + (Build.VERSION.SDK_INT >= 23 ? "PackageDexOptimizer" : "PackageManagerService");
|
||||
findAndHookMethod(className, SystemMainHooker.systemServerCL, "dexEntryExists", String.class, XC_MethodReplacement.returnConstant(true));
|
||||
} catch (XposedHelpers.ClassNotFoundError | NoSuchMethodError ignored) {
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
Router.logE("error when hooking startBootstrapServices", t);
|
||||
} finally {
|
||||
backup(systemServer);
|
||||
}
|
||||
}
|
||||
|
||||
public static void backup(Object systemServer) throws Throwable {
|
||||
SandHook.callOriginByBackup(backup, systemServer);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,5 @@
|
|||
package com.elderdrivers.riru.edxp.sandhook.config;
|
||||
|
||||
import com.elderdrivers.riru.edxp.Main;
|
||||
import com.elderdrivers.riru.edxp.config.ConfigManager;
|
||||
import com.elderdrivers.riru.edxp.config.EdXpConfig;
|
||||
import com.elderdrivers.riru.edxp.config.InstallerChooser;
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ package com.elderdrivers.riru.edxp.sandhook.config;
|
|||
|
||||
import android.util.Log;
|
||||
|
||||
import com.elderdrivers.riru.edxp.Main;
|
||||
import com.elderdrivers.riru.edxp.art.ClassLinker;
|
||||
import com.elderdrivers.riru.edxp.config.BaseHookProvider;
|
||||
import com.elderdrivers.riru.edxp.core.ResourcesHook;
|
||||
|
|
|
|||
|
|
@ -1,185 +0,0 @@
|
|||
package com.elderdrivers.riru.edxp.sandhook.core;
|
||||
|
||||
import com.elderdrivers.riru.edxp.art.Heap;
|
||||
import com.elderdrivers.riru.edxp.core.Yahfa;
|
||||
import com.elderdrivers.riru.edxp.util.Utils;
|
||||
import com.elderdrivers.riru.edxp.Main;
|
||||
import com.elderdrivers.riru.edxp.sandhook._hooker.OnePlusWorkAroundHooker;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
|
||||
import de.robv.android.xposed.XposedHelpers;
|
||||
|
||||
public class HookMain {
|
||||
|
||||
private static Set<String> hookItemWhiteList = Collections.singleton(OnePlusWorkAroundHooker.class.getName());
|
||||
|
||||
public static void doHookDefault(ClassLoader patchClassLoader, ClassLoader originClassLoader, String hookInfoClassName) {
|
||||
try {
|
||||
Class<?> hookInfoClass = Class.forName(hookInfoClassName, true, patchClassLoader);
|
||||
String[] hookItemNames = (String[]) hookInfoClass.getField("hookItemNames").get(null);
|
||||
for (String hookItemName : hookItemNames) {
|
||||
doHookItemDefault(patchClassLoader, hookItemName, originClassLoader);
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
Utils.logE("error when hooking all in: " + hookInfoClassName, e);
|
||||
}
|
||||
}
|
||||
|
||||
private static void doHookItemDefault(ClassLoader patchClassLoader, String hookItemName, ClassLoader originClassLoader) {
|
||||
try {
|
||||
Utils.logD("Start hooking with item " + hookItemName);
|
||||
Class<?> hookItem = Class.forName(hookItemName, true, patchClassLoader);
|
||||
|
||||
String className = (String) hookItem.getField("className").get(null);
|
||||
String methodName = (String) hookItem.getField("methodName").get(null);
|
||||
String methodSig = (String) hookItem.getField("methodSig").get(null);
|
||||
|
||||
if (className == null || className.equals("")) {
|
||||
Utils.logW("No target class. Skipping...");
|
||||
return;
|
||||
}
|
||||
Class<?> clazz = null;
|
||||
try {
|
||||
clazz = Class.forName(className, true, originClassLoader);
|
||||
} catch (ClassNotFoundException cnfe) {
|
||||
Utils.logE(className + " not found in " + originClassLoader);
|
||||
return;
|
||||
}
|
||||
if (Modifier.isAbstract(clazz.getModifiers())) {
|
||||
Utils.logW("Hook may fail for abstract class: " + className);
|
||||
}
|
||||
|
||||
Method hook = null;
|
||||
Method backup = null;
|
||||
for (Method method : hookItem.getDeclaredMethods()) {
|
||||
if (method.getName().equals("hook") && Modifier.isStatic(method.getModifiers())) {
|
||||
hook = method;
|
||||
} else if (method.getName().equals("backup") && Modifier.isStatic(method.getModifiers())) {
|
||||
backup = method;
|
||||
}
|
||||
}
|
||||
if (hook == null) {
|
||||
Utils.logE("Cannot find hook for " + methodName);
|
||||
return;
|
||||
}
|
||||
findAndBackupAndHook(clazz, methodName, methodSig, hook, backup);
|
||||
} catch (Throwable e) {
|
||||
if (!hookItemWhiteList.contains(hookItemName)) {
|
||||
Utils.logE("error when hooking " + hookItemName, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void findAndHook(Class targetClass, String methodName, String methodSig, Method hook) {
|
||||
hook(findMethod(targetClass, methodName, methodSig), hook);
|
||||
}
|
||||
|
||||
public static void findAndBackupAndHook(Class targetClass, String methodName, String methodSig,
|
||||
Method hook, Method backup) {
|
||||
backupAndHook(findMethod(targetClass, methodName, methodSig), hook, backup);
|
||||
}
|
||||
|
||||
public static void hook(Object target, Method hook) {
|
||||
backupAndHook(target, hook, null);
|
||||
}
|
||||
|
||||
public static void backupAndHook(Object target, Method hook, Method backup) {
|
||||
Utils.logD(String.format("target=%s, hook=%s, backup=%s", target, hook, backup));
|
||||
if (target == null) {
|
||||
throw new IllegalArgumentException("null target method");
|
||||
}
|
||||
if (hook == null) {
|
||||
throw new IllegalArgumentException("null hook method");
|
||||
}
|
||||
|
||||
if (!Modifier.isStatic(hook.getModifiers())) {
|
||||
throw new IllegalArgumentException("Hook must be a static method: " + hook);
|
||||
}
|
||||
checkCompatibleMethods(target, hook, "Original", "Hook");
|
||||
if (backup != null) {
|
||||
if (!Modifier.isStatic(backup.getModifiers())) {
|
||||
throw new IllegalArgumentException("Backup must be a static method: " + backup);
|
||||
}
|
||||
// backup is just a placeholder and the constraint could be less strict
|
||||
checkCompatibleMethods(target, backup, "Original", "Backup");
|
||||
}
|
||||
if (backup != null) {
|
||||
HookMethodResolver.resolveMethod(hook, backup);
|
||||
}
|
||||
// make sure GC completed before hook
|
||||
Thread currentThread = Thread.currentThread();
|
||||
int lastGcType = Heap.waitForGcToComplete(
|
||||
XposedHelpers.getLongField(currentThread, "nativePeer"));
|
||||
if (lastGcType < 0) {
|
||||
Utils.logW("waitForGcToComplete failed, using fallback");
|
||||
Runtime.getRuntime().gc();
|
||||
}
|
||||
if (!Yahfa.backupAndHookNative(target, hook, backup)) {
|
||||
throw new RuntimeException("Failed to hook " + target + " with " + hook);
|
||||
}
|
||||
}
|
||||
|
||||
public static Object findMethod(Class cls, String methodName, String methodSig) {
|
||||
if (cls == null) {
|
||||
throw new IllegalArgumentException("null class");
|
||||
}
|
||||
if (methodName == null) {
|
||||
throw new IllegalArgumentException("null method name");
|
||||
}
|
||||
if (methodSig == null) {
|
||||
throw new IllegalArgumentException("null method signature");
|
||||
}
|
||||
return Yahfa.findMethodNative(cls, methodName, methodSig);
|
||||
}
|
||||
|
||||
private static void checkCompatibleMethods(Object original, Method replacement, String originalName, String replacementName) {
|
||||
ArrayList<Class<?>> originalParams;
|
||||
if (original instanceof Method) {
|
||||
originalParams = new ArrayList<>(Arrays.asList(((Method) original).getParameterTypes()));
|
||||
} else if (original instanceof Constructor) {
|
||||
originalParams = new ArrayList<>(Arrays.asList(((Constructor<?>) original).getParameterTypes()));
|
||||
} else {
|
||||
throw new IllegalArgumentException("Type of target method is wrong");
|
||||
}
|
||||
|
||||
ArrayList<Class<?>> replacementParams = new ArrayList<>(Arrays.asList(replacement.getParameterTypes()));
|
||||
|
||||
if (original instanceof Method
|
||||
&& !Modifier.isStatic(((Method) original).getModifiers())) {
|
||||
originalParams.add(0, ((Method) original).getDeclaringClass());
|
||||
} else if (original instanceof Constructor) {
|
||||
originalParams.add(0, ((Constructor<?>) original).getDeclaringClass());
|
||||
}
|
||||
|
||||
|
||||
if (!Modifier.isStatic(replacement.getModifiers())) {
|
||||
replacementParams.add(0, replacement.getDeclaringClass());
|
||||
}
|
||||
|
||||
if (original instanceof Method
|
||||
&& !replacement.getReturnType().isAssignableFrom(((Method) original).getReturnType())) {
|
||||
throw new IllegalArgumentException("Incompatible return types. " + originalName + ": " + ((Method) original).getReturnType() + ", " + replacementName + ": " + replacement.getReturnType());
|
||||
} else if (original instanceof Constructor) {
|
||||
if (replacement.getReturnType().equals(Void.class)) {
|
||||
throw new IllegalArgumentException("Incompatible return types. " + "<init>" + ": " + "V" + ", " + replacementName + ": " + replacement.getReturnType());
|
||||
}
|
||||
}
|
||||
|
||||
if (originalParams.size() != replacementParams.size()) {
|
||||
throw new IllegalArgumentException("Number of arguments don't match. " + originalName + ": " + originalParams.size() + ", " + replacementName + ": " + replacementParams.size());
|
||||
}
|
||||
|
||||
for (int i = 0; i < originalParams.size(); i++) {
|
||||
if (!replacementParams.get(i).isAssignableFrom(originalParams.get(i))) {
|
||||
throw new IllegalArgumentException("Incompatible argument #" + i + ": " + originalName + ": " + originalParams.get(i) + ", " + replacementName + ": " + replacementParams.get(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,156 +0,0 @@
|
|||
package com.elderdrivers.riru.edxp.sandhook.core;
|
||||
|
||||
import android.os.Build;
|
||||
|
||||
import com.elderdrivers.riru.edxp.core.Yahfa;
|
||||
import com.elderdrivers.riru.edxp.util.Utils;
|
||||
import com.elderdrivers.riru.edxp.Main;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
/**
|
||||
* create by Swift Gan on 14/01/2019
|
||||
* To ensure method in resolved cache
|
||||
*/
|
||||
|
||||
public class HookMethodResolver {
|
||||
|
||||
public static Class artMethodClass;
|
||||
|
||||
public static Field resolvedMethodsField;
|
||||
public static Field dexCacheField;
|
||||
public static Field dexMethodIndexField;
|
||||
public static Field artMethodField;
|
||||
|
||||
public static boolean canResolvedInJava = false;
|
||||
public static boolean isArtMethod = false;
|
||||
|
||||
public static long resolvedMethodsAddress = 0;
|
||||
public static int dexMethodIndex = 0;
|
||||
|
||||
public static Method testMethod;
|
||||
public static Object testArtMethod;
|
||||
|
||||
public static void init() {
|
||||
checkSupport();
|
||||
}
|
||||
|
||||
private static void checkSupport() {
|
||||
try {
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||
isArtMethod = false;
|
||||
canResolvedInJava = false;
|
||||
return;
|
||||
}
|
||||
|
||||
testMethod = HookMethodResolver.class.getDeclaredMethod("init");
|
||||
artMethodField = getField(Method.class, "artMethod");
|
||||
|
||||
testArtMethod = artMethodField.get(testMethod);
|
||||
|
||||
if (hasJavaArtMethod() && testArtMethod.getClass() == artMethodClass) {
|
||||
checkSupportForArtMethod();
|
||||
isArtMethod = true;
|
||||
} else if (testArtMethod instanceof Long) {
|
||||
checkSupportForArtMethodId();
|
||||
isArtMethod = false;
|
||||
} else {
|
||||
canResolvedInJava = false;
|
||||
}
|
||||
|
||||
} catch (Throwable throwable) {
|
||||
Utils.logE("error when checkSupport", throwable);
|
||||
}
|
||||
}
|
||||
|
||||
// may 5.0
|
||||
private static void checkSupportForArtMethod() throws Exception {
|
||||
dexMethodIndexField = getField(artMethodClass, "dexMethodIndex");
|
||||
dexCacheField = getField(Class.class, "dexCache");
|
||||
Object dexCache = dexCacheField.get(testMethod.getDeclaringClass());
|
||||
resolvedMethodsField = getField(dexCache.getClass(), "resolvedMethods");
|
||||
if (resolvedMethodsField.get(dexCache) instanceof Object[]) {
|
||||
canResolvedInJava = true;
|
||||
}
|
||||
}
|
||||
|
||||
// may 6.0
|
||||
private static void checkSupportForArtMethodId() throws Exception {
|
||||
dexMethodIndexField = getField(Method.class, "dexMethodIndex");
|
||||
dexMethodIndex = (int) dexMethodIndexField.get(testMethod);
|
||||
dexCacheField = getField(Class.class, "dexCache");
|
||||
Object dexCache = dexCacheField.get(testMethod.getDeclaringClass());
|
||||
resolvedMethodsField = getField(dexCache.getClass(), "resolvedMethods");
|
||||
Object resolvedMethods = resolvedMethodsField.get(dexCache);
|
||||
if (resolvedMethods instanceof Long) {
|
||||
canResolvedInJava = false;
|
||||
resolvedMethodsAddress = (long) resolvedMethods;
|
||||
} else if (resolvedMethods instanceof long[]) {
|
||||
canResolvedInJava = true;
|
||||
}
|
||||
}
|
||||
|
||||
public static void resolveMethod(Method hook, Method backup) {
|
||||
if (canResolvedInJava && artMethodField != null) {
|
||||
// in java
|
||||
try {
|
||||
resolveInJava(hook, backup);
|
||||
} catch (Exception e) {
|
||||
// in native
|
||||
resolveInNative(hook, backup);
|
||||
}
|
||||
} else {
|
||||
// in native
|
||||
resolveInNative(hook, backup);
|
||||
}
|
||||
}
|
||||
|
||||
private static void resolveInJava(Method hook, Method backup) throws Exception {
|
||||
Object dexCache = dexCacheField.get(hook.getDeclaringClass());
|
||||
if (isArtMethod) {
|
||||
Object artMethod = artMethodField.get(backup);
|
||||
int dexMethodIndex = (int) dexMethodIndexField.get(artMethod);
|
||||
Object resolvedMethods = resolvedMethodsField.get(dexCache);
|
||||
((Object[])resolvedMethods)[dexMethodIndex] = artMethod;
|
||||
} else {
|
||||
int dexMethodIndex = (int) dexMethodIndexField.get(backup);
|
||||
Object resolvedMethods = resolvedMethodsField.get(dexCache);
|
||||
long artMethod = (long) artMethodField.get(backup);
|
||||
((long[])resolvedMethods)[dexMethodIndex] = artMethod;
|
||||
}
|
||||
}
|
||||
|
||||
private static void resolveInNative(Method hook, Method backup) {
|
||||
Yahfa.ensureMethodCached(hook, backup);
|
||||
}
|
||||
|
||||
public static Field getField(Class topClass, String fieldName) throws NoSuchFieldException {
|
||||
while (topClass != null && topClass != Object.class) {
|
||||
try {
|
||||
Field field = topClass.getDeclaredField(fieldName);
|
||||
field.setAccessible(true);
|
||||
return field;
|
||||
} catch (Exception e) {
|
||||
}
|
||||
topClass = topClass.getSuperclass();
|
||||
}
|
||||
throw new NoSuchFieldException(fieldName);
|
||||
}
|
||||
|
||||
public static boolean hasJavaArtMethod() {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
return false;
|
||||
}
|
||||
if (artMethodClass != null)
|
||||
return true;
|
||||
try {
|
||||
artMethodClass = Class.forName("java.lang.reflect.ArtMethod");
|
||||
return true;
|
||||
} catch (ClassNotFoundException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
package com.elderdrivers.riru.edxp.sandhook.core;
|
||||
|
||||
import android.os.Build;
|
||||
|
||||
import com.elderdrivers.riru.edxp.config.ConfigManager;
|
||||
import com.elderdrivers.riru.edxp.config.InstallerChooser;
|
||||
import com.elderdrivers.riru.edxp.core.BaseEdxpImpl;
|
||||
import com.elderdrivers.riru.edxp.core.EdxpImpl;
|
||||
import com.elderdrivers.riru.edxp.core.Main;
|
||||
import com.elderdrivers.riru.edxp.core.Yahfa;
|
||||
import com.elderdrivers.riru.edxp.core.yahfa.HookMethodResolver;
|
||||
import com.swift.sandhook.xposedcompat.methodgen.SandHookXposedBridge;
|
||||
|
||||
public class SandHookEdxpImpl extends BaseEdxpImpl {
|
||||
|
||||
static {
|
||||
final EdxpImpl edxpImpl = new SandHookEdxpImpl();
|
||||
if (Main.setEdxpImpl(edxpImpl)) {
|
||||
edxpImpl.init();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected com.elderdrivers.riru.edxp.proxy.Router createRouter() {
|
||||
return new SandHookRouter();
|
||||
}
|
||||
|
||||
@Variant
|
||||
@Override
|
||||
public int getVariant() {
|
||||
return SANDHOOK;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init() {
|
||||
Yahfa.init(Build.VERSION.SDK_INT);
|
||||
HookMethodResolver.init();
|
||||
getRouter().injectConfig();
|
||||
InstallerChooser.setInstallerPackageName(ConfigManager.getInstallerPackageName());
|
||||
SandHookXposedBridge.init();
|
||||
|
||||
setInitialized();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,64 @@
|
|||
package com.elderdrivers.riru.edxp.sandhook.core;
|
||||
|
||||
import com.elderdrivers.riru.edxp.config.EdXpConfigGlobal;
|
||||
import com.elderdrivers.riru.edxp.proxy.BaseRouter;
|
||||
import com.elderdrivers.riru.edxp.sandhook.hooker.SystemMainHooker;
|
||||
import com.elderdrivers.riru.edxp.sandhook.config.SandHookEdxpConfig;
|
||||
import com.elderdrivers.riru.edxp.sandhook.config.SandHookProvider;
|
||||
import com.elderdrivers.riru.edxp.sandhook.dexmaker.DynamicBridge;
|
||||
import com.elderdrivers.riru.edxp.sandhook.entry.AppBootstrapHookInfo;
|
||||
import com.elderdrivers.riru.edxp.sandhook.entry.SysBootstrapHookInfo;
|
||||
import com.elderdrivers.riru.edxp.sandhook.entry.SysInnerHookInfo;
|
||||
import com.elderdrivers.riru.edxp.sandhook.entry.WorkAroundHookInfo;
|
||||
import com.elderdrivers.riru.edxp.util.Utils;
|
||||
import com.swift.sandhook.xposedcompat.XposedCompat;
|
||||
|
||||
import de.robv.android.xposed.XposedBridge;
|
||||
|
||||
public class SandHookRouter extends BaseRouter {
|
||||
|
||||
private static boolean useSandHook = false;
|
||||
|
||||
public void startBootstrapHook(boolean isSystem) {
|
||||
if (useSandHook) {
|
||||
Utils.logD("startBootstrapHook starts: isSystem = " + isSystem);
|
||||
ClassLoader classLoader = XposedBridge.BOOTCLASSLOADER;
|
||||
if (isSystem) {
|
||||
XposedCompat.addHookers(classLoader, SysBootstrapHookInfo.hookItems);
|
||||
} else {
|
||||
XposedCompat.addHookers(classLoader, AppBootstrapHookInfo.hookItems);
|
||||
}
|
||||
} else {
|
||||
super.startBootstrapHook(isSystem);
|
||||
}
|
||||
}
|
||||
|
||||
public void startSystemServerHook() {
|
||||
if (useSandHook) {
|
||||
XposedCompat.addHookers(SystemMainHooker.systemServerCL, SysInnerHookInfo.hookItems);
|
||||
} else {
|
||||
super.startSystemServerHook();
|
||||
}
|
||||
}
|
||||
|
||||
public void startWorkAroundHook() {
|
||||
if (useSandHook) {
|
||||
XposedCompat.addHookers(XposedBridge.BOOTCLASSLOADER, WorkAroundHookInfo.hookItems);
|
||||
} else {
|
||||
super.startWorkAroundHook();
|
||||
}
|
||||
}
|
||||
|
||||
public void onEnterChildProcess() {
|
||||
DynamicBridge.onForkPost();
|
||||
//enable compile in child process
|
||||
//SandHook.enableCompiler(!XposedInit.startsSystemServer);
|
||||
}
|
||||
|
||||
public void injectConfig() {
|
||||
EdXpConfigGlobal.sConfig = new SandHookEdxpConfig();
|
||||
EdXpConfigGlobal.sHookProvider = new SandHookProvider();
|
||||
XposedBridge.log("using HookProvider: " + EdXpConfigGlobal.sHookProvider.getClass().getName());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -5,8 +5,7 @@ import android.os.Build;
|
|||
import android.text.TextUtils;
|
||||
|
||||
import com.elderdrivers.riru.edxp.config.ConfigManager;
|
||||
import com.elderdrivers.riru.edxp.Main;
|
||||
import com.elderdrivers.riru.edxp.sandhook.core.HookMain;
|
||||
import com.elderdrivers.riru.edxp.core.yahfa.HookMain;
|
||||
|
||||
import java.lang.reflect.Member;
|
||||
import java.security.MessageDigest;
|
||||
|
|
@ -27,8 +26,8 @@ public class DexMakerUtils {
|
|||
}
|
||||
String packageName = AndroidAppHelper.currentPackageName();
|
||||
if (TextUtils.isEmpty(packageName)) { //default to true
|
||||
DexLog.w("packageName is empty, processName=" + Main.appProcessName
|
||||
+ ", appDataDir=" + Main.appDataDir);
|
||||
DexLog.w("packageName is empty, processName=" + ConfigManager.appProcessName
|
||||
+ ", appDataDir=" + ConfigManager.appDataDir);
|
||||
return true;
|
||||
}
|
||||
return !ConfigManager.shouldUseCompatMode(packageName);
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
package com.elderdrivers.riru.edxp.sandhook.dexmaker;
|
||||
|
||||
import com.elderdrivers.riru.edxp.Main;
|
||||
import com.elderdrivers.riru.edxp.config.ConfigManager;
|
||||
|
||||
import java.io.File;
|
||||
import java.lang.reflect.Constructor;
|
||||
|
|
@ -8,16 +8,15 @@ import java.lang.reflect.InvocationTargetException;
|
|||
import java.lang.reflect.Member;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.HashMap;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import de.robv.android.xposed.XposedBridge;
|
||||
|
||||
import static com.elderdrivers.riru.edxp.sandhook.dexmaker.DexMakerUtils.shouldUseInMemoryHook;
|
||||
import static com.elderdrivers.riru.edxp.util.FileUtils.getDataPathPrefix;
|
||||
import static com.elderdrivers.riru.edxp.util.FileUtils.getPackageName;
|
||||
import static com.elderdrivers.riru.edxp.util.ProcessUtils.getCurrentProcessName;
|
||||
import static com.elderdrivers.riru.edxp.sandhook.dexmaker.DexMakerUtils.shouldUseInMemoryHook;
|
||||
|
||||
public final class DynamicBridge {
|
||||
|
||||
|
|
@ -78,9 +77,9 @@ public final class DynamicBridge {
|
|||
try {
|
||||
// we always choose to use device encrypted storage data on android N and later
|
||||
// in case some app is installing hooks before phone is unlocked
|
||||
String fixedAppDataDir = getDataPathPrefix() + getPackageName(Main.appDataDir) + "/";
|
||||
String fixedAppDataDir = getDataPathPrefix() + getPackageName(ConfigManager.appDataDir) + "/";
|
||||
dexDir = new File(fixedAppDataDir, "/cache/edhookers/"
|
||||
+ getCurrentProcessName(Main.appProcessName).replace(":", "_") + "/");
|
||||
+ getCurrentProcessName(ConfigManager.appProcessName).replace(":", "_") + "/");
|
||||
dexDir.mkdirs();
|
||||
} catch (Throwable throwable) {
|
||||
DexLog.e("error when init dex path", throwable);
|
||||
|
|
|
|||
|
|
@ -4,9 +4,8 @@ import android.annotation.TargetApi;
|
|||
import android.os.Build;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import com.elderdrivers.riru.edxp.Main;
|
||||
import com.elderdrivers.riru.edxp.core.Yahfa;
|
||||
import com.elderdrivers.riru.edxp.sandhook.core.HookMain;
|
||||
import com.elderdrivers.riru.edxp.core.yahfa.HookMain;
|
||||
|
||||
import java.io.File;
|
||||
import java.lang.reflect.Constructor;
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
package com.elderdrivers.riru.edxp.sandhook.entry.bootstrap;
|
||||
package com.elderdrivers.riru.edxp.sandhook.entry;
|
||||
|
||||
import com.elderdrivers.riru.common.KeepMembers;
|
||||
import com.elderdrivers.riru.edxp.sandhook._hooker.HandleBindAppHooker;
|
||||
import com.elderdrivers.riru.edxp.sandhook._hooker.LoadedApkConstructorHooker;
|
||||
import com.elderdrivers.riru.edxp.sandhook._hooker.OnePlusWorkAroundHooker;
|
||||
import com.elderdrivers.riru.edxp.sandhook.hooker.HandleBindAppHooker;
|
||||
import com.elderdrivers.riru.edxp.sandhook.hooker.LoadedApkConstructorHooker;
|
||||
import com.elderdrivers.riru.edxp.sandhook.hooker.OnePlusWorkAroundHooker;
|
||||
|
||||
public class AppBootstrapHookInfo implements KeepMembers {
|
||||
public static String[] hookItemNames = {
|
||||
|
|
@ -1,159 +0,0 @@
|
|||
package com.elderdrivers.riru.edxp.sandhook.entry;
|
||||
|
||||
import android.app.AndroidAppHelper;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import com.elderdrivers.riru.edxp.config.EdXpConfigGlobal;
|
||||
import com.elderdrivers.riru.edxp.sandhook.config.SandHookEdxpConfig;
|
||||
import com.elderdrivers.riru.edxp.sandhook.config.SandHookProvider;
|
||||
import com.elderdrivers.riru.edxp.sandhook.core.HookMain;
|
||||
import com.elderdrivers.riru.edxp.sandhook.dexmaker.DynamicBridge;
|
||||
import com.elderdrivers.riru.edxp.sandhook.entry.bootstrap.AppBootstrapHookInfo;
|
||||
import com.elderdrivers.riru.edxp.sandhook.entry.bootstrap.SysBootstrapHookInfo;
|
||||
import com.elderdrivers.riru.edxp.sandhook.entry.bootstrap.SysInnerHookInfo;
|
||||
import com.elderdrivers.riru.edxp.sandhook.entry.bootstrap.WorkAroundHookInfo;
|
||||
import com.elderdrivers.riru.edxp.sandhook._hooker.SystemMainHooker;
|
||||
import com.elderdrivers.riru.edxp.util.Utils;
|
||||
import com.swift.sandhook.xposedcompat.XposedCompat;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import de.robv.android.xposed.XposedBridge;
|
||||
import de.robv.android.xposed.XposedInit;
|
||||
|
||||
import static de.robv.android.xposed.XposedInit.startsSystemServer;
|
||||
|
||||
public class Router {
|
||||
|
||||
public volatile static boolean forkCompleted = false;
|
||||
|
||||
private static volatile AtomicBoolean bootstrapHooked = new AtomicBoolean(false);
|
||||
|
||||
static boolean useSandHook = false;
|
||||
|
||||
public static void initResourcesHook() {
|
||||
startWorkAroundHook(); // for OnePlus devices
|
||||
XposedBridge.initXResources();
|
||||
}
|
||||
|
||||
public static void prepare(boolean isSystem) {
|
||||
// this flag is needed when loadModules
|
||||
startsSystemServer = isSystem;
|
||||
}
|
||||
|
||||
public static void checkHookState(String appDataDir) {
|
||||
// determine whether allow xposed or not
|
||||
// XposedBridge.disableHooks = ConfigManager.shouldHook(parsePackageName(appDataDir));
|
||||
}
|
||||
|
||||
private static String parsePackageName(String appDataDir) {
|
||||
if (TextUtils.isEmpty(appDataDir)) {
|
||||
return "";
|
||||
}
|
||||
int lastIndex = appDataDir.lastIndexOf("/");
|
||||
if (lastIndex < 1) {
|
||||
return "";
|
||||
}
|
||||
return appDataDir.substring(lastIndex + 1);
|
||||
}
|
||||
|
||||
public static void installBootstrapHooks(boolean isSystem) {
|
||||
// Initialize the Xposed framework
|
||||
try {
|
||||
if (!bootstrapHooked.compareAndSet(false, true)) {
|
||||
return;
|
||||
}
|
||||
Router.startBootstrapHook(isSystem);
|
||||
XposedInit.initForZygote(isSystem);
|
||||
//SandHookConfig.compiler = !isSystem;
|
||||
} catch (Throwable t) {
|
||||
Utils.logE("error during Xposed initialization", t);
|
||||
XposedBridge.disableHooks = true;
|
||||
}
|
||||
}
|
||||
|
||||
public static void loadModulesSafely(boolean isInZygote) {
|
||||
try {
|
||||
// FIXME some coredomain app can't reading modules.list
|
||||
XposedInit.loadModules(isInZygote);
|
||||
} catch (Exception exception) {
|
||||
Utils.logE("error loading module list", exception);
|
||||
}
|
||||
}
|
||||
|
||||
public static void startBootstrapHook(boolean isSystem) {
|
||||
Utils.logD("startBootstrapHook starts: isSystem = " + isSystem);
|
||||
ClassLoader classLoader = XposedBridge.BOOTCLASSLOADER;
|
||||
if (isSystem) {
|
||||
if (useSandHook) {
|
||||
XposedCompat.addHookers(classLoader, SysBootstrapHookInfo.hookItems);
|
||||
} else {
|
||||
HookMain.doHookDefault(
|
||||
Router.class.getClassLoader(),
|
||||
classLoader,
|
||||
SysBootstrapHookInfo.class.getName());
|
||||
}
|
||||
} else {
|
||||
if (useSandHook) {
|
||||
XposedCompat.addHookers(classLoader, AppBootstrapHookInfo.hookItems);
|
||||
} else {
|
||||
HookMain.doHookDefault(
|
||||
Router.class.getClassLoader(),
|
||||
classLoader,
|
||||
AppBootstrapHookInfo.class.getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void startSystemServerHook() {
|
||||
if (useSandHook) {
|
||||
XposedCompat.addHookers(SystemMainHooker.systemServerCL, SysInnerHookInfo.hookItems);
|
||||
} else {
|
||||
HookMain.doHookDefault(
|
||||
Router.class.getClassLoader(),
|
||||
SystemMainHooker.systemServerCL,
|
||||
SysInnerHookInfo.class.getName());
|
||||
}
|
||||
}
|
||||
|
||||
public static void startWorkAroundHook() {
|
||||
if (useSandHook) {
|
||||
XposedCompat.addHookers(XposedBridge.BOOTCLASSLOADER, WorkAroundHookInfo.hookItems);
|
||||
} else {
|
||||
HookMain.doHookDefault(
|
||||
Router.class.getClassLoader(),
|
||||
XposedBridge.BOOTCLASSLOADER,
|
||||
WorkAroundHookInfo.class.getName());
|
||||
}
|
||||
}
|
||||
|
||||
public static void onForkStart() {
|
||||
forkCompleted = false;
|
||||
}
|
||||
|
||||
public static void onForkFinish() {
|
||||
forkCompleted = true;
|
||||
}
|
||||
|
||||
public static void onEnterChildProcess() {
|
||||
DynamicBridge.onForkPost();
|
||||
//enable compile in child process
|
||||
//SandHook.enableCompiler(!XposedInit.startsSystemServer);
|
||||
}
|
||||
|
||||
public static void logD(String prefix) {
|
||||
Utils.logD(String.format("%s: pkg=%s, prc=%s", prefix, AndroidAppHelper.currentPackageName(),
|
||||
AndroidAppHelper.currentProcessName()));
|
||||
}
|
||||
|
||||
public static void logE(String prefix, Throwable throwable) {
|
||||
Utils.logE(String.format("%s: pkg=%s, prc=%s", prefix, AndroidAppHelper.currentPackageName(),
|
||||
AndroidAppHelper.currentProcessName()), throwable);
|
||||
}
|
||||
|
||||
public static void injectConfig() {
|
||||
EdXpConfigGlobal.sConfig = new SandHookEdxpConfig();
|
||||
EdXpConfigGlobal.sHookProvider = new SandHookProvider();
|
||||
XposedBridge.log("using HookProvider: " + EdXpConfigGlobal.sHookProvider.getClass().getName());
|
||||
}
|
||||
}
|
||||
|
|
@ -1,10 +1,10 @@
|
|||
package com.elderdrivers.riru.edxp.sandhook.entry.bootstrap;
|
||||
package com.elderdrivers.riru.edxp.sandhook.entry;
|
||||
|
||||
import com.elderdrivers.riru.common.KeepMembers;
|
||||
import com.elderdrivers.riru.edxp.sandhook._hooker.HandleBindAppHooker;
|
||||
import com.elderdrivers.riru.edxp.sandhook._hooker.LoadedApkConstructorHooker;
|
||||
import com.elderdrivers.riru.edxp.sandhook._hooker.OnePlusWorkAroundHooker;
|
||||
import com.elderdrivers.riru.edxp.sandhook._hooker.SystemMainHooker;
|
||||
import com.elderdrivers.riru.edxp.sandhook.hooker.HandleBindAppHooker;
|
||||
import com.elderdrivers.riru.edxp.sandhook.hooker.LoadedApkConstructorHooker;
|
||||
import com.elderdrivers.riru.edxp.sandhook.hooker.OnePlusWorkAroundHooker;
|
||||
import com.elderdrivers.riru.edxp.sandhook.hooker.SystemMainHooker;
|
||||
|
||||
public class SysBootstrapHookInfo implements KeepMembers {
|
||||
public static String[] hookItemNames = {
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
package com.elderdrivers.riru.edxp.sandhook.entry.bootstrap;
|
||||
package com.elderdrivers.riru.edxp.sandhook.entry;
|
||||
|
||||
import com.elderdrivers.riru.common.KeepMembers;
|
||||
import com.elderdrivers.riru.edxp.sandhook._hooker.StartBootstrapServicesHooker;
|
||||
import com.elderdrivers.riru.edxp.sandhook.hooker.StartBootstrapServicesHooker;
|
||||
|
||||
public class SysInnerHookInfo implements KeepMembers {
|
||||
public static String[] hookItemNames = {
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
package com.elderdrivers.riru.edxp.sandhook.entry.bootstrap;
|
||||
package com.elderdrivers.riru.edxp.sandhook.entry;
|
||||
|
||||
import com.elderdrivers.riru.common.KeepMembers;
|
||||
import com.elderdrivers.riru.edxp.sandhook._hooker.OnePlusWorkAroundHooker;
|
||||
import com.elderdrivers.riru.edxp.sandhook.hooker.OnePlusWorkAroundHooker;
|
||||
|
||||
public class WorkAroundHookInfo implements KeepMembers {
|
||||
public static String[] hookItemNames = {
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
package com.elderdrivers.riru.edxp.sandhook.hooker;
|
||||
|
||||
import android.app.ActivityThread;
|
||||
|
||||
import com.elderdrivers.riru.common.KeepMembers;
|
||||
import com.elderdrivers.riru.edxp._hooker.impl.HandleBindApp;
|
||||
import com.swift.sandhook.SandHook;
|
||||
import com.swift.sandhook.annotation.HookClass;
|
||||
import com.swift.sandhook.annotation.HookMethod;
|
||||
import com.swift.sandhook.annotation.HookMethodBackup;
|
||||
import com.swift.sandhook.annotation.Param;
|
||||
import com.swift.sandhook.annotation.SkipParamCheck;
|
||||
import com.swift.sandhook.annotation.ThisObject;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import de.robv.android.xposed.XC_MethodHook;
|
||||
|
||||
@HookClass(ActivityThread.class)
|
||||
public class HandleBindAppHooker implements KeepMembers {
|
||||
|
||||
public static String className = "android.app.ActivityThread";
|
||||
public static String methodName = "handleBindApplication";
|
||||
public static String methodSig = "(Landroid/app/ActivityThread$AppBindData;)V";
|
||||
|
||||
@HookMethodBackup("handleBindApplication")
|
||||
@SkipParamCheck
|
||||
static Method backup;
|
||||
|
||||
@HookMethod("handleBindApplication")
|
||||
public static void hook(@ThisObject ActivityThread thiz, @Param("android.app.ActivityThread$AppBindData") Object bindData) throws Throwable {
|
||||
final XC_MethodHook methodHook = new HandleBindApp();
|
||||
final XC_MethodHook.MethodHookParam param = new XC_MethodHook.MethodHookParam();
|
||||
param.thisObject = thiz;
|
||||
param.args = new Object[]{bindData};
|
||||
methodHook.callBeforeHookedMethod(param);
|
||||
if (!param.returnEarly) {
|
||||
backup(thiz, bindData);
|
||||
}
|
||||
methodHook.callAfterHookedMethod(param);
|
||||
}
|
||||
|
||||
public static void backup(Object thiz, Object bindData) throws Throwable {
|
||||
SandHook.callOriginByBackup(backup, thiz, bindData);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
package com.elderdrivers.riru.edxp.sandhook.hooker;
|
||||
|
||||
import android.app.ActivityThread;
|
||||
import android.app.LoadedApk;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.res.CompatibilityInfo;
|
||||
|
||||
import com.elderdrivers.riru.common.KeepMembers;
|
||||
import com.elderdrivers.riru.edxp._hooker.impl.LoadedApkCstr;
|
||||
import com.swift.sandhook.SandHook;
|
||||
import com.swift.sandhook.annotation.HookClass;
|
||||
import com.swift.sandhook.annotation.HookMethod;
|
||||
import com.swift.sandhook.annotation.HookMethodBackup;
|
||||
import com.swift.sandhook.annotation.SkipParamCheck;
|
||||
import com.swift.sandhook.annotation.ThisObject;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import de.robv.android.xposed.XC_MethodHook;
|
||||
|
||||
@HookClass(LoadedApk.class)
|
||||
public class LoadedApkConstructorHooker implements KeepMembers {
|
||||
public static String className = "android.app.LoadedApk";
|
||||
public static String methodName = "<init>";
|
||||
public static String methodSig = "(Landroid/app/ActivityThread;" +
|
||||
"Landroid/content/pm/ApplicationInfo;" +
|
||||
"Landroid/content/res/CompatibilityInfo;" +
|
||||
"Ljava/lang/ClassLoader;ZZZ)V";
|
||||
|
||||
@HookMethodBackup
|
||||
@SkipParamCheck
|
||||
static Method backup;
|
||||
|
||||
@HookMethod
|
||||
public static void hook(@ThisObject Object thiz, ActivityThread activityThread,
|
||||
ApplicationInfo aInfo, CompatibilityInfo compatInfo,
|
||||
ClassLoader baseLoader, boolean securityViolation,
|
||||
boolean includeCode, boolean registerPackage) throws Throwable {
|
||||
final XC_MethodHook methodHook = new LoadedApkCstr();
|
||||
final XC_MethodHook.MethodHookParam param = new XC_MethodHook.MethodHookParam();
|
||||
param.thisObject = thiz;
|
||||
param.args = new Object[]{activityThread, aInfo, compatInfo, baseLoader, securityViolation,
|
||||
includeCode, registerPackage};
|
||||
methodHook.callBeforeHookedMethod(param);
|
||||
if (!param.returnEarly) {
|
||||
backup(thiz, activityThread, aInfo, compatInfo, baseLoader, securityViolation,
|
||||
includeCode, registerPackage);
|
||||
}
|
||||
methodHook.callAfterHookedMethod(param);
|
||||
}
|
||||
|
||||
public static void backup(Object thiz, ActivityThread activityThread,
|
||||
ApplicationInfo aInfo, CompatibilityInfo compatInfo,
|
||||
ClassLoader baseLoader, boolean securityViolation,
|
||||
boolean includeCode, boolean registerPackage) throws Throwable {
|
||||
SandHook.callOriginByBackup(backup, thiz, activityThread, aInfo, compatInfo, baseLoader, securityViolation, includeCode, registerPackage);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
package com.elderdrivers.riru.edxp.sandhook.hooker;
|
||||
|
||||
import com.elderdrivers.riru.common.KeepMembers;
|
||||
import com.elderdrivers.riru.edxp._hooker.impl.OneplusWorkaround;
|
||||
import com.elderdrivers.riru.edxp.core.yahfa.HookMain;
|
||||
import com.swift.sandhook.SandHook;
|
||||
import com.swift.sandhook.annotation.HookClass;
|
||||
import com.swift.sandhook.annotation.HookMethod;
|
||||
import com.swift.sandhook.annotation.HookMethodBackup;
|
||||
import com.swift.sandhook.annotation.SkipParamCheck;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import dalvik.system.BaseDexClassLoader;
|
||||
import de.robv.android.xposed.XC_MethodHook;
|
||||
|
||||
@HookClass(BaseDexClassLoader.class)
|
||||
public class OnePlusWorkAroundHooker implements KeepMembers {
|
||||
|
||||
static {
|
||||
HookMain.addHookItemWhiteList(OnePlusWorkAroundHooker.class.getName());
|
||||
}
|
||||
|
||||
public static String className = "dalvik.system.BaseDexClassLoader";
|
||||
public static String methodName = "inCompatConfigList";
|
||||
public static String methodSig = "(ILjava/lang/String;)Z";
|
||||
|
||||
@HookMethodBackup("inCompatConfigList")
|
||||
@SkipParamCheck
|
||||
static Method backup;
|
||||
|
||||
@HookMethod("inCompatConfigList")
|
||||
public static boolean hook(int type, String packageName) throws Throwable {
|
||||
final XC_MethodHook methodHook = new OneplusWorkaround();
|
||||
final XC_MethodHook.MethodHookParam param = new XC_MethodHook.MethodHookParam();
|
||||
param.thisObject = null;
|
||||
param.args = new Object[]{type, packageName};
|
||||
methodHook.callBeforeHookedMethod(param);
|
||||
if (!param.returnEarly) {
|
||||
param.setResult(backup(type, packageName));
|
||||
}
|
||||
methodHook.callAfterHookedMethod(param);
|
||||
return (boolean) param.getResult();
|
||||
}
|
||||
|
||||
public static boolean backup(int type, String packageName) throws Throwable {
|
||||
return (boolean) SandHook.callOriginByBackup(backup, null, type, packageName);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
package com.elderdrivers.riru.edxp.sandhook.hooker;
|
||||
|
||||
import com.elderdrivers.riru.common.KeepMembers;
|
||||
import com.elderdrivers.riru.edxp._hooker.impl.StartBootstrapServices;
|
||||
import com.swift.sandhook.SandHook;
|
||||
import com.swift.sandhook.annotation.HookMethod;
|
||||
import com.swift.sandhook.annotation.HookMethodBackup;
|
||||
import com.swift.sandhook.annotation.HookReflectClass;
|
||||
import com.swift.sandhook.annotation.SkipParamCheck;
|
||||
import com.swift.sandhook.annotation.ThisObject;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import de.robv.android.xposed.XC_MethodHook;
|
||||
|
||||
@HookReflectClass("com.android.server.SystemServer")
|
||||
public class StartBootstrapServicesHooker implements KeepMembers {
|
||||
public static String className = "com.android.server.SystemServer";
|
||||
public static String methodName = "startBootstrapServices";
|
||||
public static String methodSig = "()V";
|
||||
|
||||
@HookMethodBackup("startBootstrapServices")
|
||||
@SkipParamCheck
|
||||
static Method backup;
|
||||
|
||||
@HookMethod("startBootstrapServices")
|
||||
public static void hook(@ThisObject Object systemServer) throws Throwable {
|
||||
final XC_MethodHook methodHook = new StartBootstrapServices();
|
||||
final XC_MethodHook.MethodHookParam param = new XC_MethodHook.MethodHookParam();
|
||||
param.thisObject = systemServer;
|
||||
param.args = new Object[]{};
|
||||
methodHook.callBeforeHookedMethod(param);
|
||||
if (!param.returnEarly) {
|
||||
backup(systemServer);
|
||||
}
|
||||
methodHook.callAfterHookedMethod(param);
|
||||
}
|
||||
|
||||
public static void backup(Object systemServer) throws Throwable {
|
||||
SandHook.callOriginByBackup(backup, systemServer);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,10 +1,9 @@
|
|||
package com.elderdrivers.riru.edxp.sandhook._hooker;
|
||||
package com.elderdrivers.riru.edxp.sandhook.hooker;
|
||||
|
||||
import android.app.ActivityThread;
|
||||
|
||||
import com.elderdrivers.riru.common.KeepMembers;
|
||||
import com.elderdrivers.riru.edxp.deopt.PrebuiltMethodsDeopter;
|
||||
import com.elderdrivers.riru.edxp.sandhook.entry.Router;
|
||||
import com.elderdrivers.riru.edxp._hooker.impl.OneplusWorkaround;
|
||||
import com.swift.sandhook.SandHook;
|
||||
import com.swift.sandhook.annotation.HookClass;
|
||||
import com.swift.sandhook.annotation.HookMethod;
|
||||
|
|
@ -12,7 +11,7 @@ import com.swift.sandhook.annotation.HookMethodBackup;
|
|||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import de.robv.android.xposed.XposedBridge;
|
||||
import de.robv.android.xposed.XC_MethodHook;
|
||||
|
||||
|
||||
// system_server initialization
|
||||
|
|
@ -31,21 +30,16 @@ public class SystemMainHooker implements KeepMembers {
|
|||
|
||||
@HookMethod("systemMain")
|
||||
public static ActivityThread hook() throws Throwable {
|
||||
if (XposedBridge.disableHooks) {
|
||||
return backup();
|
||||
final XC_MethodHook methodHook = new OneplusWorkaround();
|
||||
final XC_MethodHook.MethodHookParam param = new XC_MethodHook.MethodHookParam();
|
||||
param.thisObject = null;
|
||||
param.args = new Object[]{};
|
||||
methodHook.callBeforeHookedMethod(param);
|
||||
if (!param.returnEarly) {
|
||||
param.setResult(backup());
|
||||
}
|
||||
Router.logD("ActivityThread#systemMain() starts");
|
||||
ActivityThread activityThread = backup();
|
||||
try {
|
||||
// get system_server classLoader
|
||||
systemServerCL = Thread.currentThread().getContextClassLoader();
|
||||
// deopt methods in SYSTEMSERVERCLASSPATH
|
||||
PrebuiltMethodsDeopter.deoptSystemServerMethods(systemServerCL);
|
||||
Router.startSystemServerHook();
|
||||
} catch (Throwable t) {
|
||||
Router.logE("error when hooking systemMain", t);
|
||||
}
|
||||
return activityThread;
|
||||
methodHook.callAfterHookedMethod(param);
|
||||
return (ActivityThread) param.getResult();
|
||||
}
|
||||
|
||||
public static ActivityThread backup() throws Throwable {
|
||||
|
|
@ -1,137 +0,0 @@
|
|||
package com.elderdrivers.riru.edxp.sandhook.proxy;
|
||||
|
||||
import android.text.TextUtils;
|
||||
|
||||
import com.elderdrivers.riru.edxp.Main;
|
||||
import com.elderdrivers.riru.edxp.config.ConfigManager;
|
||||
import com.elderdrivers.riru.edxp.deopt.PrebuiltMethodsDeopter;
|
||||
import com.elderdrivers.riru.edxp.framework.Zygote;
|
||||
import com.elderdrivers.riru.edxp.sandhook.entry.Router;
|
||||
import com.elderdrivers.riru.edxp.util.ProcessUtils;
|
||||
import com.elderdrivers.riru.edxp.util.Utils;
|
||||
|
||||
import de.robv.android.xposed.XposedBridge;
|
||||
|
||||
import static com.elderdrivers.riru.edxp.util.FileUtils.getDataPathPrefix;
|
||||
|
||||
/**
|
||||
* 1. Non dynamic mode
|
||||
* - system_server is whitelisted
|
||||
* * for all child processes of main zygote
|
||||
* What've been done in main zygote pre-forking system_server
|
||||
* 1) non dynamic flag set (no need to reset)
|
||||
* 2) boot image methods deopted (no need to redo)
|
||||
* 3) startSystemServer flag set to true (need to reset)
|
||||
* 4) workaround hooks installed (need to redo)
|
||||
* 5) module list loaded and initZygote called (no need to redo)
|
||||
* 6) close all fds (no need to redo because of 5))
|
||||
* * for all child processes of secondary zygote
|
||||
* 1) do the same things pre-forking first child process
|
||||
* - system_server is blacklisted:
|
||||
* * for all child processes of both main zygote and secondary zygote
|
||||
* 1) do the same things pre-forking first child process
|
||||
* 2. Dynamic mode:
|
||||
* to be continued
|
||||
*/
|
||||
public class BlackWhiteListProxy {
|
||||
|
||||
public static void forkAndSpecializePre(int uid, int gid, int[] gids, int debugFlags,
|
||||
int[][] rlimits, int mountExternal, String seInfo,
|
||||
String niceName, int[] fdsToClose, int[] fdsToIgnore,
|
||||
boolean startChildZygote, String instructionSet,
|
||||
String appDataDir) {
|
||||
final boolean isDynamicModulesMode = ConfigManager.isDynamicModulesEnabled();
|
||||
if (isDynamicModulesMode) {
|
||||
// should never happen
|
||||
return;
|
||||
}
|
||||
// only enter here when isDynamicModulesMode is off
|
||||
onForkPreForNonDynamicMode(false);
|
||||
}
|
||||
|
||||
public static void forkAndSpecializePost(int pid, String appDataDir, String niceName) {
|
||||
onForkPostCommon(false, appDataDir, niceName);
|
||||
}
|
||||
|
||||
public static void forkSystemServerPre(int uid, int gid, int[] gids, int debugFlags,
|
||||
int[][] rlimits, long permittedCapabilities,
|
||||
long effectiveCapabilities) {
|
||||
final boolean isDynamicModulesMode = ConfigManager.isDynamicModulesEnabled();
|
||||
if (isDynamicModulesMode) {
|
||||
// should never happen
|
||||
return;
|
||||
}
|
||||
// only enter here when isDynamicModulesMode is off
|
||||
onForkPreForNonDynamicMode(true);
|
||||
}
|
||||
|
||||
public static void forkSystemServerPost(int pid) {
|
||||
onForkPostCommon(true, getDataPathPrefix() + "android", "system_server");
|
||||
}
|
||||
|
||||
/**
|
||||
* Some details are different between main zygote and secondary zygote.
|
||||
*/
|
||||
private static void onForkPreForNonDynamicMode(boolean isSystemServer) {
|
||||
Router.onForkStart();
|
||||
Router.initResourcesHook();
|
||||
// set startsSystemServer flag used when loadModules
|
||||
Router.prepare(isSystemServer);
|
||||
// deoptBootMethods once for all child processes of zygote
|
||||
PrebuiltMethodsDeopter.deoptBootMethods();
|
||||
// we never install bootstrap hooks here in black/white list mode except workaround hooks
|
||||
// because installed hooks would be propagated to all child processes of zygote
|
||||
Router.startWorkAroundHook();
|
||||
// loadModules once for all child processes of zygote
|
||||
// TODO maybe just save initZygote callbacks and call them when whitelisted process forked?
|
||||
Router.loadModulesSafely(true);
|
||||
Zygote.closeFilesBeforeFork();
|
||||
}
|
||||
|
||||
private static void onForkPostCommon(boolean isSystemServer, String appDataDir, String niceName) {
|
||||
Main.setAppDataDir(appDataDir);
|
||||
Main.niceName = niceName;
|
||||
final boolean isDynamicModulesMode = ConfigManager.isDynamicModulesEnabled();
|
||||
if (!isDynamicModulesMode) {
|
||||
Zygote.reopenFilesAfterFork();
|
||||
}
|
||||
Router.onEnterChildProcess();
|
||||
if (!checkNeedHook(appDataDir, niceName)) {
|
||||
// if is blacklisted, just stop here
|
||||
Router.onForkFinish();
|
||||
return;
|
||||
}
|
||||
if (isDynamicModulesMode) {
|
||||
Router.initResourcesHook();
|
||||
}
|
||||
Router.prepare(isSystemServer);
|
||||
PrebuiltMethodsDeopter.deoptBootMethods();
|
||||
Router.installBootstrapHooks(isSystemServer);
|
||||
if (isDynamicModulesMode) {
|
||||
Router.loadModulesSafely(false);
|
||||
}
|
||||
Router.onForkFinish();
|
||||
}
|
||||
|
||||
private static boolean checkNeedHook(String appDataDir, String niceName) {
|
||||
boolean needHook;
|
||||
if (TextUtils.isEmpty(appDataDir)) {
|
||||
Utils.logE("niceName:" + niceName + ", procName:"
|
||||
+ ProcessUtils.getCurrentProcessName(Main.appProcessName) + ", appDataDir is null, blacklisted!");
|
||||
needHook = false;
|
||||
} else {
|
||||
// FIXME some process cannot read app_data_file because of MLS, e.g. bluetooth
|
||||
needHook = ConfigManager.isAppNeedHook(appDataDir);
|
||||
}
|
||||
if (!needHook) {
|
||||
// clean up the scene
|
||||
onBlackListed();
|
||||
}
|
||||
return needHook;
|
||||
}
|
||||
|
||||
private static void onBlackListed() {
|
||||
XposedBridge.clearLoadedPackages();
|
||||
XposedBridge.clearInitPackageResources();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,73 +0,0 @@
|
|||
package com.elderdrivers.riru.edxp.sandhook.proxy;
|
||||
|
||||
import com.elderdrivers.riru.edxp.Main;
|
||||
import com.elderdrivers.riru.edxp.config.ConfigManager;
|
||||
import com.elderdrivers.riru.edxp.deopt.PrebuiltMethodsDeopter;
|
||||
import com.elderdrivers.riru.edxp.framework.Zygote;
|
||||
import com.elderdrivers.riru.edxp.sandhook.entry.Router;
|
||||
|
||||
import static com.elderdrivers.riru.edxp.util.FileUtils.getDataPathPrefix;
|
||||
|
||||
public class NormalProxy {
|
||||
|
||||
public static void forkAndSpecializePre(int uid, int gid, int[] gids, int debugFlags,
|
||||
int[][] rlimits, int mountExternal, String seInfo,
|
||||
String niceName, int[] fdsToClose, int[] fdsToIgnore,
|
||||
boolean startChildZygote, String instructionSet,
|
||||
String appDataDir) {
|
||||
// mainly for secondary zygote
|
||||
Router.onForkStart();
|
||||
Router.initResourcesHook();
|
||||
// call this to ensure the flag is set to false ASAP
|
||||
Router.prepare(false);
|
||||
PrebuiltMethodsDeopter.deoptBootMethods(); // do it once for secondary zygote
|
||||
// install bootstrap hooks for secondary zygote
|
||||
Router.installBootstrapHooks(false);
|
||||
// only load modules for secondary zygote
|
||||
Router.loadModulesSafely(true);
|
||||
Zygote.closeFilesBeforeFork();
|
||||
}
|
||||
|
||||
public static void forkAndSpecializePost(int pid, String appDataDir, String niceName) {
|
||||
// TODO consider processes without forkAndSpecializePost called
|
||||
Main.setAppDataDir(appDataDir);
|
||||
Main.niceName = niceName;
|
||||
Router.prepare(false);
|
||||
Zygote.reopenFilesAfterFork();
|
||||
Router.onEnterChildProcess();
|
||||
// load modules for each app process on its forked if dynamic modules mode is on
|
||||
Router.loadModulesSafely(false);
|
||||
Router.onForkFinish();
|
||||
}
|
||||
|
||||
public static void forkSystemServerPre(int uid, int gid, int[] gids, int debugFlags, int[][] rlimits,
|
||||
long permittedCapabilities, long effectiveCapabilities) {
|
||||
Router.onForkStart();
|
||||
Router.initResourcesHook();
|
||||
// set startsSystemServer flag used when loadModules
|
||||
Router.prepare(true);
|
||||
PrebuiltMethodsDeopter.deoptBootMethods(); // do it once for main zygote
|
||||
// install bootstrap hooks for main zygote as early as possible
|
||||
// in case we miss some processes not forked via forkAndSpecialize
|
||||
// for instance com.android.phone
|
||||
Router.installBootstrapHooks(true);
|
||||
// loadModules have to be executed in zygote even isDynamicModules is false
|
||||
// because if not global hooks installed in initZygote might not be
|
||||
// propagated to processes not forked via forkAndSpecialize
|
||||
Router.loadModulesSafely(true);
|
||||
Zygote.closeFilesBeforeFork();
|
||||
}
|
||||
|
||||
public static void forkSystemServerPost(int pid) {
|
||||
// in system_server process
|
||||
Main.setAppDataDir(getDataPathPrefix() + "android");
|
||||
Main.niceName = "system_server";
|
||||
Router.prepare(true);
|
||||
Zygote.reopenFilesAfterFork();
|
||||
Router.onEnterChildProcess();
|
||||
// reload module list if dynamic mode is on
|
||||
Router.loadModulesSafely(false);
|
||||
Router.onForkFinish();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -4,6 +4,7 @@ import android.annotation.SuppressLint;
|
|||
import android.os.Process;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import com.elderdrivers.riru.edxp.config.ConfigManager;
|
||||
import com.swift.sandhook.SandHook;
|
||||
import com.swift.sandhook.xposedcompat.classloaders.ComposeClassLoader;
|
||||
import com.swift.sandhook.xposedcompat.methodgen.SandHookXposedBridge;
|
||||
|
|
@ -21,8 +22,6 @@ import static com.swift.sandhook.xposedcompat.utils.FileUtils.IS_USING_PROTECTED
|
|||
|
||||
public class XposedCompat {
|
||||
|
||||
public static volatile String appDataDir;
|
||||
|
||||
// TODO initialize these variables
|
||||
public static volatile File cacheDir;
|
||||
public static volatile ClassLoader classLoader;
|
||||
|
|
@ -37,16 +36,17 @@ public class XposedCompat {
|
|||
public static void addHookers(ClassLoader classLoader, Class[] hookers) {
|
||||
if (hookers == null)
|
||||
return;
|
||||
for (Class hooker:hookers) {
|
||||
for (Class hooker : hookers) {
|
||||
try {
|
||||
SandHook.addHookClass(classLoader, hooker);
|
||||
} catch (Throwable throwable) {}
|
||||
} catch (Throwable throwable) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static File getCacheDir() {
|
||||
if (cacheDir == null) {
|
||||
String fixedAppDataDir = getDataPathPrefix() + getPackageName(appDataDir) + "/";
|
||||
String fixedAppDataDir = getDataPathPrefix() + getPackageName(ConfigManager.appDataDir) + "/";
|
||||
cacheDir = new File(fixedAppDataDir, "/cache/sandhook/"
|
||||
+ ProcessUtils.getProcessName().replace(":", "_") + "/");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1 @@
|
|||
com.elderdrivers.riru.edxp.sandhook.core.SandHookEdxpImpl
|
||||
|
|
@ -12,6 +12,7 @@ android {
|
|||
targetSdkVersion 28
|
||||
versionCode 1
|
||||
versionName "1.0"
|
||||
multiDexEnabled true
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
|
|
@ -60,7 +61,8 @@ afterEvaluate {
|
|||
|
||||
task("makeAndCopy${variantNameCapped}", type: Jar, dependsOn: "assemble${variantNameCapped}") {
|
||||
dependsOn tasks.getByPath(":edxp-common:copyCommonProperties")
|
||||
from "${buildDir}/intermediates/transforms/dexMerger/${variantNameLowered}/0/"
|
||||
from "${buildDir}/intermediates/transforms/dexMerger/${variantNameLowered}/0/",
|
||||
"${projectDir}/src/main/resources/"
|
||||
destinationDir file(myTemplatePath + "system/framework/")
|
||||
baseName "edxp"
|
||||
doLast {
|
||||
|
|
|
|||
|
|
@ -1,106 +0,0 @@
|
|||
package com.elderdrivers.riru.edxp;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.os.Build;
|
||||
import android.os.Process;
|
||||
|
||||
import com.elderdrivers.riru.common.KeepAll;
|
||||
import com.elderdrivers.riru.edxp.config.ConfigManager;
|
||||
import com.elderdrivers.riru.edxp.config.InstallerChooser;
|
||||
import com.elderdrivers.riru.edxp.core.Yahfa;
|
||||
import com.elderdrivers.riru.edxp.util.Utils;
|
||||
import com.elderdrivers.riru.edxp.whale.core.HookMethodResolver;
|
||||
import com.elderdrivers.riru.edxp.whale.entry.Router;
|
||||
import com.elderdrivers.riru.edxp.whale.proxy.BlackWhiteListProxy;
|
||||
import com.elderdrivers.riru.edxp.whale.proxy.NormalProxy;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
@SuppressLint("DefaultLocale")
|
||||
public class Main implements KeepAll {
|
||||
|
||||
public static String appDataDir = "";
|
||||
public static String niceName = "";
|
||||
public static String appProcessName = "";
|
||||
private static String forkAndSpecializePramsStr = "";
|
||||
private static String forkSystemServerPramsStr = "";
|
||||
|
||||
static {
|
||||
Yahfa.init(Build.VERSION.SDK_INT);
|
||||
HookMethodResolver.init();
|
||||
Router.injectConfig();
|
||||
InstallerChooser.setInstallerPackageName(ConfigManager.getInstallerPackageName());
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// entry points
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public static void forkAndSpecializePre(int uid, int gid, int[] gids, int debugFlags,
|
||||
int[][] rlimits, int mountExternal, String seInfo,
|
||||
String niceName, int[] fdsToClose, int[] fdsToIgnore,
|
||||
boolean startChildZygote, String instructionSet,
|
||||
String appDataDir) {
|
||||
if (BuildConfig.DEBUG) {
|
||||
forkAndSpecializePramsStr = String.format(
|
||||
"Zygote#forkAndSpecialize(%d, %d, %s, %d, %s, %d, %s, %s, %s, %s, %s, %s, %s)",
|
||||
uid, gid, Arrays.toString(gids), debugFlags, Arrays.toString(rlimits),
|
||||
mountExternal, seInfo, niceName, Arrays.toString(fdsToClose),
|
||||
Arrays.toString(fdsToIgnore), startChildZygote, instructionSet, appDataDir);
|
||||
}
|
||||
if (ConfigManager.isBlackWhiteListEnabled()) {
|
||||
BlackWhiteListProxy.forkAndSpecializePre(uid, gid, gids, debugFlags, rlimits,
|
||||
mountExternal, seInfo, niceName, fdsToClose, fdsToIgnore, startChildZygote,
|
||||
instructionSet, appDataDir);
|
||||
} else {
|
||||
NormalProxy.forkAndSpecializePre(uid, gid, gids, debugFlags, rlimits, mountExternal,
|
||||
seInfo, niceName, fdsToClose, fdsToIgnore, startChildZygote, instructionSet,
|
||||
appDataDir);
|
||||
}
|
||||
}
|
||||
|
||||
public static void forkAndSpecializePost(int pid, String appDataDir, String niceName) {
|
||||
if (pid == 0) {
|
||||
Utils.logD(forkAndSpecializePramsStr + " = " + Process.myPid());
|
||||
if (ConfigManager.isBlackWhiteListEnabled()) {
|
||||
BlackWhiteListProxy.forkAndSpecializePost(pid, appDataDir, niceName);
|
||||
} else {
|
||||
NormalProxy.forkAndSpecializePost(pid, appDataDir, niceName);
|
||||
}
|
||||
} else {
|
||||
// in zygote process, res is child zygote pid
|
||||
// don't print log here, see https://github.com/RikkaApps/Riru/blob/77adfd6a4a6a81bfd20569c910bc4854f2f84f5e/riru-core/jni/main/jni_native_method.cpp#L55-L66
|
||||
}
|
||||
}
|
||||
|
||||
public static void forkSystemServerPre(int uid, int gid, int[] gids, int debugFlags, int[][] rlimits,
|
||||
long permittedCapabilities, long effectiveCapabilities) {
|
||||
if (BuildConfig.DEBUG) {
|
||||
forkSystemServerPramsStr = String.format("Zygote#forkSystemServer(%d, %d, %s, %d, %s, %d, %d)",
|
||||
uid, gid, Arrays.toString(gids), debugFlags, Arrays.toString(rlimits),
|
||||
permittedCapabilities, effectiveCapabilities);
|
||||
}
|
||||
if (ConfigManager.isBlackWhiteListEnabled()) {
|
||||
BlackWhiteListProxy.forkSystemServerPre(uid, gid, gids, debugFlags, rlimits,
|
||||
permittedCapabilities, effectiveCapabilities);
|
||||
} else {
|
||||
NormalProxy.forkSystemServerPre(uid, gid, gids, debugFlags, rlimits,
|
||||
permittedCapabilities, effectiveCapabilities);
|
||||
}
|
||||
}
|
||||
|
||||
public static void forkSystemServerPost(int pid) {
|
||||
if (pid == 0) {
|
||||
Utils.logD(forkSystemServerPramsStr + " = " + Process.myPid());
|
||||
if (ConfigManager.isBlackWhiteListEnabled()) {
|
||||
BlackWhiteListProxy.forkSystemServerPost(pid);
|
||||
} else {
|
||||
NormalProxy.forkSystemServerPost(pid);
|
||||
}
|
||||
} else {
|
||||
// in zygote process, res is child zygote pid
|
||||
// don't print log here, see https://github.com/RikkaApps/Riru/blob/77adfd6a4a6a81bfd20569c910bc4854f2f84f5e/riru-core/jni/main/jni_native_method.cpp#L55-L66
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,99 +0,0 @@
|
|||
package com.elderdrivers.riru.edxp.whale._hooker;
|
||||
|
||||
import android.app.ActivityThread;
|
||||
import android.app.AndroidAppHelper;
|
||||
import android.app.LoadedApk;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.res.CompatibilityInfo;
|
||||
import android.util.Log;
|
||||
|
||||
import com.elderdrivers.riru.common.KeepMembers;
|
||||
import com.elderdrivers.riru.edxp.hooker.XposedBlackListHooker;
|
||||
import com.elderdrivers.riru.edxp.whale.entry.Router;
|
||||
|
||||
import de.robv.android.xposed.XposedBridge;
|
||||
import de.robv.android.xposed.XposedHelpers;
|
||||
import de.robv.android.xposed.XposedInit;
|
||||
import de.robv.android.xposed.callbacks.XC_LoadPackage;
|
||||
|
||||
import static com.elderdrivers.riru.edxp.util.ClassLoaderUtils.replaceParentClassLoader;
|
||||
|
||||
// when a package is loaded for an existing process, trigger the callbacks as well
|
||||
// ed: remove resources related hooking
|
||||
public class LoadedApkConstructorHooker implements KeepMembers {
|
||||
public static String className = "android.app.LoadedApk";
|
||||
public static String methodName = "<init>";
|
||||
public static String methodSig = "(Landroid/app/ActivityThread;" +
|
||||
"Landroid/content/pm/ApplicationInfo;" +
|
||||
"Landroid/content/res/CompatibilityInfo;" +
|
||||
"Ljava/lang/ClassLoader;ZZZ)V";
|
||||
|
||||
public static void hook(Object thiz, ActivityThread activityThread,
|
||||
ApplicationInfo aInfo, CompatibilityInfo compatInfo,
|
||||
ClassLoader baseLoader, boolean securityViolation,
|
||||
boolean includeCode, boolean registerPackage) {
|
||||
|
||||
if (XposedBlackListHooker.shouldDisableHooks("")) {
|
||||
backup(thiz, activityThread, aInfo, compatInfo, baseLoader, securityViolation,
|
||||
includeCode, registerPackage);
|
||||
return;
|
||||
}
|
||||
|
||||
Router.logD("LoadedApk#<init> starts");
|
||||
backup(thiz, activityThread, aInfo, compatInfo, baseLoader, securityViolation,
|
||||
includeCode, registerPackage);
|
||||
|
||||
try {
|
||||
LoadedApk loadedApk = (LoadedApk) thiz;
|
||||
String packageName = loadedApk.getPackageName();
|
||||
Object mAppDir = XposedHelpers.getObjectField(thiz, "mAppDir");
|
||||
Router.logD("LoadedApk#<init> ends: " + mAppDir);
|
||||
|
||||
if (XposedBlackListHooker.shouldDisableHooks(packageName)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (packageName.equals("android")) {
|
||||
Router.logD("LoadedApk#<init> is android, skip: " + mAppDir);
|
||||
return;
|
||||
}
|
||||
|
||||
// mIncludeCode checking should go ahead of loadedPackagesInProcess added checking
|
||||
if (!XposedHelpers.getBooleanField(loadedApk, "mIncludeCode")) {
|
||||
Router.logD("LoadedApk#<init> mIncludeCode == false: " + mAppDir);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!XposedInit.loadedPackagesInProcess.add(packageName)) {
|
||||
Router.logD("LoadedApk#<init> has been loaded before, skip: " + mAppDir);
|
||||
return;
|
||||
}
|
||||
|
||||
// OnePlus magic...
|
||||
if (Log.getStackTraceString(new Throwable()).
|
||||
contains("android.app.ActivityThread$ApplicationThread.schedulePreload")) {
|
||||
Router.logD("LoadedApk#<init> maybe oneplus's custom opt, skip");
|
||||
return;
|
||||
}
|
||||
|
||||
replaceParentClassLoader(loadedApk.getClassLoader());
|
||||
|
||||
XC_LoadPackage.LoadPackageParam lpparam = new XC_LoadPackage.LoadPackageParam(XposedBridge.sLoadedPackageCallbacks);
|
||||
lpparam.packageName = packageName;
|
||||
lpparam.processName = AndroidAppHelper.currentProcessName();
|
||||
lpparam.classLoader = loadedApk.getClassLoader();
|
||||
lpparam.appInfo = loadedApk.getApplicationInfo();
|
||||
lpparam.isFirstApplication = false;
|
||||
XC_LoadPackage.callAll(lpparam);
|
||||
} catch (Throwable t) {
|
||||
Router.logE("error when hooking LoadedApk.<init>", t);
|
||||
}
|
||||
}
|
||||
|
||||
public static void backup(Object thiz, ActivityThread activityThread,
|
||||
ApplicationInfo aInfo, CompatibilityInfo compatInfo,
|
||||
ClassLoader baseLoader, boolean securityViolation,
|
||||
boolean includeCode, boolean registerPackage) {
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -1,41 +0,0 @@
|
|||
package com.elderdrivers.riru.edxp.whale._hooker;
|
||||
|
||||
import com.elderdrivers.riru.common.KeepMembers;
|
||||
import com.elderdrivers.riru.edxp.Main;
|
||||
import com.elderdrivers.riru.edxp.whale.entry.Router;
|
||||
|
||||
import de.robv.android.xposed.XposedBridge;
|
||||
|
||||
/**
|
||||
* On OnePlus stock roms (Android Pie), {@link dalvik.system.BaseDexClassLoader#findClass(String)}
|
||||
* will open /dev/binder to communicate with PackageManagerService to check whether
|
||||
* current package name inCompatConfigList, which is an OnePlus OEM feature enabled only when
|
||||
* system prop "persist.sys.oem.region" set to "CN".(detail of related source code:
|
||||
* https://gist.github.com/solohsu/ecc07141759958fc096ba0781fac0a5f)
|
||||
* If we invoke intZygoteCallbacks in
|
||||
* {@link Main#forkAndSpecializePre}, where in zygote process,
|
||||
* we would get a chance to invoke findclass, leaving fd of /dev/binder open in zygote process,
|
||||
* which is not allowed because /dev/binder is not in predefined whitelist here:
|
||||
* http://androidxref.com/9.0.0_r3/xref/frameworks/base/core/jni/fd_utils.cpp#35
|
||||
* So we just hook BaseDexClassLoader#inCompatConfigList to return false to prevent
|
||||
* open of /dev/binder and we haven't found side effects yet.
|
||||
* Other roms might share the same problems but not reported too.
|
||||
*/
|
||||
public class OnePlusWorkAroundHooker implements KeepMembers {
|
||||
|
||||
public static String className = "dalvik.system.BaseDexClassLoader";
|
||||
public static String methodName = "inCompatConfigList";
|
||||
public static String methodSig = "(ILjava/lang/String;)Z";
|
||||
|
||||
public static boolean hook(int type, String packageName) {
|
||||
if (XposedBridge.disableHooks || Router.forkCompleted) {
|
||||
return backup(type, packageName);
|
||||
}
|
||||
Router.logD("BaseDexClassLoader#inCompatConfigList() starts");
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean backup(int type, String packageName) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,66 +0,0 @@
|
|||
package com.elderdrivers.riru.edxp.whale._hooker;
|
||||
|
||||
import android.os.Build;
|
||||
|
||||
import com.elderdrivers.riru.common.KeepMembers;
|
||||
import com.elderdrivers.riru.edxp.whale.entry.Router;
|
||||
|
||||
import de.robv.android.xposed.XC_MethodReplacement;
|
||||
import de.robv.android.xposed.XposedBridge;
|
||||
import de.robv.android.xposed.XposedHelpers;
|
||||
import de.robv.android.xposed.XposedInit;
|
||||
import de.robv.android.xposed.callbacks.XC_LoadPackage;
|
||||
|
||||
import static com.elderdrivers.riru.edxp.util.ClassLoaderUtils.replaceParentClassLoader;
|
||||
import static com.elderdrivers.riru.edxp.util.Utils.logD;
|
||||
import static de.robv.android.xposed.XposedHelpers.findAndHookMethod;
|
||||
|
||||
public class StartBootstrapServicesHooker implements KeepMembers {
|
||||
public static String className = "com.android.server.SystemServer";
|
||||
public static String methodName = "startBootstrapServices";
|
||||
public static String methodSig = "()V";
|
||||
|
||||
public static void hook(Object systemServer) {
|
||||
|
||||
if (XposedBridge.disableHooks) {
|
||||
backup(systemServer);
|
||||
return;
|
||||
}
|
||||
|
||||
logD("SystemServer#startBootstrapServices() starts");
|
||||
|
||||
try {
|
||||
XposedInit.loadedPackagesInProcess.add("android");
|
||||
|
||||
replaceParentClassLoader(SystemMainHooker.systemServerCL);
|
||||
|
||||
XC_LoadPackage.LoadPackageParam lpparam = new XC_LoadPackage.LoadPackageParam(XposedBridge.sLoadedPackageCallbacks);
|
||||
lpparam.packageName = "android";
|
||||
lpparam.processName = "android"; // it's actually system_server, but other functions return this as well
|
||||
lpparam.classLoader = SystemMainHooker.systemServerCL;
|
||||
lpparam.appInfo = null;
|
||||
lpparam.isFirstApplication = true;
|
||||
XC_LoadPackage.callAll(lpparam);
|
||||
|
||||
// Huawei
|
||||
try {
|
||||
findAndHookMethod("com.android.server.pm.HwPackageManagerService", SystemMainHooker.systemServerCL, "isOdexMode", XC_MethodReplacement.returnConstant(false));
|
||||
} catch (XposedHelpers.ClassNotFoundError | NoSuchMethodError ignored) {
|
||||
}
|
||||
|
||||
try {
|
||||
String className = "com.android.server.pm." + (Build.VERSION.SDK_INT >= 23 ? "PackageDexOptimizer" : "PackageManagerService");
|
||||
findAndHookMethod(className, SystemMainHooker.systemServerCL, "dexEntryExists", String.class, XC_MethodReplacement.returnConstant(true));
|
||||
} catch (XposedHelpers.ClassNotFoundError | NoSuchMethodError ignored) {
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
Router.logE("error when hooking startBootstrapServices", t);
|
||||
} finally {
|
||||
backup(systemServer);
|
||||
}
|
||||
}
|
||||
|
||||
public static void backup(Object systemServer) {
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -1,43 +0,0 @@
|
|||
package com.elderdrivers.riru.edxp.whale._hooker;
|
||||
|
||||
import android.app.ActivityThread;
|
||||
|
||||
import com.elderdrivers.riru.common.KeepMembers;
|
||||
import com.elderdrivers.riru.edxp.deopt.PrebuiltMethodsDeopter;
|
||||
import com.elderdrivers.riru.edxp.whale.entry.Router;
|
||||
|
||||
import de.robv.android.xposed.XposedBridge;
|
||||
|
||||
|
||||
// system_server initialization
|
||||
// ed: only support sdk >= 21 for now
|
||||
public class SystemMainHooker implements KeepMembers {
|
||||
|
||||
public static String className = "android.app.ActivityThread";
|
||||
public static String methodName = "systemMain";
|
||||
public static String methodSig = "()Landroid/app/ActivityThread;";
|
||||
|
||||
public static ClassLoader systemServerCL;
|
||||
|
||||
public static ActivityThread hook() {
|
||||
if (XposedBridge.disableHooks) {
|
||||
return backup();
|
||||
}
|
||||
Router.logD("ActivityThread#systemMain() starts");
|
||||
ActivityThread activityThread = backup();
|
||||
try {
|
||||
// get system_server classLoader
|
||||
systemServerCL = Thread.currentThread().getContextClassLoader();
|
||||
// deopt methods in SYSTEMSERVERCLASSPATH
|
||||
PrebuiltMethodsDeopter.deoptSystemServerMethods(systemServerCL);
|
||||
Router.startSystemServerHook();
|
||||
} catch (Throwable t) {
|
||||
Router.logE("error when hooking systemMain", t);
|
||||
}
|
||||
return activityThread;
|
||||
}
|
||||
|
||||
public static ActivityThread backup() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,5 @@
|
|||
package com.elderdrivers.riru.edxp.whale.config;
|
||||
|
||||
import com.elderdrivers.riru.edxp.Main;
|
||||
import com.elderdrivers.riru.edxp.config.ConfigManager;
|
||||
import com.elderdrivers.riru.edxp.config.EdXpConfig;
|
||||
import com.elderdrivers.riru.edxp.config.InstallerChooser;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
package com.elderdrivers.riru.edxp.whale.config;
|
||||
|
||||
import com.elderdrivers.riru.edxp.Main;
|
||||
import com.elderdrivers.riru.edxp.art.ClassLinker;
|
||||
import com.elderdrivers.riru.edxp.config.BaseHookProvider;
|
||||
import com.elderdrivers.riru.edxp.core.ResourcesHook;
|
||||
|
|
|
|||
|
|
@ -1,185 +0,0 @@
|
|||
package com.elderdrivers.riru.edxp.whale.core;
|
||||
|
||||
import com.elderdrivers.riru.edxp.Main;
|
||||
import com.elderdrivers.riru.edxp.art.Heap;
|
||||
import com.elderdrivers.riru.edxp.core.Yahfa;
|
||||
import com.elderdrivers.riru.edxp.whale._hooker.OnePlusWorkAroundHooker;
|
||||
import com.elderdrivers.riru.edxp.util.Utils;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
|
||||
import de.robv.android.xposed.XposedHelpers;
|
||||
|
||||
public class HookMain {
|
||||
|
||||
private static Set<String> hookItemWhiteList = Collections.singleton(OnePlusWorkAroundHooker.class.getName());
|
||||
|
||||
public static void doHookDefault(ClassLoader patchClassLoader, ClassLoader originClassLoader, String hookInfoClassName) {
|
||||
try {
|
||||
Class<?> hookInfoClass = Class.forName(hookInfoClassName, true, patchClassLoader);
|
||||
String[] hookItemNames = (String[]) hookInfoClass.getField("hookItemNames").get(null);
|
||||
for (String hookItemName : hookItemNames) {
|
||||
doHookItemDefault(patchClassLoader, hookItemName, originClassLoader);
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
Utils.logE("error when hooking all in: " + hookInfoClassName, e);
|
||||
}
|
||||
}
|
||||
|
||||
private static void doHookItemDefault(ClassLoader patchClassLoader, String hookItemName, ClassLoader originClassLoader) {
|
||||
try {
|
||||
Utils.logD("Start hooking with item " + hookItemName);
|
||||
Class<?> hookItem = Class.forName(hookItemName, true, patchClassLoader);
|
||||
|
||||
String className = (String) hookItem.getField("className").get(null);
|
||||
String methodName = (String) hookItem.getField("methodName").get(null);
|
||||
String methodSig = (String) hookItem.getField("methodSig").get(null);
|
||||
|
||||
if (className == null || className.equals("")) {
|
||||
Utils.logW("No target class. Skipping...");
|
||||
return;
|
||||
}
|
||||
Class<?> clazz = null;
|
||||
try {
|
||||
clazz = Class.forName(className, true, originClassLoader);
|
||||
} catch (ClassNotFoundException cnfe) {
|
||||
Utils.logE(className + " not found in " + originClassLoader);
|
||||
return;
|
||||
}
|
||||
if (Modifier.isAbstract(clazz.getModifiers())) {
|
||||
Utils.logW("Hook may fail for abstract class: " + className);
|
||||
}
|
||||
|
||||
Method hook = null;
|
||||
Method backup = null;
|
||||
for (Method method : hookItem.getDeclaredMethods()) {
|
||||
if (method.getName().equals("hook") && Modifier.isStatic(method.getModifiers())) {
|
||||
hook = method;
|
||||
} else if (method.getName().equals("backup") && Modifier.isStatic(method.getModifiers())) {
|
||||
backup = method;
|
||||
}
|
||||
}
|
||||
if (hook == null) {
|
||||
Utils.logE("Cannot find hook for " + methodName);
|
||||
return;
|
||||
}
|
||||
findAndBackupAndHook(clazz, methodName, methodSig, hook, backup);
|
||||
} catch (Throwable e) {
|
||||
if (!hookItemWhiteList.contains(hookItemName)) {
|
||||
Utils.logE("error when hooking " + hookItemName, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void findAndHook(Class targetClass, String methodName, String methodSig, Method hook) {
|
||||
hook(findMethod(targetClass, methodName, methodSig), hook);
|
||||
}
|
||||
|
||||
public static void findAndBackupAndHook(Class targetClass, String methodName, String methodSig,
|
||||
Method hook, Method backup) {
|
||||
backupAndHook(findMethod(targetClass, methodName, methodSig), hook, backup);
|
||||
}
|
||||
|
||||
public static void hook(Object target, Method hook) {
|
||||
backupAndHook(target, hook, null);
|
||||
}
|
||||
|
||||
public static void backupAndHook(Object target, Method hook, Method backup) {
|
||||
Utils.logD(String.format("target=%s, hook=%s, backup=%s", target, hook, backup));
|
||||
if (target == null) {
|
||||
throw new IllegalArgumentException("null target method");
|
||||
}
|
||||
if (hook == null) {
|
||||
throw new IllegalArgumentException("null hook method");
|
||||
}
|
||||
|
||||
if (!Modifier.isStatic(hook.getModifiers())) {
|
||||
throw new IllegalArgumentException("Hook must be a static method: " + hook);
|
||||
}
|
||||
checkCompatibleMethods(target, hook, "Original", "Hook");
|
||||
if (backup != null) {
|
||||
if (!Modifier.isStatic(backup.getModifiers())) {
|
||||
throw new IllegalArgumentException("Backup must be a static method: " + backup);
|
||||
}
|
||||
// backup is just a placeholder and the constraint could be less strict
|
||||
checkCompatibleMethods(target, backup, "Original", "Backup");
|
||||
}
|
||||
if (backup != null) {
|
||||
HookMethodResolver.resolveMethod(hook, backup);
|
||||
}
|
||||
// make sure GC completed before hook
|
||||
Thread currentThread = Thread.currentThread();
|
||||
int lastGcType = Heap.waitForGcToComplete(
|
||||
XposedHelpers.getLongField(currentThread, "nativePeer"));
|
||||
if (lastGcType < 0) {
|
||||
Utils.logW("waitForGcToComplete failed, using fallback");
|
||||
Runtime.getRuntime().gc();
|
||||
}
|
||||
if (!Yahfa.backupAndHookNative(target, hook, backup)) {
|
||||
throw new RuntimeException("Failed to hook " + target + " with " + hook);
|
||||
}
|
||||
}
|
||||
|
||||
public static Object findMethod(Class cls, String methodName, String methodSig) {
|
||||
if (cls == null) {
|
||||
throw new IllegalArgumentException("null class");
|
||||
}
|
||||
if (methodName == null) {
|
||||
throw new IllegalArgumentException("null method name");
|
||||
}
|
||||
if (methodSig == null) {
|
||||
throw new IllegalArgumentException("null method signature");
|
||||
}
|
||||
return Yahfa.findMethodNative(cls, methodName, methodSig);
|
||||
}
|
||||
|
||||
private static void checkCompatibleMethods(Object original, Method replacement, String originalName, String replacementName) {
|
||||
ArrayList<Class<?>> originalParams;
|
||||
if (original instanceof Method) {
|
||||
originalParams = new ArrayList<>(Arrays.asList(((Method) original).getParameterTypes()));
|
||||
} else if (original instanceof Constructor) {
|
||||
originalParams = new ArrayList<>(Arrays.asList(((Constructor<?>) original).getParameterTypes()));
|
||||
} else {
|
||||
throw new IllegalArgumentException("Type of target method is wrong");
|
||||
}
|
||||
|
||||
ArrayList<Class<?>> replacementParams = new ArrayList<>(Arrays.asList(replacement.getParameterTypes()));
|
||||
|
||||
if (original instanceof Method
|
||||
&& !Modifier.isStatic(((Method) original).getModifiers())) {
|
||||
originalParams.add(0, ((Method) original).getDeclaringClass());
|
||||
} else if (original instanceof Constructor) {
|
||||
originalParams.add(0, ((Constructor<?>) original).getDeclaringClass());
|
||||
}
|
||||
|
||||
|
||||
if (!Modifier.isStatic(replacement.getModifiers())) {
|
||||
replacementParams.add(0, replacement.getDeclaringClass());
|
||||
}
|
||||
|
||||
if (original instanceof Method
|
||||
&& !replacement.getReturnType().isAssignableFrom(((Method) original).getReturnType())) {
|
||||
throw new IllegalArgumentException("Incompatible return types. " + originalName + ": " + ((Method) original).getReturnType() + ", " + replacementName + ": " + replacement.getReturnType());
|
||||
} else if (original instanceof Constructor) {
|
||||
if (replacement.getReturnType().equals(Void.class)) {
|
||||
throw new IllegalArgumentException("Incompatible return types. " + "<init>" + ": " + "V" + ", " + replacementName + ": " + replacement.getReturnType());
|
||||
}
|
||||
}
|
||||
|
||||
if (originalParams.size() != replacementParams.size()) {
|
||||
throw new IllegalArgumentException("Number of arguments don't match. " + originalName + ": " + originalParams.size() + ", " + replacementName + ": " + replacementParams.size());
|
||||
}
|
||||
|
||||
for (int i = 0; i < originalParams.size(); i++) {
|
||||
if (!replacementParams.get(i).isAssignableFrom(originalParams.get(i))) {
|
||||
throw new IllegalArgumentException("Incompatible argument #" + i + ": " + originalName + ": " + originalParams.get(i) + ", " + replacementName + ": " + replacementParams.get(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
package com.elderdrivers.riru.edxp.whale.core;
|
||||
|
||||
import android.os.Build;
|
||||
|
||||
import com.elderdrivers.riru.edxp.config.ConfigManager;
|
||||
import com.elderdrivers.riru.edxp.config.InstallerChooser;
|
||||
import com.elderdrivers.riru.edxp.core.BaseEdxpImpl;
|
||||
import com.elderdrivers.riru.edxp.core.Yahfa;
|
||||
import com.elderdrivers.riru.edxp.core.yahfa.HookMethodResolver;
|
||||
|
||||
public class WhaleEdxpImpl extends BaseEdxpImpl {
|
||||
|
||||
@Override
|
||||
protected com.elderdrivers.riru.edxp.proxy.Router createRouter() {
|
||||
return new WhaleRouter();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getVariant() {
|
||||
return WHALE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init() {
|
||||
Yahfa.init(Build.VERSION.SDK_INT);
|
||||
HookMethodResolver.init();
|
||||
getRouter().injectConfig();
|
||||
InstallerChooser.setInstallerPackageName(ConfigManager.getInstallerPackageName());
|
||||
|
||||
setInitialized();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
package com.elderdrivers.riru.edxp.whale.core;
|
||||
|
||||
import com.elderdrivers.riru.edxp.config.EdXpConfigGlobal;
|
||||
import com.elderdrivers.riru.edxp.proxy.BaseRouter;
|
||||
import com.elderdrivers.riru.edxp.whale.config.WhaleEdxpConfig;
|
||||
import com.elderdrivers.riru.edxp.whale.config.WhaleHookProvider;
|
||||
|
||||
import de.robv.android.xposed.XposedBridge;
|
||||
|
||||
public class WhaleRouter extends BaseRouter {
|
||||
|
||||
public void onEnterChildProcess() {
|
||||
|
||||
}
|
||||
|
||||
public void injectConfig() {
|
||||
EdXpConfigGlobal.sConfig = new WhaleEdxpConfig();
|
||||
EdXpConfigGlobal.sHookProvider = new WhaleHookProvider();
|
||||
XposedBridge.log("using HookProvider: " + EdXpConfigGlobal.sHookProvider.getClass().getName());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,37 +0,0 @@
|
|||
package com.elderdrivers.riru.edxp.whale.dexmaker;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import com.elderdrivers.riru.edxp.BuildConfig;
|
||||
|
||||
public class DexLog {
|
||||
|
||||
public static final String TAG = "EdXposed-dexmaker";
|
||||
|
||||
public static int v(String s) {
|
||||
return Log.v(TAG, s);
|
||||
}
|
||||
|
||||
public static int i(String s) {
|
||||
return Log.i(TAG, s);
|
||||
}
|
||||
|
||||
public static int d(String s) {
|
||||
if (BuildConfig.DEBUG) {
|
||||
return Log.d(TAG, s);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static int w(String s) {
|
||||
return Log.w(TAG, s);
|
||||
}
|
||||
|
||||
public static int e(String s) {
|
||||
return Log.e(TAG, s);
|
||||
}
|
||||
|
||||
public static int e(String s, Throwable t) {
|
||||
return Log.e(TAG, s, t);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,94 +0,0 @@
|
|||
package com.elderdrivers.riru.edxp.whale.dexmaker;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Member;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
public class MethodInfo {
|
||||
|
||||
public String className;
|
||||
public String classDesc;
|
||||
public String methodName;
|
||||
public String methodSig;
|
||||
public Method method;
|
||||
public Constructor constructor;
|
||||
public boolean isConstructor;
|
||||
public ClassLoader classLoader;
|
||||
|
||||
public MethodInfo(Member member) {
|
||||
if (member instanceof Method) {
|
||||
method = (Method) member;
|
||||
isConstructor = false;
|
||||
classLoader = member.getDeclaringClass().getClassLoader();
|
||||
generateMethodInfo();
|
||||
} else if (member instanceof Constructor) {
|
||||
constructor = (Constructor) member;
|
||||
isConstructor = true;
|
||||
classLoader = member.getDeclaringClass().getClassLoader();
|
||||
generateConstructorInfo();
|
||||
} else {
|
||||
throw new IllegalArgumentException("member should be Method or Constructor");
|
||||
}
|
||||
}
|
||||
|
||||
private void generateConstructorInfo() {
|
||||
methodName = "<init>";
|
||||
className = constructor.getDeclaringClass().getName();
|
||||
generateCommonInfo(constructor.getParameterTypes(), void.class);
|
||||
}
|
||||
|
||||
private void generateMethodInfo() {
|
||||
methodName = method.getName();
|
||||
className = method.getDeclaringClass().getName();
|
||||
generateCommonInfo(method.getParameterTypes(), method.getReturnType());
|
||||
}
|
||||
|
||||
private void generateCommonInfo(Class[] parameterTypes, Class returnType) {
|
||||
classDesc = "L" + className.replace(".", "/") + ";";
|
||||
StringBuilder builder = new StringBuilder();
|
||||
builder.append("(");
|
||||
for (Class parameterType : parameterTypes) {
|
||||
builder.append(getDescStr(parameterType));
|
||||
}
|
||||
builder.append(")");
|
||||
builder.append(getDescStr(returnType));
|
||||
methodSig = builder.toString();
|
||||
}
|
||||
|
||||
public Class getClassForSure() {
|
||||
try {
|
||||
// TODO does initialize make sense?
|
||||
return Class.forName(className, true, classLoader);
|
||||
} catch (Throwable throwable) {
|
||||
DexLog.e("error when getClassForSure", throwable);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static String getDescStr(Class clazz) {
|
||||
if (clazz.equals(boolean.class)) {
|
||||
return "Z";
|
||||
} else if (clazz.equals(byte.class)) {
|
||||
return "B";
|
||||
} else if (clazz.equals(char.class)) {
|
||||
return "C";
|
||||
} else if (clazz.equals(double.class)) {
|
||||
return "D";
|
||||
} else if (clazz.equals(float.class)) {
|
||||
return "F";
|
||||
} else if (clazz.equals(int.class)) {
|
||||
return "I";
|
||||
} else if (clazz.equals(long.class)) {
|
||||
return "J";
|
||||
} else if (clazz.equals(short.class)) {
|
||||
return "S";
|
||||
} else if (clazz.equals(void.class)) {
|
||||
return "V";
|
||||
} else {
|
||||
String prefix = clazz.isArray() ? "" : "L";
|
||||
String suffix = clazz.isArray() ? "" : ";";
|
||||
return prefix + clazz.getName().replace(".", "/") + suffix;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,134 +0,0 @@
|
|||
package com.elderdrivers.riru.edxp.whale.entry;
|
||||
|
||||
import android.app.AndroidAppHelper;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import com.elderdrivers.riru.edxp.config.EdXpConfigGlobal;
|
||||
import com.elderdrivers.riru.edxp.util.Utils;
|
||||
import com.elderdrivers.riru.edxp.whale.config.WhaleEdxpConfig;
|
||||
import com.elderdrivers.riru.edxp.whale.config.WhaleHookProvider;
|
||||
import com.elderdrivers.riru.edxp.whale.core.HookMain;
|
||||
import com.elderdrivers.riru.edxp.whale.entry.bootstrap.AppBootstrapHookInfo;
|
||||
import com.elderdrivers.riru.edxp.whale.entry.bootstrap.SysBootstrapHookInfo;
|
||||
import com.elderdrivers.riru.edxp.whale.entry.bootstrap.SysInnerHookInfo;
|
||||
import com.elderdrivers.riru.edxp.whale.entry.bootstrap.WorkAroundHookInfo;
|
||||
import com.elderdrivers.riru.edxp.whale._hooker.SystemMainHooker;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import de.robv.android.xposed.XposedBridge;
|
||||
import de.robv.android.xposed.XposedInit;
|
||||
|
||||
public class Router {
|
||||
|
||||
public volatile static boolean forkCompleted = false;
|
||||
|
||||
private static volatile AtomicBoolean bootstrapHooked = new AtomicBoolean(false);
|
||||
|
||||
public static void initResourcesHook() {
|
||||
startWorkAroundHook(); // for OnePlus devices
|
||||
XposedBridge.initXResources();
|
||||
}
|
||||
|
||||
public static void prepare(boolean isSystem) {
|
||||
// this flag is needed when loadModules
|
||||
XposedInit.startsSystemServer = isSystem;
|
||||
}
|
||||
|
||||
public static void checkHookState(String appDataDir) {
|
||||
// determine whether allow xposed or not
|
||||
// XposedBridge.disableHooks = ConfigManager.shouldHook(parsePackageName(appDataDir));
|
||||
}
|
||||
|
||||
private static String parsePackageName(String appDataDir) {
|
||||
if (TextUtils.isEmpty(appDataDir)) {
|
||||
return "";
|
||||
}
|
||||
int lastIndex = appDataDir.lastIndexOf("/");
|
||||
if (lastIndex < 1) {
|
||||
return "";
|
||||
}
|
||||
return appDataDir.substring(lastIndex + 1);
|
||||
}
|
||||
|
||||
public static void installBootstrapHooks(boolean isSystem) {
|
||||
// Initialize the Xposed framework
|
||||
try {
|
||||
if (!bootstrapHooked.compareAndSet(false, true)) {
|
||||
return;
|
||||
}
|
||||
Router.startBootstrapHook(isSystem);
|
||||
XposedInit.initForZygote(isSystem);
|
||||
} catch (Throwable t) {
|
||||
Utils.logE("error during Xposed initialization", t);
|
||||
XposedBridge.disableHooks = true;
|
||||
}
|
||||
}
|
||||
|
||||
public static void loadModulesSafely(boolean isInZygote) {
|
||||
try {
|
||||
// FIXME some coredomain app can't reading modules.list
|
||||
XposedInit.loadModules(isInZygote);
|
||||
} catch (Exception exception) {
|
||||
Utils.logE("error loading module list", exception);
|
||||
}
|
||||
}
|
||||
|
||||
public static void startBootstrapHook(boolean isSystem) {
|
||||
Utils.logD("startBootstrapHook starts: isSystem = " + isSystem);
|
||||
ClassLoader classLoader = XposedBridge.BOOTCLASSLOADER;
|
||||
if (isSystem) {
|
||||
HookMain.doHookDefault(
|
||||
Router.class.getClassLoader(),
|
||||
classLoader,
|
||||
SysBootstrapHookInfo.class.getName());
|
||||
} else {
|
||||
HookMain.doHookDefault(
|
||||
Router.class.getClassLoader(),
|
||||
classLoader,
|
||||
AppBootstrapHookInfo.class.getName());
|
||||
}
|
||||
}
|
||||
|
||||
public static void startSystemServerHook() {
|
||||
HookMain.doHookDefault(
|
||||
Router.class.getClassLoader(),
|
||||
SystemMainHooker.systemServerCL,
|
||||
SysInnerHookInfo.class.getName());
|
||||
}
|
||||
|
||||
public static void startWorkAroundHook() {
|
||||
HookMain.doHookDefault(
|
||||
Router.class.getClassLoader(),
|
||||
XposedBridge.BOOTCLASSLOADER,
|
||||
WorkAroundHookInfo.class.getName());
|
||||
}
|
||||
|
||||
public static void onForkStart() {
|
||||
forkCompleted = false;
|
||||
}
|
||||
|
||||
public static void onForkFinish() {
|
||||
forkCompleted = true;
|
||||
}
|
||||
|
||||
public static void onEnterChildProcess() {
|
||||
|
||||
}
|
||||
|
||||
public static void logD(String prefix) {
|
||||
Utils.logD(String.format("%s: pkg=%s, prc=%s", prefix, AndroidAppHelper.currentPackageName(),
|
||||
AndroidAppHelper.currentProcessName()));
|
||||
}
|
||||
|
||||
public static void logE(String prefix, Throwable throwable) {
|
||||
Utils.logE(String.format("%s: pkg=%s, prc=%s", prefix, AndroidAppHelper.currentPackageName(),
|
||||
AndroidAppHelper.currentProcessName()), throwable);
|
||||
}
|
||||
|
||||
public static void injectConfig() {
|
||||
EdXpConfigGlobal.sConfig = new WhaleEdxpConfig();
|
||||
EdXpConfigGlobal.sHookProvider = new WhaleHookProvider();
|
||||
XposedBridge.log("using HookProvider: " + EdXpConfigGlobal.sHookProvider.getClass().getName());
|
||||
}
|
||||
}
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
package com.elderdrivers.riru.edxp.whale.entry.bootstrap;
|
||||
|
||||
import com.elderdrivers.riru.common.KeepMembers;
|
||||
import com.elderdrivers.riru.edxp.whale._hooker.HandleBindAppHooker;
|
||||
import com.elderdrivers.riru.edxp.whale._hooker.LoadedApkConstructorHooker;
|
||||
import com.elderdrivers.riru.edxp.whale._hooker.OnePlusWorkAroundHooker;
|
||||
import com.elderdrivers.riru.edxp.whale._hooker.SystemMainHooker;
|
||||
|
||||
public class SysBootstrapHookInfo implements KeepMembers {
|
||||
public static String[] hookItemNames = {
|
||||
HandleBindAppHooker.class.getName(),
|
||||
SystemMainHooker.class.getName(),
|
||||
LoadedApkConstructorHooker.class.getName(),
|
||||
OnePlusWorkAroundHooker.class.getName()
|
||||
};
|
||||
}
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
package com.elderdrivers.riru.edxp.whale.entry.bootstrap;
|
||||
|
||||
import com.elderdrivers.riru.common.KeepMembers;
|
||||
import com.elderdrivers.riru.edxp.whale._hooker.StartBootstrapServicesHooker;
|
||||
|
||||
public class SysInnerHookInfo implements KeepMembers {
|
||||
public static String[] hookItemNames = {
|
||||
StartBootstrapServicesHooker.class.getName()
|
||||
};
|
||||
}
|
||||
|
|
@ -1,73 +0,0 @@
|
|||
package com.elderdrivers.riru.edxp.whale.proxy;
|
||||
|
||||
import com.elderdrivers.riru.edxp.Main;
|
||||
import com.elderdrivers.riru.edxp.config.ConfigManager;
|
||||
import com.elderdrivers.riru.edxp.deopt.PrebuiltMethodsDeopter;
|
||||
import com.elderdrivers.riru.edxp.framework.Zygote;
|
||||
import com.elderdrivers.riru.edxp.whale.entry.Router;
|
||||
|
||||
import static com.elderdrivers.riru.edxp.util.FileUtils.getDataPathPrefix;
|
||||
|
||||
public class NormalProxy {
|
||||
|
||||
public static void forkAndSpecializePre(int uid, int gid, int[] gids, int debugFlags,
|
||||
int[][] rlimits, int mountExternal, String seInfo,
|
||||
String niceName, int[] fdsToClose, int[] fdsToIgnore,
|
||||
boolean startChildZygote, String instructionSet,
|
||||
String appDataDir) {
|
||||
// mainly for secondary zygote
|
||||
Router.onForkStart();
|
||||
Router.initResourcesHook();
|
||||
// call this to ensure the flag is set to false ASAP
|
||||
Router.prepare(false);
|
||||
PrebuiltMethodsDeopter.deoptBootMethods(); // do it once for secondary zygote
|
||||
// install bootstrap hooks for secondary zygote
|
||||
Router.installBootstrapHooks(false);
|
||||
// only load modules for secondary zygote
|
||||
Router.loadModulesSafely(true);
|
||||
Zygote.closeFilesBeforeFork();
|
||||
}
|
||||
|
||||
public static void forkAndSpecializePost(int pid, String appDataDir, String niceName) {
|
||||
// TODO consider processes without forkAndSpecializePost called
|
||||
Main.appDataDir = appDataDir;
|
||||
Main.niceName = niceName;
|
||||
Router.prepare(false);
|
||||
Zygote.reopenFilesAfterFork();
|
||||
Router.onEnterChildProcess();
|
||||
// load modules for each app process on its forked if dynamic modules mode is on
|
||||
Router.loadModulesSafely(false);
|
||||
Router.onForkFinish();
|
||||
}
|
||||
|
||||
public static void forkSystemServerPre(int uid, int gid, int[] gids, int debugFlags, int[][] rlimits,
|
||||
long permittedCapabilities, long effectiveCapabilities) {
|
||||
Router.onForkStart();
|
||||
Router.initResourcesHook();
|
||||
// set startsSystemServer flag used when loadModules
|
||||
Router.prepare(true);
|
||||
PrebuiltMethodsDeopter.deoptBootMethods(); // do it once for main zygote
|
||||
// install bootstrap hooks for main zygote as early as possible
|
||||
// in case we miss some processes not forked via forkAndSpecialize
|
||||
// for instance com.android.phone
|
||||
Router.installBootstrapHooks(true);
|
||||
// loadModules have to be executed in zygote even isDynamicModules is false
|
||||
// because if not global hooks installed in initZygote might not be
|
||||
// propagated to processes not forked via forkAndSpecialize
|
||||
Router.loadModulesSafely(true);
|
||||
Zygote.closeFilesBeforeFork();
|
||||
}
|
||||
|
||||
public static void forkSystemServerPost(int pid) {
|
||||
// in system_server process
|
||||
Main.appDataDir = getDataPathPrefix() + "android";
|
||||
Main.niceName = "system_server";
|
||||
Router.prepare(true);
|
||||
Zygote.reopenFilesAfterFork();
|
||||
Router.onEnterChildProcess();
|
||||
// reload module list if dynamic mode is on
|
||||
Router.loadModulesSafely(false);
|
||||
Router.onForkFinish();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1 @@
|
|||
com.elderdrivers.riru.edxp.whale.core.WhaleEdxpImpl
|
||||
|
|
@ -12,6 +12,7 @@ android {
|
|||
targetSdkVersion 28
|
||||
versionCode 1
|
||||
versionName "1.0"
|
||||
multiDexEnabled true
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
|
|
@ -60,7 +61,8 @@ afterEvaluate {
|
|||
|
||||
task("makeAndCopy${variantNameCapped}", type: Jar, dependsOn: "assemble${variantNameCapped}") {
|
||||
dependsOn tasks.getByPath(":edxp-common:copyCommonProperties")
|
||||
from "${buildDir}/intermediates/transforms/dexMerger/${variantNameLowered}/0/"
|
||||
from "${buildDir}/intermediates/transforms/dexMerger/${variantNameLowered}/0/",
|
||||
"${projectDir}/src/main/resources/"
|
||||
destinationDir file(myTemplatePath + "system/framework/")
|
||||
baseName "edxp"
|
||||
doLast {
|
||||
|
|
|
|||
|
|
@ -1,106 +0,0 @@
|
|||
package com.elderdrivers.riru.edxp;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.os.Build;
|
||||
import android.os.Process;
|
||||
|
||||
import com.elderdrivers.riru.common.KeepAll;
|
||||
import com.elderdrivers.riru.edxp.config.ConfigManager;
|
||||
import com.elderdrivers.riru.edxp.config.InstallerChooser;
|
||||
import com.elderdrivers.riru.edxp.core.Yahfa;
|
||||
import com.elderdrivers.riru.edxp.util.Utils;
|
||||
import com.elderdrivers.riru.edxp.yahfa.core.HookMethodResolver;
|
||||
import com.elderdrivers.riru.edxp.yahfa.entry.Router;
|
||||
import com.elderdrivers.riru.edxp.yahfa.proxy.BlackWhiteListProxy;
|
||||
import com.elderdrivers.riru.edxp.yahfa.proxy.NormalProxy;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
@SuppressLint("DefaultLocale")
|
||||
public class Main implements KeepAll {
|
||||
|
||||
public static String appDataDir = "";
|
||||
public static String niceName = "";
|
||||
public static String appProcessName = "";
|
||||
private static String forkAndSpecializePramsStr = "";
|
||||
private static String forkSystemServerPramsStr = "";
|
||||
|
||||
static {
|
||||
Yahfa.init(Build.VERSION.SDK_INT);
|
||||
HookMethodResolver.init();
|
||||
Router.injectConfig();
|
||||
InstallerChooser.setInstallerPackageName(ConfigManager.getInstallerPackageName());
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// entry points
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public static void forkAndSpecializePre(int uid, int gid, int[] gids, int debugFlags,
|
||||
int[][] rlimits, int mountExternal, String seInfo,
|
||||
String niceName, int[] fdsToClose, int[] fdsToIgnore,
|
||||
boolean startChildZygote, String instructionSet,
|
||||
String appDataDir) {
|
||||
if (BuildConfig.DEBUG) {
|
||||
forkAndSpecializePramsStr = String.format(
|
||||
"Zygote#forkAndSpecialize(%d, %d, %s, %d, %s, %d, %s, %s, %s, %s, %s, %s, %s)",
|
||||
uid, gid, Arrays.toString(gids), debugFlags, Arrays.toString(rlimits),
|
||||
mountExternal, seInfo, niceName, Arrays.toString(fdsToClose),
|
||||
Arrays.toString(fdsToIgnore), startChildZygote, instructionSet, appDataDir);
|
||||
}
|
||||
if (ConfigManager.isBlackWhiteListEnabled()) {
|
||||
BlackWhiteListProxy.forkAndSpecializePre(uid, gid, gids, debugFlags, rlimits,
|
||||
mountExternal, seInfo, niceName, fdsToClose, fdsToIgnore, startChildZygote,
|
||||
instructionSet, appDataDir);
|
||||
} else {
|
||||
NormalProxy.forkAndSpecializePre(uid, gid, gids, debugFlags, rlimits, mountExternal,
|
||||
seInfo, niceName, fdsToClose, fdsToIgnore, startChildZygote, instructionSet,
|
||||
appDataDir);
|
||||
}
|
||||
}
|
||||
|
||||
public static void forkAndSpecializePost(int pid, String appDataDir, String niceName) {
|
||||
if (pid == 0) {
|
||||
Utils.logD(forkAndSpecializePramsStr + " = " + Process.myPid());
|
||||
if (ConfigManager.isBlackWhiteListEnabled()) {
|
||||
BlackWhiteListProxy.forkAndSpecializePost(pid, appDataDir, niceName);
|
||||
} else {
|
||||
NormalProxy.forkAndSpecializePost(pid, appDataDir, niceName);
|
||||
}
|
||||
} else {
|
||||
// in zygote process, res is child zygote pid
|
||||
// don't print log here, see https://github.com/RikkaApps/Riru/blob/77adfd6a4a6a81bfd20569c910bc4854f2f84f5e/riru-core/jni/main/jni_native_method.cpp#L55-L66
|
||||
}
|
||||
}
|
||||
|
||||
public static void forkSystemServerPre(int uid, int gid, int[] gids, int debugFlags, int[][] rlimits,
|
||||
long permittedCapabilities, long effectiveCapabilities) {
|
||||
if (BuildConfig.DEBUG) {
|
||||
forkSystemServerPramsStr = String.format("Zygote#forkSystemServer(%d, %d, %s, %d, %s, %d, %d)",
|
||||
uid, gid, Arrays.toString(gids), debugFlags, Arrays.toString(rlimits),
|
||||
permittedCapabilities, effectiveCapabilities);
|
||||
}
|
||||
if (ConfigManager.isBlackWhiteListEnabled()) {
|
||||
BlackWhiteListProxy.forkSystemServerPre(uid, gid, gids, debugFlags, rlimits,
|
||||
permittedCapabilities, effectiveCapabilities);
|
||||
} else {
|
||||
NormalProxy.forkSystemServerPre(uid, gid, gids, debugFlags, rlimits,
|
||||
permittedCapabilities, effectiveCapabilities);
|
||||
}
|
||||
}
|
||||
|
||||
public static void forkSystemServerPost(int pid) {
|
||||
if (pid == 0) {
|
||||
Utils.logD(forkSystemServerPramsStr + " = " + Process.myPid());
|
||||
if (ConfigManager.isBlackWhiteListEnabled()) {
|
||||
BlackWhiteListProxy.forkSystemServerPost(pid);
|
||||
} else {
|
||||
NormalProxy.forkSystemServerPost(pid);
|
||||
}
|
||||
} else {
|
||||
// in zygote process, res is child zygote pid
|
||||
// don't print log here, see https://github.com/RikkaApps/Riru/blob/77adfd6a4a6a81bfd20569c910bc4854f2f84f5e/riru-core/jni/main/jni_native_method.cpp#L55-L66
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,96 +0,0 @@
|
|||
package com.elderdrivers.riru.edxp.yahfa._hooker;
|
||||
|
||||
import android.app.ActivityThread;
|
||||
import android.app.LoadedApk;
|
||||
import android.content.ComponentName;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.res.CompatibilityInfo;
|
||||
|
||||
import com.elderdrivers.riru.common.KeepMembers;
|
||||
import com.elderdrivers.riru.edxp.Main;
|
||||
import com.elderdrivers.riru.edxp.hooker.SliceProviderFix;
|
||||
import com.elderdrivers.riru.edxp.hooker.XposedBlackListHooker;
|
||||
import com.elderdrivers.riru.edxp.hooker.XposedInstallerHooker;
|
||||
import com.elderdrivers.riru.edxp.util.Utils;
|
||||
import com.elderdrivers.riru.edxp.yahfa.entry.Router;
|
||||
|
||||
import de.robv.android.xposed.XposedBridge;
|
||||
import de.robv.android.xposed.XposedHelpers;
|
||||
import de.robv.android.xposed.XposedInit;
|
||||
import de.robv.android.xposed.callbacks.XC_LoadPackage;
|
||||
|
||||
import static com.elderdrivers.riru.edxp.config.InstallerChooser.INSTALLER_PACKAGE_NAME;
|
||||
import static com.elderdrivers.riru.edxp.hooker.SliceProviderFix.SYSTEMUI_PACKAGE_NAME;
|
||||
import static com.elderdrivers.riru.edxp.hooker.XposedBlackListHooker.BLACK_LIST_PACKAGE_NAME;
|
||||
import static com.elderdrivers.riru.edxp.util.ClassLoaderUtils.replaceParentClassLoader;
|
||||
|
||||
// normal process initialization (for new Activity, Service, BroadcastReceiver etc.)
|
||||
public class HandleBindAppHooker implements KeepMembers {
|
||||
|
||||
public static String className = "android.app.ActivityThread";
|
||||
public static String methodName = "handleBindApplication";
|
||||
public static String methodSig = "(Landroid/app/ActivityThread$AppBindData;)V";
|
||||
|
||||
public static void hook(Object thiz, Object bindData) {
|
||||
if (XposedBlackListHooker.shouldDisableHooks("")) {
|
||||
backup(thiz, bindData);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
Router.logD("ActivityThread#handleBindApplication() starts");
|
||||
ActivityThread activityThread = (ActivityThread) thiz;
|
||||
ApplicationInfo appInfo = (ApplicationInfo) XposedHelpers.getObjectField(bindData, "appInfo");
|
||||
// save app process name here for later use
|
||||
Main.appProcessName = (String) XposedHelpers.getObjectField(bindData, "processName");
|
||||
String reportedPackageName = appInfo.packageName.equals("android") ? "system" : appInfo.packageName;
|
||||
Utils.logD("processName=" + Main.appProcessName +
|
||||
", packageName=" + reportedPackageName + ", appDataDir=" + Main.appDataDir);
|
||||
|
||||
if (XposedBlackListHooker.shouldDisableHooks(reportedPackageName)) {
|
||||
return;
|
||||
}
|
||||
|
||||
ComponentName instrumentationName = (ComponentName) XposedHelpers.getObjectField(bindData, "instrumentationName");
|
||||
if (instrumentationName != null) {
|
||||
Router.logD("Instrumentation detected, disabling framework for");
|
||||
XposedBridge.disableHooks = true;
|
||||
return;
|
||||
}
|
||||
CompatibilityInfo compatInfo = (CompatibilityInfo) XposedHelpers.getObjectField(bindData, "compatInfo");
|
||||
if (appInfo.sourceDir == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
XposedHelpers.setObjectField(activityThread, "mBoundApplication", bindData);
|
||||
XposedInit.loadedPackagesInProcess.add(reportedPackageName);
|
||||
LoadedApk loadedApk = activityThread.getPackageInfoNoCheck(appInfo, compatInfo);
|
||||
|
||||
replaceParentClassLoader(loadedApk.getClassLoader());
|
||||
|
||||
XC_LoadPackage.LoadPackageParam lpparam = new XC_LoadPackage.LoadPackageParam(XposedBridge.sLoadedPackageCallbacks);
|
||||
lpparam.packageName = reportedPackageName;
|
||||
lpparam.processName = (String) XposedHelpers.getObjectField(bindData, "processName");
|
||||
lpparam.classLoader = loadedApk.getClassLoader();
|
||||
lpparam.appInfo = appInfo;
|
||||
lpparam.isFirstApplication = true;
|
||||
XC_LoadPackage.callAll(lpparam);
|
||||
|
||||
if (reportedPackageName.equals(INSTALLER_PACKAGE_NAME)) {
|
||||
XposedInstallerHooker.hookXposedInstaller(lpparam.classLoader);
|
||||
}
|
||||
if (reportedPackageName.equals(BLACK_LIST_PACKAGE_NAME)) {
|
||||
XposedBlackListHooker.hook(lpparam.classLoader);
|
||||
}
|
||||
if (reportedPackageName.equals(SYSTEMUI_PACKAGE_NAME)) {
|
||||
SliceProviderFix.hook();
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
Router.logE("error when hooking bindApp", t);
|
||||
} finally {
|
||||
backup(thiz, bindData);
|
||||
}
|
||||
}
|
||||
|
||||
public static void backup(Object thiz, Object bindData) {
|
||||
}
|
||||
}
|
||||
|
|
@ -1,99 +0,0 @@
|
|||
package com.elderdrivers.riru.edxp.yahfa._hooker;
|
||||
|
||||
import android.app.ActivityThread;
|
||||
import android.app.AndroidAppHelper;
|
||||
import android.app.LoadedApk;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.res.CompatibilityInfo;
|
||||
import android.util.Log;
|
||||
|
||||
import com.elderdrivers.riru.common.KeepMembers;
|
||||
import com.elderdrivers.riru.edxp.hooker.XposedBlackListHooker;
|
||||
import com.elderdrivers.riru.edxp.yahfa.entry.Router;
|
||||
|
||||
import de.robv.android.xposed.XposedBridge;
|
||||
import de.robv.android.xposed.XposedHelpers;
|
||||
import de.robv.android.xposed.XposedInit;
|
||||
import de.robv.android.xposed.callbacks.XC_LoadPackage;
|
||||
|
||||
import static com.elderdrivers.riru.edxp.util.ClassLoaderUtils.replaceParentClassLoader;
|
||||
|
||||
// when a package is loaded for an existing process, trigger the callbacks as well
|
||||
// ed: remove resources related hooking
|
||||
public class LoadedApkConstructorHooker implements KeepMembers {
|
||||
public static String className = "android.app.LoadedApk";
|
||||
public static String methodName = "<init>";
|
||||
public static String methodSig = "(Landroid/app/ActivityThread;" +
|
||||
"Landroid/content/pm/ApplicationInfo;" +
|
||||
"Landroid/content/res/CompatibilityInfo;" +
|
||||
"Ljava/lang/ClassLoader;ZZZ)V";
|
||||
|
||||
public static void hook(Object thiz, ActivityThread activityThread,
|
||||
ApplicationInfo aInfo, CompatibilityInfo compatInfo,
|
||||
ClassLoader baseLoader, boolean securityViolation,
|
||||
boolean includeCode, boolean registerPackage) {
|
||||
|
||||
if (XposedBlackListHooker.shouldDisableHooks("")) {
|
||||
backup(thiz, activityThread, aInfo, compatInfo, baseLoader, securityViolation,
|
||||
includeCode, registerPackage);
|
||||
return;
|
||||
}
|
||||
|
||||
Router.logD("LoadedApk#<init> starts");
|
||||
backup(thiz, activityThread, aInfo, compatInfo, baseLoader, securityViolation,
|
||||
includeCode, registerPackage);
|
||||
|
||||
try {
|
||||
LoadedApk loadedApk = (LoadedApk) thiz;
|
||||
String packageName = loadedApk.getPackageName();
|
||||
Object mAppDir = XposedHelpers.getObjectField(thiz, "mAppDir");
|
||||
Router.logD("LoadedApk#<init> ends: " + mAppDir);
|
||||
|
||||
if (XposedBlackListHooker.shouldDisableHooks(packageName)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (packageName.equals("android")) {
|
||||
Router.logD("LoadedApk#<init> is android, skip: " + mAppDir);
|
||||
return;
|
||||
}
|
||||
|
||||
// mIncludeCode checking should go ahead of loadedPackagesInProcess added checking
|
||||
if (!XposedHelpers.getBooleanField(loadedApk, "mIncludeCode")) {
|
||||
Router.logD("LoadedApk#<init> mIncludeCode == false: " + mAppDir);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!XposedInit.loadedPackagesInProcess.add(packageName)) {
|
||||
Router.logD("LoadedApk#<init> has been loaded before, skip: " + mAppDir);
|
||||
return;
|
||||
}
|
||||
|
||||
// OnePlus magic...
|
||||
if (Log.getStackTraceString(new Throwable()).
|
||||
contains("android.app.ActivityThread$ApplicationThread.schedulePreload")) {
|
||||
Router.logD("LoadedApk#<init> maybe oneplus's custom opt, skip");
|
||||
return;
|
||||
}
|
||||
|
||||
replaceParentClassLoader(loadedApk.getClassLoader());
|
||||
|
||||
XC_LoadPackage.LoadPackageParam lpparam = new XC_LoadPackage.LoadPackageParam(XposedBridge.sLoadedPackageCallbacks);
|
||||
lpparam.packageName = packageName;
|
||||
lpparam.processName = AndroidAppHelper.currentProcessName();
|
||||
lpparam.classLoader = loadedApk.getClassLoader();
|
||||
lpparam.appInfo = loadedApk.getApplicationInfo();
|
||||
lpparam.isFirstApplication = false;
|
||||
XC_LoadPackage.callAll(lpparam);
|
||||
} catch (Throwable t) {
|
||||
Router.logE("error when hooking LoadedApk.<init>", t);
|
||||
}
|
||||
}
|
||||
|
||||
public static void backup(Object thiz, ActivityThread activityThread,
|
||||
ApplicationInfo aInfo, CompatibilityInfo compatInfo,
|
||||
ClassLoader baseLoader, boolean securityViolation,
|
||||
boolean includeCode, boolean registerPackage) {
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -1,43 +0,0 @@
|
|||
package com.elderdrivers.riru.edxp.yahfa._hooker;
|
||||
|
||||
import android.app.ActivityThread;
|
||||
|
||||
import com.elderdrivers.riru.common.KeepMembers;
|
||||
import com.elderdrivers.riru.edxp.deopt.PrebuiltMethodsDeopter;
|
||||
import com.elderdrivers.riru.edxp.yahfa.entry.Router;
|
||||
|
||||
import de.robv.android.xposed.XposedBridge;
|
||||
|
||||
|
||||
// system_server initialization
|
||||
// ed: only support sdk >= 21 for now
|
||||
public class SystemMainHooker implements KeepMembers {
|
||||
|
||||
public static String className = "android.app.ActivityThread";
|
||||
public static String methodName = "systemMain";
|
||||
public static String methodSig = "()Landroid/app/ActivityThread;";
|
||||
|
||||
public static ClassLoader systemServerCL;
|
||||
|
||||
public static ActivityThread hook() {
|
||||
if (XposedBridge.disableHooks) {
|
||||
return backup();
|
||||
}
|
||||
Router.logD("ActivityThread#systemMain() starts");
|
||||
ActivityThread activityThread = backup();
|
||||
try {
|
||||
// get system_server classLoader
|
||||
systemServerCL = Thread.currentThread().getContextClassLoader();
|
||||
// deopt methods in SYSTEMSERVERCLASSPATH
|
||||
PrebuiltMethodsDeopter.deoptSystemServerMethods(systemServerCL);
|
||||
Router.startSystemServerHook();
|
||||
} catch (Throwable t) {
|
||||
Router.logE("error when hooking systemMain", t);
|
||||
}
|
||||
return activityThread;
|
||||
}
|
||||
|
||||
public static ActivityThread backup() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,5 @@
|
|||
package com.elderdrivers.riru.edxp.yahfa.config;
|
||||
|
||||
import com.elderdrivers.riru.edxp.Main;
|
||||
import com.elderdrivers.riru.edxp.config.ConfigManager;
|
||||
import com.elderdrivers.riru.edxp.config.EdXpConfig;
|
||||
import com.elderdrivers.riru.edxp.config.InstallerChooser;
|
||||
|
|
|
|||
|
|
@ -1,156 +0,0 @@
|
|||
package com.elderdrivers.riru.edxp.yahfa.core;
|
||||
|
||||
import android.os.Build;
|
||||
|
||||
import com.elderdrivers.riru.edxp.Main;
|
||||
import com.elderdrivers.riru.edxp.core.Yahfa;
|
||||
import com.elderdrivers.riru.edxp.util.Utils;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
/**
|
||||
* create by Swift Gan on 14/01/2019
|
||||
* To ensure method in resolved cache
|
||||
*/
|
||||
|
||||
public class HookMethodResolver {
|
||||
|
||||
public static Class artMethodClass;
|
||||
|
||||
public static Field resolvedMethodsField;
|
||||
public static Field dexCacheField;
|
||||
public static Field dexMethodIndexField;
|
||||
public static Field artMethodField;
|
||||
|
||||
public static boolean canResolvedInJava = false;
|
||||
public static boolean isArtMethod = false;
|
||||
|
||||
public static long resolvedMethodsAddress = 0;
|
||||
public static int dexMethodIndex = 0;
|
||||
|
||||
public static Method testMethod;
|
||||
public static Object testArtMethod;
|
||||
|
||||
public static void init() {
|
||||
checkSupport();
|
||||
}
|
||||
|
||||
private static void checkSupport() {
|
||||
try {
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||
isArtMethod = false;
|
||||
canResolvedInJava = false;
|
||||
return;
|
||||
}
|
||||
|
||||
testMethod = HookMethodResolver.class.getDeclaredMethod("init");
|
||||
artMethodField = getField(Method.class, "artMethod");
|
||||
|
||||
testArtMethod = artMethodField.get(testMethod);
|
||||
|
||||
if (hasJavaArtMethod() && testArtMethod.getClass() == artMethodClass) {
|
||||
checkSupportForArtMethod();
|
||||
isArtMethod = true;
|
||||
} else if (testArtMethod instanceof Long) {
|
||||
checkSupportForArtMethodId();
|
||||
isArtMethod = false;
|
||||
} else {
|
||||
canResolvedInJava = false;
|
||||
}
|
||||
|
||||
} catch (Throwable throwable) {
|
||||
Utils.logE("error when checkSupport", throwable);
|
||||
}
|
||||
}
|
||||
|
||||
// may 5.0
|
||||
private static void checkSupportForArtMethod() throws Exception {
|
||||
dexMethodIndexField = getField(artMethodClass, "dexMethodIndex");
|
||||
dexCacheField = getField(Class.class, "dexCache");
|
||||
Object dexCache = dexCacheField.get(testMethod.getDeclaringClass());
|
||||
resolvedMethodsField = getField(dexCache.getClass(), "resolvedMethods");
|
||||
if (resolvedMethodsField.get(dexCache) instanceof Object[]) {
|
||||
canResolvedInJava = true;
|
||||
}
|
||||
}
|
||||
|
||||
// may 6.0
|
||||
private static void checkSupportForArtMethodId() throws Exception {
|
||||
dexMethodIndexField = getField(Method.class, "dexMethodIndex");
|
||||
dexMethodIndex = (int) dexMethodIndexField.get(testMethod);
|
||||
dexCacheField = getField(Class.class, "dexCache");
|
||||
Object dexCache = dexCacheField.get(testMethod.getDeclaringClass());
|
||||
resolvedMethodsField = getField(dexCache.getClass(), "resolvedMethods");
|
||||
Object resolvedMethods = resolvedMethodsField.get(dexCache);
|
||||
if (resolvedMethods instanceof Long) {
|
||||
canResolvedInJava = false;
|
||||
resolvedMethodsAddress = (long) resolvedMethods;
|
||||
} else if (resolvedMethods instanceof long[]) {
|
||||
canResolvedInJava = true;
|
||||
}
|
||||
}
|
||||
|
||||
public static void resolveMethod(Method hook, Method backup) {
|
||||
if (canResolvedInJava && artMethodField != null) {
|
||||
// in java
|
||||
try {
|
||||
resolveInJava(hook, backup);
|
||||
} catch (Exception e) {
|
||||
// in native
|
||||
resolveInNative(hook, backup);
|
||||
}
|
||||
} else {
|
||||
// in native
|
||||
resolveInNative(hook, backup);
|
||||
}
|
||||
}
|
||||
|
||||
private static void resolveInJava(Method hook, Method backup) throws Exception {
|
||||
Object dexCache = dexCacheField.get(hook.getDeclaringClass());
|
||||
if (isArtMethod) {
|
||||
Object artMethod = artMethodField.get(backup);
|
||||
int dexMethodIndex = (int) dexMethodIndexField.get(artMethod);
|
||||
Object resolvedMethods = resolvedMethodsField.get(dexCache);
|
||||
((Object[])resolvedMethods)[dexMethodIndex] = artMethod;
|
||||
} else {
|
||||
int dexMethodIndex = (int) dexMethodIndexField.get(backup);
|
||||
Object resolvedMethods = resolvedMethodsField.get(dexCache);
|
||||
long artMethod = (long) artMethodField.get(backup);
|
||||
((long[])resolvedMethods)[dexMethodIndex] = artMethod;
|
||||
}
|
||||
}
|
||||
|
||||
private static void resolveInNative(Method hook, Method backup) {
|
||||
Yahfa.ensureMethodCached(hook, backup);
|
||||
}
|
||||
|
||||
public static Field getField(Class topClass, String fieldName) throws NoSuchFieldException {
|
||||
while (topClass != null && topClass != Object.class) {
|
||||
try {
|
||||
Field field = topClass.getDeclaredField(fieldName);
|
||||
field.setAccessible(true);
|
||||
return field;
|
||||
} catch (Exception e) {
|
||||
}
|
||||
topClass = topClass.getSuperclass();
|
||||
}
|
||||
throw new NoSuchFieldException(fieldName);
|
||||
}
|
||||
|
||||
public static boolean hasJavaArtMethod() {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
return false;
|
||||
}
|
||||
if (artMethodClass != null)
|
||||
return true;
|
||||
try {
|
||||
artMethodClass = Class.forName("java.lang.reflect.ArtMethod");
|
||||
return true;
|
||||
} catch (ClassNotFoundException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
package com.elderdrivers.riru.edxp.yahfa.core;
|
||||
|
||||
import android.os.Build;
|
||||
|
||||
import com.elderdrivers.riru.edxp.config.ConfigManager;
|
||||
import com.elderdrivers.riru.edxp.config.InstallerChooser;
|
||||
import com.elderdrivers.riru.edxp.core.BaseEdxpImpl;
|
||||
import com.elderdrivers.riru.edxp.core.EdxpImpl;
|
||||
import com.elderdrivers.riru.edxp.core.Main;
|
||||
import com.elderdrivers.riru.edxp.core.Proxy;
|
||||
import com.elderdrivers.riru.edxp.core.Yahfa;
|
||||
import com.elderdrivers.riru.edxp.core.yahfa.HookMethodResolver;
|
||||
import com.elderdrivers.riru.edxp.proxy.BlackWhiteListProxy;
|
||||
import com.elderdrivers.riru.edxp.proxy.NormalProxy;
|
||||
import com.elderdrivers.riru.edxp.proxy.Router;
|
||||
|
||||
public class YahfaEdxpImpl extends BaseEdxpImpl {
|
||||
|
||||
static {
|
||||
final EdxpImpl edxpImpl = new YahfaEdxpImpl();
|
||||
if (Main.setEdxpImpl(edxpImpl)) {
|
||||
edxpImpl.init();
|
||||
}
|
||||
}
|
||||
|
||||
@Variant
|
||||
@Override
|
||||
public int getVariant() {
|
||||
return YAHFA;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init() {
|
||||
Yahfa.init(Build.VERSION.SDK_INT);
|
||||
HookMethodResolver.init();
|
||||
getRouter().injectConfig();
|
||||
InstallerChooser.setInstallerPackageName(ConfigManager.getInstallerPackageName());
|
||||
|
||||
setInitialized();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Proxy createBlackWhiteListProxy() {
|
||||
return new BlackWhiteListProxy(getRouter());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Proxy createNormalProxy() {
|
||||
return new NormalProxy(getRouter());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Router createRouter() {
|
||||
return new YahfaRouter();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
package com.elderdrivers.riru.edxp.yahfa.core;
|
||||
|
||||
import com.elderdrivers.riru.edxp.config.EdXpConfigGlobal;
|
||||
import com.elderdrivers.riru.edxp.proxy.BaseRouter;
|
||||
import com.elderdrivers.riru.edxp.yahfa.config.YahfaEdxpConfig;
|
||||
import com.elderdrivers.riru.edxp.yahfa.config.YahfaHookProvider;
|
||||
import com.elderdrivers.riru.edxp.yahfa.dexmaker.DynamicBridge;
|
||||
|
||||
import de.robv.android.xposed.XposedBridge;
|
||||
|
||||
public class YahfaRouter extends BaseRouter {
|
||||
|
||||
public void onEnterChildProcess() {
|
||||
DynamicBridge.onForkPost();
|
||||
}
|
||||
|
||||
public void injectConfig() {
|
||||
EdXpConfigGlobal.sConfig = new YahfaEdxpConfig();
|
||||
EdXpConfigGlobal.sHookProvider = new YahfaHookProvider();
|
||||
XposedBridge.log("using HookProvider: " + EdXpConfigGlobal.sHookProvider.getClass().getName());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -4,9 +4,8 @@ import android.app.AndroidAppHelper;
|
|||
import android.os.Build;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import com.elderdrivers.riru.edxp.Main;
|
||||
import com.elderdrivers.riru.edxp.config.ConfigManager;
|
||||
import com.elderdrivers.riru.edxp.yahfa.core.HookMain;
|
||||
import com.elderdrivers.riru.edxp.core.yahfa.HookMain;
|
||||
|
||||
import java.lang.reflect.Member;
|
||||
import java.security.MessageDigest;
|
||||
|
|
@ -27,8 +26,8 @@ public class DexMakerUtils {
|
|||
}
|
||||
String packageName = AndroidAppHelper.currentPackageName();
|
||||
if (TextUtils.isEmpty(packageName)) { //default to true
|
||||
DexLog.w("packageName is empty, processName=" + Main.appProcessName
|
||||
+ ", appDataDir=" + Main.appDataDir);
|
||||
DexLog.w("packageName is empty, processName=" + ConfigManager.appProcessName
|
||||
+ ", appDataDir=" + ConfigManager.appDataDir);
|
||||
return true;
|
||||
}
|
||||
return !ConfigManager.shouldUseCompatMode(packageName);
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package com.elderdrivers.riru.edxp.yahfa.dexmaker;
|
||||
|
||||
import com.elderdrivers.riru.edxp.Main;
|
||||
|
||||
import com.elderdrivers.riru.edxp.config.ConfigManager;
|
||||
|
||||
import java.io.File;
|
||||
import java.lang.reflect.Constructor;
|
||||
|
|
@ -13,10 +14,10 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
|||
|
||||
import de.robv.android.xposed.XposedBridge;
|
||||
|
||||
import static com.elderdrivers.riru.edxp.yahfa.dexmaker.DexMakerUtils.shouldUseInMemoryHook;
|
||||
import static com.elderdrivers.riru.edxp.util.FileUtils.getDataPathPrefix;
|
||||
import static com.elderdrivers.riru.edxp.util.FileUtils.getPackageName;
|
||||
import static com.elderdrivers.riru.edxp.util.ProcessUtils.getCurrentProcessName;
|
||||
import static com.elderdrivers.riru.edxp.yahfa.dexmaker.DexMakerUtils.shouldUseInMemoryHook;
|
||||
|
||||
public final class DynamicBridge {
|
||||
|
||||
|
|
@ -74,12 +75,12 @@ public final class DynamicBridge {
|
|||
try {
|
||||
// we always choose to use device encrypted storage data on android N and later
|
||||
// in case some app is installing hooks before phone is unlocked
|
||||
String fixedAppDataDir = getDataPathPrefix() + getPackageName(Main.appDataDir) + "/";
|
||||
String fixedAppDataDir = getDataPathPrefix() + getPackageName(ConfigManager.appDataDir) + "/";
|
||||
dexDir = new File(fixedAppDataDir, "/cache/edhookers/"
|
||||
+ getCurrentProcessName(Main.appProcessName).replace(":", "_") + "/");
|
||||
+ getCurrentProcessName(ConfigManager.appProcessName).replace(":", "_") + "/");
|
||||
dexOptDir = new File(dexDir, "oat");
|
||||
dexDir.mkdirs();
|
||||
DexLog.d(Main.appProcessName + " deleting dir: " + dexOptDir.getAbsolutePath());
|
||||
DexLog.d(ConfigManager.appProcessName + " deleting dir: " + dexOptDir.getAbsolutePath());
|
||||
} catch (Throwable throwable) {
|
||||
DexLog.e("error when init dex path", throwable);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,9 +4,8 @@ import android.annotation.TargetApi;
|
|||
import android.os.Build;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import com.elderdrivers.riru.edxp.Main;
|
||||
import com.elderdrivers.riru.edxp.core.Yahfa;
|
||||
import com.elderdrivers.riru.edxp.yahfa.core.HookMain;
|
||||
import com.elderdrivers.riru.edxp.core.yahfa.HookMain;
|
||||
|
||||
import java.io.File;
|
||||
import java.lang.reflect.Constructor;
|
||||
|
|
|
|||
|
|
@ -1,135 +0,0 @@
|
|||
package com.elderdrivers.riru.edxp.yahfa.entry;
|
||||
|
||||
import android.app.AndroidAppHelper;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import com.elderdrivers.riru.edxp.config.EdXpConfigGlobal;
|
||||
import com.elderdrivers.riru.edxp.util.Utils;
|
||||
import com.elderdrivers.riru.edxp.yahfa.config.YahfaEdxpConfig;
|
||||
import com.elderdrivers.riru.edxp.yahfa.config.YahfaHookProvider;
|
||||
import com.elderdrivers.riru.edxp.yahfa.core.HookMain;
|
||||
import com.elderdrivers.riru.edxp.yahfa.dexmaker.DynamicBridge;
|
||||
import com.elderdrivers.riru.edxp.yahfa.entry.bootstrap.AppBootstrapHookInfo;
|
||||
import com.elderdrivers.riru.edxp.yahfa.entry.bootstrap.SysBootstrapHookInfo;
|
||||
import com.elderdrivers.riru.edxp.yahfa.entry.bootstrap.SysInnerHookInfo;
|
||||
import com.elderdrivers.riru.edxp.yahfa.entry.bootstrap.WorkAroundHookInfo;
|
||||
import com.elderdrivers.riru.edxp.yahfa._hooker.SystemMainHooker;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import de.robv.android.xposed.XposedBridge;
|
||||
import de.robv.android.xposed.XposedInit;
|
||||
|
||||
public class Router {
|
||||
|
||||
public volatile static boolean forkCompleted = false;
|
||||
|
||||
private static volatile AtomicBoolean bootstrapHooked = new AtomicBoolean(false);
|
||||
|
||||
public static void initResourcesHook() {
|
||||
startWorkAroundHook(); // for OnePlus devices
|
||||
XposedBridge.initXResources();
|
||||
}
|
||||
|
||||
public static void prepare(boolean isSystem) {
|
||||
// this flag is needed when loadModules
|
||||
XposedInit.startsSystemServer = isSystem;
|
||||
}
|
||||
|
||||
public static void checkHookState(String appDataDir) {
|
||||
// determine whether allow xposed or not
|
||||
// XposedBridge.disableHooks = ConfigManager.shouldHook(parsePackageName(appDataDir));
|
||||
}
|
||||
|
||||
private static String parsePackageName(String appDataDir) {
|
||||
if (TextUtils.isEmpty(appDataDir)) {
|
||||
return "";
|
||||
}
|
||||
int lastIndex = appDataDir.lastIndexOf("/");
|
||||
if (lastIndex < 1) {
|
||||
return "";
|
||||
}
|
||||
return appDataDir.substring(lastIndex + 1);
|
||||
}
|
||||
|
||||
public static void installBootstrapHooks(boolean isSystem) {
|
||||
// Initialize the Xposed framework
|
||||
try {
|
||||
if (!bootstrapHooked.compareAndSet(false, true)) {
|
||||
return;
|
||||
}
|
||||
Router.startBootstrapHook(isSystem);
|
||||
XposedInit.initForZygote(isSystem);
|
||||
} catch (Throwable t) {
|
||||
Utils.logE("error during Xposed initialization", t);
|
||||
XposedBridge.disableHooks = true;
|
||||
}
|
||||
}
|
||||
|
||||
public static void loadModulesSafely(boolean isInZygote) {
|
||||
try {
|
||||
// FIXME some coredomain app can't reading modules.list
|
||||
XposedInit.loadModules(isInZygote);
|
||||
} catch (Exception exception) {
|
||||
Utils.logE("error loading module list", exception);
|
||||
}
|
||||
}
|
||||
|
||||
public static void startBootstrapHook(boolean isSystem) {
|
||||
Utils.logD("startBootstrapHook starts: isSystem = " + isSystem);
|
||||
ClassLoader classLoader = XposedBridge.BOOTCLASSLOADER;
|
||||
if (isSystem) {
|
||||
HookMain.doHookDefault(
|
||||
Router.class.getClassLoader(),
|
||||
classLoader,
|
||||
SysBootstrapHookInfo.class.getName());
|
||||
} else {
|
||||
HookMain.doHookDefault(
|
||||
Router.class.getClassLoader(),
|
||||
classLoader,
|
||||
AppBootstrapHookInfo.class.getName());
|
||||
}
|
||||
}
|
||||
|
||||
public static void startSystemServerHook() {
|
||||
HookMain.doHookDefault(
|
||||
Router.class.getClassLoader(),
|
||||
SystemMainHooker.systemServerCL,
|
||||
SysInnerHookInfo.class.getName());
|
||||
}
|
||||
|
||||
public static void startWorkAroundHook() {
|
||||
HookMain.doHookDefault(
|
||||
Router.class.getClassLoader(),
|
||||
XposedBridge.BOOTCLASSLOADER,
|
||||
WorkAroundHookInfo.class.getName());
|
||||
}
|
||||
|
||||
public static void onForkStart() {
|
||||
forkCompleted = false;
|
||||
}
|
||||
|
||||
public static void onForkFinish() {
|
||||
forkCompleted = true;
|
||||
}
|
||||
|
||||
public static void onEnterChildProcess() {
|
||||
DynamicBridge.onForkPost();
|
||||
}
|
||||
|
||||
public static void logD(String prefix) {
|
||||
Utils.logD(String.format("%s: pkg=%s, prc=%s", prefix, AndroidAppHelper.currentPackageName(),
|
||||
AndroidAppHelper.currentProcessName()));
|
||||
}
|
||||
|
||||
public static void logE(String prefix, Throwable throwable) {
|
||||
Utils.logE(String.format("%s: pkg=%s, prc=%s", prefix, AndroidAppHelper.currentPackageName(),
|
||||
AndroidAppHelper.currentProcessName()), throwable);
|
||||
}
|
||||
|
||||
public static void injectConfig() {
|
||||
EdXpConfigGlobal.sConfig = new YahfaEdxpConfig();
|
||||
EdXpConfigGlobal.sHookProvider = new YahfaHookProvider();
|
||||
XposedBridge.log("using HookProvider: " + EdXpConfigGlobal.sHookProvider.getClass().getName());
|
||||
}
|
||||
}
|
||||
|
|
@ -1,14 +0,0 @@
|
|||
package com.elderdrivers.riru.edxp.yahfa.entry.bootstrap;
|
||||
|
||||
import com.elderdrivers.riru.common.KeepMembers;
|
||||
import com.elderdrivers.riru.edxp.yahfa._hooker.HandleBindAppHooker;
|
||||
import com.elderdrivers.riru.edxp.yahfa._hooker.LoadedApkConstructorHooker;
|
||||
import com.elderdrivers.riru.edxp.yahfa._hooker.OnePlusWorkAroundHooker;
|
||||
|
||||
public class AppBootstrapHookInfo implements KeepMembers {
|
||||
public static String[] hookItemNames = {
|
||||
HandleBindAppHooker.class.getName(),
|
||||
LoadedApkConstructorHooker.class.getName(),
|
||||
OnePlusWorkAroundHooker.class.getName()
|
||||
};
|
||||
}
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
package com.elderdrivers.riru.edxp.yahfa.entry.bootstrap;
|
||||
|
||||
import com.elderdrivers.riru.common.KeepMembers;
|
||||
import com.elderdrivers.riru.edxp.yahfa._hooker.OnePlusWorkAroundHooker;
|
||||
|
||||
public class WorkAroundHookInfo implements KeepMembers {
|
||||
public static String[] hookItemNames = {
|
||||
OnePlusWorkAroundHooker.class.getName()
|
||||
};
|
||||
}
|
||||
|
|
@ -1,137 +0,0 @@
|
|||
package com.elderdrivers.riru.edxp.yahfa.proxy;
|
||||
|
||||
import android.text.TextUtils;
|
||||
|
||||
import com.elderdrivers.riru.edxp.Main;
|
||||
import com.elderdrivers.riru.edxp.config.ConfigManager;
|
||||
import com.elderdrivers.riru.edxp.deopt.PrebuiltMethodsDeopter;
|
||||
import com.elderdrivers.riru.edxp.framework.Zygote;
|
||||
import com.elderdrivers.riru.edxp.util.ProcessUtils;
|
||||
import com.elderdrivers.riru.edxp.util.Utils;
|
||||
import com.elderdrivers.riru.edxp.yahfa.entry.Router;
|
||||
|
||||
import de.robv.android.xposed.XposedBridge;
|
||||
|
||||
import static com.elderdrivers.riru.edxp.util.FileUtils.getDataPathPrefix;
|
||||
|
||||
/**
|
||||
* 1. Non dynamic mode
|
||||
* - system_server is whitelisted
|
||||
* * for all child processes of main zygote
|
||||
* What've been done in main zygote pre-forking system_server
|
||||
* 1) non dynamic flag set (no need to reset)
|
||||
* 2) boot image methods deopted (no need to redo)
|
||||
* 3) startSystemServer flag set to true (need to reset)
|
||||
* 4) workaround hooks installed (need to redo)
|
||||
* 5) module list loaded and initZygote called (no need to redo)
|
||||
* 6) close all fds (no need to redo because of 5))
|
||||
* * for all child processes of secondary zygote
|
||||
* 1) do the same things pre-forking first child process
|
||||
* - system_server is blacklisted:
|
||||
* * for all child processes of both main zygote and secondary zygote
|
||||
* 1) do the same things pre-forking first child process
|
||||
* 2. Dynamic mode:
|
||||
* to be continued
|
||||
*/
|
||||
public class BlackWhiteListProxy {
|
||||
|
||||
public static void forkAndSpecializePre(int uid, int gid, int[] gids, int debugFlags,
|
||||
int[][] rlimits, int mountExternal, String seInfo,
|
||||
String niceName, int[] fdsToClose, int[] fdsToIgnore,
|
||||
boolean startChildZygote, String instructionSet,
|
||||
String appDataDir) {
|
||||
final boolean isDynamicModulesMode = ConfigManager.isDynamicModulesEnabled();
|
||||
if (isDynamicModulesMode) {
|
||||
// should never happen
|
||||
return;
|
||||
}
|
||||
// only enter here when isDynamicModulesMode is off
|
||||
onForkPreForNonDynamicMode(false);
|
||||
}
|
||||
|
||||
public static void forkAndSpecializePost(int pid, String appDataDir, String niceName) {
|
||||
onForkPostCommon(false, appDataDir, niceName);
|
||||
}
|
||||
|
||||
public static void forkSystemServerPre(int uid, int gid, int[] gids, int debugFlags,
|
||||
int[][] rlimits, long permittedCapabilities,
|
||||
long effectiveCapabilities) {
|
||||
final boolean isDynamicModulesMode = ConfigManager.isDynamicModulesEnabled();
|
||||
if (isDynamicModulesMode) {
|
||||
// should never happen
|
||||
return;
|
||||
}
|
||||
// only enter here when isDynamicModulesMode is off
|
||||
onForkPreForNonDynamicMode(true);
|
||||
}
|
||||
|
||||
public static void forkSystemServerPost(int pid) {
|
||||
onForkPostCommon(true, getDataPathPrefix() + "android", "system_server");
|
||||
}
|
||||
|
||||
/**
|
||||
* Some details are different between main zygote and secondary zygote.
|
||||
*/
|
||||
private static void onForkPreForNonDynamicMode(boolean isSystemServer) {
|
||||
Router.onForkStart();
|
||||
Router.initResourcesHook();
|
||||
// set startsSystemServer flag used when loadModules
|
||||
Router.prepare(isSystemServer);
|
||||
// deoptBootMethods once for all child processes of zygote
|
||||
PrebuiltMethodsDeopter.deoptBootMethods();
|
||||
// we never install bootstrap hooks here in black/white list mode except workaround hooks
|
||||
// because installed hooks would be propagated to all child processes of zygote
|
||||
Router.startWorkAroundHook();
|
||||
// loadModules once for all child processes of zygote
|
||||
// TODO maybe just save initZygote callbacks and call them when whitelisted process forked?
|
||||
Router.loadModulesSafely(true);
|
||||
Zygote.closeFilesBeforeFork();
|
||||
}
|
||||
|
||||
private static void onForkPostCommon(boolean isSystemServer, String appDataDir, String niceName) {
|
||||
Main.appDataDir = appDataDir;
|
||||
Main.niceName = niceName;
|
||||
final boolean isDynamicModulesMode = ConfigManager.isDynamicModulesEnabled();
|
||||
if (!isDynamicModulesMode) {
|
||||
Zygote.reopenFilesAfterFork();
|
||||
}
|
||||
Router.onEnterChildProcess();
|
||||
if (!checkNeedHook(appDataDir, niceName)) {
|
||||
// if is blacklisted, just stop here
|
||||
Router.onForkFinish();
|
||||
return;
|
||||
}
|
||||
if (isDynamicModulesMode) {
|
||||
Router.initResourcesHook();
|
||||
}
|
||||
Router.prepare(isSystemServer);
|
||||
PrebuiltMethodsDeopter.deoptBootMethods();
|
||||
Router.installBootstrapHooks(isSystemServer);
|
||||
if (isDynamicModulesMode) {
|
||||
Router.loadModulesSafely(false);
|
||||
}
|
||||
Router.onForkFinish();
|
||||
}
|
||||
|
||||
private static boolean checkNeedHook(String appDataDir, String niceName) {
|
||||
boolean needHook;
|
||||
if (TextUtils.isEmpty(appDataDir)) {
|
||||
Utils.logE("niceName:" + niceName + ", procName:"
|
||||
+ ProcessUtils.getCurrentProcessName(Main.appProcessName) + ", appDataDir is null, blacklisted!");
|
||||
needHook = false;
|
||||
} else {
|
||||
// FIXME some process cannot read app_data_file because of MLS, e.g. bluetooth
|
||||
needHook = ConfigManager.isAppNeedHook(appDataDir);
|
||||
}
|
||||
if (!needHook) {
|
||||
// clean up the scene
|
||||
onBlackListed();
|
||||
}
|
||||
return needHook;
|
||||
}
|
||||
|
||||
private static void onBlackListed() {
|
||||
XposedBridge.clearLoadedPackages();
|
||||
XposedBridge.clearInitPackageResources();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,72 +0,0 @@
|
|||
package com.elderdrivers.riru.edxp.yahfa.proxy;
|
||||
|
||||
import com.elderdrivers.riru.edxp.Main;
|
||||
import com.elderdrivers.riru.edxp.deopt.PrebuiltMethodsDeopter;
|
||||
import com.elderdrivers.riru.edxp.framework.Zygote;
|
||||
import com.elderdrivers.riru.edxp.yahfa.entry.Router;
|
||||
|
||||
import static com.elderdrivers.riru.edxp.util.FileUtils.getDataPathPrefix;
|
||||
|
||||
public class NormalProxy {
|
||||
|
||||
public static void forkAndSpecializePre(int uid, int gid, int[] gids, int debugFlags,
|
||||
int[][] rlimits, int mountExternal, String seInfo,
|
||||
String niceName, int[] fdsToClose, int[] fdsToIgnore,
|
||||
boolean startChildZygote, String instructionSet,
|
||||
String appDataDir) {
|
||||
// mainly for secondary zygote
|
||||
Router.onForkStart();
|
||||
Router.initResourcesHook();
|
||||
// call this to ensure the flag is set to false ASAP
|
||||
Router.prepare(false);
|
||||
PrebuiltMethodsDeopter.deoptBootMethods(); // do it once for secondary zygote
|
||||
// install bootstrap hooks for secondary zygote
|
||||
Router.installBootstrapHooks(false);
|
||||
// only load modules for secondary zygote
|
||||
Router.loadModulesSafely(true);
|
||||
Zygote.closeFilesBeforeFork();
|
||||
}
|
||||
|
||||
public static void forkAndSpecializePost(int pid, String appDataDir, String niceName) {
|
||||
// TODO consider processes without forkAndSpecializePost called
|
||||
Main.appDataDir = appDataDir;
|
||||
Main.niceName = niceName;
|
||||
Router.prepare(false);
|
||||
Zygote.reopenFilesAfterFork();
|
||||
Router.onEnterChildProcess();
|
||||
// load modules for each app process on its forked if dynamic modules mode is on
|
||||
Router.loadModulesSafely(false);
|
||||
Router.onForkFinish();
|
||||
}
|
||||
|
||||
public static void forkSystemServerPre(int uid, int gid, int[] gids, int debugFlags, int[][] rlimits,
|
||||
long permittedCapabilities, long effectiveCapabilities) {
|
||||
Router.onForkStart();
|
||||
Router.initResourcesHook();
|
||||
// set startsSystemServer flag used when loadModules
|
||||
Router.prepare(true);
|
||||
PrebuiltMethodsDeopter.deoptBootMethods(); // do it once for main zygote
|
||||
// install bootstrap hooks for main zygote as early as possible
|
||||
// in case we miss some processes not forked via forkAndSpecialize
|
||||
// for instance com.android.phone
|
||||
Router.installBootstrapHooks(true);
|
||||
// loadModules have to be executed in zygote even isDynamicModules is false
|
||||
// because if not global hooks installed in initZygote might not be
|
||||
// propagated to processes not forked via forkAndSpecialize
|
||||
Router.loadModulesSafely(true);
|
||||
Zygote.closeFilesBeforeFork();
|
||||
}
|
||||
|
||||
public static void forkSystemServerPost(int pid) {
|
||||
// in system_server process
|
||||
Main.appDataDir = getDataPathPrefix() + "android";
|
||||
Main.niceName = "system_server";
|
||||
Router.prepare(true);
|
||||
Zygote.reopenFilesAfterFork();
|
||||
Router.onEnterChildProcess();
|
||||
// reload module list if dynamic mode is on
|
||||
Router.loadModulesSafely(false);
|
||||
Router.onForkFinish();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1 @@
|
|||
com.elderdrivers.riru.edxp.yahfa.core.YahfaEdxpImpl
|
||||
Loading…
Reference in New Issue