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 fc96b8ed..c22c4407 100644 --- a/edxp-core/src/main/cpp/external/yahfa/include/HookMain.h +++ b/edxp-core/src/main/cpp/external/yahfa/include/HookMain.h @@ -20,7 +20,9 @@ jboolean Java_lab_galaxy_yahfa_HookMain_backupAndHookNative(JNIEnv *env, jclass 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); @@ -28,8 +30,7 @@ void *getArtMethod(JNIEnv *env, jobject jmethod); // TODO: move to common utils instead of in YAHFA's code void *getEntryPoint(void* method); -#ifdef __cplusplus -} -#endif +void *getOriginalEntryPointFromHookedEntryPoint(void* method); + #endif // HOOK_MAIN_H \ No newline at end of file diff --git a/edxp-core/src/main/cpp/external/yahfa/src/trampoline.h b/edxp-core/src/main/cpp/external/yahfa/include/trampoline.h similarity index 87% rename from edxp-core/src/main/cpp/external/yahfa/src/trampoline.h rename to edxp-core/src/main/cpp/external/yahfa/include/trampoline.h index f5fca72a..3d5b7b47 100644 --- a/edxp-core/src/main/cpp/external/yahfa/src/trampoline.h +++ b/edxp-core/src/main/cpp/external/yahfa/include/trampoline.h @@ -8,6 +8,7 @@ extern int SDKVersion; extern unsigned char trampoline[]; +extern unsigned char trampolineForBackup[]; void* doInitHookCap(size_t cap); void setupTrampoline(uint8_t offset); diff --git a/edxp-core/src/main/cpp/external/yahfa/src/HookMain.c b/edxp-core/src/main/cpp/external/yahfa/src/HookMain.cpp similarity index 74% rename from edxp-core/src/main/cpp/external/yahfa/src/HookMain.c rename to edxp-core/src/main/cpp/external/yahfa/src/HookMain.cpp index f96372fd..a6f9e307 100644 --- a/edxp-core/src/main/cpp/external/yahfa/src/HookMain.c +++ b/edxp-core/src/main/cpp/external/yahfa/src/HookMain.cpp @@ -1,11 +1,13 @@ #include "jni.h" #include -#include -#include +#include +#include #include "common.h" -#include "trampoline.h" #include "HookMain.h" +extern "C" { +#include "trampoline.h" +} int SDKVersion; static uint32_t OFFSET_entry_point_from_interpreter_in_ArtMethod; @@ -14,7 +16,8 @@ static uint32_t OFFSET_ArtMehod_in_Object; static uint32_t OFFSET_access_flags_in_ArtMethod; static uint32_t kAccCompileDontBother = 0x01000000; -static jfieldID fieldArtMethod = NULL; +static jfieldID fieldArtMethod = nullptr; +static std::unordered_map replaced_entrypoint; static inline uint32_t read32(void *addr) { return *((uint32_t *) addr); @@ -32,14 +35,14 @@ static inline void writeAddr(void *addr, void *value) { *((void **)addr) = value; } -void Java_lab_galaxy_yahfa_HookMain_init(JNIEnv *env, jclass clazz, jint sdkVersion) { +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(env, "java/lang/reflect/Executable"); - fieldArtMethod = (*env)->GetFieldID(env, classExecutable, "artMethod", "J"); + classExecutable = env->FindClass("java/lang/reflect/Executable"); + fieldArtMethod = env->GetFieldID(classExecutable, "artMethod", "J"); case __ANDROID_API_Q__: case __ANDROID_API_P__: kAccCompileDontBother = 0x02000000; @@ -93,12 +96,14 @@ void Java_lab_galaxy_yahfa_HookMain_init(JNIEnv *env, jclass clazz, jint sdkVers setupTrampoline(OFFSET_entry_point_from_quick_compiled_code_in_ArtMethod); } -static uint32_t getFlags(char *method) { +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(char *method, uint32_t access_flags) { +static void setFlags(void *method_, uint32_t access_flags) { + char* method = (char*)method_; write32(method + OFFSET_access_flags_in_ArtMethod, access_flags); } @@ -119,7 +124,7 @@ void *getEntryPoint(void* method) { static int replaceMethod(void *fromMethod, void *toMethod, int isBackup) { // replace entry point - void *newEntrypoint = NULL; + void *newEntrypoint = nullptr; if(isBackup) { void *originEntrypoint = readAddr((char *) toMethod + OFFSET_entry_point_from_quick_compiled_code_in_ArtMethod); // entry point hardcoded @@ -127,24 +132,28 @@ static int replaceMethod(void *fromMethod, void *toMethod, int isBackup) { } else { // entry point from ArtMethod struct - newEntrypoint = genTrampoline(toMethod, NULL); + newEntrypoint = genTrampoline(toMethod, nullptr); } + void* fromEntrypoint = (char *) fromMethod + OFFSET_entry_point_from_quick_compiled_code_in_ArtMethod; + replaced_entrypoint[fromEntrypoint] = newEntrypoint; + LOGI("replace entry point from %p to %p", - readAddr((char *) fromMethod + OFFSET_entry_point_from_quick_compiled_code_in_ArtMethod), + readAddr(fromEntrypoint), newEntrypoint ); if (newEntrypoint) { - writeAddr((char *) fromMethod + OFFSET_entry_point_from_quick_compiled_code_in_ArtMethod, + 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((char *) fromMethod + OFFSET_entry_point_from_interpreter_in_ArtMethod, + writeAddr(fromEntrypoint, interpEntrypoint); } @@ -180,16 +189,16 @@ static int doBackupAndHook(void *targetMethod, void *hookMethod, void *backupMet } void *getArtMethod(JNIEnv *env, jobject jmethod) { - void *artMethod = NULL; + void *artMethod = nullptr; - if (jmethod == NULL) { + if (jmethod == nullptr) { return artMethod; } if (SDKVersion == __ANDROID_API_R__) { - artMethod = (void *) (*env)->GetLongField(env, jmethod, fieldArtMethod); + artMethod = (void *) env->GetLongField(jmethod, fieldArtMethod); } else { - artMethod = (void *) (*env)->FromReflectedMethod(env, jmethod); + artMethod = (void *) env->FromReflectedMethod(jmethod); } LOGI("HookMain: getArtMethod: %p", artMethod); @@ -197,34 +206,34 @@ void *getArtMethod(JNIEnv *env, jobject jmethod) { } -jobject Java_lab_galaxy_yahfa_HookMain_findMethodNative(JNIEnv *env, jclass clazz, +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(env, methodName, NULL); - const char *c_methodSig = (*env)->GetStringUTFChars(env, methodSig, NULL); - jobject ret = NULL; + 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(env, targetClass, c_methodName, c_methodSig); - if (!(*env)->ExceptionCheck(env)) { - ret = (*env)->ToReflectedMethod(env, targetClass, method, JNI_FALSE); + jmethodID method = env->GetMethodID(targetClass, c_methodName, c_methodSig); + if (!env->ExceptionCheck()) { + ret = env->ToReflectedMethod(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); + env->ExceptionClear(); + method = env->GetStaticMethodID(targetClass, c_methodName, c_methodSig); + if (!env->ExceptionCheck()) { + ret = env->ToReflectedMethod(targetClass, method, JNI_TRUE); } else { - (*env)->ExceptionClear(env); + env->ExceptionClear(); } } - (*env)->ReleaseStringUTFChars(env, methodName, c_methodName); - (*env)->ReleaseStringUTFChars(env, methodSig, c_methodSig); + env->ReleaseStringUTFChars(methodName, c_methodName); + env->ReleaseStringUTFChars(methodSig, c_methodSig); return ret; } -jboolean Java_lab_galaxy_yahfa_HookMain_backupAndHookNative(JNIEnv *env, jclass clazz, +extern "C" jboolean Java_lab_galaxy_yahfa_HookMain_backupAndHookNative(JNIEnv *env, jclass clazz, jobject target, jobject hook, jobject backup) { @@ -232,10 +241,14 @@ jboolean Java_lab_galaxy_yahfa_HookMain_backupAndHookNative(JNIEnv *env, jclass 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); + 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 *getOriginalEntryPointFromHookedEntryPoint(void* method) { + return replaced_entrypoint[method]; +} \ No newline at end of file diff --git a/edxp-core/src/main/cpp/main/include/art/runtime/oat_quick_method_header.h b/edxp-core/src/main/cpp/main/include/art/runtime/oat_quick_method_header.h new file mode 100644 index 00000000..fe87cc3e --- /dev/null +++ b/edxp-core/src/main/cpp/main/include/art/runtime/oat_quick_method_header.h @@ -0,0 +1,38 @@ +// +// Created by εŒθ‰ι…Έι…― on 12/18/20. +// + +#ifndef EDXPOSED_OAT_QUICK_METHOD_HEADER_H +#define EDXPOSED_OAT_QUICK_METHOD_HEADER_H + +#include +#include +#include +namespace art { + // https://github.com/ElderDrivers/EdXposed/issues/740 + class OatQuickMethodHeader : public edxp::HookedObject { + private: + CREATE_HOOK_STUB_ENTRIES(uint32_t, GetCodeSize, void *thiz) { + LOGD("OatQuickMethodHeader::GetCodeSize: %p", thiz); + void* oep = getOriginalEntryPointFromHookedEntryPoint(thiz); + if (oep) { + LOGD("OatQuickMethodHeader: Original entry point: %p", oep); + return GetCodeSizeBackup(oep); + } else { + LOGD("OatQuickMethodHeader: Original entry point not found"); + return GetCodeSizeBackup(thiz); + } + } + + public: + static void Setup(void *handle, HookFunType hook_func) { + if (edxp::GetAndroidApiLevel() >= __ANDROID_API_R__) { + HOOK_FUNC(GetCodeSize, "_ZNK3art20OatQuickMethodHeader11GetCodeSizeEv"); + } + } + }; + +} + + +#endif //EDXPOSED_OAT_QUICK_METHOD_HEADER_H 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 f73e3144..d05ae242 100644 --- a/edxp-core/src/main/cpp/main/src/native_hook.cpp +++ b/edxp-core/src/main/cpp/main/src/native_hook.cpp @@ -17,6 +17,7 @@ #include "art/runtime/gc/heap.h" #include "art/runtime/hidden_api.h" #include "art/runtime/oat_file_manager.h" +#include "art/runtime/oat_quick_method_header.h" #include "art/runtime/jit/jit_code_cache.h" std::vector linker_get_solist(); // Dobby but not in .h @@ -79,6 +80,7 @@ namespace edxp { art::mirror::Class::Setup(art_handle, hook_func); art::JNIEnvExt::Setup(art_handle, hook_func); art::oat_file_manager::DisableOnlyUseSystemOatFiles(art_handle, hook_func); + art::OatQuickMethodHeader::Setup(art_handle, hook_func); art::jit::HookJitCacheCode(art_handle, hook_func); art_hooks_installed = true;