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 4479b2c6..a50518b5 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 @@ -34,9 +34,58 @@ namespace art { class ClassLinker : public lspd::HookedObject { - private: - inline static ClassLinker *instance_; + [[gnu::always_inline]] + static auto MaybeDelayHook(void *clazz_ptr) { + std::vector> out; + art::mirror::Class mirror_class(clazz_ptr); + auto class_def = mirror_class.GetClassDef(); + if (!class_def) return out; + auto set = lspd::isClassHooked(class_def); + if (!set.empty()) [[unlikely]] { + LOGD("Pending hook for %p (%s)", clazz_ptr, + art::mirror::Class(clazz_ptr).GetDescriptor().c_str()); + for (auto art_method : set) { + out.emplace_back(art_method, yahfa::getEntryPoint(art_method)); + } + } + return out; + } + + [[gnu::always_inline]] + static void FixTrampoline(const std::vector>& methods) { + for (const auto &[art_method, old_trampoline] : methods) { + auto *new_trampoline = yahfa::getEntryPoint(art_method); + auto *backup = lspd::isHooked(art_method); + if (backup && new_trampoline != old_trampoline) { + yahfa::setEntryPoint(backup, new_trampoline); + yahfa::setEntryPoint(art_method, old_trampoline); + } + } + } + + CREATE_MEM_HOOK_STUB_ENTRIES( + "_ZN3art11ClassLinker22FixupStaticTrampolinesENS_6ObjPtrINS_6mirror5ClassEEE", + void, FixupStaticTrampolines, (void * thiz, void * clazz_ptr), { + auto b = MaybeDelayHook(clazz_ptr); + backup(thiz, clazz_ptr); + FixTrampoline(b); + }); + + CREATE_MEM_HOOK_STUB_ENTRIES( + "_ZN3art11ClassLinker22FixupStaticTrampolinesEPNS_6ThreadENS_6ObjPtrINS_6mirror5ClassEEE", + void, FixupStaticTrampolinesWithThread, + (void * thiz, void * self, void * clazz_ptr), { + auto b = MaybeDelayHook(clazz_ptr); + backup(thiz, self, clazz_ptr); + FixTrampoline(b); + }); + + CREATE_MEM_FUNC_SYMBOL_ENTRY(void, MakeInitializedClassesVisiblyInitialized, void *thiz, + void *self, bool wait) { + if (MakeInitializedClassesVisiblyInitializedSym) [[likely]] + MakeInitializedClassesVisiblyInitializedSym(thiz, self, wait); + } CREATE_MEM_FUNC_SYMBOL_ENTRY(void, SetEntryPointsToInterpreter, void *thiz, void *art_method) { @@ -66,21 +115,15 @@ namespace art { }); public: - ClassLinker(void *thiz) : HookedObject(thiz) {} - - inline static ClassLinker *Current() { - return instance_; - } - // @ApiSensitive(Level.MIDDLE) inline static void Setup(const SandHook::ElfImg &handle) { - instance_ = new ClassLinker(nullptr); // make it nullptr - RETRIEVE_MEM_FUNC_SYMBOL(SetEntryPointsToInterpreter, "_ZNK3art11ClassLinker27SetEntryPointsToInterpreterEPNS_9ArtMethodE"); lspd::HookSyms(handle, ShouldUseInterpreterEntrypoint, ShouldStayInSwitchInterpreter); + lspd::HookSyms(handle, FixupStaticTrampolinesWithThread, FixupStaticTrampolines); + 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"); @@ -89,7 +132,7 @@ namespace art { } [[gnu::always_inline]] - void SetEntryPointsToInterpreter(void *art_method) const { + static void SetEntryPointsToInterpreter(void *art_method) { if (art_quick_to_interpreter_bridgeSym && art_quick_generic_jni_trampolineSym) [[likely]] { if (yahfa::getAccessFlags(art_method) & yahfa::kAccNative) [[unlikely]] { yahfa::setEntryPoint(art_method, @@ -99,7 +142,7 @@ namespace art { reinterpret_cast(art_quick_to_interpreter_bridgeSym)); } } - SetEntryPointsToInterpreter(thiz_, art_method); + SetEntryPointsToInterpreter(nullptr, art_method); } }; diff --git a/core/src/main/cpp/main/include/art/runtime/instrumentation.h b/core/src/main/cpp/main/include/art/runtime/instrumentation.h deleted file mode 100644 index 77cae34c..00000000 --- a/core/src/main/cpp/main/include/art/runtime/instrumentation.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - * This file is part of LSPosed. - * - * LSPosed is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * LSPosed is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with LSPosed. If not, see . - * - * Copyright (C) 2020 EdXposed Contributors - * Copyright (C) 2021 LSPosed Contributors - */ - -#ifndef LSPOSED_INSTRUMENTATION_H -#define LSPOSED_INSTRUMENTATION_H - -#include "base/object.h" - -namespace art { - namespace instrumentation { - - CREATE_MEM_HOOK_STUB_ENTRIES( - "_ZN3art15instrumentation15Instrumentation21UpdateMethodsCodeImplEPNS_9ArtMethodEPKv", - void, UpdateMethodsCodeImpl, (void * thiz, void * art_method, const void *quick_code), { - if (auto backup = lspd::isHooked(art_method); - backup && yahfa::getEntryPoint(art_method) != quick_code) [[unlikely]] { - LOGD("redirect update method code for hooked method %s to its backup", - art_method::PrettyMethod(art_method).c_str()); - art_method = backup; - } - backup(thiz, art_method, quick_code); - }); - - CREATE_MEM_HOOK_STUB_ENTRIES( - "_ZN3art15instrumentation15Instrumentation17UpdateMethodsCodeEPNS_9ArtMethodEPKv", - void, UpdateMethodsCode, (void * thiz, void * art_method, const void *quick_code), { - if (auto backup = lspd::isHooked(art_method); - backup && yahfa::getEntryPoint(art_method) != quick_code) [[unlikely]] { - LOGD("redirect update method code for hooked method %s to its backup", - art_method::PrettyMethod(art_method).c_str()); - art_method = backup; - } - // avoid calling our hook again - if (UpdateMethodsCodeImpl.backup) { - UpdateMethodsCodeImpl.backup(thiz, art_method, quick_code); - } else { - backup(thiz, art_method, quick_code); - } - }); - - inline void DisableUpdateHookedMethodsCode(const SandHook::ElfImg &handle) { - lspd::HookSym(handle, UpdateMethodsCode); - lspd::HookSym(handle, UpdateMethodsCodeImpl); - } - } -} -#endif //LSPOSED_INSTRUMENTATION_H diff --git a/core/src/main/cpp/main/src/jni/art_class_linker.cpp b/core/src/main/cpp/main/src/jni/art_class_linker.cpp index 9f7895b5..3e911115 100644 --- a/core/src/main/cpp/main/src/jni/art_class_linker.cpp +++ b/core/src/main/cpp/main/src/jni/art_class_linker.cpp @@ -30,7 +30,7 @@ namespace lspd { LSP_DEF_NATIVE_METHOD(void, ClassLinker, setEntryPointsToInterpreter, jobject method) { void *reflected_method = yahfa::getArtMethod(env, method); LOGD("deoptimizing method: %p", reflected_method); - art::ClassLinker::Current()->SetEntryPointsToInterpreter(reflected_method); + art::ClassLinker::SetEntryPointsToInterpreter(reflected_method); LOGD("method deoptimized: %p", reflected_method); } diff --git a/core/src/main/cpp/main/src/jni/yahfa.cpp b/core/src/main/cpp/main/src/jni/yahfa.cpp index 9fab9d41..73647167 100644 --- a/core/src/main/cpp/main/src/jni/yahfa.cpp +++ b/core/src/main/cpp/main/src/jni/yahfa.cpp @@ -37,6 +37,9 @@ namespace lspd { std::vector> jit_movements_; std::shared_mutex jit_movements_lock_; + + std::unordered_map> hooked_classes_; + std::shared_mutex hooked_classes_lock_; } void* isHooked(void *art_method) { @@ -48,10 +51,27 @@ namespace lspd { } void recordHooked(void *art_method, void *backup) { - std::unique_lock lk(hooked_methods_lock_); - hooked_methods_.emplace(art_method, backup); + { + std::unique_lock lk(hooked_methods_lock_); + hooked_methods_.emplace(art_method, backup); + } + auto clazz = art::mirror::Class(reinterpret_cast(*reinterpret_cast(art_method))); + { + std::unique_lock lk(hooked_classes_lock_); + hooked_classes_[clazz.GetClassDef()].emplace(art_method); + } } + const std::unordered_set &isClassHooked(void *clazz) { + static std::unordered_set empty; + std::shared_lock lk(hooked_classes_lock_); + if (auto found = hooked_classes_.find(clazz); found != hooked_classes_.end()) { + return found->second; + } + return empty; + } + + void recordJitMovement(void *target, void *backup) { std::unique_lock lk(jit_movements_lock_); jit_movements_.emplace_back(target, backup); diff --git a/core/src/main/cpp/main/src/jni/yahfa.h b/core/src/main/cpp/main/src/jni/yahfa.h index 0b1fc594..c6be13fe 100644 --- a/core/src/main/cpp/main/src/jni/yahfa.h +++ b/core/src/main/cpp/main/src/jni/yahfa.h @@ -21,6 +21,7 @@ #pragma once #include "jni.h" +#include #include #include @@ -30,6 +31,8 @@ namespace lspd { std::vector> getJitMovements(); + const std::unordered_set &isClassHooked(void *clazz); + void RegisterYahfa(JNIEnv *); } // namespace lspd diff --git a/core/src/main/cpp/main/src/native_hook.cpp b/core/src/main/cpp/main/src/native_hook.cpp index 712daa88..aeb15c86 100644 --- a/core/src/main/cpp/main/src/native_hook.cpp +++ b/core/src/main/cpp/main/src/native_hook.cpp @@ -33,7 +33,6 @@ #include "art/runtime/class_linker.h" #include "art/runtime/thread.h" #include "art/runtime/hidden_api.h" -#include "art/runtime/instrumentation.h" #include "art/runtime/thread_list.h" #include "art/runtime/gc/scoped_gc_critical_section.h" #include "art/runtime/jit/jit_code_cache.h" @@ -58,7 +57,6 @@ namespace lspd { art::ClassLinker::Setup(handle_libart); art::mirror::Class::Setup(handle_libart); art::JNIEnvExt::Setup(handle_libart); - art::instrumentation::DisableUpdateHookedMethodsCode(handle_libart); art::thread_list::ScopedSuspendAll::Setup(handle_libart); art::gc::ScopedGCCriticalSection::Setup(handle_libart); art::jit::jit_code_cache::Setup(handle_libart);