From dcd29b8751e92b2f36569fb844092afab3268cb6 Mon Sep 17 00:00:00 2001 From: LoveSy Date: Sat, 12 Feb 2022 15:23:18 +0800 Subject: [PATCH] Fix deopt method since Android 13 --- .../cpp/external/yahfa/include/HookMain.h | 5 + .../cpp/external/yahfa/include/trampoline.h | 13 +- .../main/cpp/external/yahfa/src/HookMain.cpp | 22 +- .../cpp/external/yahfa/src/trampoline.cpp | 190 +++++++++--------- .../main/include/art/runtime/class_linker.h | 21 +- 5 files changed, 142 insertions(+), 109 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..dece1c80 100644 --- a/core/src/main/cpp/external/yahfa/include/HookMain.h +++ b/core/src/main/cpp/external/yahfa/include/HookMain.h @@ -8,6 +8,7 @@ namespace yahfa { constexpr uint32_t kAccPrivate = 0x0002; // field, method, ic constexpr uint32_t kAccProtected = 0x0004; // field, method, ic constexpr uint32_t kAccStatic = 0x0008; // field, method, ic + constexpr uint32_t kAccNative = 0x0100; // method void init(JNIEnv *env, jclass clazz, jint sdkVersion); @@ -24,6 +25,10 @@ namespace yahfa { uint32_t getAccessFlags(void* art_method); void setAccessFlags(void* art_method, uint32_t access_flags); + + void* getEntryPoint(void* art_method); + + void setEntryPoint(void* art_method, void* entry_point); } #endif // HOOK_MAIN_H diff --git a/core/src/main/cpp/external/yahfa/include/trampoline.h b/core/src/main/cpp/external/yahfa/include/trampoline.h index f6ab06f7..a79ac2a2 100644 --- a/core/src/main/cpp/external/yahfa/include/trampoline.h +++ b/core/src/main/cpp/external/yahfa/include/trampoline.h @@ -4,14 +4,11 @@ #ifndef YAHFA_TAMPOLINE_H #define YAHFA_TAMPOLINE_H -#ifdef __cplusplus -extern "C" { -#endif -extern size_t OFFSET_entry_point_from_quick_compiled_code_in_ArtMethod; -void setupTrampoline(); -void *genTrampoline(void *hookMethod); -#ifdef __cplusplus +namespace yahfa { + void setupTrampoline(); + + void *genTrampoline(void *hookMethod); } -#endif + #endif //YAHFA_TAMPOLINE_H diff --git a/core/src/main/cpp/external/yahfa/src/HookMain.cpp b/core/src/main/cpp/external/yahfa/src/HookMain.cpp index a87df609..1975f1b8 100644 --- a/core/src/main/cpp/external/yahfa/src/HookMain.cpp +++ b/core/src/main/cpp/external/yahfa/src/HookMain.cpp @@ -7,10 +7,11 @@ #include "trampoline.h" #include "HookMain.h" -int SDKVersion; -size_t OFFSET_entry_point_from_quick_compiled_code_in_ArtMethod; namespace yahfa { + size_t OFFSET_entry_point_from_quick_compiled_code_in_ArtMethod; + int SDKVersion; + namespace { constexpr size_t OFFSET_access_flags_in_ArtMethod = 4; constexpr uint32_t kAccCompileDontBother = 0x02000000; @@ -81,14 +82,11 @@ namespace yahfa { // 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), + getEntryPoint(targetMethod), newEntrypoint ); if (newEntrypoint) { - writeAddr((char *) targetMethod + - OFFSET_entry_point_from_quick_compiled_code_in_ArtMethod, - newEntrypoint); + setEntryPoint(targetMethod, newEntrypoint); } else { LOGE("failed to allocate space for trampoline of target method"); return 1; @@ -159,6 +157,16 @@ namespace yahfa { write32((char *) art_method + OFFSET_access_flags_in_ArtMethod, access_flags); } + void *getEntryPoint(void *art_method) { + return readAddr( + (char *) art_method + OFFSET_entry_point_from_quick_compiled_code_in_ArtMethod); + } + + void setEntryPoint(void *art_method, void *entry_point) { + writeAddr((char *) art_method + OFFSET_entry_point_from_quick_compiled_code_in_ArtMethod, + entry_point); + } + jobject findMethodNative(JNIEnv *env, [[maybe_unused]] jclass clazz, jclass targetClass, jstring methodName, diff --git a/core/src/main/cpp/external/yahfa/src/trampoline.cpp b/core/src/main/cpp/external/yahfa/src/trampoline.cpp index 984a8dc6..98d29f00 100644 --- a/core/src/main/cpp/external/yahfa/src/trampoline.cpp +++ b/core/src/main/cpp/external/yahfa/src/trampoline.cpp @@ -2,12 +2,12 @@ // Created by liuruikai756 on 05/07/2017. // #include -#include -#include +#include +#include #include -#include +#include #include -#include +#include #include #include #include @@ -19,13 +19,16 @@ static_assert(std::endian::native == std::endian::little, "Unsupported architecture"); -union Trampoline { - uintptr_t addr; - unsigned count : 12; -}; +namespace yahfa { + extern size_t OFFSET_entry_point_from_quick_compiled_code_in_ArtMethod; -static_assert(sizeof(Trampoline) == sizeof(uintptr_t), "Unsupported architecture"); -static_assert(std::atomic_uintptr_t ::is_always_lock_free, "Unsupported architecture"); + union Trampoline { + uintptr_t addr; + unsigned count: 12; + }; + + static_assert(sizeof(Trampoline) == sizeof(uintptr_t), "Unsupported architecture"); + static_assert(std::atomic_uintptr_t::is_always_lock_free, "Unsupported architecture"); // trampoline: // 1. set eax/r0/x0 to the hook ArtMethod addr @@ -34,110 +37,111 @@ static_assert(std::atomic_uintptr_t ::is_always_lock_free, "Unsupported architec // b8 78 56 34 12 ; mov eax, 0x12345678 (addr of the hook method) // ff 70 20 ; push DWORD PTR [eax + 0x20] // c3 ; ret -unsigned char trampoline[] = "\xb8\x78\x56\x34\x12\xff\x70\x20\xc3"; + unsigned char trampoline[] = "\xb8\x78\x56\x34\x12\xff\x70\x20\xc3"; #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] -// c3 ; ret -unsigned char trampoline[] = "\x48\xbf\x78\x56\x34\x12\x78\x56\x34\x12\xff\x77\x20\xc3"; + // 48 bf 78 56 34 12 78 56 34 12 ; movabs rdi, 0x1234567812345678 + // ff 77 20 ; push QWORD PTR [rdi + 0x20] + // c3 ; ret + unsigned char trampoline[] = "\x48\xbf\x78\x56\x34\x12\x78\x56\x34\x12\xff\x77\x20\xc3"; #elif defined(__arm__) -// 00 00 9F E5 ; ldr r0, [pc, #0] -// 20 F0 90 E5 ; ldr pc, [r0, 0x20] -// 78 56 34 12 ; 0x12345678 (addr of the hook method) -unsigned char trampoline[] = "\x00\x00\x9f\xe5\x20\xf0\x90\xe5\x78\x56\x34\x12"; + // 00 00 9F E5 ; ldr r0, [pc, #0] + // 20 F0 90 E5 ; ldr pc, [r0, 0x20] + // 78 56 34 12 ; 0x12345678 (addr of the hook method) + unsigned char trampoline[] = "\x00\x00\x9f\xe5\x20\xf0\x90\xe5\x78\x56\x34\x12"; #elif defined(__aarch64__) -// 60 00 00 58 ; ldr x0, 12 -// 10 00 40 F8 ; ldr x16, [x0, #0x00] -// 00 02 1f d6 ; br x16 -// 78 56 34 12 -// 78 56 34 12 ; 0x1234567812345678 (addr of the hook method) -unsigned char trampoline[] = "\x60\x00\x00\x58\x10\x00\x40\xf8\x00\x02\x1f\xd6\x78\x56\x34\x12\x78\x56\x34\x12"; + // 60 00 00 58 ; ldr x0, 12 + // 10 00 40 F8 ; ldr x16, [x0, #0x00] + // 00 02 1f d6 ; br x16 + // 78 56 34 12 + // 78 56 34 12 ; 0x1234567812345678 (addr of the hook method) + unsigned char trampoline[] = "\x60\x00\x00\x58\x10\x00\x40\xf8\x00\x02\x1f\xd6\x78\x56\x34\x12\x78\x56\x34\x12"; #endif -static std::atomic_uintptr_t trampoline_pool{0}; -static std::atomic_flag trampoline_lock{false}; -static constexpr size_t trampolineSize = roundUpToPtrSize(sizeof(trampoline)); -static constexpr size_t pageSize = 4096; -static constexpr size_t trampolineNumPerPage = pageSize / trampolineSize; + static std::atomic_uintptr_t trampoline_pool{0}; + static std::atomic_flag trampoline_lock{false}; + static constexpr size_t trampolineSize = roundUpToPtrSize(sizeof(trampoline)); + static constexpr size_t pageSize = 4096; + static constexpr size_t trampolineNumPerPage = pageSize / trampolineSize; -static inline void FlushCache(void *addr, size_t size) { - __builtin___clear_cache((char *) addr, (char *) ((uintptr_t) addr + size)); -} + static inline void FlushCache(void *addr, size_t size) { + __builtin___clear_cache((char *) addr, (char *) ((uintptr_t) addr + size)); + } -void *genTrampoline(void *hookMethod) { - unsigned count; - uintptr_t addr; - while (true) { - auto tl = Trampoline {.addr = trampoline_pool.fetch_add(1, std::memory_order_release)}; - count = tl.count; - addr = tl.addr & ~uintptr_t(0xfff); - if (addr == 0 || count >= trampolineNumPerPage) { - if (trampoline_lock.test_and_set(std::memory_order_acq_rel)) { - trampoline_lock.wait(true, std::memory_order_acquire); - continue; - } else { - addr = reinterpret_cast(mmap(nullptr, pageSize, - PROT_READ | PROT_WRITE | PROT_EXEC, - MAP_ANONYMOUS | MAP_PRIVATE, -1, 0)); - if (addr == reinterpret_cast(MAP_FAILED)) { - LOGE("mmap failed, errno = %s", strerror(errno)); + void *genTrampoline(void *hookMethod) { + unsigned count; + uintptr_t addr; + while (true) { + auto tl = Trampoline{.addr = trampoline_pool.fetch_add(1, std::memory_order_release)}; + count = tl.count; + addr = tl.addr & ~uintptr_t(0xfff); + if (addr == 0 || count >= trampolineNumPerPage) { + if (trampoline_lock.test_and_set(std::memory_order_acq_rel)) { + trampoline_lock.wait(true, std::memory_order_acquire); + continue; + } else { + addr = reinterpret_cast(mmap(nullptr, pageSize, + PROT_READ | PROT_WRITE | PROT_EXEC, + MAP_ANONYMOUS | MAP_PRIVATE, -1, 0)); + if (addr == reinterpret_cast(MAP_FAILED)) { + LOGE("mmap failed, errno = %s", strerror(errno)); + trampoline_lock.clear(std::memory_order_release); + trampoline_lock.notify_all(); + return nullptr; + } + count = 0; + tl.addr = addr; + tl.count = count + 1; + trampoline_pool.store(tl.addr, std::memory_order_release); trampoline_lock.clear(std::memory_order_release); trampoline_lock.notify_all(); - return nullptr; } - count = 0; - tl.addr = addr; - tl.count = count + 1; - trampoline_pool.store(tl.addr, std::memory_order_release); - trampoline_lock.clear(std::memory_order_release); - trampoline_lock.notify_all(); } + LOGI("trampoline: count = %u, addr = %zx, target = %zx", count, addr, + addr + count * trampolineSize); + addr = addr + count * trampolineSize; + break; } - LOGI("trampoline: count = %u, addr = %zx, target = %zx", count, addr, addr + count * trampolineSize); - addr = addr + count * trampolineSize; - break; + unsigned char *targetAddr = reinterpret_cast(addr); + memcpy(targetAddr, trampoline, + sizeof(trampoline)); // do not use trampolineSize since it's a rounded size + + // replace with the actual ArtMethod addr +#if defined(__i386__) + memcpy(targetAddr + 1, &hookMethod, pointer_size); + +#elif defined(__x86_64__) + memcpy((char*)targetAddr + 2, &hookMethod, pointer_size); + +#elif defined(__arm__) + memcpy(targetAddr+8, &hookMethod, pointer_size); + +#elif defined(__aarch64__) + memcpy(targetAddr + 12, &hookMethod, pointer_size); + +#else +#error Unsupported architecture +#endif + FlushCache(targetAddr, sizeof(trampoline)); + + return targetAddr; } - unsigned char *targetAddr = reinterpret_cast(addr); -// unsigned char*targetAddr = reinterpret_cast(mmap(NULL, trampolineSize, PROT_READ | PROT_WRITE | PROT_EXEC, -// MAP_ANONYMOUS | MAP_PRIVATE, -1, 0)); - memcpy(targetAddr, trampoline, - sizeof(trampoline)); // do not use trampolineSize since it's a rounded size - // replace with the actual ArtMethod addr + void setupTrampoline() { #if defined(__i386__) - memcpy(targetAddr+1, &hookMethod, pointer_size); - + trampoline[7] = (unsigned char) OFFSET_entry_point_from_quick_compiled_code_in_ArtMethod; #elif defined(__x86_64__) - memcpy((char*)targetAddr + 2, &hookMethod, pointer_size); - + trampoline[12] = (unsigned char)OFFSET_entry_point_from_quick_compiled_code_in_ArtMethod; #elif defined(__arm__) - memcpy(targetAddr+8, &hookMethod, pointer_size); - + trampoline[4] = (unsigned char)OFFSET_entry_point_from_quick_compiled_code_in_ArtMethod; #elif defined(__aarch64__) - memcpy(targetAddr + 12, &hookMethod, pointer_size); - + 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 - FlushCache(targetAddr, sizeof(trampoline)); + } - return targetAddr; -} - -void setupTrampoline() { -#if defined(__i386__) - trampoline[7] = (unsigned char)OFFSET_entry_point_from_quick_compiled_code_in_ArtMethod; -#elif defined(__x86_64__) - trampoline[12] = (unsigned char)OFFSET_entry_point_from_quick_compiled_code_in_ArtMethod; -#elif defined(__arm__) - trampoline[4] = (unsigned char)OFFSET_entry_point_from_quick_compiled_code_in_ArtMethod; -#elif defined(__aarch64__) - 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 } diff --git a/core/src/main/cpp/main/include/art/runtime/class_linker.h b/core/src/main/cpp/main/include/art/runtime/class_linker.h index 11b258f1..80392124 100644 --- a/core/src/main/cpp/main/include/art/runtime/class_linker.h +++ b/core/src/main/cpp/main/include/art/runtime/class_linker.h @@ -101,6 +101,9 @@ namespace art { return backup(art_method, quick_code); }); + CREATE_FUNC_SYMBOL_ENTRY(void, art_quick_to_interpreter_bridge, void*) {} + CREATE_FUNC_SYMBOL_ENTRY(void, art_quick_generic_jni_trampoline, void*) {} + public: ClassLinker(void *thiz) : HookedObject(thiz) {} @@ -117,7 +120,9 @@ namespace art { RETRIEVE_MEM_FUNC_SYMBOL(SetEntryPointsToInterpreter, "_ZNK3art11ClassLinker27SetEntryPointsToInterpreterEPNS_9ArtMethodE"); - lspd::HookSyms(handle, ShouldUseInterpreterEntrypoint); + if (api_level < __ANDROID_API_T__) { + lspd::HookSyms(handle, ShouldUseInterpreterEntrypoint); + } if (api_level >= __ANDROID_API_R__) { // In android R, FixupStaticTrampolines won't be called unless it's marking it as @@ -139,6 +144,11 @@ namespace art { // "_ZN3art11ClassLinker40MakeInitializedClassesVisiblyInitializedEPNS_6ThreadEb"); // } + RETRIEVE_FUNC_SYMBOL(art_quick_to_interpreter_bridge, "art_quick_to_interpreter_bridge"); + RETRIEVE_FUNC_SYMBOL(art_quick_generic_jni_trampoline, "art_quick_generic_jni_trampoline"); + + LOGD("art_quick_to_interpreter_bridge = %p", art_quick_to_interpreter_bridgeSym); + LOGD("art_quick_generic_jni_trampoline = %p", art_quick_generic_jni_trampolineSym); } [[gnu::always_inline]] @@ -151,6 +161,15 @@ namespace art { [[gnu::always_inline]] void SetEntryPointsToInterpreter(void *art_method) const { + if (art_quick_to_interpreter_bridgeSym && art_quick_generic_jni_trampolineSym) [[likely]] { + if (yahfa::getAccessFlags(art_method) & yahfa::kAccNative) [[unlikely]] { + yahfa::setEntryPoint(art_method, + reinterpret_cast(art_quick_generic_jni_trampolineSym)); + } else { + yahfa::setEntryPoint(art_method, + reinterpret_cast(art_quick_to_interpreter_bridgeSym)); + } + } SetEntryPointsToInterpreter(thiz_, art_method); }