From 780cbe09a35b45a5f02de0e4fcb640ea936a2710 Mon Sep 17 00:00:00 2001 From: LoveSy Date: Tue, 10 Oct 2023 02:29:53 +0800 Subject: [PATCH] Fix class verification of hooker crash for sdk 34 --- lsplant/src/main/jni/lsplant.cc | 132 ++++++++++++++++---------------- 1 file changed, 67 insertions(+), 65 deletions(-) diff --git a/lsplant/src/main/jni/lsplant.cc b/lsplant/src/main/jni/lsplant.cc index 53c2388..393893e 100644 --- a/lsplant/src/main/jni/lsplant.cc +++ b/lsplant/src/main/jni/lsplant.cc @@ -301,6 +301,58 @@ bool InitNative(JNIEnv *env, const HookHandler &handler) { return true; } +struct JavaDebuggableGuard { + JavaDebuggableGuard() { + while (true) { + size_t expected = 0; + if (count.compare_exchange_strong(expected, 1, std::memory_order_acq_rel, + std::memory_order_acquire)) { + Runtime::Current()->SetJavaDebuggable( + Runtime::RuntimeDebugState::kJavaDebuggableAtInit); + count.fetch_add(1, std::memory_order_release); + count.notify_all(); + break; + } + if (expected == 1) { + count.wait(expected, std::memory_order_acquire); + continue; + } + if (count.compare_exchange_strong(expected, expected + 1, std::memory_order_acq_rel, + std::memory_order_relaxed)) { + break; + } + } + } + + ~JavaDebuggableGuard() { + while (true) { + size_t expected = 2; + if (count.compare_exchange_strong(expected, 1, std::memory_order_acq_rel, + std::memory_order_acquire)) { + Runtime::Current()->SetJavaDebuggable( + Runtime::RuntimeDebugState::kNonJavaDebuggable); + count.fetch_sub(1, std::memory_order_release); + count.notify_all(); + break; + } + if (expected == 1) { + count.wait(expected, std::memory_order_acquire); + continue; + } + if (count.compare_exchange_strong(expected, expected - 1, std::memory_order_acq_rel, + std::memory_order_relaxed)) { + break; + } + } + } + +private: + inline static std::atomic_size_t count{0}; + static_assert(std::atomic_size_t::is_always_lock_free, "Unsupported architecture"); + static_assert(std::is_same_v, + "Unsupported architecture"); +}; + std::tuple BuildDex(JNIEnv *env, jobject class_loader, std::string_view shorty, bool is_static, std::string_view method_name, @@ -395,17 +447,17 @@ std::tuple BuildDex(JNIEnv *env, jobject jclass target_class = nullptr; + ScopedLocalRef my_cl{nullptr}; + if (in_memory_class_loader_init) [[likely]] { auto dex_buffer = JNI_NewDirectByteBuffer(env, const_cast(image.ptr()), static_cast(image.size())); - auto my_cl = JNI_NewObject(env, in_memory_class_loader, in_memory_class_loader_init, + // FIXME: a very hacky way to disable background verification of the hooker classloader, + // which fixes a crash for art 34+; there should be a better way to do this. + JavaDebuggableGuard guard; + + my_cl = JNI_NewObject(env, in_memory_class_loader, in_memory_class_loader_init, dex_buffer, class_loader); - if (my_cl) { - target_class = JNI_Cast(JNI_CallObjectMethod( - env, my_cl, load_class, - JNI_NewStringUTF(env, generated_class_name.data()))) - .release(); - } } else { void *target = mmap(nullptr, image.size(), PROT_WRITE | PROT_READ, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); @@ -420,15 +472,18 @@ std::tuple BuildDex(JNIEnv *env, jobject } auto java_dex_file = WrapScope(env, dex ? dex->ToJavaDexFile(env) : jobject{nullptr}); if (dex && java_dex_file) { - auto p = JNI_NewObject(env, path_class_loader, path_class_loader_init, + my_cl = JNI_NewObject(env, path_class_loader, path_class_loader_init, JNI_NewStringUTF(env, ""), class_loader); - target_class = JNI_Cast(JNI_CallObjectMethod( - env, java_dex_file, load_class, - env->NewStringUTF(generated_class_name.data()), p)) - .release(); } } + if (my_cl) { + target_class = JNI_Cast(JNI_CallObjectMethod( + env, my_cl, load_class, + JNI_NewStringUTF(env, generated_class_name.data()))) + .release(); + } + if (target_class) { return { target_class, @@ -613,59 +668,6 @@ std::string GetProxyMethodShorty(JNIEnv *env, jobject proxy_method) { } return out; } - -struct JavaDebuggableGuard { - JavaDebuggableGuard() { - while (true) { - size_t expected = 0; - if (count.compare_exchange_strong(expected, 1, std::memory_order_acq_rel, - std::memory_order_acquire)) { - Runtime::Current()->SetJavaDebuggable( - Runtime::RuntimeDebugState::kJavaDebuggableAtInit); - count.fetch_add(1, std::memory_order_release); - count.notify_all(); - break; - } - if (expected == 1) { - count.wait(expected, std::memory_order_acquire); - continue; - } - if (count.compare_exchange_strong(expected, expected + 1, std::memory_order_acq_rel, - std::memory_order_relaxed)) { - break; - } - } - } - - ~JavaDebuggableGuard() { - while (true) { - size_t expected = 2; - if (count.compare_exchange_strong(expected, 1, std::memory_order_acq_rel, - std::memory_order_acquire)) { - Runtime::Current()->SetJavaDebuggable( - Runtime::RuntimeDebugState::kNonJavaDebuggable); - count.fetch_sub(1, std::memory_order_release); - count.notify_all(); - break; - } - if (expected == 1) { - count.wait(expected, std::memory_order_acquire); - continue; - } - if (count.compare_exchange_strong(expected, expected - 1, std::memory_order_acq_rel, - std::memory_order_relaxed)) { - break; - } - } - } - -private: - inline static std::atomic_size_t count{0}; - static_assert(std::atomic_size_t::is_always_lock_free, "Unsupported architecture"); - static_assert(std::is_same_v, - "Unsupported architecture"); -}; - } // namespace inline namespace v2 {