Merge with latest Yahfa
This commit is contained in:
parent
d49757b5ad
commit
e36c3ed314
|
|
@ -7,8 +7,6 @@ public class Yahfa {
|
||||||
|
|
||||||
public static native boolean backupAndHookNative(Object target, Method hook, Method backup);
|
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
|
// JNI.ToReflectedMethod() could return either Method or Constructor
|
||||||
public static native Object findMethodNative(Class targetClass, String methodName, String methodSig);
|
public static native Object findMethodNative(Class targetClass, String methodName, String methodSig);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -121,11 +121,6 @@ public class HookMain {
|
||||||
// backup is just a placeholder and the constraint could be less strict
|
// backup is just a placeholder and the constraint could be less strict
|
||||||
checkCompatibleMethods(target, backup, "Original", "Backup");
|
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
|
// make sure GC completed before hook
|
||||||
Thread currentThread = Thread.currentThread();
|
Thread currentThread = Thread.currentThread();
|
||||||
int lastGcType = Heap.waitForGcToComplete(
|
int lastGcType = Heap.waitForGcToComplete(
|
||||||
|
|
|
||||||
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -10,16 +10,13 @@
|
||||||
|
|
||||||
int SDKVersion;
|
int SDKVersion;
|
||||||
static int OFFSET_entry_point_from_interpreter_in_ArtMethod;
|
static int OFFSET_entry_point_from_interpreter_in_ArtMethod;
|
||||||
int OFFSET_entry_point_from_quick_compiled_code_in_ArtMethod;
|
static 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_ArtMehod_in_Object;
|
static int OFFSET_ArtMehod_in_Object;
|
||||||
static int OFFSET_access_flags_in_ArtMethod;
|
static int OFFSET_access_flags_in_ArtMethod;
|
||||||
static size_t ArtMethodSize;
|
|
||||||
static int kAccNative = 0x0100;
|
static int kAccNative = 0x0100;
|
||||||
static int kAccCompileDontBother = 0x01000000;
|
static int kAccCompileDontBother = 0x01000000;
|
||||||
static int kAccFastInterpreterToInterpreterInvoke = 0x40000000;
|
static int kAccFastInterpreterToInterpreterInvoke = 0x40000000;
|
||||||
|
static int kAccPreCompiled = 0x00200000;
|
||||||
|
|
||||||
static jfieldID fieldArtMethod = NULL;
|
static jfieldID fieldArtMethod = NULL;
|
||||||
|
|
||||||
|
|
@ -49,47 +46,32 @@ void Java_lab_galaxy_yahfa_HookMain_init(JNIEnv *env, jclass clazz, jint sdkVers
|
||||||
kAccCompileDontBother = 0x02000000;
|
kAccCompileDontBother = 0x02000000;
|
||||||
OFFSET_ArtMehod_in_Object = 0;
|
OFFSET_ArtMehod_in_Object = 0;
|
||||||
OFFSET_access_flags_in_ArtMethod = 4;
|
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 =
|
OFFSET_entry_point_from_quick_compiled_code_in_ArtMethod =
|
||||||
roundUpToPtrSize(4 * 4 + 2 * 2) + pointer_size;
|
roundUpToPtrSize(4 * 4 + 2 * 2) + pointer_size;
|
||||||
ArtMethodSize = roundUpToPtrSize(4 * 4 + 2 * 2) + pointer_size * 2;
|
|
||||||
break;
|
break;
|
||||||
case __ANDROID_API_O_MR1__:
|
case __ANDROID_API_O_MR1__:
|
||||||
kAccCompileDontBother = 0x02000000;
|
kAccCompileDontBother = 0x02000000;
|
||||||
case __ANDROID_API_O__:
|
case __ANDROID_API_O__:
|
||||||
OFFSET_ArtMehod_in_Object = 0;
|
OFFSET_ArtMehod_in_Object = 0;
|
||||||
OFFSET_access_flags_in_ArtMethod = 4;
|
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 =
|
OFFSET_entry_point_from_quick_compiled_code_in_ArtMethod =
|
||||||
roundUpToPtrSize(4 * 4 + 2 * 2) + pointer_size * 2;
|
roundUpToPtrSize(4 * 4 + 2 * 2) + pointer_size * 2;
|
||||||
ArtMethodSize = roundUpToPtrSize(4 * 4 + 2 * 2) + pointer_size * 3;
|
|
||||||
break;
|
break;
|
||||||
case __ANDROID_API_N_MR1__:
|
case __ANDROID_API_N_MR1__:
|
||||||
case __ANDROID_API_N__:
|
case __ANDROID_API_N__:
|
||||||
OFFSET_ArtMehod_in_Object = 0;
|
OFFSET_ArtMehod_in_Object = 0;
|
||||||
OFFSET_access_flags_in_ArtMethod = 4; // sizeof(GcRoot<mirror::Class>) = 4
|
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
|
// ptr_sized_fields_ is rounded up to pointer_size in ArtMethod
|
||||||
OFFSET_entry_point_from_quick_compiled_code_in_ArtMethod =
|
OFFSET_entry_point_from_quick_compiled_code_in_ArtMethod =
|
||||||
roundUpToPtrSize(4 * 4 + 2 * 2) + pointer_size * 3;
|
roundUpToPtrSize(4 * 4 + 2 * 2) + pointer_size * 3;
|
||||||
|
|
||||||
ArtMethodSize = roundUpToPtrSize(4 * 4 + 2 * 2) + pointer_size * 4;
|
|
||||||
break;
|
break;
|
||||||
case __ANDROID_API_M__:
|
case __ANDROID_API_M__:
|
||||||
OFFSET_ArtMehod_in_Object = 0;
|
OFFSET_ArtMehod_in_Object = 0;
|
||||||
OFFSET_entry_point_from_interpreter_in_ArtMethod = roundUpToPtrSize(4 * 7);
|
OFFSET_entry_point_from_interpreter_in_ArtMethod = roundUpToPtrSize(4 * 7);
|
||||||
OFFSET_entry_point_from_quick_compiled_code_in_ArtMethod =
|
OFFSET_entry_point_from_quick_compiled_code_in_ArtMethod =
|
||||||
OFFSET_entry_point_from_interpreter_in_ArtMethod + pointer_size * 2;
|
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;
|
break;
|
||||||
case __ANDROID_API_L_MR1__:
|
case __ANDROID_API_L_MR1__:
|
||||||
OFFSET_ArtMehod_in_Object = 4 * 2;
|
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_ArtMehod_in_Object + 4 * 7);
|
||||||
OFFSET_entry_point_from_quick_compiled_code_in_ArtMethod =
|
OFFSET_entry_point_from_quick_compiled_code_in_ArtMethod =
|
||||||
OFFSET_entry_point_from_interpreter_in_ArtMethod + pointer_size * 2;
|
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;
|
break;
|
||||||
case __ANDROID_API_L__:
|
case __ANDROID_API_L__:
|
||||||
OFFSET_ArtMehod_in_Object = 4 * 2;
|
OFFSET_ArtMehod_in_Object = 4 * 2;
|
||||||
OFFSET_entry_point_from_interpreter_in_ArtMethod = OFFSET_ArtMehod_in_Object + 4 * 4;
|
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_quick_compiled_code_in_ArtMethod =
|
||||||
OFFSET_entry_point_from_interpreter_in_ArtMethod + 8 * 2;
|
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;
|
break;
|
||||||
default:
|
default:
|
||||||
LOGE("not compatible with SDK %d", sdkVersion);
|
LOGE("not compatible with SDK %d", sdkVersion);
|
||||||
break;
|
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) {
|
void setNonCompilable(void *method) {
|
||||||
if (SDKVersion < __ANDROID_API_N__) {
|
if (SDKVersion < __ANDROID_API_N__) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
int access_flags = read32((char *) method + OFFSET_access_flags_in_ArtMethod);
|
int access_flags = getFlags(method);
|
||||||
LOGI("setNonCompilable: access flags is 0x%x", access_flags);
|
int old_flags = access_flags;
|
||||||
access_flags |= kAccCompileDontBother;
|
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) {
|
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);
|
LOGI("setNativeFlag: access flags is 0x%x", access_flags);
|
||||||
int old_access_flags = access_flags;
|
int old_access_flags = access_flags;
|
||||||
if (isNative) {
|
if (isNative) {
|
||||||
|
|
@ -145,13 +129,14 @@ bool setNativeFlag(void *method, bool isNative) {
|
||||||
access_flags &= ~kAccNative;
|
access_flags &= ~kAccNative;
|
||||||
}
|
}
|
||||||
if (access_flags != old_access_flags) {
|
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 true;
|
||||||
}
|
}
|
||||||
return false;
|
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) {
|
if (hookCount >= hookCap) {
|
||||||
LOGI("not enough capacity. Allocating...");
|
LOGI("not enough capacity. Allocating...");
|
||||||
if (doInitHookCap(DEFAULT_CAP)) {
|
if (doInitHookCap(DEFAULT_CAP)) {
|
||||||
|
|
@ -161,35 +146,26 @@ static int doBackupAndHook(JNIEnv *env, void *targetMethod, void *hookMethod, vo
|
||||||
LOGI("Allocating done");
|
LOGI("Allocating done");
|
||||||
}
|
}
|
||||||
|
|
||||||
LOGI("target method is at %p, hook method is at %p, backup method is at %p",
|
LOGI("replace method from %p to %p", fromMethod, toMethod);
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
// replace entry point
|
// replace entry point
|
||||||
void *newEntrypoint = genTrampoline(hookMethod);
|
void *newEntrypoint = NULL;
|
||||||
LOGI("origin ep is %p, new ep is %p",
|
if(isBackup) {
|
||||||
readAddr((char *) targetMethod + OFFSET_entry_point_from_quick_compiled_code_in_ArtMethod),
|
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
|
newEntrypoint
|
||||||
);
|
);
|
||||||
if (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,
|
&newEntrypoint,
|
||||||
pointer_size);
|
pointer_size);
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -198,69 +174,46 @@ static int doBackupAndHook(JNIEnv *env, void *targetMethod, void *hookMethod, vo
|
||||||
}
|
}
|
||||||
|
|
||||||
if (OFFSET_entry_point_from_interpreter_in_ArtMethod != 0) {
|
if (OFFSET_entry_point_from_interpreter_in_ArtMethod != 0) {
|
||||||
memcpy((char *) targetMethod + OFFSET_entry_point_from_interpreter_in_ArtMethod,
|
memcpy((char *) fromMethod + OFFSET_entry_point_from_interpreter_in_ArtMethod,
|
||||||
(char *) hookMethod + OFFSET_entry_point_from_interpreter_in_ArtMethod,
|
(char *) toMethod + OFFSET_entry_point_from_interpreter_in_ArtMethod,
|
||||||
pointer_size);
|
pointer_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
// set the target method to native so that Android O wouldn't invoke it with interpreter
|
// set the target method to native so that Android O wouldn't invoke it with interpreter
|
||||||
if (SDKVersion >= __ANDROID_API_O__) {
|
if (SDKVersion >= __ANDROID_API_O__) {
|
||||||
setNativeFlag(targetMethod, true);
|
setNativeFlag(fromMethod, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
LOGI("hook and backup done");
|
|
||||||
hookCount += 1;
|
hookCount += 1;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ensureMethodCached(void *hookMethod, void *backupMethod,
|
static int doBackupAndHook(void *targetMethod, void *hookMethod, void *backupMethod) {
|
||||||
void *hookClassResolvedMethods) {
|
LOGI("target method is at %p, hook method is at %p, backup method is at %p",
|
||||||
if (!backupMethod) {
|
targetMethod, hookMethod, 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));
|
|
||||||
|
|
||||||
// todo fixme
|
int res = 0;
|
||||||
if (methodIndex >= 512) {
|
|
||||||
LOGW("methodIndex = %d", methodIndex);
|
// 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
|
if (backupMethod) {// do method backup
|
||||||
// first we find the array of cached methods
|
// we use the same way as hooking target method
|
||||||
dexCacheResolvedMethods = hookClassResolvedMethods;
|
// hook backup method and redirect back to the original target method
|
||||||
|
// the only difference is that the entry point is now hardcoded
|
||||||
if (!dexCacheResolvedMethods) {
|
// instead of reading from ArtMethod struct since it's overwritten
|
||||||
LOGE("dexCacheResolvedMethods is null");
|
res += replaceMethod(backupMethod, targetMethod, 1);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// finally the addr of backup method is put at the corresponding location in cached methods array
|
res += replaceMethod(targetMethod, hookMethod, 0);
|
||||||
if (SDKVersion >= __ANDROID_API_O_MR1__) {
|
|
||||||
// array of MethodDexCacheType is used as dexCacheResolvedMethods in Android 8.1
|
LOGI("hook and backup done");
|
||||||
// struct:
|
return res;
|
||||||
// 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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void *getArtMethod(JNIEnv *env, jobject jmethod) {
|
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 target, jobject hook,
|
||||||
jobject backup) {
|
jobject backup) {
|
||||||
|
|
||||||
if (!doBackupAndHook(env,
|
if (!doBackupAndHook(getArtMethod(env, target),
|
||||||
getArtMethod(env, target),
|
|
||||||
getArtMethod(env, hook),
|
getArtMethod(env, hook),
|
||||||
getArtMethod(env, backup)
|
getArtMethod(env, backup)
|
||||||
)) {
|
)) {
|
||||||
(*env)->NewGlobalRef(env,
|
(*env)->NewGlobalRef(env, hook); // keep a global ref so that the hook method would not be GCed
|
||||||
hook); // keep a global ref so that the hook method would not be GCed
|
|
||||||
if (backup) (*env)->NewGlobalRef(env, backup);
|
if (backup) (*env)->NewGlobalRef(env, backup);
|
||||||
return JNI_TRUE;
|
return JNI_TRUE;
|
||||||
} else {
|
} 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) {
|
static void *getResolvedMethodsAddr(JNIEnv *env, jobject hook) {
|
||||||
// get backup class
|
// get backup class
|
||||||
jclass methodClass = (*env)->FindClass(env, "java/lang/reflect/Method");
|
jclass methodClass = (*env)->FindClass(env, "java/lang/reflect/Method");
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,8 @@
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "trampoline.h"
|
#include "trampoline.h"
|
||||||
|
|
||||||
|
#define MAX(a, b) ((a) > (b) ? (a) : (b))
|
||||||
|
|
||||||
static unsigned char *trampolineCode; // place where trampolines are saved
|
static unsigned char *trampolineCode; // place where trampolines are saved
|
||||||
static unsigned int trampolineSize; // trampoline size required for each hook
|
static unsigned int trampolineSize; // trampoline size required for each hook
|
||||||
|
|
||||||
|
|
@ -21,8 +23,13 @@ unsigned int hookCap = 0;
|
||||||
unsigned int hookCount = 0;
|
unsigned int hookCount = 0;
|
||||||
|
|
||||||
// trampoline:
|
// 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
|
// 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__)
|
#if defined(__i386__)
|
||||||
// b8 78 56 34 12 ; mov eax, 0x12345678 (addr of the hook method)
|
// b8 78 56 34 12 ; mov eax, 0x12345678 (addr of the hook method)
|
||||||
// ff 70 20 ; push DWORD PTR [eax + 0x20]
|
// ff 70 20 ; push DWORD PTR [eax + 0x20]
|
||||||
|
|
@ -33,6 +40,15 @@ unsigned char trampoline[] = {
|
||||||
0xc3
|
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__)
|
#elif defined(__x86_64__)
|
||||||
// 48 bf 78 56 34 12 78 56 34 12 ; movabs rdi, 0x1234567812345678
|
// 48 bf 78 56 34 12 78 56 34 12 ; movabs rdi, 0x1234567812345678
|
||||||
// ff 77 20 ; push QWORD PTR [rdi + 0x20]
|
// ff 77 20 ; push QWORD PTR [rdi + 0x20]
|
||||||
|
|
@ -43,6 +59,17 @@ unsigned char trampoline[] = {
|
||||||
0xc3
|
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__)
|
#elif defined(__arm__)
|
||||||
// 00 00 9F E5 ; ldr r0, [pc, #0]
|
// 00 00 9F E5 ; ldr r0, [pc, #0]
|
||||||
// 20 F0 90 E5 ; ldr pc, [r0, 0x20]
|
// 20 F0 90 E5 ; ldr pc, [r0, 0x20]
|
||||||
|
|
@ -53,6 +80,21 @@ unsigned char trampoline[] = {
|
||||||
0x78, 0x56, 0x34, 0x12
|
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__)
|
#elif defined(__aarch64__)
|
||||||
// 60 00 00 58 ; ldr x0, 12
|
// 60 00 00 58 ; ldr x0, 12
|
||||||
// 10 00 40 F8 ; ldr x16, [x0, #0x00]
|
// 10 00 40 F8 ; ldr x16, [x0, #0x00]
|
||||||
|
|
@ -66,28 +108,74 @@ unsigned char trampoline[] = {
|
||||||
0x78, 0x56, 0x34, 0x12,
|
0x78, 0x56, 0x34, 0x12,
|
||||||
0x89, 0x67, 0x45, 0x23
|
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
|
#endif
|
||||||
static unsigned int trampolineSize = roundUpToPtrSize(sizeof(trampoline));
|
static unsigned int trampolineSize = roundUpToPtrSize(MAX(sizeof(trampoline), sizeof(trampolineForBackup)));
|
||||||
|
|
||||||
void *genTrampoline(void *hookMethod) {
|
void *genTrampoline(void *toMethod, void *entrypoint) {
|
||||||
void *targetAddr;
|
unsigned char *targetAddr = trampolineCode + trampolineSize * hookCount;
|
||||||
|
|
||||||
targetAddr = trampolineCode + trampolineSize * hookCount;
|
if(entrypoint != NULL) {
|
||||||
memcpy(targetAddr, trampoline,
|
memcpy(targetAddr, trampolineForBackup, sizeof(trampolineForBackup));
|
||||||
sizeof(trampoline)); // do not use trampolineSize since it's a rounded size
|
}
|
||||||
|
else {
|
||||||
|
memcpy(targetAddr, trampoline,
|
||||||
|
sizeof(trampoline)); // do not use trampolineSize since it's a rounded size
|
||||||
|
}
|
||||||
|
|
||||||
// replace with the actual ArtMethod addr
|
// replace with the actual ArtMethod addr
|
||||||
#if defined(__i386__)
|
#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__)
|
#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__)
|
#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__)
|
#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
|
#else
|
||||||
#error Unsupported architecture
|
#error Unsupported architecture
|
||||||
|
|
@ -96,18 +184,16 @@ void *genTrampoline(void *hookMethod) {
|
||||||
return targetAddr;
|
return targetAddr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setupTrampoline() {
|
void setupTrampoline(uint8_t offset) {
|
||||||
#if defined(__i386__)
|
#if defined(__i386__)
|
||||||
trampoline[7] = (unsigned char)OFFSET_entry_point_from_quick_compiled_code_in_ArtMethod;
|
trampoline[7] = offset;
|
||||||
#elif defined(__x86_64__)
|
#elif defined(__x86_64__)
|
||||||
trampoline[12] = (unsigned char)OFFSET_entry_point_from_quick_compiled_code_in_ArtMethod;
|
trampoline[12] = offset;
|
||||||
#elif defined(__arm__)
|
#elif defined(__arm__)
|
||||||
trampoline[4] = (unsigned char)OFFSET_entry_point_from_quick_compiled_code_in_ArtMethod;
|
trampoline[4] = offset;
|
||||||
#elif defined(__aarch64__)
|
#elif defined(__aarch64__)
|
||||||
trampoline[5] |=
|
trampoline[5] |= offset << 4;
|
||||||
((unsigned char) OFFSET_entry_point_from_quick_compiled_code_in_ArtMethod) << 4;
|
trampoline[6] |= offset >> 4;
|
||||||
trampoline[6] |=
|
|
||||||
((unsigned char) OFFSET_entry_point_from_quick_compiled_code_in_ArtMethod) >> 4;
|
|
||||||
#else
|
#else
|
||||||
#error Unsupported architecture
|
#error Unsupported architecture
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,6 @@
|
||||||
#define YAHFA_TAMPOLINE_H
|
#define YAHFA_TAMPOLINE_H
|
||||||
|
|
||||||
extern int SDKVersion;
|
extern int SDKVersion;
|
||||||
extern int OFFSET_entry_point_from_quick_compiled_code_in_ArtMethod;
|
|
||||||
|
|
||||||
extern unsigned int hookCap; // capacity for trampolines
|
extern unsigned int hookCap; // capacity for trampolines
|
||||||
extern unsigned int hookCount; // current count of used 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[];
|
extern unsigned char trampoline[];
|
||||||
|
|
||||||
int doInitHookCap(unsigned int cap);
|
int doInitHookCap(unsigned int cap);
|
||||||
void setupTrampoline();
|
void setupTrampoline(uint8_t offset);
|
||||||
void *genTrampoline(void *hookMethod);
|
void *genTrampoline(void *toMethod, void *entrypoint);
|
||||||
|
|
||||||
#define DEFAULT_CAP 1 //size of each trampoline area would be no more than 4k Bytes(one page)
|
#define DEFAULT_CAP 1 //size of each trampoline area would be no more than 4k Bytes(one page)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -344,6 +344,7 @@ namespace edxp {
|
||||||
[](auto i) {
|
[](auto i) {
|
||||||
return GetFrameworkPath(i);
|
return GetFrameworkPath(i);
|
||||||
});
|
});
|
||||||
|
LOGI("Got base config path: %s", misc_path_.c_str());
|
||||||
} catch (const RirudSocket::RirudSocketException &e) {
|
} catch (const RirudSocket::RirudSocketException &e) {
|
||||||
LOGE("%s", e.what());
|
LOGE("%s", e.what());
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -22,10 +22,6 @@ namespace edxp {
|
||||||
return Java_lab_galaxy_yahfa_HookMain_backupAndHookNative(env, clazz, target, hook, backup);
|
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) {
|
static void Yahfa_setMethodNonCompilable(JNI_START, jobject member) {
|
||||||
if (!member) {
|
if (!member) {
|
||||||
LOGE("setNonCompilableNative: member is null");
|
LOGE("setNonCompilableNative: member is null");
|
||||||
|
|
@ -59,8 +55,6 @@ namespace edxp {
|
||||||
"(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;)Ljava/lang/Object;"),
|
"(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;)Ljava/lang/Object;"),
|
||||||
NATIVE_METHOD(Yahfa, backupAndHookNative,
|
NATIVE_METHOD(Yahfa, backupAndHookNative,
|
||||||
"(Ljava/lang/Object;Ljava/lang/reflect/Method;Ljava/lang/reflect/Method;)Z"),
|
"(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, setMethodNonCompilable, "(Ljava/lang/reflect/Member;)V"),
|
||||||
NATIVE_METHOD(Yahfa, setNativeFlag, "(Ljava/lang/reflect/Member;Z)Z"),
|
NATIVE_METHOD(Yahfa, setNativeFlag, "(Ljava/lang/reflect/Member;Z)Z"),
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -169,5 +169,5 @@ chcon -R u:object_r:system_file:s0 "${MODDIR}"
|
||||||
chcon -R ${PATH_CONTEXT} "${LOG_PATH}"
|
chcon -R ${PATH_CONTEXT} "${LOG_PATH}"
|
||||||
chown -R ${PATH_OWNER} "${LOG_PATH}"
|
chown -R ${PATH_OWNER} "${LOG_PATH}"
|
||||||
chmod -R 666 "${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
|
rm -f /data/adb/edxp/new_install
|
||||||
|
|
@ -6,7 +6,6 @@ import com.elderdrivers.riru.edxp.core.BaseEdxpImpl;
|
||||||
import com.elderdrivers.riru.edxp.core.EdxpImpl;
|
import com.elderdrivers.riru.edxp.core.EdxpImpl;
|
||||||
import com.elderdrivers.riru.edxp.core.Main;
|
import com.elderdrivers.riru.edxp.core.Main;
|
||||||
import com.elderdrivers.riru.edxp.core.Yahfa;
|
import com.elderdrivers.riru.edxp.core.Yahfa;
|
||||||
import com.elderdrivers.riru.edxp.core.yahfa.HookMethodResolver;
|
|
||||||
import com.swift.sandhook.xposedcompat.methodgen.SandHookXposedBridge;
|
import com.swift.sandhook.xposedcompat.methodgen.SandHookXposedBridge;
|
||||||
|
|
||||||
public class SandHookEdxpImpl extends BaseEdxpImpl {
|
public class SandHookEdxpImpl extends BaseEdxpImpl {
|
||||||
|
|
@ -32,7 +31,6 @@ public class SandHookEdxpImpl extends BaseEdxpImpl {
|
||||||
@Override
|
@Override
|
||||||
public void init() {
|
public void init() {
|
||||||
Yahfa.init(Build.VERSION.SDK_INT);
|
Yahfa.init(Build.VERSION.SDK_INT);
|
||||||
HookMethodResolver.init();
|
|
||||||
getRouter().injectConfig();
|
getRouter().injectConfig();
|
||||||
SandHookXposedBridge.init();
|
SandHookXposedBridge.init();
|
||||||
setInitialized();
|
setInitialized();
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,5 @@
|
||||||
package com.elderdrivers.riru.edxp.service;
|
package com.elderdrivers.riru.edxp.service;
|
||||||
|
|
||||||
import android.accounts.Account;
|
|
||||||
import android.accounts.AccountManager;
|
|
||||||
import android.annotation.SuppressLint;
|
import android.annotation.SuppressLint;
|
||||||
import android.app.ActivityThread;
|
import android.app.ActivityThread;
|
||||||
import android.content.BroadcastReceiver;
|
import android.content.BroadcastReceiver;
|
||||||
|
|
@ -98,9 +96,11 @@ public class PackageReceiver {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateModuleList(int uid) {
|
private void updateModuleList(int uid, String packageName) {
|
||||||
Map<String, String> enabledModules = loadEnabledModules(uid);
|
Map<String, String> enabledModules = loadEnabledModules(uid);
|
||||||
|
|
||||||
|
if(packageName != null && !enabledModules.containsKey(packageName)) return;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
File moduleListFile = new File(CONFIG_PATH, uid + "/" + MODULES_LIST_FILENAME);
|
File moduleListFile = new File(CONFIG_PATH, uid + "/" + MODULES_LIST_FILENAME);
|
||||||
moduleListFile.createNewFile();
|
moduleListFile.createNewFile();
|
||||||
|
|
@ -155,7 +155,7 @@ public class PackageReceiver {
|
||||||
for (Object uh : (List<Object>) m.invoke(um)) {
|
for (Object uh : (List<Object>) m.invoke(um)) {
|
||||||
int uid = (int) uh.getClass().getDeclaredField("id").get(uh);
|
int uid = (int) uh.getClass().getDeclaredField("id").get(uh);
|
||||||
Utils.logI("updating uid: " + uid);
|
Utils.logI("updating uid: " + uid);
|
||||||
updateModuleList(uid);
|
updateModuleList(uid, pkgInfo == null ? null : packageName);
|
||||||
}
|
}
|
||||||
Toast.makeText(context, "EdXposed: Updated " + packageName, Toast.LENGTH_SHORT).show();
|
Toast.makeText(context, "EdXposed: Updated " + packageName, Toast.LENGTH_SHORT).show();
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,6 @@ import com.elderdrivers.riru.edxp.core.EdxpImpl;
|
||||||
import com.elderdrivers.riru.edxp.core.Main;
|
import com.elderdrivers.riru.edxp.core.Main;
|
||||||
import com.elderdrivers.riru.edxp.core.Proxy;
|
import com.elderdrivers.riru.edxp.core.Proxy;
|
||||||
import com.elderdrivers.riru.edxp.core.Yahfa;
|
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.NormalProxy;
|
||||||
import com.elderdrivers.riru.edxp.proxy.Router;
|
import com.elderdrivers.riru.edxp.proxy.Router;
|
||||||
|
|
||||||
|
|
@ -29,7 +28,6 @@ public class YahfaEdxpImpl extends BaseEdxpImpl {
|
||||||
@Override
|
@Override
|
||||||
public void init() {
|
public void init() {
|
||||||
Yahfa.init(Build.VERSION.SDK_INT);
|
Yahfa.init(Build.VERSION.SDK_INT);
|
||||||
HookMethodResolver.init();
|
|
||||||
getRouter().injectConfig();
|
getRouter().injectConfig();
|
||||||
setInitialized();
|
setInitialized();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue