diff --git a/edxp-common/src/main/java/com/elderdrivers/riru/edxp/core/Yahfa.java b/edxp-common/src/main/java/com/elderdrivers/riru/edxp/core/Yahfa.java index 2fd0686f..8405ada1 100644 --- a/edxp-common/src/main/java/com/elderdrivers/riru/edxp/core/Yahfa.java +++ b/edxp-common/src/main/java/com/elderdrivers/riru/edxp/core/Yahfa.java @@ -7,8 +7,6 @@ public class Yahfa { public static native boolean backupAndHookNative(Object target, Method hook, Method backup); - public static native void ensureMethodCached(Method hook, Method backup); - // JNI.ToReflectedMethod() could return either Method or Constructor public static native Object findMethodNative(Class targetClass, String methodName, String methodSig); diff --git a/edxp-common/src/main/java/com/elderdrivers/riru/edxp/core/yahfa/HookMain.java b/edxp-common/src/main/java/com/elderdrivers/riru/edxp/core/yahfa/HookMain.java index bd840818..5fa6972e 100644 --- a/edxp-common/src/main/java/com/elderdrivers/riru/edxp/core/yahfa/HookMain.java +++ b/edxp-common/src/main/java/com/elderdrivers/riru/edxp/core/yahfa/HookMain.java @@ -121,11 +121,6 @@ public class HookMain { // backup is just a placeholder and the constraint could be less strict checkCompatibleMethods(target, backup, "Original", "Backup"); } - if (backup != null) { - HookMethodResolver.resolveMethod(hook, backup, target); - } else { - Utils.logD("wanna resolve backup method, but it's null, target: " + target); - } // make sure GC completed before hook Thread currentThread = Thread.currentThread(); int lastGcType = Heap.waitForGcToComplete( diff --git a/edxp-common/src/main/java/com/elderdrivers/riru/edxp/core/yahfa/HookMethodResolver.java b/edxp-common/src/main/java/com/elderdrivers/riru/edxp/core/yahfa/HookMethodResolver.java deleted file mode 100644 index e1c81acb..00000000 --- a/edxp-common/src/main/java/com/elderdrivers/riru/edxp/core/yahfa/HookMethodResolver.java +++ /dev/null @@ -1,157 +0,0 @@ -package com.elderdrivers.riru.edxp.core.yahfa; - -import android.os.Build; - -import com.elderdrivers.riru.edxp.core.Yahfa; -import com.elderdrivers.riru.edxp.util.Utils; - -import java.lang.reflect.Field; -import java.lang.reflect.Method; - -/** - * create by Swift Gan on 14/01/2019 - * To ensure method in resolved cache - */ - -public class HookMethodResolver { - - public static Class artMethodClass; - - public static Field resolvedMethodsField; - public static Field dexCacheField; - public static Field dexMethodIndexField; - public static Field artMethodField; - - public static boolean canResolvedInJava = false; - public static boolean isArtMethod = false; - - public static long resolvedMethodsAddress = 0; - public static int dexMethodIndex = 0; - - public static Method testMethod; - public static Object testArtMethod; - - public static void init() { - checkSupport(); - } - - private static void checkSupport() { - try { - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { - isArtMethod = false; - canResolvedInJava = false; - return; - } - - testMethod = HookMethodResolver.class.getDeclaredMethod("init"); - artMethodField = getField(Method.class, "artMethod"); - - testArtMethod = artMethodField.get(testMethod); - - if (hasJavaArtMethod() && testArtMethod.getClass() == artMethodClass) { - checkSupportForArtMethod(); - isArtMethod = true; - } else if (testArtMethod instanceof Long) { - checkSupportForArtMethodId(); - isArtMethod = false; - } else { - canResolvedInJava = false; - } - - } catch (Throwable throwable) { - Utils.logE("error when checkSupport", throwable); - } - } - - // may 5.0 - private static void checkSupportForArtMethod() throws Exception { - dexMethodIndexField = getField(artMethodClass, "dexMethodIndex"); - dexCacheField = getField(Class.class, "dexCache"); - Object dexCache = dexCacheField.get(testMethod.getDeclaringClass()); - resolvedMethodsField = getField(dexCache.getClass(), "resolvedMethods"); - if (resolvedMethodsField.get(dexCache) instanceof Object[]) { - canResolvedInJava = true; - } - } - - // may 6.0 - private static void checkSupportForArtMethodId() throws Exception { - dexMethodIndexField = getField(Method.class, "dexMethodIndex"); - dexMethodIndex = (int) dexMethodIndexField.get(testMethod); - dexCacheField = getField(Class.class, "dexCache"); - Object dexCache = dexCacheField.get(testMethod.getDeclaringClass()); - resolvedMethodsField = getField(dexCache.getClass(), "resolvedMethods"); - Object resolvedMethods = resolvedMethodsField.get(dexCache); - if (resolvedMethods instanceof Long) { - canResolvedInJava = false; - resolvedMethodsAddress = (long) resolvedMethods; - } else if (resolvedMethods instanceof long[]) { - canResolvedInJava = true; - } - } - - public static void resolveMethod(Method hook, Method backup, Object target) { - if (canResolvedInJava && artMethodField != null) { - // in java - try { - resolveInJava(hook, backup, target); - } catch (Exception e) { - // in native - resolveInNative(hook, backup, target); - } - } else { - // in native - resolveInNative(hook, backup, target); - } - } - - private static void resolveInJava(Method hook, Method backup, Object target) throws Exception { - Utils.logD("start to resolve in java. target: " + target); - Object dexCache = dexCacheField.get(hook.getDeclaringClass()); - if (isArtMethod) { - Object artMethod = artMethodField.get(backup); - int dexMethodIndex = (int) dexMethodIndexField.get(artMethod); - Object resolvedMethods = resolvedMethodsField.get(dexCache); - ((Object[]) resolvedMethods)[dexMethodIndex] = artMethod; - } else { - int dexMethodIndex = (int) dexMethodIndexField.get(backup); - Object resolvedMethods = resolvedMethodsField.get(dexCache); - long artMethod = (long) artMethodField.get(backup); - ((long[]) resolvedMethods)[dexMethodIndex] = artMethod; - } - } - - private static void resolveInNative(Method hook, Method backup, Object target) { - Utils.logD("start to resolve in native. target: " + target); - Yahfa.ensureMethodCached(hook, backup); - } - - public static Field getField(Class topClass, String fieldName) throws NoSuchFieldException { - while (topClass != null && topClass != Object.class) { - try { - Field field = topClass.getDeclaredField(fieldName); - field.setAccessible(true); - return field; - } catch (Exception e) { - } - topClass = topClass.getSuperclass(); - } - throw new NoSuchFieldException(fieldName); - } - - public static boolean hasJavaArtMethod() { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { - return false; - } - if (artMethodClass != null) - return true; - try { - artMethodClass = Class.forName("java.lang.reflect.ArtMethod"); - return true; - } catch (ClassNotFoundException e) { - return false; - } - } - -} \ No newline at end of file diff --git a/edxp-core/src/main/cpp/external/yahfa/src/HookMain.c b/edxp-core/src/main/cpp/external/yahfa/src/HookMain.c index f40b53de..34b4037b 100644 --- a/edxp-core/src/main/cpp/external/yahfa/src/HookMain.c +++ b/edxp-core/src/main/cpp/external/yahfa/src/HookMain.c @@ -10,16 +10,13 @@ int SDKVersion; static int OFFSET_entry_point_from_interpreter_in_ArtMethod; -int OFFSET_entry_point_from_quick_compiled_code_in_ArtMethod; -static int OFFSET_dex_method_index_in_ArtMethod; -static int OFFSET_dex_cache_resolved_methods_in_ArtMethod; -static int OFFSET_array_in_PointerArray; +static int OFFSET_entry_point_from_quick_compiled_code_in_ArtMethod; static int OFFSET_ArtMehod_in_Object; static int OFFSET_access_flags_in_ArtMethod; -static size_t ArtMethodSize; static int kAccNative = 0x0100; static int kAccCompileDontBother = 0x01000000; static int kAccFastInterpreterToInterpreterInvoke = 0x40000000; +static int kAccPreCompiled = 0x00200000; static jfieldID fieldArtMethod = NULL; @@ -49,47 +46,32 @@ void Java_lab_galaxy_yahfa_HookMain_init(JNIEnv *env, jclass clazz, jint sdkVers kAccCompileDontBother = 0x02000000; OFFSET_ArtMehod_in_Object = 0; OFFSET_access_flags_in_ArtMethod = 4; - OFFSET_dex_method_index_in_ArtMethod = 4 * 3; - OFFSET_array_in_PointerArray = 0; OFFSET_entry_point_from_quick_compiled_code_in_ArtMethod = roundUpToPtrSize(4 * 4 + 2 * 2) + pointer_size; - ArtMethodSize = roundUpToPtrSize(4 * 4 + 2 * 2) + pointer_size * 2; break; case __ANDROID_API_O_MR1__: kAccCompileDontBother = 0x02000000; case __ANDROID_API_O__: OFFSET_ArtMehod_in_Object = 0; OFFSET_access_flags_in_ArtMethod = 4; - OFFSET_dex_method_index_in_ArtMethod = 4 * 3; - OFFSET_dex_cache_resolved_methods_in_ArtMethod = roundUpToPtrSize(4 * 4 + 2 * 2); - OFFSET_array_in_PointerArray = 0; OFFSET_entry_point_from_quick_compiled_code_in_ArtMethod = roundUpToPtrSize(4 * 4 + 2 * 2) + pointer_size * 2; - ArtMethodSize = roundUpToPtrSize(4 * 4 + 2 * 2) + pointer_size * 3; break; case __ANDROID_API_N_MR1__: case __ANDROID_API_N__: OFFSET_ArtMehod_in_Object = 0; OFFSET_access_flags_in_ArtMethod = 4; // sizeof(GcRoot) = 4 - OFFSET_dex_method_index_in_ArtMethod = 4 * 3; - OFFSET_dex_cache_resolved_methods_in_ArtMethod = roundUpToPtrSize(4 * 4 + 2 * 2); - OFFSET_array_in_PointerArray = 0; // ptr_sized_fields_ is rounded up to pointer_size in ArtMethod OFFSET_entry_point_from_quick_compiled_code_in_ArtMethod = roundUpToPtrSize(4 * 4 + 2 * 2) + pointer_size * 3; - ArtMethodSize = roundUpToPtrSize(4 * 4 + 2 * 2) + pointer_size * 4; break; case __ANDROID_API_M__: OFFSET_ArtMehod_in_Object = 0; OFFSET_entry_point_from_interpreter_in_ArtMethod = roundUpToPtrSize(4 * 7); OFFSET_entry_point_from_quick_compiled_code_in_ArtMethod = OFFSET_entry_point_from_interpreter_in_ArtMethod + pointer_size * 2; - OFFSET_dex_method_index_in_ArtMethod = 4 * 5; - OFFSET_dex_cache_resolved_methods_in_ArtMethod = 4; - OFFSET_array_in_PointerArray = 4 * 3; - ArtMethodSize = roundUpToPtrSize(4 * 7) + pointer_size * 3; break; case __ANDROID_API_L_MR1__: OFFSET_ArtMehod_in_Object = 4 * 2; @@ -97,42 +79,44 @@ void Java_lab_galaxy_yahfa_HookMain_init(JNIEnv *env, jclass clazz, jint sdkVers OFFSET_ArtMehod_in_Object + 4 * 7); OFFSET_entry_point_from_quick_compiled_code_in_ArtMethod = OFFSET_entry_point_from_interpreter_in_ArtMethod + pointer_size * 2; - OFFSET_dex_method_index_in_ArtMethod = OFFSET_ArtMehod_in_Object + 4 * 5; - OFFSET_dex_cache_resolved_methods_in_ArtMethod = OFFSET_ArtMehod_in_Object + 4; - OFFSET_array_in_PointerArray = 12; - ArtMethodSize = OFFSET_entry_point_from_interpreter_in_ArtMethod + pointer_size * 3; break; case __ANDROID_API_L__: OFFSET_ArtMehod_in_Object = 4 * 2; OFFSET_entry_point_from_interpreter_in_ArtMethod = OFFSET_ArtMehod_in_Object + 4 * 4; OFFSET_entry_point_from_quick_compiled_code_in_ArtMethod = OFFSET_entry_point_from_interpreter_in_ArtMethod + 8 * 2; - OFFSET_dex_method_index_in_ArtMethod = - OFFSET_ArtMehod_in_Object + 4 * 4 + 8 * 4 + 4 * 2; - OFFSET_dex_cache_resolved_methods_in_ArtMethod = OFFSET_ArtMehod_in_Object + 4; - OFFSET_array_in_PointerArray = 12; - ArtMethodSize = OFFSET_ArtMehod_in_Object + 4 * 4 + 8 * 4 + 4 * 4; break; default: LOGE("not compatible with SDK %d", sdkVersion); break; } - setupTrampoline(); + setupTrampoline(OFFSET_entry_point_from_quick_compiled_code_in_ArtMethod); +} + +static uint32_t getFlags(char *method) { + uint32_t access_flags = read32(method + OFFSET_access_flags_in_ArtMethod); + return access_flags; +} + +static void setFlags(char *method, uint32_t access_flags) { + write32(method + OFFSET_access_flags_in_ArtMethod, access_flags); } void setNonCompilable(void *method) { if (SDKVersion < __ANDROID_API_N__) { return; } - int access_flags = read32((char *) method + OFFSET_access_flags_in_ArtMethod); - LOGI("setNonCompilable: access flags is 0x%x", access_flags); + int access_flags = getFlags(method); + int old_flags = access_flags; access_flags |= kAccCompileDontBother; - write32((char *) method + OFFSET_access_flags_in_ArtMethod, access_flags); + setFlags(method, access_flags); + LOGI("setNonCompilable: change access flags from 0x%x to 0x%x", old_flags, access_flags); } bool setNativeFlag(void *method, bool isNative) { - int access_flags = read32((char *) method + OFFSET_access_flags_in_ArtMethod); + int access_flags = getFlags(method); + int old_flags = access_flags; LOGI("setNativeFlag: access flags is 0x%x", access_flags); int old_access_flags = access_flags; if (isNative) { @@ -145,13 +129,14 @@ bool setNativeFlag(void *method, bool isNative) { access_flags &= ~kAccNative; } if (access_flags != old_access_flags) { - write32((char *) method + OFFSET_access_flags_in_ArtMethod, access_flags); + setFlags(method, access_flags); + LOGI("change access flags from 0x%x to 0x%x", old_flags, access_flags); return true; } return false; } -static int doBackupAndHook(JNIEnv *env, void *targetMethod, void *hookMethod, void *backupMethod) { +static int replaceMethod(void *fromMethod, void *toMethod, int isBackup) { if (hookCount >= hookCap) { LOGI("not enough capacity. Allocating..."); if (doInitHookCap(DEFAULT_CAP)) { @@ -161,35 +146,26 @@ static int doBackupAndHook(JNIEnv *env, void *targetMethod, void *hookMethod, vo 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_ - if (SDKVersion >= __ANDROID_API_N__) { - 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); - } + LOGI("replace method from %p to %p", fromMethod, toMethod); // 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), + void *newEntrypoint = NULL; + if(isBackup) { + void *originEntrypoint = readAddr((char *) toMethod + OFFSET_entry_point_from_quick_compiled_code_in_ArtMethod); + // entry point hardcoded + newEntrypoint = genTrampoline(toMethod, originEntrypoint); + } + else { + // entry point from ArtMethod struct + newEntrypoint = genTrampoline(toMethod, NULL); + } + + LOGI("replace entry point from %p to %p", + readAddr((char *) fromMethod + OFFSET_entry_point_from_quick_compiled_code_in_ArtMethod), newEntrypoint ); if (newEntrypoint) { - memcpy((char *) targetMethod + OFFSET_entry_point_from_quick_compiled_code_in_ArtMethod, + memcpy((char *) fromMethod + OFFSET_entry_point_from_quick_compiled_code_in_ArtMethod, &newEntrypoint, pointer_size); } else { @@ -198,69 +174,46 @@ static int doBackupAndHook(JNIEnv *env, void *targetMethod, void *hookMethod, vo } if (OFFSET_entry_point_from_interpreter_in_ArtMethod != 0) { - memcpy((char *) targetMethod + OFFSET_entry_point_from_interpreter_in_ArtMethod, - (char *) hookMethod + OFFSET_entry_point_from_interpreter_in_ArtMethod, + memcpy((char *) fromMethod + OFFSET_entry_point_from_interpreter_in_ArtMethod, + (char *) toMethod + OFFSET_entry_point_from_interpreter_in_ArtMethod, pointer_size); } // set the target method to native so that Android O wouldn't invoke it with interpreter if (SDKVersion >= __ANDROID_API_O__) { - setNativeFlag(targetMethod, true); + setNativeFlag(fromMethod, true); } - LOGI("hook and backup done"); hookCount += 1; return 0; } -static void ensureMethodCached(void *hookMethod, void *backupMethod, - void *hookClassResolvedMethods) { - if (!backupMethod) { - LOGE("ensureMethodCached: backupMethod is null"); - return; - } - void *dexCacheResolvedMethods; - // then we get the dex method index of the static backup method - int methodIndex = read32( - (void *) ((char *) backupMethod + OFFSET_dex_method_index_in_ArtMethod)); +static 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); - // todo fixme - if (methodIndex >= 512) { - LOGW("methodIndex = %d", methodIndex); + int res = 0; + + // set kAccCompileDontBother for a method we do not want the compiler to compile + // so that we don't need to worry about hotness_count_ + if (SDKVersion >= __ANDROID_API_N__) { + setNonCompilable(targetMethod); +// setNonCompilable(hookMethod); + if(backupMethod) setNonCompilable(backupMethod); } - // update the cached method manually - // first we find the array of cached methods - dexCacheResolvedMethods = hookClassResolvedMethods; - - if (!dexCacheResolvedMethods) { - LOGE("dexCacheResolvedMethods is null"); - return; + if (backupMethod) {// do method backup + // we use the same way as hooking target method + // hook backup method and redirect back to the original target method + // the only difference is that the entry point is now hardcoded + // instead of reading from ArtMethod struct since it's overwritten + res += replaceMethod(backupMethod, targetMethod, 1); } - // finally the addr of backup method is put at the corresponding location in cached methods array - if (SDKVersion >= __ANDROID_API_O_MR1__) { - // array of MethodDexCacheType is used as dexCacheResolvedMethods in Android 8.1 - // struct: - // struct NativeDexCachePair = { T*, size_t idx } - // MethodDexCachePair = NativeDexCachePair = { ArtMethod*, size_t idx } - // MethodDexCacheType = std::atomic - memcpy((char *) dexCacheResolvedMethods + OFFSET_array_in_PointerArray + - pointer_size * 2 * methodIndex, - (&backupMethod), - pointer_size - ); - memcpy((char *) dexCacheResolvedMethods + OFFSET_array_in_PointerArray + - pointer_size * 2 * methodIndex + pointer_size, - &methodIndex, - pointer_size - ); - } else { - memcpy((char *) dexCacheResolvedMethods + OFFSET_array_in_PointerArray + - pointer_size * methodIndex, - (&backupMethod), - pointer_size); - } + res += replaceMethod(targetMethod, hookMethod, 0); + + LOGI("hook and backup done"); + return res; } void *getArtMethod(JNIEnv *env, jobject jmethod) { @@ -312,13 +265,11 @@ jboolean Java_lab_galaxy_yahfa_HookMain_backupAndHookNative(JNIEnv *env, jclass jobject target, jobject hook, jobject backup) { - if (!doBackupAndHook(env, - getArtMethod(env, target), + if (!doBackupAndHook(getArtMethod(env, target), getArtMethod(env, hook), getArtMethod(env, backup) )) { - (*env)->NewGlobalRef(env, - hook); // keep a global ref so that the hook method would not be GCed + (*env)->NewGlobalRef(env, hook); // keep a global ref so that the hook method would not be GCed if (backup) (*env)->NewGlobalRef(env, backup); return JNI_TRUE; } else { @@ -326,14 +277,6 @@ jboolean Java_lab_galaxy_yahfa_HookMain_backupAndHookNative(JNIEnv *env, jclass } } -void Java_lab_galaxy_yahfa_HookMain_ensureMethodCached(JNIEnv *env, jclass clazz, - jobject hook, - jobject backup) { - ensureMethodCached(getArtMethod(env, hook), - getArtMethod(env, backup), - getResolvedMethodsAddr(env, hook)); -} - static void *getResolvedMethodsAddr(JNIEnv *env, jobject hook) { // get backup class jclass methodClass = (*env)->FindClass(env, "java/lang/reflect/Method"); diff --git a/edxp-core/src/main/cpp/external/yahfa/src/trampoline.c b/edxp-core/src/main/cpp/external/yahfa/src/trampoline.c index 5b9eb8da..2652a8c8 100644 --- a/edxp-core/src/main/cpp/external/yahfa/src/trampoline.c +++ b/edxp-core/src/main/cpp/external/yahfa/src/trampoline.c @@ -14,6 +14,8 @@ #include "common.h" #include "trampoline.h" +#define MAX(a, b) ((a) > (b) ? (a) : (b)) + static unsigned char *trampolineCode; // place where trampolines are saved static unsigned int trampolineSize; // trampoline size required for each hook @@ -21,8 +23,13 @@ unsigned int hookCap = 0; unsigned int hookCount = 0; // trampoline: -// 1. set eax/r0/x0 to the hook ArtMethod addr +// 1. set eax/rdi/r0/x0 to the hook ArtMethod addr // 2. jump into its entry point + +// trampoline for backup: +// 1. set eax/rdi/r0/x0 to the target ArtMethod addr +// 2. ret to the hardcoded original entry point + #if defined(__i386__) // b8 78 56 34 12 ; mov eax, 0x12345678 (addr of the hook method) // ff 70 20 ; push DWORD PTR [eax + 0x20] @@ -33,6 +40,15 @@ unsigned char trampoline[] = { 0xc3 }; +// b8 78 56 34 12 ; mov eax, 0x12345678 (addr of the target method) +// 68 78 56 34 12 ; push 0x12345678 (original entry point of the target method) +// c3 ; ret +unsigned char trampolineForBackup[] = { + 0xb8, 0x78, 0x56, 0x34, 0x12, + 0x68, 0x78, 0x56, 0x34, 0x12, + 0xc3 +}; + #elif defined(__x86_64__) // 48 bf 78 56 34 12 78 56 34 12 ; movabs rdi, 0x1234567812345678 // ff 77 20 ; push QWORD PTR [rdi + 0x20] @@ -43,6 +59,17 @@ unsigned char trampoline[] = { 0xc3 }; +// 48 bf 78 56 34 12 78 56 34 12 ; movabs rdi, 0x1234567812345678 +// 57 ; push rdi (original entry point of the target method) +// 48 bf 78 56 34 12 78 56 34 12 ; movabs rdi, 0x1234567812345678 (addr of the target method) +// c3 ; ret +unsigned char trampolineForBackup[] = { + 0x48, 0xbf, 0x78, 0x56, 0x34, 0x12, 0x78, 0x56, 0x34, 0x12, + 0x57, + 0x48, 0xbf, 0x78, 0x56, 0x34, 0x12, 0x78, 0x56, 0x34, 0x12, + 0xc3 +}; + #elif defined(__arm__) // 00 00 9F E5 ; ldr r0, [pc, #0] // 20 F0 90 E5 ; ldr pc, [r0, 0x20] @@ -53,6 +80,21 @@ unsigned char trampoline[] = { 0x78, 0x56, 0x34, 0x12 }; +// 0c 00 9F E5 ; ldr r0, [pc, #12] +// 01 00 2d e9 ; push {r0} +// 00 00 9F E5 ; ldr r0, [pc, #0] +// 00 80 bd e8 ; pop {pc} +// 78 56 34 12 ; 0x12345678 (addr of the hook method) +// 78 56 34 12 ; 0x12345678 (original entry point of the target method) +unsigned char trampolineForBackup[] = { + 0x0c, 0x00, 0x9f, 0xe5, + 0x01, 0x00, 0x2d, 0xe9, + 0x00, 0x00, 0x9f, 0xe5, + 0x00, 0x80, 0xbd, 0xe8, + 0x78, 0x56, 0x34, 0x12, + 0x78, 0x56, 0x34, 0x12 +}; + #elif defined(__aarch64__) // 60 00 00 58 ; ldr x0, 12 // 10 00 40 F8 ; ldr x16, [x0, #0x00] @@ -66,28 +108,74 @@ unsigned char trampoline[] = { 0x78, 0x56, 0x34, 0x12, 0x89, 0x67, 0x45, 0x23 }; + +// 60 00 00 58 ; ldr x0, 12 +// 90 00 00 58 ; ldr x16, 16 +// 00 02 1f d6 ; br x16 +// 78 56 34 12 +// 89 67 45 23 ; 0x2345678912345678 (addr of the hook method) +// 78 56 34 12 +// 89 67 45 23 ; 0x2345678912345678 (original entry point of the target method) +unsigned char trampolineForBackup[] = { + 0x60, 0x00, 0x00, 0x58, + 0x90, 0x00, 0x00, 0x58, + 0x00, 0x02, 0x1f, 0xd6, + 0x78, 0x56, 0x34, 0x12, + 0x89, 0x67, 0x45, 0x23, + 0x78, 0x56, 0x34, 0x12, + 0x89, 0x67, 0x45, 0x23 +}; + #endif -static unsigned int trampolineSize = roundUpToPtrSize(sizeof(trampoline)); +static unsigned int trampolineSize = roundUpToPtrSize(MAX(sizeof(trampoline), sizeof(trampolineForBackup))); -void *genTrampoline(void *hookMethod) { - void *targetAddr; +void *genTrampoline(void *toMethod, void *entrypoint) { + unsigned char *targetAddr = trampolineCode + trampolineSize * hookCount; - targetAddr = trampolineCode + trampolineSize * hookCount; - memcpy(targetAddr, trampoline, - sizeof(trampoline)); // do not use trampolineSize since it's a rounded size + if(entrypoint != NULL) { + memcpy(targetAddr, trampolineForBackup, sizeof(trampolineForBackup)); + } + else { + memcpy(targetAddr, trampoline, + sizeof(trampoline)); // do not use trampolineSize since it's a rounded size + } // replace with the actual ArtMethod addr #if defined(__i386__) - memcpy(targetAddr+1, &hookMethod, pointer_size); + if(entrypoint) { + memcpy(targetAddr + 1, &toMethod, pointer_size); + memcpy(targetAddr + 6, &entrypoint, pointer_size); + } + else { + memcpy(targetAddr + 1, &toMethod, pointer_size); + } #elif defined(__x86_64__) - memcpy((char*)targetAddr + 2, &hookMethod, pointer_size); + if(entrypoint) { + memcpy(targetAddr + 2, &entrypoint, pointer_size); + memcpy(targetAddr + 13, &toMethod, pointer_size); + } + else { + memcpy(targetAddr + 2, &toMethod, pointer_size); + } #elif defined(__arm__) - memcpy(targetAddr+8, &hookMethod, pointer_size); + if(entrypoint) { + memcpy(targetAddr + 20, &entrypoint, pointer_size); + memcpy(targetAddr + 16, &toMethod, pointer_size); + } + else { + memcpy(targetAddr + 8, &toMethod, pointer_size); + } #elif defined(__aarch64__) - memcpy(targetAddr + 12, &hookMethod, pointer_size); + if(entrypoint) { + memcpy(targetAddr + 20, &entrypoint, pointer_size); + memcpy(targetAddr + 12, &toMethod, pointer_size); + } + else { + memcpy(targetAddr + 12, &toMethod, pointer_size); + } #else #error Unsupported architecture @@ -96,18 +184,16 @@ void *genTrampoline(void *hookMethod) { return targetAddr; } -void setupTrampoline() { +void setupTrampoline(uint8_t offset) { #if defined(__i386__) - trampoline[7] = (unsigned char)OFFSET_entry_point_from_quick_compiled_code_in_ArtMethod; + trampoline[7] = offset; #elif defined(__x86_64__) - trampoline[12] = (unsigned char)OFFSET_entry_point_from_quick_compiled_code_in_ArtMethod; + trampoline[12] = offset; #elif defined(__arm__) - trampoline[4] = (unsigned char)OFFSET_entry_point_from_quick_compiled_code_in_ArtMethod; + trampoline[4] = offset; #elif defined(__aarch64__) - trampoline[5] |= - ((unsigned char) OFFSET_entry_point_from_quick_compiled_code_in_ArtMethod) << 4; - trampoline[6] |= - ((unsigned char) OFFSET_entry_point_from_quick_compiled_code_in_ArtMethod) >> 4; + trampoline[5] |= offset << 4; + trampoline[6] |= offset >> 4; #else #error Unsupported architecture #endif diff --git a/edxp-core/src/main/cpp/external/yahfa/src/trampoline.h b/edxp-core/src/main/cpp/external/yahfa/src/trampoline.h index 69fd7458..2235a42d 100644 --- a/edxp-core/src/main/cpp/external/yahfa/src/trampoline.h +++ b/edxp-core/src/main/cpp/external/yahfa/src/trampoline.h @@ -6,7 +6,6 @@ #define YAHFA_TAMPOLINE_H extern int SDKVersion; -extern int 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 @@ -14,8 +13,8 @@ extern unsigned int hookCount; // current count of used trampolines extern unsigned char trampoline[]; int doInitHookCap(unsigned int cap); -void setupTrampoline(); -void *genTrampoline(void *hookMethod); +void setupTrampoline(uint8_t offset); +void *genTrampoline(void *toMethod, void *entrypoint); #define DEFAULT_CAP 1 //size of each trampoline area would be no more than 4k Bytes(one page) diff --git a/edxp-core/src/main/cpp/main/src/config_manager.cpp b/edxp-core/src/main/cpp/main/src/config_manager.cpp index 304f1950..f9ac5e48 100644 --- a/edxp-core/src/main/cpp/main/src/config_manager.cpp +++ b/edxp-core/src/main/cpp/main/src/config_manager.cpp @@ -344,6 +344,7 @@ namespace edxp { [](auto i) { return GetFrameworkPath(i); }); + LOGI("Got base config path: %s", misc_path_.c_str()); } catch (const RirudSocket::RirudSocketException &e) { LOGE("%s", e.what()); } diff --git a/edxp-core/src/main/cpp/main/src/jni/edxp_yahfa.cpp b/edxp-core/src/main/cpp/main/src/jni/edxp_yahfa.cpp index 26012788..4d705b22 100644 --- a/edxp-core/src/main/cpp/main/src/jni/edxp_yahfa.cpp +++ b/edxp-core/src/main/cpp/main/src/jni/edxp_yahfa.cpp @@ -22,10 +22,6 @@ namespace edxp { return Java_lab_galaxy_yahfa_HookMain_backupAndHookNative(env, clazz, target, hook, backup); } - static void Yahfa_ensureMethodCached(JNI_START, jobject hook, jobject backup) { - Java_lab_galaxy_yahfa_HookMain_ensureMethodCached(env, clazz, hook, backup); - } - static void Yahfa_setMethodNonCompilable(JNI_START, jobject member) { if (!member) { LOGE("setNonCompilableNative: member is null"); @@ -59,8 +55,6 @@ namespace edxp { "(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;)Ljava/lang/Object;"), NATIVE_METHOD(Yahfa, backupAndHookNative, "(Ljava/lang/Object;Ljava/lang/reflect/Method;Ljava/lang/reflect/Method;)Z"), - NATIVE_METHOD(Yahfa, ensureMethodCached, - "(Ljava/lang/reflect/Method;Ljava/lang/reflect/Method;)V"), NATIVE_METHOD(Yahfa, setMethodNonCompilable, "(Ljava/lang/reflect/Member;)V"), NATIVE_METHOD(Yahfa, setNativeFlag, "(Ljava/lang/reflect/Member;Z)Z"), }; diff --git a/edxp-core/template_override/post-fs-data.sh b/edxp-core/template_override/post-fs-data.sh index c0cfb5cd..041bb9ab 100644 --- a/edxp-core/template_override/post-fs-data.sh +++ b/edxp-core/template_override/post-fs-data.sh @@ -169,5 +169,5 @@ chcon -R u:object_r:system_file:s0 "${MODDIR}" chcon -R ${PATH_CONTEXT} "${LOG_PATH}" chown -R ${PATH_OWNER} "${LOG_PATH}" chmod -R 666 "${LOG_PATH}" -[[ -z "$MISC_PATH" ]] && chcon -R u:object_r:magisk_file:s0 "$BASE_PATH" +[[ -z "$MISC_PATH" ]] || chcon -R u:object_r:magisk_file:s0 "$BASE_PATH" rm -f /data/adb/edxp/new_install \ No newline at end of file diff --git a/edxp-sandhook/src/main/java/com/elderdrivers/riru/edxp/sandhook/core/SandHookEdxpImpl.java b/edxp-sandhook/src/main/java/com/elderdrivers/riru/edxp/sandhook/core/SandHookEdxpImpl.java index 5464a5a3..1f578656 100644 --- a/edxp-sandhook/src/main/java/com/elderdrivers/riru/edxp/sandhook/core/SandHookEdxpImpl.java +++ b/edxp-sandhook/src/main/java/com/elderdrivers/riru/edxp/sandhook/core/SandHookEdxpImpl.java @@ -6,7 +6,6 @@ import com.elderdrivers.riru.edxp.core.BaseEdxpImpl; import com.elderdrivers.riru.edxp.core.EdxpImpl; import com.elderdrivers.riru.edxp.core.Main; import com.elderdrivers.riru.edxp.core.Yahfa; -import com.elderdrivers.riru.edxp.core.yahfa.HookMethodResolver; import com.swift.sandhook.xposedcompat.methodgen.SandHookXposedBridge; public class SandHookEdxpImpl extends BaseEdxpImpl { @@ -32,7 +31,6 @@ public class SandHookEdxpImpl extends BaseEdxpImpl { @Override public void init() { Yahfa.init(Build.VERSION.SDK_INT); - HookMethodResolver.init(); getRouter().injectConfig(); SandHookXposedBridge.init(); setInitialized(); diff --git a/edxp-service/src/main/java/com/elderdrivers/riru/edxp/service/PackageReceiver.java b/edxp-service/src/main/java/com/elderdrivers/riru/edxp/service/PackageReceiver.java index fde8ee09..e179a3a4 100644 --- a/edxp-service/src/main/java/com/elderdrivers/riru/edxp/service/PackageReceiver.java +++ b/edxp-service/src/main/java/com/elderdrivers/riru/edxp/service/PackageReceiver.java @@ -1,7 +1,5 @@ package com.elderdrivers.riru.edxp.service; -import android.accounts.Account; -import android.accounts.AccountManager; import android.annotation.SuppressLint; import android.app.ActivityThread; import android.content.BroadcastReceiver; @@ -98,9 +96,11 @@ public class PackageReceiver { return result; } - private void updateModuleList(int uid) { + private void updateModuleList(int uid, String packageName) { Map enabledModules = loadEnabledModules(uid); + if(packageName != null && !enabledModules.containsKey(packageName)) return; + try { File moduleListFile = new File(CONFIG_PATH, uid + "/" + MODULES_LIST_FILENAME); moduleListFile.createNewFile(); @@ -155,7 +155,7 @@ public class PackageReceiver { for (Object uh : (List) m.invoke(um)) { int uid = (int) uh.getClass().getDeclaredField("id").get(uh); Utils.logI("updating uid: " + uid); - updateModuleList(uid); + updateModuleList(uid, pkgInfo == null ? null : packageName); } Toast.makeText(context, "EdXposed: Updated " + packageName, Toast.LENGTH_SHORT).show(); } catch (Throwable e) { diff --git a/edxp-yahfa/src/main/java/com/elderdrivers/riru/edxp/yahfa/core/YahfaEdxpImpl.java b/edxp-yahfa/src/main/java/com/elderdrivers/riru/edxp/yahfa/core/YahfaEdxpImpl.java index 628dbde6..af0c6f35 100644 --- a/edxp-yahfa/src/main/java/com/elderdrivers/riru/edxp/yahfa/core/YahfaEdxpImpl.java +++ b/edxp-yahfa/src/main/java/com/elderdrivers/riru/edxp/yahfa/core/YahfaEdxpImpl.java @@ -7,7 +7,6 @@ import com.elderdrivers.riru.edxp.core.EdxpImpl; import com.elderdrivers.riru.edxp.core.Main; import com.elderdrivers.riru.edxp.core.Proxy; import com.elderdrivers.riru.edxp.core.Yahfa; -import com.elderdrivers.riru.edxp.core.yahfa.HookMethodResolver; import com.elderdrivers.riru.edxp.proxy.NormalProxy; import com.elderdrivers.riru.edxp.proxy.Router; @@ -29,7 +28,6 @@ public class YahfaEdxpImpl extends BaseEdxpImpl { @Override public void init() { Yahfa.init(Build.VERSION.SDK_INT); - HookMethodResolver.init(); getRouter().injectConfig(); setInitialized(); }