From 9e21bc9e19d291a6e64146fcde099f250ad4ff39 Mon Sep 17 00:00:00 2001 From: solohsu Date: Fri, 22 Feb 2019 11:33:07 +0800 Subject: [PATCH] Bring back new black/white list mode --- .../com/elderdrivers/riru/xposed/Main.java | 54 +++---- .../riru/xposed/config/InstallerChooser.java | 4 +- .../riru/xposed/entry/Router.java | 2 +- .../proxy/yahfa/BlackWhiteListProxy.java | 35 +++++ .../riru/xposed/proxy/yahfa/NormalProxy.java | 54 +++++++ Core/jni/main/Android.mk | 3 +- Core/jni/main/inject/config_manager.cpp | 135 ++++++++++++++++++ Core/jni/main/inject/config_manager.h | 14 ++ Core/jni/main/inject/framework_hook.cpp | 20 ++- Core/jni/main/java_hook/java_hook.cpp | 6 +- 10 files changed, 286 insertions(+), 41 deletions(-) create mode 100644 Bridge/src/main/java/com/elderdrivers/riru/xposed/proxy/yahfa/BlackWhiteListProxy.java create mode 100644 Bridge/src/main/java/com/elderdrivers/riru/xposed/proxy/yahfa/NormalProxy.java create mode 100644 Core/jni/main/inject/config_manager.cpp create mode 100644 Core/jni/main/inject/config_manager.h diff --git a/Bridge/src/main/java/com/elderdrivers/riru/xposed/Main.java b/Bridge/src/main/java/com/elderdrivers/riru/xposed/Main.java index 7699c8a2..e24a9262 100644 --- a/Bridge/src/main/java/com/elderdrivers/riru/xposed/Main.java +++ b/Bridge/src/main/java/com/elderdrivers/riru/xposed/Main.java @@ -5,17 +5,14 @@ import android.os.Build; import android.os.Process; import com.elderdrivers.riru.common.KeepAll; -import com.elderdrivers.riru.xposed.config.ConfigManager; import com.elderdrivers.riru.xposed.core.HookMethodResolver; -import com.elderdrivers.riru.xposed.dexmaker.DynamicBridge; -import com.elderdrivers.riru.xposed.entry.Router; +import com.elderdrivers.riru.xposed.proxy.yahfa.BlackWhiteListProxy; +import com.elderdrivers.riru.xposed.proxy.yahfa.NormalProxy; import com.elderdrivers.riru.xposed.util.Utils; import java.lang.reflect.Method; import java.util.Arrays; -import static com.elderdrivers.riru.xposed.util.FileUtils.getDataPathPrefix; - @SuppressLint("DefaultLocale") public class Main implements KeepAll { @@ -45,23 +42,17 @@ public class Main implements KeepAll { mountExternal, seInfo, niceName, Arrays.toString(fdsToClose), Arrays.toString(fdsToIgnore), startChildZygote, instructionSet, appDataDir); } - Main.appDataDir = appDataDir; - Router.prepare(false); - // install bootstrap hooks for secondary zygote - Router.installBootstrapHooks(false); - // load modules for secondary zygote - Router.loadModulesSafely(); + NormalProxy.forkAndSpecializePre(uid, gid, gids, debugFlags, rlimits, mountExternal, seInfo, + niceName, fdsToClose, fdsToIgnore, startChildZygote, instructionSet, appDataDir); } - public static void forkAndSpecializePost(int pid, String appDataDir) { + public static void forkAndSpecializePost(int pid, String appDataDir, boolean isBlackWhiteListMode) { if (pid == 0) { Utils.logD(forkAndSpecializePramsStr + " = " + Process.myPid()); - // TODO consider processes without forkAndSpecializePost called - Router.onEnterChildProcess(); - DynamicBridge.onForkPost(); - if (ConfigManager.isDynamicModulesMode()) { - // load modules for each app process on its forked - Router.loadModulesSafely(); + if (isBlackWhiteListMode) { + BlackWhiteListProxy.forkAndSpecializePost(pid, appDataDir); + } else { + NormalProxy.forkAndSpecializePost(pid, appDataDir); } } else { // in zygote process, res is child zygote pid @@ -76,23 +67,18 @@ public class Main implements KeepAll { uid, gid, Arrays.toString(gids), debugFlags, Arrays.toString(rlimits), permittedCapabilities, effectiveCapabilities); } - Main.appDataDir = getDataPathPrefix() + "android"; - Router.prepare(true); - // install bootstrap hooks for main zygote as early as possible - // in case we miss some processes not forked via forkAndSpecialize - // for instance com.android.phone - Router.installBootstrapHooks(true); - // loadModules have to be executed in zygote even isDynamicModules is false - // because if not global hooks installed in initZygote might not be - // propagated to processes not forked via forkAndSpecialize - Router.loadModulesSafely(); + NormalProxy.forkSystemServerPre(uid, gid, gids, debugFlags, rlimits, + permittedCapabilities, effectiveCapabilities); } - public static void forkSystemServerPost(int pid) { + public static void forkSystemServerPost(int pid, boolean isBlackWhiteListMode) { if (pid == 0) { Utils.logD(forkSystemServerPramsStr + " = " + Process.myPid()); - // in system_server process - Router.onEnterChildProcess(); + if (isBlackWhiteListMode) { + BlackWhiteListProxy.forkSystemServerPost(pid); + } else { + NormalProxy.forkSystemServerPost(pid); + } } else { // in zygote process, res is child zygote pid // don't print log here, see https://github.com/RikkaApps/Riru/blob/77adfd6a4a6a81bfd20569c910bc4854f2f84f5e/riru-core/jni/main/jni_native_method.cpp#L55-L66 @@ -103,16 +89,14 @@ public class Main implements KeepAll { // native methods /////////////////////////////////////////////////////////////////////////////////////////////// - @SuppressWarnings("all") public static native boolean backupAndHookNative(Object target, Method hook, Method backup); - @SuppressWarnings("all") public static native void ensureMethodCached(Method hook, Method backup); - @SuppressWarnings("all") // JNI.ToReflectedMethod() could return either Method or Constructor public static native Object findMethodNative(Class targetClass, String methodName, String methodSig); - @SuppressWarnings("all") private static native void init(int SDK_version); + + public static native String getInstallerPkgName(); } diff --git a/Bridge/src/main/java/com/elderdrivers/riru/xposed/config/InstallerChooser.java b/Bridge/src/main/java/com/elderdrivers/riru/xposed/config/InstallerChooser.java index 20677317..f0aeb624 100644 --- a/Bridge/src/main/java/com/elderdrivers/riru/xposed/config/InstallerChooser.java +++ b/Bridge/src/main/java/com/elderdrivers/riru/xposed/config/InstallerChooser.java @@ -10,6 +10,8 @@ import java.util.concurrent.atomic.AtomicBoolean; import de.robv.android.xposed.SELinuxHelper; import de.robv.android.xposed.services.BaseService; +import static com.elderdrivers.riru.xposed.Main.getInstallerPkgName; + public class InstallerChooser { private static final AtomicBoolean hasSet = new AtomicBoolean(false); @@ -21,7 +23,7 @@ public class InstallerChooser { public static final String SECONDARY_INSTALLER_PACKAGE_NAME = "org.meowcat.edxposed.manager"; public static final String LEGACY_INSTALLER_PACKAGE_NAME = "de.robv.android.xposed.installer"; - public static String INSTALLER_PACKAGE_NAME = PRIMARY_INSTALLER_PACKAGE_NAME; + public static String INSTALLER_PACKAGE_NAME = getInstallerPkgName(); @SuppressLint("SdCardPath") public static String INSTALLER_DATA_BASE_DIR = DATA_DIR_PATH_PREFIX + INSTALLER_PACKAGE_NAME + "/"; diff --git a/Bridge/src/main/java/com/elderdrivers/riru/xposed/entry/Router.java b/Bridge/src/main/java/com/elderdrivers/riru/xposed/entry/Router.java index e10f688c..73ef995f 100644 --- a/Bridge/src/main/java/com/elderdrivers/riru/xposed/entry/Router.java +++ b/Bridge/src/main/java/com/elderdrivers/riru/xposed/entry/Router.java @@ -20,7 +20,7 @@ public class Router { public static void prepare(boolean isSystem) { // this flag is needed when loadModules XposedInit.startsSystemServer = isSystem; - InstallerChooser.setup(); +// InstallerChooser.setup(); } public static void checkHookState(String appDataDir) { diff --git a/Bridge/src/main/java/com/elderdrivers/riru/xposed/proxy/yahfa/BlackWhiteListProxy.java b/Bridge/src/main/java/com/elderdrivers/riru/xposed/proxy/yahfa/BlackWhiteListProxy.java new file mode 100644 index 00000000..80bc850b --- /dev/null +++ b/Bridge/src/main/java/com/elderdrivers/riru/xposed/proxy/yahfa/BlackWhiteListProxy.java @@ -0,0 +1,35 @@ +package com.elderdrivers.riru.xposed.proxy.yahfa; + +import com.elderdrivers.riru.xposed.Main; +import com.elderdrivers.riru.xposed.entry.Router; + +import static com.elderdrivers.riru.xposed.util.FileUtils.getDataPathPrefix; + +public class BlackWhiteListProxy { + + public static void forkAndSpecializePre(int uid, int gid, int[] gids, int debugFlags, + int[][] rlimits, int mountExternal, String seInfo, + String niceName, int[] fdsToClose, int[] fdsToIgnore, + boolean startChildZygote, String instructionSet, + String appDataDir) { + } + + public static void forkAndSpecializePost(int pid, String appDataDir) { + Main.appDataDir = appDataDir; + Router.prepare(false); + Router.installBootstrapHooks(false); + Router.loadModulesSafely(); + } + + public static void forkSystemServerPre(int uid, int gid, int[] gids, int debugFlags, int[][] rlimits, + long permittedCapabilities, long effectiveCapabilities) { + + } + + public static void forkSystemServerPost(int pid) { + Main.appDataDir = getDataPathPrefix() + "android"; + Router.prepare(true); + Router.installBootstrapHooks(true); + Router.loadModulesSafely(); + } +} diff --git a/Bridge/src/main/java/com/elderdrivers/riru/xposed/proxy/yahfa/NormalProxy.java b/Bridge/src/main/java/com/elderdrivers/riru/xposed/proxy/yahfa/NormalProxy.java new file mode 100644 index 00000000..b4316ddc --- /dev/null +++ b/Bridge/src/main/java/com/elderdrivers/riru/xposed/proxy/yahfa/NormalProxy.java @@ -0,0 +1,54 @@ +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 static com.elderdrivers.riru.xposed.util.FileUtils.getDataPathPrefix; + +public class NormalProxy { + + public static void forkAndSpecializePre(int uid, int gid, int[] gids, int debugFlags, + int[][] rlimits, int mountExternal, String seInfo, + String niceName, int[] fdsToClose, int[] fdsToIgnore, + boolean startChildZygote, String instructionSet, + String appDataDir) { + Main.appDataDir = appDataDir; + Router.prepare(false); + // install bootstrap hooks for secondary zygote + Router.installBootstrapHooks(false); + // load modules for secondary zygote + Router.loadModulesSafely(); + } + + public static void forkAndSpecializePost(int pid, String appDataDir) { + // TODO consider processes without forkAndSpecializePost called + Router.onEnterChildProcess(); + DynamicBridge.onForkPost(); + if (ConfigManager.isDynamicModulesMode()) { + // load modules for each app process on its forked + Router.loadModulesSafely(); + } + } + + public static void forkSystemServerPre(int uid, int gid, int[] gids, int debugFlags, int[][] rlimits, + long permittedCapabilities, long effectiveCapabilities) { + Main.appDataDir = getDataPathPrefix() + "android"; + Router.prepare(true); + // install bootstrap hooks for main zygote as early as possible + // in case we miss some processes not forked via forkAndSpecialize + // for instance com.android.phone + Router.installBootstrapHooks(true); + // loadModules have to be executed in zygote even isDynamicModules is false + // because if not global hooks installed in initZygote might not be + // propagated to processes not forked via forkAndSpecialize + Router.loadModulesSafely(); + } + + public static void forkSystemServerPost(int pid) { + // in system_server process + Router.onEnterChildProcess(); + } + +} diff --git a/Core/jni/main/Android.mk b/Core/jni/main/Android.mk index b8bff4fe..0abc2c81 100644 --- a/Core/jni/main/Android.mk +++ b/Core/jni/main/Android.mk @@ -18,6 +18,7 @@ LOCAL_SRC_FILES:= \ yahfa/HookMain.c \ yahfa/trampoline.c \ java_hook/java_hook.cpp \ - inject/framework_hook.cpp + inject/framework_hook.cpp \ + inject/config_manager.cpp include $(BUILD_SHARED_LIBRARY) \ No newline at end of file diff --git a/Core/jni/main/inject/config_manager.cpp b/Core/jni/main/inject/config_manager.cpp new file mode 100644 index 00000000..d2832c06 --- /dev/null +++ b/Core/jni/main/inject/config_manager.cpp @@ -0,0 +1,135 @@ +// +// Created by Solo on 2019/1/27. +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "config_manager.h" + +#define PRIMARY_INSTALLER_PKG_NAME "com.solohsu.android.edxp.manager" +#define SECONDARY_INSTALLER_PKG_NAME "org.meowcat.edxposed.manager" +#define LEGACY_INSTALLER_PKG_NAME "de.robv.android.xposed.installer" + +static bool use_prot_storage = GetAndroidApiLevel() >= ANDROID_N; +static const char *data_path_prefix = use_prot_storage ? "/data/user_de/0/" : "/data/user/0/"; +static const char *config_path_tpl = "%s/%s/conf/%s"; +static char data_test_path[PATH_MAX]; +static char blacklist_path[PATH_MAX]; +static char whitelist_path[PATH_MAX]; +static char use_whitelist_path[PATH_MAX]; +static char black_white_list_path[PATH_MAX]; +static char dynamic_modules_path[PATH_MAX]; + +static const char *installer_package_name; +static bool black_white_list_enabled = false; +static bool inited = false; + +static const char *get_installer_package_name() { + snprintf(data_test_path, PATH_MAX, config_path_tpl, data_path_prefix, + PRIMARY_INSTALLER_PKG_NAME, "/"); + if (access(data_test_path, F_OK) == 0) { + LOGI("using installer " + PRIMARY_INSTALLER_PKG_NAME); + return PRIMARY_INSTALLER_PKG_NAME; + } + snprintf(data_test_path, PATH_MAX, config_path_tpl, data_path_prefix, + SECONDARY_INSTALLER_PKG_NAME, "/"); + if (access(data_test_path, F_OK) == 0) { + LOGI("using installer " + SECONDARY_INSTALLER_PKG_NAME); + return SECONDARY_INSTALLER_PKG_NAME; + } + snprintf(data_test_path, PATH_MAX, config_path_tpl, data_path_prefix, + LEGACY_INSTALLER_PKG_NAME, "/"); + if (access(data_test_path, F_OK) == 0) { + LOGI("using installer " + LEGACY_INSTALLER_PKG_NAME); + return LEGACY_INSTALLER_PKG_NAME; + } + LOGE("no supported installer app found, using primary as default"); + return PRIMARY_INSTALLER_PKG_NAME; +} + +static void init_once() { + if (!inited) { + installer_package_name = get_installer_package_name(); + snprintf(blacklist_path, PATH_MAX, config_path_tpl, data_path_prefix, + installer_package_name, "blacklist/"); + snprintf(whitelist_path, PATH_MAX, config_path_tpl, data_path_prefix, + installer_package_name, "whitelist/"); + snprintf(use_whitelist_path, PATH_MAX, config_path_tpl, data_path_prefix, + installer_package_name, "usewhitelist"); + snprintf(black_white_list_path, PATH_MAX, config_path_tpl, data_path_prefix, + installer_package_name, "blackwhitelist"); + snprintf(dynamic_modules_path, PATH_MAX, config_path_tpl, data_path_prefix, + installer_package_name, "dynamicmodules"); + black_white_list_enabled = access(black_white_list_path, F_OK) == 0; + LOGI("black/white list mode: %d", black_white_list_enabled); + inited = true; + } +} + +static char package_name[256]; + +bool is_app_need_hook(JNIEnv *env, jstring appDataDir) { + init_once(); + if (!black_white_list_enabled) { + return true; + } + bool use_white_list = access(use_whitelist_path, F_OK) == 0; + LOGI("using %s list mode", use_white_list ? "white" : "black"); + if (!appDataDir) { + LOGE("appDataDir is null"); + return !use_white_list; + } + const char *app_data_dir = env->GetStringUTFChars(appDataDir, nullptr); + int user = 0; + if (sscanf(app_data_dir, "/data/%*[^/]/%d/%s", &user, package_name) != 2) { + if (sscanf(app_data_dir, "/data/%*[^/]/%s", package_name) != 1) { + package_name[0] = '\0'; + LOGE("can't parse %s", app_data_dir); + env->ReleaseStringUTFChars(appDataDir, app_data_dir); + return !use_white_list; + } + } + if (strcmp(package_name, "com.solohsu.android.edxp.manager") == 0 + || strcmp(package_name, "org.meowcat.edxposed.manager") == 0 + || strcmp(package_name, "de.robv.android.xposed.installer") == 0) { + // always hook installer apps + env->ReleaseStringUTFChars(appDataDir, app_data_dir); + return true; + } + if (use_white_list) { + char path[PATH_MAX]; + snprintf(path, PATH_MAX, "%s%s", whitelist_path, package_name); + bool res = access(path, F_OK) == 0; + LOGD("using whitelist, %s -> %d", app_data_dir, res); + env->ReleaseStringUTFChars(appDataDir, app_data_dir); + return res; + } else { + char path[PATH_MAX]; + snprintf(path, PATH_MAX, "%s%s", blacklist_path, package_name); + bool res = access(path, F_OK) != 0; + LOGD("using blacklist, %s -> %d", app_data_dir, res); + env->ReleaseStringUTFChars(appDataDir, app_data_dir); + return res; + } +} + +bool is_black_white_list_enabled() { + init_once(); + return black_white_list_enabled; +} + +jstring get_installer_pkg_name(JNIEnv *env) { + init_once(); + return env->NewStringUTF(installer_package_name); +} diff --git a/Core/jni/main/inject/config_manager.h b/Core/jni/main/inject/config_manager.h new file mode 100644 index 00000000..67d4a3c7 --- /dev/null +++ b/Core/jni/main/inject/config_manager.h @@ -0,0 +1,14 @@ +// +// Created by Solo on 2019/1/27. +// + +#ifndef EDXPOSED_CONFIG_MANAGER_H +#define EDXPOSED_CONFIG_MANAGER_H + +bool is_app_need_hook(JNIEnv *env, jstring appDataDir); + +bool is_black_white_list_enabled(); + +jstring get_installer_pkg_name(JNIEnv *env); + +#endif //EDXPOSED_CONFIG_MANAGER_H diff --git a/Core/jni/main/inject/framework_hook.cpp b/Core/jni/main/inject/framework_hook.cpp index 66cb9e24..c289167d 100644 --- a/Core/jni/main/inject/framework_hook.cpp +++ b/Core/jni/main/inject/framework_hook.cpp @@ -5,6 +5,7 @@ #include #include "framework_hook.h" #include "include/misc.h" +#include "config_manager.h" #define SYSTEM_SERVER_DATA_DIR "/data/user/0/android" @@ -41,6 +42,10 @@ void onNativeForkSystemServerPre(JNIEnv *env, jclass clazz, uid_t uid, gid_t gid jint runtime_flags, jobjectArray rlimits, jlong permittedCapabilities, jlong effectiveCapabilities) { sAppDataDir = env->NewStringUTF(SYSTEM_SERVER_DATA_DIR); + if (is_black_white_list_enabled()) { + // when black/white list is on, never inject into zygote + return; + } prepareJavaEnv(env); // jump to java code findAndCall(env, "forkSystemServerPre", "(II[II[[IJJ)V", uid, gid, gids, runtime_flags, rlimits, @@ -50,9 +55,12 @@ void onNativeForkSystemServerPre(JNIEnv *env, jclass clazz, uid_t uid, gid_t gid int onNativeForkSystemServerPost(JNIEnv *env, jclass clazz, jint res) { if (res == 0) { + if (!is_app_need_hook(env, sAppDataDir)) { + return 0; + } prepareJavaEnv(env); // only do work in child since findAndCall would print log - findAndCall(env, "forkSystemServerPost", "(I)V", res); + findAndCall(env, "forkSystemServerPost", "(IZ)V", res, is_black_white_list_enabled()); } 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 @@ -74,6 +82,10 @@ void onNativeForkAndSpecializePre(JNIEnv *env, jclass clazz, jstring instructionSet, jstring appDataDir) { sAppDataDir = appDataDir; + if (is_black_white_list_enabled()) { + // when black/white list is on, never inject into zygote + return; + } prepareJavaEnv(env); findAndCall(env, "forkAndSpecializePre", "(II[II[[IILjava/lang/String;Ljava/lang/String;[I[IZLjava/lang/String;Ljava/lang/String;)V", @@ -84,8 +96,12 @@ void onNativeForkAndSpecializePre(JNIEnv *env, jclass clazz, int onNativeForkAndSpecializePost(JNIEnv *env, jclass clazz, jint res) { if (res == 0) { + if (!is_app_need_hook(env, sAppDataDir)) { + return 0; + } prepareJavaEnv(env); - findAndCall(env, "forkAndSpecializePost", "(ILjava/lang/String;)V", res, sAppDataDir); + findAndCall(env, "forkAndSpecializePost", "(ILjava/lang/String;Z)V", res, sAppDataDir, + is_black_white_list_enabled()); } 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 diff --git a/Core/jni/main/java_hook/java_hook.cpp b/Core/jni/main/java_hook/java_hook.cpp index 15ba92bf..64a73081 100644 --- a/Core/jni/main/java_hook/java_hook.cpp +++ b/Core/jni/main/java_hook/java_hook.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include "java_hook/java_hook.h" #include "include/logging.h" #include "native_hook/native_hook.h" @@ -38,6 +39,9 @@ static JNINativeMethod hookMethods[] = { "ensureMethodCached", "(Ljava/lang/reflect/Method;Ljava/lang/reflect/Method;)V", (void *) Java_lab_galaxy_yahfa_HookMain_ensureMethodCached + }, + { + "getInstallerPkgName", "()Ljava/lang/String;", (void *)get_installer_pkg_name } }; @@ -76,7 +80,7 @@ void loadDexAndInit(JNIEnv *env, const char *dexPath) { jclass entry_class = findClassFromLoader(env, myClassLoader, ENTRY_CLASS_NAME); if (NULL != entry_class) { LOGD("HookEntry Class %p", entry_class); - env->RegisterNatives(entry_class, hookMethods, 4); + env->RegisterNatives(entry_class, hookMethods, 5); isInited = true; LOGD("RegisterNatives succeed for HookEntry."); } else {