Better Hidden
This commit is contained in:
parent
a5d6cbe44f
commit
0ece9b141d
|
|
@ -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 +1,2 @@
|
|||
/build
|
||||
dex
|
||||
|
|
|
|||
|
|
@ -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 +1,2 @@
|
|||
/build
|
||||
dex
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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.
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -51,4 +51,7 @@ public class BaseEdxpConfig implements EdxpConfig {
|
|||
public boolean isBlackWhiteListMode() {
|
||||
return ConfigManager.isBlackWhiteListEnabled();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getModulesList() { return ConfigManager.getModulesList(); }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -50,4 +50,6 @@ public class ConfigManager {
|
|||
public static native String getDataPathPrefix();
|
||||
|
||||
public static native boolean isAppNeedHook(String appDataDir);
|
||||
|
||||
public static native String getModulesList();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
};
|
||||
}
|
||||
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -7,3 +7,4 @@
|
|||
/template_override/system
|
||||
/template_override/system_x86
|
||||
*.iml
|
||||
/.cxx
|
||||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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";
|
||||
}
|
||||
}
|
||||
|
|
@ -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(...)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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>();
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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}"
|
||||
|
|
|
|||
|
|
@ -1,2 +1,2 @@
|
|||
/build
|
||||
/template_override/system/framework/edxp.jar
|
||||
/template_override/system/framework
|
||||
|
|
@ -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 }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,6 +32,6 @@
|
|||
|
||||
-keep class com.swift.sandhook.** {*;}
|
||||
|
||||
-keepclasseswithmember class * {
|
||||
-keepclasseswithmembers class * {
|
||||
native <methods>;
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
};
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,2 +1,2 @@
|
|||
/build
|
||||
/template_override/system/framework/edxp.jar
|
||||
/template_override/system/framework
|
||||
|
|
@ -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") ?
|
||||
|
|
|
|||
|
|
@ -32,6 +32,6 @@
|
|||
|
||||
-keep class com.lody.** {*;}
|
||||
|
||||
-keepclasseswithmember class * {
|
||||
-keepclasseswithmembers class * {
|
||||
native <methods>;
|
||||
}
|
||||
|
|
@ -1,2 +1,2 @@
|
|||
/build
|
||||
/template_override/system/framework/edxp.jar
|
||||
/template_override/system/framework
|
||||
|
|
@ -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 }
|
||||
|
|
|
|||
|
|
@ -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>;
|
||||
}
|
||||
|
|
@ -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());
|
||||
|
|
|
|||
|
|
@ -1,3 +1,2 @@
|
|||
android.enableR8=false
|
||||
|
||||
androidCompileSdkVersion=30
|
||||
androidCompileNdkVersion=22.0.6917172 rc1
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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')
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ apply plugin: 'com.android.library'
|
|||
|
||||
android {
|
||||
compileSdkVersion androidCompileSdkVersion.toInteger()
|
||||
buildToolsVersion '28.0.3'
|
||||
|
||||
defaultConfig {
|
||||
minSdkVersion 26
|
||||
|
|
|
|||
|
|
@ -21,4 +21,6 @@ public interface EdxpConfig {
|
|||
boolean isResourcesHookEnabled();
|
||||
|
||||
boolean isBlackWhiteListMode();
|
||||
|
||||
String getModulesList();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue