[core] use dex builder to generate resource dummy class (#215)

This commit is contained in:
LoveSy 2021-02-27 13:27:23 +08:00 committed by GitHub
parent 27d9fd0a70
commit cb5c9ea4d2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 59 additions and 20 deletions

@ -1 +1 @@
Subproject commit 360465c7c9f8fe6c81fdae17da6895be0884d9f1
Subproject commit 89988a43bd4bdcd2ed38bf7dc5ab2ea01f5e91df

View File

@ -20,6 +20,9 @@
#include <jni.h>
#include <resource_hook.h>
#include <dex_builder.h>
#include <art/runtime/thread.h>
#include <art/runtime/mirror/class.h>
#include "native_util.h"
#include "nativehelper/jni_macros.h"
#include "resources_hook.h"
@ -43,9 +46,34 @@ namespace lspd {
return JNI_FALSE;
}
LSP_DEF_NATIVE_METHOD(jobject, ResourcesHook, buildDummyClassLoader, jobject parent, jobject resource_super_class, jobject typed_array_super_class) {
using namespace startop::dex;
static auto in_memory_classloader = (jclass)env->NewGlobalRef(env->FindClass( "dalvik/system/InMemoryDexClassLoader"));
static jmethodID initMid = JNI_GetMethodID(env, in_memory_classloader, "<init>",
"(Ljava/nio/ByteBuffer;Ljava/lang/ClassLoader;)V");
DexBuilder dex_file;
std::string storage;
auto current_thread = art::Thread::Current();
ClassBuilder xresource_builder{
dex_file.MakeClass("xposed.dummy.XResourcesSuperClass")};
xresource_builder.setSuperClass(TypeDescriptor::FromDescriptor(art::mirror::Class(current_thread.DecodeJObject(resource_super_class)).GetDescriptor(&storage)));
ClassBuilder xtypearray_builder{
dex_file.MakeClass("xposed.dummy.XTypedArraySuperClass")};
xtypearray_builder.setSuperClass(TypeDescriptor::FromDescriptor(art::mirror::Class(current_thread.DecodeJObject(typed_array_super_class)).GetDescriptor(&storage)));
slicer::MemView image{dex_file.CreateImage()};
auto dex_buffer = env->NewDirectByteBuffer(const_cast<void*>(image.ptr()), image.size());
return JNI_NewObject(env, in_memory_classloader, initMid,
dex_buffer, parent);
}
static JNINativeMethod gMethods[] = {
LSP_NATIVE_METHOD(ResourcesHook, initXResourcesNative, "()Z"),
LSP_NATIVE_METHOD(ResourcesHook, removeFinalFlagNative, "(Ljava/lang/Class;)Z"),
LSP_NATIVE_METHOD(ResourcesHook, buildDummyClassLoader, "(Ljava/lang/ClassLoader;Ljava/lang/Class;Ljava/lang/Class;)Ljava/lang/ClassLoader;"),
};
void RegisterResourcesHook(JNIEnv *env) {

View File

@ -153,10 +153,8 @@ namespace lspd {
auto *back_method = backup_builder.Encode();
slicer::MemView image{dex_file.CreateImage()};
std::unique_ptr<char[]> buffer = std::make_unique<char[]>(image.size());
memcpy(buffer.get(), image.ptr(), image.size());
auto dex_buffer = env->NewDirectByteBuffer(buffer.get(), image.size());
auto dex_buffer = env->NewDirectByteBuffer(const_cast<void*>(image.ptr()), image.size());
jobject my_cl = JNI_NewObject(env, in_memory_classloader, initMid,
dex_buffer, app_class_loader);

View File

@ -49,6 +49,7 @@ import de.robv.android.xposed.callbacks.XC_LoadPackage;
import external.com.android.dx.DexMaker;
import external.com.android.dx.TypeId;
import io.github.lsposed.lspd.nativebridge.ModuleLogger;
import io.github.lsposed.lspd.nativebridge.ResourcesHook;
import static de.robv.android.xposed.XposedHelpers.setObjectField;
@ -97,8 +98,8 @@ public final class XposedBridge {
}
try {
Resources res = Resources.getSystem();
Class resClass = res.getClass();
Class taClass = TypedArray.class;
Class<?> resClass = res.getClass();
Class<?> taClass = TypedArray.class;
try {
TypedArray ta = res.obtainTypedArray(res.getIdentifier(
"preloaded_drawables", "array", "android"));
@ -109,16 +110,20 @@ public final class XposedBridge {
}
XposedBridge.removeFinalFlagNative(resClass);
XposedBridge.removeFinalFlagNative(taClass);
DexMaker dexMaker = new DexMaker();
dexMaker.declare(TypeId.get("Lxposed/dummy/XResourcesSuperClass;"),
"XResourcesSuperClass.java",
Modifier.PUBLIC, TypeId.get(resClass));
dexMaker.declare(TypeId.get("Lxposed/dummy/XTypedArraySuperClass;"),
"XTypedArraySuperClass.java",
Modifier.PUBLIC, TypeId.get(taClass));
ClassLoader myCL = XposedBridge.class.getClassLoader();
dummyClassLoader = new InMemoryDexClassLoader(
ByteBuffer.wrap(dexMaker.generate()), myCL.getParent());
dummyClassLoader = ResourcesHook.buildDummyClassLoader(myCL.getParent(), resClass, taClass);
if (dummyClassLoader == null) {
XposedBridge.log("Dexbuilder fails, fallback to dexmaker");
DexMaker dexMaker = new DexMaker();
dexMaker.declare(TypeId.get("Lxposed/dummy/XResourcesSuperClass;"),
"XResourcesSuperClass.java",
Modifier.PUBLIC, TypeId.get(resClass));
dexMaker.declare(TypeId.get("Lxposed/dummy/XTypedArraySuperClass;"),
"XTypedArraySuperClass.java",
Modifier.PUBLIC, TypeId.get(taClass));
dummyClassLoader = new InMemoryDexClassLoader(
ByteBuffer.wrap(dexMaker.generate()), myCL.getParent());
}
dummyClassLoader.loadClass("xposed.dummy.XResourcesSuperClass");
dummyClassLoader.loadClass("xposed.dummy.XTypedArraySuperClass");
setObjectField(myCL, "parent", dummyClassLoader);

View File

@ -142,13 +142,12 @@ public final class XposedInit {
final ThreadLocal<Object> latestResKey = new ThreadLocal<>();
final String createResourceMethod;
classGTLR = android.app.ResourcesManager.class;
classResKey = android.content.res.ResourcesKey.class;
if (Build.VERSION.SDK_INT < 30) {
classGTLR = Class.forName("android.app.ResourcesManager");
classResKey = Class.forName("android.content.res.ResourcesKey");
createResourceMethod = "getOrCreateResources";
} else {
classGTLR = Class.forName("android.app.ResourcesManager");
classResKey = Class.forName("android.content.res.ResourcesKey");
createResourceMethod = "createResources";
}

View File

@ -24,6 +24,7 @@ public class ResourcesHook {
public static native boolean initXResourcesNative();
public static native boolean removeFinalFlagNative(Class clazz);
public static native boolean removeFinalFlagNative(Class<?> clazz);
public static native ClassLoader buildDummyClassLoader(ClassLoader parent, Class<?> resourceSuperClass, Class<?> typedArraySuperClass);
}

View File

@ -0,0 +1,4 @@
package android.app;
public class ResourcesManager {
}

View File

@ -0,0 +1,4 @@
package android.content.res;
public class ResourcesKey {
}