mirror of
https://github.com/LSPosed/LSPlant.git
synced 2025-05-04 20:42:02 +08:00
parent
8c3c6e6b2c
commit
ce08314ca3
@ -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();
|
||||||
|
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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;
|
||||||
|
@ -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,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user