mirror of
https://github.com/LSPosed/LSPlant.git
synced 2025-05-04 20:42:02 +08:00
Support SetRuntimeDebugState (#24)
This commit is contained in:
parent
2bd37aaba9
commit
7c5457a699
@ -2,5 +2,5 @@ val androidTargetSdkVersion by extra(33)
|
|||||||
val androidMinSdkVersion by extra(21)
|
val androidMinSdkVersion by extra(21)
|
||||||
val androidBuildToolsVersion by extra("33.0.0")
|
val androidBuildToolsVersion by extra("33.0.0")
|
||||||
val androidCompileSdkVersion by extra(33)
|
val androidCompileSdkVersion by extra(33)
|
||||||
val androidNdkVersion by extra("24.0.8215888")
|
val androidNdkVersion by extra("25.1.8937393")
|
||||||
val androidCmakeVersion by extra("3.22.1+")
|
val androidCmakeVersion by extra("3.22.1+")
|
||||||
|
2
gradle/wrapper/gradle-wrapper.properties
vendored
2
gradle/wrapper/gradle-wrapper.properties
vendored
@ -1,5 +1,5 @@
|
|||||||
distributionBase=GRADLE_USER_HOME
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-bin.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-bin.zip
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
zipStorePath=wrapper/dists
|
zipStorePath=wrapper/dists
|
||||||
|
@ -114,7 +114,7 @@ publishing {
|
|||||||
register<MavenPublication>("lsplant") {
|
register<MavenPublication>("lsplant") {
|
||||||
group = "org.lsposed.lsplant"
|
group = "org.lsposed.lsplant"
|
||||||
artifactId = "lsplant"
|
artifactId = "lsplant"
|
||||||
version = "4.1"
|
version = "4.2"
|
||||||
afterEvaluate {
|
afterEvaluate {
|
||||||
from(components.getByName("release"))
|
from(components.getByName("release"))
|
||||||
artifact(symbolsTask)
|
artifact(symbolsTask)
|
||||||
|
@ -24,19 +24,46 @@
|
|||||||
namespace lsplant::art {
|
namespace lsplant::art {
|
||||||
|
|
||||||
class Runtime {
|
class Runtime {
|
||||||
|
public:
|
||||||
|
enum class RuntimeDebugState {
|
||||||
|
// This doesn't support any debug features / method tracing. This is the expected state
|
||||||
|
// usually.
|
||||||
|
kNonJavaDebuggable,
|
||||||
|
// This supports method tracing and a restricted set of debug features (for ex: redefinition
|
||||||
|
// isn't supported). We transition to this state when method tracing has started or when the
|
||||||
|
// debugger was attached and transition back to NonDebuggable once the tracing has stopped /
|
||||||
|
// the debugger agent has detached..
|
||||||
|
kJavaDebuggable,
|
||||||
|
// The runtime was started as a debuggable runtime. This allows us to support the extended
|
||||||
|
// set
|
||||||
|
// of debug features (for ex: redefinition). We never transition out of this state.
|
||||||
|
kJavaDebuggableAtInit
|
||||||
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
inline static Runtime *instance_;
|
inline static Runtime *instance_;
|
||||||
|
|
||||||
CREATE_MEM_FUNC_SYMBOL_ENTRY(void, SetJavaDebuggable, void *thiz, bool value) {
|
CREATE_MEM_FUNC_SYMBOL_ENTRY(void, SetJavaDebuggable, void *thiz, bool value) {
|
||||||
if (SetJavaDebuggableSym) [[likely]] {
|
|
||||||
SetJavaDebuggableSym(thiz, value);
|
SetJavaDebuggableSym(thiz, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CREATE_MEM_FUNC_SYMBOL_ENTRY(void, SetRuntimeDebugState, void *thiz, RuntimeDebugState value) {
|
||||||
|
SetRuntimeDebugStateSym(thiz, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline static size_t debug_state_offset = 0U;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
inline static Runtime *Current() { return instance_; }
|
inline static Runtime *Current() { return instance_; }
|
||||||
|
|
||||||
void SetJavaDebuggable(bool value) { SetJavaDebuggable(this, value); }
|
void SetJavaDebuggable(RuntimeDebugState value) {
|
||||||
|
if (SetJavaDebuggableSym) {
|
||||||
|
SetJavaDebuggable(this, value != RuntimeDebugState::kNonJavaDebuggable);
|
||||||
|
} else if (debug_state_offset > 0) {
|
||||||
|
*reinterpret_cast<RuntimeDebugState *>(reinterpret_cast<uintptr_t>(instance_) +
|
||||||
|
debug_state_offset) = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static bool Init(const HookHandler &handler) {
|
static bool Init(const HookHandler &handler) {
|
||||||
int sdk_int = GetAndroidApiLevel();
|
int sdk_int = GetAndroidApiLevel();
|
||||||
@ -48,7 +75,32 @@ public:
|
|||||||
LOGD("runtime instance = %p", instance_);
|
LOGD("runtime instance = %p", instance_);
|
||||||
if (sdk_int >= __ANDROID_API_O__) {
|
if (sdk_int >= __ANDROID_API_O__) {
|
||||||
if (!RETRIEVE_MEM_FUNC_SYMBOL(SetJavaDebuggable,
|
if (!RETRIEVE_MEM_FUNC_SYMBOL(SetJavaDebuggable,
|
||||||
"_ZN3art7Runtime17SetJavaDebuggableEb")) {
|
"_ZN3art7Runtime17SetJavaDebuggableEb") &&
|
||||||
|
!RETRIEVE_MEM_FUNC_SYMBOL(
|
||||||
|
SetRuntimeDebugState,
|
||||||
|
"_ZN3art7Runtime20SetRuntimeDebugStateENS0_17RuntimeDebugStateE")) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (SetRuntimeDebugStateSym) {
|
||||||
|
static constexpr size_t kLargeEnoughSizeForRuntime = 4096;
|
||||||
|
std::array<uint8_t, kLargeEnoughSizeForRuntime> code;
|
||||||
|
static_assert(static_cast<int>(RuntimeDebugState::kJavaDebuggable) != 0);
|
||||||
|
static_assert(static_cast<int>(RuntimeDebugState::kJavaDebuggableAtInit) != 0);
|
||||||
|
code.fill(uint8_t{0});
|
||||||
|
auto *const fake_runtime = reinterpret_cast<Runtime *>(code.data());
|
||||||
|
SetRuntimeDebugState(fake_runtime, RuntimeDebugState::kJavaDebuggable);
|
||||||
|
for (size_t i = 0; i < kLargeEnoughSizeForRuntime; ++i) {
|
||||||
|
if (*reinterpret_cast<RuntimeDebugState *>(
|
||||||
|
reinterpret_cast<uintptr_t>(fake_runtime) + i) ==
|
||||||
|
RuntimeDebugState::kJavaDebuggable) {
|
||||||
|
LOGD("found debug_state at offset %zu", i);
|
||||||
|
debug_state_offset = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (debug_state_offset == 0) {
|
||||||
|
LOGE("failed to find debug_state");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -274,7 +274,7 @@ bool InitNative(JNIEnv *env, const HookHandler &handler) {
|
|||||||
if (IsJavaDebuggable(env)) {
|
if (IsJavaDebuggable(env)) {
|
||||||
// Make the runtime non-debuggable as a workaround
|
// Make the runtime non-debuggable as a workaround
|
||||||
// when ShouldUseInterpreterEntrypoint inlined
|
// when ShouldUseInterpreterEntrypoint inlined
|
||||||
Runtime::Current()->SetJavaDebuggable(false);
|
Runtime::Current()->SetJavaDebuggable(Runtime::RuntimeDebugState::kNonJavaDebuggable);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -735,8 +735,13 @@ using ::lsplant::IsHooked;
|
|||||||
|
|
||||||
[[maybe_unused]] bool MakeDexFileTrusted(JNIEnv *env, jobject cookie) {
|
[[maybe_unused]] bool MakeDexFileTrusted(JNIEnv *env, jobject cookie) {
|
||||||
struct Guard {
|
struct Guard {
|
||||||
Guard() { Runtime::Current()->SetJavaDebuggable(true); }
|
Guard() {
|
||||||
~Guard() { Runtime::Current()->SetJavaDebuggable(false); }
|
Runtime::Current()->SetJavaDebuggable(
|
||||||
|
Runtime::RuntimeDebugState::kJavaDebuggableAtInit);
|
||||||
|
}
|
||||||
|
~Guard() {
|
||||||
|
Runtime::Current()->SetJavaDebuggable(Runtime::RuntimeDebugState::kNonJavaDebuggable);
|
||||||
|
}
|
||||||
} guard;
|
} guard;
|
||||||
if (!cookie) return false;
|
if (!cookie) return false;
|
||||||
return DexFile::SetTrusted(env, cookie);
|
return DexFile::SetTrusted(env, cookie);
|
||||||
|
@ -5,8 +5,8 @@ pluginManagement {
|
|||||||
mavenCentral()
|
mavenCentral()
|
||||||
}
|
}
|
||||||
plugins {
|
plugins {
|
||||||
id("com.android.application") version "7.2.1"
|
id("com.android.application") version "7.2.2"
|
||||||
id("com.android.library") version "7.2.1"
|
id("com.android.library") version "7.2.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
dependencyResolutionManagement {
|
dependencyResolutionManagement {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user