Skip to content

Commit

Permalink
Revert YAHFA to fix OatQuickMethodHeader soft reboot issue
Browse files Browse the repository at this point in the history
Co-Authored-By: LoveSy <shana@zju.edu.cn>
  • Loading branch information
MlgmXyysd and LoveSy committed Feb 7, 2021
1 parent eadb07f commit 235ee81
Show file tree
Hide file tree
Showing 23 changed files with 566 additions and 993 deletions.
Expand Up @@ -12,7 +12,7 @@ public class Yahfa {

public static native void init(int sdkVersion);

public static native void setMethodNonCompilable(Member member);
// public static native void setMethodNonCompilable(Member member);

public static native void recordHooked(Member member);

Expand Down
Expand Up @@ -2,7 +2,6 @@

import com.elderdrivers.riru.edxp.art.Heap;
import com.elderdrivers.riru.edxp.core.Yahfa;
import com.elderdrivers.riru.edxp.util.ClassUtils;
import com.elderdrivers.riru.edxp.util.Utils;

import java.lang.reflect.Constructor;
Expand All @@ -11,89 +10,7 @@
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;

import de.robv.android.xposed.XposedHelpers;

public class HookMain {

private static final Set<String> hookItemWhiteList = new HashSet<String>();

public static void addHookItemWhiteList(String className) {
hookItemWhiteList.add(className);
}

public static void doHookDefault(ClassLoader patchClassLoader, ClassLoader originClassLoader, String hookInfoClassName) {
try {
Class<?> hookInfoClass = Class.forName(hookInfoClassName, true, patchClassLoader);
String[] hookItemNames = (String[]) hookInfoClass.getField("hookItemNames").get(null);
for (String hookItemName : hookItemNames) {
doHookItemDefault(patchClassLoader, hookItemName, originClassLoader);
}
} catch (Throwable e) {
Utils.logE("error when hooking all in: " + hookInfoClassName, e);
}
}

private static void doHookItemDefault(ClassLoader patchClassLoader, String hookItemName, ClassLoader originClassLoader) {
try {
Utils.logD("Start hooking with item " + hookItemName);
Class<?> hookItem = Class.forName(hookItemName, true, patchClassLoader);

String className = (String) hookItem.getField("className").get(null);
String methodName = (String) hookItem.getField("methodName").get(null);
String methodSig = (String) hookItem.getField("methodSig").get(null);

if (className == null || className.equals("")) {
Utils.logW("No target class. Skipping...");
return;
}
Class<?> clazz = null;
try {
clazz = Class.forName(className, true, originClassLoader);
} catch (ClassNotFoundException cnfe) {
Utils.logE(className + " not found in " + originClassLoader);
return;
}
if (Modifier.isAbstract(clazz.getModifiers())) {
Utils.logW("Hook may fail for abstract class: " + className);
}

Method hook = null;
Method backup = null;
for (Method method : hookItem.getDeclaredMethods()) {
if (method.getName().equals("hook") && Modifier.isStatic(method.getModifiers())) {
hook = method;
} else if (method.getName().equals("backup") && Modifier.isStatic(method.getModifiers())) {
backup = method;
}
}
if (hook == null) {
Utils.logE("Cannot find hook for " + methodName);
return;
}
findAndBackupAndHook(clazz, methodName, methodSig, hook, backup);
} catch (Throwable e) {
if (!hookItemWhiteList.contains(hookItemName)) {
Utils.logE("error when hooking " + hookItemName, e);
}
}
}

public static void findAndHook(Class targetClass, String methodName, String methodSig, Method hook) {
hook(findMethod(targetClass, methodName, methodSig), hook);
}

public static void findAndBackupAndHook(Class targetClass, String methodName, String methodSig,
Method hook, Method backup) {
backupAndHook(findMethod(targetClass, methodName, methodSig), hook, backup);
}

public static void hook(Member target, Method hook) {
backupAndHook(target, hook, null);
}

public static void backupAndHook(Member target, Method hook, Method backup) {
Utils.logD(String.format("target=%s, hook=%s, backup=%s", target, hook, backup));
if (target == null) {
Expand All @@ -106,13 +23,13 @@ public static void backupAndHook(Member target, Method hook, Method backup) {
if (!Modifier.isStatic(hook.getModifiers())) {
throw new IllegalArgumentException("Hook must be a static method: " + hook);
}
checkCompatibleMethods(target, hook, "Original", "Hook");
checkCompatibleMethods(target, hook, "Hook");
if (backup != null) {
if (!Modifier.isStatic(backup.getModifiers())) {
throw new IllegalArgumentException("Backup must be a static method: " + backup);
}
// backup is just a placeholder and the constraint could be less strict
checkCompatibleMethods(target, backup, "Original", "Backup");
checkCompatibleMethods(target, backup, "Backup");
}
// make sure GC completed before hook
int lastGcType = Heap.waitForGcToComplete();
Expand All @@ -121,28 +38,15 @@ public static void backupAndHook(Member target, Method hook, Method backup) {
Runtime.getRuntime().gc();
}

if (!Yahfa.backupAndHookNative(target, hook, backup)) {
if(!Yahfa.backupAndHookNative(target, hook, backup)){
throw new RuntimeException("Failed to hook " + target + " with " + hook);
} else {
Yahfa.recordHooked(target);
Yahfa.recordHooked(backup);
}
}

public static Member findMethod(Class cls, String methodName, String methodSig) {
if (cls == null) {
throw new IllegalArgumentException("null class");
}
if (methodName == null) {
throw new IllegalArgumentException("null method name");
}
if (methodSig == null) {
throw new IllegalArgumentException("null method signature");
// Yahfa.recordHooked(backup);
}
return Yahfa.findMethodNative(cls, methodName, methodSig);
}

private static void checkCompatibleMethods(Object original, Method replacement, String originalName, String replacementName) {
private static void checkCompatibleMethods(Object original, Method replacement, String replacementName) {
ArrayList<Class<?>> originalParams;
if (original instanceof Method) {
originalParams = new ArrayList<>(Arrays.asList(((Method) original).getParameterTypes()));
Expand All @@ -168,20 +72,20 @@ private static void checkCompatibleMethods(Object original, Method replacement,

if (original instanceof Method
&& !replacement.getReturnType().isAssignableFrom(((Method) original).getReturnType())) {
throw new IllegalArgumentException("Incompatible return types. " + originalName + ": " + ((Method) original).getReturnType() + ", " + replacementName + ": " + replacement.getReturnType());
throw new IllegalArgumentException("Incompatible return types. " + "Original" + ": " + ((Method) original).getReturnType() + ", " + replacementName + ": " + replacement.getReturnType());
} else if (original instanceof Constructor) {
if (replacement.getReturnType().equals(Void.class)) {
throw new IllegalArgumentException("Incompatible return types. " + "<init>" + ": " + "V" + ", " + replacementName + ": " + replacement.getReturnType());
}
}

if (originalParams.size() != replacementParams.size()) {
throw new IllegalArgumentException("Number of arguments don't match. " + originalName + ": " + originalParams.size() + ", " + replacementName + ": " + replacementParams.size());
throw new IllegalArgumentException("Number of arguments don't match. " + "Original" + ": " + originalParams.size() + ", " + replacementName + ": " + replacementParams.size());
}

for (int i = 0; i < originalParams.size(); i++) {
if (!replacementParams.get(i).isAssignableFrom(originalParams.get(i))) {
throw new IllegalArgumentException("Incompatible argument #" + i + ": " + originalName + ": " + originalParams.get(i) + ", " + replacementName + ": " + replacementParams.get(i));
throw new IllegalArgumentException("Incompatible argument #" + i + ": " + "Original" + ": " + originalParams.get(i) + ", " + replacementName + ": " + replacementParams.get(i));
}
}
}
Expand Down
Expand Up @@ -32,8 +32,6 @@ public abstract class BaseRouter implements Router {

protected volatile AtomicBoolean bootstrapHooked = new AtomicBoolean(false);

protected static boolean useXposedApi = false;

public void initResourcesHook() {
XposedBridge.initXResources();
}
Expand Down Expand Up @@ -81,49 +79,27 @@ public String parsePackageName(String appDataDir) {
public void startBootstrapHook(boolean isSystem) {
Utils.logD("startBootstrapHook starts: isSystem = " + isSystem);
ClassLoader classLoader = BaseRouter.class.getClassLoader();
if (useXposedApi) {
if (isSystem) {
XposedHelpers.findAndHookMethod(SystemMainHooker.className, classLoader,
SystemMainHooker.methodName, new SystemMain());
}
XposedHelpers.findAndHookMethod(HandleBindAppHooker.className, classLoader,
HandleBindAppHooker.methodName,
"android.app.ActivityThread$AppBindData",
new HandleBindApp());
XposedHelpers.findAndHookConstructor(LoadedApkConstructorHooker.className, classLoader,
ActivityThread.class, ApplicationInfo.class, CompatibilityInfo.class,
ClassLoader.class, boolean.class, boolean.class, boolean.class,
new LoadedApkCstr());
} else {
if (isSystem) {
HookMain.doHookDefault(
BaseRouter.class.getClassLoader(),
classLoader,
SysBootstrapHookInfo.class.getName());
} else {
HookMain.doHookDefault(
BaseRouter.class.getClassLoader(),
classLoader,
AppBootstrapHookInfo.class.getName());
}
if (isSystem) {
XposedHelpers.findAndHookMethod(SystemMainHooker.className, classLoader,
SystemMainHooker.methodName, new SystemMain());
}
XposedHelpers.findAndHookMethod(HandleBindAppHooker.className, classLoader,
HandleBindAppHooker.methodName,
"android.app.ActivityThread$AppBindData",
new HandleBindApp());
XposedHelpers.findAndHookConstructor(LoadedApkConstructorHooker.className, classLoader,
ActivityThread.class, ApplicationInfo.class, CompatibilityInfo.class,
ClassLoader.class, boolean.class, boolean.class, boolean.class,
new LoadedApkCstr());
}

public void startSystemServerHook() {
ClassLoader classLoader = BaseRouter.class.getClassLoader();
if (useXposedApi) {
StartBootstrapServices sbsHooker = new StartBootstrapServices();
Object[] paramTypesAndCallback = Versions.hasR() ?
new Object[]{"com.android.server.utils.TimingsTraceAndSlog", sbsHooker} :
new Object[]{sbsHooker};
XposedHelpers.findAndHookMethod(StartBootstrapServicesHooker.className,
SystemMain.systemServerCL,
StartBootstrapServicesHooker.methodName, paramTypesAndCallback);
} else {
HookMain.doHookDefault(
classLoader,
SystemMain.systemServerCL,
SysInnerHookInfo.class.getName());
}
StartBootstrapServices sbsHooker = new StartBootstrapServices();
Object[] paramTypesAndCallback = Versions.hasR() ?
new Object[]{"com.android.server.utils.TimingsTraceAndSlog", sbsHooker} :
new Object[]{sbsHooker};
XposedHelpers.findAndHookMethod(StartBootstrapServicesHooker.className,
SystemMain.systemServerCL,
StartBootstrapServicesHooker.methodName, paramTypesAndCallback);
}
}
Expand Up @@ -41,9 +41,9 @@ private void forkPostCommon(int pid, boolean isSystem, String appDataDir, String
mRouter.initResourcesHook();
mRouter.prepare(isSystem);
PrebuiltMethodsDeopter.deoptBootMethods(); // do it once for secondary zygote
mRouter.installBootstrapHooks(isSystem);
ConfigManager.appDataDir = appDataDir;
ConfigManager.niceName = niceName;
mRouter.installBootstrapHooks(isSystem);
XposedInit.prefsBasePath = ConfigManager.getPrefsPath("");
mRouter.onEnterChildProcess();
Utils.logI("Loading modules for " + niceName);
Expand Down
Expand Up @@ -72,6 +72,6 @@ public static String getPackageName(String dataDir) {
}

public static String getDataPathPrefix() {
return ConfigManager.getDataPathPrefix();
return ConfigManager.getDataPathPrefix() + "/";
}
}
17 changes: 4 additions & 13 deletions edxp-core/src/main/cpp/external/yahfa/include/HookMain.h
Expand Up @@ -17,21 +17,12 @@ jboolean Java_lab_galaxy_yahfa_HookMain_backupAndHookNative(JNIEnv *env, jclass
jobject target, jobject hook,
jobject backup);

void Java_lab_galaxy_yahfa_HookMain_ensureMethodCached(JNIEnv *env, jclass clazz,
jobject hook,
jobject backup);
#ifdef __cplusplus
}
#endif
void setNonCompilable(void *method);

void *getArtMethod(JNIEnv *env, jobject jmethod);

// TODO: move to common utils instead of in YAHFA's code
void *getEntryPoint(void* method);

// get original entrypoint from target ArtMethod
void *getOriginalEntryPointFromTargetMethod(void* method);

#ifdef __cplusplus
}
#endif

#endif // HOOK_MAIN_H
#endif // HOOK_MAIN_H
13 changes: 9 additions & 4 deletions edxp-core/src/main/cpp/external/yahfa/include/trampoline.h
Expand Up @@ -6,12 +6,17 @@
#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

extern unsigned char trampoline[];
extern unsigned char trampolineForBackup[];

void* doInitHookCap(size_t cap);
void setupTrampoline(uint8_t offset);
void *genTrampoline(void *toMethod, void *entrypoint);
int doInitHookCap(unsigned int cap);
void setupTrampoline();
void *genTrampoline(void *hookMethod);

#define DEFAULT_CAP 1 //size of each trampoline area would be no more than 4k Bytes(one page)

#endif //YAHFA_TAMPOLINE_H

0 comments on commit 235ee81

Please sign in to comment.