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 e288b725..e8eeda96 100644 --- a/Bridge/src/main/java/com/elderdrivers/riru/xposed/Main.java +++ b/Bridge/src/main/java/com/elderdrivers/riru/xposed/Main.java @@ -123,4 +123,6 @@ public class Main implements KeepAll { public static native void closeFilesBeforeForkNative(); public static native void reopenFilesAfterForkNative(); + + public static native void deoptMethodNative(Object object); } diff --git a/Core/jni/main/inject/config_manager.cpp b/Core/jni/main/inject/config_manager.cpp index 0780718a..5af64060 100644 --- a/Core/jni/main/inject/config_manager.cpp +++ b/Core/jni/main/inject/config_manager.cpp @@ -27,10 +27,12 @@ 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 char deopt_boot_image_path[PATH_MAX]; static const char *installer_package_name; static bool black_white_list_enabled = false; static bool dynamic_modules_enabled = false; +static bool deopt_boot_image_enabled = false; static bool inited = false; static const char *get_installer_package_name() { @@ -72,8 +74,11 @@ static void init_once() { installer_package_name, "blackwhitelist"); snprintf(dynamic_modules_path, PATH_MAX, config_path_tpl, data_path_prefix, installer_package_name, "dynamicmodules"); + snprintf(deopt_boot_image_path, PATH_MAX, config_path_tpl, data_path_prefix, + installer_package_name, "deoptbootimage"); dynamic_modules_enabled = access(dynamic_modules_path, F_OK) == 0; black_white_list_enabled = access(black_white_list_path, F_OK) == 0; + deopt_boot_image_enabled = access(deopt_boot_image_path, F_OK) == 0; LOGI("black/white list mode: %d", black_white_list_enabled); LOGI("dynamic modules mode: %d", dynamic_modules_enabled); inited = true; @@ -136,7 +141,12 @@ bool is_dynamic_modules_enabled() { return dynamic_modules_enabled; } -jstring get_installer_pkg_name(JNIEnv *env) { +bool is_deopt_boot_image_enabled() { + init_once(); + return deopt_boot_image_enabled; +} + +jstring get_installer_pkg_name(JNIEnv *env, jclass) { 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 index f9561f66..8fb59259 100644 --- a/Core/jni/main/inject/config_manager.h +++ b/Core/jni/main/inject/config_manager.h @@ -5,12 +5,16 @@ #ifndef EDXPOSED_CONFIG_MANAGER_H #define EDXPOSED_CONFIG_MANAGER_H +#include + bool is_app_need_hook(JNIEnv *env, jstring appDataDir); bool is_black_white_list_enabled(); bool is_dynamic_modules_enabled(); -jstring get_installer_pkg_name(JNIEnv *env); +bool is_deopt_boot_image_enabled(); + +jstring get_installer_pkg_name(JNIEnv *env, jclass clazz); #endif //EDXPOSED_CONFIG_MANAGER_H diff --git a/Core/jni/main/java_hook/java_hook.cpp b/Core/jni/main/java_hook/java_hook.cpp index f11f35ba..2baf2a03 100644 --- a/Core/jni/main/java_hook/java_hook.cpp +++ b/Core/jni/main/java_hook/java_hook.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include "java_hook/java_hook.h" #include "include/logging.h" #include "include/fd_utils-inl.h" @@ -64,6 +65,9 @@ static JNINativeMethod hookMethods[] = { }, { "reopenFilesAfterForkNative", "()V", (void *)reopenFilesAfterForkNative + }, + { + "deoptMethodNative", "(Ljava/lang/Object;)V", (void *)deoptimize_method } }; @@ -102,7 +106,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, 7); + env->RegisterNatives(entry_class, hookMethods, 8); isInited = true; LOGD("RegisterNatives succeed for HookEntry."); } else { diff --git a/Core/jni/main/native_hook/native_hook.cpp b/Core/jni/main/native_hook/native_hook.cpp index 71cb767d..3bb3fb11 100644 --- a/Core/jni/main/native_hook/native_hook.cpp +++ b/Core/jni/main/native_hook/native_hook.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include "include/logging.h" #include "native_hook.h" @@ -13,12 +14,20 @@ static const char *(*getDesc)(void *, std::string *); static bool (*isInSamePackageBackup)(void *, void *) = nullptr; +// runtime void *runtime_ = nullptr; void (*deoptBootImage)(void *runtime) = nullptr; bool (*runtimeInitBackup)(void *runtime, void *mapAddr) = nullptr; +// instrumentation +void *instru_ = nullptr; + +static void *(*instrCstBackup)(void *instru) = nullptr; + +void (*deoptMethod)(void *, void *) = nullptr; + bool my_runtimeInit(void *runtime, void *mapAddr) { if (!runtimeInitBackup) { LOGE("runtimeInitBackup is null"); @@ -45,7 +54,6 @@ static bool onIsInSamePackageCalled(void *thiz, void *that) { || strstr(thatDesc, "EdHooker") != nullptr || strstr(thisDesc, "com/elderdrivers/riru/") != nullptr || strstr(thatDesc, "com/elderdrivers/riru/") != nullptr) { -// LOGE("onIsInSamePackageCalled, %s -> %s", thisDesc, thatDesc); return true; } return (*isInSamePackageBackup)(thiz, that); @@ -61,8 +69,8 @@ static bool onInvokeHiddenAPI() { * But we don't know the symbols until it's published. * @author asLody */ -static bool disable_HiddenAPIPolicyImpl(int api_level, void *artHandle, - void (*hookFun)(void *, void *, void **)) { +static bool disableHiddenAPIPolicyImpl(int api_level, void *artHandle, + void (*hookFun)(void *, void *, void **)) { if (api_level < ANDROID_P) { return true; } @@ -121,7 +129,63 @@ static void hookIsInSamePackage(int api_level, void *artHandle, reinterpret_cast(&isInSamePackageBackup)); } +void *my_instruCst(void *instru) { + if (!instrCstBackup) { + LOGE("instrCstBackup is null"); + return instru; + } + LOGI("instrCst starts"); + void *result = (*instrCstBackup)(instru); + LOGI("instrCst finishes"); + if (instru_ != instru) { + LOGI("instru_ changed from %p to %p", instru_, instru); + instru_ = instru; + } + return result; +} + +void hookInstrumentation(int api_level, void *artHandle, void (*hookFun)(void *, void *, void **)) { + if (api_level < ANDROID_P) { + // TODO support other api levels + return; + } + void *instruCstSym = dlsym(artHandle, + "_ZN3art15instrumentation15InstrumentationC2Ev"); + deoptMethod = reinterpret_cast( + dlsym(artHandle, + "_ZN3art15instrumentation15Instrumentation40UpdateMethodsCodeToInterpreterEntryPointEPNS_9ArtMethodE")); + if (!instruCstSym) { + LOGE("can't get instruCstSym: %s", dlerror()); + return; + } + (*hookFun)(instruCstSym, reinterpret_cast(my_instruCst), + reinterpret_cast(&instrCstBackup)); + LOGI("instrCst hooked"); +} + +std::vector deoptedMethods; + +void deoptimize_method(JNIEnv *env, jclass clazz, jobject method) { + if (!deoptMethod) { + LOGE("deoptMethodSym is null, skip deopt"); + return; + } + void *reflected_method = env->FromReflectedMethod(method); + if (std::find(deoptedMethods.begin(), deoptedMethods.end(), reflected_method) != + deoptedMethods.end()) { + LOGD("method %p has been deopted before, skip...", reflected_method); + return; + } + LOGD("deoptimize method: %p", reflected_method); + (*deoptMethod)(instru_, reflected_method); + deoptedMethods.push_back(reflected_method); + LOGD("deoptimize method done: %p"); +} + void hookRuntime(int api_level, void *artHandle, void (*hookFun)(void *, void *, void **)) { + if (!is_deopt_boot_image_enabled()) { + return; + } void *runtimeInitSym = nullptr; if (api_level >= ANDROID_O) { // only oreo has deoptBootImageSym in Runtime @@ -177,12 +241,13 @@ void install_inline_hooks() { LOGE("can't open libart: %s", dlerror()); return; } - hookIsInSamePackage(api_level, artHandle, hookFun); hookRuntime(api_level, artHandle, hookFun); - if (disable_HiddenAPIPolicyImpl(api_level, artHandle, hookFun)) { - LOGI("disable_HiddenAPIPolicyImpl done."); + hookInstrumentation(api_level, artHandle, hookFun); + hookIsInSamePackage(api_level, artHandle, hookFun); + if (disableHiddenAPIPolicyImpl(api_level, artHandle, hookFun)) { + LOGI("disableHiddenAPIPolicyImpl done."); } else { - LOGE("disable_HiddenAPIPolicyImpl failed."); + LOGE("disableHiddenAPIPolicyImpl failed."); } dlclose(whaleHandle); dlclose(artHandle); diff --git a/Core/jni/main/native_hook/native_hook.h b/Core/jni/main/native_hook/native_hook.h index fab2f98b..e9843289 100644 --- a/Core/jni/main/native_hook/native_hook.h +++ b/Core/jni/main/native_hook/native_hook.h @@ -21,4 +21,6 @@ static constexpr const char *kLibWhalePath = "/system/lib/libwhale.so"; void install_inline_hooks(); +void deoptimize_method(JNIEnv *env, jclass clazz, jobject method); + #endif // HOOK_H