diff --git a/edxp-common/src/main/java/com/elderdrivers/riru/edxp/core/Main.java b/edxp-common/src/main/java/com/elderdrivers/riru/edxp/core/Main.java index 06c41d36f..07ff8c04d 100644 --- a/edxp-common/src/main/java/com/elderdrivers/riru/edxp/core/Main.java +++ b/edxp-common/src/main/java/com/elderdrivers/riru/edxp/core/Main.java @@ -6,7 +6,6 @@ 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.framework.ProcessHelper; import com.elderdrivers.riru.edxp.util.Utils; import java.security.AccessController; @@ -16,8 +15,6 @@ import java.util.ServiceLoader; import java.util.concurrent.atomic.AtomicReference; -import static com.elderdrivers.riru.edxp.proxy.BaseProxy.onBlackListed; - @SuppressLint("DefaultLocale") public class Main implements KeepAll { @@ -40,9 +37,6 @@ public static void forkAndSpecializePre(int uid, int gid, int[] gids, int debugF String niceName, int[] fdsToClose, int[] fdsToIgnore, boolean startChildZygote, String instructionSet, String appDataDir) { - if (isBlackListedProcess(uid)) { - return; - } final EdxpImpl edxp = getEdxpImpl(); if (edxp == null || !edxp.isInitialized()) { return; @@ -67,10 +61,6 @@ public static void forkAndSpecializePre(int uid, int gid, int[] gids, int debugF } public static void forkAndSpecializePost(int pid, String appDataDir, String niceName) { - if (isBlackListedProcess(Process.myUid())) { - onBlackListed(); - return; - } final EdxpImpl edxp = getEdxpImpl(); if (edxp == null || !edxp.isInitialized()) { return; @@ -159,11 +149,4 @@ public Void run() { } }); } - - // TODO do this earlier? - private static boolean isBlackListedProcess(int uid) { - return ProcessHelper.isIsolated(uid) - || ProcessHelper.isRELROUpdater(uid) - || ProcessHelper.isWebViewZygote(uid); - } } diff --git a/edxp-common/src/main/java/com/elderdrivers/riru/edxp/framework/ProcessHelper.java b/edxp-common/src/main/java/com/elderdrivers/riru/edxp/framework/ProcessHelper.java deleted file mode 100644 index 0d669da87..000000000 --- a/edxp-common/src/main/java/com/elderdrivers/riru/edxp/framework/ProcessHelper.java +++ /dev/null @@ -1,96 +0,0 @@ -package com.elderdrivers.riru.edxp.framework; - -import android.os.Process; - -import de.robv.android.xposed.XposedHelpers; -import de.robv.android.xposed.annotation.ApiSensitive; -import de.robv.android.xposed.annotation.Level; - -@ApiSensitive(Level.MIDDLE) -public class ProcessHelper { - - static { - // WEBVIEW_ZYGOTE_UID differ among versions - WEBVIEW_ZYGOTE_UID = XposedHelpers.getStaticIntField(android.os.Process.class, "WEBVIEW_ZYGOTE_UID"); - } - - /** - * Defines the UID/GID for the shared RELRO file updater process. - */ - public static final int SHARED_RELRO_UID = 1037; - - /** - * Defines the UID/GID for the WebView zygote process. - */ - public static final int WEBVIEW_ZYGOTE_UID; - - /** - * First uid used for fully isolated sandboxed processes (with no permissions of their own) - */ - public static final int FIRST_ISOLATED_UID = 99000; - /** - * Last uid used for fully isolated sandboxed processes (with no permissions of their own) - */ - public static final int LAST_ISOLATED_UID = 99999; - - /** - * First uid used for fully isolated sandboxed processes spawned from an app zygote - */ - public static final int FIRST_APP_ZYGOTE_ISOLATED_UID = 90000; - /** - * Number of UIDs we allocate per application zygote - */ - public static final int NUM_UIDS_PER_APP_ZYGOTE = 100; - /** - * Last uid used for fully isolated sandboxed processes spawned from an app zygote - */ - public static final int LAST_APP_ZYGOTE_ISOLATED_UID = 98999; - - /** - * Range of uids allocated for a user. - */ - public static final int PER_USER_RANGE = 100000; - - // @see UserHandle#getAppId(int) - public static int getAppId(int uid) { - return uid % PER_USER_RANGE; - } - - public static boolean isRELROUpdater(int uid) { - return getAppId(uid) == SHARED_RELRO_UID; - } - - public static boolean isWebViewZygote(int uid) { - return getAppId(uid) == WEBVIEW_ZYGOTE_UID; - } - - public static boolean isIsolated(int uid) { - return (boolean) XposedHelpers.callStaticMethod( - Process.class, "isIsolated", uid); - } - - /** - * Whether a UID belongs to a regular app. *Note* "Not a regular app" does not mean - * "it's system", because of isolated UIDs. Use {@link #isCore} for that. - */ - public static boolean isApp(int uid) { - if (uid > 0) { - final int appId = getAppId(uid); - return appId >= Process.FIRST_APPLICATION_UID && appId <= Process.LAST_APPLICATION_UID; - } else { - return false; - } - } - - /** - * Whether a UID belongs to a system core component or not. - */ - public static boolean isCore(int uid) { - if (uid >= 0) { - final int appId = getAppId(uid); - return appId < Process.FIRST_APPLICATION_UID; - } else { - return false; - } - } -} diff --git a/edxp-core/src/main/cpp/external/yahfa/src/common.h b/edxp-core/src/main/cpp/external/yahfa/src/common.h index 570f794c1..fcf840d2c 100644 --- a/edxp-core/src/main/cpp/external/yahfa/src/common.h +++ b/edxp-core/src/main/cpp/external/yahfa/src/common.h @@ -15,7 +15,7 @@ #define LOGE(...) #else #define LOG_TAG "EdXposed" -#ifdef DEBUG +#ifndef NDEBUG #define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__) #define LOGW(...) __android_log_print(ANDROID_LOG_WARN,LOG_TAG,__VA_ARGS__) #define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__) diff --git a/edxp-core/src/main/cpp/main/include/JNIHelper.h b/edxp-core/src/main/cpp/main/include/JNIHelper.h index d3dab8a23..ccee86ba6 100644 --- a/edxp-core/src/main/cpp/main/include/JNIHelper.h +++ b/edxp-core/src/main/cpp/main/include/JNIHelper.h @@ -103,3 +103,31 @@ ALWAYS_INLINE static int ClearException(JNIEnv *env) { env->RegisterNatives(class, methods, size); \ if (ClearException(env)) LOGE("RegisterNatives " #class); +class JUTFString { +public: + inline JUTFString(JNIEnv *env, jstring jstr) : JUTFString(env, jstr, nullptr) { + } + + inline JUTFString(JNIEnv *env, jstring jstr, const char *default_cstr) : env_(env), + jstr_(jstr) { + if (env_ && jstr_) cstr_ = env_->GetStringUTFChars(jstr, nullptr); + else cstr_ = default_cstr; + } + + inline operator const char *() const { return cstr_; } + + inline operator const std::string() const { return cstr_; } + + inline operator const bool() const { return cstr_ != nullptr; } + + inline auto get() const { return cstr_; } + + inline ~JUTFString() { + if (env_ && jstr_) env_->ReleaseStringUTFChars(jstr_, cstr_); + } + +private: + JNIEnv *env_; + jstring jstr_; + const char *cstr_; +}; diff --git a/edxp-core/src/main/cpp/main/src/edxp_context.cpp b/edxp-core/src/main/cpp/main/src/edxp_context.cpp index e6a3a38df..750b7a32b 100644 --- a/edxp-core/src/main/cpp/main/src/edxp_context.cpp +++ b/edxp-core/src/main/cpp/main/src/edxp_context.cpp @@ -22,27 +22,12 @@ #pragma clang diagnostic ignored "-Wunused-value" namespace edxp { - - Context *Context::instance_ = nullptr; - - Context *Context::GetInstance() { - if (instance_ == nullptr) { - instance_ = new Context(); - } - return instance_; - } - - ALWAYS_INLINE bool Context::IsInitialized() const { - return initialized_; - } - - ALWAYS_INLINE Variant Context::GetVariant() const { - return variant_; - } - - ALWAYS_INLINE jobject Context::GetCurrentClassLoader() const { - return inject_class_loader_; - } + constexpr int FIRST_ISOLATED_UID = 99000; + constexpr int LAST_ISOLATED_UID = 99999; + constexpr int FIRST_APP_ZYGOTE_ISOLATED_UID = 90000; + constexpr int LAST_APP_ZYGOTE_ISOLATED_UID = 98999; + constexpr int SHARED_RELRO_UID = 1037; + constexpr int PER_USER_RANGE = 100000; void Context::CallPostFixupStaticTrampolinesCallback(void *class_ptr, jmethodID callback_mid) { if (UNLIKELY(!callback_mid || !class_linker_class_)) { @@ -188,6 +173,28 @@ namespace edxp { LoadDexAndInit(env, kInjectDexPath); } + void Context::ReleaseJavaEnv(JNIEnv *env) { + if (UNLIKELY(!instance_)) return; + 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; + } + inline void Context::FindAndCall(JNIEnv *env, const char *method_name, const char *method_sig, ...) const { @@ -206,26 +213,6 @@ namespace edxp { } } - ALWAYS_INLINE JavaVM *Context::GetJavaVM() const { - return vm_; - } - - ALWAYS_INLINE void Context::SetAppDataDir(jstring app_data_dir) { - app_data_dir_ = app_data_dir; - } - - ALWAYS_INLINE jstring Context::GetAppDataDir() const { - return app_data_dir_; - } - - ALWAYS_INLINE void Context::SetNiceName(jstring nice_name) { - nice_name_ = nice_name; - } - - ALWAYS_INLINE jstring Context::GetNiceName() const { - return nice_name_; - } - void Context::OnNativeForkSystemServerPre(JNIEnv *env, jclass clazz, uid_t uid, gid_t gid, jintArray gids, @@ -252,6 +239,33 @@ namespace edxp { return 0; } + 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; + if (is_child_zygote) { + skip = true; + LOGW("skip injecting into %s because it's a child zygote", package_name.get()); + } + + if ((app_id >= FIRST_ISOLATED_UID && app_id <= LAST_ISOLATED_UID) || + (app_id >= FIRST_APP_ZYGOTE_ISOLATED_UID && app_id <= LAST_APP_ZYGOTE_ISOLATED_UID) || + app_id == SHARED_RELRO_UID) { + skip = true; + LOGW("skip injecting into %s because it's isolated", package_name.get()); + } + + // TODO(yujincheng08): check whitelist/blacklist. + const JUTFString dir(env, data_dir); + if(!dir || !ConfigManager::GetInstance()->IsAppNeedHook(dir)) { + skip = true; + LOGW("skip injecting xposed into %s because it's whitelisted/blacklisted", + package_name.get()); + } + return skip; + } + void Context::OnNativeForkAndSpecializePre(JNIEnv *env, jclass clazz, jint uid, jint gid, jintArray gids, @@ -265,21 +279,32 @@ namespace edxp { jboolean is_child_zygote, jstring instruction_set, jstring app_data_dir) { + skip_ = ShouldSkipInject(env, nice_name, app_data_dir, uid, is_child_zygote); app_data_dir_ = app_data_dir; nice_name_ = nice_name; PrepareJavaEnv(env); - 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); + if(!skip_) { + FindAndCall(env, "forkAndSpecializePre", + "(II[II[[IILjava/lang/String;Ljava/lang/String;[I[IZLjava/lang/String;Ljava/lang/String;)V", + uid, gid, gids, runtime_flags, rlimits, + mount_external, se_info, nice_name, fds_to_close, fds_to_ignore, + is_child_zygote, instruction_set, app_data_dir); + } } int Context::OnNativeForkAndSpecializePost(JNIEnv *env, jclass clazz, jint res) { if (res == 0) { - PrepareJavaEnv(env); - FindAndCall(env, "forkAndSpecializePost", "(ILjava/lang/String;Ljava/lang/String;)V", - res, app_data_dir_, nice_name_); + const JUTFString package_name(env, nice_name_); + if (!skip_) { + PrepareJavaEnv(env); + FindAndCall(env, "forkAndSpecializePost", + "(ILjava/lang/String;Ljava/lang/String;)V", + res, app_data_dir_, nice_name_); + LOGD("injected xposed into %s", package_name.get()); + } else { + ReleaseJavaEnv(env); + LOGD("skipped %s", package_name.get()); + } } 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/edxp-core/src/main/cpp/main/src/edxp_context.h b/edxp-core/src/main/cpp/main/src/edxp_context.h index c5cc80420..9e3a3efd1 100644 --- a/edxp-core/src/main/cpp/main/src/edxp_context.h +++ b/edxp-core/src/main/cpp/main/src/edxp_context.h @@ -18,9 +18,14 @@ namespace edxp { class Context { public: - static Context *GetInstance(); + inline static auto GetInstance() { + if (instance_ == nullptr) { + instance_ = new Context(); + } + return instance_; + } - jobject GetCurrentClassLoader() const; + inline auto GetCurrentClassLoader() const { return inject_class_loader_; } void CallOnPreFixupStaticTrampolines(void *class_ptr); @@ -30,15 +35,15 @@ namespace edxp { void FindAndCall(JNIEnv *env, const char *method_name, const char *method_sig, ...) const; - JavaVM *GetJavaVM() const; + inline auto *GetJavaVM() const { return vm_; } - void SetAppDataDir(jstring app_data_dir); + inline void SetAppDataDir(jstring app_data_dir) { app_data_dir_ = app_data_dir; } - void SetNiceName(jstring nice_name); + inline void SetNiceName(jstring nice_name) { nice_name_ = nice_name; } - jstring GetAppDataDir() const; + inline auto GetAppDataDir() const { return app_data_dir_; } - jstring GetNiceName() const; + inline auto GetNiceName() const { return nice_name_; } jclass FindClassFromLoader(JNIEnv *env, const char *className) const; @@ -58,12 +63,12 @@ namespace edxp { jlong permitted_capabilities, jlong effective_capabilities); - bool IsInitialized() const; + inline auto IsInitialized() const { return initialized_; } - Variant GetVariant() const; + inline auto GetVariant() const { return variant_; }; private: - static Context *instance_; + inline static Context *instance_; bool initialized_ = false; Variant variant_ = NONE; jobject inject_class_loader_ = nullptr; @@ -74,6 +79,7 @@ namespace edxp { jclass class_linker_class_ = nullptr; jmethodID pre_fixup_static_mid_ = nullptr; jmethodID post_fixup_static_mid_ = nullptr; + bool skip_ = false; Context() {} @@ -84,6 +90,11 @@ namespace edxp { jclass FindClassFromLoader(JNIEnv *env, jobject class_loader, const char *class_name) const; void CallPostFixupStaticTrampolinesCallback(void *class_ptr, jmethodID mid); + + static bool ShouldSkipInject(JNIEnv *env, jstring nice_name, jstring data_dir, jint uid, + jboolean is_child_zygote); + + void ReleaseJavaEnv(JNIEnv *env); }; }