From bf89c754dcdc017cc5f4d5aa7f98cfbe5c55aa0f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=AE=8B=E9=A1=B5?= <31466456+canyie@users.noreply.github.com> Date: Tue, 21 Sep 2021 17:00:54 +0800 Subject: [PATCH] [core] Clear ProfilingInfo in backup method (#1147) Co-authored-by: vvb2060 --- .../src/main/cpp/external/yahfa/include/HookMain.h | 2 +- core/src/main/cpp/external/yahfa/src/HookMain.cpp | 14 ++++++++++---- core/src/main/cpp/main/src/jni/yahfa.cpp | 6 +++--- .../java/org/lsposed/lspd/core/yahfa/HookMain.java | 7 ++++++- .../java/org/lsposed/lspd/nativebridge/Yahfa.java | 2 +- 5 files changed, 21 insertions(+), 10 deletions(-) diff --git a/core/src/main/cpp/external/yahfa/include/HookMain.h b/core/src/main/cpp/external/yahfa/include/HookMain.h index 4e0b77f1..c9d6e178 100644 --- a/core/src/main/cpp/external/yahfa/include/HookMain.h +++ b/core/src/main/cpp/external/yahfa/include/HookMain.h @@ -17,7 +17,7 @@ namespace yahfa { jboolean backupAndHookNative(JNIEnv *env, jclass clazz, jobject target, jobject hook, - jobject backup); + jobject backup, jboolean clearData); void *getArtMethod(JNIEnv *env, jobject jmethod); diff --git a/core/src/main/cpp/external/yahfa/src/HookMain.cpp b/core/src/main/cpp/external/yahfa/src/HookMain.cpp index 0997d3b7..9d5abf1c 100644 --- a/core/src/main/cpp/external/yahfa/src/HookMain.cpp +++ b/core/src/main/cpp/external/yahfa/src/HookMain.cpp @@ -9,6 +9,7 @@ int SDKVersion; size_t OFFSET_entry_point_from_quick_compiled_code_in_ArtMethod; +size_t OFFSET_data_in_ArtMethod; namespace yahfa { namespace { @@ -57,7 +58,7 @@ namespace yahfa { } } - int doBackupAndHook(void *targetMethod, void *hookMethod, void *backupMethod) { + int doBackupAndHook(void *targetMethod, void *hookMethod, void *backupMethod, bool clearData) { LOGI("target method is at %p, hook method is at %p, backup method is at %p", targetMethod, hookMethod, backupMethod); @@ -101,6 +102,9 @@ namespace yahfa { setAccessFlags(targetMethod, access_flags); } + if (clearData) + writeAddr((char *) backupMethod + OFFSET_data_in_ArtMethod, nullptr); + LOGI("hook and backup done"); return 0; } @@ -136,6 +140,7 @@ namespace yahfa { LOGE("not compatible with SDK %d", sdkVersion); break; } + OFFSET_data_in_ArtMethod = OFFSET_entry_point_from_quick_compiled_code_in_ArtMethod - pointer_size; setupTrampoline(); } @@ -184,13 +189,14 @@ namespace yahfa { return ret; } - jboolean backupAndHookNative(JNIEnv *env, [[maybe_unused]] jclass clazz, + jboolean backupAndHookNative(JNIEnv *env, jclass, jobject target, jobject hook, - jobject backup) { + jobject backup, jboolean clearData) { if (!doBackupAndHook(getArtMethod(env, target), getArtMethod(env, hook), - getArtMethod(env, backup) + getArtMethod(env, backup), + clearData == JNI_TRUE )) { env->NewGlobalRef(hook); // keep a global ref so that the hook method would not be GCed if (backup) env->NewGlobalRef(backup); diff --git a/core/src/main/cpp/main/src/jni/yahfa.cpp b/core/src/main/cpp/main/src/jni/yahfa.cpp index 72fd92fe..4b4f04dc 100644 --- a/core/src/main/cpp/main/src/jni/yahfa.cpp +++ b/core/src/main/cpp/main/src/jni/yahfa.cpp @@ -42,12 +42,12 @@ namespace lspd { } LSP_DEF_NATIVE_METHOD(jboolean, Yahfa, backupAndHookNative, jobject target, - jobject hook, jobject backup) { + jobject hook, jobject backup, jboolean clearData) { art::gc::ScopedGCCriticalSection section(art::Thread::Current().Get(), art::gc::kGcCauseDebugger, art::gc::kCollectorTypeDebugger); art::thread_list::ScopedSuspendAll suspend("Yahfa Hook", false); - return yahfa::backupAndHookNative(env, clazz, target, hook, backup); + return yahfa::backupAndHookNative(env, clazz, target, hook, backup, clearData); } LSP_DEF_NATIVE_METHOD(void, Yahfa, recordHooked, jobject member) { @@ -172,7 +172,7 @@ namespace lspd { LSP_NATIVE_METHOD(Yahfa, findMethodNative, "(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;)Ljava/lang/reflect/Executable;"), LSP_NATIVE_METHOD(Yahfa, backupAndHookNative, - "(Ljava/lang/reflect/Executable;Ljava/lang/reflect/Method;Ljava/lang/reflect/Method;)Z"), + "(Ljava/lang/reflect/Executable;Ljava/lang/reflect/Method;Ljava/lang/reflect/Method;Z)Z"), LSP_NATIVE_METHOD(Yahfa, recordHooked, "(Ljava/lang/reflect/Executable;)V"), LSP_NATIVE_METHOD(Yahfa, isHooked, "(Ljava/lang/reflect/Executable;)Z"), LSP_NATIVE_METHOD(Yahfa, buildHooker, diff --git a/core/src/main/java/org/lsposed/lspd/core/yahfa/HookMain.java b/core/src/main/java/org/lsposed/lspd/core/yahfa/HookMain.java index c89b189e..a3c315b7 100644 --- a/core/src/main/java/org/lsposed/lspd/core/yahfa/HookMain.java +++ b/core/src/main/java/org/lsposed/lspd/core/yahfa/HookMain.java @@ -27,6 +27,7 @@ import java.lang.reflect.Constructor; import java.lang.reflect.Executable; import java.lang.reflect.Method; import java.lang.reflect.Modifier; +import java.lang.reflect.Proxy; import java.util.ArrayList; import java.util.Arrays; @@ -51,7 +52,11 @@ public class HookMain { // backup is just a placeholder and the constraint could be less strict checkCompatibleMethods(target, backup, "Backup"); } - if(!Yahfa.backupAndHookNative(target, hook, backup)){ + // Since Android 7.0, the data_ member is used to save a profiling info which used for optimizing + // This may cause some crashes, clear the member to avoid it + // Note that this cannot be applied to native and proxy methods as their data_ member has been used for other purposes + boolean clearData = !(Modifier.isNative(target.getModifiers()) || Proxy.isProxyClass(target.getDeclaringClass())); + if(!Yahfa.backupAndHookNative(target, hook, backup, clearData)) { throw new RuntimeException("Failed to hook " + target + " with " + hook); } else { Yahfa.recordHooked(target); diff --git a/core/src/main/java/org/lsposed/lspd/nativebridge/Yahfa.java b/core/src/main/java/org/lsposed/lspd/nativebridge/Yahfa.java index 4105f2f4..33f3cf5c 100644 --- a/core/src/main/java/org/lsposed/lspd/nativebridge/Yahfa.java +++ b/core/src/main/java/org/lsposed/lspd/nativebridge/Yahfa.java @@ -25,7 +25,7 @@ import java.lang.reflect.Method; public class Yahfa { - public static native boolean backupAndHookNative(Executable target, Method hook, Method backup); + public static native boolean backupAndHookNative(Executable target, Method hook, Method backup, boolean clearData); // JNI.ToReflectedMethod() could return either Method or Constructor public static native Executable findMethodNative(Class targetClass, String methodName, String methodSig);