From 6d8f3da2486d7486d6e67f33eafffcd5e23c5cb5 Mon Sep 17 00:00:00 2001 From: Ruikai Liu Date: Wed, 13 Sep 2017 15:10:58 +0800 Subject: [PATCH] use copy ArtMethod --- .../Hook_ClassWithJNIMethod_fromJNI.java | 10 +++++ .../Hook_ClassWithStaticMethod_tac.java | 5 +++ .../Hook_ClassWithVirtualMethod_tac.java | 5 +++ .../galaxy/yahfa/demoPlugin/Hook_Log_e.java | 5 +++ .../demoPlugin/Hook_String_startsWith.java | 5 +++ .../main/java/lab/galaxy/yahfa/HookMain.java | 17 ++++--- library/src/main/jni/HookMain.c | 45 ++++++++++--------- library/src/main/jni/trampoline.c | 6 +-- 8 files changed, 66 insertions(+), 32 deletions(-) diff --git a/demoPlugin/src/main/java/lab/galaxy/yahfa/demoPlugin/Hook_ClassWithJNIMethod_fromJNI.java b/demoPlugin/src/main/java/lab/galaxy/yahfa/demoPlugin/Hook_ClassWithJNIMethod_fromJNI.java index 4f84638..26c6aed 100644 --- a/demoPlugin/src/main/java/lab/galaxy/yahfa/demoPlugin/Hook_ClassWithJNIMethod_fromJNI.java +++ b/demoPlugin/src/main/java/lab/galaxy/yahfa/demoPlugin/Hook_ClassWithJNIMethod_fromJNI.java @@ -13,6 +13,16 @@ public class Hook_ClassWithJNIMethod_fromJNI { // calling origin method is no longer available for JNI methods public static String hook() { + Log.w("YAHFA", "calling fromJNI"); + return origin(); + } + + public static String origin() { + Log.w("YAHFA", "calling fromJNI"); + return "1234"; + } + + public static String copy() { Log.w("YAHFA", "calling fromJNI"); return "1234"; } diff --git a/demoPlugin/src/main/java/lab/galaxy/yahfa/demoPlugin/Hook_ClassWithStaticMethod_tac.java b/demoPlugin/src/main/java/lab/galaxy/yahfa/demoPlugin/Hook_ClassWithStaticMethod_tac.java index 112b21b..bb5f1cf 100644 --- a/demoPlugin/src/main/java/lab/galaxy/yahfa/demoPlugin/Hook_ClassWithStaticMethod_tac.java +++ b/demoPlugin/src/main/java/lab/galaxy/yahfa/demoPlugin/Hook_ClassWithStaticMethod_tac.java @@ -21,4 +21,9 @@ public static String origin(String a, String b, String c, String d) { Log.w("YAHFA", "ClassWithStaticMethod.tac() should not be here"); return ""; } + + public static String copy(String a, String b, String c, String d) { + Log.w("YAHFA", "ClassWithStaticMethod.tac() should not be here"); + return ""; + } } diff --git a/demoPlugin/src/main/java/lab/galaxy/yahfa/demoPlugin/Hook_ClassWithVirtualMethod_tac.java b/demoPlugin/src/main/java/lab/galaxy/yahfa/demoPlugin/Hook_ClassWithVirtualMethod_tac.java index 279b215..639d7b6 100644 --- a/demoPlugin/src/main/java/lab/galaxy/yahfa/demoPlugin/Hook_ClassWithVirtualMethod_tac.java +++ b/demoPlugin/src/main/java/lab/galaxy/yahfa/demoPlugin/Hook_ClassWithVirtualMethod_tac.java @@ -21,4 +21,9 @@ public static String origin(Object thiz, String a, String b, String c, String d) Log.w("YAHFA", "ClassWithVirtualMethod.tac() should not be here"); return ""; } + + public static String copy(Object thiz, String a, String b, String c, String d) { + Log.w("YAHFA", "ClassWithVirtualMethod.tac() should not be here"); + return ""; + } } diff --git a/demoPlugin/src/main/java/lab/galaxy/yahfa/demoPlugin/Hook_Log_e.java b/demoPlugin/src/main/java/lab/galaxy/yahfa/demoPlugin/Hook_Log_e.java index 70db10c..5711e32 100644 --- a/demoPlugin/src/main/java/lab/galaxy/yahfa/demoPlugin/Hook_Log_e.java +++ b/demoPlugin/src/main/java/lab/galaxy/yahfa/demoPlugin/Hook_Log_e.java @@ -19,4 +19,9 @@ public static int origin(String tag, String msg) { Log.w("YAHFA", "Log.e() should not be here"); return 1; } + + public static int copy(String tag, String msg) { + Log.w("YAHFA", "Log.e() should not be here"); + return 1; + } } diff --git a/demoPlugin/src/main/java/lab/galaxy/yahfa/demoPlugin/Hook_String_startsWith.java b/demoPlugin/src/main/java/lab/galaxy/yahfa/demoPlugin/Hook_String_startsWith.java index e38df11..20e6ad7 100644 --- a/demoPlugin/src/main/java/lab/galaxy/yahfa/demoPlugin/Hook_String_startsWith.java +++ b/demoPlugin/src/main/java/lab/galaxy/yahfa/demoPlugin/Hook_String_startsWith.java @@ -19,4 +19,9 @@ public static boolean origin(String thiz, String prefix) { Log.w("YAHFA", "String.startsWith() should not be here"); return false; } + + public static boolean copy(String thiz, String prefix) { + Log.w("YAHFA", "String.startsWith() should not be here"); + return false; + } } diff --git a/library/src/main/java/lab/galaxy/yahfa/HookMain.java b/library/src/main/java/lab/galaxy/yahfa/HookMain.java index d83ec98..a03f97d 100644 --- a/library/src/main/java/lab/galaxy/yahfa/HookMain.java +++ b/library/src/main/java/lab/galaxy/yahfa/HookMain.java @@ -57,19 +57,22 @@ private static void doHookItemDefault(ClassLoader patchClassLoader, String hookI } Method hook = null; - Method backup = null; + Method origin = null; + Method copy = null; for (Method method : hookItem.getDeclaredMethods()) { if (method.getName().equals("hook") && Modifier.isStatic(method.getModifiers())) { hook = method; - } else if (method.getName().equals("origin") && Modifier.isStatic(method.getModifiers())) { - backup = method; + } else if (method.getName().equals("origin") && Modifier.isStatic(method.getModifiers())) { + origin = method; + } else if (method.getName().equals("copy") && Modifier.isStatic(method.getModifiers())) { + copy = method; } } if (hook == null) { Log.e(TAG, "Cannot find hook for "+methodName); return; } - findAndBackupAndHook(clazz, methodName, methodSig, hook, backup); + findAndBackupAndHook(clazz, methodName, methodSig, hook, origin, copy); } catch (Exception e) { e.printStackTrace(); @@ -78,14 +81,14 @@ private static void doHookItemDefault(ClassLoader patchClassLoader, String hookI public static void findAndBackupAndHook(Class targetClass, String methodName, String methodSig, - Method hook, Method backup) { + Method hook, Method origin, Method copy) { try { int hookParamCount = hook.getParameterTypes().length; int targetParamCount = getParamCountFromSignature(methodSig); Log.d(TAG, "target method param count is "+targetParamCount); boolean isStatic = (hookParamCount == targetParamCount); // virtual method has 'thiz' object as the first parameter - findAndBackupAndHook(targetClass, methodName, methodSig, isStatic, hook, backup); + findAndBackupAndHook(targetClass, methodName, methodSig, isStatic, hook, origin, copy); } catch (Exception e) { e.printStackTrace(); @@ -147,7 +150,7 @@ private static int parseSignature(String signature) throws Exception { private static native void findAndBackupAndHook(Class targetClass, String methodName, String methodSig, boolean isStatic, - Method hook, Method backup); + Method hook, Method origin, Method copy); private static native void init(int SDK_version); } diff --git a/library/src/main/jni/HookMain.c b/library/src/main/jni/HookMain.c index 70c6ef1..8e08843 100644 --- a/library/src/main/jni/HookMain.c +++ b/library/src/main/jni/HookMain.c @@ -94,7 +94,7 @@ void Java_lab_galaxy_yahfa_HookMain_init(JNIEnv *env, jclass clazz, jint sdkVers #endif } -static int doBackupAndHook(void *originMethod, void *hookMethod, void *backupMethod) { +static int doBackupAndHook(void *targetMethod, void *hookMethod, void *originMethod, void *copyMethod) { if(hookCount >= hookCap) { LOGW("not enough capacity. Allocating..."); if(doInitHookCap(DEFAULT_CAP)) { @@ -104,31 +104,27 @@ static int doBackupAndHook(void *originMethod, void *hookMethod, void *backupMet LOGI("Allocating done"); } - LOGI("origin method is at %p, hook method is at %p, backup method is at %p", - originMethod, hookMethod, backupMethod); + LOGI("target method is at %p, hook method is at %p, origin method is at %p, copy method is at %p", + targetMethod, hookMethod, originMethod, copyMethod); - if(!backupMethod) { - LOGW("backup method is null"); + if(!originMethod || !copyMethod) { + LOGW("Origin method or copy method is null. Cannot call origin"); } else { //do method backup - // have to copy the whole origin ArtMethod here - // if the origin method calls other methods which are to be resolved + // 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 origin method's entrypoint would result in a wrong 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 - void *originMethodCopy = malloc(ArtMethodSize); - if(!originMethodCopy) { - LOGE("malloc failed for copying origin method"); - return 1; - } - memcpy(originMethodCopy, originMethod, ArtMethodSize); - void *realEntryPoint = (void *)readAddr((char *) originMethod + + memcpy(copyMethod, targetMethod, ArtMethodSize); + + void *realEntryPoint = (void *)readAddr((char *) targetMethod + OFFSET_entry_point_from_quick_compiled_code_in_ArtMethod); - void *newEntryPoint = genTrampoline2(originMethodCopy, realEntryPoint); + void *newEntryPoint = genTrampoline2(copyMethod, realEntryPoint); if(newEntryPoint) { - memcpy((char *) backupMethod + OFFSET_entry_point_from_quick_compiled_code_in_ArtMethod, + memcpy((char *) originMethod + OFFSET_entry_point_from_quick_compiled_code_in_ArtMethod, &newEntryPoint, pointer_size); } else { @@ -144,7 +140,7 @@ static int doBackupAndHook(void *originMethod, void *hookMethod, void *backupMet // newEntrypoint // ); if(newEntrypoint) { - memcpy((char *) originMethod + OFFSET_entry_point_from_quick_compiled_code_in_ArtMethod, + memcpy((char *) targetMethod + OFFSET_entry_point_from_quick_compiled_code_in_ArtMethod, &newEntrypoint, pointer_size); } @@ -154,7 +150,7 @@ static int doBackupAndHook(void *originMethod, void *hookMethod, void *backupMet } if(OFFSET_entry_point_from_interpreter_in_ArtMethod != 0) { - memcpy((char *) originMethod + OFFSET_entry_point_from_interpreter_in_ArtMethod, + memcpy((char *) targetMethod + OFFSET_entry_point_from_interpreter_in_ArtMethod, (char *) hookMethod + OFFSET_entry_point_from_interpreter_in_ArtMethod, pointer_size); } @@ -165,7 +161,8 @@ static int doBackupAndHook(void *originMethod, void *hookMethod, void *backupMet } void Java_lab_galaxy_yahfa_HookMain_findAndBackupAndHook(JNIEnv *env, jclass clazz, - jclass targetClass, jstring methodName, jstring methodSig, jboolean isStatic, jobject hook, jobject backup) { + jclass targetClass, jstring methodName, jstring methodSig, jboolean isStatic, + jobject hook, jobject origin, jobject copy) { if(!methodName || !methodSig) { LOGE("empty method name or signature"); return; @@ -195,8 +192,12 @@ void Java_lab_galaxy_yahfa_HookMain_findAndBackupAndHook(JNIEnv *env, jclass cla goto end; } - if(!doBackupAndHook(targetMethod, (void *)(*env)->FromReflectedMethod(env, hook), - backup==NULL ? NULL : (void *)(*env)->FromReflectedMethod(env, backup))) { + if(!doBackupAndHook( + targetMethod, + (void *)(*env)->FromReflectedMethod(env, hook), + origin==NULL ? NULL : (void *)(*env)->FromReflectedMethod(env, origin), + copy==NULL ? NULL : (void *)(*env)->FromReflectedMethod(env, copy) + )) { (*env)->NewGlobalRef(env, hook); // keep a global ref so that the hook method would not be GCed } end: diff --git a/library/src/main/jni/trampoline.c b/library/src/main/jni/trampoline.c index 08b2611..793e3e0 100644 --- a/library/src/main/jni/trampoline.c +++ b/library/src/main/jni/trampoline.c @@ -55,9 +55,9 @@ static unsigned int t1Size = roundUpToPtrSize(sizeof(trampoline1)); #endif // trampoline2: -// 1 set eax/r0/x0 to the copy of origin ArtMethod addr, -// 2. clear hotness_count of the copy origin ArtMethod(only after Android N) -// 3. jump into origin's real entry point +// 1. set eax/r0/x0 to the copy ArtMethod addr, +// 2. clear hotness_count of the copy ArtMethod(only after Android N) +// 3. jump into target's real entry point #if defined(__i386__) // b8 21 43 65 87 ; mov eax, 0x87654321 // 66 c7 40 12 00 00 ; mov word [eax + 0x12], 0