From 3955a98d9b0a54a9a8d2e1c005601c330688c204 Mon Sep 17 00:00:00 2001 From: LoveSy Date: Fri, 18 Feb 2022 12:55:49 +0800 Subject: [PATCH] Use jobject instead of jmethodid --- library/jni/include/lsplant.hpp | 12 ++++----- library/jni/lsplant.cc | 48 +++++++++++++++------------------ 2 files changed, 27 insertions(+), 33 deletions(-) diff --git a/library/jni/include/lsplant.hpp b/library/jni/include/lsplant.hpp index 35b5c93..cbc12bf 100644 --- a/library/jni/include/lsplant.hpp +++ b/library/jni/include/lsplant.hpp @@ -94,8 +94,8 @@ bool Init(JNIEnv *env, const InitInfo &info); /// will success. If you call this with different \p hooker_object on the same target_method /// simultaneously, the behavior is undefined. [[nodiscard]] [[maybe_unused]] [[gnu::visibility("default")]] -jmethodID -Hook(JNIEnv *env, jmethodID target_method, jobject hooker_object, jmethodID callback_method); +jobject +Hook(JNIEnv *env, jobject target_method, jobject hooker_object, jobject callback_method); /// \brief Unhook a Java function that is previously hooked. /// \param[in] env The Java environment. @@ -104,7 +104,7 @@ Hook(JNIEnv *env, jmethodID target_method, jobject hooker_object, jmethodID call /// \note please read #Hook()'s note for more details. /// \see Hook() [[nodiscard]] [[maybe_unused]] [[gnu::visibility("default")]] -bool UnHook(JNIEnv *env, jmethodID target_method); +bool UnHook(JNIEnv *env, jobject target_method); /// \brief Check if a Java function is hooked by LSPlant or not /// \param[in] env The Java environment. @@ -112,7 +112,7 @@ bool UnHook(JNIEnv *env, jmethodID target_method); /// \return If \p method hooked, ture; otherwise, false. /// \note please read #Hook()'s note for more details. [[nodiscard]] [[maybe_unused]] [[gnu::visibility("default")]] -bool IsHooked(JNIEnv *env, jmethodID method); +bool IsHooked(JNIEnv *env, jobject method); /// \brief Deoptimize a method to avoid hooked callee not being called because of inline /// \param[in] env The Java environment. @@ -128,7 +128,7 @@ bool IsHooked(JNIEnv *env, jmethodID method); /// \note It is safe to call deoptimizing on a hooked method because the deoptimization will /// perform on the backup method instead. [[nodiscard]] [[maybe_unused]] [[gnu::visibility("default")]] -bool Deoptimize(JNIEnv *env, jmethodID method); +bool Deoptimize(JNIEnv *env, jobject method); /// \brief Get the registered native function pointer of a native function. It helps user to hook native /// methods directly by backing up the native function pointer this function returns and @@ -138,6 +138,6 @@ bool Deoptimize(JNIEnv *env, jmethodID method); /// \return The native function pointer the \p method previously registered. If it has not been /// registered or it is not a native method, null is returned instead. [[nodiscard]] [[maybe_unused]] [[gnu::visibility("default")]] -void *GetNativeFunction(JNIEnv *env, jmethodID method); +void *GetNativeFunction(JNIEnv *env, jobject method); } } // namespace lsplant diff --git a/library/jni/lsplant.cc b/library/jni/lsplant.cc index 3934798..5a7fccd 100644 --- a/library/jni/lsplant.cc +++ b/library/jni/lsplant.cc @@ -448,20 +448,17 @@ bool Init(JNIEnv *env, const InitInfo &info) { } -// TODO: sync? does not record hook immediately [[maybe_unused]] -jmethodID -Hook(JNIEnv *env, jmethodID target_method, jobject hooker_object, jmethodID callback_method) { - auto reflected_target = JNI_ToReflectedMethod(env, jclass{ nullptr }, target_method, false); - auto reflected_callback = JNI_ToReflectedMethod(env, jclass{ nullptr }, callback_method, false); +jobject +Hook(JNIEnv *env, jobject target_method, jobject hooker_object, jobject callback_method) { jmethodID hook_method = nullptr; jmethodID backup_method = nullptr; jfieldID hooker_field = nullptr; auto target_class = JNI_Cast( - JNI_CallObjectMethod(env, reflected_target, method_get_declaring_class)); + JNI_CallObjectMethod(env, target_method, method_get_declaring_class)); bool is_proxy = JNI_CallBooleanMethod(env, target_class, class_is_proxy); - auto *target = ArtMethod::FromReflectedMethod(env, reflected_target); + auto *target = ArtMethod::FromReflectedMethod(env, target_method); bool is_static = target->IsStatic(); if (IsHooked(target) || IsPending(target)) { @@ -472,22 +469,23 @@ Hook(JNIEnv *env, jmethodID target_method, jobject hooker_object, jmethodID call ScopedLocalRef built_class{ env }; { auto callback_name = JNI_Cast( - JNI_CallObjectMethod(env, reflected_callback, method_get_name)); + JNI_CallObjectMethod(env, callback_method, method_get_name)); JUTFString method_name(callback_name); - auto callback_class = JNI_Cast(JNI_CallObjectMethod(env, reflected_callback, + auto callback_class = JNI_Cast(JNI_CallObjectMethod(env, callback_method, method_get_declaring_class)); auto callback_class_loader = JNI_CallObjectMethod(env, callback_class, class_get_class_loader); auto callback_class_name = JNI_Cast(JNI_CallObjectMethod(env, callback_class, class_get_canonical_name)); JUTFString class_name(callback_class_name); - if (env->IsInstanceOf(hooker_object, callback_class)) { + if (!env->IsInstanceOf(hooker_object, callback_class)) { LOGE("callback_method is not a method of hooker_object"); return nullptr; } std::tie(built_class, hooker_field, hook_method, backup_method) = WrapScope(env, BuildDex(env, callback_class_loader, - ArtMethod::GetMethodShorty(env, target_method), + ArtMethod::GetMethodShorty(env, env->FromReflectedMethod( + target_method)), is_static, method_name.get(), class_name.get(), @@ -498,8 +496,8 @@ Hook(JNIEnv *env, jmethodID target_method, jobject hooker_object, jmethodID call } } - auto reflected_hook = JNI_ToReflectedMethod(env, jclass{ nullptr }, hook_method, false); - auto reflected_backup = JNI_ToReflectedMethod(env, jclass{ nullptr }, backup_method, false); + auto reflected_hook = JNI_ToReflectedMethod(env, built_class, hook_method, is_static); + auto reflected_backup = JNI_ToReflectedMethod(env, built_class, backup_method, is_static); auto *hook = ArtMethod::FromReflectedMethod(env, reflected_hook); auto *backup = ArtMethod::FromReflectedMethod(env, reflected_backup); @@ -518,21 +516,20 @@ Hook(JNIEnv *env, jmethodID target_method, jobject hooker_object, jmethodID call return nullptr; } RecordPending(class_def, target, hook, backup); - return backup_method; + return reflected_backup; } if (DoHook(target, hook, backup)) { RecordHooked(target, JNI_NewGlobalRef(env, reflected_backup)); if (!is_proxy) [[likely]] RecordJitMovement(target, backup); - return backup_method; + return reflected_backup; } return nullptr; } [[maybe_unused]] -bool UnHook(JNIEnv *env, jmethodID target_method) { - auto reflected_target = JNI_ToReflectedMethod(env, jclass{ nullptr }, target_method, false); - auto *target = ArtMethod::FromReflectedMethod(env, reflected_target); +bool UnHook(JNIEnv *env, jobject target_method) { + auto *target = ArtMethod::FromReflectedMethod(env, target_method); jobject reflected_backup = nullptr; { std::unique_lock lk(pending_methods_lock_); @@ -558,9 +555,8 @@ bool UnHook(JNIEnv *env, jmethodID target_method) { } [[maybe_unused]] -bool IsHooked(JNIEnv *env, jmethodID method) { - auto reflected = JNI_ToReflectedMethod(env, jclass{ nullptr }, method, false); - auto *art_method = ArtMethod::FromReflectedMethod(env, reflected); +bool IsHooked(JNIEnv *env, jobject method) { + auto *art_method = ArtMethod::FromReflectedMethod(env, method); if (std::shared_lock lk(hooked_methods_lock_); hooked_methods_.contains(art_method)) { return true; @@ -572,9 +568,8 @@ bool IsHooked(JNIEnv *env, jmethodID method) { } [[maybe_unused]] -bool Deoptimize(JNIEnv *env, jmethodID method) { - auto reflected = JNI_ToReflectedMethod(env, jclass{ nullptr }, method, false); - auto *art_method = ArtMethod::FromReflectedMethod(env, reflected); +bool Deoptimize(JNIEnv *env, jobject method) { + auto *art_method = ArtMethod::FromReflectedMethod(env, method); if (IsHooked(art_method)) { std::shared_lock lk(hooked_methods_lock_); auto it = hooked_methods_.find(art_method); @@ -590,9 +585,8 @@ bool Deoptimize(JNIEnv *env, jmethodID method) { } [[maybe_unused]] -void *GetNativeFunction(JNIEnv *env, jmethodID method) { - auto reflected = JNI_ToReflectedMethod(env, jclass{ nullptr }, method, false); - auto *art_method = ArtMethod::FromReflectedMethod(env, reflected); +void *GetNativeFunction(JNIEnv *env, jobject method) { + auto *art_method = ArtMethod::FromReflectedMethod(env, method); if (!art_method->IsNative()) return nullptr; return art_method->GetData(); }