Merge with latest Yahfa

This commit is contained in:
LoveSy 2020-12-08 04:20:28 +08:00 committed by 双草酸酯
parent d49757b5ad
commit e36c3ed314
12 changed files with 175 additions and 320 deletions

View File

@ -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);

View File

@ -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(

View File

@ -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;
}
}
}

View File

@ -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<mirror::Class>) = 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> = { T*, size_t idx }
// MethodDexCachePair = NativeDexCachePair<ArtMethod> = { ArtMethod*, size_t idx }
// MethodDexCacheType = std::atomic<MethodDexCachePair>
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");

View File

@ -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

View File

@ -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)

View File

@ -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());
}

View File

@ -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"),
};

View File

@ -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

View File

@ -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();

View File

@ -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<String, String> 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<Object>) 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) {

View File

@ -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();
}