Fix art_quick_* not found

Close #136
This commit is contained in:
LoveSy 2025-02-26 20:58:24 +08:00
parent 8c3c6e6b2c
commit ce08314ca3
No known key found for this signature in database
5 changed files with 106 additions and 61 deletions

View File

@ -2,6 +2,7 @@ module;
#include <atomic> #include <atomic>
#include <string> #include <string>
#include <memory>
#include "logging.hpp" #include "logging.hpp"
@ -98,6 +99,18 @@ public:
SetAccessFlags(access_flags); SetAccessFlags(access_flags);
} }
void SetNative() {
auto access_flags = GetAccessFlags();
access_flags |= kAccNative;
SetAccessFlags(access_flags);
}
void SetNonNative() {
auto access_flags = GetAccessFlags();
access_flags &= ~kAccNative;
SetAccessFlags(access_flags);
}
bool IsPrivate() { return GetAccessFlags() & kAccPrivate; } bool IsPrivate() { return GetAccessFlags() & kAccPrivate; }
bool IsProtected() { return GetAccessFlags() & kAccProtected; } bool IsProtected() { return GetAccessFlags() & kAccProtected; }
bool IsPublic() { return GetAccessFlags() & kAccPublic; } bool IsPublic() { return GetAccessFlags() & kAccPublic; }
@ -155,6 +168,12 @@ public:
reinterpret_cast<uintptr_t>(this) + declaring_class_offset)); reinterpret_cast<uintptr_t>(this) + declaring_class_offset));
} }
std::unique_ptr<ArtMethod> Clone() {
auto *method = reinterpret_cast<ArtMethod*>(::operator new(art_method_size));
method->CopyFrom(this);
return std::unique_ptr<ArtMethod>(method);
}
void BackupTo(ArtMethod *backup) { void BackupTo(ArtMethod *backup) {
SetNonCompilable(); SetNonCompilable();

View File

@ -12,6 +12,7 @@ import common;
import clazz; import clazz;
import handle; import handle;
import hook_helper; import hook_helper;
import runtime;
namespace lsplant::art { namespace lsplant::art {
export class ClassLinker { export class ClassLinker {
@ -35,6 +36,9 @@ private:
inline static Function<"art_quick_generic_jni_trampoline", void(void *)> inline static Function<"art_quick_generic_jni_trampoline", void(void *)>
art_quick_generic_jni_trampoline_; art_quick_generic_jni_trampoline_;
inline static Function<"_ZN3art15instrumentationL19GetOptimizedCodeForEPNS_9ArtMethodE",
void *(ArtMethod *)> GetOptimizedCodeFor_;
inline static art::ArtMethod *MayGetBackup(art::ArtMethod *method) { inline static art::ArtMethod *MayGetBackup(art::ArtMethod *method) {
if (auto backup = IsHooked(method); backup) [[unlikely]] { if (auto backup = IsHooked(method); backup) [[unlikely]] {
method = backup; method = backup;
@ -161,7 +165,7 @@ private:
}; };
public: public:
static bool Init(const HookHandler &handler) { static bool Init(JNIEnv *env, const HookHandler &handler) {
int sdk_int = GetAndroidApiLevel(); int sdk_int = GetAndroidApiLevel();
if (sdk_int >= __ANDROID_API_N__ && sdk_int < __ANDROID_API_T__) { if (sdk_int >= __ANDROID_API_N__ && sdk_int < __ANDROID_API_T__) {
@ -187,16 +191,32 @@ public:
} }
} }
if (!handler.dlsym(SetEntryPointsToInterpreter_)) [[unlikely]] { if (handler.dlsym(GetOptimizedCodeFor_, true)) [[likely]] {
auto obj = JNI_FindClass(env, "java/lang/Object");
if (!obj) {
return false;
}
auto method = JNI_GetMethodID(env, obj, "equals", "(Ljava/lang/Object;)Z");
if (!method) {
return false;
}
auto dummy = ArtMethod::FromReflectedMethod(
env, JNI_ToReflectedMethod(env, obj, method, false).get())->Clone();
JavaDebuggableGuard guard;
dummy->SetNonNative();
art_quick_to_interpreter_bridge_ = GetOptimizedCodeFor_(dummy.get());
dummy->SetNative();
art_quick_generic_jni_trampoline_ = GetOptimizedCodeFor_(dummy.get());
} else if (!handler.dlsym(SetEntryPointsToInterpreter_)) [[unlikely]] {
if (!handler.dlsym(art_quick_to_interpreter_bridge_)) [[unlikely]] { if (!handler.dlsym(art_quick_to_interpreter_bridge_)) [[unlikely]] {
return false; return false;
} }
if (!handler.dlsym(art_quick_generic_jni_trampoline_)) [[unlikely]] { if (!handler.dlsym(art_quick_generic_jni_trampoline_)) [[unlikely]] {
return false; return false;
} }
LOGD("art_quick_to_interpreter_bridge = %p", &art_quick_to_interpreter_bridge_);
LOGD("art_quick_generic_jni_trampoline = %p", &art_quick_generic_jni_trampoline_);
} }
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; return true;
} }

View File

@ -1,6 +1,7 @@
module; module;
#include <array> #include <array>
#include <atomic>
#include "logging.hpp" #include "logging.hpp"
@ -87,4 +88,56 @@ public:
return true; return true;
} }
}; };
export 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<std::atomic_size_t::value_type, size_t>,
"Unsupported architecture");
};
} // namespace lsplant::art } // namespace lsplant::art

View File

@ -129,6 +129,10 @@ struct Function<Sym, Ret(Args...)> {
[[gnu::always_inline]] constexpr Ret operator()(Args... args) { return function_(args...); } [[gnu::always_inline]] constexpr Ret operator()(Args... args) { return function_(args...); }
[[gnu::always_inline]] operator bool() { return function_ != nullptr; } [[gnu::always_inline]] operator bool() { return function_ != nullptr; }
auto operator&() const { return function_; } auto operator&() const { return function_; }
Function &operator=(void *function) {
function_ = reinterpret_cast<decltype(function_)>(function);
return *this;
}
private: private:
friend struct HookHandler; friend struct HookHandler;

View File

@ -50,6 +50,7 @@ using art::jit::JitCodeCache;
using art::jni::JniIdManager; using art::jni::JniIdManager;
using art::mirror::Class; using art::mirror::Class;
using art::thread_list::ScopedSuspendAll; using art::thread_list::ScopedSuspendAll;
using art::JavaDebuggableGuard;
using namespace std::string_view_literals; using namespace std::string_view_literals;
@ -272,7 +273,11 @@ bool InitNative(JNIEnv *env, const HookHandler &handler) {
LOGE("Failed to init mirror class"); LOGE("Failed to init mirror class");
return false; return false;
} }
if (!ClassLinker::Init(handler)) { if (!Runtime::Init(handler)) {
LOGE("Failed to init runtime");
return false;
}
if (!ClassLinker::Init(env, handler)) {
LOGE("Failed to init class linker"); LOGE("Failed to init class linker");
return false; return false;
} }
@ -304,10 +309,6 @@ bool InitNative(JNIEnv *env, const HookHandler &handler) {
LOGE("Failed to init jni id manager"); LOGE("Failed to init jni id manager");
return false; return false;
} }
if (!Runtime::Init(handler)) {
LOGE("Failed to init runtime");
return false;
}
// This should always be the last one // This should always be the last one
if (IsJavaDebuggable(env)) { if (IsJavaDebuggable(env)) {
@ -318,58 +319,6 @@ bool InitNative(JNIEnv *env, const HookHandler &handler) {
return true; 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<std::atomic_size_t::value_type, size_t>,
"Unsupported architecture");
};
std::tuple<jclass, jfieldID, jmethodID, jmethodID> BuildDex(JNIEnv *env, jobject class_loader, std::tuple<jclass, jfieldID, jmethodID, jmethodID> BuildDex(JNIEnv *env, jobject class_loader,
std::string_view shorty, bool is_static, std::string_view shorty, bool is_static,
std::string_view method_name, std::string_view method_name,