Merge branch 'master' of https://github.com/ElderDrivers/EdXposed
This commit is contained in:
commit
d18c05fc1d
|
|
@ -1,6 +1,7 @@
|
|||
package com.elderdrivers.riru.xposed.config;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Set;
|
||||
|
||||
import de.robv.android.xposed.SELinuxHelper;
|
||||
|
|
@ -16,24 +17,32 @@ public class ConfigManager {
|
|||
private static final String USE_WHITE_LIST = INSTALLER_DATA_BASE_DIR + "conf/usewhitelist";
|
||||
private static final String DYNAMIC_MODULES = INSTALLER_DATA_BASE_DIR + "conf/dynamicmodules";
|
||||
private static final Set<String> WHITE_LIST = Collections.singleton(INSTALLER_PACKAGE_NAME);
|
||||
private static final HashMap<String, Boolean> compatModeCache = new HashMap<>();
|
||||
private static volatile boolean IS_DYNAMIC_MODULES = false;
|
||||
|
||||
public static boolean isDynamicModulesMode() {
|
||||
return IS_DYNAMIC_MODULES;
|
||||
}
|
||||
|
||||
public static synchronized void setDynamicModulesMode(boolean isDynamicModulesMode) {
|
||||
if (isDynamicModulesMode != IS_DYNAMIC_MODULES) {
|
||||
IS_DYNAMIC_MODULES = isDynamicModulesMode;
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isDynamicModulesMode() {
|
||||
return IS_DYNAMIC_MODULES;
|
||||
}
|
||||
|
||||
public static boolean shouldUseWhitelist() {
|
||||
return isFileExists(USE_WHITE_LIST);
|
||||
}
|
||||
|
||||
public static boolean shouldUseCompatMode(String packageName) {
|
||||
return isFileExists(COMPAT_LIST_PATH + packageName);
|
||||
Boolean result;
|
||||
if (compatModeCache.containsKey(packageName)
|
||||
&& (result = compatModeCache.get(packageName)) != null) {
|
||||
return result;
|
||||
}
|
||||
result = isFileExists(COMPAT_LIST_PATH + packageName);
|
||||
compatModeCache.put(packageName, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
public static boolean shouldHook(String packageName) {
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@ import com.elderdrivers.riru.xposed.config.ConfigManager;
|
|||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import de.robv.android.xposed.SELinuxHelper;
|
||||
import external.com.android.dx.Code;
|
||||
import external.com.android.dx.Local;
|
||||
import external.com.android.dx.TypeId;
|
||||
|
|
@ -156,8 +155,8 @@ public class DexMakerUtils {
|
|||
code.loadConstant(booleanLocal, false);
|
||||
code.loadConstant(byteLocal, (byte) 0);
|
||||
code.loadConstant(charLocal, '\0');
|
||||
code.loadConstant(doubleLocal,0.0);
|
||||
code.loadConstant(floatLocal,0.0f);
|
||||
code.loadConstant(doubleLocal, 0.0);
|
||||
code.loadConstant(floatLocal, 0.0f);
|
||||
code.loadConstant(intLocal, 0);
|
||||
code.loadConstant(longLocal, 0L);
|
||||
code.loadConstant(shortLocal, (short) 0);
|
||||
|
|
|
|||
|
|
@ -27,6 +27,10 @@ public final class DynamicBridge {
|
|||
private static File dexDir;
|
||||
private static File dexOptDir;
|
||||
|
||||
/**
|
||||
* Reset dexPathInited flag once we enter child process
|
||||
* since it might have been set to true in zygote process
|
||||
*/
|
||||
public static void onForkPost() {
|
||||
dexPathInited.set(false);
|
||||
}
|
||||
|
|
@ -46,36 +50,48 @@ public final class DynamicBridge {
|
|||
try {
|
||||
// for Android Oreo and later use InMemoryClassLoader
|
||||
if (!shouldUseInMemoryHook()) {
|
||||
// using file based DexClassLoader
|
||||
if (dexPathInited.compareAndSet(false, true)) {
|
||||
// delete previous compiled dex to prevent potential crashing
|
||||
// TODO find a way to reuse them in consideration of performance
|
||||
try {
|
||||
// we always choose to use device encrypted storage data on android N and later
|
||||
// in case some app is installing hooks before phone is unlocked
|
||||
String fixedAppDataDir = getDataPathPrefix() + getPackageName(Main.appDataDir) + "/";
|
||||
dexDir = new File(fixedAppDataDir, "/cache/edhookers/"
|
||||
+ getCurrentProcessName().replace(":", "_") + "/");
|
||||
dexOptDir = new File(dexDir, "oat");
|
||||
dexDir.mkdirs();
|
||||
DexLog.d(Main.appProcessName + " deleting dir: " + dexOptDir.getAbsolutePath());
|
||||
try {
|
||||
FileUtils.delete(dexOptDir);
|
||||
} catch (Throwable throwable) {
|
||||
}
|
||||
} catch (Throwable throwable) {
|
||||
DexLog.e("error when init dex path", throwable);
|
||||
}
|
||||
}
|
||||
setupDexCachePath();
|
||||
}
|
||||
dexMaker.start(hookMethod, additionalHookInfo,
|
||||
hookMethod.getDeclaringClass().getClassLoader(), dexDir == null ? null : dexDir.getAbsolutePath());
|
||||
hookMethod.getDeclaringClass().getClassLoader(), getDexDirPath());
|
||||
hookedInfo.put(hookMethod, dexMaker.getCallBackupMethod());
|
||||
} catch (Exception e) {
|
||||
DexLog.e("error occur when generating dex. dexDir=" + dexDir, e);
|
||||
}
|
||||
}
|
||||
|
||||
private static String getDexDirPath() {
|
||||
if (dexDir == null) {
|
||||
return null;
|
||||
}
|
||||
return dexDir.getAbsolutePath();
|
||||
}
|
||||
|
||||
private static void setupDexCachePath() {
|
||||
// using file based DexClassLoader
|
||||
if (!dexPathInited.compareAndSet(false, true)) {
|
||||
return;
|
||||
}
|
||||
// delete previous compiled dex to prevent potential crashing
|
||||
// TODO find a way to reuse them in consideration of performance
|
||||
try {
|
||||
// we always choose to use device encrypted storage data on android N and later
|
||||
// in case some app is installing hooks before phone is unlocked
|
||||
String fixedAppDataDir = getDataPathPrefix() + getPackageName(Main.appDataDir) + "/";
|
||||
dexDir = new File(fixedAppDataDir, "/cache/edhookers/"
|
||||
+ getCurrentProcessName().replace(":", "_") + "/");
|
||||
dexOptDir = new File(dexDir, "oat");
|
||||
dexDir.mkdirs();
|
||||
DexLog.d(Main.appProcessName + " deleting dir: " + dexOptDir.getAbsolutePath());
|
||||
try {
|
||||
FileUtils.delete(dexOptDir);
|
||||
} catch (Throwable throwable) {
|
||||
}
|
||||
} catch (Throwable throwable) {
|
||||
DexLog.e("error when init dex path", throwable);
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean checkMember(Member member) {
|
||||
|
||||
if (member instanceof Method) {
|
||||
|
|
|
|||
|
|
@ -30,7 +30,6 @@ import static com.elderdrivers.riru.xposed.dexmaker.DexMakerUtils.autoBoxIfNeces
|
|||
import static com.elderdrivers.riru.xposed.dexmaker.DexMakerUtils.autoUnboxIfNecessary;
|
||||
import static com.elderdrivers.riru.xposed.dexmaker.DexMakerUtils.createResultLocals;
|
||||
import static com.elderdrivers.riru.xposed.dexmaker.DexMakerUtils.getObjTypeIdIfPrimitive;
|
||||
import static com.elderdrivers.riru.xposed.dexmaker.DexMakerUtils.shouldUseInMemoryHook;
|
||||
|
||||
public class HookerDexMaker {
|
||||
|
||||
|
|
@ -193,14 +192,11 @@ public class HookerDexMaker {
|
|||
generateCallBackupMethod();
|
||||
|
||||
ClassLoader loader;
|
||||
if (shouldUseInMemoryHook()) {
|
||||
if (TextUtils.isEmpty(mDexDirPath)) {
|
||||
// in memory dex classloader
|
||||
byte[] dexBytes = mDexMaker.generate();
|
||||
loader = new InMemoryDexClassLoader(ByteBuffer.wrap(dexBytes), mAppClassLoader);
|
||||
} else {
|
||||
if (TextUtils.isEmpty(mDexDirPath)) {
|
||||
throw new IllegalArgumentException("dexDirPath should not be empty!!!");
|
||||
}
|
||||
// Create the dex file and load it.
|
||||
loader = mDexMaker.generateAndLoad(mAppClassLoader, new File(mDexDirPath));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,19 +2,15 @@ package com.elderdrivers.riru.xposed.entry;
|
|||
|
||||
import android.text.TextUtils;
|
||||
|
||||
import com.elderdrivers.riru.xposed.Main;
|
||||
import com.elderdrivers.riru.xposed.core.HookMain;
|
||||
import com.elderdrivers.riru.xposed.dexmaker.DynamicBridge;
|
||||
import com.elderdrivers.riru.xposed.entry.bootstrap.AppBootstrapHookInfo;
|
||||
import com.elderdrivers.riru.xposed.entry.bootstrap.SysBootstrapHookInfo;
|
||||
import com.elderdrivers.riru.xposed.entry.bootstrap.SysInnerHookInfo;
|
||||
import com.elderdrivers.riru.xposed.entry.hooker.SystemMainHooker;
|
||||
import com.elderdrivers.riru.xposed.util.InlinedMethodCallers;
|
||||
import com.elderdrivers.riru.xposed.util.Utils;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import de.robv.android.xposed.XposedBridge;
|
||||
import de.robv.android.xposed.XposedHelpers;
|
||||
import de.robv.android.xposed.XposedInit;
|
||||
|
||||
public class Router {
|
||||
|
|
@ -87,5 +83,6 @@ public class Router {
|
|||
|
||||
public static void onEnterChildProcess() {
|
||||
forkCompleted = true;
|
||||
DynamicBridge.onForkPost();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,6 +18,8 @@ public class BlackWhiteListProxy {
|
|||
// when isDynamicModulesMode is not on
|
||||
final boolean isDynamicModulesMode = Main.isDynamicModulesEnabled();
|
||||
ConfigManager.setDynamicModulesMode(isDynamicModulesMode);
|
||||
// call this to ensure the flag is set to false ASAP
|
||||
Router.prepare(false);
|
||||
PrebuiltMethodsDeopter.deoptBootMethods(); // do it once for secondary zygote
|
||||
if (!isDynamicModulesMode) {
|
||||
Router.loadModulesSafely();
|
||||
|
|
@ -34,7 +36,7 @@ public class BlackWhiteListProxy {
|
|||
}
|
||||
Main.appDataDir = appDataDir;
|
||||
ConfigManager.setDynamicModulesMode(isDynamicModulesMode);
|
||||
Router.prepare(false);
|
||||
Router.onEnterChildProcess();
|
||||
Router.installBootstrapHooks(false);
|
||||
Router.loadModulesSafely();
|
||||
}
|
||||
|
|
@ -46,6 +48,8 @@ public class BlackWhiteListProxy {
|
|||
final boolean isDynamicModulesMode = Main.isDynamicModulesEnabled();
|
||||
ConfigManager.setDynamicModulesMode(isDynamicModulesMode);
|
||||
PrebuiltMethodsDeopter.deoptBootMethods(); // do it once for main zygote
|
||||
// set startsSystemServer flag used when loadModules
|
||||
Router.prepare(true);
|
||||
// we never install bootstrap hooks here in black/white list mode
|
||||
// because installed hooks would be propagated to all child processes of main zygote
|
||||
// hence we cannot install hooks for processes like com.android.phone process who are
|
||||
|
|
@ -65,7 +69,7 @@ public class BlackWhiteListProxy {
|
|||
}
|
||||
Main.appDataDir = getDataPathPrefix() + "android";
|
||||
ConfigManager.setDynamicModulesMode(isDynamicModulesMode);
|
||||
Router.prepare(true);
|
||||
Router.onEnterChildProcess();
|
||||
Router.installBootstrapHooks(true);
|
||||
Router.loadModulesSafely();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ package com.elderdrivers.riru.xposed.proxy.yahfa;
|
|||
|
||||
import com.elderdrivers.riru.xposed.Main;
|
||||
import com.elderdrivers.riru.xposed.config.ConfigManager;
|
||||
import com.elderdrivers.riru.xposed.dexmaker.DynamicBridge;
|
||||
import com.elderdrivers.riru.xposed.entry.Router;
|
||||
import com.elderdrivers.riru.xposed.util.PrebuiltMethodsDeopter;
|
||||
|
||||
|
|
@ -19,6 +18,7 @@ public class NormalProxy {
|
|||
Main.appDataDir = appDataDir;
|
||||
ConfigManager.setDynamicModulesMode(isDynamicModulesMode);
|
||||
PrebuiltMethodsDeopter.deoptBootMethods(); // do it once for secondary zygote
|
||||
// call this to ensure the flag is set to false ASAP
|
||||
Router.prepare(false);
|
||||
// install bootstrap hooks for secondary zygote
|
||||
Router.installBootstrapHooks(false);
|
||||
|
|
@ -31,7 +31,6 @@ public class NormalProxy {
|
|||
// TODO consider processes without forkAndSpecializePost called
|
||||
Main.reopenFilesAfterForkNative();
|
||||
Router.onEnterChildProcess();
|
||||
DynamicBridge.onForkPost();
|
||||
// load modules for each app process on its forked if dynamic modules mode is on
|
||||
Router.loadModulesSafely();
|
||||
}
|
||||
|
|
@ -41,6 +40,7 @@ public class NormalProxy {
|
|||
final boolean isDynamicModulesMode = Main.isDynamicModulesEnabled();
|
||||
Main.appDataDir = getDataPathPrefix() + "android";
|
||||
ConfigManager.setDynamicModulesMode(isDynamicModulesMode);
|
||||
// set startsSystemServer flag used when loadModules
|
||||
Router.prepare(true);
|
||||
PrebuiltMethodsDeopter.deoptBootMethods(); // do it once for main zygote
|
||||
// install bootstrap hooks for main zygote as early as possible
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
package com.elderdrivers.riru.xposed.util;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.os.Build;
|
||||
import android.os.Process;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
|
|
@ -10,6 +12,8 @@ import java.io.FileReader;
|
|||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
|
||||
import static com.elderdrivers.riru.xposed.util.ProcessUtils.PER_USER_RANGE;
|
||||
|
||||
public class FileUtils {
|
||||
|
||||
public static final boolean IS_USING_PROTECTED_STORAGE = Build.VERSION.SDK_INT >= Build.VERSION_CODES.N;
|
||||
|
|
@ -71,7 +75,11 @@ public class FileUtils {
|
|||
return dataDir.substring(lastIndex + 1);
|
||||
}
|
||||
|
||||
// FIXME: Although multi-users is considered here, but compat mode doesn't support other users' apps on Oreo and later yet.
|
||||
@SuppressLint("SdCardPath")
|
||||
public static String getDataPathPrefix() {
|
||||
return IS_USING_PROTECTED_STORAGE ? "/data/user_de/0/" : "/data/data/";
|
||||
int userId = Process.myUid() / PER_USER_RANGE;
|
||||
String format = IS_USING_PROTECTED_STORAGE ? "/data/user_de/%d/" : "/data/user/%d/";
|
||||
return String.format(format, userId);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,6 +12,10 @@ import java.io.InputStreamReader;
|
|||
|
||||
public class ProcessUtils {
|
||||
|
||||
// Copied from UserHandle, indicates range of uids allocated for a user.
|
||||
public static final int PER_USER_RANGE = 100000;
|
||||
public static final int USER_SYSTEM = 0;
|
||||
|
||||
public static String getCurrentProcessName() {
|
||||
String prettyName = Main.appProcessName;
|
||||
if (!TextUtils.isEmpty(prettyName)) {
|
||||
|
|
|
|||
|
|
@ -19,6 +19,16 @@
|
|||
#include "include/config.h"
|
||||
|
||||
extern "C" {
|
||||
|
||||
__attribute__((visibility("default"))) void onModuleLoaded() {
|
||||
LOGI("onModuleLoaded: welcome to EdXposed!");
|
||||
install_inline_hooks();
|
||||
}
|
||||
|
||||
__attribute__((visibility("default"))) int shouldSkipUid(int uid) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
__attribute__((visibility("default"))) void nativeForkAndSpecializePre(JNIEnv *env, jclass clazz,
|
||||
jint _uid, jint gid,
|
||||
jintArray gids,
|
||||
|
|
@ -42,11 +52,6 @@ __attribute__((visibility("default"))) int nativeForkAndSpecializePost(JNIEnv *e
|
|||
return onNativeForkAndSpecializePost(env, clazz, res);
|
||||
}
|
||||
|
||||
__attribute__((visibility("default"))) void onModuleLoaded() {
|
||||
LOGI("onModuleLoaded: welcome to EdXposed!");
|
||||
install_inline_hooks();
|
||||
}
|
||||
|
||||
__attribute__((visibility("default")))
|
||||
void nativeForkSystemServerPre(JNIEnv *env, jclass clazz, uid_t uid, gid_t gid, jintArray gids,
|
||||
jint runtime_flags, jobjectArray rlimits,
|
||||
|
|
@ -55,7 +60,6 @@ void nativeForkSystemServerPre(JNIEnv *env, jclass clazz, uid_t uid, gid_t gid,
|
|||
permittedCapabilities, effectiveCapabilities);
|
||||
}
|
||||
|
||||
|
||||
__attribute__((visibility("default")))
|
||||
int nativeForkSystemServerPost(JNIEnv *env, jclass clazz, jint res) {
|
||||
return onNativeForkSystemServerPost(env, clazz, res);
|
||||
|
|
|
|||
Loading…
Reference in New Issue