From b04d830fba16b9ac92bc9e3aac56694387dadea2 Mon Sep 17 00:00:00 2001 From: LoveSy Date: Thu, 28 Jan 2021 17:44:46 +0800 Subject: [PATCH] Revert YAHFA to the version where backup are memcpied --- .../cpp/external/yahfa/include/HookMain.h | 17 +- .../cpp/external/yahfa/include/trampoline.h | 13 +- .../main/cpp/external/yahfa/src/HookMain.c | 252 +++++++++++++++++ .../main/cpp/external/yahfa/src/HookMain.cpp | 257 ------------------ .../main/cpp/external/yahfa/src/trampoline.c | 151 +++------- .../include/art/runtime/jit/jit_code_cache.h | 24 +- .../main/include/art/runtime/mirror/class.h | 2 +- .../cpp/main/include/art/runtime/reflection.h | 28 ++ .../src/main/cpp/main/src/jni/edxp_yahfa.cpp | 15 - .../src/main/cpp/main/src/native_hook.cpp | 2 + .../elderdrivers/riru/edxp/core/Yahfa.java | 2 - .../riru/edxp/core/yahfa/HookMain.java | 109 +------- .../riru/edxp/proxy/BaseRouter.java | 60 ++-- .../edxp/sandhook/core/SandHookRouter.java | 1 - .../riru/edxp/yahfa/core/YahfaRouter.java | 2 - .../edxp/yahfa/dexmaker/DynamicBridge.java | 12 +- .../de/robv/android/xposed/LspHooker.java | 50 ++-- 17 files changed, 398 insertions(+), 599 deletions(-) create mode 100644 edxp-core/src/main/cpp/external/yahfa/src/HookMain.c delete mode 100644 edxp-core/src/main/cpp/external/yahfa/src/HookMain.cpp create mode 100644 edxp-core/src/main/cpp/main/include/art/runtime/reflection.h diff --git a/edxp-core/src/main/cpp/external/yahfa/include/HookMain.h b/edxp-core/src/main/cpp/external/yahfa/include/HookMain.h index f61ced19..70bf4e4f 100644 --- a/edxp-core/src/main/cpp/external/yahfa/include/HookMain.h +++ b/edxp-core/src/main/cpp/external/yahfa/include/HookMain.h @@ -17,21 +17,12 @@ jboolean Java_lab_galaxy_yahfa_HookMain_backupAndHookNative(JNIEnv *env, jclass jobject target, jobject hook, jobject backup); -void Java_lab_galaxy_yahfa_HookMain_ensureMethodCached(JNIEnv *env, jclass clazz, - jobject hook, - jobject backup); -#ifdef __cplusplus -} -#endif void setNonCompilable(void *method); void *getArtMethod(JNIEnv *env, jobject jmethod); -// TODO: move to common utils instead of in YAHFA's code -void *getEntryPoint(void* method); +#ifdef __cplusplus +} +#endif -// get original entrypoint from target ArtMethod -void *getOriginalEntryPointFromTargetMethod(void* method); - - -#endif // HOOK_MAIN_H \ No newline at end of file +#endif // HOOK_MAIN_H diff --git a/edxp-core/src/main/cpp/external/yahfa/include/trampoline.h b/edxp-core/src/main/cpp/external/yahfa/include/trampoline.h index 3d5b7b47..69fd7458 100644 --- a/edxp-core/src/main/cpp/external/yahfa/include/trampoline.h +++ b/edxp-core/src/main/cpp/external/yahfa/include/trampoline.h @@ -6,12 +6,17 @@ #define YAHFA_TAMPOLINE_H extern int SDKVersion; +extern int OFFSET_entry_point_from_quick_compiled_code_in_ArtMethod; + +extern unsigned int hookCap; // capacity for trampolines +extern unsigned int hookCount; // current count of used trampolines extern unsigned char trampoline[]; -extern unsigned char trampolineForBackup[]; -void* doInitHookCap(size_t cap); -void setupTrampoline(uint8_t offset); -void *genTrampoline(void *toMethod, void *entrypoint); +int doInitHookCap(unsigned int cap); +void setupTrampoline(); +void *genTrampoline(void *hookMethod); + +#define DEFAULT_CAP 1 //size of each trampoline area would be no more than 4k Bytes(one page) #endif //YAHFA_TAMPOLINE_H diff --git a/edxp-core/src/main/cpp/external/yahfa/src/HookMain.c b/edxp-core/src/main/cpp/external/yahfa/src/HookMain.c new file mode 100644 index 00000000..1532645d --- /dev/null +++ b/edxp-core/src/main/cpp/external/yahfa/src/HookMain.c @@ -0,0 +1,252 @@ +#include "jni.h" +#include +#include +#include +#include + +#include "common.h" +#include "trampoline.h" +#include "HookMain.h" + +int SDKVersion; +static int OFFSET_entry_point_from_interpreter_in_ArtMethod; +int OFFSET_entry_point_from_quick_compiled_code_in_ArtMethod; +static int OFFSET_ArtMehod_in_Object; +static int OFFSET_access_flags_in_ArtMethod; +static size_t ArtMethodSize; +static uint32_t kAccCompileDontBother = 0x01000000; +static uint32_t kAccPublic = 0x0001; // class, field, method, ic +static uint32_t kAccPrivate = 0x0002; // field, method, ic +static uint32_t kAccProtected = 0x0004; // field, method, ic +static uint32_t kAccStatic = 0x0008; // field, method, ic + + +static jfieldID fieldArtMethod = NULL; + +static inline uint32_t read32(void *addr) { + return *((uint32_t *) addr); +} + +static inline void write32(void *addr, uint32_t value) { + *((uint32_t *) addr) = value; +} + +static inline void *readAddr(void *addr) { + return *((void **) addr); +} + +static inline void writeAddr(void *addr, void *value) { + *((void **) addr) = value; +} + +void Java_lab_galaxy_yahfa_HookMain_init(JNIEnv *env, jclass clazz, jint sdkVersion) { + SDKVersion = sdkVersion; + jclass classExecutable; + LOGI("init to SDK %d", sdkVersion); + switch (sdkVersion) { + case __ANDROID_API_R__: + classExecutable = (*env)->FindClass(env, "java/lang/reflect/Executable"); + fieldArtMethod = (*env)->GetFieldID(env, classExecutable, "artMethod", "J"); + case __ANDROID_API_Q__: + case __ANDROID_API_P__: + kAccCompileDontBother = 0x02000000; + OFFSET_ArtMehod_in_Object = 0; + OFFSET_access_flags_in_ArtMethod = 4; + OFFSET_entry_point_from_quick_compiled_code_in_ArtMethod = + roundUpToPtrSize(4 * 4 + 2 * 2) + pointer_size; + ArtMethodSize = roundUpToPtrSize(4 * 4 + 2 * 2) + pointer_size * 2; + break; + case __ANDROID_API_O_MR1__: + kAccCompileDontBother = 0x02000000; + case __ANDROID_API_O__: + OFFSET_ArtMehod_in_Object = 0; + OFFSET_access_flags_in_ArtMethod = 4; + OFFSET_entry_point_from_quick_compiled_code_in_ArtMethod = + roundUpToPtrSize(4 * 4 + 2 * 2) + pointer_size * 2; + ArtMethodSize = roundUpToPtrSize(4 * 4 + 2 * 2) + pointer_size * 3; + break; + case __ANDROID_API_N_MR1__: + case __ANDROID_API_N__: + OFFSET_ArtMehod_in_Object = 0; + OFFSET_access_flags_in_ArtMethod = 4; // sizeof(GcRoot) = 4 + // ptr_sized_fields_ is rounded up to pointer_size in ArtMethod + OFFSET_entry_point_from_quick_compiled_code_in_ArtMethod = + roundUpToPtrSize(4 * 4 + 2 * 2) + pointer_size * 3; + + ArtMethodSize = roundUpToPtrSize(4 * 4 + 2 * 2) + pointer_size * 4; + break; + case __ANDROID_API_M__: + OFFSET_ArtMehod_in_Object = 0; + OFFSET_entry_point_from_interpreter_in_ArtMethod = roundUpToPtrSize(4 * 7); + OFFSET_entry_point_from_quick_compiled_code_in_ArtMethod = + OFFSET_entry_point_from_interpreter_in_ArtMethod + pointer_size * 2; + ArtMethodSize = roundUpToPtrSize(4 * 7) + pointer_size * 3; + break; + case __ANDROID_API_L_MR1__: + OFFSET_ArtMehod_in_Object = 4 * 2; + OFFSET_entry_point_from_interpreter_in_ArtMethod = roundUpToPtrSize( + OFFSET_ArtMehod_in_Object + 4 * 7); + OFFSET_entry_point_from_quick_compiled_code_in_ArtMethod = + OFFSET_entry_point_from_interpreter_in_ArtMethod + pointer_size * 2; + ArtMethodSize = OFFSET_entry_point_from_interpreter_in_ArtMethod + pointer_size * 3; + break; + case __ANDROID_API_L__: + OFFSET_ArtMehod_in_Object = 4 * 2; + OFFSET_entry_point_from_interpreter_in_ArtMethod = OFFSET_ArtMehod_in_Object + 4 * 4; + OFFSET_entry_point_from_quick_compiled_code_in_ArtMethod = + OFFSET_entry_point_from_interpreter_in_ArtMethod + 8 * 2; + ArtMethodSize = OFFSET_ArtMehod_in_Object + 4 * 4 + 8 * 4 + 4 * 4; + break; + default: + LOGE("not compatible with SDK %d", sdkVersion); + break; + } + + setupTrampoline(); +} + +void setNonCompilable(void *method) { + if (SDKVersion < __ANDROID_API_N__) { + return; + } + uint32_t access_flags = read32((char *) method + OFFSET_access_flags_in_ArtMethod); + LOGI("setNonCompilable: access flags is 0x%x", access_flags); + access_flags |= kAccCompileDontBother; + write32((char *) method + OFFSET_access_flags_in_ArtMethod, access_flags); +} + +void setPrivate(void *method) { + uint32_t access_flags = read32((char *) method + OFFSET_access_flags_in_ArtMethod); + if (!(access_flags & kAccStatic)) { + LOGI("setPrivate: access flags is 0x%x", access_flags); + access_flags |= kAccPrivate; + access_flags &= ~kAccProtected; + access_flags &= ~kAccPublic; + write32((char *) method + OFFSET_access_flags_in_ArtMethod, access_flags); + } +} + +static int doBackupAndHook(JNIEnv *env, void *targetMethod, void *hookMethod, void *backupMethod) { + if (hookCount >= hookCap) { + LOGI("not enough capacity. Allocating..."); + if (doInitHookCap(DEFAULT_CAP)) { + LOGE("cannot hook method"); + return 1; + } + LOGI("Allocating done"); + } + + LOGI("target method is at %p, hook method is at %p, backup method is at %p", + targetMethod, hookMethod, backupMethod); + + + // set kAccCompileDontBother for a method we do not want the compiler to compile + // so that we don't need to worry about hotness_count_ + if (SDKVersion >= __ANDROID_API_N__) { + setNonCompilable(targetMethod); + setNonCompilable(hookMethod); + } + + if (backupMethod) {// do method backup + // have to copy the whole target ArtMethod here + // if the target method calls other methods which are to be resolved + // then ToDexPC would be invoked for the caller(origin method) + // in which case ToDexPC would use the entrypoint as a base for mapping pc to dex offset + // so any changes to the target method's entrypoint would result in a wrong dex offset + // and artQuickResolutionTrampoline would fail for methods called by the origin method + memcpy(backupMethod, targetMethod, ArtMethodSize); + setPrivate(backupMethod); + } + + // replace entry point + void *newEntrypoint = genTrampoline(hookMethod); + LOGI("origin ep is %p, new ep is %p", + readAddr((char *) targetMethod + OFFSET_entry_point_from_quick_compiled_code_in_ArtMethod), + newEntrypoint + ); + if (newEntrypoint) { + writeAddr((char *) targetMethod + OFFSET_entry_point_from_quick_compiled_code_in_ArtMethod, + newEntrypoint); + } else { + LOGE("failed to allocate space for trampoline of target method"); + return 1; + } + + if (OFFSET_entry_point_from_interpreter_in_ArtMethod != 0) { + writeAddr((char *) targetMethod + OFFSET_entry_point_from_interpreter_in_ArtMethod, + readAddr((char *) hookMethod + OFFSET_entry_point_from_interpreter_in_ArtMethod)); + + } + + // set the target method to native so that Android O wouldn't invoke it with interpreter + if (SDKVersion >= __ANDROID_API_O__) { +// setNativeFlag(targetMethod, true); + } + + LOGI("hook and backup done"); + hookCount += 1; + return 0; +} + +void *getArtMethod(JNIEnv *env, jobject jmethod) { + void *artMethod = NULL; + + if (jmethod == NULL) { + return artMethod; + } + + if (SDKVersion == __ANDROID_API_R__) { + artMethod = (void *) (*env)->GetLongField(env, jmethod, fieldArtMethod); + } else { + artMethod = (void *) (*env)->FromReflectedMethod(env, jmethod); + } + + LOGI("ArtMethod: %p", artMethod); + return artMethod; + +} + +jobject Java_lab_galaxy_yahfa_HookMain_findMethodNative(JNIEnv *env, jclass clazz, + jclass targetClass, jstring methodName, + jstring methodSig) { + const char *c_methodName = (*env)->GetStringUTFChars(env, methodName, NULL); + const char *c_methodSig = (*env)->GetStringUTFChars(env, methodSig, NULL); + jobject ret = NULL; + + + //Try both GetMethodID and GetStaticMethodID -- Whatever works :) + jmethodID method = (*env)->GetMethodID(env, targetClass, c_methodName, c_methodSig); + if (!(*env)->ExceptionCheck(env)) { + ret = (*env)->ToReflectedMethod(env, targetClass, method, JNI_FALSE); + } else { + (*env)->ExceptionClear(env); + method = (*env)->GetStaticMethodID(env, targetClass, c_methodName, c_methodSig); + if (!(*env)->ExceptionCheck(env)) { + ret = (*env)->ToReflectedMethod(env, targetClass, method, JNI_TRUE); + } else { + (*env)->ExceptionClear(env); + } + } + + (*env)->ReleaseStringUTFChars(env, methodName, c_methodName); + (*env)->ReleaseStringUTFChars(env, methodSig, c_methodSig); + return ret; +} + +jboolean Java_lab_galaxy_yahfa_HookMain_backupAndHookNative(JNIEnv *env, jclass clazz, + jobject target, jobject hook, + jobject backup) { + + if (!doBackupAndHook(env, + getArtMethod(env, target), + getArtMethod(env, hook), + getArtMethod(env, backup) + )) { + (*env)->NewGlobalRef(env, + hook); // keep a global ref so that the hook method would not be GCed + if (backup) (*env)->NewGlobalRef(env, backup); + return JNI_TRUE; + } else { + return JNI_FALSE; + } +} diff --git a/edxp-core/src/main/cpp/external/yahfa/src/HookMain.cpp b/edxp-core/src/main/cpp/external/yahfa/src/HookMain.cpp deleted file mode 100644 index 9f9f21e0..00000000 --- a/edxp-core/src/main/cpp/external/yahfa/src/HookMain.cpp +++ /dev/null @@ -1,257 +0,0 @@ -#include "jni.h" -#include -#include -#include - -#include "common.h" -#include "HookMain.h" - -extern "C" { -#include "trampoline.h" -} - -int SDKVersion; -namespace { - uint32_t OFFSET_entry_point_from_interpreter_in_ArtMethod; - uint32_t OFFSET_entry_point_from_quick_compiled_code_in_ArtMethod; - uint32_t OFFSET_ArtMehod_in_Object; - uint32_t OFFSET_access_flags_in_ArtMethod; - uint32_t kAccCompileDontBother = 0x01000000; - uint32_t kAccNative = 0x0100; - uint32_t kAccFastInterpreterToInterpreterInvoke = 0x40000000; - - jfieldID fieldArtMethod = nullptr; - - std::unordered_map replaced_entrypoint; - - inline uint32_t read32(void *addr) { - return *((uint32_t *) addr); - } - - inline void write32(void *addr, uint32_t value) { - *((uint32_t *) addr) = value; - } - - inline void *readAddr(void *addr) { - return *((void **) addr); - } - - inline void writeAddr(void *addr, void *value) { - *((void **) addr) = value; - } -} - -extern "C" void Java_lab_galaxy_yahfa_HookMain_init(JNIEnv *env, jclass clazz, jint sdkVersion) { - SDKVersion = sdkVersion; - jclass classExecutable; - LOGI("init to SDK %d", sdkVersion); - switch (sdkVersion) { - case __ANDROID_API_R__: - classExecutable = env->FindClass("java/lang/reflect/Executable"); - fieldArtMethod = env->GetFieldID(classExecutable, "artMethod", "J"); - case __ANDROID_API_Q__: - case __ANDROID_API_P__: - kAccCompileDontBother = 0x02000000; - OFFSET_ArtMehod_in_Object = 0; - OFFSET_access_flags_in_ArtMethod = 4; - OFFSET_entry_point_from_quick_compiled_code_in_ArtMethod = - roundUpToPtrSize(4 * 4 + 2 * 2) + pointer_size; - break; - case __ANDROID_API_O_MR1__: - kAccCompileDontBother = 0x02000000; - case __ANDROID_API_O__: - OFFSET_ArtMehod_in_Object = 0; - OFFSET_access_flags_in_ArtMethod = 4; - OFFSET_entry_point_from_quick_compiled_code_in_ArtMethod = - roundUpToPtrSize(4 * 4 + 2 * 2) + pointer_size * 2; - break; - case __ANDROID_API_N_MR1__: - case __ANDROID_API_N__: - OFFSET_ArtMehod_in_Object = 0; - OFFSET_access_flags_in_ArtMethod = 4; // sizeof(GcRoot) = 4 - - // ptr_sized_fields_ is rounded up to pointer_size in ArtMethod - OFFSET_entry_point_from_quick_compiled_code_in_ArtMethod = - roundUpToPtrSize(4 * 4 + 2 * 2) + pointer_size * 3; - - break; - case __ANDROID_API_M__: - OFFSET_ArtMehod_in_Object = 0; - OFFSET_entry_point_from_interpreter_in_ArtMethod = roundUpToPtrSize(4 * 7); - OFFSET_entry_point_from_quick_compiled_code_in_ArtMethod = - OFFSET_entry_point_from_interpreter_in_ArtMethod + pointer_size * 2; - break; - case __ANDROID_API_L_MR1__: - OFFSET_ArtMehod_in_Object = 4 * 2; - OFFSET_entry_point_from_interpreter_in_ArtMethod = roundUpToPtrSize( - OFFSET_ArtMehod_in_Object + 4 * 7); - OFFSET_entry_point_from_quick_compiled_code_in_ArtMethod = - OFFSET_entry_point_from_interpreter_in_ArtMethod + pointer_size * 2; - break; - case __ANDROID_API_L__: - OFFSET_ArtMehod_in_Object = 4 * 2; - OFFSET_entry_point_from_interpreter_in_ArtMethod = OFFSET_ArtMehod_in_Object + 4 * 4; - OFFSET_entry_point_from_quick_compiled_code_in_ArtMethod = - OFFSET_entry_point_from_interpreter_in_ArtMethod + 8 * 2; - break; - default: - LOGE("not compatible with SDK %d", sdkVersion); - break; - } - - setupTrampoline(OFFSET_entry_point_from_quick_compiled_code_in_ArtMethod); -} - -static uint32_t getFlags(void *method_) { - char *method = (char *) method_; - uint32_t access_flags = read32(method + OFFSET_access_flags_in_ArtMethod); - return access_flags; -} - -static void setFlags(void *method_, uint32_t access_flags) { - char *method = (char *) method_; - write32(method + OFFSET_access_flags_in_ArtMethod, access_flags); -} - -void setNonCompilable(void *method) { - if (SDKVersion < __ANDROID_API_N__) { - return; - } - uint32_t access_flags = getFlags(method); - uint32_t old_flags = access_flags; - access_flags |= kAccCompileDontBother; - setFlags(method, access_flags); - LOGI("setNonCompilable: change access flags from 0x%x to 0x%x", old_flags, access_flags); -} - -void *getEntryPoint(void *method) { - return readAddr((char *) method + OFFSET_entry_point_from_quick_compiled_code_in_ArtMethod); -} - -static int replaceMethod(void *fromMethod, void *toMethod, int isBackup) { - // replace entry point - void *newEntrypoint = nullptr; - void *fromEntrypoint = - (char *) fromMethod + OFFSET_entry_point_from_quick_compiled_code_in_ArtMethod; - if (isBackup) { - void *originEntrypoint = readAddr( - (char *) toMethod + OFFSET_entry_point_from_quick_compiled_code_in_ArtMethod); - // entry point hardcoded - newEntrypoint = genTrampoline(toMethod, originEntrypoint); - } else { - // entry point from ArtMethod struct - newEntrypoint = genTrampoline(toMethod, nullptr); - } - replaced_entrypoint[fromMethod] = readAddr(fromEntrypoint); - - LOGI("replace entry point from %p to %p", readAddr(fromEntrypoint), newEntrypoint); - if (newEntrypoint) { - writeAddr(fromEntrypoint, newEntrypoint); - } else { - LOGE("failed to allocate space for trampoline of target method"); - return 1; - } - - // For pre Android M devices, should be not used by EdXposed. - if (OFFSET_entry_point_from_interpreter_in_ArtMethod != 0) { - void *interpEntrypoint = readAddr( - (char *) toMethod + OFFSET_entry_point_from_interpreter_in_ArtMethod); - writeAddr(fromEntrypoint, interpEntrypoint); - } - - return 0; -} - -static int doBackupAndHook(void *targetMethod, void *hookMethod, void *backupMethod) { - LOGI("target method is at %p, hook method is at %p, backup method is at %p", - targetMethod, hookMethod, backupMethod); - - int res = 0; - - // set kAccCompileDontBother for a method we do not want the compiler to compile - // so that we don't need to worry about hotness_count_ - if (SDKVersion >= __ANDROID_API_N__) { - setNonCompilable(targetMethod); -// setNonCompilable(hookMethod); - if (backupMethod) setNonCompilable(backupMethod); - } - - if (backupMethod) {// do method backup - // we use the same way as hooking target method - // hook backup method and redirect back to the original target method - // the only difference is that the entry point is now hardcoded - // instead of reading from ArtMethod struct since it's overwritten - res += replaceMethod(backupMethod, targetMethod, 1); - } - - res += replaceMethod(targetMethod, hookMethod, 0); - - LOGI("hook and backup done"); - return res; -} - -void *getArtMethod(JNIEnv *env, jobject jmethod) { - void *artMethod = nullptr; - - if (jmethod == nullptr) { - return artMethod; - } - - if (SDKVersion == __ANDROID_API_R__) { - artMethod = (void *) env->GetLongField(jmethod, fieldArtMethod); - } else { - artMethod = (void *) env->FromReflectedMethod(jmethod); - } - - LOGI("HookMain: getArtMethod: %p", artMethod); - return artMethod; - -} - -extern "C" jobject Java_lab_galaxy_yahfa_HookMain_findMethodNative(JNIEnv *env, jclass clazz, - jclass targetClass, - jstring methodName, - jstring methodSig) { - const char *c_methodName = env->GetStringUTFChars(methodName, nullptr); - const char *c_methodSig = env->GetStringUTFChars(methodSig, nullptr); - jobject ret = nullptr; - - - //Try both GetMethodID and GetStaticMethodID -- Whatever works :) - jmethodID method = env->GetMethodID(targetClass, c_methodName, c_methodSig); - if (!env->ExceptionCheck()) { - ret = env->ToReflectedMethod(targetClass, method, JNI_FALSE); - } else { - env->ExceptionClear(); - method = env->GetStaticMethodID(targetClass, c_methodName, c_methodSig); - if (!env->ExceptionCheck()) { - ret = env->ToReflectedMethod(targetClass, method, JNI_TRUE); - } else { - env->ExceptionClear(); - } - } - - env->ReleaseStringUTFChars(methodName, c_methodName); - env->ReleaseStringUTFChars(methodSig, c_methodSig); - return ret; -} - -extern "C" jboolean Java_lab_galaxy_yahfa_HookMain_backupAndHookNative(JNIEnv *env, jclass clazz, - jobject target, jobject hook, - jobject backup) { - - if (!doBackupAndHook(getArtMethod(env, target), - getArtMethod(env, hook), - getArtMethod(env, backup) - )) { - env->NewGlobalRef(hook); // keep a global ref so that the hook method would not be GCed - if (backup) env->NewGlobalRef(backup); - return JNI_TRUE; - } else { - return JNI_FALSE; - } -} - -void *getOriginalEntryPointFromTargetMethod(void *method) { - return replaced_entrypoint[method]; -} \ No newline at end of file diff --git a/edxp-core/src/main/cpp/external/yahfa/src/trampoline.c b/edxp-core/src/main/cpp/external/yahfa/src/trampoline.c index 9648c788..3731d51f 100644 --- a/edxp-core/src/main/cpp/external/yahfa/src/trampoline.c +++ b/edxp-core/src/main/cpp/external/yahfa/src/trampoline.c @@ -14,17 +14,15 @@ #include "common.h" #include "trampoline.h" -#define MAX(a, b) ((a) > (b) ? (a) : (b)) +static unsigned char *trampolineCode; // place where trampolines are saved +static unsigned int trampolineSize; // trampoline size required for each hook +unsigned int hookCap = 0; +unsigned int hookCount = 0; // trampoline: -// 1. set eax/rdi/r0/x0 to the hook ArtMethod addr +// 1. set eax/r0/x0 to the hook ArtMethod addr // 2. jump into its entry point - -// trampoline for backup: -// 1. set eax/rdi/r0/x0 to the target ArtMethod addr -// 2. ret to the hardcoded original entry point - #if defined(__i386__) // b8 78 56 34 12 ; mov eax, 0x12345678 (addr of the hook method) // ff 70 20 ; push DWORD PTR [eax + 0x20] @@ -35,15 +33,6 @@ unsigned char trampoline[] = { 0xc3 }; -// b8 78 56 34 12 ; mov eax, 0x12345678 (addr of the target method) -// 68 78 56 34 12 ; push 0x12345678 (original entry point of the target method) -// c3 ; ret -unsigned char trampolineForBackup[] = { - 0xb8, 0x78, 0x56, 0x34, 0x12, - 0x68, 0x78, 0x56, 0x34, 0x12, - 0xc3 -}; - #elif defined(__x86_64__) // 48 bf 78 56 34 12 78 56 34 12 ; movabs rdi, 0x1234567812345678 // ff 77 20 ; push QWORD PTR [rdi + 0x20] @@ -54,17 +43,6 @@ unsigned char trampoline[] = { 0xc3 }; -// 48 bf 78 56 34 12 78 56 34 12 ; movabs rdi, 0x1234567812345678 -// 57 ; push rdi (original entry point of the target method) -// 48 bf 78 56 34 12 78 56 34 12 ; movabs rdi, 0x1234567812345678 (addr of the target method) -// c3 ; ret -unsigned char trampolineForBackup[] = { - 0x48, 0xbf, 0x78, 0x56, 0x34, 0x12, 0x78, 0x56, 0x34, 0x12, - 0x57, - 0x48, 0xbf, 0x78, 0x56, 0x34, 0x12, 0x78, 0x56, 0x34, 0x12, - 0xc3 -}; - #elif defined(__arm__) // 00 00 9F E5 ; ldr r0, [pc, #0] // 20 F0 90 E5 ; ldr pc, [r0, 0x20] @@ -75,21 +53,6 @@ unsigned char trampoline[] = { 0x78, 0x56, 0x34, 0x12 }; -// 0c 00 9F E5 ; ldr r0, [pc, #12] -// 01 00 2d e9 ; push {r0} -// 00 00 9F E5 ; ldr r0, [pc, #0] -// 00 80 bd e8 ; pop {pc} -// 78 56 34 12 ; 0x12345678 (addr of the hook method) -// 78 56 34 12 ; 0x12345678 (original entry point of the target method) -unsigned char trampolineForBackup[] = { - 0x0c, 0x00, 0x9f, 0xe5, - 0x01, 0x00, 0x2d, 0xe9, - 0x00, 0x00, 0x9f, 0xe5, - 0x00, 0x80, 0xbd, 0xe8, - 0x78, 0x56, 0x34, 0x12, - 0x78, 0x56, 0x34, 0x12 -}; - #elif defined(__aarch64__) // 60 00 00 58 ; ldr x0, 12 // 10 00 40 F8 ; ldr x16, [x0, #0x00] @@ -103,113 +66,75 @@ unsigned char trampoline[] = { 0x78, 0x56, 0x34, 0x12, 0x89, 0x67, 0x45, 0x23 }; - -// 60 00 00 58 ; ldr x0, 12 -// 90 00 00 58 ; ldr x16, 16 -// 00 02 1f d6 ; br x16 -// 78 56 34 12 -// 89 67 45 23 ; 0x2345678912345678 (addr of the hook method) -// 78 56 34 12 -// 89 67 45 23 ; 0x2345678912345678 (original entry point of the target method) -unsigned char trampolineForBackup[] = { - 0x60, 0x00, 0x00, 0x58, - 0x90, 0x00, 0x00, 0x58, - 0x00, 0x02, 0x1f, 0xd6, - 0x78, 0x56, 0x34, 0x12, - 0x89, 0x67, 0x45, 0x23, - 0x78, 0x56, 0x34, 0x12, - 0x89, 0x67, 0x45, 0x23 -}; - #endif +static unsigned int trampolineSize = roundUpToPtrSize(sizeof(trampoline)); static inline void FlushCache(void *addr, size_t size) { __builtin___clear_cache((char *) addr, (char *) ((uintptr_t) addr + size)); } -void *genTrampoline(void *toMethod, void *entrypoint) { - size_t size = entrypoint == NULL ? sizeof(trampoline) : sizeof(trampolineForBackup); +void *genTrampoline(void *hookMethod) { + void *targetAddr; - // TODO: make use of thread_local to avoid frequent memory allocate - char *targetAddr = doInitHookCap(size); - if (targetAddr == NULL) return NULL; - - if (entrypoint != NULL) { - memcpy(targetAddr, trampolineForBackup, size); - } else { - memcpy(targetAddr, trampoline, size); - } + targetAddr = trampolineCode + trampolineSize * hookCount; + memcpy(targetAddr, trampoline, + sizeof(trampoline)); // do not use trampolineSize since it's a rounded size // replace with the actual ArtMethod addr #if defined(__i386__) - if(entrypoint) { - memcpy(targetAddr + 1, &toMethod, pointer_size); - memcpy(targetAddr + 6, &entrypoint, pointer_size); - } - else { - memcpy(targetAddr + 1, &toMethod, pointer_size); - } + memcpy(targetAddr+1, &hookMethod, pointer_size); #elif defined(__x86_64__) - if(entrypoint) { - memcpy(targetAddr + 2, &entrypoint, pointer_size); - memcpy(targetAddr + 13, &toMethod, pointer_size); - } - else { - memcpy(targetAddr + 2, &toMethod, pointer_size); - } + memcpy((char*)targetAddr + 2, &hookMethod, pointer_size); #elif defined(__arm__) - if(entrypoint) { - memcpy(targetAddr + 20, &entrypoint, pointer_size); - memcpy(targetAddr + 16, &toMethod, pointer_size); - } - else { - memcpy(targetAddr + 8, &toMethod, pointer_size); - } + memcpy(targetAddr+8, &hookMethod, pointer_size); #elif defined(__aarch64__) - if (entrypoint) { - memcpy(targetAddr + 20, &entrypoint, pointer_size); - memcpy(targetAddr + 12, &toMethod, pointer_size); - } else { - memcpy(targetAddr + 12, &toMethod, pointer_size); - } + memcpy(targetAddr + 12, &hookMethod, pointer_size); #else #error Unsupported architecture #endif - FlushCache(targetAddr, size); + FlushCache(targetAddr, sizeof(trampoline)); return targetAddr; } -void setupTrampoline(uint8_t offset) { +void setupTrampoline() { #if defined(__i386__) - trampoline[7] = offset; + trampoline[7] = (unsigned char)OFFSET_entry_point_from_quick_compiled_code_in_ArtMethod; #elif defined(__x86_64__) - trampoline[12] = offset; + trampoline[12] = (unsigned char)OFFSET_entry_point_from_quick_compiled_code_in_ArtMethod; #elif defined(__arm__) - trampoline[4] = offset; + trampoline[4] = (unsigned char)OFFSET_entry_point_from_quick_compiled_code_in_ArtMethod; #elif defined(__aarch64__) - trampoline[5] |= offset << 4; - trampoline[6] |= offset >> 4; + trampoline[5] |= + ((unsigned char) OFFSET_entry_point_from_quick_compiled_code_in_ArtMethod) << 4; + trampoline[6] |= + ((unsigned char) OFFSET_entry_point_from_quick_compiled_code_in_ArtMethod) >> 4; #else #error Unsupported architecture #endif } -void *doInitHookCap(size_t size) { - if (size == 0) { - LOGE("invalid capacity: %zx", size); - return NULL; +int doInitHookCap(unsigned int cap) { + if (cap == 0) { + LOGE("invalid capacity: %d", cap); + return 1; } - unsigned char *buf = mmap(NULL, size, PROT_READ | PROT_WRITE | PROT_EXEC, + if (hookCap) { + LOGI("allocating new space for trampoline code"); + } + unsigned int allSize = trampolineSize * cap; + unsigned char *buf = mmap(NULL, allSize, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); if (buf == MAP_FAILED) { LOGE("mmap failed, errno = %s", strerror(errno)); - return NULL; + return 1; } - return buf; + hookCap = cap; + hookCount = 0; + trampolineCode = buf; + return 0; } - diff --git a/edxp-core/src/main/cpp/main/include/art/runtime/jit/jit_code_cache.h b/edxp-core/src/main/cpp/main/include/art/runtime/jit/jit_code_cache.h index ad92cd39..2421798b 100644 --- a/edxp-core/src/main/cpp/main/include/art/runtime/jit/jit_code_cache.h +++ b/edxp-core/src/main/cpp/main/include/art/runtime/jit/jit_code_cache.h @@ -7,17 +7,17 @@ namespace art { namespace jit { - CREATE_MEM_HOOK_STUB_ENTRIES("_ZN3art3jit12JitCodeCache37GetSavedEntryPointOfPreCompiledMethodEPNS_9ArtMethodE", - const void*, GetSavedEntryPointOfPreCompiledMethod, (void *thiz, - void *art_method), { - if (UNLIKELY(edxp::isHooked(art_method))) { - LOGD("Found hooked method %p (%s), return entrypoint as jit entrypoint", art_method, - art::art_method::PrettyMethod(art_method).c_str()); - return getEntryPoint(art_method); - } - return backup(thiz, art_method); - }); - +// CREATE_MEM_HOOK_STUB_ENTRIES("_ZN3art3jit12JitCodeCache37GetSavedEntryPointOfPreCompiledMethodEPNS_9ArtMethodE", +// const void*, GetSavedEntryPointOfPreCompiledMethod, (void *thiz, +// void *art_method), { +// if (UNLIKELY(edxp::isHooked(art_method))) { +// LOGD("Found hooked method %p (%s), return entrypoint as jit entrypoint", art_method, +// art::art_method::PrettyMethod(art_method).c_str()); +// return getEntryPoint(art_method); +// } +// return backup(thiz, art_method); +// }); +// static void HookJitCacheCode(void *handle, HookFunType hook_func) { const int api_level = edxp::GetAndroidApiLevel(); // For android R, the invisibly initialization makes static methods initializes multiple @@ -25,7 +25,7 @@ namespace art { // our hooked entry point won't be overwritten. // This is for SandHook and YAHFA if (api_level >= __ANDROID_API_R__) { - edxp::HookSyms(handle, hook_func, GetSavedEntryPointOfPreCompiledMethod); +// edxp::HookSyms(handle, hook_func, GetSavedEntryPointOfPreCompiledMethod); } } diff --git a/edxp-core/src/main/cpp/main/include/art/runtime/mirror/class.h b/edxp-core/src/main/cpp/main/include/art/runtime/mirror/class.h index 8c0995d3..377780e0 100644 --- a/edxp-core/src/main/cpp/main/include/art/runtime/mirror/class.h +++ b/edxp-core/src/main/cpp/main/include/art/runtime/mirror/class.h @@ -64,7 +64,7 @@ namespace art { // RETRIEVE_FIELD_SYMBOL(mutator_lock_, "_ZN3art5Locks13mutator_lock_E"); // LOGE("mutator_lock_: %p", mutator_lock_); - edxp::HookSyms(handle, hook_func, IsInSamePackage); +// edxp::HookSyms(handle, hook_func, IsInSamePackage); // HOOK_FUNC(ClassForName, // "_ZN3artL18Class_classForNameEP7_JNIEnvP7_jclassP8_jstringhP8_jobject"); diff --git a/edxp-core/src/main/cpp/main/include/art/runtime/reflection.h b/edxp-core/src/main/cpp/main/include/art/runtime/reflection.h new file mode 100644 index 00000000..49dd2c1b --- /dev/null +++ b/edxp-core/src/main/cpp/main/include/art/runtime/reflection.h @@ -0,0 +1,28 @@ +// +// Created by loves on 1/28/2021. +// + +#ifndef EDXPOSED_REFLECTION_H +#define EDXPOSED_REFLECTION_H + +#include "base/object.h" + +namespace art { + + CREATE_HOOK_STUB_ENTRIES( + "_ZN3art12VerifyAccessENS_6ObjPtrINS_6mirror6ObjectEEENS0_INS1_5ClassEEEjS5_", + bool, VerifyAccess, + (void * obj, void * declaring_class, uint32_t access_flags, void * calling_class), { + auto calling_desc = art::mirror::Class(calling_class).GetDescriptor(); + if (UNLIKELY(calling_desc.find("de/robv/android/xposed/LspHooker") != + std::string::npos)) { + return true; + } + return backup(obj, declaring_class, access_flags, calling_class); + }); + + static void PermissiveAccessByReflection(void *handle, HookFunType hook_func) { + edxp::HookSym(handle, hook_func, VerifyAccess); + } +} +#endif //EDXPOSED_REFLECTION_H diff --git a/edxp-core/src/main/cpp/main/src/jni/edxp_yahfa.cpp b/edxp-core/src/main/cpp/main/src/jni/edxp_yahfa.cpp index 5c88b821..06145957 100644 --- a/edxp-core/src/main/cpp/main/src/jni/edxp_yahfa.cpp +++ b/edxp-core/src/main/cpp/main/src/jni/edxp_yahfa.cpp @@ -24,20 +24,6 @@ namespace edxp { return Java_lab_galaxy_yahfa_HookMain_backupAndHookNative(env, clazz, target, hook, backup); } - static void Yahfa_setMethodNonCompilable(JNI_START, jobject member) { - if (!member) { - LOGE("setNonCompilableNative: member is null"); - return; - } - void *art_method = getArtMethod(env, member); - - if (!art_method) { - LOGE("setNonCompilableNative: art_method is null"); - return; - } - setNonCompilable(art_method); - } - static void Yahfa_recordHooked(JNI_START, jobject member) { edxp::recordHooked(getArtMethod(env, member)); } @@ -52,7 +38,6 @@ namespace edxp { "(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;)Ljava/lang/reflect/Member;"), NATIVE_METHOD(Yahfa, backupAndHookNative, "(Ljava/lang/Object;Ljava/lang/reflect/Method;Ljava/lang/reflect/Method;)Z"), - //NATIVE_METHOD(Yahfa, setMethodNonCompilable, "(Ljava/lang/reflect/Member;)V"), NATIVE_METHOD(Yahfa, recordHooked, "(Ljava/lang/reflect/Member;)V"), NATIVE_METHOD(Yahfa, isHooked, "(Ljava/lang/reflect/Member;)Z"), }; diff --git a/edxp-core/src/main/cpp/main/src/native_hook.cpp b/edxp-core/src/main/cpp/main/src/native_hook.cpp index 19cd0bc8..fbe548c2 100644 --- a/edxp-core/src/main/cpp/main/src/native_hook.cpp +++ b/edxp-core/src/main/cpp/main/src/native_hook.cpp @@ -21,6 +21,7 @@ #include "art/runtime/jit/jit_code_cache.h" #include "art/runtime/art_method.h" #include "art/runtime/instrumentation.h" +#include "art/runtime/reflection.h" std::vector linker_get_solist(); // Dobby but not in .h @@ -86,6 +87,7 @@ namespace edxp { // art::oat_file_manager::DisableOnlyUseSystemOatFiles(art_handle, hook_func); // art::jit::HookJitCacheCode(art_handle, hook_func); art::instrumentation::DisableUpdateHookedMethodsCode(art_handle, hook_func); + art::PermissiveAccessByReflection(art_handle, hook_func); art_hooks_installed = true; LOGI("ART hooks installed"); diff --git a/edxp-core/src/main/java/com/elderdrivers/riru/edxp/core/Yahfa.java b/edxp-core/src/main/java/com/elderdrivers/riru/edxp/core/Yahfa.java index 149cc78c..e48dfd2a 100644 --- a/edxp-core/src/main/java/com/elderdrivers/riru/edxp/core/Yahfa.java +++ b/edxp-core/src/main/java/com/elderdrivers/riru/edxp/core/Yahfa.java @@ -12,8 +12,6 @@ public class Yahfa { public static native void init(int sdkVersion); - //public static native void setMethodNonCompilable(Member member); - public static native void recordHooked(Member member); public static native boolean isHooked(Member member); diff --git a/edxp-core/src/main/java/com/elderdrivers/riru/edxp/core/yahfa/HookMain.java b/edxp-core/src/main/java/com/elderdrivers/riru/edxp/core/yahfa/HookMain.java index 2e6396a7..fad8b299 100644 --- a/edxp-core/src/main/java/com/elderdrivers/riru/edxp/core/yahfa/HookMain.java +++ b/edxp-core/src/main/java/com/elderdrivers/riru/edxp/core/yahfa/HookMain.java @@ -10,87 +10,7 @@ import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.Arrays; -import java.util.HashSet; -import java.util.Set; - public class HookMain { - - private static final Set hookItemWhiteList = new HashSet(); - - public static void addHookItemWhiteList(String className) { - hookItemWhiteList.add(className); - } - - public static void doHookDefault(ClassLoader patchClassLoader, ClassLoader originClassLoader, String hookInfoClassName) { - try { - Class hookInfoClass = Class.forName(hookInfoClassName, true, patchClassLoader); - String[] hookItemNames = (String[]) hookInfoClass.getField("hookItemNames").get(null); - for (String hookItemName : hookItemNames) { - doHookItemDefault(patchClassLoader, hookItemName, originClassLoader); - } - } catch (Throwable e) { - Utils.logE("error when hooking all in: " + hookInfoClassName, e); - } - } - - private static void doHookItemDefault(ClassLoader patchClassLoader, String hookItemName, ClassLoader originClassLoader) { - try { - Utils.logD("Start hooking with item " + hookItemName); - Class hookItem = Class.forName(hookItemName, true, patchClassLoader); - - String className = (String) hookItem.getField("className").get(null); - String methodName = (String) hookItem.getField("methodName").get(null); - String methodSig = (String) hookItem.getField("methodSig").get(null); - - if (className == null || className.equals("")) { - Utils.logW("No target class. Skipping..."); - return; - } - Class clazz = null; - try { - clazz = Class.forName(className, true, originClassLoader); - } catch (ClassNotFoundException cnfe) { - Utils.logE(className + " not found in " + originClassLoader); - return; - } - if (Modifier.isAbstract(clazz.getModifiers())) { - Utils.logW("Hook may fail for abstract class: " + className); - } - - Method hook = null; - Method backup = null; - for (Method method : hookItem.getDeclaredMethods()) { - if (method.getName().equals("hook") && Modifier.isStatic(method.getModifiers())) { - hook = method; - } else if (method.getName().equals("backup") && Modifier.isStatic(method.getModifiers())) { - backup = method; - } - } - if (hook == null) { - Utils.logE("Cannot find hook for " + methodName); - return; - } - findAndBackupAndHook(clazz, methodName, methodSig, hook, backup); - } catch (Throwable e) { - if (!hookItemWhiteList.contains(hookItemName)) { - Utils.logE("error when hooking " + hookItemName, e); - } - } - } - - public static void findAndHook(Class targetClass, String methodName, String methodSig, Method hook) { - hook(findMethod(targetClass, methodName, methodSig), hook); - } - - public static void findAndBackupAndHook(Class targetClass, String methodName, String methodSig, - Method hook, Method backup) { - backupAndHook(findMethod(targetClass, methodName, methodSig), hook, backup); - } - - public static void hook(Member target, Method hook) { - backupAndHook(target, hook, null); - } - public static void backupAndHook(Member target, Method hook, Method backup) { Utils.logD(String.format("target=%s, hook=%s, backup=%s", target, hook, backup)); if (target == null) { @@ -103,13 +23,13 @@ public class HookMain { if (!Modifier.isStatic(hook.getModifiers())) { throw new IllegalArgumentException("Hook must be a static method: " + hook); } - checkCompatibleMethods(target, hook, "Original", "Hook"); + checkCompatibleMethods(target, hook, "Hook"); if (backup != null) { if (!Modifier.isStatic(backup.getModifiers())) { throw new IllegalArgumentException("Backup must be a static method: " + backup); } // backup is just a placeholder and the constraint could be less strict - checkCompatibleMethods(target, backup, "Original", "Backup"); + checkCompatibleMethods(target, backup, "Backup"); } // make sure GC completed before hook int lastGcType = Heap.waitForGcToComplete(); @@ -118,28 +38,15 @@ public class HookMain { Runtime.getRuntime().gc(); } - if (!Yahfa.backupAndHookNative(target, hook, backup)) { + if(!Yahfa.backupAndHookNative(target, hook, backup)){ throw new RuntimeException("Failed to hook " + target + " with " + hook); } else { Yahfa.recordHooked(target); - Yahfa.recordHooked(backup); +// Yahfa.recordHooked(backup); } } - public static Member findMethod(Class cls, String methodName, String methodSig) { - if (cls == null) { - throw new IllegalArgumentException("null class"); - } - if (methodName == null) { - throw new IllegalArgumentException("null method name"); - } - if (methodSig == null) { - throw new IllegalArgumentException("null method signature"); - } - return Yahfa.findMethodNative(cls, methodName, methodSig); - } - - private static void checkCompatibleMethods(Object original, Method replacement, String originalName, String replacementName) { + private static void checkCompatibleMethods(Object original, Method replacement, String replacementName) { ArrayList> originalParams; if (original instanceof Method) { originalParams = new ArrayList<>(Arrays.asList(((Method) original).getParameterTypes())); @@ -165,7 +72,7 @@ public class HookMain { if (original instanceof Method && !replacement.getReturnType().isAssignableFrom(((Method) original).getReturnType())) { - throw new IllegalArgumentException("Incompatible return types. " + originalName + ": " + ((Method) original).getReturnType() + ", " + replacementName + ": " + replacement.getReturnType()); + throw new IllegalArgumentException("Incompatible return types. " + "Original" + ": " + ((Method) original).getReturnType() + ", " + replacementName + ": " + replacement.getReturnType()); } else if (original instanceof Constructor) { if (replacement.getReturnType().equals(Void.class)) { throw new IllegalArgumentException("Incompatible return types. " + "" + ": " + "V" + ", " + replacementName + ": " + replacement.getReturnType()); @@ -173,12 +80,12 @@ public class HookMain { } if (originalParams.size() != replacementParams.size()) { - throw new IllegalArgumentException("Number of arguments don't match. " + originalName + ": " + originalParams.size() + ", " + replacementName + ": " + replacementParams.size()); + throw new IllegalArgumentException("Number of arguments don't match. " + "Original" + ": " + originalParams.size() + ", " + replacementName + ": " + replacementParams.size()); } for (int i = 0; i < originalParams.size(); i++) { if (!replacementParams.get(i).isAssignableFrom(originalParams.get(i))) { - throw new IllegalArgumentException("Incompatible argument #" + i + ": " + originalName + ": " + originalParams.get(i) + ", " + replacementName + ": " + replacementParams.get(i)); + throw new IllegalArgumentException("Incompatible argument #" + i + ": " + "Original" + ": " + originalParams.get(i) + ", " + replacementName + ": " + replacementParams.get(i)); } } } diff --git a/edxp-core/src/main/java/com/elderdrivers/riru/edxp/proxy/BaseRouter.java b/edxp-core/src/main/java/com/elderdrivers/riru/edxp/proxy/BaseRouter.java index 4c8ef585..ab69e24f 100644 --- a/edxp-core/src/main/java/com/elderdrivers/riru/edxp/proxy/BaseRouter.java +++ b/edxp-core/src/main/java/com/elderdrivers/riru/edxp/proxy/BaseRouter.java @@ -32,8 +32,6 @@ public abstract class BaseRouter implements Router { protected volatile AtomicBoolean bootstrapHooked = new AtomicBoolean(false); - protected static boolean useXposedApi = false; - public void initResourcesHook() { XposedBridge.initXResources(); } @@ -81,49 +79,27 @@ public abstract class BaseRouter implements Router { public void startBootstrapHook(boolean isSystem) { Utils.logD("startBootstrapHook starts: isSystem = " + isSystem); ClassLoader classLoader = BaseRouter.class.getClassLoader(); - if (useXposedApi) { - if (isSystem) { - XposedHelpers.findAndHookMethod(SystemMainHooker.className, classLoader, - SystemMainHooker.methodName, new SystemMain()); - } - XposedHelpers.findAndHookMethod(HandleBindAppHooker.className, classLoader, - HandleBindAppHooker.methodName, - "android.app.ActivityThread$AppBindData", - new HandleBindApp()); - XposedHelpers.findAndHookConstructor(LoadedApkConstructorHooker.className, classLoader, - ActivityThread.class, ApplicationInfo.class, CompatibilityInfo.class, - ClassLoader.class, boolean.class, boolean.class, boolean.class, - new LoadedApkCstr()); - } else { - if (isSystem) { - HookMain.doHookDefault( - BaseRouter.class.getClassLoader(), - classLoader, - SysBootstrapHookInfo.class.getName()); - } else { - HookMain.doHookDefault( - BaseRouter.class.getClassLoader(), - classLoader, - AppBootstrapHookInfo.class.getName()); - } + if (isSystem) { + XposedHelpers.findAndHookMethod(SystemMainHooker.className, classLoader, + SystemMainHooker.methodName, new SystemMain()); } + XposedHelpers.findAndHookMethod(HandleBindAppHooker.className, classLoader, + HandleBindAppHooker.methodName, + "android.app.ActivityThread$AppBindData", + new HandleBindApp()); + XposedHelpers.findAndHookConstructor(LoadedApkConstructorHooker.className, classLoader, + ActivityThread.class, ApplicationInfo.class, CompatibilityInfo.class, + ClassLoader.class, boolean.class, boolean.class, boolean.class, + new LoadedApkCstr()); } public void startSystemServerHook() { - ClassLoader classLoader = BaseRouter.class.getClassLoader(); - if (useXposedApi) { - StartBootstrapServices sbsHooker = new StartBootstrapServices(); - Object[] paramTypesAndCallback = Versions.hasR() ? - new Object[]{"com.android.server.utils.TimingsTraceAndSlog", sbsHooker} : - new Object[]{sbsHooker}; - XposedHelpers.findAndHookMethod(StartBootstrapServicesHooker.className, - SystemMain.systemServerCL, - StartBootstrapServicesHooker.methodName, paramTypesAndCallback); - } else { - HookMain.doHookDefault( - classLoader, - SystemMain.systemServerCL, - SysInnerHookInfo.class.getName()); - } + StartBootstrapServices sbsHooker = new StartBootstrapServices(); + Object[] paramTypesAndCallback = Versions.hasR() ? + new Object[]{"com.android.server.utils.TimingsTraceAndSlog", sbsHooker} : + new Object[]{sbsHooker}; + XposedHelpers.findAndHookMethod(StartBootstrapServicesHooker.className, + SystemMain.systemServerCL, + StartBootstrapServicesHooker.methodName, paramTypesAndCallback); } } diff --git a/edxp-core/src/main/java/com/elderdrivers/riru/edxp/sandhook/core/SandHookRouter.java b/edxp-core/src/main/java/com/elderdrivers/riru/edxp/sandhook/core/SandHookRouter.java index aa1f4ff1..a44749c1 100644 --- a/edxp-core/src/main/java/com/elderdrivers/riru/edxp/sandhook/core/SandHookRouter.java +++ b/edxp-core/src/main/java/com/elderdrivers/riru/edxp/sandhook/core/SandHookRouter.java @@ -16,7 +16,6 @@ import de.robv.android.xposed.XposedBridge; public class SandHookRouter extends BaseRouter { public SandHookRouter() { - useXposedApi = true; } private static boolean useSandHook = false; diff --git a/edxp-core/src/main/java/com/elderdrivers/riru/edxp/yahfa/core/YahfaRouter.java b/edxp-core/src/main/java/com/elderdrivers/riru/edxp/yahfa/core/YahfaRouter.java index 1c5dcfd1..e24d9fb1 100644 --- a/edxp-core/src/main/java/com/elderdrivers/riru/edxp/yahfa/core/YahfaRouter.java +++ b/edxp-core/src/main/java/com/elderdrivers/riru/edxp/yahfa/core/YahfaRouter.java @@ -8,8 +8,6 @@ import com.elderdrivers.riru.edxp.yahfa.dexmaker.DynamicBridge; public class YahfaRouter extends BaseRouter { YahfaRouter() { - // TODO: disable for better performance - useXposedApi = true; } public void onEnterChildProcess() { diff --git a/edxp-core/src/main/java/com/elderdrivers/riru/edxp/yahfa/dexmaker/DynamicBridge.java b/edxp-core/src/main/java/com/elderdrivers/riru/edxp/yahfa/dexmaker/DynamicBridge.java index 9ae98604..73a5e8cb 100644 --- a/edxp-core/src/main/java/com/elderdrivers/riru/edxp/yahfa/dexmaker/DynamicBridge.java +++ b/edxp-core/src/main/java/com/elderdrivers/riru/edxp/yahfa/dexmaker/DynamicBridge.java @@ -1,15 +1,12 @@ package com.elderdrivers.riru.edxp.yahfa.dexmaker; - -import com.elderdrivers.riru.edxp.config.ConfigManager; - -import java.io.File; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Member; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.HashMap; +import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicBoolean; import de.robv.android.xposed.LspHooker; @@ -17,7 +14,7 @@ import de.robv.android.xposed.XposedBridge; public final class DynamicBridge { - private static final HashMap hookedInfo = new HashMap<>(); + private static final ConcurrentHashMap hookedInfo = new ConcurrentHashMap<>(); private static final HookerDexMaker dexMaker = new HookerDexMaker(); private static final AtomicBoolean dexPathInited = new AtomicBoolean(false); @@ -74,7 +71,10 @@ public final class DynamicBridge { if (hooker == null) { throw new IllegalStateException("method not hooked, cannot call original method."); } - return hooker.callBackup(thisObject, args); + if (args == null) { + args = new Object[0]; + } + return hooker.getBackup().invoke(thisObject, args); } } diff --git a/edxp-core/src/main/java/de/robv/android/xposed/LspHooker.java b/edxp-core/src/main/java/de/robv/android/xposed/LspHooker.java index 7424c64a..2772651f 100644 --- a/edxp-core/src/main/java/de/robv/android/xposed/LspHooker.java +++ b/edxp-core/src/main/java/de/robv/android/xposed/LspHooker.java @@ -18,39 +18,12 @@ public class LspHooker { this.backup = backup; } - public Object callBackup(Object thisObject, Object[] args) throws InvocationTargetException, IllegalAccessException { - if (args == null) { - args = new Object[0]; - } - if (Modifier.isStatic(method.getModifiers())) { - return backup.invoke(null, args); - } else { - Object[] newArgs = new Object[args.length + 1]; - newArgs[0] = thisObject; - System.arraycopy(args, 0, newArgs, 1, args.length); - return backup.invoke(null, newArgs); - } + public Method getBackup() { + return backup; } @SuppressWarnings({"unused", "RedundantSuppression"}) public Object handleHookedMethod(Object[] args) throws Throwable { - if (disableHooks) { - try { - return backup.invoke(null, args); - } catch (InvocationTargetException ite) { - throw ite.getCause(); - } - } - Object[] callbacksSnapshot = additionalInfo.callbacks.getSnapshot(); - final int callbacksLength = callbacksSnapshot.length; - if (callbacksLength == 0) { - try { - return backup.invoke(null, args); - } catch (InvocationTargetException ite) { - throw ite.getCause(); - } - } - XC_MethodHook.MethodHookParam param = new XC_MethodHook.MethodHookParam(); param.method = method; @@ -64,6 +37,23 @@ public class LspHooker { System.arraycopy(args, 1, param.args, 0, args.length - 1); } + if (disableHooks) { + try { + return backup.invoke(param.thisObject, param.args); + } catch (InvocationTargetException ite) { + throw ite.getCause(); + } + } + Object[] callbacksSnapshot = additionalInfo.callbacks.getSnapshot(); + final int callbacksLength = callbacksSnapshot.length; + if (callbacksLength == 0) { + try { + return backup.invoke(param.thisObject, param.args); + } catch (InvocationTargetException ite) { + throw ite.getCause(); + } + } + // call "before method" callbacks int beforeIdx = 0; do { @@ -88,7 +78,7 @@ public class LspHooker { // call original method if not requested otherwise if (!param.returnEarly) { try { - param.setResult(callBackup(param.thisObject, param.args)); + param.setResult(backup.invoke(param.thisObject, param.args)); } catch (InvocationTargetException e) { param.setThrowable(e.getCause()); }