Better Hidden

This commit is contained in:
LoveSy 2020-11-13 21:09:32 +08:00 committed by 双草酸酯
parent a5d6cbe44f
commit 0ece9b141d
57 changed files with 579 additions and 856 deletions

View File

@ -7,8 +7,7 @@ buildscript {
jcenter() jcenter()
} }
dependencies { dependencies {
classpath 'com.android.tools.build:gradle:3.4.0' classpath 'com.android.tools.build:gradle:4.1.1'
// NOTE: Do not place your application dependencies here; they belong // NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files // in the individual module build.gradle files

1
dalvikdx/.gitignore vendored
View File

@ -1 +1,2 @@
/build /build
dex

View File

@ -23,21 +23,31 @@ task findDx {
} }
} }
task dexInJar(type: Jar) { task makeDex(type: Exec) {
dependsOn jar dependsOn jar
dependsOn findDx dependsOn findDx
doFirst { def dexName = "classes.dex"
exec { workingDir jar.destinationDir
workingDir jar.destinationDir if (OperatingSystem.current().isWindows()) {
if (OperatingSystem.current().isWindows()){ executable "dx.bat"
executable "dx.bat" args "--dex", "--output", dexName, "${jar.archiveName}"
args "--dex", "--output", "classes.dex", "${jar.archiveName}" } else {
} else { executable "bash"
executable "bash" args rootProject.ext.dxPath.trim(), "--dex", "--output", dexName, "${jar.archiveName}"
args rootProject.ext.dxPath.trim(), "--dex", "--output", "classes.dex", "${jar.archiveName}"
}
}
} }
}
task dex(type: Copy) {
dependsOn makeDex
from (jar.destinationDir) {
include "classes.dex"
rename "classes.dex", "eddalvikdx.dex"
}
destinationDir new File(projectDir, "dex")
}
task dexInJar(type: Jar) {
dependsOn makeDex
from "${jar.destinationDir}/classes.dex" from "${jar.destinationDir}/classes.dex"
destinationDir jar.destinationDir destinationDir jar.destinationDir
baseName "eddalvikdx" baseName "eddalvikdx"

3
dexmaker/.gitignore vendored
View File

@ -1 +1,2 @@
/build /build
dex

View File

@ -14,20 +14,30 @@ dependencies {
compileOnly project(':dalvikdx') compileOnly project(':dalvikdx')
} }
task dexInJar(type: Jar) { task makeDex(type: Exec) {
dependsOn jar dependsOn jar
doFirst { def dexName = "classes.dex"
exec { workingDir jar.destinationDir
workingDir jar.destinationDir if (OperatingSystem.current().isWindows()) {
if (OperatingSystem.current().isWindows()){ executable "dx.bat"
executable "dx.bat" args "--dex", "--output", dexName, "${jar.archiveName}"
args "--dex", "--output", "classes.dex", "${jar.archiveName}" } else {
} else { executable "bash"
executable "bash" args rootProject.ext.dxPath.trim(), "--dex", "--output", dexName, "${jar.archiveName}"
args rootProject.ext.dxPath.trim(), "--dex", "--output", "classes.dex", "${jar.archiveName}"
}
}
} }
}
task dex(type: Copy) {
dependsOn makeDex
from (jar.destinationDir) {
include "classes.dex"
rename "classes.dex", "eddexmaker.dex"
}
destinationDir new File(projectDir, "dex")
}
task dexInJar(type: Jar) {
dependsOn makeDex
from "${jar.destinationDir}/classes.dex" from "${jar.destinationDir}/classes.dex"
destinationDir jar.destinationDir destinationDir jar.destinationDir
baseName "eddexmaker" baseName "eddexmaker"

View File

@ -17,13 +17,14 @@ android {
} }
} }
ndkVersion androidCompileNdkVersion
} }
dependencies { dependencies {
compileOnly project(':hiddenapi-stubs') compileOnly project(':hiddenapi-stubs')
api project(':xposed-bridge') api project(':xposed-bridge')
compileOnly project(':dexmaker') compileOnly project(':dexmaker')
api "androidx.annotation:annotation:1.1.0-rc01" compileOnly 'com.android.support:support-annotations:28.0.0'
} }

Binary file not shown.

View File

@ -1,36 +0,0 @@
package com.elderdrivers.riru.edxp._hooker.impl;
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 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 OneplusWorkaround extends XC_MethodHook {
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
if (XposedBridge.disableHooks || Main.getEdxpImpl().getRouter().isForkCompleted()) {
return;
}
Hookers.logD("BaseDexClassLoader#inCompatConfigList() starts");
param.setResult(false);
}
}

View File

@ -1,38 +0,0 @@
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;
import de.robv.android.xposed.annotation.ApiSensitive;
import de.robv.android.xposed.annotation.Level;
@ApiSensitive(Level.MIDDLE)
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;
}
}

View File

@ -51,4 +51,7 @@ public class BaseEdxpConfig implements EdxpConfig {
public boolean isBlackWhiteListMode() { public boolean isBlackWhiteListMode() {
return ConfigManager.isBlackWhiteListEnabled(); return ConfigManager.isBlackWhiteListEnabled();
} }
@Override
public String getModulesList() { return ConfigManager.getModulesList(); }
} }

View File

@ -50,4 +50,6 @@ public class ConfigManager {
public static native String getDataPathPrefix(); public static native String getDataPathPrefix();
public static native boolean isAppNeedHook(String appDataDir); public static native boolean isAppNeedHook(String appDataDir);
public static native String getModulesList();
} }

View File

@ -1,14 +1,12 @@
package com.elderdrivers.riru.edxp.core; package com.elderdrivers.riru.edxp.core;
import androidx.annotation.NonNull; import android.support.annotation.NonNull;
import com.elderdrivers.riru.edxp.proxy.BlackWhiteListProxy;
import com.elderdrivers.riru.edxp.proxy.NormalProxy; import com.elderdrivers.riru.edxp.proxy.NormalProxy;
import com.elderdrivers.riru.edxp.proxy.Router; import com.elderdrivers.riru.edxp.proxy.Router;
public abstract class BaseEdxpImpl implements EdxpImpl { public abstract class BaseEdxpImpl implements EdxpImpl {
protected Proxy mBlackWhiteListProxy;
protected Proxy mNormalProxy; protected Proxy mNormalProxy;
protected Router mRouter; protected Router mRouter;
@ -23,15 +21,6 @@ public abstract class BaseEdxpImpl implements EdxpImpl {
return mInitialized; return mInitialized;
} }
@NonNull
@Override
public Proxy getBlackWhiteListProxy() {
if (mBlackWhiteListProxy == null) {
mBlackWhiteListProxy = createBlackWhiteListProxy();
}
return mBlackWhiteListProxy;
}
@NonNull @NonNull
@Override @Override
public Proxy getNormalProxy() { public Proxy getNormalProxy() {
@ -50,10 +39,6 @@ public abstract class BaseEdxpImpl implements EdxpImpl {
return mRouter; return mRouter;
} }
protected Proxy createBlackWhiteListProxy() {
return new BlackWhiteListProxy(getRouter());
}
protected Proxy createNormalProxy() { protected Proxy createNormalProxy() {
return new NormalProxy(getRouter()); return new NormalProxy(getRouter());
} }

View File

@ -1,7 +1,7 @@
package com.elderdrivers.riru.edxp.core; package com.elderdrivers.riru.edxp.core;
import androidx.annotation.IntDef; import android.support.annotation.IntDef;
import androidx.annotation.NonNull; import android.support.annotation.NonNull;
import com.elderdrivers.riru.common.KeepAll; import com.elderdrivers.riru.common.KeepAll;
import com.elderdrivers.riru.edxp.proxy.Router; import com.elderdrivers.riru.edxp.proxy.Router;
@ -20,9 +20,6 @@ public interface EdxpImpl extends KeepAll {
@NonNull @NonNull
Proxy getNormalProxy(); Proxy getNormalProxy();
@NonNull
Proxy getBlackWhiteListProxy();
@NonNull @NonNull
Router getRouter(); Router getRouter();

View File

@ -1,27 +1,20 @@
package com.elderdrivers.riru.edxp.core; package com.elderdrivers.riru.edxp.core;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
import android.os.Process;
import com.elderdrivers.riru.common.KeepAll; import com.elderdrivers.riru.common.KeepAll;
import com.elderdrivers.riru.edxp.common.BuildConfig;
import com.elderdrivers.riru.edxp.config.ConfigManager;
import com.elderdrivers.riru.edxp.util.Utils; import com.elderdrivers.riru.edxp.util.Utils;
import java.security.AccessController; import java.security.AccessController;
import java.security.PrivilegedAction; import java.security.PrivilegedAction;
import java.util.Arrays;
import java.util.Iterator; import java.util.Iterator;
import java.util.ServiceLoader; import java.util.ServiceLoader;
import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.atomic.AtomicReference;
import static com.elderdrivers.riru.edxp.core.EdxpImpl.NONE;
@SuppressLint("DefaultLocale") @SuppressLint("DefaultLocale")
public class Main implements KeepAll { public class Main implements KeepAll {
private static final boolean logEnabled = BuildConfig.DEBUG;
private static String forkAndSpecializePramsStr = "";
private static String forkSystemServerPramsStr = "";
private static final AtomicReference<EdxpImpl> edxpImplRef = new AtomicReference<>(null); private static final AtomicReference<EdxpImpl> edxpImplRef = new AtomicReference<>(null);
static { static {
@ -37,67 +30,23 @@ public class Main implements KeepAll {
String niceName, int[] fdsToClose, int[] fdsToIgnore, String niceName, int[] fdsToClose, int[] fdsToIgnore,
boolean startChildZygote, String instructionSet, boolean startChildZygote, String instructionSet,
String appDataDir) { String appDataDir) {
final EdxpImpl edxp = getEdxpImpl(); // won't be loaded
if (edxp == null || !edxp.isInitialized()) {
return;
}
if (logEnabled) {
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()) {
edxp.getBlackWhiteListProxy().forkAndSpecializePre(uid, gid, gids, debugFlags, rlimits,
mountExternal, seInfo, niceName, fdsToClose, fdsToIgnore, startChildZygote,
instructionSet, appDataDir);
} else {
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) { public static void forkAndSpecializePost(int pid, String appDataDir, String niceName) {
final EdxpImpl edxp = getEdxpImpl(); final EdxpImpl edxp = getEdxpImpl();
if (edxp == null || !edxp.isInitialized()) { if (edxp == null || !edxp.isInitialized()) {
Utils.logE("Not started up");
return; return;
} }
if (pid == 0) { if (pid == 0) {
if (logEnabled) { edxp.getNormalProxy().forkAndSpecializePost(pid, appDataDir, niceName);
Utils.logI(forkAndSpecializePramsStr + " = " + Process.myPid());
}
if (ConfigManager.isBlackWhiteListEnabled()) {
edxp.getBlackWhiteListProxy().forkAndSpecializePost(pid, appDataDir, niceName);
} else {
edxp.getNormalProxy().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, public static void forkSystemServerPre(int uid, int gid, int[] gids, int debugFlags, int[][] rlimits,
long permittedCapabilities, long effectiveCapabilities) { long permittedCapabilities, long effectiveCapabilities) {
final EdxpImpl edxp = getEdxpImpl(); // Won't load
if (edxp == null || !edxp.isInitialized()) {
return;
}
if (logEnabled) {
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()) {
edxp.getBlackWhiteListProxy().forkSystemServerPre(uid, gid, gids, debugFlags, rlimits,
permittedCapabilities, effectiveCapabilities);
} else {
edxp.getNormalProxy().forkSystemServerPre(uid, gid, gids, debugFlags, rlimits,
permittedCapabilities, effectiveCapabilities);
}
} }
public static void forkSystemServerPost(int pid) { public static void forkSystemServerPost(int pid) {
@ -106,17 +55,7 @@ public class Main implements KeepAll {
return; return;
} }
if (pid == 0) { if (pid == 0) {
if (logEnabled) { edxp.getNormalProxy().forkSystemServerPost(pid);
Utils.logI(forkSystemServerPramsStr + " = " + Process.myPid());
}
if (ConfigManager.isBlackWhiteListEnabled()) {
edxp.getBlackWhiteListProxy().forkSystemServerPost(pid);
} else {
edxp.getNormalProxy().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
} }
} }
@ -134,19 +73,21 @@ public class Main implements KeepAll {
} }
private static void loadEdxpImpls() { private static void loadEdxpImpls() {
AccessController.doPrivileged(new PrivilegedAction<Void>() { // We don't have Manifest now, so we have to load manually.
public Void run() { try {
Iterator<EdxpImpl> iterator = ServiceLoader.load( Class.forName("com.elderdrivers.riru.edxp.sandhook.core.SandHookEdxpImpl");
EdxpImpl.class, Main.class.getClassLoader()).iterator(); }catch(Throwable ignored) {
try { Utils.logD("not using sandhook");
while (iterator.hasNext()) { }
iterator.next(); try {
} Class.forName("com.elderdrivers.riru.edxp.yahfa.core.YahfaEdxpImpl");
} catch (Throwable t) { }catch(Throwable ignored) {
Utils.logE("error when loadEdxpImpls", t); Utils.logD("not using yahfa");
} }
return null; try {
} Class.forName("com.elderdrivers.riru.edxp.whale.core.WhaleEdxpImpl");
}); }catch(Throwable ignored) {
Utils.logD("not found whale");
}
} }
} }

View File

@ -3,12 +3,10 @@ package com.elderdrivers.riru.edxp.entry.yahfa;
import com.elderdrivers.riru.common.KeepMembers; import com.elderdrivers.riru.common.KeepMembers;
import com.elderdrivers.riru.edxp._hooker.yahfa.HandleBindAppHooker; import com.elderdrivers.riru.edxp._hooker.yahfa.HandleBindAppHooker;
import com.elderdrivers.riru.edxp._hooker.yahfa.LoadedApkConstructorHooker; import com.elderdrivers.riru.edxp._hooker.yahfa.LoadedApkConstructorHooker;
import com.elderdrivers.riru.edxp._hooker.yahfa.OnePlusWorkAroundHooker;
public class AppBootstrapHookInfo implements KeepMembers { public class AppBootstrapHookInfo implements KeepMembers {
public static String[] hookItemNames = { public static String[] hookItemNames = {
HandleBindAppHooker.class.getName(), HandleBindAppHooker.class.getName(),
LoadedApkConstructorHooker.class.getName(), LoadedApkConstructorHooker.class.getName(),
OnePlusWorkAroundHooker.class.getName()
}; };
} }

View File

@ -3,7 +3,6 @@ package com.elderdrivers.riru.edxp.entry.yahfa;
import com.elderdrivers.riru.common.KeepMembers; import com.elderdrivers.riru.common.KeepMembers;
import com.elderdrivers.riru.edxp._hooker.yahfa.HandleBindAppHooker; import com.elderdrivers.riru.edxp._hooker.yahfa.HandleBindAppHooker;
import com.elderdrivers.riru.edxp._hooker.yahfa.LoadedApkConstructorHooker; import com.elderdrivers.riru.edxp._hooker.yahfa.LoadedApkConstructorHooker;
import com.elderdrivers.riru.edxp._hooker.yahfa.OnePlusWorkAroundHooker;
import com.elderdrivers.riru.edxp._hooker.yahfa.SystemMainHooker; import com.elderdrivers.riru.edxp._hooker.yahfa.SystemMainHooker;
public class SysBootstrapHookInfo implements KeepMembers { public class SysBootstrapHookInfo implements KeepMembers {
@ -11,6 +10,5 @@ public class SysBootstrapHookInfo implements KeepMembers {
HandleBindAppHooker.class.getName(), HandleBindAppHooker.class.getName(),
SystemMainHooker.class.getName(), SystemMainHooker.class.getName(),
LoadedApkConstructorHooker.class.getName(), LoadedApkConstructorHooker.class.getName(),
OnePlusWorkAroundHooker.class.getName()
}; };
} }

View File

@ -1,10 +0,0 @@
package com.elderdrivers.riru.edxp.entry.yahfa;
import com.elderdrivers.riru.common.KeepMembers;
import com.elderdrivers.riru.edxp._hooker.yahfa.OnePlusWorkAroundHooker;
public class WorkAroundHookInfo implements KeepMembers {
public static String[] hookItemNames = {
OnePlusWorkAroundHooker.class.getName()
};
}

View File

@ -7,19 +7,16 @@ import android.text.TextUtils;
import com.elderdrivers.riru.edxp._hooker.impl.HandleBindApp; import com.elderdrivers.riru.edxp._hooker.impl.HandleBindApp;
import com.elderdrivers.riru.edxp._hooker.impl.LoadedApkCstr; import com.elderdrivers.riru.edxp._hooker.impl.LoadedApkCstr;
import com.elderdrivers.riru.edxp._hooker.impl.OneplusWorkaround;
import com.elderdrivers.riru.edxp._hooker.impl.StartBootstrapServices; import com.elderdrivers.riru.edxp._hooker.impl.StartBootstrapServices;
import com.elderdrivers.riru.edxp._hooker.impl.SystemMain; import com.elderdrivers.riru.edxp._hooker.impl.SystemMain;
import com.elderdrivers.riru.edxp._hooker.yahfa.HandleBindAppHooker; import com.elderdrivers.riru.edxp._hooker.yahfa.HandleBindAppHooker;
import com.elderdrivers.riru.edxp._hooker.yahfa.LoadedApkConstructorHooker; import com.elderdrivers.riru.edxp._hooker.yahfa.LoadedApkConstructorHooker;
import com.elderdrivers.riru.edxp._hooker.yahfa.OnePlusWorkAroundHooker;
import com.elderdrivers.riru.edxp._hooker.yahfa.StartBootstrapServicesHooker; import com.elderdrivers.riru.edxp._hooker.yahfa.StartBootstrapServicesHooker;
import com.elderdrivers.riru.edxp._hooker.yahfa.SystemMainHooker; import com.elderdrivers.riru.edxp._hooker.yahfa.SystemMainHooker;
import com.elderdrivers.riru.edxp.core.yahfa.HookMain; import com.elderdrivers.riru.edxp.core.yahfa.HookMain;
import com.elderdrivers.riru.edxp.entry.yahfa.AppBootstrapHookInfo; import com.elderdrivers.riru.edxp.entry.yahfa.AppBootstrapHookInfo;
import com.elderdrivers.riru.edxp.entry.yahfa.SysBootstrapHookInfo; import com.elderdrivers.riru.edxp.entry.yahfa.SysBootstrapHookInfo;
import com.elderdrivers.riru.edxp.entry.yahfa.SysInnerHookInfo; import com.elderdrivers.riru.edxp.entry.yahfa.SysInnerHookInfo;
import com.elderdrivers.riru.edxp.entry.yahfa.WorkAroundHookInfo;
import com.elderdrivers.riru.edxp.util.Utils; import com.elderdrivers.riru.edxp.util.Utils;
import com.elderdrivers.riru.edxp.util.Versions; import com.elderdrivers.riru.edxp.util.Versions;
@ -33,14 +30,11 @@ import de.robv.android.xposed.annotation.Level;
public abstract class BaseRouter implements Router { public abstract class BaseRouter implements Router {
protected volatile boolean forkCompleted = false;
protected volatile AtomicBoolean bootstrapHooked = new AtomicBoolean(false); protected volatile AtomicBoolean bootstrapHooked = new AtomicBoolean(false);
protected static boolean useXposedApi = false; protected static boolean useXposedApi = false;
public void initResourcesHook() { public void initResourcesHook() {
startWorkAroundHook(); // for OnePlus devices
XposedBridge.initXResources(); XposedBridge.initXResources();
} }
@ -49,18 +43,6 @@ public abstract class BaseRouter implements Router {
XposedInit.startsSystemServer = isSystem; XposedInit.startsSystemServer = isSystem;
} }
public void onForkStart() {
forkCompleted = false;
}
public void onForkFinish() {
forkCompleted = true;
}
public boolean isForkCompleted() {
return forkCompleted;
}
public void installBootstrapHooks(boolean isSystem) { public void installBootstrapHooks(boolean isSystem) {
// Initialize the Xposed framework // Initialize the Xposed framework
try { try {
@ -75,10 +57,9 @@ public abstract class BaseRouter implements Router {
} }
} }
public void loadModulesSafely(boolean isInZygote, boolean callInitZygote) { public void loadModulesSafely(boolean callInitZygote) {
try { try {
// FIXME some coredomain app can't reading modules.list XposedInit.loadModules(callInitZygote);
XposedInit.loadModules(isInZygote, callInitZygote);
} catch (Exception exception) { } catch (Exception exception) {
Utils.logE("error loading module list", exception); Utils.logE("error loading module list", exception);
} }
@ -145,22 +126,4 @@ public abstract class BaseRouter implements Router {
SysInnerHookInfo.class.getName()); SysInnerHookInfo.class.getName());
} }
} }
@ApiSensitive(Level.LOW)
public void startWorkAroundHook() {
ClassLoader classLoader = BaseRouter.class.getClassLoader();
if (useXposedApi) {
try {
XposedHelpers.findAndHookMethod(OnePlusWorkAroundHooker.className,
classLoader, OnePlusWorkAroundHooker.methodName,
int.class, String.class, new OneplusWorkaround());
} catch (Throwable ignored) {
}
} else {
HookMain.doHookDefault(
BaseRouter.class.getClassLoader(),
classLoader,
WorkAroundHookInfo.class.getName());
}
}
} }

View File

@ -1,139 +0,0 @@
package com.elderdrivers.riru.edxp.proxy;
import android.text.TextUtils;
import com.elderdrivers.riru.edxp.config.ConfigManager;
import com.elderdrivers.riru.edxp.deopt.PrebuiltMethodsDeopter;
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 extends BaseProxy {
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) {
onForkPreForDynamicMode(false);
} else {
onForkPreForNonDynamicMode(false);
}
}
public void forkAndSpecializePost(int pid, String appDataDir, String niceName) {
onForkPostCommon(false, appDataDir, niceName);
}
public void forkSystemServerPre(int uid, int gid, int[] gids, int debugFlags,
int[][] rlimits, long permittedCapabilities,
long effectiveCapabilities) {
final boolean isDynamicModulesMode = ConfigManager.isDynamicModulesEnabled();
if (isDynamicModulesMode) {
onForkPreForDynamicMode(true);
} else {
onForkPreForNonDynamicMode(true);
}
}
public void forkSystemServerPost(int pid) {
onForkPostCommon(true, getDataPathPrefix() + "android", "system_server");
}
private void onForkPreForDynamicMode(boolean isSystemServer) {
mRouter.onForkStart();
mRouter.initResourcesHook();
mRouter.prepare(isSystemServer);
mRouter.loadModulesSafely(true, false);
}
/**
* Some details are different between main zygote and secondary zygote.
*/
private void onForkPreForNonDynamicMode(boolean isSystemServer) {
mRouter.onForkStart();
mRouter.initResourcesHook();
// set startsSystemServer flag used when loadModules
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
mRouter.startWorkAroundHook();
// loadModules once for all child processes of zygote
mRouter.loadModulesSafely(true, false);
}
private void onForkPostCommon(boolean isSystemServer, String appDataDir, String niceName) {
ConfigManager.appDataDir = appDataDir;
ConfigManager.niceName = niceName;
final boolean isDynamicModulesMode = ConfigManager.isDynamicModulesEnabled();
mRouter.onEnterChildProcess();
if (!checkNeedHook(appDataDir, niceName)) {
// if is blacklisted, just stop here
mRouter.onForkFinish();
return;
}
if (isDynamicModulesMode) {
mRouter.initResourcesHook();
}
mRouter.prepare(isSystemServer);
PrebuiltMethodsDeopter.deoptBootMethods();
mRouter.installBootstrapHooks(isSystemServer);
// under dynamic modules mode, don't call initZygote when loadModule
// cuz loaded module won't has that chance to do it
if (isDynamicModulesMode) {
mRouter.loadModulesSafely(false, false);
}
// call all initZygote callbacks
XposedBridge.callInitZygotes();
mRouter.onForkFinish();
}
private boolean checkNeedHook(String appDataDir, String niceName) {
boolean needHook;
if (TextUtils.isEmpty(appDataDir)) {
Utils.logE("niceName:" + niceName + ", procName:"
+ 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
needHook = ConfigManager.isAppNeedHook(appDataDir);
}
if (!needHook) {
// clean up the scene
onBlackListed();
}
return needHook;
}
}

View File

@ -18,8 +18,9 @@ public class NormalProxy extends BaseProxy {
String niceName, int[] fdsToClose, int[] fdsToIgnore, String niceName, int[] fdsToClose, int[] fdsToIgnore,
boolean startChildZygote, String instructionSet, boolean startChildZygote, String instructionSet,
String appDataDir) { String appDataDir) {
// mainly for secondary zygote }
mRouter.onForkStart();
public void forkAndSpecializePost(int pid, String appDataDir, String niceName) {
SELinuxHelper.initOnce(); SELinuxHelper.initOnce();
mRouter.initResourcesHook(); mRouter.initResourcesHook();
// call this to ensure the flag is set to false ASAP // call this to ensure the flag is set to false ASAP
@ -27,18 +28,15 @@ public class NormalProxy extends BaseProxy {
PrebuiltMethodsDeopter.deoptBootMethods(); // do it once for secondary zygote PrebuiltMethodsDeopter.deoptBootMethods(); // do it once for secondary zygote
// install bootstrap hooks for secondary zygote // install bootstrap hooks for secondary zygote
mRouter.installBootstrapHooks(false); mRouter.installBootstrapHooks(false);
// only load modules for secondary zygote
mRouter.loadModulesSafely(true, true);
}
public void forkAndSpecializePost(int pid, String appDataDir, String niceName) {
// TODO consider processes without forkAndSpecializePost being called // TODO consider processes without forkAndSpecializePost being called
forkPostCommon(pid, false, appDataDir, niceName); forkPostCommon(pid, false, appDataDir, niceName);
} }
public void forkSystemServerPre(int uid, int gid, int[] gids, int debugFlags, int[][] rlimits, public void forkSystemServerPre(int uid, int gid, int[] gids, int debugFlags, int[][] rlimits,
long permittedCapabilities, long effectiveCapabilities) { long permittedCapabilities, long effectiveCapabilities) {
mRouter.onForkStart(); }
public void forkSystemServerPost(int pid) {
SELinuxHelper.initOnce(); SELinuxHelper.initOnce();
mRouter.initResourcesHook(); mRouter.initResourcesHook();
// set startsSystemServer flag used when loadModules // set startsSystemServer flag used when loadModules
@ -48,13 +46,6 @@ public class NormalProxy extends BaseProxy {
// in case we miss some processes not forked via forkAndSpecialize // in case we miss some processes not forked via forkAndSpecialize
// for instance com.android.phone // for instance com.android.phone
mRouter.installBootstrapHooks(true); 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, true);
}
public void forkSystemServerPost(int pid) {
// in system_server process // in system_server process
forkPostCommon(pid, true, forkPostCommon(pid, true,
getDataPathPrefix() + "android", "system_server"); getDataPathPrefix() + "android", "system_server");
@ -66,13 +57,7 @@ public class NormalProxy extends BaseProxy {
ConfigManager.niceName = niceName; ConfigManager.niceName = niceName;
mRouter.prepare(isSystem); mRouter.prepare(isSystem);
mRouter.onEnterChildProcess(); mRouter.onEnterChildProcess();
// reload module list if dynamic mode is on mRouter.loadModulesSafely(true);
if (ConfigManager.isDynamicModulesEnabled()) {
// FIXME this could be error-prone because hooks installed inside old versions
// of initZygote instances of same module are not unhooked
mRouter.loadModulesSafely(false, true);
}
mRouter.onForkFinish();
} }
} }

View File

@ -10,21 +10,13 @@ public interface Router {
void installBootstrapHooks(boolean isSystem); void installBootstrapHooks(boolean isSystem);
void loadModulesSafely(boolean isInZygote, boolean callInitZygote); void loadModulesSafely(boolean callInitZygote);
void startBootstrapHook(boolean isSystem); void startBootstrapHook(boolean isSystem);
void startSystemServerHook(); void startSystemServerHook();
void startWorkAroundHook();
void onForkStart();
void onForkFinish();
void onEnterChildProcess(); void onEnterChildProcess();
void injectConfig(); void injectConfig();
boolean isForkCompleted();
} }

View File

@ -21,7 +21,7 @@ import de.robv.android.xposed.annotation.Level;
@ApiSensitive(Level.LOW) @ApiSensitive(Level.LOW)
public class ClassLoaderUtils { public class ClassLoaderUtils {
public static final String DEXPATH = "/system/framework/edxp.jar:/system/framework/eddalvikdx.jar:/system/framework/eddexmaker.jar"; public static final String DEXPATH = "/system/framework/edxp.dex:/system/framework/eddalvikdx.dex:/system/framework/eddexmaker.dex";
public static void replaceParentClassLoader(ClassLoader appClassLoader) { public static void replaceParentClassLoader(ClassLoader appClassLoader) {
if (appClassLoader == null) { if (appClassLoader == null) {

View File

@ -6,4 +6,5 @@
/template_override/module.prop /template_override/module.prop
/template_override/system /template_override/system
/template_override/system_x86 /template_override/system_x86
*.iml *.iml
/.cxx

View File

@ -70,8 +70,8 @@ android {
release { release {
externalNativeBuild { externalNativeBuild {
cmake { cmake {
cppFlags "-fvisibility=hidden -fvisibility-inlines-hidden -O2 -s -Wno-unused-value" cppFlags "-fvisibility=hidden -fvisibility-inlines-hidden -O2 -s -Wno-unused-value -fomit-frame-pointer"
cFlags "-fvisibility=hidden -fvisibility-inlines-hidden -O2 -s -Wno-unused-value" cFlags "-fvisibility=hidden -fvisibility-inlines-hidden -O2 -s -Wno-unused-value -fomit-frame-pointer"
} }
} }
minifyEnabled true minifyEnabled true
@ -83,6 +83,35 @@ android {
path "src/main/cpp/CMakeLists.txt" path "src/main/cpp/CMakeLists.txt"
} }
} }
ndkVersion androidCompileNdkVersion
}
task copyDalvikdxDex {
def dexTask = tasks.getByPath(':dalvikdx:dex')
dependsOn dexTask
doLast {
copy {
from dexTask
into jar_dest_dir
}
}
onlyIf {
!dexTask.state.upToDate
}
}
task copyDexmakerDex {
def dexTask = tasks.getByPath(':dexmaker:dex')
dependsOn dexTask
doLast {
copy {
from dexTask
into jar_dest_dir
}
}
onlyIf {
!dexTask.state.upToDate
}
} }
task copyDalvikdxJar { task copyDalvikdxJar {
@ -132,8 +161,8 @@ afterEvaluate {
def magiskModuleId = property("${backendLowered}" + "_module_id") def magiskModuleId = property("${backendLowered}" + "_module_id")
def prepareJarsTask = task("prepareJars${backendCapped}${variantCapped}") { def prepareJarsTask = task("prepareJars${backendCapped}${variantCapped}") {
dependsOn cleanTemplate, copyDalvikdxJar, copyDexmakerJar dependsOn cleanTemplate, copyDalvikdxDex, copyDexmakerDex
dependsOn tasks.getByPath(":edxp-${backendLowered}:makeAndCopy${variantCapped}") dependsOn tasks.getByPath(":edxp-${backendLowered}:copyDex${variantCapped}")
} }
def prepareMagiskFilesTask = task("prepareMagiskFiles${backendCapped}${variantCapped}", type: Delete) { def prepareMagiskFilesTask = task("prepareMagiskFiles${backendCapped}${variantCapped}", type: Delete) {
@ -220,7 +249,28 @@ afterEvaluate {
workingDir "${projectDir}/release" workingDir "${projectDir}/release"
def commands = ["adb", "push", def commands = ["adb", "push",
"${module_name}-${backend}-${project.version}-${variantLowered}.zip", "${module_name}-${backend}-${project.version}-${variantLowered}.zip",
"/sdcard/"] "/data/local/tmp/"]
if (is_windows) {
commandLine 'cmd', '/c', commands.join(" ")
} else {
commandLine commands
}
}
task("flash${backendCapped}${variantCapped}", type: Exec) {
dependsOn tasks.getByPath("push${backendCapped}${variantCapped}")
workingDir "${projectDir}/release"
def commands = ["adb", "shell", "su", "-c",
"magisk --install-module /data/local/tmp/${module_name}-${backend}-${project.version}-${variantLowered}.zip"]
if (is_windows) {
commandLine 'cmd', '/c', commands.join(" ")
} else {
commandLine commands
}
}
task("flashAndReboot${backendCapped}${variantCapped}", type: Exec) {
dependsOn tasks.getByPath("flash${backendCapped}${variantCapped}")
workingDir "${projectDir}/release"
def commands = ["adb", "shell", "reboot"]
if (is_windows) { if (is_windows) {
commandLine 'cmd', '/c', commands.join(" ") commandLine 'cmd', '/c', commands.join(" ")
} else { } else {

View File

@ -4,7 +4,7 @@
#include <art/base/macros.h> #include <art/base/macros.h>
#include "logging.h" #include "logging.h"
#define JNI_START JNIEnv *env, jclass clazz #define JNI_START JNIEnv *env, [[maybe_unused]] jclass clazz
ALWAYS_INLINE static void JNIExceptionClear(JNIEnv *env) { ALWAYS_INLINE static void JNIExceptionClear(JNIEnv *env) {
if (env->ExceptionCheck()) { if (env->ExceptionCheck()) {
@ -126,8 +126,29 @@ public:
if (env_ && jstr_) env_->ReleaseStringUTFChars(jstr_, cstr_); if (env_ && jstr_) env_->ReleaseStringUTFChars(jstr_, cstr_);
} }
JUTFString(JUTFString &&other)
: env_(std::move(other.env_)), jstr_(std::move(other.jstr_)),
cstr_(std::move(other.cstr_)) {
other.cstr_ = nullptr;
}
JUTFString &
operator=(JUTFString &&other) {
if (&other != this) {
env_ = std::move(other.env_);
jstr_ = std::move(other.jstr_);
cstr_ = std::move(other.cstr_);
other.cstr_ = nullptr;
}
return *this;
}
private: private:
JNIEnv *env_; JNIEnv *env_;
jstring jstr_; jstring jstr_;
const char *cstr_; const char *cstr_;
JUTFString(const JUTFString &) = delete;
JUTFString &operator=(const JUTFString &) = delete;
}; };

View File

@ -5,15 +5,15 @@
#include <dlfcn.h> #include <dlfcn.h>
#include <sys/mman.h> #include <sys/mman.h>
#define __uintval(p) reinterpret_cast<uintptr_t>(p) #define _uintval(p) reinterpret_cast<uintptr_t>(p)
#define __ptr(p) reinterpret_cast<void *>(p) #define _ptr(p) reinterpret_cast<void *>(p)
#define __align_up(x, n) (((x) + ((n) - 1)) & ~((n) - 1)) #define _align_up(x, n) (((x) + ((n) - 1)) & ~((n) - 1))
#define __align_down(x, n) ((x) & -(n)) #define _align_down(x, n) ((x) & -(n))
#define __page_size 4096 #define _page_size 4096
#define __page_align(n) __align_up(static_cast<uintptr_t>(n), __page_size) #define _page_align(n) _align_up(static_cast<uintptr_t>(n), _page_size)
#define __ptr_align(x) __ptr(__align_down(reinterpret_cast<uintptr_t>(x), __page_size)) #define _ptr_align(x) _ptr(_align_down(reinterpret_cast<uintptr_t>(x), _page_size))
#define __make_rwx(p, n) ::mprotect(__ptr_align(p), \ #define _make_rwx(p, n) ::mprotect(_ptr_align(p), \
__page_align(__uintval(p) + n) != __page_align(__uintval(p)) ? __page_align(n) + __page_size : __page_align(n), \ _page_align(_uintval(p) + n) != _page_align(_uintval(p)) ? _page_align(n) + _page_size : _page_align(n), \
PROT_READ | PROT_WRITE | PROT_EXEC) PROT_READ | PROT_WRITE | PROT_EXEC)
typedef void (*HookFunType)(void *, void *, void **); typedef void (*HookFunType)(void *, void *, void **);
@ -97,7 +97,7 @@ namespace edxp {
ALWAYS_INLINE inline static void HookFunction(HookFunType hook_fun, void *original, ALWAYS_INLINE inline static void HookFunction(HookFunType hook_fun, void *original,
void *replace, void **backup) { void *replace, void **backup) {
__make_rwx(original, __page_size); _make_rwx(original, _page_size);
hook_fun(original, replace, backup); hook_fun(original, replace, backup);
} }

View File

@ -6,6 +6,7 @@
#include <string> #include <string>
#include "art/base/macros.h" #include "art/base/macros.h"
#include "android_build.h" #include "android_build.h"
#include "utils.h"
namespace edxp { namespace edxp {
@ -18,23 +19,22 @@ namespace edxp {
# define LP_SELECT(lp32, lp64) (lp32) # define LP_SELECT(lp32, lp64) (lp32)
#endif #endif
static constexpr auto kInjectDexPath = "/system/framework/edxp.jar:" static const auto kInjectDexPath = "/system/framework/edxp.dex:"
"/system/framework/eddalvikdx.jar:" "/system/framework/eddalvikdx.dex:"
"/system/framework/eddexmaker.jar"; "/system/framework/eddexmaker.dex"_str;
static constexpr auto kEntryClassName = "com.elderdrivers.riru.edxp.core.Main"; static const auto kEntryClassName = "com.elderdrivers.riru.edxp.core.Main"_str;
static constexpr auto kClassLinkerClassName = "com.elderdrivers.riru.edxp.art.ClassLinker"; static const auto kClassLinkerClassName = "com.elderdrivers.riru.edxp.art.ClassLinker";
static constexpr auto kSandHookClassName = "com.swift.sandhook.SandHook"; static const auto kSandHookClassName = "com.swift.sandhook.SandHook"_str;
static constexpr auto kSandHookNeverCallClassName = "com.swift.sandhook.ClassNeverCall"; static const auto kSandHookNeverCallClassName = "com.swift.sandhook.ClassNeverCall"_str;
static constexpr auto kXposedBridgeClassName = "de.robv.android.xposed.XposedBridge";
static constexpr auto kLibArtName = "libart.so"; static const auto kLibArtName = "libart.so"_str;
static constexpr auto kLibFwkName = "libandroid_runtime.so"; static const auto kLibFwkName = "libandroid_runtime.so"_str;
static constexpr auto kLibFwName = "libandroidfw.so"; static const auto kLibFwName = "libandroidfw.so"_str;
static constexpr auto kLibWhaleName = "libwhale.edxp.so"; static const auto kLibWhaleName = "libwhale.edxp.so"_str;
static constexpr auto kLibSandHookName = "libsandhook.edxp.so"; static const auto kLibSandHookName = "libsandhook.edxp.so"_str;
static constexpr auto kLibDlName = "libdl.so"; static const auto kLibDlName = "libdl.so"_str;
static constexpr auto kLibSandHookNativeName = "libsandhook-native.so"; static const auto kLibSandHookNativeName = "libsandhook-native.so"_str;
static const auto kLibBasePath = std::string( static const auto kLibBasePath = std::string(
LP_SELECT("/system/lib/", LP_SELECT("/system/lib/",
@ -50,7 +50,7 @@ namespace edxp {
static const auto kLibFwPath = kLibBasePath + kLibFwName; static const auto kLibFwPath = kLibBasePath + kLibFwName;
static const auto kLibFwkPath = kLibBasePath + kLibFwkName; static const auto kLibFwkPath = kLibBasePath + kLibFwkName;
inline const char *const BoolToString(bool b) { inline constexpr const char *const BoolToString(bool b) {
return b ? "true" : "false"; return b ? "true" : "false";
} }
} }

View File

@ -17,7 +17,7 @@
#define LOGW(...) #define LOGW(...)
#define LOGE(...) #define LOGE(...)
#else #else
#ifndef NDEBUG #if 1
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__) #define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
#else #else
#define LOGD(...) #define LOGD(...)

View File

@ -0,0 +1,15 @@
//
// Created by loves on 11/13/2020.
//
#ifndef EDXPOSED_UTILS_H
#define EDXPOSED_UTILS_H
#include <string>
namespace edxp{
inline const std::string operator ""_str(const char *str, std::size_t size) {
return {str, size};
}
}
#endif //EDXPOSED_UTILS_H

View File

@ -14,55 +14,46 @@
#include <android_build.h> #include <android_build.h>
#include <logging.h> #include <logging.h>
#include <linux/limits.h> #include <climits>
#include <JNIHelper.h> #include <fstream>
#include "art/runtime/native/native_util.h" #include "art/runtime/native/native_util.h"
#include "config_manager.h" #include "config_manager.h"
using namespace std;
using namespace art;
namespace edxp { namespace edxp {
namespace fs = std::filesystem;
std::string ConfigManager::RetrieveInstallerPkgName() const { std::string ConfigManager::RetrieveInstallerPkgName() const {
std::string data_test_path = data_path_prefix_ + kPrimaryInstallerPkgName; std::string data_test_path = data_path_prefix_ / kPrimaryInstallerPkgName;
if (access(data_test_path.c_str(), F_OK) == 0) { if (fs::exists(data_test_path)) {
LOGI("using installer %s", kPrimaryInstallerPkgName); LOGI("using installer %s", kPrimaryInstallerPkgName.c_str());
return kPrimaryInstallerPkgName; return kPrimaryInstallerPkgName;
} }
data_test_path = data_path_prefix_ + kLegacyInstallerPkgName; data_test_path = data_path_prefix_ / kLegacyInstallerPkgName;
if (access(data_test_path.c_str(), F_OK) == 0) { if (fs::exists(data_test_path)) {
LOGI("using installer %s", kLegacyInstallerPkgName); LOGI("using installer %s", kLegacyInstallerPkgName.c_str());
return kLegacyInstallerPkgName; return kLegacyInstallerPkgName;
} }
LOGE("no supported installer app found, using default: %s", kPrimaryInstallerPkgName); LOGE("no supported installer app found, using default: %s",
kPrimaryInstallerPkgName.c_str());
return kPrimaryInstallerPkgName; return kPrimaryInstallerPkgName;
} }
void ConfigManager::SnapshotBlackWhiteList() { void ConfigManager::SnapshotBlackWhiteList() {
DIR *dir; white_list_default_.clear();
struct dirent *dent; for (auto &item: fs::directory_iterator(whitelist_path_)) {
dir = opendir(whitelist_path_.c_str()); if (item.is_regular_file()) {
if (dir != nullptr) { const auto &file_name = item.path().filename();
while ((dent = readdir(dir)) != nullptr) { LOGI(" whitelist: %s", file_name.c_str());
if (dent->d_type == DT_REG) { white_list_default_.emplace(file_name);
const char *fileName = dent->d_name;
LOGI(" whitelist: %s", fileName);
white_list_default_.emplace_back(fileName);
}
} }
closedir(dir);
} }
dir = opendir(blacklist_path_.c_str()); black_list_default_.clear();
if (dir != nullptr) { for (auto &item: fs::directory_iterator(blacklist_path_)) {
while ((dent = readdir(dir)) != nullptr) { if (item.is_regular_file()) {
if (dent->d_type == DT_REG) { const auto &file_name = item.path().filename();
const char *fileName = dent->d_name; LOGI(" blacklist: %s", file_name.c_str());
LOGI(" blacklist: %s", fileName); black_list_default_.emplace(file_name);
black_list_default_.emplace_back(fileName);
}
} }
closedir(dir);
} }
} }
@ -72,10 +63,8 @@ namespace edxp {
last_user_ = user; last_user_ = user;
} }
const char *format = use_prot_storage_ ? "/data/user_de/%u/" : "/data/user/%u/"; data_path_prefix_ = use_prot_storage_ ? "/data/user_de" : "/data/user";
char buff[PATH_MAX]; data_path_prefix_ /= std::to_string(last_user_);
snprintf(buff, sizeof(buff), format, last_user_);
data_path_prefix_ = buff;
installer_pkg_name_ = RetrieveInstallerPkgName(); installer_pkg_name_ = RetrieveInstallerPkgName();
base_config_path_ = GetConfigPath(""); base_config_path_ = GetConfigPath("");
@ -83,15 +72,16 @@ namespace edxp {
whitelist_path_ = GetConfigPath("whitelist/"); whitelist_path_ = GetConfigPath("whitelist/");
use_whitelist_path_ = GetConfigPath("usewhitelist"); use_whitelist_path_ = GetConfigPath("usewhitelist");
dynamic_modules_enabled_ = access(GetConfigPath("dynamicmodules").c_str(), F_OK) == 0; dynamic_modules_enabled_ = fs::exists(GetConfigPath("dynamicmodules"));
black_white_list_enabled_ = access(GetConfigPath("blackwhitelist").c_str(), F_OK) == 0; black_white_list_enabled_ = fs::exists(GetConfigPath("blackwhitelist"));
deopt_boot_image_enabled_ = access(GetConfigPath("deoptbootimage").c_str(), F_OK) == 0; deopt_boot_image_enabled_ = fs::exists(GetConfigPath("deoptbootimage"));
resources_hook_enabled_ = access(GetConfigPath("enable_resources").c_str(), F_OK) == 0; resources_hook_enabled_ = fs::exists(GetConfigPath("enable_resources"));
no_module_log_enabled_ = access(GetConfigPath("disable_modules_log").c_str(), F_OK) == 0; no_module_log_enabled_ = fs::exists(GetConfigPath("disable_modules_log"));
hidden_api_bypass_enabled_ = access(GetConfigPath("disable_hidden_api_bypass").c_str(), F_OK) != 0; hidden_api_bypass_enabled_ =
!fs::exists(GetConfigPath("disable_hidden_api_bypass"));
// use_white_list snapshot // use_white_list snapshot
use_white_list_snapshot_ = access(use_whitelist_path_.c_str(), F_OK) == 0; use_white_list_snapshot_ = fs::exists(use_whitelist_path_);
LOGI("data path prefix: %s", data_path_prefix_.c_str()); LOGI("data path prefix: %s", data_path_prefix_.c_str());
LOGI(" application list mode: %s", BoolToString(black_white_list_enabled_)); LOGI(" application list mode: %s", BoolToString(black_white_list_enabled_));
LOGI(" using whitelist: %s", BoolToString(use_white_list_snapshot_)); LOGI(" using whitelist: %s", BoolToString(use_white_list_snapshot_));
@ -105,19 +95,32 @@ namespace edxp {
} }
} }
std::tuple<bool, uid_t, std::string>
ConfigManager::GetAppInfoFromDir(const std::string &app_data_dir) {
uid_t uid = 0;
fs::path path(app_data_dir);
std::vector<std::string> splits(path.begin(), path.end());
if (splits.size() < 5u) {
LOGE("can't parse %s", path.c_str());
return {false, uid, {}};
}
const auto &uid_str = splits[3];
const auto &package_name = splits[4];
try {
uid = stol(uid_str);
} catch (const std::invalid_argument &ignored) {
LOGE("can't parse %s", app_data_dir.c_str());
return {false, 0, {}};
}
return {true, uid, package_name};
}
// TODO ignore unrelated processes // TODO ignore unrelated processes
bool ConfigManager::IsAppNeedHook(const std::string &app_data_dir) { bool ConfigManager::IsAppNeedHook(const std::string &app_data_dir) {
// zygote always starts with `uid == 0` and then fork into different user. // zygote always starts with `uid == 0` and then fork into different user.
// so we have to check if we are the correct user or not. // so we have to check if we are the correct user or not.
uid_t user = 0; const auto[res, user, package_name] = GetAppInfoFromDir(app_data_dir);
char package_name[PATH_MAX]; if (!res) return true;
if (sscanf(app_data_dir.c_str(), "/data/%*[^/]/%u/%s", &user, package_name) != 2) {
if (sscanf(app_data_dir.c_str(), "/data/%*[^/]/%s", package_name) != 1) {
package_name[0] = '\0';
LOGE("can't parse %s", app_data_dir.c_str());
return false; // default to no hooking for safety
}
}
if (last_user_ != user) { if (last_user_ != user) {
UpdateConfigPath(user); UpdateConfigPath(user);
@ -126,17 +129,17 @@ namespace edxp {
if (!black_white_list_enabled_) { if (!black_white_list_enabled_) {
return true; return true;
} }
bool can_access_app_data = access(base_config_path_.c_str(), F_OK) == 0; bool can_access_app_data = fs::exists(base_config_path_);
bool use_white_list; bool use_white_list;
if (can_access_app_data) { if (can_access_app_data) {
use_white_list = access(use_whitelist_path_.c_str(), F_OK) == 0; use_white_list = fs::exists(use_whitelist_path_);
} else { } else {
LOGE("can't access config path, using snapshot use_white_list: %s", LOGE("can't access config path, using snapshot use_white_list: %s",
app_data_dir.c_str()); app_data_dir.c_str());
use_white_list = use_white_list_snapshot_; use_white_list = use_white_list_snapshot_;
} }
if (strcmp(package_name, kPrimaryInstallerPkgName) == 0 if (package_name == kPrimaryInstallerPkgName
|| strcmp(package_name, kLegacyInstallerPkgName) == 0) { || package_name == kLegacyInstallerPkgName) {
// always hook installer apps // always hook installer apps
return true; return true;
} }
@ -144,80 +147,55 @@ namespace edxp {
if (!can_access_app_data) { if (!can_access_app_data) {
LOGE("can't access config path, using snapshot white list: %s", LOGE("can't access config path, using snapshot white list: %s",
app_data_dir.c_str()); app_data_dir.c_str());
return !(find(white_list_default_.begin(), white_list_default_.end(), return white_list_default_.count(package_name);
package_name) ==
white_list_default_.end());
} }
std::string target_path = whitelist_path_ + package_name; std::string target_path = whitelist_path_ / package_name;
bool res = access(target_path.c_str(), F_OK) == 0; bool res = fs::exists(target_path);
LOGD("using whitelist, %s -> %d", app_data_dir.c_str(), res); LOGD("using whitelist, %s -> %d", app_data_dir.c_str(), res);
return res; return res;
} else { } else {
if (!can_access_app_data) { if (!can_access_app_data) {
LOGE("can't access config path, using snapshot black list: %s", LOGE("can't access config path, using snapshot black list: %s",
app_data_dir.c_str()); app_data_dir.c_str());
return find(black_list_default_.begin(), black_list_default_.end(), package_name) == return black_list_default_.count(package_name);
black_list_default_.end();
} }
std::string target_path = blacklist_path_ + package_name; std::string target_path = blacklist_path_ / package_name;
bool res = access(target_path.c_str(), F_OK) != 0; bool res = !fs::exists(target_path);
LOGD("using blacklist, %s -> %d", app_data_dir.c_str(), res); LOGD("using blacklist, %s -> %d", app_data_dir.c_str(), res);
return res; return res;
} }
} }
ALWAYS_INLINE bool ConfigManager::IsBlackWhiteListEnabled() const {
return black_white_list_enabled_;
}
ALWAYS_INLINE bool ConfigManager::IsDynamicModulesEnabled() const {
return dynamic_modules_enabled_;
}
ALWAYS_INLINE bool ConfigManager::IsNoModuleLogEnabled() const {
return no_module_log_enabled_;
}
ALWAYS_INLINE bool ConfigManager::IsResourcesHookEnabled() const {
return resources_hook_enabled_;
}
ALWAYS_INLINE bool ConfigManager::IsDeoptBootImageEnabled() const {
return deopt_boot_image_enabled_;
}
ALWAYS_INLINE bool ConfigManager::IsHiddenAPIBypassEnabled() const {
return hidden_api_bypass_enabled_;
}
ALWAYS_INLINE std::string ConfigManager::GetInstallerPackageName() const {
return installer_pkg_name_;
}
ALWAYS_INLINE std::string ConfigManager::GetXposedPropPath() const {
return kXposedPropPath;
}
ALWAYS_INLINE std::string ConfigManager::GetLibSandHookName() const {
return kLibSandHookName;
}
ALWAYS_INLINE std::string ConfigManager::GetLibWhaleName() const {
return kLibWhaleName;
}
ALWAYS_INLINE std::string ConfigManager::GetDataPathPrefix() const {
return data_path_prefix_;
}
ALWAYS_INLINE std::string ConfigManager::GetConfigPath(const std::string &suffix) const {
return data_path_prefix_ + installer_pkg_name_ + "/conf/" + suffix;
};
ConfigManager::ConfigManager() { ConfigManager::ConfigManager() {
use_prot_storage_ = GetAndroidApiLevel() >= __ANDROID_API_N__; use_prot_storage_ = GetAndroidApiLevel() >= __ANDROID_API_N__;
last_user_ = 0; last_user_ = 0;
UpdateConfigPath(last_user_); UpdateConfigPath(last_user_);
} }
bool ConfigManager::UpdateModuleList() {
if (LIKELY(modules_list_) && !IsDynamicModulesEnabled())
return true;
auto global_modules_list = GetConfigPath("modules.list");
if (!fs::exists(global_modules_list)) {
LOGE("Cannot access path %s", global_modules_list.c_str());
return false;
}
if (auto last_write_time = fs::last_write_time(global_modules_list);
LIKELY(last_write_time < last_write_time_)) {
return true;
} else {
last_write_time_ = last_write_time;
}
std::ifstream ifs(global_modules_list);
if (!ifs.good()) {
LOGE("Cannot access path %s", global_modules_list.c_str());
return false;
}
modules_list_ = std::make_unique<std::string>(std::istreambuf_iterator<char>(ifs),
std::istreambuf_iterator<char>());
return true;
}
} }

View File

@ -3,62 +3,77 @@
#include <vector> #include <vector>
#include <string> #include <string>
#include <JNIHelper.h> #include "JNIHelper.h"
#include <utility>
#include <art/runtime/native/native_util.h> #include <art/runtime/native/native_util.h>
#include <filesystem>
#include <unordered_set>
namespace edxp { namespace edxp {
static constexpr const char *kPrimaryInstallerPkgName = "org.meowcat.edxposed.manager"; static const std::string kPrimaryInstallerPkgName = "org.meowcat.edxposed.manager";
static constexpr const char *kLegacyInstallerPkgName = "de.robv.android.xposed.installer"; static const std::string kLegacyInstallerPkgName = "de.robv.android.xposed.installer";
static constexpr auto kXposedPropPath = "/system/framework/edconfig.jar"; static const std::string kXposedPropPath = "/system/framework/edconfig.jar";
class ConfigManager { class ConfigManager {
public: public:
static ConfigManager *GetInstance() { inline static ConfigManager *GetInstance() {
if (instance_ == 0) { if (!instance_) {
instance_ = new ConfigManager(); instance_ = std::make_unique<ConfigManager>();
} }
return instance_; return instance_.get();
} }
bool IsBlackWhiteListEnabled() const; inline static std::unique_ptr<ConfigManager> ReleaseInstance() {
return std::move(instance_);
}
bool IsDynamicModulesEnabled() const; inline auto IsBlackWhiteListEnabled() const { return black_white_list_enabled_; }
bool IsResourcesHookEnabled() const; inline auto IsDynamicModulesEnabled() const { return dynamic_modules_enabled_; }
bool IsDeoptBootImageEnabled() const; inline auto IsResourcesHookEnabled() const { return resources_hook_enabled_; }
bool IsNoModuleLogEnabled() const; inline auto IsDeoptBootImageEnabled() const { return deopt_boot_image_enabled_; }
bool IsHiddenAPIBypassEnabled() const; inline auto IsNoModuleLogEnabled() const { return no_module_log_enabled_; }
std::string GetInstallerPackageName() const; inline auto IsHiddenAPIBypassEnabled() const { return hidden_api_bypass_enabled_; }
std::string GetXposedPropPath() const; inline auto GetInstallerPackageName() const { return installer_pkg_name_; }
std::string GetLibSandHookName() const; inline auto GetXposedPropPath() const { return kXposedPropPath; }
std::string GetLibWhaleName() const; inline auto GetLibSandHookName() const { return kLibSandHookName; }
std::string GetDataPathPrefix() const; inline auto GetLibWhaleName() const { return kLibWhaleName; }
std::string GetConfigPath(const std::string &suffix) const; inline auto GetDataPathPrefix() const { return data_path_prefix_; }
inline auto GetConfigPath(const std::string &suffix) const {
return data_path_prefix_ / installer_pkg_name_ / "conf" / suffix;
}
inline auto GetModulesList() const { return modules_list_.get(); }
bool IsAppNeedHook(const std::string &app_data_dir); bool IsAppNeedHook(const std::string &app_data_dir);
bool hidden_api_bypass_enabled_ = false; bool UpdateModuleList();
static std::tuple<bool, uid_t, std::string>
GetAppInfoFromDir(const std::string &app_data_dir);
private: private:
inline static ConfigManager *instance_; inline static std::unique_ptr<ConfigManager> instance_ = nullptr;
uid_t last_user_ = false; uid_t last_user_ = false;
bool use_prot_storage_ = true; bool use_prot_storage_ = true;
std::string data_path_prefix_; std::filesystem::path data_path_prefix_;
std::string installer_pkg_name_; std::filesystem::path installer_pkg_name_;
std::string base_config_path_; std::filesystem::path base_config_path_;
std::string blacklist_path_; std::filesystem::path blacklist_path_;
std::string whitelist_path_; std::filesystem::path whitelist_path_;
std::string use_whitelist_path_; std::filesystem::path use_whitelist_path_;
bool black_white_list_enabled_ = false; bool black_white_list_enabled_ = false;
bool dynamic_modules_enabled_ = false; bool dynamic_modules_enabled_ = false;
bool deopt_boot_image_enabled_ = false; bool deopt_boot_image_enabled_ = false;
@ -66,8 +81,13 @@ namespace edxp {
bool resources_hook_enabled_ = false; bool resources_hook_enabled_ = false;
// snapshot at boot // snapshot at boot
bool use_white_list_snapshot_ = false; bool use_white_list_snapshot_ = false;
std::vector<std::string> white_list_default_; std::unordered_set<std::string> white_list_default_;
std::vector<std::string> black_list_default_; std::unordered_set<std::string> black_list_default_;
bool hidden_api_bypass_enabled_ = false;
std::unique_ptr<std::string> modules_list_ = nullptr;
std::filesystem::file_time_type last_write_time_;
ConfigManager(); ConfigManager();
@ -76,6 +96,8 @@ namespace edxp {
void SnapshotBlackWhiteList(); void SnapshotBlackWhiteList();
std::string RetrieveInstallerPkgName() const; std::string RetrieveInstallerPkgName() const;
friend std::unique_ptr<ConfigManager> std::make_unique<ConfigManager>();
}; };
} // namespace edxp } // namespace edxp

View File

@ -14,6 +14,8 @@
#include <android-base/strings.h> #include <android-base/strings.h>
#include <nativehelper/scoped_local_ref.h> #include <nativehelper/scoped_local_ref.h>
#include <jni/edxp_pending_hooks.h> #include <jni/edxp_pending_hooks.h>
#include <fstream>
#include <sstream>
#include "edxp_context.h" #include "edxp_context.h"
#include "config_manager.h" #include "config_manager.h"
@ -52,7 +54,28 @@ namespace edxp {
CallPostFixupStaticTrampolinesCallback(class_ptr, post_fixup_static_mid_); CallPostFixupStaticTrampolinesCallback(class_ptr, post_fixup_static_mid_);
} }
void Context::LoadDexAndInit(JNIEnv *env, const char *dex_path) { void Context::PreLoadDex(JNIEnv *env, const std::string &dex_path) {
if (LIKELY(!dexes.empty())) return;
std::vector<std::string> paths;
{
std::istringstream is(dex_path);
std::string path;
while (std::getline(is, path, ':')) {
paths.emplace_back(std::move(path));
}
}
for (const auto &path: paths) {
std::ifstream is(path, std::ios::binary);
if (!is.good()) {
LOGE("Cannot load path %s", path.c_str());
}
dexes.emplace_back(std::istreambuf_iterator<char>(is),
std::istreambuf_iterator<char>());
LOGD("Loaded %s with size %zu", path.c_str(), dexes.back().size());
}
}
void Context::InjectDexAndInit(JNIEnv *env) {
if (LIKELY(initialized_)) { if (LIKELY(initialized_)) {
return; return;
} }
@ -62,21 +85,34 @@ namespace edxp {
env, classloader, "getSystemClassLoader", "()Ljava/lang/ClassLoader;"); env, classloader, "getSystemClassLoader", "()Ljava/lang/ClassLoader;");
jobject sys_classloader = JNI_CallStaticObjectMethod(env, classloader, getsyscl_mid); jobject sys_classloader = JNI_CallStaticObjectMethod(env, classloader, getsyscl_mid);
if (UNLIKELY(!sys_classloader)) { if (UNLIKELY(!sys_classloader)) {
LOG(ERROR) << "getSystemClassLoader failed!!!"; LOGE("getSystemClassLoader failed!!!");
return; return;
} }
jclass path_classloader = JNI_FindClass(env, "dalvik/system/PathClassLoader"); jclass in_memory_classloader = JNI_FindClass(env, "dalvik/system/InMemoryDexClassLoader");
jmethodID initMid = JNI_GetMethodID(env, path_classloader, "<init>", jmethodID initMid = JNI_GetMethodID(env, in_memory_classloader, "<init>",
"(Ljava/lang/String;Ljava/lang/String;Ljava/lang/ClassLoader;)V"); "([Ljava/nio/ByteBuffer;Ljava/lang/ClassLoader;)V");
jobject my_cl = JNI_NewObject(env, path_classloader, initMid, env->NewStringUTF(dex_path), jclass byte_buffer_class = JNI_FindClass(env, "java/nio/ByteBuffer");
nullptr, sys_classloader); jmethodID byte_buffer_wrap = JNI_GetStaticMethodID(env, byte_buffer_class, "wrap",
"([B)Ljava/nio/ByteBuffer;");
auto buffer_array = env->NewObjectArray(dexes.size(), byte_buffer_class, nullptr);
for (size_t i = 0; i != dexes.size(); ++i) {
const auto dex = dexes.at(i);
auto byte_array = env->NewByteArray(dex.size());
env->SetByteArrayRegion(byte_array, 0, dex.size(),
dex.data());
auto buffer = JNI_CallStaticObjectMethod(env, byte_buffer_class, byte_buffer_wrap,
byte_array);
env->SetObjectArrayElement(buffer_array, i, buffer);
}
jobject my_cl = env->NewObject(in_memory_classloader, initMid,
buffer_array, sys_classloader);
env->DeleteLocalRef(classloader); env->DeleteLocalRef(classloader);
env->DeleteLocalRef(sys_classloader); env->DeleteLocalRef(sys_classloader);
env->DeleteLocalRef(path_classloader); env->DeleteLocalRef(in_memory_classloader);
env->DeleteLocalRef(byte_buffer_class);
if (UNLIKELY(my_cl == nullptr)) { if (UNLIKELY(my_cl == nullptr)) {
LOG(ERROR) << "PathClassLoader creation failed!!!"; LOGE("InMemoryDexClassLoader creation failed!!!");
return; return;
} }
@ -140,7 +176,7 @@ namespace edxp {
} }
jclass jclass
Context::FindClassFromLoader(JNIEnv *env, jobject class_loader, const char *class_name) const { Context::FindClassFromLoader(JNIEnv *env, jobject class_loader, const char *class_name) {
jclass clz = JNI_GetObjectClass(env, class_loader); jclass clz = JNI_GetObjectClass(env, class_loader);
jmethodID mid = JNI_GetMethodID(env, clz, "loadClass", jmethodID mid = JNI_GetMethodID(env, clz, "loadClass",
"(Ljava/lang/String;)Ljava/lang/Class;"); "(Ljava/lang/String;)Ljava/lang/Class;");
@ -155,57 +191,17 @@ namespace edxp {
return (jclass) target; return (jclass) target;
} }
} else { } else {
LOG(ERROR) << "No loadClass/findClass method found"; LOGE("No loadClass/findClass method found");
} }
LOG(ERROR) << "Class " << class_name << " not found"; LOGE("Class %s not found", class_name);
return ret; return ret;
} }
jclass Context::FindClassFromLoader(JNIEnv *env, const char *className) const {
return FindClassFromLoader(env, GetCurrentClassLoader(), className);
}
inline void Context::PrepareJavaEnv(JNIEnv *env) { inline void Context::PrepareJavaEnv(JNIEnv *env) {
LoadDexAndInit(env, kInjectDexPath); InjectDexAndInit(env);
} }
void Context::ReleaseJavaEnv(JNIEnv *env) {
if (UNLIKELY(!instance_)) return;
auto xposed_bridge_class = FindClassFromLoader(env, inject_class_loader_, kXposedBridgeClassName);
if(LIKELY(xposed_bridge_class)){
jmethodID clear_all_callbacks_method = JNI_GetStaticMethodID(env, xposed_bridge_class, "clearAllCallbacks",
"()V");
if(LIKELY(clear_all_callbacks_method)) {
JNI_CallStaticVoidMethod(env, xposed_bridge_class, clear_all_callbacks_method);
}
}
initialized_ = false;
if (entry_class_) {
env->DeleteGlobalRef(entry_class_);
entry_class_ = nullptr;
}
if (class_linker_class_) {
env->DeleteGlobalRef(class_linker_class_);
class_linker_class_ = nullptr;
}
if (inject_class_loader_) {
env->DeleteGlobalRef(inject_class_loader_);
inject_class_loader_ = nullptr;
}
app_data_dir_ = nullptr;
nice_name_ = nullptr;
vm_ = nullptr;
pre_fixup_static_mid_ = nullptr;
post_fixup_static_mid_ = nullptr;
auto systemClass = env->FindClass("java/lang/System");
auto systemGCMethod = env->GetStaticMethodID(systemClass, "gc", "()V");
env->CallStaticVoidMethod(systemClass, systemGCMethod);
}
inline void Context::FindAndCall(JNIEnv *env, const char *method_name, inline void Context::FindAndCall(JNIEnv *env, const char *method_name,
const char *method_sig, ...) const { const char *method_sig, ...) const {
if (UNLIKELY(!entry_class_)) { if (UNLIKELY(!entry_class_)) {
@ -224,16 +220,15 @@ namespace edxp {
} }
void void
Context::OnNativeForkSystemServerPre(JNIEnv *env, jclass clazz, uid_t uid, gid_t gid, Context::OnNativeForkSystemServerPre(JNIEnv *env, [[maybe_unused]] jclass clazz, uid_t uid,
gid_t gid,
jintArray gids, jintArray gids,
jint runtime_flags, jobjectArray rlimits, jint runtime_flags, jobjectArray rlimits,
jlong permitted_capabilities, jlong permitted_capabilities,
jlong effective_capabilities) { jlong effective_capabilities) {
app_data_dir_ = env->NewStringUTF(SYSTEM_SERVER_DATA_DIR); app_data_dir_ = env->NewStringUTF(SYSTEM_SERVER_DATA_DIR.c_str());
PrepareJavaEnv(env); ConfigManager::GetInstance()->UpdateModuleList();
// jump to java code PreLoadDex(env, kInjectDexPath);
FindAndCall(env, "forkSystemServerPre", "(II[II[[IJJ)V", uid, gid, gids, runtime_flags,
rlimits, permitted_capabilities, effective_capabilities);
} }
@ -249,15 +244,13 @@ namespace edxp {
return 0; return 0;
} }
std::tuple<bool, bool> Context::ShouldSkipInject(JNIEnv *env, jstring nice_name, jstring data_dir, jint uid, bool Context::ShouldSkipInject(JNIEnv *env, jstring nice_name, jstring data_dir, jint uid,
jboolean is_child_zygote) { jboolean is_child_zygote) {
const auto app_id = uid % PER_USER_RANGE; const auto app_id = uid % PER_USER_RANGE;
const JUTFString package_name(env, nice_name, "UNKNOWN"); const JUTFString package_name(env, nice_name, "UNKNOWN");
bool skip = false; bool skip = false;
bool release = true;
if (is_child_zygote) { if (is_child_zygote) {
skip = true; skip = true;
release = false; // In Android R, calling XposedBridge.clearAllCallbacks cause crashes.
LOGW("skip injecting into %s because it's a child zygote", package_name.get()); LOGW("skip injecting into %s because it's a child zygote", package_name.get());
} }
@ -265,17 +258,16 @@ namespace edxp {
(app_id >= FIRST_APP_ZYGOTE_ISOLATED_UID && app_id <= LAST_APP_ZYGOTE_ISOLATED_UID) || (app_id >= FIRST_APP_ZYGOTE_ISOLATED_UID && app_id <= LAST_APP_ZYGOTE_ISOLATED_UID) ||
app_id == SHARED_RELRO_UID) { app_id == SHARED_RELRO_UID) {
skip = true; skip = true;
release = false; // In Android R, calling XposedBridge.clearAllCallbacks cause crashes.
LOGW("skip injecting into %s because it's isolated", package_name.get()); LOGW("skip injecting into %s because it's isolated", package_name.get());
} }
const JUTFString dir(env, data_dir); const JUTFString dir(env, data_dir);
if(!dir || !ConfigManager::GetInstance()->IsAppNeedHook(dir)) { if (!dir || !ConfigManager::GetInstance()->IsAppNeedHook(dir)) {
skip = true; skip = true;
LOGW("skip injecting xposed into %s because it's whitelisted/blacklisted", LOGW("skip injecting xposed into %s because it's whitelisted/blacklisted",
package_name.get()); package_name.get());
} }
return {skip, release}; return skip;
} }
void Context::OnNativeForkAndSpecializePre(JNIEnv *env, jclass clazz, void Context::OnNativeForkAndSpecializePre(JNIEnv *env, jclass clazz,
@ -291,32 +283,29 @@ namespace edxp {
jboolean is_child_zygote, jboolean is_child_zygote,
jstring instruction_set, jstring instruction_set,
jstring app_data_dir) { jstring app_data_dir) {
std::tie(skip_, release_) = ShouldSkipInject(env, nice_name, app_data_dir, uid, is_child_zygote); skip_ = ShouldSkipInject(env, nice_name, app_data_dir, uid,
is_child_zygote);
ConfigManager::GetInstance()->UpdateModuleList();
app_data_dir_ = app_data_dir; app_data_dir_ = app_data_dir;
nice_name_ = nice_name; nice_name_ = nice_name;
PrepareJavaEnv(env); PreLoadDex(env, kInjectDexPath);
if(!skip_) {
FindAndCall(env, "forkAndSpecializePre",
"(II[II[[IILjava/lang/String;Ljava/lang/String;[I[IZLjava/lang/String;Ljava/lang/String;)V",
uid, gid, gids, runtime_flags, rlimits,
mount_external, se_info, nice_name, fds_to_close, fds_to_ignore,
is_child_zygote, instruction_set, app_data_dir);
}
} }
int Context::OnNativeForkAndSpecializePost(JNIEnv *env, jclass clazz, jint res) { int
Context::OnNativeForkAndSpecializePost(JNIEnv *env, [[maybe_unused]]jclass clazz, jint res) {
if (res == 0) { if (res == 0) {
const JUTFString package_name(env, nice_name_); const JUTFString process_name(env, nice_name_);
if (!skip_) { if (!skip_) {
PrepareJavaEnv(env); PrepareJavaEnv(env);
LOGD("Done prepare");
FindAndCall(env, "forkAndSpecializePost", FindAndCall(env, "forkAndSpecializePost",
"(ILjava/lang/String;Ljava/lang/String;)V", "(ILjava/lang/String;Ljava/lang/String;)V",
res, app_data_dir_, nice_name_); res, app_data_dir_, nice_name_);
LOGD("injected xposed into %s", package_name.get()); LOGD("injected xposed into %s", process_name.get());
} else { } else {
if(release_) auto config_manager = ConfigManager::ReleaseInstance();
ReleaseJavaEnv(env); auto context = Context::ReleaseInstance();
LOGD("skipped %s", package_name.get()); LOGD("skipped %s", process_name.get());
} }
} else { } else {
// in zygote process, res is child zygote pid // in zygote process, res is child zygote pid

View File

@ -1,13 +1,15 @@
#pragma once #pragma once
#include <utility>
#include <unistd.h> #include <unistd.h>
#include <mutex> #include <vector>
#include <string>
#include <string_view>
#include "utils.h"
namespace edxp { namespace edxp {
static const auto SYSTEM_SERVER_DATA_DIR = "/data/user/0/android"_str;
#define SYSTEM_SERVER_DATA_DIR "/data/user/0/android"
enum Variant { enum Variant {
NONE = 0, NONE = 0,
YAHFA = 1, YAHFA = 1,
@ -18,11 +20,15 @@ namespace edxp {
class Context { class Context {
public: public:
inline static auto GetInstance() { inline static Context *GetInstance() {
if (instance_ == nullptr) { if (!instance_) {
instance_ = new Context(); instance_ = std::make_unique<Context>();
} }
return instance_; return instance_.get();
}
inline static std::unique_ptr<Context> ReleaseInstance() {
return std::move(instance_);
} }
inline auto GetCurrentClassLoader() const { return inject_class_loader_; } inline auto GetCurrentClassLoader() const { return inject_class_loader_; }
@ -45,7 +51,13 @@ namespace edxp {
inline auto GetNiceName() const { return nice_name_; } inline auto GetNiceName() const { return nice_name_; }
jclass FindClassFromLoader(JNIEnv *env, const char *className) const; inline jclass FindClassFromLoader(JNIEnv *env, const std::string &className) const {
return FindClassFromLoader(env, className.c_str());
};
inline jclass FindClassFromLoader(JNIEnv *env, const char *className) const {
return FindClassFromLoader(env, GetCurrentClassLoader(), className);
}
void OnNativeForkAndSpecializePre(JNIEnv *env, jclass clazz, jint uid, jint gid, void OnNativeForkAndSpecializePre(JNIEnv *env, jclass clazz, jint uid, jint gid,
jintArray gids, jint runtime_flags, jobjectArray rlimits, jintArray gids, jint runtime_flags, jobjectArray rlimits,
@ -68,7 +80,7 @@ namespace edxp {
inline auto GetVariant() const { return variant_; }; inline auto GetVariant() const { return variant_; };
private: private:
inline static Context *instance_; inline static std::unique_ptr<Context> instance_;
bool initialized_ = false; bool initialized_ = false;
Variant variant_ = NONE; Variant variant_ = NONE;
jobject inject_class_loader_ = nullptr; jobject inject_class_loader_ = nullptr;
@ -80,22 +92,29 @@ namespace edxp {
jmethodID pre_fixup_static_mid_ = nullptr; jmethodID pre_fixup_static_mid_ = nullptr;
jmethodID post_fixup_static_mid_ = nullptr; jmethodID post_fixup_static_mid_ = nullptr;
bool skip_ = false; bool skip_ = false;
bool release_ = true; std::vector<std::vector<signed char>> dexes;
Context() {} Context() {}
~Context() {} void PreLoadDex(JNIEnv *env, const std::string &dex_path);
void LoadDexAndInit(JNIEnv *env, const char *dex_path); void InjectDexAndInit(JNIEnv *env);
jclass FindClassFromLoader(JNIEnv *env, jobject class_loader, const char *class_name) const; inline jclass FindClassFromLoader(JNIEnv *env, jobject class_loader,
const std::string &class_name) const {
return FindClassFromLoader(env, class_loader, class_name.c_str());
}
static jclass
FindClassFromLoader(JNIEnv *env, jobject class_loader, const char *class_name);
void CallPostFixupStaticTrampolinesCallback(void *class_ptr, jmethodID mid); void CallPostFixupStaticTrampolinesCallback(void *class_ptr, jmethodID mid);
static std::tuple<bool, bool> ShouldSkipInject(JNIEnv *env, jstring nice_name, jstring data_dir, jint uid, static bool ShouldSkipInject(JNIEnv *env, jstring nice_name, jstring data_dir, jint uid,
jboolean is_child_zygote); jboolean is_child_zygote);
void ReleaseJavaEnv(JNIEnv *env); friend std::unique_ptr<Context> std::make_unique<Context>();
}; };
} }

View File

@ -61,6 +61,16 @@ namespace edxp {
return result; return result;
} }
static jstring ConfigManager_getModulesList(JNI_START) {
if (auto module_list = ConfigManager::GetInstance()->GetModulesList(); module_list) {
LOGD("module list: %s", module_list->c_str());
return env->NewStringUTF(module_list->c_str());
} else {
LOGW("Empty modules list");
return env->NewStringUTF("");
}
}
static JNINativeMethod gMethods[] = { static JNINativeMethod gMethods[] = {
NATIVE_METHOD(ConfigManager, isBlackWhiteListEnabled, "()Z"), NATIVE_METHOD(ConfigManager, isBlackWhiteListEnabled, "()Z"),
NATIVE_METHOD(ConfigManager, isDynamicModulesEnabled, "()Z"), NATIVE_METHOD(ConfigManager, isDynamicModulesEnabled, "()Z"),
@ -72,8 +82,10 @@ namespace edxp {
NATIVE_METHOD(ConfigManager, getLibSandHookName, "()Ljava/lang/String;"), NATIVE_METHOD(ConfigManager, getLibSandHookName, "()Ljava/lang/String;"),
NATIVE_METHOD(ConfigManager, getLibWhaleName, "()Ljava/lang/String;"), NATIVE_METHOD(ConfigManager, getLibWhaleName, "()Ljava/lang/String;"),
NATIVE_METHOD(ConfigManager, getDataPathPrefix, "()Ljava/lang/String;"), NATIVE_METHOD(ConfigManager, getDataPathPrefix, "()Ljava/lang/String;"),
NATIVE_METHOD(ConfigManager, getInstallerConfigPath, "(Ljava/lang/String;)Ljava/lang/String;"), NATIVE_METHOD(ConfigManager, getInstallerConfigPath,
"(Ljava/lang/String;)Ljava/lang/String;"),
NATIVE_METHOD(ConfigManager, isAppNeedHook, "(Ljava/lang/String;)Z"), NATIVE_METHOD(ConfigManager, isAppNeedHook, "(Ljava/lang/String;)Z"),
NATIVE_METHOD(ConfigManager, getModulesList, "()Ljava/lang/String;"),
}; };
void RegisterConfigManagerMethods(JNIEnv *env) { void RegisterConfigManagerMethods(JNIEnv *env) {

View File

@ -36,18 +36,18 @@ PROP_PRODUCT=$(getprop ro.build.product)
PROP_BRAND=$(getprop ro.product.brand) PROP_BRAND=$(getprop ro.product.brand)
PROP_MANUFACTURER=$(getprop ro.product.manufacturer) PROP_MANUFACTURER=$(getprop ro.product.manufacturer)
JAR_EDXP="$(getRandomNameExist 8 "" ".jar" " JAR_EDXP="$(getRandomNameExist 8 "" ".dex" "
/system/framework /system/framework
").jar" ").dex"
JAR_EDDALVIKDX="$(getRandomNameExist 8 "" ".jar" " JAR_EDDALVIKDX="$(getRandomNameExist 8 "" ".dex" "
/system/framework /system/framework
").jar" ").dex"
JAR_EDDEXMAKER="$(getRandomNameExist 8 "" ".jar" " JAR_EDDEXMAKER="$(getRandomNameExist 8 "" ".dex" "
/system/framework /system/framework
").jar" ").dex"
JAR_EDCONFIG="$(getRandomNameExist 8 "" ".jar" " #JAR_EDCONFIG="$(getRandomNameExist 8 "" ".jar" "
/system/framework #/system/framework
").jar" #").jar"
LIB_RIRU_EDXP="libriru_${RIRU_EDXP}.so" LIB_RIRU_EDXP="libriru_${RIRU_EDXP}.so"
LIB_WHALE_EDXP="lib$(getRandomNameExist 10 "lib" ".so" " LIB_WHALE_EDXP="lib$(getRandomNameExist 10 "lib" ".so" "
/system/lib /system/lib
@ -267,10 +267,10 @@ fi
ui_print "- Copying framework libraries" ui_print "- Copying framework libraries"
mv "${MODPATH}/system/framework/eddalvikdx.jar" "${MODPATH}/system/framework/${JAR_EDDALVIKDX}" mv "${MODPATH}/system/framework/eddalvikdx.dex" "${MODPATH}/system/framework/${JAR_EDDALVIKDX}"
mv "${MODPATH}/system/framework/edxp.jar" "${MODPATH}/system/framework/${JAR_EDXP}" mv "${MODPATH}/system/framework/edxp.dex" "${MODPATH}/system/framework/${JAR_EDXP}"
mv "${MODPATH}/system/framework/eddexmaker.jar" "${MODPATH}/system/framework/${JAR_EDDEXMAKER}" mv "${MODPATH}/system/framework/eddexmaker.dex" "${MODPATH}/system/framework/${JAR_EDDEXMAKER}"
mv "${MODPATH}/system/framework/edconfig.jar" "${MODPATH}/system/framework/${JAR_EDCONFIG}" #mv "${MODPATH}/system/framework/edconfig.jar" "${MODPATH}/system/framework/${JAR_EDCONFIG}"
mv "${MODPATH}/system/lib/libriru_edxp.so" "${MODPATH}/system/lib/${LIB_RIRU_EDXP}" mv "${MODPATH}/system/lib/libriru_edxp.so" "${MODPATH}/system/lib/${LIB_RIRU_EDXP}"
#mv "${MODPATH}/system/lib/libwhale.edxp.so" "${MODPATH}/system/lib/${LIB_WHALE_EDXP}" #mv "${MODPATH}/system/lib/libwhale.edxp.so" "${MODPATH}/system/lib/${LIB_WHALE_EDXP}"
mv "${MODPATH}/system/lib/libsandhook-native.so" "${MODPATH}/system/lib/libsandhook-native.so" mv "${MODPATH}/system/lib/libsandhook-native.so" "${MODPATH}/system/lib/libsandhook-native.so"
@ -290,15 +290,15 @@ fi
ui_print "- Resetting libraries path" ui_print "- Resetting libraries path"
sed -i 's:/system/framework/edxp.jar\:/system/framework/eddalvikdx.jar\:/system/framework/eddexmaker.jar:/system/framework/'"${JAR_EDXP}"'\:/system/framework/'"${JAR_EDDALVIKDX}"'\:/system/framework/'"${JAR_EDDEXMAKER}"':g' "${MODPATH}/system/lib/${LIB_RIRU_EDXP}" sed -i 's:/system/framework/edxp.dex\:/system/framework/eddalvikdx.dex\:/system/framework/eddexmaker.dex:/system/framework/'"${JAR_EDXP}"'\:/system/framework/'"${JAR_EDDALVIKDX}"'\:/system/framework/'"${JAR_EDDEXMAKER}"':g' "${MODPATH}/system/lib/${LIB_RIRU_EDXP}"
sed -i 's:/system/framework/edconfig.jar:/system/framework/'"${JAR_EDCONFIG}"':g' "${MODPATH}/system/lib/${LIB_RIRU_EDXP}" #sed -i 's:/system/framework/edconfig.jar:/system/framework/'"${JAR_EDCONFIG}"':g' "${MODPATH}/system/lib/${LIB_RIRU_EDXP}"
sed -i 's:libriru_edxp.so:'"${LIB_RIRU_EDXP}"':g' "${MODPATH}/system/lib/${LIB_RIRU_EDXP}" sed -i 's:libriru_edxp.so:'"${LIB_RIRU_EDXP}"':g' "${MODPATH}/system/lib/${LIB_RIRU_EDXP}"
#sed -i 's:libwhale.edxp.so:'"${LIB_WHALE_EDXP}"':g' "${MODPATH}/system/lib/${LIB_RIRU_EDXP}" #sed -i 's:libwhale.edxp.so:'"${LIB_WHALE_EDXP}"':g' "${MODPATH}/system/lib/${LIB_RIRU_EDXP}"
sed -i 's:libsandhook.edxp.so:'"${LIB_SANDHOOK_EDXP}"':g' "${MODPATH}/system/lib/${LIB_RIRU_EDXP}" sed -i 's:libsandhook.edxp.so:'"${LIB_SANDHOOK_EDXP}"':g' "${MODPATH}/system/lib/${LIB_RIRU_EDXP}"
if [[ "${IS64BIT}" == true ]]; then if [[ "${IS64BIT}" == true ]]; then
sed -i 's:/system/framework/edxp.jar\:/system/framework/eddalvikdx.jar\:/system/framework/eddexmaker.jar:/system/framework/'"${JAR_EDXP}"'\:/system/framework/'"${JAR_EDDALVIKDX}"'\:/system/framework/'"${JAR_EDDEXMAKER}"':g' "${MODPATH}/system/lib64/${LIB_RIRU_EDXP}" sed -i 's:/system/framework/edxp.dex\:/system/framework/eddalvikdx.dex\:/system/framework/eddexmaker.dex:/system/framework/'"${JAR_EDXP}"'\:/system/framework/'"${JAR_EDDALVIKDX}"'\:/system/framework/'"${JAR_EDDEXMAKER}"':g' "${MODPATH}/system/lib64/${LIB_RIRU_EDXP}"
sed -i 's:/system/framework/edconfig.jar:/system/framework/'"${JAR_EDCONFIG}"':g' "${MODPATH}/system/lib64/${LIB_RIRU_EDXP}" # sed -i 's:/system/framework/edconfig.jar:/system/framework/'"${JAR_EDCONFIG}"':g' "${MODPATH}/system/lib64/${LIB_RIRU_EDXP}"
sed -i 's:libriru_edxp.so:'"${LIB_RIRU_EDXP}"':g' "${MODPATH}/system/lib64/${LIB_RIRU_EDXP}" sed -i 's:libriru_edxp.so:'"${LIB_RIRU_EDXP}"':g' "${MODPATH}/system/lib64/${LIB_RIRU_EDXP}"
#sed -i 's:libwhale.edxp.so:'"${LIB_WHALE_EDXP}"':g' "${MODPATH}/system/lib64/${LIB_RIRU_EDXP}" #sed -i 's:libwhale.edxp.so:'"${LIB_WHALE_EDXP}"':g' "${MODPATH}/system/lib64/${LIB_RIRU_EDXP}"
sed -i 's:libsandhook.edxp.so:'"${LIB_SANDHOOK_EDXP}"':g' "${MODPATH}/system/lib64/${LIB_RIRU_EDXP}" sed -i 's:libsandhook.edxp.so:'"${LIB_SANDHOOK_EDXP}"':g' "${MODPATH}/system/lib64/${LIB_RIRU_EDXP}"

View File

@ -2,5 +2,5 @@ allow system_server system_server process execmem
allow system_server system_server memprotect mmap_zero allow system_server system_server memprotect mmap_zero
allow coredomain coredomain process execmem allow coredomain coredomain process execmem
allow coredomain app_data_file * * allow coredomain app_data_file * *
attradd {system_app platform_app} mlstrustedsubject attradd { system_app platform_app } mlstrustedsubject
allow zygote apk_data_file * * allow zygote apk_data_file * *

View File

@ -1,2 +1,2 @@
/build /build
/template_override/system/framework/edxp.jar /template_override/system/framework

View File

@ -22,10 +22,11 @@ android {
} }
} }
ndkVersion androidCompileNdkVersion
} }
dependencies { dependencies {
compileOnly files("${hiddenApiStubJarFilePath}") compileOnly project(':hiddenapi-stubs')
implementation project(':edxp-common') implementation project(':edxp-common')
implementation 'com.swift.sandhook:hooklib:4.2.1' implementation 'com.swift.sandhook:hooklib:4.2.1'
compileOnly project(':dexmaker') compileOnly project(':dexmaker')
@ -59,20 +60,39 @@ afterEvaluate {
def myTemplatePath = "${projectDir}/template_override/" def myTemplatePath = "${projectDir}/template_override/"
task("makeAndCopy${variantNameCapped}", type: Jar, dependsOn: "assemble${variantNameCapped}") { task("copyDex${variantNameCapped}", type: Copy) {
dependsOn "assemble${variantNameCapped}"
dependsOn tasks.getByPath(":edxp-common:copyCommonProperties") dependsOn tasks.getByPath(":edxp-common:copyCommonProperties")
def dexOutPath = variant.name.contains("release") ? def dexOutPath = "${buildDir}/intermediates/dex/${variantNameLowered}/minify${variantNameCapped}WithR8"
"${buildDir}/intermediates/transforms/dexMerger/${variantNameLowered}/0/" : from (dexOutPath){
"${buildDir}/intermediates/dex/${variantNameLowered}/mergeDex${variantNameCapped}/out/" rename("classes.dex", "edxp.dex")
from dexOutPath, "${projectDir}/src/main/resources/" }
from "${projectDir}/src/main/resources/"
destinationDir file(myTemplatePath + "system/framework/") destinationDir file(myTemplatePath + "system/framework/")
baseName "edxp"
doLast { doLast {
copy { copy {
from file(myTemplatePath) from file(myTemplatePath)
into file(templateRootPath) into file(templateRootPath)
} }
} }
}
task("makeAndCopy${variantNameCapped}", type: Jar, dependsOn: "assemble${variantNameCapped}") {
dependsOn tasks.getByPath(":edxp-common:copyCommonProperties")
def dexOutPath = "${buildDir}/intermediates/dex/${variantNameLowered}/mergeDex${variantNameCapped}"
from (dexOutPath){
rename("classes.dex", "edxp.dex")
}
from "${projectDir}/src/main/resources/"
destinationDir file(myTemplatePath + "system/framework/")
baseName "edxp"
doLast {
copy {
from file(myTemplatePath)
into file(templateRootPath)
include "*.dex"
}
}
outputs.upToDateWhen { false } outputs.upToDateWhen { false }
} }
} }

View File

@ -32,6 +32,6 @@
-keep class com.swift.sandhook.** {*;} -keep class com.swift.sandhook.** {*;}
-keepclasseswithmember class * { -keepclasseswithmembers class * {
native <methods>; native <methods>;
} }

View File

@ -7,7 +7,6 @@ import com.elderdrivers.riru.edxp.sandhook.config.SandHookProvider;
import com.elderdrivers.riru.edxp.sandhook.entry.AppBootstrapHookInfo; import com.elderdrivers.riru.edxp.sandhook.entry.AppBootstrapHookInfo;
import com.elderdrivers.riru.edxp.sandhook.entry.SysBootstrapHookInfo; import com.elderdrivers.riru.edxp.sandhook.entry.SysBootstrapHookInfo;
import com.elderdrivers.riru.edxp.sandhook.entry.SysInnerHookInfo; import com.elderdrivers.riru.edxp.sandhook.entry.SysInnerHookInfo;
import com.elderdrivers.riru.edxp.sandhook.entry.WorkAroundHookInfo;
import com.elderdrivers.riru.edxp.sandhook.hooker.SystemMainHooker; import com.elderdrivers.riru.edxp.sandhook.hooker.SystemMainHooker;
import com.elderdrivers.riru.edxp.util.Utils; import com.elderdrivers.riru.edxp.util.Utils;
import com.swift.sandhook.xposedcompat.XposedCompat; import com.swift.sandhook.xposedcompat.XposedCompat;
@ -45,14 +44,6 @@ public class SandHookRouter extends BaseRouter {
} }
} }
public void startWorkAroundHook() {
if (useSandHook) {
XposedCompat.addHookers(XposedBridge.BOOTCLASSLOADER, WorkAroundHookInfo.hookItems);
} else {
super.startWorkAroundHook();
}
}
public void onEnterChildProcess() { public void onEnterChildProcess() {
SandHookXposedBridge.onForkPost(); SandHookXposedBridge.onForkPost();
//enable compile in child process //enable compile in child process

View File

@ -3,11 +3,9 @@ package com.elderdrivers.riru.edxp.sandhook.entry;
import com.elderdrivers.riru.common.KeepMembers; import com.elderdrivers.riru.common.KeepMembers;
import com.elderdrivers.riru.edxp.sandhook.hooker.HandleBindAppHooker; import com.elderdrivers.riru.edxp.sandhook.hooker.HandleBindAppHooker;
import com.elderdrivers.riru.edxp.sandhook.hooker.LoadedApkConstructorHooker; import com.elderdrivers.riru.edxp.sandhook.hooker.LoadedApkConstructorHooker;
import com.elderdrivers.riru.edxp.sandhook.hooker.OnePlusWorkAroundHooker;
public class AppBootstrapHookInfo implements KeepMembers { public class AppBootstrapHookInfo implements KeepMembers {
public static String[] hookItemNames = { public static String[] hookItemNames = {
OnePlusWorkAroundHooker.class.getName(),
HandleBindAppHooker.class.getName(), HandleBindAppHooker.class.getName(),
LoadedApkConstructorHooker.class.getName(), LoadedApkConstructorHooker.class.getName(),
}; };
@ -15,6 +13,5 @@ public class AppBootstrapHookInfo implements KeepMembers {
public static Class[] hookItems = { public static Class[] hookItems = {
HandleBindAppHooker.class, HandleBindAppHooker.class,
LoadedApkConstructorHooker.class, LoadedApkConstructorHooker.class,
OnePlusWorkAroundHooker.class
}; };
} }

View File

@ -3,12 +3,10 @@ package com.elderdrivers.riru.edxp.sandhook.entry;
import com.elderdrivers.riru.common.KeepMembers; import com.elderdrivers.riru.common.KeepMembers;
import com.elderdrivers.riru.edxp.sandhook.hooker.HandleBindAppHooker; import com.elderdrivers.riru.edxp.sandhook.hooker.HandleBindAppHooker;
import com.elderdrivers.riru.edxp.sandhook.hooker.LoadedApkConstructorHooker; 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.SystemMainHooker;
public class SysBootstrapHookInfo implements KeepMembers { public class SysBootstrapHookInfo implements KeepMembers {
public static String[] hookItemNames = { public static String[] hookItemNames = {
OnePlusWorkAroundHooker.class.getName(),
HandleBindAppHooker.class.getName(), HandleBindAppHooker.class.getName(),
SystemMainHooker.class.getName(), SystemMainHooker.class.getName(),
LoadedApkConstructorHooker.class.getName() LoadedApkConstructorHooker.class.getName()
@ -18,6 +16,5 @@ public class SysBootstrapHookInfo implements KeepMembers {
HandleBindAppHooker.class, HandleBindAppHooker.class,
SystemMainHooker.class, SystemMainHooker.class,
LoadedApkConstructorHooker.class, LoadedApkConstructorHooker.class,
OnePlusWorkAroundHooker.class
}; };
} }

View File

@ -1,14 +0,0 @@
package com.elderdrivers.riru.edxp.sandhook.entry;
import com.elderdrivers.riru.common.KeepMembers;
import com.elderdrivers.riru.edxp.sandhook.hooker.OnePlusWorkAroundHooker;
public class WorkAroundHookInfo implements KeepMembers {
public static String[] hookItemNames = {
OnePlusWorkAroundHooker.class.getName()
};
public static Class[] hookItems = {
OnePlusWorkAroundHooker.class
};
}

View File

@ -1,53 +0,0 @@
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;
import de.robv.android.xposed.annotation.ApiSensitive;
import de.robv.android.xposed.annotation.Level;
// TODO check HOS / OOS ver.11 when available
@ApiSensitive(Level.MIDDLE)
@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);
}
}

View File

@ -1,2 +1,2 @@
/build /build
/template_override/system/framework/edxp.jar /template_override/system/framework

View File

@ -22,10 +22,11 @@ android {
} }
} }
ndkVersion androidCompileNdkVersion
} }
dependencies { dependencies {
compileOnly files("${hiddenApiStubJarFilePath}") compileOnly project(':hiddenapi-stubs')
implementation project(':edxp-common') implementation project(':edxp-common')
compileOnly project(':dexmaker') compileOnly project(':dexmaker')
} }
@ -58,6 +59,24 @@ afterEvaluate {
def myTemplatePath = "${projectDir}/template_override/" def myTemplatePath = "${projectDir}/template_override/"
task("copyDex${variantNameCapped}", type: Copy) {
dependsOn "assemble${variantNameCapped}"
dependsOn tasks.getByPath(":edxp-common:copyCommonProperties")
def dexOutPath = "${buildDir}/intermediates/dex/${variantNameLowered}/minify${variantNameCapped}WithR8"
from (dexOutPath){
rename("classes.dex", "edxp.dex")
}
from "${projectDir}/src/main/resources/"
destinationDir file(myTemplatePath + "system/framework/")
doLast {
copy {
from file(myTemplatePath)
into file(templateRootPath)
include "*.dex"
}
}
}
task("makeAndCopy${variantNameCapped}", type: Jar, dependsOn: "assemble${variantNameCapped}") { task("makeAndCopy${variantNameCapped}", type: Jar, dependsOn: "assemble${variantNameCapped}") {
dependsOn tasks.getByPath(":edxp-common:copyCommonProperties") dependsOn tasks.getByPath(":edxp-common:copyCommonProperties")
def dexOutPath = variant.name.contains("release") ? def dexOutPath = variant.name.contains("release") ?

View File

@ -32,6 +32,6 @@
-keep class com.lody.** {*;} -keep class com.lody.** {*;}
-keepclasseswithmember class * { -keepclasseswithmembers class * {
native <methods>; native <methods>;
} }

View File

@ -1,2 +1,2 @@
/build /build
/template_override/system/framework/edxp.jar /template_override/system/framework

View File

@ -22,10 +22,11 @@ android {
} }
} }
ndkVersion androidCompileNdkVersion
} }
dependencies { dependencies {
compileOnly files("${hiddenApiStubJarFilePath}") compileOnly project(':hiddenapi-stubs')
implementation project(':edxp-common') implementation project(':edxp-common')
compileOnly project(':dexmaker') compileOnly project(':dexmaker')
} }
@ -58,6 +59,23 @@ afterEvaluate {
def myTemplatePath = "${projectDir}/template_override/" def myTemplatePath = "${projectDir}/template_override/"
task("copyDex${variantNameCapped}", type: Copy) {
dependsOn "assemble${variantNameCapped}"
dependsOn tasks.getByPath(":edxp-common:copyCommonProperties")
def dexOutPath = "${buildDir}/intermediates/dex/${variantNameLowered}/minify${variantNameCapped}WithR8"
from (dexOutPath){
rename("classes.dex", "edxp.dex")
}
from "${projectDir}/src/main/resources/"
destinationDir file(myTemplatePath + "system/framework/")
doLast {
copy {
from file(myTemplatePath)
into file(templateRootPath)
}
}
}
task("makeAndCopy${variantNameCapped}", type: Jar, dependsOn: "assemble${variantNameCapped}") { task("makeAndCopy${variantNameCapped}", type: Jar, dependsOn: "assemble${variantNameCapped}") {
dependsOn tasks.getByPath(":edxp-common:copyCommonProperties") dependsOn tasks.getByPath(":edxp-common:copyCommonProperties")
def dexOutPath = variant.name.contains("release") ? def dexOutPath = variant.name.contains("release") ?
@ -70,6 +88,7 @@ afterEvaluate {
copy { copy {
from file(myTemplatePath) from file(myTemplatePath)
into file(templateRootPath) into file(templateRootPath)
include "*.dex"
} }
} }
outputs.upToDateWhen { false } outputs.upToDateWhen { false }

View File

@ -30,6 +30,6 @@
-keep class * implements com.elderdrivers.riru.common.KeepAll { *; } -keep class * implements com.elderdrivers.riru.common.KeepAll { *; }
-keepclassmembers class * implements com.elderdrivers.riru.common.KeepMembers { *; } -keepclassmembers class * implements com.elderdrivers.riru.common.KeepMembers { *; }
-keepclasseswithmember class * { -keepclasseswithmembers class * {
native <methods>; native <methods>;
} }

View File

@ -8,7 +8,6 @@ import com.elderdrivers.riru.edxp.core.Main;
import com.elderdrivers.riru.edxp.core.Proxy; import com.elderdrivers.riru.edxp.core.Proxy;
import com.elderdrivers.riru.edxp.core.Yahfa; import com.elderdrivers.riru.edxp.core.Yahfa;
import com.elderdrivers.riru.edxp.core.yahfa.HookMethodResolver; 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.NormalProxy;
import com.elderdrivers.riru.edxp.proxy.Router; import com.elderdrivers.riru.edxp.proxy.Router;
@ -35,11 +34,6 @@ public class YahfaEdxpImpl extends BaseEdxpImpl {
setInitialized(); setInitialized();
} }
@Override
protected Proxy createBlackWhiteListProxy() {
return new BlackWhiteListProxy(getRouter());
}
@Override @Override
protected Proxy createNormalProxy() { protected Proxy createNormalProxy() {
return new NormalProxy(getRouter()); return new NormalProxy(getRouter());

View File

@ -1,3 +1,2 @@
android.enableR8=false androidCompileSdkVersion=30
androidCompileNdkVersion=22.0.6917172 rc1
androidCompileSdkVersion=30

View File

@ -1,6 +1,6 @@
#Sat Apr 20 12:28:06 CST 2019 #Fri Nov 13 15:00:57 CST 2020
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-5.1.1-all.zip distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-all.zip

View File

@ -7,8 +7,9 @@ android {
} }
task makeStubJar(type: Jar){ task makeStubJar(type: Jar){
dependsOn assemble
baseName 'framework-stub' baseName 'framework-stub'
from("${projectDir}/build/intermediates/javac/release/compileReleaseJavaWithJavac/classes/") from("${projectDir}/build/intermediates/javac/release/classes/")
into('') into('')
destinationDir file("${projectDir}/libs") destinationDir file("${projectDir}/libs")
exclude('BuildConfig.class', 'R.class') exclude('BuildConfig.class', 'R.class')

View File

@ -2,7 +2,6 @@ apply plugin: 'com.android.library'
android { android {
compileSdkVersion androidCompileSdkVersion.toInteger() compileSdkVersion androidCompileSdkVersion.toInteger()
buildToolsVersion '28.0.3'
defaultConfig { defaultConfig {
minSdkVersion 26 minSdkVersion 26

View File

@ -21,4 +21,6 @@ public interface EdxpConfig {
boolean isResourcesHookEnabled(); boolean isResourcesHookEnabled();
boolean isBlackWhiteListMode(); boolean isBlackWhiteListMode();
String getModulesList();
} }

View File

@ -17,10 +17,12 @@ import com.android.internal.os.ZygoteInit;
import com.elderdrivers.riru.edxp.config.EdXpConfigGlobal; import com.elderdrivers.riru.edxp.config.EdXpConfigGlobal;
import java.io.BufferedReader; import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.io.StringBufferInputStream;
import java.lang.ref.WeakReference; import java.lang.ref.WeakReference;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.ArrayList; import java.util.ArrayList;
@ -307,38 +309,21 @@ public final class XposedInit {
private static final Object moduleLoadLock = new Object(); private static final Object moduleLoadLock = new Object();
// @GuardedBy("moduleLoadLock") // @GuardedBy("moduleLoadLock")
private static final ArraySet<String> loadedModules = new ArraySet<>(); private static final ArraySet<String> loadedModules = new ArraySet<>();
// @GuardedBy("moduleLoadLock")
private static long lastModuleListModifiedTime = -1;
public static boolean loadModules(boolean isInZygote, boolean callInitZygote) throws IOException { public static boolean loadModules(boolean callInitZygote) throws IOException {
boolean hasLoaded = !modulesLoaded.compareAndSet(false, true); boolean hasLoaded = !modulesLoaded.compareAndSet(false, true);
if (hasLoaded && !EdXpConfigGlobal.getConfig().isDynamicModulesMode()) { if (hasLoaded && !EdXpConfigGlobal.getConfig().isDynamicModulesMode()) {
return false; return false;
} }
synchronized (moduleLoadLock) { synchronized (moduleLoadLock) {
final String filename = EdXpConfigGlobal.getConfig().getInstallerConfigPath("modules.list");
BaseService service = SELinuxHelper.getAppDataFileService();
if (!service.checkFileExists(filename)) {
Log.e(TAG, "Cannot load any modules because " + filename + " was not found");
// FIXME module list is cleared but never could be reload again
// when using dynamic-module-list under multi-user environment
clearAllCallbacks();
return false;
}
long moduleListModifiedTime = service.getFileModificationTime(filename);
if (lastModuleListModifiedTime == moduleListModifiedTime) {
// module list has not changed
return false;
}
ClassLoader topClassLoader = XposedBridge.BOOTCLASSLOADER; ClassLoader topClassLoader = XposedBridge.BOOTCLASSLOADER;
ClassLoader parent; ClassLoader parent;
while ((parent = topClassLoader.getParent()) != null) { while ((parent = topClassLoader.getParent()) != null) {
topClassLoader = parent; topClassLoader = parent;
} }
InputStream stream = service.getFileInputStream(filename); String moduleList = EdXpConfigGlobal.getConfig().getModulesList();
InputStream stream = new ByteArrayInputStream(moduleList.getBytes());
BufferedReader apks = new BufferedReader(new InputStreamReader(stream)); BufferedReader apks = new BufferedReader(new InputStreamReader(stream));
ArraySet<String> newLoadedApk = new ArraySet<>(); ArraySet<String> newLoadedApk = new ArraySet<>();
String apk; String apk;
@ -358,9 +343,6 @@ public final class XposedInit {
// refresh callback according to current loaded module list // refresh callback according to current loaded module list
pruneCallbacks(loadedModules); pruneCallbacks(loadedModules);
lastModuleListModifiedTime = moduleListModifiedTime;
} }
return true; return true;
} }