From 628d4e7ab0f0d09c425d94bf165f7d68d9063953 Mon Sep 17 00:00:00 2001 From: solohsu Date: Wed, 27 Feb 2019 01:38:40 +0800 Subject: [PATCH] Add an interface to deoptimize specified ArtMethod for Android Pie --- .../com/elderdrivers/riru/xposed/Main.java | 2 + Core/jni/main/inject/config_manager.cpp | 2 +- Core/jni/main/inject/config_manager.h | 2 +- Core/jni/main/java_hook/java_hook.cpp | 6 +- Core/jni/main/native_hook/native_hook.cpp | 75 +++++++++++++++++-- Core/jni/main/native_hook/native_hook.h | 2 + 6 files changed, 79 insertions(+), 10 deletions(-) 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..b8447eeb 100644 --- a/Core/jni/main/inject/config_manager.cpp +++ b/Core/jni/main/inject/config_manager.cpp @@ -136,7 +136,7 @@ bool is_dynamic_modules_enabled() { return dynamic_modules_enabled; } -jstring get_installer_pkg_name(JNIEnv *env) { +jstring get_installer_pkg_name(JNIEnv *env, jclass clazz) { 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..8bd831c7 100644 --- a/Core/jni/main/inject/config_manager.h +++ b/Core/jni/main/inject/config_manager.h @@ -11,6 +11,6 @@ bool is_black_white_list_enabled(); bool is_dynamic_modules_enabled(); -jstring get_installer_pkg_name(JNIEnv *env); +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..5a2b9808 100644 --- a/Core/jni/main/native_hook/native_hook.cpp +++ b/Core/jni/main/native_hook/native_hook.cpp @@ -13,12 +13,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 +53,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 +68,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,6 +128,59 @@ 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 **)) { void *runtimeInitSym = nullptr; if (api_level >= ANDROID_O) { @@ -177,12 +237,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