From efa42a4eb0109c73dcc61c6625c6bfc1800f910e Mon Sep 17 00:00:00 2001 From: LoveSy Date: Fri, 28 May 2021 19:58:01 +0800 Subject: [PATCH] [core] Remove isSamePackage hook (#690) --- core/src/main/cpp/external/DexBuilder | 2 +- .../cpp/external/yahfa/include/HookMain.h | 9 + .../cpp/external/yahfa/include/trampoline.h | 6 - .../main/cpp/external/yahfa/src/HookMain.cpp | 212 +++++++++--------- .../main/cpp/external/yahfa/src/trampoline.c | 36 +-- .../main/include/art/runtime/mirror/class.h | 26 --- .../main/cpp/main/src/jni/resources_hook.cpp | 21 +- core/src/main/cpp/main/src/jni/yahfa.cpp | 25 +-- .../de/robv/android/xposed/XposedBridge.java | 4 +- .../lspd/nativebridge/ResourcesHook.java | 4 +- .../org/lsposed/lspd/nativebridge/Yahfa.java | 2 +- .../lspd/yahfa/dexmaker/HookerDexMaker.java | 38 +++- 12 files changed, 188 insertions(+), 197 deletions(-) diff --git a/core/src/main/cpp/external/DexBuilder b/core/src/main/cpp/external/DexBuilder index 5c1ccd55..41b91718 160000 --- a/core/src/main/cpp/external/DexBuilder +++ b/core/src/main/cpp/external/DexBuilder @@ -1 +1 @@ -Subproject commit 5c1ccd55836e4bf43cdb6adbad40443d18cd43db +Subproject commit 41b9171852840cb421d8be22ef73d9467db02799 diff --git a/core/src/main/cpp/external/yahfa/include/HookMain.h b/core/src/main/cpp/external/yahfa/include/HookMain.h index fd7e5db7..4e0b77f1 100644 --- a/core/src/main/cpp/external/yahfa/include/HookMain.h +++ b/core/src/main/cpp/external/yahfa/include/HookMain.h @@ -4,6 +4,11 @@ #include namespace yahfa { + constexpr uint32_t kAccPublic = 0x0001; // class, field, method, ic + constexpr uint32_t kAccPrivate = 0x0002; // field, method, ic + constexpr uint32_t kAccProtected = 0x0004; // field, method, ic + constexpr uint32_t kAccStatic = 0x0008; // field, method, ic + void init(JNIEnv *env, jclass clazz, jint sdkVersion); jobject findMethodNative(JNIEnv *env, jclass clazz, @@ -15,6 +20,10 @@ namespace yahfa { jobject backup); void *getArtMethod(JNIEnv *env, jobject jmethod); + + uint32_t getAccessFlags(void* art_method); + + void setAccessFlags(void* art_method, uint32_t access_flags); } #endif // HOOK_MAIN_H diff --git a/core/src/main/cpp/external/yahfa/include/trampoline.h b/core/src/main/cpp/external/yahfa/include/trampoline.h index 5c18d939..75c34a28 100644 --- a/core/src/main/cpp/external/yahfa/include/trampoline.h +++ b/core/src/main/cpp/external/yahfa/include/trampoline.h @@ -10,16 +10,10 @@ extern "C" { extern int SDKVersion; extern size_t OFFSET_entry_point_from_quick_compiled_code_in_ArtMethod; -extern unsigned int hookCap; // capacity for trampolines -extern unsigned int hookCount; // current count of used trampolines - extern unsigned char trampoline[]; -int doInitHookCap(unsigned int cap); void setupTrampoline(); void *genTrampoline(void *hookMethod); - -#define DEFAULT_CAP 1 //size of each trampoline area would be no more than 4k Bytes(one page) #ifdef __cplusplus } #endif diff --git a/core/src/main/cpp/external/yahfa/src/HookMain.cpp b/core/src/main/cpp/external/yahfa/src/HookMain.cpp index 6ee5ee88..c31cf9a4 100644 --- a/core/src/main/cpp/external/yahfa/src/HookMain.cpp +++ b/core/src/main/cpp/external/yahfa/src/HookMain.cpp @@ -9,115 +9,103 @@ int SDKVersion; size_t OFFSET_entry_point_from_quick_compiled_code_in_ArtMethod; -namespace { - constexpr size_t OFFSET_access_flags_in_ArtMethod = 4; - constexpr uint32_t kAccCompileDontBother = 0x02000000; - constexpr uint32_t kAccPublic = 0x0001; // class, field, method, ic - constexpr uint32_t kAccPrivate = 0x0002; // field, method, ic - constexpr uint32_t kAccProtected = 0x0004; // field, method, ic - constexpr uint32_t kAccStatic = 0x0008; // field, method, ic - constexpr uint32_t kAccFastInterpreterToInterpreterInvoke = 0x40000000; - - size_t ArtMethodSize; - uint32_t kAccPreCompiled = 0x00200000; - - jfieldID fieldArtMethod = nullptr; - - constexpr inline uint32_t read32(void *addr) { - return *((uint32_t *) addr); - } - - constexpr inline void write32(void *addr, uint32_t value) { - *((uint32_t *) addr) = value; - } - - constexpr inline void *readAddr(void *addr) { - return *((void **) addr); - } - - constexpr inline void writeAddr(void *addr, void *value) { - *((void **) addr) = value; - } - - void setNonCompilable(void *method) { - uint32_t access_flags = read32((char *) method + OFFSET_access_flags_in_ArtMethod); - LOGI("setNonCompilable: access flags is 0x%x", access_flags); - access_flags |= kAccCompileDontBother; - if (SDKVersion >= __ANDROID_API_R__) - access_flags &= ~kAccPreCompiled; - write32((char *) method + OFFSET_access_flags_in_ArtMethod, access_flags); - } - - void setPrivate(void *method) { - uint32_t access_flags = read32((char *) method + OFFSET_access_flags_in_ArtMethod); - if (!(access_flags & kAccStatic)) { - LOGI("setPrivate: access flags is 0x%x", access_flags); - access_flags |= kAccPrivate; - access_flags &= ~kAccProtected; - access_flags &= ~kAccPublic; - write32((char *) method + OFFSET_access_flags_in_ArtMethod, access_flags); - } - } - - int doBackupAndHook(void *targetMethod, void *hookMethod, void *backupMethod) { - if (hookCount >= hookCap) { - LOGI("not enough capacity. Allocating..."); - if (doInitHookCap(DEFAULT_CAP)) { - LOGE("cannot hook method"); - return 1; - } - LOGI("Allocating done"); - } - - LOGI("target method is at %p, hook method is at %p, backup method is at %p", - targetMethod, hookMethod, backupMethod); - - - // set kAccCompileDontBother for a method we do not want the compiler to compile - // so that we don't need to worry about hotness_count_ - setNonCompilable(targetMethod); - setNonCompilable(hookMethod); - - if (backupMethod) {// do method backup - // have to copy the whole target ArtMethod here - // if the target method calls other methods which are to be resolved - // then ToDexPC would be invoked for the caller(origin method) - // in which case ToDexPC would use the entrypoint as a base for mapping pc to dex offset - // so any changes to the target method's entrypoint would result in a wrong dex offset - // and artQuickResolutionTrampoline would fail for methods called by the origin method - memcpy(backupMethod, targetMethod, ArtMethodSize); - setPrivate(backupMethod); - } - - // replace entry point - void *newEntrypoint = genTrampoline(hookMethod); - LOGI("origin ep is %p, new ep is %p", - readAddr((char *) targetMethod + OFFSET_entry_point_from_quick_compiled_code_in_ArtMethod), - newEntrypoint - ); - if (newEntrypoint) { - writeAddr((char *) targetMethod + OFFSET_entry_point_from_quick_compiled_code_in_ArtMethod, - newEntrypoint); - } else { - LOGE("failed to allocate space for trampoline of target method"); - return 1; - } - - if (SDKVersion >= __ANDROID_API_Q__) { - uint32_t access_flags = read32((char *) targetMethod + OFFSET_access_flags_in_ArtMethod); - // On API 29 whether to use the fast path or not is cached in the ART method structure - access_flags &= ~kAccFastInterpreterToInterpreterInvoke; - write32((char *) targetMethod + OFFSET_access_flags_in_ArtMethod, access_flags); - } - - LOGI("hook and backup done"); - hookCount += 1; - return 0; - } - -} namespace yahfa { + namespace { + constexpr size_t OFFSET_access_flags_in_ArtMethod = 4; + constexpr uint32_t kAccCompileDontBother = 0x02000000; + constexpr uint32_t kAccFastInterpreterToInterpreterInvoke = 0x40000000; + + size_t ArtMethodSize; + uint32_t kAccPreCompiled = 0x00200000; + + jfieldID fieldArtMethod = nullptr; + + constexpr inline uint32_t read32(void *addr) { + return *((uint32_t *) addr); + } + + constexpr inline void write32(void *addr, uint32_t value) { + *((uint32_t *) addr) = value; + } + + constexpr inline void *readAddr(void *addr) { + return *((void **) addr); + } + + constexpr inline void writeAddr(void *addr, void *value) { + *((void **) addr) = value; + } + + void setNonCompilable(void *method) { + uint32_t access_flags = getAccessFlags(method); + LOGI("setNonCompilable: access flags is 0x%x", access_flags); + access_flags |= kAccCompileDontBother; + if (SDKVersion >= __ANDROID_API_R__) + access_flags &= ~kAccPreCompiled; + setAccessFlags(method, access_flags); + } + + void setPrivate(void *method) { + uint32_t access_flags = getAccessFlags(method); + if (!(access_flags & kAccStatic)) { + LOGI("setPrivate: access flags is 0x%x", access_flags); + access_flags |= kAccPrivate; + access_flags &= ~kAccProtected; + access_flags &= ~kAccPublic; + setAccessFlags(method, access_flags); + } + } + + int doBackupAndHook(void *targetMethod, void *hookMethod, void *backupMethod) { + LOGI("target method is at %p, hook method is at %p, backup method is at %p", + targetMethod, hookMethod, backupMethod); + + + // set kAccCompileDontBother for a method we do not want the compiler to compile + // so that we don't need to worry about hotness_count_ + setNonCompilable(targetMethod); + setNonCompilable(hookMethod); + + if (backupMethod) {// do method backup + // have to copy the whole target ArtMethod here + // if the target method calls other methods which are to be resolved + // then ToDexPC would be invoked for the caller(origin method) + // in which case ToDexPC would use the entrypoint as a base for mapping pc to dex offset + // so any changes to the target method's entrypoint would result in a wrong dex offset + // and artQuickResolutionTrampoline would fail for methods called by the origin method + memcpy(backupMethod, targetMethod, ArtMethodSize); + setPrivate(backupMethod); + } + + // replace entry point + void *newEntrypoint = genTrampoline(hookMethod); + LOGI("origin ep is %p, new ep is %p", + readAddr((char *) targetMethod + + OFFSET_entry_point_from_quick_compiled_code_in_ArtMethod), + newEntrypoint + ); + if (newEntrypoint) { + writeAddr((char *) targetMethod + + OFFSET_entry_point_from_quick_compiled_code_in_ArtMethod, + newEntrypoint); + } else { + LOGE("failed to allocate space for trampoline of target method"); + return 1; + } + + if (SDKVersion >= __ANDROID_API_Q__) { + uint32_t access_flags = getAccessFlags(targetMethod); + // On API 29 whether to use the fast path or not is cached in the ART method structure + access_flags &= ~kAccFastInterpreterToInterpreterInvoke; + setAccessFlags(targetMethod, access_flags); + } + + LOGI("hook and backup done"); + return 0; + } + + } void init(JNIEnv *env, [[maybe_unused]] jclass clazz, jint sdkVersion) { SDKVersion = sdkVersion; @@ -160,6 +148,16 @@ namespace yahfa { } } + uint32_t getAccessFlags(void *art_method) { + + return read32((char *) art_method + OFFSET_access_flags_in_ArtMethod); + // On API 29 whether to use the fast path or not is cached in the ART method structure + } + + void setAccessFlags(void *art_method, uint32_t access_flags) { + write32((char *) art_method + OFFSET_access_flags_in_ArtMethod, access_flags); + } + jobject findMethodNative(JNIEnv *env, [[maybe_unused]] jclass clazz, jclass targetClass, jstring methodName, diff --git a/core/src/main/cpp/external/yahfa/src/trampoline.c b/core/src/main/cpp/external/yahfa/src/trampoline.c index 3731d51f..6829c786 100644 --- a/core/src/main/cpp/external/yahfa/src/trampoline.c +++ b/core/src/main/cpp/external/yahfa/src/trampoline.c @@ -14,12 +14,6 @@ #include "common.h" #include "trampoline.h" -static unsigned char *trampolineCode; // place where trampolines are saved -static unsigned int trampolineSize; // trampoline size required for each hook - -unsigned int hookCap = 0; -unsigned int hookCount = 0; - // trampoline: // 1. set eax/r0/x0 to the hook ArtMethod addr // 2. jump into its entry point @@ -74,9 +68,12 @@ static inline void FlushCache(void *addr, size_t size) { } void *genTrampoline(void *hookMethod) { - void *targetAddr; - - targetAddr = trampolineCode + trampolineSize * hookCount; + unsigned char *targetAddr = mmap(NULL, trampolineSize, PROT_READ | PROT_WRITE | PROT_EXEC, + MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); + if (targetAddr == MAP_FAILED) { + LOGE("mmap failed, errno = %s", strerror(errno)); + return NULL; + } memcpy(targetAddr, trampoline, sizeof(trampoline)); // do not use trampolineSize since it's a rounded size @@ -117,24 +114,3 @@ void setupTrampoline() { #error Unsupported architecture #endif } - -int doInitHookCap(unsigned int cap) { - if (cap == 0) { - LOGE("invalid capacity: %d", cap); - return 1; - } - if (hookCap) { - LOGI("allocating new space for trampoline code"); - } - unsigned int allSize = trampolineSize * cap; - unsigned char *buf = mmap(NULL, allSize, PROT_READ | PROT_WRITE | PROT_EXEC, - MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); - if (buf == MAP_FAILED) { - LOGE("mmap failed, errno = %s", strerror(errno)); - return 1; - } - hookCap = cap; - hookCount = 0; - trampolineCode = buf; - return 0; -} diff --git a/core/src/main/cpp/main/include/art/runtime/mirror/class.h b/core/src/main/cpp/main/include/art/runtime/mirror/class.h index 4712e8fe..b7871d6a 100644 --- a/core/src/main/cpp/main/include/art/runtime/mirror/class.h +++ b/core/src/main/cpp/main/include/art/runtime/mirror/class.h @@ -41,29 +41,6 @@ namespace art { return ""; } - CREATE_MEM_HOOK_STUB_ENTRIES("_ZN3art6mirror5Class15IsInSamePackageENS_6ObjPtrIS1_EE", - bool, IsInSamePackage, (void *thiz, void* that), { - std::string storage1; - std::string storage2; - const char *thisDesc = GetDescriptor(thiz, &storage1); - const char *thatDesc = GetDescriptor(that, &storage2); - // Note: these identifiers should be consistent with those in Java layer - if (strstr(thisDesc, "LspHooker_") != nullptr - || strstr(thatDesc, "LspHooker_") != nullptr - || strstr(thisDesc, "org/lsposed/") != nullptr - || strstr(thatDesc, "org/lsposed/") != nullptr) { - return true; - } - // for MIUI resources hooking - if (strstr(thisDesc, "android/content/res/MiuiTypedArray") != nullptr - || strstr(thatDesc, "android/content/res/MiuiTypedArray") != nullptr - || strstr(thisDesc, "android/content/res/XResources$XTypedArray") != nullptr - || strstr(thatDesc, "android/content/res/XResources$XTypedArray") != nullptr) { - return true; - } - return backup(thiz, that); - }); - CREATE_MEM_FUNC_SYMBOL_ENTRY(void*, GetClassDef, void* thiz) { if (LIKELY(GetClassDefSym)) return GetClassDefSym(thiz); @@ -77,10 +54,7 @@ namespace art { static void Setup(void *handle) { RETRIEVE_MEM_FUNC_SYMBOL(GetDescriptor, "_ZN3art6mirror5Class13GetDescriptorEPNSt3__112" "basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEE"); - RETRIEVE_MEM_FUNC_SYMBOL(GetClassDef, "_ZN3art6mirror5Class11GetClassDefEv"); - - lspd::HookSyms(handle, IsInSamePackage); } const char *GetDescriptor(std::string *storage) { diff --git a/core/src/main/cpp/main/src/jni/resources_hook.cpp b/core/src/main/cpp/main/src/jni/resources_hook.cpp index 828cbe8c..75f56164 100644 --- a/core/src/main/cpp/main/src/jni/resources_hook.cpp +++ b/core/src/main/cpp/main/src/jni/resources_hook.cpp @@ -25,6 +25,7 @@ #include #include #include +#include #include "native_util.h" #include "resources_hook.h" @@ -95,13 +96,24 @@ namespace lspd { } // @ApiSensitive(Level.MIDDLE) - LSP_DEF_NATIVE_METHOD(jboolean, ResourcesHook, removeFinalFlagNative, jclass target_class) { + LSP_DEF_NATIVE_METHOD(jboolean, ResourcesHook, makeInheritable, jclass target_class, + jobjectArray constructors) { if (target_class) { - auto class_clazz = JNI_FindClass(env, "java/lang/Class"); - jfieldID java_lang_Class_accessFlags = JNI_GetFieldID( + static auto class_clazz = JNI_NewGlobalRef(env, JNI_FindClass(env, "java/lang/Class")); + static jfieldID java_lang_Class_accessFlags = JNI_GetFieldID( env, class_clazz, "accessFlags", "I"); jint access_flags = env->GetIntField(target_class, java_lang_Class_accessFlags); env->SetIntField(target_class, java_lang_Class_accessFlags, access_flags & ~kAccFinal); + for (auto i = 0u; i < env->GetArrayLength(constructors); ++i) { + auto constructor = env->GetObjectArrayElement(constructors, i); + void *method = yahfa::getArtMethod(env, constructor); + uint32_t flags = yahfa::getAccessFlags(method); + if ((flags & yahfa::kAccPublic) == 0 && (flags & yahfa::kAccProtected) == 0) { + flags |= yahfa::kAccProtected; + flags &= ~yahfa::kAccPrivate; + } + yahfa::setAccessFlags(method, flags); + } return JNI_TRUE; } return JNI_FALSE; @@ -208,7 +220,8 @@ namespace lspd { static JNINativeMethod gMethods[] = { LSP_NATIVE_METHOD(ResourcesHook, initXResourcesNative, "()Z"), - LSP_NATIVE_METHOD(ResourcesHook, removeFinalFlagNative, "(Ljava/lang/Class;)Z"), + LSP_NATIVE_METHOD(ResourcesHook, makeInheritable, + "(Ljava/lang/Class;[Ljava/lang/reflect/Constructor;)Z"), LSP_NATIVE_METHOD(ResourcesHook, buildDummyClassLoader, "(Ljava/lang/ClassLoader;Ljava/lang/Class;Ljava/lang/Class;)Ljava/lang/ClassLoader;"), LSP_NATIVE_METHOD(ResourcesHook, rewriteXmlReferencesNative, diff --git a/core/src/main/cpp/main/src/jni/yahfa.cpp b/core/src/main/cpp/main/src/jni/yahfa.cpp index 0bdecb9b..02b14326 100644 --- a/core/src/main/cpp/main/src/jni/yahfa.cpp +++ b/core/src/main/cpp/main/src/jni/yahfa.cpp @@ -58,8 +58,8 @@ namespace lspd { return lspd::isHooked(yahfa::getArtMethod(env, member)); } - LSP_DEF_NATIVE_METHOD(jclass, Yahfa, buildHooker, jobject app_class_loader, jclass return_class, - jobjectArray classes, jstring method_name) { + LSP_DEF_NATIVE_METHOD(jclass, Yahfa, buildHooker, jobject app_class_loader, jchar return_class, + jcharArray classes, jstring method_name) { static auto in_memory_classloader = JNI_NewGlobalRef(env, JNI_FindClass(env, "dalvik/system/InMemoryDexClassLoader")); static jmethodID initMid = JNI_GetMethodID(env, in_memory_classloader, "", @@ -70,15 +70,14 @@ namespace lspd { auto parameter_types = std::vector(); parameter_types.reserve(parameter_length); std::string storage; - auto current_thread = art::Thread::Current(); - auto return_type = TypeDescriptor::FromDescriptor( - art::mirror::Class(current_thread.DecodeJObject(return_class)).GetDescriptor( - &storage)); + auto return_type = + return_class == 'L' ? TypeDescriptor::Object : TypeDescriptor::FromDescriptor( + (char) return_class); + auto params = env->GetCharArrayElements(classes, nullptr); for (int i = 0; i < parameter_length; ++i) { - auto param = (jclass) env->GetObjectArrayElement(classes, i); - auto *param_ref = current_thread.DecodeJObject(param); - auto descriptor = art::mirror::Class(param_ref).GetDescriptor(&storage); - parameter_types.push_back(TypeDescriptor::FromDescriptor(descriptor)); + parameter_types.push_back( + params[i] == 'L' ? TypeDescriptor::Object : TypeDescriptor::FromDescriptor( + (char) params[i])); } ClassBuilder cbuilder{dex_file.MakeClass("LspHooker_")}; @@ -136,7 +135,7 @@ namespace lspd { Instruction::Cast(tmp, Value::Type(type_def->orig_index))); hookBuilder.BuildReturn(tmp, true); } - auto *hook_method = hookBuilder.Encode(); + [[maybe_unused]] auto *hook_method = hookBuilder.Encode(); auto backup_builder{ cbuilder.CreateMethod("backup", Prototype{return_type, parameter_types})}; @@ -153,7 +152,7 @@ namespace lspd { backup_builder.BuildConst(zero, 0); backup_builder.BuildReturn(zero, /*is_object=*/!return_type.is_primitive(), false); } - auto *back_method = backup_builder.Encode(); + [[maybe_unused]] auto *back_method = backup_builder.Encode(); slicer::MemView image{dex_file.CreateImage()}; @@ -185,7 +184,7 @@ namespace lspd { LSP_NATIVE_METHOD(Yahfa, recordHooked, "(Ljava/lang/reflect/Executable;)V"), LSP_NATIVE_METHOD(Yahfa, isHooked, "(Ljava/lang/reflect/Executable;)Z"), LSP_NATIVE_METHOD(Yahfa, buildHooker, - "(Ljava/lang/ClassLoader;Ljava/lang/Class;[Ljava/lang/Class;Ljava/lang/String;)Ljava/lang/Class;"), + "(Ljava/lang/ClassLoader;C[CLjava/lang/String;)Ljava/lang/Class;"), }; void RegisterYahfa(JNIEnv *env) { diff --git a/core/src/main/java/de/robv/android/xposed/XposedBridge.java b/core/src/main/java/de/robv/android/xposed/XposedBridge.java index 84e02c5c..cb4a9edd 100644 --- a/core/src/main/java/de/robv/android/xposed/XposedBridge.java +++ b/core/src/main/java/de/robv/android/xposed/XposedBridge.java @@ -103,8 +103,8 @@ public final class XposedBridge { } catch (Resources.NotFoundException nfe) { XposedBridge.log(nfe); } - ResourcesHook.removeFinalFlagNative(resClass); - ResourcesHook.removeFinalFlagNative(taClass); + ResourcesHook.makeInheritable(resClass, resClass.getDeclaredConstructors()); + ResourcesHook.makeInheritable(taClass, taClass.getDeclaredConstructors()); ClassLoader myCL = XposedBridge.class.getClassLoader(); dummyClassLoader = ResourcesHook.buildDummyClassLoader(myCL.getParent(), resClass, taClass); dummyClassLoader.loadClass("xposed.dummy.XResourcesSuperClass"); diff --git a/core/src/main/java/org/lsposed/lspd/nativebridge/ResourcesHook.java b/core/src/main/java/org/lsposed/lspd/nativebridge/ResourcesHook.java index 34f4c319..ac444e5a 100644 --- a/core/src/main/java/org/lsposed/lspd/nativebridge/ResourcesHook.java +++ b/core/src/main/java/org/lsposed/lspd/nativebridge/ResourcesHook.java @@ -23,11 +23,13 @@ package org.lsposed.lspd.nativebridge; import android.content.res.Resources; import android.content.res.XResources; +import java.lang.reflect.Constructor; + public class ResourcesHook { public static native boolean initXResourcesNative(); - public static native boolean removeFinalFlagNative(Class clazz); + public static native boolean makeInheritable(Class clazz, Constructor[] constructors); public static native ClassLoader buildDummyClassLoader(ClassLoader parent, Class resourceSuperClass, Class typedArraySuperClass); diff --git a/core/src/main/java/org/lsposed/lspd/nativebridge/Yahfa.java b/core/src/main/java/org/lsposed/lspd/nativebridge/Yahfa.java index adfea0d5..4105f2f4 100644 --- a/core/src/main/java/org/lsposed/lspd/nativebridge/Yahfa.java +++ b/core/src/main/java/org/lsposed/lspd/nativebridge/Yahfa.java @@ -36,5 +36,5 @@ public class Yahfa { public static native boolean isHooked(Executable member); - public static native Class buildHooker(ClassLoader appClassLoader, Class returnType, Class[] params, String methodName); + public static native Class buildHooker(ClassLoader appClassLoader, char returnType, char[] params, String methodName); } diff --git a/core/src/main/java/org/lsposed/lspd/yahfa/dexmaker/HookerDexMaker.java b/core/src/main/java/org/lsposed/lspd/yahfa/dexmaker/HookerDexMaker.java index 0639ff47..3c910d43 100644 --- a/core/src/main/java/org/lsposed/lspd/yahfa/dexmaker/HookerDexMaker.java +++ b/core/src/main/java/org/lsposed/lspd/yahfa/dexmaker/HookerDexMaker.java @@ -29,6 +29,7 @@ import java.lang.reflect.Constructor; import java.lang.reflect.Executable; import java.lang.reflect.Method; import java.lang.reflect.Modifier; +import java.util.HashMap; import de.robv.android.xposed.LspHooker; import de.robv.android.xposed.XposedBridge; @@ -38,6 +39,18 @@ public class HookerDexMaker { public static final String METHOD_NAME_BACKUP = "backup"; public static final String METHOD_NAME_SETUP = "setup"; + private static final HashMap, Character> descriptors = new HashMap<>() {{ + put(int.class, 'I'); + put(boolean.class, 'Z'); + put(char.class, 'C'); + put(long.class, 'J'); + put(short.class, 'S'); + put(float.class, 'F'); + put(double.class, 'D'); + put(byte.class, 'B'); + put(void.class, 'V'); + put(Object.class, 'L'); + }}; private Class mReturnType; private Class[] mActualParameterTypes; @@ -49,18 +62,31 @@ public class HookerDexMaker { private static Class[] getParameterTypes(Executable method, boolean isStatic) { Class[] parameterTypes = method.getParameterTypes(); + for (int i = 0; i < parameterTypes.length; ++i) { + parameterTypes[i] = parameterTypes[i].isPrimitive() ? parameterTypes[i] : Object.class; + } if (isStatic) { return parameterTypes; } int parameterSize = parameterTypes.length; - int targetParameterSize = parameterSize + 1; - Class[] newParameterTypes = new Class[targetParameterSize]; - int offset = 1; - newParameterTypes[0] = method.getDeclaringClass(); - System.arraycopy(parameterTypes, 0, newParameterTypes, offset, parameterTypes.length); + Class[] newParameterTypes = new Class[parameterSize + 1]; + newParameterTypes[0] = Object.class; + System.arraycopy(parameterTypes, 0, newParameterTypes, 1, parameterSize); return newParameterTypes; } + private static char getDescriptor(Class clazz) { + return descriptors.getOrDefault(clazz, 'L'); + } + + private static char[] getDescriptors(Class[] classes) { + var descriptors = new char[classes.length]; + for (int i = 0; i < classes.length; ++i) { + descriptors[i] = getDescriptor(classes[i]); + } + return descriptors; + } + public void start(Executable member, XposedBridge.AdditionalHookInfo hookInfo, ClassLoader appClassLoader) throws Exception { if (member instanceof Method) { @@ -89,7 +115,7 @@ public class HookerDexMaker { } private void doMake(String methodName) throws Exception { - Class hookClass = Yahfa.buildHooker(mAppClassLoader, mReturnType, mActualParameterTypes, methodName); + Class hookClass = Yahfa.buildHooker(mAppClassLoader, getDescriptor(mReturnType), getDescriptors(mActualParameterTypes), methodName); // Execute our newly-generated code in-process. Method backupMethod = hookClass.getMethod(METHOD_NAME_BACKUP, mActualParameterTypes); mHooker = new LspHooker(mHookInfo, mMember, backupMethod);