diff --git a/lsplant/src/main/jni/lsplant.cc b/lsplant/src/main/jni/lsplant.cc index e87f9e55b..f869d5741 100644 --- a/lsplant/src/main/jni/lsplant.cc +++ b/lsplant/src/main/jni/lsplant.cc @@ -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; @@ -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; @@ -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, "", - "(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, "", + 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, "", "(Ljava/lang/String;Ljava/lang/ClassLoader;)V"); - if (!path_class_loader_init) { - LOGE("Failed to find PathClassLoader."); - 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."); + 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, "", + "([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, "", "([Ljava/nio/ByteBuffer;)V"); + } + if (sdk_int >= __ANDROID_API_O__ && !dex_file_init_with_cl && !dex_file_init) { + LOGE("Failed to find DexFile."); + 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; } @@ -370,7 +374,6 @@ std::tuple BuildDex(JNIEnv *env, jobject auto parameter_types = std::vector(); 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 @@ -447,21 +450,21 @@ std::tuple BuildDex(JNIEnv *env, jobject jclass target_class = nullptr; - if (in_memory_class_loader_init) [[likely]] { - auto dex_buffer = JNI_NewDirectByteBuffer(env, const_cast(image.ptr()), - static_cast(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(JNI_CallObjectMethod( - env, my_cl, load_class, - JNI_NewStringUTF(env, generated_class_name.data()))) - .release(); - } + ScopedLocalRef 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(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(image.ptr()), image.size()))); } else { void *target = mmap(nullptr, image.size(), PROT_WRITE | PROT_READ, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); @@ -473,17 +476,20 @@ std::tuple 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( - 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( + JNI_CallObjectMethod(env, java_dex_file, load_class, + JNI_NewStringUTF(env, generated_class_name.data()), my_cl)) + .release(); } if (target_class) {