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()
}
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
// in the individual module build.gradle files

1
dalvikdx/.gitignore vendored
View File

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

View File

@ -23,21 +23,31 @@ task findDx {
}
}
task dexInJar(type: Jar) {
task makeDex(type: Exec) {
dependsOn jar
dependsOn findDx
doFirst {
exec {
def dexName = "classes.dex"
workingDir jar.destinationDir
if (OperatingSystem.current().isWindows()) {
executable "dx.bat"
args "--dex", "--output", "classes.dex", "${jar.archiveName}"
args "--dex", "--output", dexName, "${jar.archiveName}"
} else {
executable "bash"
args rootProject.ext.dxPath.trim(), "--dex", "--output", "classes.dex", "${jar.archiveName}"
args rootProject.ext.dxPath.trim(), "--dex", "--output", dexName, "${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"
destinationDir jar.destinationDir
baseName "eddalvikdx"

1
dexmaker/.gitignore vendored
View File

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

View File

@ -14,20 +14,30 @@ dependencies {
compileOnly project(':dalvikdx')
}
task dexInJar(type: Jar) {
task makeDex(type: Exec) {
dependsOn jar
doFirst {
exec {
def dexName = "classes.dex"
workingDir jar.destinationDir
if (OperatingSystem.current().isWindows()) {
executable "dx.bat"
args "--dex", "--output", "classes.dex", "${jar.archiveName}"
args "--dex", "--output", dexName, "${jar.archiveName}"
} else {
executable "bash"
args rootProject.ext.dxPath.trim(), "--dex", "--output", "classes.dex", "${jar.archiveName}"
args rootProject.ext.dxPath.trim(), "--dex", "--output", dexName, "${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"
destinationDir jar.destinationDir
baseName "eddexmaker"

View File

@ -17,13 +17,14 @@ android {
}
}
ndkVersion androidCompileNdkVersion
}
dependencies {
compileOnly project(':hiddenapi-stubs')
api project(':xposed-bridge')
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() {
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 boolean isAppNeedHook(String appDataDir);
public static native String getModulesList();
}

View File

@ -1,14 +1,12 @@
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.Router;
public abstract class BaseEdxpImpl implements EdxpImpl {
protected Proxy mBlackWhiteListProxy;
protected Proxy mNormalProxy;
protected Router mRouter;
@ -23,15 +21,6 @@ public abstract class BaseEdxpImpl implements EdxpImpl {
return mInitialized;
}
@NonNull
@Override
public Proxy getBlackWhiteListProxy() {
if (mBlackWhiteListProxy == null) {
mBlackWhiteListProxy = createBlackWhiteListProxy();
}
return mBlackWhiteListProxy;
}
@NonNull
@Override
public Proxy getNormalProxy() {
@ -50,10 +39,6 @@ public abstract class BaseEdxpImpl implements EdxpImpl {
return mRouter;
}
protected Proxy createBlackWhiteListProxy() {
return new BlackWhiteListProxy(getRouter());
}
protected Proxy createNormalProxy() {
return new NormalProxy(getRouter());
}

View File

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

View File

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

View File

@ -3,12 +3,10 @@ package com.elderdrivers.riru.edxp.entry.yahfa;
import com.elderdrivers.riru.common.KeepMembers;
import com.elderdrivers.riru.edxp._hooker.yahfa.HandleBindAppHooker;
import com.elderdrivers.riru.edxp._hooker.yahfa.LoadedApkConstructorHooker;
import com.elderdrivers.riru.edxp._hooker.yahfa.OnePlusWorkAroundHooker;
public class AppBootstrapHookInfo implements KeepMembers {
public static String[] hookItemNames = {
HandleBindAppHooker.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.edxp._hooker.yahfa.HandleBindAppHooker;
import com.elderdrivers.riru.edxp._hooker.yahfa.LoadedApkConstructorHooker;
import com.elderdrivers.riru.edxp._hooker.yahfa.OnePlusWorkAroundHooker;
import com.elderdrivers.riru.edxp._hooker.yahfa.SystemMainHooker;
public class SysBootstrapHookInfo implements KeepMembers {
@ -11,6 +10,5 @@ public class SysBootstrapHookInfo implements KeepMembers {
HandleBindAppHooker.class.getName(),
SystemMainHooker.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.LoadedApkCstr;
import com.elderdrivers.riru.edxp._hooker.impl.OneplusWorkaround;
import com.elderdrivers.riru.edxp._hooker.impl.StartBootstrapServices;
import com.elderdrivers.riru.edxp._hooker.impl.SystemMain;
import com.elderdrivers.riru.edxp._hooker.yahfa.HandleBindAppHooker;
import com.elderdrivers.riru.edxp._hooker.yahfa.LoadedApkConstructorHooker;
import com.elderdrivers.riru.edxp._hooker.yahfa.OnePlusWorkAroundHooker;
import com.elderdrivers.riru.edxp._hooker.yahfa.StartBootstrapServicesHooker;
import com.elderdrivers.riru.edxp._hooker.yahfa.SystemMainHooker;
import com.elderdrivers.riru.edxp.core.yahfa.HookMain;
import com.elderdrivers.riru.edxp.entry.yahfa.AppBootstrapHookInfo;
import com.elderdrivers.riru.edxp.entry.yahfa.SysBootstrapHookInfo;
import com.elderdrivers.riru.edxp.entry.yahfa.SysInnerHookInfo;
import com.elderdrivers.riru.edxp.entry.yahfa.WorkAroundHookInfo;
import com.elderdrivers.riru.edxp.util.Utils;
import com.elderdrivers.riru.edxp.util.Versions;
@ -33,14 +30,11 @@ import de.robv.android.xposed.annotation.Level;
public abstract class BaseRouter implements Router {
protected volatile boolean forkCompleted = false;
protected volatile AtomicBoolean bootstrapHooked = new AtomicBoolean(false);
protected static boolean useXposedApi = false;
public void initResourcesHook() {
startWorkAroundHook(); // for OnePlus devices
XposedBridge.initXResources();
}
@ -49,18 +43,6 @@ public abstract class BaseRouter implements Router {
XposedInit.startsSystemServer = isSystem;
}
public void onForkStart() {
forkCompleted = false;
}
public void onForkFinish() {
forkCompleted = true;
}
public boolean isForkCompleted() {
return forkCompleted;
}
public void installBootstrapHooks(boolean isSystem) {
// Initialize the Xposed framework
try {
@ -75,10 +57,9 @@ public abstract class BaseRouter implements Router {
}
}
public void loadModulesSafely(boolean isInZygote, boolean callInitZygote) {
public void loadModulesSafely(boolean callInitZygote) {
try {
// FIXME some coredomain app can't reading modules.list
XposedInit.loadModules(isInZygote, callInitZygote);
XposedInit.loadModules(callInitZygote);
} catch (Exception exception) {
Utils.logE("error loading module list", exception);
}
@ -145,22 +126,4 @@ public abstract class BaseRouter implements Router {
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,
boolean startChildZygote, String instructionSet,
String appDataDir) {
// mainly for secondary zygote
mRouter.onForkStart();
}
public void forkAndSpecializePost(int pid, String appDataDir, String niceName) {
SELinuxHelper.initOnce();
mRouter.initResourcesHook();
// 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
// install bootstrap hooks for secondary zygote
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
forkPostCommon(pid, false, appDataDir, niceName);
}
public void forkSystemServerPre(int uid, int gid, int[] gids, int debugFlags, int[][] rlimits,
long permittedCapabilities, long effectiveCapabilities) {
mRouter.onForkStart();
}
public void forkSystemServerPost(int pid) {
SELinuxHelper.initOnce();
mRouter.initResourcesHook();
// 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
// for instance com.android.phone
mRouter.installBootstrapHooks(true);
// loadModules have to be executed in zygote even isDynamicModules is false
// because if not global hooks installed in initZygote might not be
// propagated to processes not forked via forkAndSpecialize
mRouter.loadModulesSafely(true, true);
}
public void forkSystemServerPost(int pid) {
// in system_server process
forkPostCommon(pid, true,
getDataPathPrefix() + "android", "system_server");
@ -66,13 +57,7 @@ public class NormalProxy extends BaseProxy {
ConfigManager.niceName = niceName;
mRouter.prepare(isSystem);
mRouter.onEnterChildProcess();
// reload module list if dynamic mode is on
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();
mRouter.loadModulesSafely(true);
}
}

View File

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

View File

@ -21,7 +21,7 @@ import de.robv.android.xposed.annotation.Level;
@ApiSensitive(Level.LOW)
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) {
if (appClassLoader == null) {

View File

@ -7,3 +7,4 @@
/template_override/system
/template_override/system_x86
*.iml
/.cxx

View File

@ -70,8 +70,8 @@ android {
release {
externalNativeBuild {
cmake {
cppFlags "-fvisibility=hidden -fvisibility-inlines-hidden -O2 -s -Wno-unused-value"
cFlags "-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 -fomit-frame-pointer"
}
}
minifyEnabled true
@ -83,6 +83,35 @@ android {
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 {
@ -132,8 +161,8 @@ afterEvaluate {
def magiskModuleId = property("${backendLowered}" + "_module_id")
def prepareJarsTask = task("prepareJars${backendCapped}${variantCapped}") {
dependsOn cleanTemplate, copyDalvikdxJar, copyDexmakerJar
dependsOn tasks.getByPath(":edxp-${backendLowered}:makeAndCopy${variantCapped}")
dependsOn cleanTemplate, copyDalvikdxDex, copyDexmakerDex
dependsOn tasks.getByPath(":edxp-${backendLowered}:copyDex${variantCapped}")
}
def prepareMagiskFilesTask = task("prepareMagiskFiles${backendCapped}${variantCapped}", type: Delete) {
@ -220,7 +249,28 @@ afterEvaluate {
workingDir "${projectDir}/release"
def commands = ["adb", "push",
"${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) {
commandLine 'cmd', '/c', commands.join(" ")
} else {

View File

@ -4,7 +4,7 @@
#include <art/base/macros.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) {
if (env->ExceptionCheck()) {
@ -126,8 +126,29 @@ public:
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:
JNIEnv *env_;
jstring jstr_;
const char *cstr_;
JUTFString(const JUTFString &) = delete;
JUTFString &operator=(const JUTFString &) = delete;
};

View File

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

View File

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

View File

@ -17,7 +17,7 @@
#define LOGW(...)
#define LOGE(...)
#else
#ifndef NDEBUG
#if 1
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
#else
#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 <logging.h>
#include <linux/limits.h>
#include <JNIHelper.h>
#include <climits>
#include <fstream>
#include "art/runtime/native/native_util.h"
#include "config_manager.h"
using namespace std;
using namespace art;
namespace edxp {
namespace fs = std::filesystem;
std::string ConfigManager::RetrieveInstallerPkgName() const {
std::string data_test_path = data_path_prefix_ + kPrimaryInstallerPkgName;
if (access(data_test_path.c_str(), F_OK) == 0) {
LOGI("using installer %s", kPrimaryInstallerPkgName);
std::string data_test_path = data_path_prefix_ / kPrimaryInstallerPkgName;
if (fs::exists(data_test_path)) {
LOGI("using installer %s", kPrimaryInstallerPkgName.c_str());
return kPrimaryInstallerPkgName;
}
data_test_path = data_path_prefix_ + kLegacyInstallerPkgName;
if (access(data_test_path.c_str(), F_OK) == 0) {
LOGI("using installer %s", kLegacyInstallerPkgName);
data_test_path = data_path_prefix_ / kLegacyInstallerPkgName;
if (fs::exists(data_test_path)) {
LOGI("using installer %s", kLegacyInstallerPkgName.c_str());
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;
}
void ConfigManager::SnapshotBlackWhiteList() {
DIR *dir;
struct dirent *dent;
dir = opendir(whitelist_path_.c_str());
if (dir != nullptr) {
while ((dent = readdir(dir)) != nullptr) {
if (dent->d_type == DT_REG) {
const char *fileName = dent->d_name;
LOGI(" whitelist: %s", fileName);
white_list_default_.emplace_back(fileName);
white_list_default_.clear();
for (auto &item: fs::directory_iterator(whitelist_path_)) {
if (item.is_regular_file()) {
const auto &file_name = item.path().filename();
LOGI(" whitelist: %s", file_name.c_str());
white_list_default_.emplace(file_name);
}
}
closedir(dir);
black_list_default_.clear();
for (auto &item: fs::directory_iterator(blacklist_path_)) {
if (item.is_regular_file()) {
const auto &file_name = item.path().filename();
LOGI(" blacklist: %s", file_name.c_str());
black_list_default_.emplace(file_name);
}
dir = opendir(blacklist_path_.c_str());
if (dir != nullptr) {
while ((dent = readdir(dir)) != nullptr) {
if (dent->d_type == DT_REG) {
const char *fileName = dent->d_name;
LOGI(" blacklist: %s", fileName);
black_list_default_.emplace_back(fileName);
}
}
closedir(dir);
}
}
@ -72,10 +63,8 @@ namespace edxp {
last_user_ = user;
}
const char *format = use_prot_storage_ ? "/data/user_de/%u/" : "/data/user/%u/";
char buff[PATH_MAX];
snprintf(buff, sizeof(buff), format, last_user_);
data_path_prefix_ = buff;
data_path_prefix_ = use_prot_storage_ ? "/data/user_de" : "/data/user";
data_path_prefix_ /= std::to_string(last_user_);
installer_pkg_name_ = RetrieveInstallerPkgName();
base_config_path_ = GetConfigPath("");
@ -83,15 +72,16 @@ namespace edxp {
whitelist_path_ = GetConfigPath("whitelist/");
use_whitelist_path_ = GetConfigPath("usewhitelist");
dynamic_modules_enabled_ = access(GetConfigPath("dynamicmodules").c_str(), F_OK) == 0;
black_white_list_enabled_ = access(GetConfigPath("blackwhitelist").c_str(), F_OK) == 0;
deopt_boot_image_enabled_ = access(GetConfigPath("deoptbootimage").c_str(), F_OK) == 0;
resources_hook_enabled_ = access(GetConfigPath("enable_resources").c_str(), F_OK) == 0;
no_module_log_enabled_ = access(GetConfigPath("disable_modules_log").c_str(), F_OK) == 0;
hidden_api_bypass_enabled_ = access(GetConfigPath("disable_hidden_api_bypass").c_str(), F_OK) != 0;
dynamic_modules_enabled_ = fs::exists(GetConfigPath("dynamicmodules"));
black_white_list_enabled_ = fs::exists(GetConfigPath("blackwhitelist"));
deopt_boot_image_enabled_ = fs::exists(GetConfigPath("deoptbootimage"));
resources_hook_enabled_ = fs::exists(GetConfigPath("enable_resources"));
no_module_log_enabled_ = fs::exists(GetConfigPath("disable_modules_log"));
hidden_api_bypass_enabled_ =
!fs::exists(GetConfigPath("disable_hidden_api_bypass"));
// 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(" application list mode: %s", BoolToString(black_white_list_enabled_));
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
bool ConfigManager::IsAppNeedHook(const std::string &app_data_dir) {
// 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.
uid_t user = 0;
char package_name[PATH_MAX];
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
}
}
const auto[res, user, package_name] = GetAppInfoFromDir(app_data_dir);
if (!res) return true;
if (last_user_ != user) {
UpdateConfigPath(user);
@ -126,17 +129,17 @@ namespace edxp {
if (!black_white_list_enabled_) {
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;
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 {
LOGE("can't access config path, using snapshot use_white_list: %s",
app_data_dir.c_str());
use_white_list = use_white_list_snapshot_;
}
if (strcmp(package_name, kPrimaryInstallerPkgName) == 0
|| strcmp(package_name, kLegacyInstallerPkgName) == 0) {
if (package_name == kPrimaryInstallerPkgName
|| package_name == kLegacyInstallerPkgName) {
// always hook installer apps
return true;
}
@ -144,80 +147,55 @@ namespace edxp {
if (!can_access_app_data) {
LOGE("can't access config path, using snapshot white list: %s",
app_data_dir.c_str());
return !(find(white_list_default_.begin(), white_list_default_.end(),
package_name) ==
white_list_default_.end());
return white_list_default_.count(package_name);
}
std::string target_path = whitelist_path_ + package_name;
bool res = access(target_path.c_str(), F_OK) == 0;
std::string target_path = whitelist_path_ / package_name;
bool res = fs::exists(target_path);
LOGD("using whitelist, %s -> %d", app_data_dir.c_str(), res);
return res;
} else {
if (!can_access_app_data) {
LOGE("can't access config path, using snapshot black list: %s",
app_data_dir.c_str());
return find(black_list_default_.begin(), black_list_default_.end(), package_name) ==
black_list_default_.end();
return black_list_default_.count(package_name);
}
std::string target_path = blacklist_path_ + package_name;
bool res = access(target_path.c_str(), F_OK) != 0;
std::string target_path = blacklist_path_ / package_name;
bool res = !fs::exists(target_path);
LOGD("using blacklist, %s -> %d", app_data_dir.c_str(), 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() {
use_prot_storage_ = GetAndroidApiLevel() >= __ANDROID_API_N__;
last_user_ = 0;
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 <string>
#include <JNIHelper.h>
#include "JNIHelper.h"
#include <utility>
#include <art/runtime/native/native_util.h>
#include <filesystem>
#include <unordered_set>
namespace edxp {
static constexpr const char *kPrimaryInstallerPkgName = "org.meowcat.edxposed.manager";
static constexpr const char *kLegacyInstallerPkgName = "de.robv.android.xposed.installer";
static constexpr auto kXposedPropPath = "/system/framework/edconfig.jar";
static const std::string kPrimaryInstallerPkgName = "org.meowcat.edxposed.manager";
static const std::string kLegacyInstallerPkgName = "de.robv.android.xposed.installer";
static const std::string kXposedPropPath = "/system/framework/edconfig.jar";
class ConfigManager {
public:
static ConfigManager *GetInstance() {
if (instance_ == 0) {
instance_ = new ConfigManager();
inline static ConfigManager *GetInstance() {
if (!instance_) {
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 hidden_api_bypass_enabled_ = false;
bool UpdateModuleList();
static std::tuple<bool, uid_t, std::string>
GetAppInfoFromDir(const std::string &app_data_dir);
private:
inline static ConfigManager *instance_;
inline static std::unique_ptr<ConfigManager> instance_ = nullptr;
uid_t last_user_ = false;
bool use_prot_storage_ = true;
std::string data_path_prefix_;
std::string installer_pkg_name_;
std::string base_config_path_;
std::string blacklist_path_;
std::string whitelist_path_;
std::string use_whitelist_path_;
std::filesystem::path data_path_prefix_;
std::filesystem::path installer_pkg_name_;
std::filesystem::path base_config_path_;
std::filesystem::path blacklist_path_;
std::filesystem::path whitelist_path_;
std::filesystem::path use_whitelist_path_;
bool black_white_list_enabled_ = false;
bool dynamic_modules_enabled_ = false;
bool deopt_boot_image_enabled_ = false;
@ -66,8 +81,13 @@ namespace edxp {
bool resources_hook_enabled_ = false;
// snapshot at boot
bool use_white_list_snapshot_ = false;
std::vector<std::string> white_list_default_;
std::vector<std::string> black_list_default_;
std::unordered_set<std::string> white_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();
@ -76,6 +96,8 @@ namespace edxp {
void SnapshotBlackWhiteList();
std::string RetrieveInstallerPkgName() const;
friend std::unique_ptr<ConfigManager> std::make_unique<ConfigManager>();
};
} // namespace edxp

View File

@ -14,6 +14,8 @@
#include <android-base/strings.h>
#include <nativehelper/scoped_local_ref.h>
#include <jni/edxp_pending_hooks.h>
#include <fstream>
#include <sstream>
#include "edxp_context.h"
#include "config_manager.h"
@ -52,7 +54,28 @@ namespace edxp {
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_)) {
return;
}
@ -62,21 +85,34 @@ namespace edxp {
env, classloader, "getSystemClassLoader", "()Ljava/lang/ClassLoader;");
jobject sys_classloader = JNI_CallStaticObjectMethod(env, classloader, getsyscl_mid);
if (UNLIKELY(!sys_classloader)) {
LOG(ERROR) << "getSystemClassLoader failed!!!";
LOGE("getSystemClassLoader failed!!!");
return;
}
jclass path_classloader = JNI_FindClass(env, "dalvik/system/PathClassLoader");
jmethodID initMid = JNI_GetMethodID(env, path_classloader, "<init>",
"(Ljava/lang/String;Ljava/lang/String;Ljava/lang/ClassLoader;)V");
jobject my_cl = JNI_NewObject(env, path_classloader, initMid, env->NewStringUTF(dex_path),
nullptr, sys_classloader);
jclass in_memory_classloader = JNI_FindClass(env, "dalvik/system/InMemoryDexClassLoader");
jmethodID initMid = JNI_GetMethodID(env, in_memory_classloader, "<init>",
"([Ljava/nio/ByteBuffer;Ljava/lang/ClassLoader;)V");
jclass byte_buffer_class = JNI_FindClass(env, "java/nio/ByteBuffer");
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(sys_classloader);
env->DeleteLocalRef(path_classloader);
env->DeleteLocalRef(in_memory_classloader);
env->DeleteLocalRef(byte_buffer_class);
if (UNLIKELY(my_cl == nullptr)) {
LOG(ERROR) << "PathClassLoader creation failed!!!";
LOGE("InMemoryDexClassLoader creation failed!!!");
return;
}
@ -140,7 +176,7 @@ namespace edxp {
}
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);
jmethodID mid = JNI_GetMethodID(env, clz, "loadClass",
"(Ljava/lang/String;)Ljava/lang/Class;");
@ -155,57 +191,17 @@ namespace edxp {
return (jclass) target;
}
} 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;
}
jclass Context::FindClassFromLoader(JNIEnv *env, const char *className) const {
return FindClassFromLoader(env, GetCurrentClassLoader(), className);
}
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,
const char *method_sig, ...) const {
if (UNLIKELY(!entry_class_)) {
@ -224,16 +220,15 @@ namespace edxp {
}
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,
jint runtime_flags, jobjectArray rlimits,
jlong permitted_capabilities,
jlong effective_capabilities) {
app_data_dir_ = env->NewStringUTF(SYSTEM_SERVER_DATA_DIR);
PrepareJavaEnv(env);
// jump to java code
FindAndCall(env, "forkSystemServerPre", "(II[II[[IJJ)V", uid, gid, gids, runtime_flags,
rlimits, permitted_capabilities, effective_capabilities);
app_data_dir_ = env->NewStringUTF(SYSTEM_SERVER_DATA_DIR.c_str());
ConfigManager::GetInstance()->UpdateModuleList();
PreLoadDex(env, kInjectDexPath);
}
@ -249,15 +244,13 @@ namespace edxp {
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) {
const auto app_id = uid % PER_USER_RANGE;
const JUTFString package_name(env, nice_name, "UNKNOWN");
bool skip = false;
bool release = true;
if (is_child_zygote) {
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());
}
@ -265,7 +258,6 @@ namespace edxp {
(app_id >= FIRST_APP_ZYGOTE_ISOLATED_UID && app_id <= LAST_APP_ZYGOTE_ISOLATED_UID) ||
app_id == SHARED_RELRO_UID) {
skip = true;
release = false; // In Android R, calling XposedBridge.clearAllCallbacks cause crashes.
LOGW("skip injecting into %s because it's isolated", package_name.get());
}
@ -275,7 +267,7 @@ namespace edxp {
LOGW("skip injecting xposed into %s because it's whitelisted/blacklisted",
package_name.get());
}
return {skip, release};
return skip;
}
void Context::OnNativeForkAndSpecializePre(JNIEnv *env, jclass clazz,
@ -291,32 +283,29 @@ namespace edxp {
jboolean is_child_zygote,
jstring instruction_set,
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;
nice_name_ = nice_name;
PrepareJavaEnv(env);
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);
}
PreLoadDex(env, kInjectDexPath);
}
int Context::OnNativeForkAndSpecializePost(JNIEnv *env, jclass clazz, jint res) {
int
Context::OnNativeForkAndSpecializePost(JNIEnv *env, [[maybe_unused]]jclass clazz, jint res) {
if (res == 0) {
const JUTFString package_name(env, nice_name_);
const JUTFString process_name(env, nice_name_);
if (!skip_) {
PrepareJavaEnv(env);
LOGD("Done prepare");
FindAndCall(env, "forkAndSpecializePost",
"(ILjava/lang/String;Ljava/lang/String;)V",
res, app_data_dir_, nice_name_);
LOGD("injected xposed into %s", package_name.get());
LOGD("injected xposed into %s", process_name.get());
} else {
if(release_)
ReleaseJavaEnv(env);
LOGD("skipped %s", package_name.get());
auto config_manager = ConfigManager::ReleaseInstance();
auto context = Context::ReleaseInstance();
LOGD("skipped %s", process_name.get());
}
} else {
// in zygote process, res is child zygote pid

View File

@ -1,13 +1,15 @@
#pragma once
#include <utility>
#include <unistd.h>
#include <mutex>
#include <vector>
#include <string>
#include <string_view>
#include "utils.h"
namespace edxp {
#define SYSTEM_SERVER_DATA_DIR "/data/user/0/android"
static const auto SYSTEM_SERVER_DATA_DIR = "/data/user/0/android"_str;
enum Variant {
NONE = 0,
YAHFA = 1,
@ -18,11 +20,15 @@ namespace edxp {
class Context {
public:
inline static auto GetInstance() {
if (instance_ == nullptr) {
instance_ = new Context();
inline static Context *GetInstance() {
if (!instance_) {
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_; }
@ -45,7 +51,13 @@ namespace edxp {
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,
jintArray gids, jint runtime_flags, jobjectArray rlimits,
@ -68,7 +80,7 @@ namespace edxp {
inline auto GetVariant() const { return variant_; };
private:
inline static Context *instance_;
inline static std::unique_ptr<Context> instance_;
bool initialized_ = false;
Variant variant_ = NONE;
jobject inject_class_loader_ = nullptr;
@ -80,22 +92,29 @@ namespace edxp {
jmethodID pre_fixup_static_mid_ = nullptr;
jmethodID post_fixup_static_mid_ = nullptr;
bool skip_ = false;
bool release_ = true;
std::vector<std::vector<signed char>> dexes;
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);
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);
void ReleaseJavaEnv(JNIEnv *env);
friend std::unique_ptr<Context> std::make_unique<Context>();
};
}

View File

@ -61,6 +61,16 @@ namespace edxp {
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[] = {
NATIVE_METHOD(ConfigManager, isBlackWhiteListEnabled, "()Z"),
NATIVE_METHOD(ConfigManager, isDynamicModulesEnabled, "()Z"),
@ -72,8 +82,10 @@ namespace edxp {
NATIVE_METHOD(ConfigManager, getLibSandHookName, "()Ljava/lang/String;"),
NATIVE_METHOD(ConfigManager, getLibWhaleName, "()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, getModulesList, "()Ljava/lang/String;"),
};
void RegisterConfigManagerMethods(JNIEnv *env) {

View File

@ -36,18 +36,18 @@ PROP_PRODUCT=$(getprop ro.build.product)
PROP_BRAND=$(getprop ro.product.brand)
PROP_MANUFACTURER=$(getprop ro.product.manufacturer)
JAR_EDXP="$(getRandomNameExist 8 "" ".jar" "
JAR_EDXP="$(getRandomNameExist 8 "" ".dex" "
/system/framework
").jar"
JAR_EDDALVIKDX="$(getRandomNameExist 8 "" ".jar" "
").dex"
JAR_EDDALVIKDX="$(getRandomNameExist 8 "" ".dex" "
/system/framework
").jar"
JAR_EDDEXMAKER="$(getRandomNameExist 8 "" ".jar" "
").dex"
JAR_EDDEXMAKER="$(getRandomNameExist 8 "" ".dex" "
/system/framework
").jar"
JAR_EDCONFIG="$(getRandomNameExist 8 "" ".jar" "
/system/framework
").jar"
").dex"
#JAR_EDCONFIG="$(getRandomNameExist 8 "" ".jar" "
#/system/framework
#").jar"
LIB_RIRU_EDXP="libriru_${RIRU_EDXP}.so"
LIB_WHALE_EDXP="lib$(getRandomNameExist 10 "lib" ".so" "
/system/lib
@ -267,10 +267,10 @@ fi
ui_print "- Copying framework libraries"
mv "${MODPATH}/system/framework/eddalvikdx.jar" "${MODPATH}/system/framework/${JAR_EDDALVIKDX}"
mv "${MODPATH}/system/framework/edxp.jar" "${MODPATH}/system/framework/${JAR_EDXP}"
mv "${MODPATH}/system/framework/eddexmaker.jar" "${MODPATH}/system/framework/${JAR_EDDEXMAKER}"
mv "${MODPATH}/system/framework/edconfig.jar" "${MODPATH}/system/framework/${JAR_EDCONFIG}"
mv "${MODPATH}/system/framework/eddalvikdx.dex" "${MODPATH}/system/framework/${JAR_EDDALVIKDX}"
mv "${MODPATH}/system/framework/edxp.dex" "${MODPATH}/system/framework/${JAR_EDXP}"
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/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/libsandhook-native.so" "${MODPATH}/system/lib/libsandhook-native.so"
@ -290,15 +290,15 @@ fi
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/edconfig.jar:/system/framework/'"${JAR_EDCONFIG}"':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: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:libsandhook.edxp.so:'"${LIB_SANDHOOK_EDXP}"':g' "${MODPATH}/system/lib/${LIB_RIRU_EDXP}"
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/edconfig.jar:/system/framework/'"${JAR_EDCONFIG}"':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: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:libsandhook.edxp.so:'"${LIB_SANDHOOK_EDXP}"':g' "${MODPATH}/system/lib64/${LIB_RIRU_EDXP}"

View File

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

View File

@ -22,10 +22,11 @@ android {
}
}
ndkVersion androidCompileNdkVersion
}
dependencies {
compileOnly files("${hiddenApiStubJarFilePath}")
compileOnly project(':hiddenapi-stubs')
implementation project(':edxp-common')
implementation 'com.swift.sandhook:hooklib:4.2.1'
compileOnly project(':dexmaker')
@ -59,20 +60,39 @@ afterEvaluate {
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")
def dexOutPath = variant.name.contains("release") ?
"${buildDir}/intermediates/transforms/dexMerger/${variantNameLowered}/0/" :
"${buildDir}/intermediates/dex/${variantNameLowered}/mergeDex${variantNameCapped}/out/"
from dexOutPath, "${projectDir}/src/main/resources/"
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/")
baseName "edxp"
doLast {
copy {
from file(myTemplatePath)
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 }
}
}

View File

@ -32,6 +32,6 @@
-keep class com.swift.sandhook.** {*;}
-keepclasseswithmember class * {
-keepclasseswithmembers class * {
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.SysBootstrapHookInfo;
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.util.Utils;
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() {
SandHookXposedBridge.onForkPost();
//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.edxp.sandhook.hooker.HandleBindAppHooker;
import com.elderdrivers.riru.edxp.sandhook.hooker.LoadedApkConstructorHooker;
import com.elderdrivers.riru.edxp.sandhook.hooker.OnePlusWorkAroundHooker;
public class AppBootstrapHookInfo implements KeepMembers {
public static String[] hookItemNames = {
OnePlusWorkAroundHooker.class.getName(),
HandleBindAppHooker.class.getName(),
LoadedApkConstructorHooker.class.getName(),
};
@ -15,6 +13,5 @@ public class AppBootstrapHookInfo implements KeepMembers {
public static Class[] hookItems = {
HandleBindAppHooker.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.edxp.sandhook.hooker.HandleBindAppHooker;
import com.elderdrivers.riru.edxp.sandhook.hooker.LoadedApkConstructorHooker;
import com.elderdrivers.riru.edxp.sandhook.hooker.OnePlusWorkAroundHooker;
import com.elderdrivers.riru.edxp.sandhook.hooker.SystemMainHooker;
public class SysBootstrapHookInfo implements KeepMembers {
public static String[] hookItemNames = {
OnePlusWorkAroundHooker.class.getName(),
HandleBindAppHooker.class.getName(),
SystemMainHooker.class.getName(),
LoadedApkConstructorHooker.class.getName()
@ -18,6 +16,5 @@ public class SysBootstrapHookInfo implements KeepMembers {
HandleBindAppHooker.class,
SystemMainHooker.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
/template_override/system/framework/edxp.jar
/template_override/system/framework

View File

@ -22,10 +22,11 @@ android {
}
}
ndkVersion androidCompileNdkVersion
}
dependencies {
compileOnly files("${hiddenApiStubJarFilePath}")
compileOnly project(':hiddenapi-stubs')
implementation project(':edxp-common')
compileOnly project(':dexmaker')
}
@ -58,6 +59,24 @@ afterEvaluate {
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}") {
dependsOn tasks.getByPath(":edxp-common:copyCommonProperties")
def dexOutPath = variant.name.contains("release") ?

View File

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

View File

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

View File

@ -22,10 +22,11 @@ android {
}
}
ndkVersion androidCompileNdkVersion
}
dependencies {
compileOnly files("${hiddenApiStubJarFilePath}")
compileOnly project(':hiddenapi-stubs')
implementation project(':edxp-common')
compileOnly project(':dexmaker')
}
@ -58,6 +59,23 @@ afterEvaluate {
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}") {
dependsOn tasks.getByPath(":edxp-common:copyCommonProperties")
def dexOutPath = variant.name.contains("release") ?
@ -70,6 +88,7 @@ afterEvaluate {
copy {
from file(myTemplatePath)
into file(templateRootPath)
include "*.dex"
}
}
outputs.upToDateWhen { false }

View File

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

View File

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

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
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
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){
dependsOn assemble
baseName 'framework-stub'
from("${projectDir}/build/intermediates/javac/release/compileReleaseJavaWithJavac/classes/")
from("${projectDir}/build/intermediates/javac/release/classes/")
into('')
destinationDir file("${projectDir}/libs")
exclude('BuildConfig.class', 'R.class')

View File

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

View File

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

View File

@ -17,10 +17,12 @@ import com.android.internal.os.ZygoteInit;
import com.elderdrivers.riru.edxp.config.EdXpConfigGlobal;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.StringBufferInputStream;
import java.lang.ref.WeakReference;
import java.lang.reflect.Method;
import java.util.ArrayList;
@ -307,38 +309,21 @@ public final class XposedInit {
private static final Object moduleLoadLock = new Object();
// @GuardedBy("moduleLoadLock")
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);
if (hasLoaded && !EdXpConfigGlobal.getConfig().isDynamicModulesMode()) {
return false;
}
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 parent;
while ((parent = topClassLoader.getParent()) != null) {
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));
ArraySet<String> newLoadedApk = new ArraySet<>();
String apk;
@ -358,9 +343,6 @@ public final class XposedInit {
// refresh callback according to current loaded module list
pruneCallbacks(loadedModules);
lastModuleListModifiedTime = moduleListModifiedTime;
}
return true;
}