Skip to content

Commit

Permalink
Avoid using too much java debuggable guard
Browse files Browse the repository at this point in the history
  • Loading branch information
yujincheng08 committed Oct 11, 2023
1 parent 899766f commit 801f739
Showing 1 changed file with 60 additions and 54 deletions.
114 changes: 60 additions & 54 deletions lsplant/src/main/jni/lsplant.cc
Original file line number Diff line number Diff line change
Expand Up @@ -85,8 +85,8 @@ jmethodID class_get_name = nullptr;
jmethodID class_get_class_loader = nullptr;
jmethodID class_get_declared_constructors = nullptr;
jfieldID class_access_flags = nullptr;
jclass in_memory_class_loader = nullptr;
jmethodID in_memory_class_loader_init = nullptr;
jmethodID dex_file_init_with_cl = nullptr;
jmethodID dex_file_init = nullptr;
jmethodID load_class = nullptr;
jmethodID set_accessible = nullptr;
jclass executable = nullptr;
Expand All @@ -95,12 +95,11 @@ jclass executable = nullptr;
jmethodID method_get_parameter_types = nullptr;
jmethodID method_get_return_type = nullptr;
// for old platform
jclass path_class_loader = nullptr;
jmethodID path_class_loader_init = nullptr;

constexpr auto kInternalMethods = std::make_tuple(
&method_get_name, &method_get_declaring_class, &class_get_name, &class_get_class_loader,
&class_get_declared_constructors, &in_memory_class_loader_init, &load_class, &set_accessible,
&class_get_declared_constructors, &dex_file_init, &load_class, &set_accessible,
&method_get_parameter_types, &method_get_return_type, &path_class_loader_init);

std::string generated_class_name;
Expand Down Expand Up @@ -194,32 +193,37 @@ bool InitJNI(JNIEnv *env) {
LOGE("Failed to find Class.accessFlags");
return false;
}
if (sdk_int >= __ANDROID_API_O__ &&
(in_memory_class_loader = JNI_NewGlobalRef(
env, JNI_FindClass(env, "dalvik/system/InMemoryDexClassLoader")))) [[likely]] {
in_memory_class_loader_init =
JNI_GetMethodID(env, in_memory_class_loader, "<init>",
"(Ljava/nio/ByteBuffer;Ljava/lang/ClassLoader;)V");
load_class = JNI_GetMethodID(env, in_memory_class_loader, "loadClass",
"(Ljava/lang/String;)Ljava/lang/Class;");
if (!load_class) {
load_class = JNI_GetMethodID(env, in_memory_class_loader, "findClass",
"(Ljava/lang/String;)Ljava/lang/Class;");
}
} else if (auto dex_file = JNI_FindClass(env, "dalvik/system/DexFile");
dex_file && (path_class_loader = JNI_NewGlobalRef(
env, JNI_FindClass(env, "dalvik/system/PathClassLoader")))) {
path_class_loader_init = JNI_GetMethodID(env, path_class_loader, "<init>",
auto path_class_loader = JNI_FindClass(env, "dalvik/system/PathClassLoader");
if (!path_class_loader) {
LOGE("Failed to find PathClassLoader");
return false;
}
if (path_class_loader_init = JNI_GetMethodID(env, path_class_loader, "<init>",
"(Ljava/lang/String;Ljava/lang/ClassLoader;)V");
if (!path_class_loader_init) {
LOGE("Failed to find PathClassLoader.<init>");
return false;
}
load_class =
JNI_GetMethodID(env, dex_file, "loadClass",
"(Ljava/lang/String;Ljava/lang/ClassLoader;)Ljava/lang/Class;");
!path_class_loader_init) {
LOGE("Failed to find PathClassLoader.<init>");
return false;
}
auto dex_file_class = JNI_FindClass(env, "dalvik/system/DexFile");
if (!dex_file_class) {
LOGE("Failed to find DexFile");
return false;
}
if (!load_class) {
if (sdk_int >= __ANDROID_API_Q__) {
dex_file_init_with_cl = JNI_GetMethodID(
env, dex_file_class, "<init>",
"([Ljava/nio/ByteBuffer;Ljava/lang/ClassLoader;[Ldalvik/system/DexPathList$Element;)V");
} else if (sdk_int >= __ANDROID_API_O__) {
dex_file_init = JNI_GetMethodID(env, dex_file_class, "<init>", "([Ljava/nio/ByteBuffer;)V");
}
if (sdk_int >= __ANDROID_API_O__ && !dex_file_init_with_cl && !dex_file_init) {
LOGE("Failed to find DexFile.<init>");
return false;
}
if (load_class =
JNI_GetMethodID(env, dex_file_class, "loadClass",
"(Ljava/lang/String;Ljava/lang/ClassLoader;)Ljava/lang/Class;");
!load_class) {
LOGE("Failed to find a suitable way to load class");
return false;
}
Expand Down Expand Up @@ -370,7 +374,6 @@ std::tuple<jclass, jfieldID, jmethodID, jmethodID> BuildDex(JNIEnv *env, jobject

auto parameter_types = std::vector<TypeDescriptor>();
parameter_types.reserve(shorty.size() - 1);
std::string storage;
auto return_type =
shorty[0] == 'L' ? TypeDescriptor::Object : TypeDescriptor::FromDescriptor(shorty[0]);
if (!is_static) parameter_types.push_back(TypeDescriptor::Object); // this object
Expand Down Expand Up @@ -447,21 +450,21 @@ std::tuple<jclass, jfieldID, jmethodID, jmethodID> BuildDex(JNIEnv *env, jobject

jclass target_class = nullptr;

if (in_memory_class_loader_init) [[likely]] {
auto dex_buffer = JNI_NewDirectByteBuffer(env, const_cast<void *>(image.ptr()),
static_cast<jlong>(image.size()));
// 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;

auto 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<jclass>(JNI_CallObjectMethod(
env, my_cl, load_class,
JNI_NewStringUTF(env, generated_class_name.data())))
.release();
}
ScopedLocalRef<jobject> java_dex_file{nullptr};

if (auto dex_file_class = JNI_FindClass(env, "dalvik/system/DexFile"); dex_file_init_with_cl) {
java_dex_file = JNI_NewObject(
env, dex_file_class, dex_file_init_with_cl,
JNI_NewObjectArray(
env, 1, JNI_FindClass(env, "java/nio/ByteBuffer"),
JNI_NewDirectByteBuffer(env, const_cast<void *>(image.ptr()), image.size())),
nullptr, nullptr);
} else if (dex_file_init) {
java_dex_file = JNI_NewObject(
env, dex_file_class, dex_file_init,
JNI_NewObjectArray(
env, 1, JNI_FindClass(env, "java/nio/ByteBuffer"),
JNI_NewDirectByteBuffer(env, const_cast<void *>(image.ptr()), image.size())));
} else {
void *target =
mmap(nullptr, image.size(), PROT_WRITE | PROT_READ, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
Expand All @@ -473,17 +476,20 @@ std::tuple<jclass, jfieldID, jmethodID, jmethodID> BuildDex(JNIEnv *env, jobject
&err_msg);
if (!dex) {
LOGE("Failed to open memory dex: %s", err_msg.data());
} else {
java_dex_file = WrapScope(env, dex ? dex->ToJavaDexFile(env) : jobject{nullptr});
}
auto java_dex_file = WrapScope(env, dex ? dex->ToJavaDexFile(env) : jobject{nullptr});
if (dex && java_dex_file) {
auto my_cl = JNI_NewObject(env, path_class_loader, path_class_loader_init,
JNI_NewStringUTF(env, ""), class_loader);
target_class =
JNI_Cast<jclass>(
JNI_CallObjectMethod(env, java_dex_file, load_class,
JNI_NewStringUTF(env, generated_class_name.data()), my_cl))
.release();
}
}

if (auto path_class_loader = JNI_FindClass(env, "dalvik/system/PathClassLoader");
java_dex_file) {
auto my_cl = JNI_NewObject(env, path_class_loader, path_class_loader_init,
JNI_NewStringUTF(env, ""), class_loader);
target_class =
JNI_Cast<jclass>(
JNI_CallObjectMethod(env, java_dex_file, load_class,
JNI_NewStringUTF(env, generated_class_name.data()), my_cl))
.release();
}

if (target_class) {
Expand Down

0 comments on commit 801f739

Please sign in to comment.