From 2ac5eb19c967f37e16f293cb8141d56dd74c30af Mon Sep 17 00:00:00 2001 From: solohsu Date: Thu, 28 Feb 2019 18:05:01 +0800 Subject: [PATCH] Suspend all threads when doing hook stuffs to prevent crashes caused by GC --- .../com/elderdrivers/riru/xposed/Main.java | 4 ++ .../riru/xposed/core/HookMain.java | 10 ++++- Core/jni/main/java_hook/java_hook.cpp | 38 +++++++++++++++---- Core/jni/main/native_hook/native_hook.cpp | 14 +++++++ Core/jni/main/native_hook/native_hook.h | 7 ++++ 5 files changed, 63 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 e8eeda96..504a308d 100644 --- a/Bridge/src/main/java/com/elderdrivers/riru/xposed/Main.java +++ b/Bridge/src/main/java/com/elderdrivers/riru/xposed/Main.java @@ -125,4 +125,8 @@ public class Main implements KeepAll { public static native void reopenFilesAfterForkNative(); public static native void deoptMethodNative(Object object); + + public static native long suspendAllThreads(); + + public static native void resumeAllThreads(long obj); } diff --git a/Bridge/src/main/java/com/elderdrivers/riru/xposed/core/HookMain.java b/Bridge/src/main/java/com/elderdrivers/riru/xposed/core/HookMain.java index 21ad22f1..89413aed 100644 --- a/Bridge/src/main/java/com/elderdrivers/riru/xposed/core/HookMain.java +++ b/Bridge/src/main/java/com/elderdrivers/riru/xposed/core/HookMain.java @@ -1,5 +1,6 @@ package com.elderdrivers.riru.xposed.core; +import com.elderdrivers.riru.xposed.Main; import com.elderdrivers.riru.xposed.entry.hooker.OnePlusWorkAroundHooker; import com.elderdrivers.riru.xposed.util.Utils; @@ -111,8 +112,13 @@ public class HookMain { if (backup != null) { HookMethodResolver.resolveMethod(hook, backup); } - if (!backupAndHookNative(target, hook, backup)) { - throw new RuntimeException("Failed to hook " + target + " with " + hook); + long obj = Main.suspendAllThreads(); + try { + if (!backupAndHookNative(target, hook, backup)) { + throw new RuntimeException("Failed to hook " + target + " with " + hook); + } + } finally { + Main.resumeAllThreads(obj); } } diff --git a/Core/jni/main/java_hook/java_hook.cpp b/Core/jni/main/java_hook/java_hook.cpp index 2baf2a03..76f086f6 100644 --- a/Core/jni/main/java_hook/java_hook.cpp +++ b/Core/jni/main/java_hook/java_hook.cpp @@ -20,13 +20,13 @@ jobject gInjectDexClassLoader; static bool isInited = false; -static FileDescriptorTable* gClosedFdTable = nullptr; +static FileDescriptorTable *gClosedFdTable = nullptr; -void closeFilesBeforeForkNative(JNIEnv*, jclass) { +void closeFilesBeforeForkNative(JNIEnv *, jclass) { gClosedFdTable = FileDescriptorTable::Create(); } -void reopenFilesAfterForkNative(JNIEnv*, jclass) { +void reopenFilesAfterForkNative(JNIEnv *, jclass) { if (!gClosedFdTable) { LOGE("gClosedFdTable is null when reopening files"); return; @@ -36,6 +36,22 @@ void reopenFilesAfterForkNative(JNIEnv*, jclass) { gClosedFdTable = nullptr; } +jlong suspendAllThreads(JNIEnv *, jclass) { + if (!suspendAll) { + return 0; + } + ScopedSuspendAll *suspendAllObj = (ScopedSuspendAll *) malloc(sizeof(ScopedSuspendAll)); + suspendAll(suspendAllObj, "edxp_stop_gc", false); + return reinterpret_cast(suspendAllObj); +} + +void resumeAllThreads(JNIEnv *, jclass, jlong obj) { + if (!resumeAll) { + return; + } + resumeAll(reinterpret_cast(obj)); +} + static JNINativeMethod hookMethods[] = { { "init", @@ -58,16 +74,22 @@ static JNINativeMethod hookMethods[] = { (void *) Java_lab_galaxy_yahfa_HookMain_ensureMethodCached }, { - "getInstallerPkgName", "()Ljava/lang/String;", (void *)get_installer_pkg_name + "getInstallerPkgName", "()Ljava/lang/String;", (void *) get_installer_pkg_name }, { - "closeFilesBeforeForkNative", "()V", (void *)closeFilesBeforeForkNative + "closeFilesBeforeForkNative", "()V", (void *) closeFilesBeforeForkNative }, { - "reopenFilesAfterForkNative", "()V", (void *)reopenFilesAfterForkNative + "reopenFilesAfterForkNative", "()V", (void *) reopenFilesAfterForkNative }, { - "deoptMethodNative", "(Ljava/lang/Object;)V", (void *)deoptimize_method + "deoptMethodNative", "(Ljava/lang/Object;)V", (void *) deoptimize_method + }, + { + "suspendAllThreads", "()J", (void *) suspendAllThreads + }, + { + "resumeAllThreads", "(J)V", (void *) resumeAllThreads } }; @@ -106,7 +128,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, 8); + env->RegisterNatives(entry_class, hookMethods, 10); 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 3bb3fb11..4b9e3c7e 100644 --- a/Core/jni/main/native_hook/native_hook.cpp +++ b/Core/jni/main/native_hook/native_hook.cpp @@ -212,6 +212,19 @@ void hookRuntime(int api_level, void *artHandle, void (*hookFun)(void *, void *, } } +void (*suspendAll)(ScopedSuspendAll*, const char*, bool) = nullptr; +void (*resumeAll)(ScopedSuspendAll*) = nullptr; + +void getSuspendSyms(int api_level, void *artHandle, void (*hookFun)(void *, void *, void **)) { + if (api_level < ANDROID_N) { + return; + } + suspendAll = reinterpret_cast(dlsym(artHandle, + "_ZN3art16ScopedSuspendAllC2EPKcb")); + resumeAll = reinterpret_cast(dlsym(artHandle, + "_ZN3art16ScopedSuspendAllD2Ev")); +} + void install_inline_hooks() { if (inlineHooksInstalled) { LOGI("inline hooks installed, skip"); @@ -243,6 +256,7 @@ void install_inline_hooks() { } hookRuntime(api_level, artHandle, hookFun); hookInstrumentation(api_level, artHandle, hookFun); + getSuspendSyms(api_level, artHandle, hookFun); hookIsInSamePackage(api_level, artHandle, hookFun); if (disableHiddenAPIPolicyImpl(api_level, artHandle, hookFun)) { LOGI("disableHiddenAPIPolicyImpl done."); diff --git a/Core/jni/main/native_hook/native_hook.h b/Core/jni/main/native_hook/native_hook.h index e9843289..eedb5e94 100644 --- a/Core/jni/main/native_hook/native_hook.h +++ b/Core/jni/main/native_hook/native_hook.h @@ -19,6 +19,13 @@ static constexpr const char *kLibWhalePath = "/system/lib/libwhale.so"; static ret (*old_##func)(__VA_ARGS__); \ static ret new_##func(__VA_ARGS__) +class ScopedSuspendAll { +}; + +extern void (*suspendAll)(ScopedSuspendAll *, const char *, bool); + +extern void (*resumeAll)(ScopedSuspendAll *); + void install_inline_hooks(); void deoptimize_method(JNIEnv *env, jclass clazz, jobject method);