diff --git a/lsplant/src/main/jni/art/mirror/class.cxx b/lsplant/src/main/jni/art/mirror/class.cxx index 3d46810..86ea836 100644 --- a/lsplant/src/main/jni/art/mirror/class.cxx +++ b/lsplant/src/main/jni/art/mirror/class.cxx @@ -3,7 +3,6 @@ module; #include #include "logging.hpp" -#include "utils/hook_helper.hpp" export module clazz; @@ -11,23 +10,20 @@ import common; import art_method; import thread; import handle; +import hook_helper; namespace lsplant::art::mirror { export class Class { private: - CREATE_MEM_FUNC_SYMBOL_ENTRY(const char *, GetDescriptor, Class *thiz, std::string *storage) { - if (GetDescriptorSym) [[likely]] - return GetDescriptorSym(thiz, storage); - else - return ""; - } + inline static MemberFunction< + "_ZN3art6mirror5Class13GetDescriptorEPNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEE", + Class, const char *(std::string *)> + GetDescriptor_; - CREATE_MEM_FUNC_SYMBOL_ENTRY(const dex::ClassDef *, GetClassDef, Class *thiz) { - if (GetClassDefSym) [[likely]] - return GetClassDefSym(thiz); - return nullptr; - } + inline static MemberFunction<"_ZN3art6mirror5Class11GetClassDefEv", Class, + const dex::ClassDef *()> + GetClassDef_; using BackupMethods = phmap::flat_hash_map; inline static phmap::flat_hash_map h, uint8_t new_status, Thread *self), { + inline static Hooker< + "_ZN3art6mirror5Class9SetStatusENS_6HandleIS1_EENS_11ClassStatusEPNS_6ThreadE", + void(TrivialHandle, uint8_t, Thread *)> + SetClassStatus_ = +[](TrivialHandle h, uint8_t new_status, Thread *self) { if (new_status == initialized_status) { - BackupClassMethods(h->GetClassDef(), self); + BackupClassMethods(GetClassDef_(h.Get()), self); } - return backup(h, new_status, self); - }); + return SetClassStatus_(h, new_status, self); + }; - CREATE_HOOK_STUB_ENTRY( - "_ZN3art6mirror5Class9SetStatusENS_6HandleIS1_EENS1_6StatusEPNS_6ThreadE", void, SetStatus, - (Handle h, int new_status, Thread *self), { + inline static Hooker<"_ZN3art6mirror5Class9SetStatusENS_6HandleIS1_EENS1_6StatusEPNS_6ThreadE", + void(Handle, int, Thread *)> + SetStatus_ = +[](Handle h, int new_status, Thread *self) { if (new_status == static_cast(initialized_status)) { - BackupClassMethods(h->GetClassDef(), self); + BackupClassMethods(GetClassDef_(h.Get()), self); } - return backup(h, new_status, self); - }); + return SetStatus_(h, new_status, self); + }; - CREATE_HOOK_STUB_ENTRY( - "_ZN3art6mirror5Class9SetStatusENS_6HandleIS1_EENS1_6StatusEPNS_6ThreadE", void, - TrivialSetStatus, (TrivialHandle h, uint32_t new_status, Thread *self), { + inline static Hooker<"_ZN3art6mirror5Class9SetStatusENS_6HandleIS1_EENS1_6StatusEPNS_6ThreadE", + void(TrivialHandle, uint32_t, Thread *)> + TrivialSetStatus_ = +[](TrivialHandle h, uint32_t new_status, Thread *self) { if (new_status == initialized_status) { - BackupClassMethods(h->GetClassDef(), self); + BackupClassMethods(GetClassDef_(h.Get()), self); } - return backup(h, new_status, self); - }); + return TrivialSetStatus_(h, new_status, self); + }; - CREATE_MEM_HOOK_STUB_ENTRY("_ZN3art6mirror5Class9SetStatusENS1_6StatusEPNS_6ThreadE", void, - ClassSetStatus, (Class * thiz, int new_status, Thread *self), { - if (new_status == static_cast(initialized_status)) { - BackupClassMethods(thiz->GetClassDef(), self); - } - return backup(thiz, new_status, self); - }); - - inline static uint8_t initialized_status = 0; + inline static Hooker<"_ZN3art6mirror5Class9SetStatusENS1_6StatusEPNS_6ThreadE", + void(Class *, int, Thread *)> + ClassSetStatus_ = +[](Class *thiz, int new_status, Thread *self) { + if (new_status == static_cast(initialized_status)) { + BackupClassMethods(GetClassDef_(thiz), self); + } + return ClassSetStatus_(thiz, new_status, self); + }; public: static bool Init(const HookHandler &handler) { - if (!RETRIEVE_MEM_FUNC_SYMBOL(GetDescriptor, - "_ZN3art6mirror5Class13GetDescriptorEPNSt3__112" - "basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEE")) { - return false; - } - if (!RETRIEVE_MEM_FUNC_SYMBOL(GetClassDef, "_ZN3art6mirror5Class11GetClassDefEv")) { + if (!handler.dlsym(GetDescriptor_) || !handler.dlsym(GetClassDef_)) { return false; } int sdk_int = GetAndroidApiLevel(); if (sdk_int < __ANDROID_API_O__) { - if (!HookSyms(handler, SetStatus, ClassSetStatus)) { + if (!handler.hook(SetStatus_, ClassSetStatus_)) { return false; } } else { - if (!HookSyms(handler, SetClassStatus, TrivialSetStatus)) { + if (!handler.hook(SetClassStatus_, TrivialSetStatus_)) { return false; } } @@ -137,22 +130,14 @@ public: return true; } - const char *GetDescriptor(std::string *storage) { - if (GetDescriptorSym) { - return GetDescriptor(this, storage); - } - return ""; - } + const char *GetDescriptor(std::string *storage) { return GetDescriptor_(this, storage); } std::string GetDescriptor() { std::string storage; return GetDescriptor(&storage); } - const dex::ClassDef *GetClassDef() { - if (GetClassDefSym) return GetClassDef(this); - return nullptr; - } + const dex::ClassDef *GetClassDef() { return GetClassDef_(this); } static auto PopBackup(const dex::ClassDef *class_def, art::Thread *self) { BackupMethods methods; diff --git a/lsplant/src/main/jni/art/runtime/art_method.cxx b/lsplant/src/main/jni/art/runtime/art_method.cxx index f325654..1afe574 100644 --- a/lsplant/src/main/jni/art/runtime/art_method.cxx +++ b/lsplant/src/main/jni/art/runtime/art_method.cxx @@ -1,11 +1,14 @@ module; +#include +#include + #include "logging.hpp" -#include "utils/hook_helper.hpp" export module art_method; import common; +import hook_helper; namespace lsplant::art { namespace mirror { @@ -13,33 +16,43 @@ class Class; } export class ArtMethod { - CREATE_FUNC_SYMBOL_ENTRY(std::string, PrettyMethod, ArtMethod *thiz, bool with_signature) { - if (thiz == nullptr) [[unlikely]] - return "null"; - else if (PrettyMethodSym) [[likely]] - return PrettyMethodSym(thiz, with_signature); - else - return "null sym"; + inline static MemberFunction<"_ZN3art9ArtMethod12PrettyMethodEPS0_b", ArtMethod, + std::string(bool)> + PrettyMethod_; + + inline static Function<"_ZN3art12PrettyMethodEPNS_9ArtMethodEb", + std::string(ArtMethod *thiz, bool with_signature)> + PrettyMethodStatic_; + + inline static Function<"_ZN3art12PrettyMethodEPNS_6mirror9ArtMethodEb", + std::string(ArtMethod *thiz, bool with_signature)> + PrettyMethodMirror_; + + inline static Function<"_ZN3artL15GetMethodShortyEP7_JNIEnvP10_jmethodID", + const char *(JNIEnv *env, jmethodID method)> + GetMethodShortyL_; + inline static Function<"_ZN3art15GetMethodShortyEP7_JNIEnvP10_jmethodID", + const char *(JNIEnv *env, jmethodID mid)> + GetMethodShorty_; + + inline static MemberFunction<"_ZN3art9ArtMethod24ThrowInvocationTimeErrorEv", ArtMethod, void()> + ThrowInvocationTimeError_; + + inline static Function<"artInterpreterToCompiledCodeBridge", void()> + art_interpreter_to_compiled_code_bridge_; + + inline void ThrowInvocationTimeError() { + if (ThrowInvocationTimeError_) { + [[likely]] ThrowInvocationTimeError_(this); + } } - CREATE_MEM_FUNC_SYMBOL_ENTRY(void, ThrowInvocationTimeError, ArtMethod *thiz) { - if (thiz && ThrowInvocationTimeErrorSym) [[likely]] - return ThrowInvocationTimeErrorSym(thiz); - } - - CREATE_FUNC_SYMBOL_ENTRY(const char *, GetMethodShorty, JNIEnv *env, jmethodID mid) { - if (GetMethodShortySym) [[likely]] - return GetMethodShortySym(env, mid); - return nullptr; - } - - CREATE_FUNC_SYMBOL_ENTRY(void, art_interpreter_to_compiled_code_bridge) {} - - inline void ThrowInvocationTimeError() { ThrowInvocationTimeError(this); } - public: inline static const char *GetMethodShorty(JNIEnv *env, jobject method) { - return GetMethodShorty(env, env->FromReflectedMethod(method)); + if (GetMethodShortyL_) { + return GetMethodShortyL_(env, env->FromReflectedMethod(method)); + } + return GetMethodShorty_(env, env->FromReflectedMethod(method)); } void SetNonCompilable() { @@ -101,7 +114,7 @@ public: if (interpreter_entry_point_offset) [[unlikely]] { *reinterpret_cast(reinterpret_cast(this) + interpreter_entry_point_offset) = - reinterpret_cast(art_interpreter_to_compiled_code_bridgeSym); + reinterpret_cast(&art_interpreter_to_compiled_code_bridge_); } } @@ -130,7 +143,11 @@ public: } std::string PrettyMethod(bool with_signature = true) { - return PrettyMethod(this, with_signature); + if (PrettyMethod_) [[likely]] + return PrettyMethod_(this, with_signature); + if (PrettyMethodStatic_) return PrettyMethodStatic_(this, with_signature); + if (PrettyMethodMirror_) return PrettyMethodMirror_(this, with_signature); + return "null sym"; } mirror::Class *GetDeclaringClass() { @@ -229,7 +246,7 @@ public: JNI_GetObjectField( env, JNI_ToReflectedField(env, executable, - JNI_GetFieldID(env, executable, name, sig), false), + JNI_GetFieldID(env, executable, name, sig), false), art_field_field), field_offset); }; @@ -256,17 +273,13 @@ public: } if (sdk_int < __ANDROID_API_Q__) kAccFastInterpreterToInterpreterInvoke = 0; - if (!RETRIEVE_FUNC_SYMBOL(GetMethodShorty, - "_ZN3artL15GetMethodShortyEP7_JNIEnvP10_jmethodID", true) && - !RETRIEVE_FUNC_SYMBOL(GetMethodShorty, - "_ZN3art15GetMethodShortyEP7_JNIEnvP10_jmethodID")) { + if (!handler.dlsym(GetMethodShortyL_, true) && !handler.dlsym(GetMethodShorty_)) { LOGE("Failed to find GetMethodShorty"); return false; } - !RETRIEVE_FUNC_SYMBOL(PrettyMethod, "_ZN3art9ArtMethod12PrettyMethodEPS0_b") && - !RETRIEVE_FUNC_SYMBOL(PrettyMethod, "_ZN3art12PrettyMethodEPNS_9ArtMethodEb") && - !RETRIEVE_FUNC_SYMBOL(PrettyMethod, "_ZN3art12PrettyMethodEPNS_6mirror9ArtMethodEb"); + handler.dlsym(PrettyMethod_) || handler.dlsym(PrettyMethodStatic_) || + handler.dlsym(PrettyMethodMirror_); if (sdk_int <= __ANDROID_API_O__) [[unlikely]] { auto abstract_method_error = JNI_FindClass(env, "java/lang/AbstractMethodError"); @@ -281,8 +294,7 @@ public: LOGE("Failed to find Executable.getName"); return false; } - RETRIEVE_MEM_FUNC_SYMBOL(ThrowInvocationTimeError, - "_ZN3art9ArtMethod24ThrowInvocationTimeErrorEv"); + handler.dlsym(ThrowInvocationTimeError_); auto abstract_method = FromReflectedMethod( env, JNI_ToReflectedMethod(env, executable, executable_get_name, false).get()); uint32_t access_flags = abstract_method->GetAccessFlags(); @@ -301,8 +313,7 @@ public: kAccCompileDontBother = 0; } if (sdk_int <= __ANDROID_API_M__) [[unlikely]] { - if (!RETRIEVE_FUNC_SYMBOL(art_interpreter_to_compiled_code_bridge, - "artInterpreterToCompiledCodeBridge")) { + if (!handler.dlsym(art_interpreter_to_compiled_code_bridge_)) { return false; } if (sdk_int >= __ANDROID_API_L_MR1__) { diff --git a/lsplant/src/main/jni/art/runtime/class_linker.cxx b/lsplant/src/main/jni/art/runtime/class_linker.cxx index f31a923..8d9a105 100644 --- a/lsplant/src/main/jni/art/runtime/class_linker.cxx +++ b/lsplant/src/main/jni/art/runtime/class_linker.cxx @@ -1,6 +1,7 @@ module; -#include "include/utils/hook_helper.hpp" +#include + #include "logging.hpp" export module class_linker; @@ -10,29 +11,29 @@ import thread; import common; import clazz; import handle; +import hook_helper; namespace lsplant::art { export class ClassLinker { private: - CREATE_MEM_FUNC_SYMBOL_ENTRY(void, SetEntryPointsToInterpreter, ClassLinker *thiz, - ArtMethod *art_method) { - if (SetEntryPointsToInterpreterSym) [[likely]] { - SetEntryPointsToInterpreterSym(thiz, art_method); - } - } + inline static MemberFunction< + "_ZNK3art11ClassLinker27SetEntryPointsToInterpreterEPNS_9ArtMethodE", ClassLinker, + void(ArtMethod *)> + SetEntryPointsToInterpreter_; - CREATE_HOOK_STUB_ENTRY( - "_ZN3art11ClassLinker30ShouldUseInterpreterEntrypointEPNS_9ArtMethodEPKv", bool, - ShouldUseInterpreterEntrypoint, (ArtMethod * art_method, const void *quick_code), { + inline static Hooker<"_ZN3art11ClassLinker30ShouldUseInterpreterEntrypointEPNS_9ArtMethodEPKv", + bool(ArtMethod *, const void *)> + ShouldUseInterpreterEntrypoint_ = +[](ArtMethod *art_method, const void *quick_code) { if (quick_code != nullptr && IsHooked(art_method)) [[unlikely]] { return false; } - return backup(art_method, quick_code); - }); + return ShouldUseInterpreterEntrypoint_(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 *) {} + inline static Function<"art_quick_to_interpreter_bridge", void(void *)> + art_quick_to_interpreter_bridge_; + inline static Function<"art_quick_generic_jni_trampoline", void(void *)> + art_quick_generic_jni_trampoline_; inline static art::ArtMethod *MayGetBackup(art::ArtMethod *method) { if (auto backup = IsHooked(method); backup) [[unlikely]] { @@ -42,44 +43,60 @@ private: return method; } - CREATE_MEM_HOOK_STUB_ENTRY( - "_ZN3art6mirror9ArtMethod14RegisterNativeEPNS_6ThreadEPKvb", void, RegisterNativeThread, - (art::ArtMethod * method, art::Thread *thread, const void *native_method, bool is_fast), - { return backup(MayGetBackup(method), thread, native_method, is_fast); }); + inline static MemberHooker<"_ZN3art6mirror9ArtMethod14RegisterNativeEPNS_6ThreadEPKvb", + ClassLinker, void(ArtMethod *, Thread *, const void *, bool)> + RegisterNativeThread_ = +[](ClassLinker *thiz, ArtMethod *method, Thread *thread, + const void *native_method, bool is_fast) { + return RegisterNativeThread_(thiz, MayGetBackup(method), thread, native_method, + is_fast); + }; - CREATE_MEM_HOOK_STUB_ENTRY("_ZN3art6mirror9ArtMethod16UnregisterNativeEPNS_6ThreadE", void, - UnregisterNativeThread, - (art::ArtMethod * method, art::Thread *thread), - { return backup(MayGetBackup(method), thread); }); + inline static MemberHooker<"_ZN3art6mirror9ArtMethod16UnregisterNativeEPNS_6ThreadE", + ClassLinker, void(ArtMethod *, Thread *)> + UnregisterNativeThread_ = +[](ClassLinker *thiz, ArtMethod *method, Thread *thread) { + return UnregisterNativeThread_(thiz, MayGetBackup(method), thread); + }; - CREATE_MEM_HOOK_STUB_ENTRY("_ZN3art9ArtMethod14RegisterNativeEPKvb", void, RegisterNativeFast, - (art::ArtMethod * method, const void *native_method, bool is_fast), - { return backup(MayGetBackup(method), native_method, is_fast); }); + inline static MemberHooker<"_ZN3art9ArtMethod14RegisterNativeEPKvb", ClassLinker, + void(ArtMethod *, const void *, bool)> + RegisterNativeFast_ = + +[](ClassLinker *thiz, ArtMethod *method, const void *native_method, bool is_fast) { + return RegisterNativeFast_(thiz, MayGetBackup(method), native_method, is_fast); + }; - CREATE_MEM_HOOK_STUB_ENTRY("_ZN3art9ArtMethod16UnregisterNativeEv", void, UnregisterNativeFast, - (art::ArtMethod * method), { return backup(MayGetBackup(method)); }); + inline static MemberHooker<"_ZN3art9ArtMethod16UnregisterNativeEv", ClassLinker, + void(ArtMethod *)> + UnregisterNativeFast_ = +[](ClassLinker *thiz, ArtMethod *method) { + return UnregisterNativeFast_(thiz, MayGetBackup(method)); + }; - CREATE_MEM_HOOK_STUB_ENTRY("_ZN3art9ArtMethod14RegisterNativeEPKv", const void *, - RegisterNative, (art::ArtMethod * method, const void *native_method), - { return backup(MayGetBackup(method), native_method); }); + inline static MemberHooker<"_ZN3art9ArtMethod14RegisterNativeEPKv", ClassLinker, + const void *(ArtMethod *, const void *)> + RegisterNative_ = +[](ClassLinker *thiz, ArtMethod *method, const void *native_method) { + return RegisterNative_(thiz, MayGetBackup(method), native_method); + }; - CREATE_MEM_HOOK_STUB_ENTRY("_ZN3art9ArtMethod16UnregisterNativeEv", const void *, - UnregisterNative, (art::ArtMethod * method), - { return backup(MayGetBackup(method)); }); + inline static MemberHooker<"_ZN3art9ArtMethod16UnregisterNativeEv", ClassLinker, + const void *(ArtMethod *)> + UnregisterNative_ = +[](ClassLinker *thiz, ArtMethod *method) { + return UnregisterNative_(thiz, MayGetBackup(method)); + }; - CREATE_MEM_HOOK_STUB_ENTRY( - "_ZN3art11ClassLinker14RegisterNativeEPNS_6ThreadEPNS_9ArtMethodEPKv", const void *, - RegisterNativeClassLinker, - (art::ClassLinker * thiz, art::Thread *self, art::ArtMethod *method, - const void *native_method), - { return backup(thiz, self, MayGetBackup(method), native_method); }); + inline static MemberHooker< + "_ZN3art11ClassLinker14RegisterNativeEPNS_6ThreadEPNS_9ArtMethodEPKv", ClassLinker, + const void *(Thread *, ArtMethod *, const void *)> + RegisterNativeClassLinker_ = + +[](ClassLinker *thiz, Thread *self, ArtMethod *method, const void *native_method) { + return RegisterNativeClassLinker_(thiz, self, MayGetBackup(method), native_method); + }; - CREATE_MEM_HOOK_STUB_ENTRY("_ZN3art11ClassLinker16UnregisterNativeEPNS_6ThreadEPNS_9ArtMethodE", - const void *, UnregisterNativeClassLinker, - (art::ClassLinker * thiz, art::Thread *self, art::ArtMethod *method), - { return backup(thiz, self, MayGetBackup(method)); }); + inline static MemberHooker<"_ZN3art11ClassLinker16UnregisterNativeEPNS_6ThreadEPNS_9ArtMethodE", + ClassLinker, const void *(Thread *, ArtMethod *)> + UnregisterNativeClassLinker_ = +[](ClassLinker *thiz, Thread *self, ArtMethod *method) { + return UnregisterNativeClassLinker_(thiz, self, MayGetBackup(method)); + }; - static auto RestoreBackup(const dex::ClassDef *class_def, art::Thread *self) { + static void RestoreBackup(const dex::ClassDef *class_def, art::Thread *self) { auto methods = mirror::Class::PopBackup(class_def, self); for (const auto &[art_method, old_trampoline] : methods) { auto new_trampoline = art_method->GetEntryPoint(); @@ -93,8 +110,8 @@ private: backup_method->SetEntryPoint(new_trampoline); } } else if (deoptimized) { - if (new_trampoline != art_quick_to_interpreter_bridge && - new_trampoline != art_quick_generic_jni_trampoline) { + if (new_trampoline != &art_quick_to_interpreter_bridge_ && + new_trampoline != &art_quick_generic_jni_trampoline_) { LOGV("re-deoptimize for %p", art_method); SetEntryPointsToInterpreter(art_method); } @@ -102,107 +119,105 @@ private: } } - CREATE_MEM_HOOK_STUB_ENTRY( - "_ZN3art11ClassLinker22FixupStaticTrampolinesENS_6ObjPtrINS_6mirror5ClassEEE", void, - FixupStaticTrampolines, (ClassLinker * thiz, ObjPtr mirror_class), { - backup(thiz, mirror_class); + inline static MemberHooker< + "_ZN3art11ClassLinker22FixupStaticTrampolinesENS_6ObjPtrINS_6mirror5ClassEEE", ClassLinker, + void(ObjPtr)> + FixupStaticTrampolines_ = +[](ClassLinker *thiz, ObjPtr mirror_class) { + FixupStaticTrampolines_(thiz, mirror_class); RestoreBackup(mirror_class->GetClassDef(), nullptr); - }); + }; - CREATE_MEM_HOOK_STUB_ENTRY( + inline static MemberHooker< "_ZN3art11ClassLinker22FixupStaticTrampolinesEPNS_6ThreadENS_6ObjPtrINS_6mirror5ClassEEE", - void, FixupStaticTrampolinesWithThread, - (ClassLinker * thiz, art::Thread *self, ObjPtr mirror_class), { - backup(thiz, self, mirror_class); - RestoreBackup(mirror_class->GetClassDef(), self); - }); + ClassLinker, void(Thread *, ObjPtr)> + FixupStaticTrampolinesWithThread_ = + +[](ClassLinker *thiz, Thread *self, ObjPtr mirror_class) { + FixupStaticTrampolinesWithThread_(thiz, self, mirror_class); + RestoreBackup(mirror_class->GetClassDef(), self); + }; - CREATE_MEM_HOOK_STUB_ENTRY("_ZN3art11ClassLinker22FixupStaticTrampolinesEPNS_6mirror5ClassE", - void, FixupStaticTrampolinesRaw, - (ClassLinker * thiz, mirror::Class *mirror_class), { - backup(thiz, mirror_class); - RestoreBackup(mirror_class->GetClassDef(), nullptr); - }); + inline static MemberHooker<"_ZN3art11ClassLinker22FixupStaticTrampolinesEPNS_6mirror5ClassE", + ClassLinker, void(mirror::Class *)> + FixupStaticTrampolinesRaw_ = +[](ClassLinker *thiz, mirror::Class *mirror_class) { + FixupStaticTrampolinesRaw_(thiz, mirror_class); + RestoreBackup(mirror_class->GetClassDef(), nullptr); + }; - CREATE_MEM_HOOK_STUB_ENTRY( - LP_SELECT( - "_ZN3art11ClassLinker26VisiblyInitializedCallback29AdjustThreadVisibilityCounterEPNS_6ThreadEi", - "_ZN3art11ClassLinker26VisiblyInitializedCallback29AdjustThreadVisibilityCounterEPNS_6ThreadEl"), - void, AdjustThreadVisibilityCounter, (void *thiz, art::Thread *self, ssize_t adjustment), { - backup(thiz, self, adjustment); + inline static MemberHooker< + {"_ZN3art11ClassLinker26VisiblyInitializedCallback29AdjustThreadVisibilityCounterEPNS_6ThreadEi", + "_ZN3art11ClassLinker26VisiblyInitializedCallback29AdjustThreadVisibilityCounterEPNS_6ThreadEl"}, + ClassLinker, void(Thread *, ssize_t)> + AdjustThreadVisibilityCounter_ = +[](ClassLinker *thiz, Thread *self, ssize_t adjustment) { + AdjustThreadVisibilityCounter_(thiz, self, adjustment); RestoreBackup(nullptr, self); - }); + }; - CREATE_MEM_HOOK_STUB_ENTRY( + inline static MemberHooker< "_ZN3art11ClassLinker26VisiblyInitializedCallback22MarkVisiblyInitializedEPNS_6ThreadE", - void, MarkVisiblyInitialized, (void *thiz, Thread *self), { - backup(thiz, self); + ClassLinker, void(Thread *)> + MarkVisiblyInitialized_ = +[](ClassLinker *thiz, Thread *self) { + MarkVisiblyInitialized_(thiz, self); RestoreBackup(nullptr, self); - }); + }; public: static bool Init(const HookHandler &handler) { int sdk_int = GetAndroidApiLevel(); if (sdk_int >= __ANDROID_API_N__ && sdk_int < __ANDROID_API_T__) { - HookSyms(handler, ShouldUseInterpreterEntrypoint); + handler.hook(ShouldUseInterpreterEntrypoint_); } - if (!HookSyms(handler, FixupStaticTrampolinesWithThread, FixupStaticTrampolines, - FixupStaticTrampolinesRaw)) { + if (!handler.hook(FixupStaticTrampolinesWithThread_, FixupStaticTrampolines_, + FixupStaticTrampolinesRaw_)) { return false; } - if (!HookSyms(handler, RegisterNativeClassLinker, RegisterNative, RegisterNativeFast, - RegisterNativeThread) || - !HookSyms(handler, UnregisterNativeClassLinker, UnregisterNative, UnregisterNativeFast, - UnregisterNativeThread)) { + if (!handler.hook(RegisterNativeClassLinker_, RegisterNative_, RegisterNativeFast_, + RegisterNativeThread_) || + !handler.hook(UnregisterNativeClassLinker_, UnregisterNative_, UnregisterNativeFast_, + UnregisterNativeThread_)) { return false; } if (sdk_int >= __ANDROID_API_R__) { if constexpr (kArch != Arch::kX86 && kArch != Arch::kX86_64) { // fixup static trampoline may have been inlined - HookSyms(handler, AdjustThreadVisibilityCounter, MarkVisiblyInitialized); + handler.hook(AdjustThreadVisibilityCounter_, MarkVisiblyInitialized_); } } - if (!RETRIEVE_MEM_FUNC_SYMBOL( - SetEntryPointsToInterpreter, - "_ZNK3art11ClassLinker27SetEntryPointsToInterpreterEPNS_9ArtMethodE")) - [[unlikely]] { - if (!RETRIEVE_FUNC_SYMBOL(art_quick_to_interpreter_bridge, - "art_quick_to_interpreter_bridge")) [[unlikely]] { + if (!handler.dlsym(SetEntryPointsToInterpreter_)) [[unlikely]] { + if (!handler.dlsym(art_quick_to_interpreter_bridge_)) [[unlikely]] { return false; } - if (!RETRIEVE_FUNC_SYMBOL(art_quick_generic_jni_trampoline, - "art_quick_generic_jni_trampoline")) [[unlikely]] { + if (!handler.dlsym(art_quick_generic_jni_trampoline_)) [[unlikely]] { return false; } - LOGD("art_quick_to_interpreter_bridge = %p", art_quick_to_interpreter_bridgeSym); - LOGD("art_quick_generic_jni_trampoline = %p", art_quick_generic_jni_trampolineSym); + LOGD("art_quick_to_interpreter_bridge = %p", &art_quick_to_interpreter_bridge_); + LOGD("art_quick_generic_jni_trampoline = %p", &art_quick_generic_jni_trampoline_); } return true; } [[gnu::always_inline]] static bool SetEntryPointsToInterpreter(ArtMethod *art_method) { - if (SetEntryPointsToInterpreterSym) [[likely]] { - SetEntryPointsToInterpreter(nullptr, art_method); + if (SetEntryPointsToInterpreter_) [[likely]] { + SetEntryPointsToInterpreter_(nullptr, art_method); return true; } // Android 13 - if (art_quick_to_interpreter_bridgeSym && art_quick_generic_jni_trampolineSym) [[likely]] { + if (art_quick_to_interpreter_bridge_ && art_quick_generic_jni_trampoline_) [[likely]] { if (art_method->GetAccessFlags() & ArtMethod::kAccNative) [[unlikely]] { LOGV("deoptimize native method %s from %p to %p", art_method->PrettyMethod(true).data(), art_method->GetEntryPoint(), - art_quick_generic_jni_trampolineSym); + &art_quick_generic_jni_trampoline_); art_method->SetEntryPoint( - reinterpret_cast(art_quick_generic_jni_trampolineSym)); + reinterpret_cast(&art_quick_generic_jni_trampoline_)); } else { LOGV("deoptimize method %s from %p to %p", art_method->PrettyMethod(true).data(), - art_method->GetEntryPoint(), art_quick_to_interpreter_bridgeSym); + art_method->GetEntryPoint(), &art_quick_to_interpreter_bridge_); art_method->SetEntryPoint( - reinterpret_cast(art_quick_to_interpreter_bridgeSym)); + reinterpret_cast(&art_quick_to_interpreter_bridge_)); } return true; } diff --git a/lsplant/src/main/jni/art/runtime/dex_file.cxx b/lsplant/src/main/jni/art/runtime/dex_file.cxx index 60cd846..031f996 100644 --- a/lsplant/src/main/jni/art/runtime/dex_file.cxx +++ b/lsplant/src/main/jni/art/runtime/dex_file.cxx @@ -5,11 +5,11 @@ module; #include #include "logging.hpp" -#include "utils/hook_helper.hpp" export module dex_file; import common; +import hook_helper; namespace lsplant::art { export class DexFile { @@ -17,70 +17,59 @@ export class DexFile { [[maybe_unused]] uint8_t magic_[8]; uint32_t checksum_; // See also location_checksum_ }; - CREATE_FUNC_SYMBOL_ENTRY(std::unique_ptr, OpenMemory, const uint8_t* dex_file, - size_t size, const std::string& location, uint32_t location_checksum, - void* mem_map, const void* oat_dex_file, std::string* error_msg) { - if (OpenMemorySym) [[likely]] { - return OpenMemorySym(dex_file, size, location, location_checksum, mem_map, oat_dex_file, - error_msg); - } - if (error_msg) *error_msg = "null sym"; - return nullptr; - } - CREATE_FUNC_SYMBOL_ENTRY(const DexFile*, OpenMemoryRaw, const uint8_t* dex_file, size_t size, - const std::string& location, uint32_t location_checksum, void* mem_map, - const void* oat_dex_file, std::string* error_msg) { - if (OpenMemoryRawSym) [[likely]] { - return OpenMemoryRawSym(dex_file, size, location, location_checksum, mem_map, - oat_dex_file, error_msg); - } - if (error_msg) *error_msg = "null sym"; - return nullptr; - } + inline static Function< + {"_ZN3art7DexFile10OpenMemoryEPKhjRKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEjPNS_6MemMapEPKNS_10OatDexFileEPS9_", + "_ZN3art7DexFile10OpenMemoryEPKhmRKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEjPNS_6MemMapEPKNS_10OatDexFileEPS9_"}, + std::unique_ptr(const uint8_t* dex_file, size_t size, const std::string& location, + uint32_t location_checksum, void* mem_map, + const void* oat_dex_file, std::string* error_msg)> + OpenMemory_; - CREATE_FUNC_SYMBOL_ENTRY(const DexFile*, OpenMemoryWithoutOdex, const uint8_t* dex_file, - size_t size, const std::string& location, uint32_t location_checksum, - void* mem_map, std::string* error_msg) { - if (OpenMemoryWithoutOdexSym) [[likely]] { - return OpenMemoryWithoutOdexSym(dex_file, size, location, location_checksum, mem_map, - error_msg); - } - if (error_msg) *error_msg = "null sym"; - return nullptr; - } + inline static Function< + {"_ZN3art7DexFile10OpenMemoryEPKhjRKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEjPNS_6MemMapEPKNS_7OatFileEPS9_", + "_ZN3art7DexFile10OpenMemoryEPKhmRKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEjPNS_6MemMapEPKNS_7OatFileEPS9_"}, + const DexFile*(const uint8_t* dex_file, size_t size, const std::string& location, + uint32_t location_checksum, void* mem_map, const void* oat_dex_file, + std::string* error_msg)> + OpenMemoryRaw_; - CREATE_FUNC_SYMBOL_ENTRY(void, DexFile_setTrusted, JNIEnv* env, jclass clazz, - jobject j_cookie) { - if (DexFile_setTrustedSym != nullptr) [[likely]] { - DexFile_setTrustedSym(env, clazz, j_cookie); - } - } + inline static Function< + {"_ZN3art7DexFile10OpenMemoryEPKhjRKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEjPNS_6MemMapEPS9_", + "_ZN3art7DexFile10OpenMemoryEPKhmRKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEjPNS_6MemMapEPS9_"}, + const DexFile*(const uint8_t* dex_file, size_t size, const std::string& location, + uint32_t location_checksum, void* mem_map, std::string* error_msg)> + OpenMemoryWithoutOdex_; + + inline static Function<"_ZN3artL18DexFile_setTrustedEP7_JNIEnvP7_jclassP8_jobject", + void(JNIEnv* env, jclass clazz, jobject j_cookie)> + DexFile_setTrusted_; public: - static const DexFile* OpenMemory(const void* dex_file, size_t size, std::string location, + static const DexFile* OpenMemory(const uint8_t* dex_file, size_t size, std::string location, std::string* error_msg) { - if (OpenMemorySym) [[likely]] { - return OpenMemory(reinterpret_cast(dex_file), size, location, - reinterpret_cast(dex_file)->checksum_, nullptr, - nullptr, error_msg) + if (OpenMemory_) [[likely]] { + return OpenMemory_(dex_file, size, location, + reinterpret_cast(dex_file)->checksum_, nullptr, + nullptr, error_msg) .release(); - } else if (OpenMemoryRawSym) [[likely]] { - return OpenMemoryRaw(reinterpret_cast(dex_file), size, location, - reinterpret_cast(dex_file)->checksum_, nullptr, - nullptr, error_msg); - } else if (OpenMemoryWithoutOdexSym) [[likely]] { - return OpenMemoryWithoutOdex(reinterpret_cast(dex_file), size, location, - reinterpret_cast(dex_file)->checksum_, - nullptr, error_msg); - } else { - if (error_msg) *error_msg = "no sym"; - return nullptr; } + if (OpenMemoryRaw_) [[likely]] { + return OpenMemoryRaw_(dex_file, size, location, + reinterpret_cast(dex_file)->checksum_, nullptr, + nullptr, error_msg); + } + if (OpenMemoryWithoutOdex_) [[likely]] { + return OpenMemoryWithoutOdex_(dex_file, size, location, + reinterpret_cast(dex_file)->checksum_, + nullptr, error_msg); + } + if (error_msg) *error_msg = "null sym"; + return nullptr; } jobject ToJavaDexFile(JNIEnv* env) const { - auto java_dex_file = env->AllocObject(dex_file_class); + auto* java_dex_file = env->AllocObject(dex_file_class); auto cookie = JNI_NewLongArray(env, dex_file_start_index + 1); if (dex_file_start_index != size_t(-1)) [[likely]] { cookie[oat_file_index] = 0; @@ -100,41 +89,23 @@ public: } static bool SetTrusted(JNIEnv* env, jobject cookie) { - if (!DexFile_setTrustedSym) return false; - DexFile_setTrusted(env, nullptr, cookie); + if (!DexFile_setTrusted_) return false; + DexFile_setTrusted_(env, nullptr, cookie); return true; } static bool Init(JNIEnv* env, const HookHandler& handler) { auto sdk_int = GetAndroidApiLevel(); if (sdk_int >= __ANDROID_API_P__) [[likely]] { - if (!RETRIEVE_FUNC_SYMBOL(DexFile_setTrusted, - "_ZN3artL18DexFile_setTrustedEP7_JNIEnvP7_jclassP8_jobject", - true)) { + if (!handler.dlsym(DexFile_setTrusted_, true)) { LOGW("DexFile.setTrusted not found, MakeDexFileTrusted will not work."); } } if (sdk_int >= __ANDROID_API_O__) [[likely]] { return true; } - if (!RETRIEVE_FUNC_SYMBOL( - OpenMemory, - LP_SELECT("_ZN3art7DexFile10OpenMemoryEPKhjRKNSt3__112basic_stringIcNS3_11char_" - "traitsIcEENS3_9allocatorIcEEEEjPNS_6MemMapEPKNS_10OatDexFileEPS9_", - "_ZN3art7DexFile10OpenMemoryEPKhmRKNSt3__112basic_stringIcNS3_11char_" - "traitsIcEENS3_9allocatorIcEEEEjPNS_6MemMapEPKNS_10OatDexFileEPS9_")) && - !RETRIEVE_FUNC_SYMBOL( - OpenMemoryRaw, - LP_SELECT("_ZN3art7DexFile10OpenMemoryEPKhjRKNSt3__112basic_stringIcNS3_11char_" - "traitsIcEENS3_9allocatorIcEEEEjPNS_6MemMapEPKNS_7OatFileEPS9_", - "_ZN3art7DexFile10OpenMemoryEPKhmRKNSt3__112basic_stringIcNS3_11char_" - "traitsIcEENS3_9allocatorIcEEEEjPNS_6MemMapEPKNS_7OatFileEPS9_")) && - !RETRIEVE_FUNC_SYMBOL( - OpenMemoryWithoutOdex, - LP_SELECT("_ZN3art7DexFile10OpenMemoryEPKhjRKNSt3__112basic_stringIcNS3_11char_" - "traitsIcEENS3_9allocatorIcEEEEjPNS_6MemMapEPS9_", - "_ZN3art7DexFile10OpenMemoryEPKhmRKNSt3__112basic_stringIcNS3_11char_" - "traitsIcEENS3_9allocatorIcEEEEjPNS_6MemMapEPS9_"))) [[unlikely]] { + if (!handler.dlsym(OpenMemory_) && !handler.dlsym(OpenMemoryRaw_) && + !handler.dlsym(OpenMemoryWithoutOdex_)) [[unlikely]] { LOGE("Failed to find OpenMemory"); return false; } diff --git a/lsplant/src/main/jni/art/runtime/gc/scoped_gc_critical_section.cxx b/lsplant/src/main/jni/art/runtime/gc/scoped_gc_critical_section.cxx index 88eae44..556dbad 100644 --- a/lsplant/src/main/jni/art/runtime/gc/scoped_gc_critical_section.cxx +++ b/lsplant/src/main/jni/art/runtime/gc/scoped_gc_critical_section.cxx @@ -1,11 +1,12 @@ module; -#include "utils/hook_helper.hpp" +#include export module scope_gc_critical_section; import thread; import common; +import hook_helper; namespace lsplant::art::gc { // Which types of collections are able to be performed. @@ -97,35 +98,30 @@ private: }; export class ScopedGCCriticalSection { - CREATE_MEM_FUNC_SYMBOL_ENTRY(void, constructor, ScopedGCCriticalSection *thiz, Thread *self, - GcCause cause, CollectorType collector_type) { - if (thiz && constructorSym) [[likely]] - return constructorSym(thiz, self, cause, collector_type); - } - - CREATE_MEM_FUNC_SYMBOL_ENTRY(void, destructor, ScopedGCCriticalSection *thiz) { - if (thiz && destructorSym) [[likely]] - destructorSym(thiz); - } + inline static MemberFunction< + "_ZN3art2gc23ScopedGCCriticalSectionC2EPNS_6ThreadENS0_7GcCauseENS0_13CollectorTypeE", + ScopedGCCriticalSection, void(Thread *, GcCause, CollectorType)> + constructor_; + inline static MemberFunction<"_ZN3art2gc23ScopedGCCriticalSectionD2Ev", ScopedGCCriticalSection, + void()> + destructor_; public: ScopedGCCriticalSection(Thread *self, GcCause cause, CollectorType collector_type) { - constructor(this, self, cause, collector_type); + if (constructor_) { + constructor_(this, self, cause, collector_type); + } } - ~ScopedGCCriticalSection() { destructor(this); } + ~ScopedGCCriticalSection() { + if (destructor_) destructor_(this); + } static bool Init(const HookHandler &handler) { // for Android M, it's safe to not found since we have suspendVM & resumeVM auto sdk_int = GetAndroidApiLevel(); if (sdk_int >= __ANDROID_API_N__) [[likely]] { - if (!RETRIEVE_MEM_FUNC_SYMBOL(constructor, - "_ZN3art2gc23ScopedGCCriticalSectionC2EPNS_6ThreadENS0_" - "7GcCauseENS0_13CollectorTypeE")) [[unlikely]] { - return false; - } - if (!RETRIEVE_MEM_FUNC_SYMBOL(destructor, "_ZN3art2gc23ScopedGCCriticalSectionD2Ev")) - [[unlikely]] { + if (!handler.dlsym(constructor_) || !handler.dlsym(destructor_)) { return false; } } diff --git a/lsplant/src/main/jni/art/runtime/instrumentation.cxx b/lsplant/src/main/jni/art/runtime/instrumentation.cxx index 76864cc..eb541ae 100644 --- a/lsplant/src/main/jni/art/runtime/instrumentation.cxx +++ b/lsplant/src/main/jni/art/runtime/instrumentation.cxx @@ -1,12 +1,12 @@ module; #include "logging.hpp" -#include "utils/hook_helper.hpp" export module instrumentation; import art_method; import common; +import hook_helper; namespace lsplant::art { @@ -21,29 +21,32 @@ export class Instrumentation { return art_method; } - CREATE_MEM_HOOK_STUB_ENTRY( + inline static MemberHooker< "_ZN3art15instrumentation15Instrumentation40UpdateMethodsCodeToInterpreterEntryPointEPNS_9ArtMethodE", - void, UpdateMethodsCodeToInterpreterEntryPoint, - (Instrumentation * thiz, ArtMethod *art_method), { - if (IsDeoptimized(art_method)) { - LOGV("skip update entrypoint on deoptimized method %s", - art_method->PrettyMethod(true).c_str()); - return; - } - backup(thiz, MaybeUseBackupMethod(art_method, nullptr)); - }); + Instrumentation, void(ArtMethod *)> + UpdateMethodsCodeToInterpreterEntryPoint_ = + +[](Instrumentation *thiz, ArtMethod *art_method) { + if (IsDeoptimized(art_method)) { + LOGV("skip update entrypoint on deoptimized method %s", + art_method->PrettyMethod(true).c_str()); + return; + } + UpdateMethodsCodeToInterpreterEntryPoint_( + thiz, MaybeUseBackupMethod(art_method, nullptr)); + }; - CREATE_MEM_HOOK_STUB_ENTRY( - "_ZN3art15instrumentation15Instrumentation21InitializeMethodsCodeEPNS_9ArtMethodEPKv", void, - InitializeMethodsCode, - (Instrumentation * thiz, ArtMethod *art_method, const void *quick_code), { + inline static MemberHooker< + "_ZN3art15instrumentation15Instrumentation21InitializeMethodsCodeEPNS_9ArtMethodEPKv", + Instrumentation, void(ArtMethod *, const void *)> + InitializeMethodsCode_ = +[](Instrumentation *thiz, ArtMethod *art_method, + const void *quick_code) { if (IsDeoptimized(art_method)) { LOGV("skip update entrypoint on deoptimized method %s", art_method->PrettyMethod(true).c_str()); return; } - backup(thiz, MaybeUseBackupMethod(art_method, quick_code), quick_code); - }); + InitializeMethodsCode_(thiz, MaybeUseBackupMethod(art_method, quick_code), quick_code); + }; public: static bool Init(JNIEnv *env, const HookHandler &handler) { @@ -52,8 +55,7 @@ public: } int sdk_int = GetAndroidApiLevel(); if (sdk_int >= __ANDROID_API_P__) [[likely]] { - if (!HookSyms(handler, InitializeMethodsCode, - UpdateMethodsCodeToInterpreterEntryPoint)) { + if (!handler.hook(InitializeMethodsCode_, UpdateMethodsCodeToInterpreterEntryPoint_)) { return false; } } diff --git a/lsplant/src/main/jni/art/runtime/jit/jit.cxx b/lsplant/src/main/jni/art/runtime/jit/jit.cxx index 3e57bfc..010d705 100644 --- a/lsplant/src/main/jni/art/runtime/jit/jit.cxx +++ b/lsplant/src/main/jni/art/runtime/jit/jit.cxx @@ -1,13 +1,13 @@ module; #include "logging.hpp" -#include "utils/hook_helper.hpp" export module jit; import art_method; import common; import thread; +import hook_helper; namespace lsplant::art::jit { enum class CompilationKind { @@ -17,38 +17,38 @@ enum class CompilationKind { }; export class Jit { - CREATE_MEM_HOOK_STUB_ENTRY( - "_ZN3art3jit3Jit27EnqueueOptimizedCompilationEPNS_9ArtMethodEPNS_6ThreadE", void, - EnqueueOptimizedCompilation, (Jit * thiz, ArtMethod *method, Thread *self), { + inline static MemberHooker< + "_ZN3art3jit3Jit27EnqueueOptimizedCompilationEPNS_9ArtMethodEPNS_6ThreadE", Jit, + void(ArtMethod *, Thread *)> + EnqueueOptimizedCompilation_ = +[](Jit *thiz, ArtMethod *method, Thread *self) { if (auto target = IsBackup(method); target) [[unlikely]] { LOGD("Propagate enqueue compilation: %p -> %p", method, target); method = target; } - return backup(thiz, method, self); - }); + return EnqueueOptimizedCompilation_(thiz, method, self); + }; - CREATE_MEM_HOOK_STUB_ENTRY( - "_ZN3art3jit3Jit14AddCompileTaskEPNS_6ThreadEPNS_9ArtMethodENS_15CompilationKindEb", void, - AddCompileTask, - (Jit * thiz, Thread *self, ArtMethod *method, CompilationKind compilation_kind, - bool precompile), - { - if (compilation_kind == CompilationKind::kOptimized && !precompile/* && in_enqueue*/) { + inline static MemberHooker< + "_ZN3art3jit3Jit14AddCompileTaskEPNS_6ThreadEPNS_9ArtMethodENS_15CompilationKindEb", Jit, + void(Thread *, ArtMethod *, CompilationKind, bool)> + AddCompileTask_ = +[](Jit *thiz, Thread *self, ArtMethod *method, + CompilationKind compilation_kind, bool precompile) { + if (compilation_kind == CompilationKind::kOptimized && !precompile) { if (auto backup = IsHooked(method); backup) [[unlikely]] { LOGD("Propagate compile task: %p -> %p", method, backup); method = backup; } } - return backup(thiz, self, method, compilation_kind, precompile); - }); + return AddCompileTask_(thiz, self, method, compilation_kind, precompile); + }; public: static bool Init(const HookHandler &handler) { auto sdk_int = GetAndroidApiLevel(); if (sdk_int <= __ANDROID_API_U__) [[likely]] { - HookSyms(handler, EnqueueOptimizedCompilation); - HookSyms(handler, AddCompileTask); + handler.hook(EnqueueOptimizedCompilation_); + handler.hook(AddCompileTask_); } return true; } diff --git a/lsplant/src/main/jni/art/runtime/jit/jit_code_cache.cxx b/lsplant/src/main/jni/art/runtime/jit/jit_code_cache.cxx index abd8d98..a5c78ac 100644 --- a/lsplant/src/main/jni/art/runtime/jit/jit_code_cache.cxx +++ b/lsplant/src/main/jni/art/runtime/jit/jit_code_cache.cxx @@ -1,60 +1,57 @@ module; #include "logging.hpp" -#include "utils/hook_helper.hpp" export module jit_code_cache; import art_method; import common; import thread; +import hook_helper; namespace lsplant::art::jit { export class JitCodeCache { - CREATE_MEM_FUNC_SYMBOL_ENTRY(void, MoveObsoleteMethod, JitCodeCache *thiz, - ArtMethod *old_method, ArtMethod *new_method) { - if (MoveObsoleteMethodSym) [[likely]] { - MoveObsoleteMethodSym(thiz, old_method, new_method); - } else { - // fallback to set data - new_method->SetData(old_method->GetData()); - old_method->SetData(nullptr); - } - } + inline static MemberFunction<"_ZN3art3jit12JitCodeCache18MoveObsoleteMethodEPNS_9ArtMethodES3_", + JitCodeCache, void(ArtMethod *, ArtMethod *)> + MoveObsoleteMethod_; - void MoveObsoleteMethods() { + static void MoveObsoleteMethods(JitCodeCache *thiz) { auto movements = GetJitMovements(); LOGD("Before jit cache collection, moving %zu hooked methods", movements.size()); for (auto [target, backup] : movements) { - MoveObsoleteMethod(this, target, backup); + if (MoveObsoleteMethod_) [[likely]] + MoveObsoleteMethod_(thiz, target, backup); + else { + backup->SetData(backup->GetData()); + target->SetData(nullptr); + } } } - CREATE_MEM_HOOK_STUB_ENTRY("_ZN3art3jit12JitCodeCache19GarbageCollectCacheEPNS_6ThreadE", void, - GarbageCollectCache, (JitCodeCache * thiz, Thread *self), { - thiz->MoveObsoleteMethods(); - backup(thiz, self); - }); + inline static MemberHooker<"_ZN3art3jit12JitCodeCache19GarbageCollectCacheEPNS_6ThreadE", + JitCodeCache, void(Thread *)> + GarbageCollectCache_ = +[](JitCodeCache *thiz, Thread *self) { + MoveObsoleteMethods(thiz); + GarbageCollectCache_(thiz, self); + }; - CREATE_MEM_HOOK_STUB_ENTRY("_ZN3art3jit12JitCodeCache12DoCollectionEPNS_6ThreadE", void, - DoCollection, (JitCodeCache * thiz, Thread *self), { - thiz->MoveObsoleteMethods(); - backup(thiz, self); - }); + inline static MemberHooker<"_ZN3art3jit12JitCodeCache12DoCollectionEPNS_6ThreadE", JitCodeCache, + void(Thread *)> + DoCollection_ = +[](JitCodeCache *thiz, Thread *self) { + MoveObsoleteMethods(thiz); + DoCollection_(thiz, self); + }; public: static bool Init(const HookHandler &handler) { auto sdk_int = GetAndroidApiLevel(); if (sdk_int >= __ANDROID_API_O__) [[likely]] { - if (!RETRIEVE_MEM_FUNC_SYMBOL( - MoveObsoleteMethod, - "_ZN3art3jit12JitCodeCache18MoveObsoleteMethodEPNS_9ArtMethodES3_")) - [[unlikely]] { + if (!handler.dlsym(MoveObsoleteMethod_)) [[unlikely]] { return false; } } if (sdk_int >= __ANDROID_API_N__) [[likely]] { - if (!HookSyms(handler, GarbageCollectCache, DoCollection)) [[unlikely]] { + if (!handler.hook(GarbageCollectCache_, DoCollection_)) [[unlikely]] { return false; } } diff --git a/lsplant/src/main/jni/art/runtime/jni/jni_id_manager.cxx b/lsplant/src/main/jni/art/runtime/jni/jni_id_manager.cxx index 2667251..dceaae9 100644 --- a/lsplant/src/main/jni/art/runtime/jni/jni_id_manager.cxx +++ b/lsplant/src/main/jni/art/runtime/jni/jni_id_manager.cxx @@ -1,33 +1,35 @@ module; #include "logging.hpp" -#include "utils/hook_helper.hpp" export module jni_id_manager; import art_method; import common; import handle; +import hook_helper; namespace lsplant::art::jni { export class JniIdManager { private: - CREATE_MEM_HOOK_STUB_ENTRY( + inline static MemberHooker< "_ZN3art3jni12JniIdManager15EncodeGenericIdINS_9ArtMethodEEEmNS_16ReflectiveHandleIT_EE", - uintptr_t, EncodeGenericId, (JniIdManager * thiz, ReflectiveHandle method), { - if (auto target = IsBackup(method.Get()); target) { - LOGD("get generic id for %s", method.Get()->PrettyMethod().c_str()); - method.Set(target); - } - return backup(thiz, method); - }); + JniIdManager, uintptr_t(ReflectiveHandle)> + EncodeGenericId_ = + +[](JniIdManager *thiz, ReflectiveHandle method) -> uintptr_t { + if (auto target = IsBackup(method.Get()); target) { + LOGD("get generic id for %s", method.Get()->PrettyMethod().c_str()); + method.Set(target); + } + return EncodeGenericId_(thiz, method); + }; public: static bool Init(JNIEnv *env, const HookHandler &handler) { int sdk_int = GetAndroidApiLevel(); if (sdk_int >= __ANDROID_API_R__) { - if (IsJavaDebuggable(env) && !HookSyms(handler, EncodeGenericId)) { + if (IsJavaDebuggable(env) && !handler.hook(EncodeGenericId_)) { LOGW("Failed to hook EncodeGenericId, attaching debugger may crash the process"); } } diff --git a/lsplant/src/main/jni/art/runtime/runtime.cxx b/lsplant/src/main/jni/art/runtime/runtime.cxx index 70ffc89..521a3ce 100644 --- a/lsplant/src/main/jni/art/runtime/runtime.cxx +++ b/lsplant/src/main/jni/art/runtime/runtime.cxx @@ -1,11 +1,13 @@ module; +#include + #include "logging.hpp" -#include "utils/hook_helper.hpp" export module runtime; import common; +import hook_helper; namespace lsplant::art { @@ -27,55 +29,47 @@ public: }; private: - inline static Runtime *instance_; + inline static Field<"_ZN3art7Runtime9instance_E", Runtime *> instance_; - CREATE_MEM_FUNC_SYMBOL_ENTRY(void, SetJavaDebuggable, void *thiz, bool value) { - SetJavaDebuggableSym(thiz, value); - } - - CREATE_MEM_FUNC_SYMBOL_ENTRY(void, SetRuntimeDebugState, void *thiz, RuntimeDebugState value) { - SetRuntimeDebugStateSym(thiz, value); - } + inline static MemberFunction<"_ZN3art7Runtime17SetJavaDebuggableEb", Runtime, void(bool)> + SetJavaDebuggable_; + inline static MemberFunction<"_ZN3art7Runtime20SetRuntimeDebugStateENS0_17RuntimeDebugStateE", + Runtime, void(RuntimeDebugState)> + SetRuntimeDebugState_; inline static size_t debug_state_offset = 0U; public: - inline static Runtime *Current() { return instance_; } + inline static Runtime *Current() { return *instance_; } void SetJavaDebuggable(RuntimeDebugState value) { - if (SetJavaDebuggableSym) { - SetJavaDebuggable(this, value != RuntimeDebugState::kNonJavaDebuggable); + if (SetJavaDebuggable_) { + SetJavaDebuggable_(this, value != RuntimeDebugState::kNonJavaDebuggable); } else if (debug_state_offset > 0) { - *reinterpret_cast(reinterpret_cast(instance_) + + *reinterpret_cast(reinterpret_cast(*instance_) + debug_state_offset) = value; } } static bool Init(const HookHandler &handler) { int sdk_int = GetAndroidApiLevel(); - if (void **instance; !RETRIEVE_FIELD_SYMBOL(instance, "_ZN3art7Runtime9instance_E")) { - return false; - } else if (instance_ = reinterpret_cast(*instance); !instance_) { + if (!handler.dlsym(instance_) || !*instance_) { return false; } - LOGD("runtime instance = %p", instance_); + LOGD("runtime instance = %p", *instance_); if (sdk_int >= __ANDROID_API_O__) { - if (!RETRIEVE_MEM_FUNC_SYMBOL(SetJavaDebuggable, - "_ZN3art7Runtime17SetJavaDebuggableEb") && - !RETRIEVE_MEM_FUNC_SYMBOL( - SetRuntimeDebugState, - "_ZN3art7Runtime20SetRuntimeDebugStateENS0_17RuntimeDebugStateE")) { + if (!handler.dlsym(SetJavaDebuggable_) && !handler.dlsym(SetRuntimeDebugState_)) { return false; } } - if (SetRuntimeDebugStateSym) { + if (SetRuntimeDebugState_) { static constexpr size_t kLargeEnoughSizeForRuntime = 4096; std::array code; static_assert(static_cast(RuntimeDebugState::kJavaDebuggable) != 0); static_assert(static_cast(RuntimeDebugState::kJavaDebuggableAtInit) != 0); code.fill(uint8_t{0}); auto *const fake_runtime = reinterpret_cast(code.data()); - SetRuntimeDebugState(fake_runtime, RuntimeDebugState::kJavaDebuggable); + SetRuntimeDebugState_(fake_runtime, RuntimeDebugState::kJavaDebuggable); for (size_t i = 0; i < kLargeEnoughSizeForRuntime; ++i) { if (*reinterpret_cast( reinterpret_cast(fake_runtime) + i) == diff --git a/lsplant/src/main/jni/art/runtime/thread.cxx b/lsplant/src/main/jni/art/runtime/thread.cxx index 1680d98..9880d6d 100644 --- a/lsplant/src/main/jni/art/runtime/thread.cxx +++ b/lsplant/src/main/jni/art/runtime/thread.cxx @@ -1,24 +1,22 @@ module; -#include "utils/hook_helper.hpp" - export module thread; +import hook_helper; + namespace lsplant::art { export class Thread { - CREATE_FUNC_SYMBOL_ENTRY(Thread *, CurrentFromGdb) { - if (CurrentFromGdbSym) [[likely]] - return CurrentFromGdbSym(); - else - return nullptr; - } + inline static Function<"_ZN3art6Thread14CurrentFromGdbEv", Thread *()> CurrentFromGdb_; public: - static Thread *Current() { return CurrentFromGdb(); } + static Thread *Current() { + if (CurrentFromGdb_) [[likely]] + return CurrentFromGdb_(); + return nullptr; + } static bool Init(const HookHandler &handler) { - if (!RETRIEVE_FUNC_SYMBOL(CurrentFromGdb, "_ZN3art6Thread14CurrentFromGdbEv")) - [[unlikely]] { + if (!handler.dlsym(CurrentFromGdb_)) [[unlikely]] { return false; } return true; diff --git a/lsplant/src/main/jni/art/runtime/thread_list.cxx b/lsplant/src/main/jni/art/runtime/thread_list.cxx index 10321cc..95d0eb6 100644 --- a/lsplant/src/main/jni/art/runtime/thread_list.cxx +++ b/lsplant/src/main/jni/art/runtime/thread_list.cxx @@ -1,55 +1,43 @@ module; -#include "include/utils/hook_helper.hpp" - export module thread_list; +import hook_helper; + namespace lsplant::art::thread_list { export class ScopedSuspendAll { - CREATE_MEM_FUNC_SYMBOL_ENTRY(void, constructor, ScopedSuspendAll *thiz, const char *cause, - bool long_suspend) { - if (thiz && constructorSym) [[likely]] { - return constructorSym(thiz, cause, long_suspend); - } else { - SuspendVM(); - } - } + inline static MemberFunction<"_ZN3art16ScopedSuspendAllC2EPKcb", ScopedSuspendAll, + void(const char *, bool)> + constructor_; + inline static MemberFunction<"_ZN3art16ScopedSuspendAllD2Ev", ScopedSuspendAll, void()> + destructor_; - CREATE_MEM_FUNC_SYMBOL_ENTRY(void, destructor, ScopedSuspendAll *thiz) { - if (thiz && destructorSym) [[likely]] { - return destructorSym(thiz); - } else { - ResumeVM(); - } - } - - CREATE_FUNC_SYMBOL_ENTRY(void, SuspendVM) { - if (SuspendVMSym) [[likely]] { - SuspendVMSym(); - } - } - - CREATE_FUNC_SYMBOL_ENTRY(void, ResumeVM) { - if (ResumeVMSym) [[likely]] { - ResumeVMSym(); - } - } + inline static Function<"_ZN3art3Dbg9SuspendVMEv", void()> SuspendVM_; + inline static Function<"_ZN3art3Dbg8ResumeVMEv", void()> ResumeVM_; public: ScopedSuspendAll(const char *cause, bool long_suspend) { - constructor(this, cause, long_suspend); + if (constructor_) { + constructor_(this, cause, long_suspend); + } else if (SuspendVM_) { + SuspendVM_(); + } } - ~ScopedSuspendAll() { destructor(this); } + ~ScopedSuspendAll() { + if (destructor_) { + destructor_(this); + } else if (ResumeVM_) { + ResumeVM_(); + } + } static bool Init(const HookHandler &handler) { - if (!RETRIEVE_MEM_FUNC_SYMBOL(constructor, "_ZN3art16ScopedSuspendAllC2EPKcb") && - !RETRIEVE_FUNC_SYMBOL(SuspendVM, "_ZN3art3Dbg9SuspendVMEv")) [[unlikely]] { + if (!handler.dlsym(constructor_) && !handler.dlsym(SuspendVM_)) [[unlikely]] { return false; } - if (!RETRIEVE_MEM_FUNC_SYMBOL(destructor, "_ZN3art16ScopedSuspendAllD2Ev") && - !RETRIEVE_FUNC_SYMBOL(ResumeVM, "_ZN3art3Dbg8ResumeVMEv")) [[unlikely]] { + if (!handler.dlsym(destructor_) && !handler.dlsym(ResumeVM_)) [[unlikely]] { return false; } return true; diff --git a/lsplant/src/main/jni/include/utils/hook_helper.hpp b/lsplant/src/main/jni/include/utils/hook_helper.hpp index 05e94d8..935aa81 100644 --- a/lsplant/src/main/jni/include/utils/hook_helper.hpp +++ b/lsplant/src/main/jni/include/utils/hook_helper.hpp @@ -7,61 +7,47 @@ #include "lsplant.hpp" #include "type_traits.hpp" -#if defined(__LP64__) -#define LP_SELECT(lp32, lp64) lp64 -#else -#define LP_SELECT(lp32, lp64) lp32 -#endif - -#define CREATE_HOOK_STUB_ENTRY(SYM, RET, FUNC, PARAMS, DEF) \ - inline static struct : public lsplant::Hooker{ \ - inline static RET replace PARAMS DEF} FUNC - -#define CREATE_MEM_HOOK_STUB_ENTRY(SYM, RET, FUNC, PARAMS, DEF) \ - inline static struct : public lsplant::MemHooker{ \ - inline static RET replace PARAMS DEF} FUNC - -#define RETRIEVE_FUNC_SYMBOL(name, ...) \ - (name##Sym = reinterpret_cast(lsplant::Dlsym(handler, __VA_ARGS__))) - -#define RETRIEVE_MEM_FUNC_SYMBOL(name, ...) \ - (name##Sym = reinterpret_cast(lsplant::Dlsym(handler, __VA_ARGS__))) - -#define RETRIEVE_FIELD_SYMBOL(name, ...) \ - (name = reinterpret_cast(lsplant::Dlsym(handler, __VA_ARGS__))) - -#define CREATE_FUNC_SYMBOL_ENTRY(ret, func, ...) \ - typedef ret (*func##Type)(__VA_ARGS__); \ - inline static ret (*func##Sym)(__VA_ARGS__); \ - inline static ret func(__VA_ARGS__) - -#define CREATE_MEM_FUNC_SYMBOL_ENTRY(ret, func, thiz, ...) \ - using func##Type = lsplant::MemberFunction; \ - inline static func##Type func##Sym; \ - inline static ret func(thiz, ##__VA_ARGS__) - namespace lsplant { -using HookHandler = InitInfo; - template struct FixedString { - consteval inline FixedString(const char (&str)[N]) { std::copy_n(str, N, data); } + consteval FixedString(const char (&str)[N]) { std::copy_n(str, N, data); } +#if defined(__LP64__) + template + consteval FixedString(const char (&)[M], const char (&str)[N]) : FixedString(str) {} +#else + template + consteval FixedString(const char (&str)[N], const char (&)[M]) : FixedString(str) {} +#endif char data[N] = {}; }; -inline void *Dlsym(const HookHandler &handle, const char *name, bool match_prefix = false) { - if (auto match = handle.art_symbol_resolver(name); match) { - return match; - } else if (match_prefix && handle.art_symbol_prefix_resolver) { - return handle.art_symbol_prefix_resolver(name); - } - return nullptr; -} +template +struct Function; + +template +struct MemberFunction; + +template +struct Field { + [[gnu::always_inline]] T *operator->() { return field_; } + [[gnu::always_inline]] T &operator*() { return *field_; } + [[gnu::always_inline]] operator bool() { return field_ != nullptr; } + +private: + friend struct HookHandler; + T *field_; +}; + +template +struct Hooker; + +template +struct MemberHooker; template requires(std::is_same_v || std::is_same_v) -inline static auto memfun_cast(Return (*func)(T *, Args...)) { +inline auto memfun_cast(Return (*func)(T *, Args...)) { union { Return (Class::*f)(Args...); @@ -79,102 +65,106 @@ inline auto memfun_cast(Return (*func)(T *, Args...)) { return memfun_cast(func); } -template -class MemberFunction; +struct HookHandler { + HookHandler(const InitInfo &info) : info_(info) {} + template + [[gnu::always_inline]] bool dlsym(MemberFunction &function, + bool match_prefix = false) const { + return function.function_ = memfun_cast( + reinterpret_cast(dlsym(match_prefix))); + } -template -class MemberFunction { - using SelfType = MemberFunction; - using ThisType = std::conditional_t, SelfType, This>; - using MemFunType = Return (ThisType::*)(Args...); + template + [[gnu::always_inline]] bool dlsym(Function &function, + bool match_prefix = false) const { + return function.function_ = reinterpret_cast(dlsym(match_prefix)); + } -public: - using FunType = Return (*)(This *, Args...); + template + [[gnu::always_inline]] bool dlsym(Field &field, bool match_prefix = false) const { + return field.field_ = reinterpret_cast(dlsym(match_prefix)); + } + + template + [[gnu::always_inline]] bool hook(Hooker &hooker) const { + return hooker.function_ = reinterpret_cast( + hook(dlsym(), reinterpret_cast(hooker.replace_))); + } + + template + [[gnu::always_inline]] bool hook(MemberHooker &hooker) const { + return hooker.function_ = memfun_cast(reinterpret_cast( + hook(dlsym(), reinterpret_cast(hooker.replace_)))); + } + + template + [[gnu::always_inline]] bool hook(T &...args) const { + return (hook(args) || ...); + } private: - MemFunType f_ = nullptr; + const InitInfo &info_; -public: - MemberFunction() = default; - - MemberFunction(FunType f) : f_(memfun_cast(f)) {} - - MemberFunction(MemFunType f) : f_(f) {} - - Return operator()(This *thiz, Args... args) { - return (reinterpret_cast(thiz)->*f_)(std::forward(args)...); - } - - inline operator bool() { return f_ != nullptr; } -}; - -// deduction guide -template -MemberFunction(Return (*f)(This *, Args...)) -> MemberFunction; - -template -MemberFunction(Return (This::*f)(Args...)) -> MemberFunction; - -template -struct Hooker; - -template -struct Hooker { - inline static Ret (*backup)(Args...) = nullptr; - - inline static constexpr std::string_view sym = Sym.data; -}; - -template -struct MemHooker; -template -struct MemHooker { - inline static MemberFunction backup; - inline static constexpr std::string_view sym = Sym.data; -}; - -template -concept HookerType = requires(T a) { - a.backup; - a.replace; -}; - -template -inline static bool HookSymNoHandle(const HookHandler &handler, void *original, T &arg) { - if (original) { - if constexpr (is_instance_v) { - void *backup = handler.inline_hooker(original, reinterpret_cast(arg.replace)); - arg.backup = reinterpret_cast(backup); - } else { - arg.backup = reinterpret_cast( - handler.inline_hooker(original, reinterpret_cast(arg.replace))); + template + [[gnu::always_inline]] void *dlsym(bool match_prefix = false) const { + if (auto match = info_.art_symbol_resolver(Sym.data); match) { + return match; } - return true; - } else { - return false; + if (match_prefix && info_.art_symbol_prefix_resolver) { + return info_.art_symbol_prefix_resolver(Sym.data); + } + return nullptr; } -} -template -inline static bool HookSym(const HookHandler &handler, T &arg) { - auto original = handler.art_symbol_resolver(arg.sym); - return HookSymNoHandle(handler, original, arg); -} - -template -inline static bool HookSyms(const HookHandler &handle, T &first, Args &...rest) { - if (!(HookSym(handle, first) || ... || HookSym(handle, rest))) { - __android_log_print(ANDROID_LOG_ERROR, -#ifdef LOG_TAG - LOG_TAG, -#else - "HookHelper", -#endif - "Hook Fails: %*s", static_cast(first.sym.size()), - first.sym.data()); - return false; + void *hook(void *original, void *replace) const { + if (original) { + return info_.inline_hooker(original, replace); + } + return nullptr; } - return true; -} +}; + +template +struct Function { + [[gnu::always_inline]] constexpr Ret operator()(Args... args) { return function_(args...); } + [[gnu::always_inline]] operator bool() { return function_ != nullptr; } + auto operator&() const { return function_; } + +private: + friend struct HookHandler; + Ret (*function_)(Args...) = nullptr; +}; + +template +struct MemberFunction { + [[gnu::always_inline]] constexpr Ret operator()(This *thiz, Args... args) { + return (reinterpret_cast(thiz)->*function_)(args...); + } + [[gnu::always_inline]] operator bool() { return function_ != nullptr; } + +private: + friend struct HookHandler; + using ThisType = std::conditional_t, MemberFunction, This>; + Ret (ThisType::*function_)(Args...) = nullptr; +}; + +template +struct Hooker : Function { + [[gnu::always_inline]] constexpr Hooker(Ret (*replace)(Args...)) : replace_(replace) {}; + +private: + friend struct HookHandler; + [[maybe_unused]] Ret (*replace_)(Args...) = nullptr; +}; + +template +struct MemberHooker : MemberFunction { + [[gnu::always_inline]] constexpr MemberHooker(Ret (*replace)(This *, Args...)) + : replace_(replace) {}; + +private: + friend struct HookHandler; + [[maybe_unused]] Ret (*replace_)(This *, Args...) = nullptr; +}; } // namespace lsplant diff --git a/lsplant/src/main/jni/include/utils/hook_helper.ixx b/lsplant/src/main/jni/include/utils/hook_helper.ixx new file mode 100644 index 0000000..c7887e4 --- /dev/null +++ b/lsplant/src/main/jni/include/utils/hook_helper.ixx @@ -0,0 +1,16 @@ +module; + +#include "hook_helper.hpp" + +export module hook_helper; + +export namespace lsplant { +using lsplant::Field; +using lsplant::FixedString; +using lsplant::Function; +using lsplant::Hooker; +using lsplant::HookHandler; +using lsplant::MemberFunction; +using lsplant::MemberHooker; +using lsplant::memfun_cast; +} // namespace lsplant diff --git a/lsplant/src/main/jni/lsplant.cc b/lsplant/src/main/jni/lsplant.cc index 718deae..efd3bbe 100644 --- a/lsplant/src/main/jni/lsplant.cc +++ b/lsplant/src/main/jni/lsplant.cc @@ -1,14 +1,16 @@ #include #include +#include #include #include #include #include #include +#include +#include #include "logging.hpp" -#include "utils/hook_helper.hpp" import dex_builder; import lsplant; @@ -26,6 +28,7 @@ import jit_code_cache; import jni_id_manager; import dex_file; import jit; +import hook_helper; #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wunknown-pragmas" @@ -42,8 +45,8 @@ using art::Instrumentation; using art::Runtime; using art::Thread; using art::gc::ScopedGCCriticalSection; -using art::jit::JitCodeCache; using art::jit::Jit; +using art::jit::JitCodeCache; using art::jni::JniIdManager; using art::mirror::Class; using art::thread_list::ScopedSuspendAll; @@ -256,9 +259,6 @@ inline void UpdateTrampoline(uint8_t offset) { } bool InitNative(JNIEnv *env, const HookHandler &handler) { - if (!handler.inline_hooker || !handler.inline_unhooker || !handler.art_symbol_resolver) { - return false; - } if (!ArtMethod::Init(env, handler)) { LOGE("Failed to init art method"); return false; @@ -482,8 +482,8 @@ std::tuple BuildDex(JNIEnv *env, jobject mprotect(target, image.size(), PROT_READ); std::string err_msg; const auto *dex = DexFile::OpenMemory( - target, image.size(), generated_source_name.empty() ? "lsplant" : generated_source_name, - &err_msg); + reinterpret_cast(target), image.size(), + generated_source_name.empty() ? "lsplant" : generated_source_name, &err_msg); if (!dex) { LOGE("Failed to open memory dex: %s", err_msg.data()); } else { @@ -694,6 +694,10 @@ inline namespace v2 { using ::lsplant::IsHooked; [[maybe_unused]] bool Init(JNIEnv *env, const InitInfo &info) { + if (!info.inline_hooker || !info.inline_unhooker || !info.art_symbol_resolver || + !info.art_symbol_prefix_resolver) { + return false; + } bool static kInit = InitConfig(info) && InitJNI(env) && InitNative(env, info); return kInit; }