Skip to content

Commit

Permalink
use copy ArtMethod
Browse files Browse the repository at this point in the history
  • Loading branch information
rk700 committed Sep 13, 2017
1 parent 4b10a31 commit 6d8f3da
Show file tree
Hide file tree
Showing 8 changed files with 66 additions and 32 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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";
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 "";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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 "";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
}
17 changes: 10 additions & 7 deletions library/src/main/java/lab/galaxy/yahfa/HookMain.java
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand All @@ -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();
Expand Down Expand Up @@ -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);
}
45 changes: 23 additions & 22 deletions library/src/main/jni/HookMain.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)) {
Expand All @@ -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 {
Expand All @@ -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);
}
Expand All @@ -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);
}
Expand All @@ -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;
Expand Down Expand Up @@ -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:
Expand Down
6 changes: 3 additions & 3 deletions library/src/main/jni/trampoline.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit 6d8f3da

Please sign in to comment.