This commit is contained in:
Shauli Bracha 2019-02-28 18:49:05 +02:00
commit 57fd982979
14 changed files with 235 additions and 56 deletions

View File

@ -34,36 +34,32 @@ public class Main implements KeepAll {
int[][] rlimits, int mountExternal, String seInfo, int[][] rlimits, int mountExternal, String seInfo,
String niceName, int[] fdsToClose, int[] fdsToIgnore, String niceName, int[] fdsToClose, int[] fdsToIgnore,
boolean startChildZygote, String instructionSet, boolean startChildZygote, String instructionSet,
String appDataDir, boolean isBlackWhiteListMode, String appDataDir) {
boolean isDynamicModulesMode) {
if (BuildConfig.DEBUG) { if (BuildConfig.DEBUG) {
forkAndSpecializePramsStr = String.format( forkAndSpecializePramsStr = String.format(
"Zygote#forkAndSpecialize(%d, %d, %s, %d, %s, %d, %s, %s, %s, %s, %s, %s, %s)", "Zygote#forkAndSpecialize(%d, %d, %s, %d, %s, %d, %s, %s, %s, %s, %s, %s, %s)",
uid, gid, Arrays.toString(gids), debugFlags, Arrays.toString(rlimits), uid, gid, Arrays.toString(gids), debugFlags, Arrays.toString(rlimits),
mountExternal, seInfo, niceName, Arrays.toString(fdsToClose), mountExternal, seInfo, niceName, Arrays.toString(fdsToClose),
Arrays.toString(fdsToIgnore), startChildZygote, instructionSet, appDataDir, Arrays.toString(fdsToIgnore), startChildZygote, instructionSet, appDataDir);
isDynamicModulesMode);
} }
if (isBlackWhiteListMode) { if (isBlackWhiteListEnabled()) {
BlackWhiteListProxy.forkAndSpecializePre(uid, gid, gids, debugFlags, rlimits, BlackWhiteListProxy.forkAndSpecializePre(uid, gid, gids, debugFlags, rlimits,
mountExternal, seInfo, niceName, fdsToClose, fdsToIgnore, startChildZygote, mountExternal, seInfo, niceName, fdsToClose, fdsToIgnore, startChildZygote,
instructionSet, appDataDir, isDynamicModulesMode); instructionSet, appDataDir);
} else { } else {
NormalProxy.forkAndSpecializePre(uid, gid, gids, debugFlags, rlimits, mountExternal, NormalProxy.forkAndSpecializePre(uid, gid, gids, debugFlags, rlimits, mountExternal,
seInfo, niceName, fdsToClose, fdsToIgnore, startChildZygote, instructionSet, seInfo, niceName, fdsToClose, fdsToIgnore, startChildZygote, instructionSet,
appDataDir, isDynamicModulesMode); appDataDir);
} }
} }
public static void forkAndSpecializePost(int pid, String appDataDir, public static void forkAndSpecializePost(int pid, String appDataDir) {
boolean isBlackWhiteListMode,
boolean isDynamicModulesMode) {
if (pid == 0) { if (pid == 0) {
Utils.logD(forkAndSpecializePramsStr + " = " + Process.myPid()); Utils.logD(forkAndSpecializePramsStr + " = " + Process.myPid());
if (isBlackWhiteListMode) { if (isBlackWhiteListEnabled()) {
BlackWhiteListProxy.forkAndSpecializePost(pid, appDataDir, isDynamicModulesMode); BlackWhiteListProxy.forkAndSpecializePost(pid, appDataDir);
} else { } else {
NormalProxy.forkAndSpecializePost(pid, appDataDir, isDynamicModulesMode); NormalProxy.forkAndSpecializePost(pid, appDataDir);
} }
} else { } else {
// in zygote process, res is child zygote pid // in zygote process, res is child zygote pid
@ -72,30 +68,28 @@ public class Main implements KeepAll {
} }
public static void forkSystemServerPre(int uid, int gid, int[] gids, int debugFlags, int[][] rlimits, public static void forkSystemServerPre(int uid, int gid, int[] gids, int debugFlags, int[][] rlimits,
long permittedCapabilities, long effectiveCapabilities, long permittedCapabilities, long effectiveCapabilities) {
boolean isBlackWhiteListMode, boolean isDynamicModulesMode) {
if (BuildConfig.DEBUG) { if (BuildConfig.DEBUG) {
forkSystemServerPramsStr = String.format("Zygote#forkSystemServer(%d, %d, %s, %d, %s, %d, %d)", forkSystemServerPramsStr = String.format("Zygote#forkSystemServer(%d, %d, %s, %d, %s, %d, %d)",
uid, gid, Arrays.toString(gids), debugFlags, Arrays.toString(rlimits), uid, gid, Arrays.toString(gids), debugFlags, Arrays.toString(rlimits),
permittedCapabilities, effectiveCapabilities); permittedCapabilities, effectiveCapabilities);
} }
if (isBlackWhiteListMode) { if (isBlackWhiteListEnabled()) {
BlackWhiteListProxy.forkSystemServerPre(uid, gid, gids, debugFlags, rlimits, BlackWhiteListProxy.forkSystemServerPre(uid, gid, gids, debugFlags, rlimits,
permittedCapabilities, effectiveCapabilities, isDynamicModulesMode); permittedCapabilities, effectiveCapabilities);
} else { } else {
NormalProxy.forkSystemServerPre(uid, gid, gids, debugFlags, rlimits, NormalProxy.forkSystemServerPre(uid, gid, gids, debugFlags, rlimits,
permittedCapabilities, effectiveCapabilities, isDynamicModulesMode); permittedCapabilities, effectiveCapabilities);
} }
} }
public static void forkSystemServerPost(int pid, boolean isBlackWhiteListMode, public static void forkSystemServerPost(int pid) {
boolean isDynamicModulesMode) {
if (pid == 0) { if (pid == 0) {
Utils.logD(forkSystemServerPramsStr + " = " + Process.myPid()); Utils.logD(forkSystemServerPramsStr + " = " + Process.myPid());
if (isBlackWhiteListMode) { if (isBlackWhiteListEnabled()) {
BlackWhiteListProxy.forkSystemServerPost(pid, isDynamicModulesMode); BlackWhiteListProxy.forkSystemServerPost(pid);
} else { } else {
NormalProxy.forkSystemServerPost(pid, isDynamicModulesMode); NormalProxy.forkSystemServerPost(pid);
} }
} else { } else {
// in zygote process, res is child zygote pid // in zygote process, res is child zygote pid
@ -118,6 +112,10 @@ public class Main implements KeepAll {
public static native String getInstallerPkgName(); public static native String getInstallerPkgName();
public static native boolean isBlackWhiteListEnabled();
public static native boolean isDynamicModulesEnabled();
// prevent from fatal error caused by holding not whitelisted file descriptors when forking zygote // prevent from fatal error caused by holding not whitelisted file descriptors when forking zygote
// https://github.com/rovo89/Xposed/commit/b3ba245ad04cd485699fb1d2ebde7117e58214ff // https://github.com/rovo89/Xposed/commit/b3ba245ad04cd485699fb1d2ebde7117e58214ff
public static native void closeFilesBeforeForkNative(); public static native void closeFilesBeforeForkNative();
@ -125,4 +123,8 @@ public class Main implements KeepAll {
public static native void reopenFilesAfterForkNative(); public static native void reopenFilesAfterForkNative();
public static native void deoptMethodNative(Object object); public static native void deoptMethodNative(Object object);
public static native long suspendAllThreads();
public static native void resumeAllThreads(long obj);
} }

View File

@ -1,5 +1,6 @@
package com.elderdrivers.riru.xposed.core; package com.elderdrivers.riru.xposed.core;
import com.elderdrivers.riru.xposed.Main;
import com.elderdrivers.riru.xposed.entry.hooker.OnePlusWorkAroundHooker; import com.elderdrivers.riru.xposed.entry.hooker.OnePlusWorkAroundHooker;
import com.elderdrivers.riru.xposed.util.Utils; import com.elderdrivers.riru.xposed.util.Utils;
@ -111,9 +112,14 @@ public class HookMain {
if (backup != null) { if (backup != null) {
HookMethodResolver.resolveMethod(hook, backup); HookMethodResolver.resolveMethod(hook, backup);
} }
long obj = Main.suspendAllThreads();
try {
if (!backupAndHookNative(target, hook, backup)) { if (!backupAndHookNative(target, hook, backup)) {
throw new RuntimeException("Failed to hook " + target + " with " + hook); throw new RuntimeException("Failed to hook " + target + " with " + hook);
} }
} finally {
Main.resumeAllThreads(obj);
}
} }
public static Object findMethod(Class cls, String methodName, String methodSig) { public static Object findMethod(Class cls, String methodName, String methodSig) {

View File

@ -2,15 +2,19 @@ package com.elderdrivers.riru.xposed.entry;
import android.text.TextUtils; import android.text.TextUtils;
import com.elderdrivers.riru.xposed.config.InstallerChooser; import com.elderdrivers.riru.xposed.Main;
import com.elderdrivers.riru.xposed.core.HookMain; import com.elderdrivers.riru.xposed.core.HookMain;
import com.elderdrivers.riru.xposed.entry.bootstrap.AppBootstrapHookInfo; import com.elderdrivers.riru.xposed.entry.bootstrap.AppBootstrapHookInfo;
import com.elderdrivers.riru.xposed.entry.bootstrap.SysBootstrapHookInfo; import com.elderdrivers.riru.xposed.entry.bootstrap.SysBootstrapHookInfo;
import com.elderdrivers.riru.xposed.entry.bootstrap.SysInnerHookInfo; import com.elderdrivers.riru.xposed.entry.bootstrap.SysInnerHookInfo;
import com.elderdrivers.riru.xposed.entry.hooker.SystemMainHooker; import com.elderdrivers.riru.xposed.entry.hooker.SystemMainHooker;
import com.elderdrivers.riru.xposed.util.InlinedMethodCallers;
import com.elderdrivers.riru.xposed.util.Utils; import com.elderdrivers.riru.xposed.util.Utils;
import java.util.Arrays;
import de.robv.android.xposed.XposedBridge; import de.robv.android.xposed.XposedBridge;
import de.robv.android.xposed.XposedHelpers;
import de.robv.android.xposed.XposedInit; import de.robv.android.xposed.XposedInit;
public class Router { public class Router {

View File

@ -4,6 +4,7 @@ import android.app.ActivityThread;
import com.elderdrivers.riru.common.KeepMembers; import com.elderdrivers.riru.common.KeepMembers;
import com.elderdrivers.riru.xposed.entry.Router; import com.elderdrivers.riru.xposed.entry.Router;
import com.elderdrivers.riru.xposed.util.PrebuiltMethodsDeopter;
import de.robv.android.xposed.XposedBridge; import de.robv.android.xposed.XposedBridge;
@ -30,6 +31,8 @@ public class SystemMainHooker implements KeepMembers {
try { try {
// get system_server classLoader // get system_server classLoader
systemServerCL = Thread.currentThread().getContextClassLoader(); systemServerCL = Thread.currentThread().getContextClassLoader();
// deopt methods in SYSTEMSERVERCLASSPATH
PrebuiltMethodsDeopter.deoptSystemServerMethods(systemServerCL);
Router.startSystemServerHook(); Router.startSystemServerHook();
} catch (Throwable t) { } catch (Throwable t) {
logE("error when hooking systemMain", t); logE("error when hooking systemMain", t);

View File

@ -3,6 +3,7 @@ package com.elderdrivers.riru.xposed.proxy.yahfa;
import com.elderdrivers.riru.xposed.Main; import com.elderdrivers.riru.xposed.Main;
import com.elderdrivers.riru.xposed.config.ConfigManager; import com.elderdrivers.riru.xposed.config.ConfigManager;
import com.elderdrivers.riru.xposed.entry.Router; import com.elderdrivers.riru.xposed.entry.Router;
import com.elderdrivers.riru.xposed.util.PrebuiltMethodsDeopter;
import static com.elderdrivers.riru.xposed.util.FileUtils.getDataPathPrefix; import static com.elderdrivers.riru.xposed.util.FileUtils.getDataPathPrefix;
@ -12,16 +13,22 @@ public class BlackWhiteListProxy {
int[][] rlimits, int mountExternal, String seInfo, int[][] rlimits, int mountExternal, String seInfo,
String niceName, int[] fdsToClose, int[] fdsToIgnore, String niceName, int[] fdsToClose, int[] fdsToIgnore,
boolean startChildZygote, String instructionSet, boolean startChildZygote, String instructionSet,
String appDataDir, boolean isDynamicModulesMode) { String appDataDir) {
// always enter here, make sure secondary zygote's modules is loaded only once
// when isDynamicModulesMode is not on
final boolean isDynamicModulesMode = Main.isDynamicModulesEnabled();
ConfigManager.setDynamicModulesMode(isDynamicModulesMode); ConfigManager.setDynamicModulesMode(isDynamicModulesMode);
PrebuiltMethodsDeopter.deoptBootMethods(); // do it once for secondary zygote
if (!isDynamicModulesMode) { if (!isDynamicModulesMode) {
Router.loadModulesSafely(); Router.loadModulesSafely();
Main.closeFilesBeforeForkNative(); Main.closeFilesBeforeForkNative();
} }
} }
public static void forkAndSpecializePost(int pid, String appDataDir, public static void forkAndSpecializePost(int pid, String appDataDir) {
boolean isDynamicModulesMode) { // when this process is in white list or not in black list
// installBootstrapHooks -> loadModules if needed
final boolean isDynamicModulesMode = Main.isDynamicModulesEnabled();
if (!isDynamicModulesMode) { if (!isDynamicModulesMode) {
Main.reopenFilesAfterForkNative(); Main.reopenFilesAfterForkNative();
} }
@ -34,16 +41,25 @@ public class BlackWhiteListProxy {
public static void forkSystemServerPre(int uid, int gid, int[] gids, int debugFlags, public static void forkSystemServerPre(int uid, int gid, int[] gids, int debugFlags,
int[][] rlimits, long permittedCapabilities, int[][] rlimits, long permittedCapabilities,
long effectiveCapabilities, long effectiveCapabilities) {
boolean isDynamicModulesMode) { // we always enter here whether black/white list is on or not
final boolean isDynamicModulesMode = Main.isDynamicModulesEnabled();
ConfigManager.setDynamicModulesMode(isDynamicModulesMode); ConfigManager.setDynamicModulesMode(isDynamicModulesMode);
PrebuiltMethodsDeopter.deoptBootMethods(); // do it once for main zygote
// we never install bootstrap hooks here in black/white list mode
// because installed hooks would be propagated to all child processes of main zygote
// hence we cannot install hooks for processes like com.android.phone process who are
// not from forkAndSpecialize as a side effect
if (!isDynamicModulesMode) { if (!isDynamicModulesMode) {
Router.loadModulesSafely(); Router.loadModulesSafely();
Main.closeFilesBeforeForkNative(); Main.closeFilesBeforeForkNative();
} }
} }
public static void forkSystemServerPost(int pid, boolean isDynamicModulesMode) { public static void forkSystemServerPost(int pid) {
// should only here when system_server is in white list or not in black list
// installBootstrapHooks -> loadModules if needed
final boolean isDynamicModulesMode = Main.isDynamicModulesEnabled();
if (!isDynamicModulesMode) { if (!isDynamicModulesMode) {
Main.reopenFilesAfterForkNative(); Main.reopenFilesAfterForkNative();
} }

View File

@ -4,6 +4,7 @@ import com.elderdrivers.riru.xposed.Main;
import com.elderdrivers.riru.xposed.config.ConfigManager; import com.elderdrivers.riru.xposed.config.ConfigManager;
import com.elderdrivers.riru.xposed.dexmaker.DynamicBridge; import com.elderdrivers.riru.xposed.dexmaker.DynamicBridge;
import com.elderdrivers.riru.xposed.entry.Router; import com.elderdrivers.riru.xposed.entry.Router;
import com.elderdrivers.riru.xposed.util.PrebuiltMethodsDeopter;
import static com.elderdrivers.riru.xposed.util.FileUtils.getDataPathPrefix; import static com.elderdrivers.riru.xposed.util.FileUtils.getDataPathPrefix;
@ -13,9 +14,11 @@ public class NormalProxy {
int[][] rlimits, int mountExternal, String seInfo, int[][] rlimits, int mountExternal, String seInfo,
String niceName, int[] fdsToClose, int[] fdsToIgnore, String niceName, int[] fdsToClose, int[] fdsToIgnore,
boolean startChildZygote, String instructionSet, boolean startChildZygote, String instructionSet,
String appDataDir, boolean isDynamicModulesMode) { String appDataDir) {
final boolean isDynamicModulesMode = Main.isDynamicModulesEnabled();
Main.appDataDir = appDataDir; Main.appDataDir = appDataDir;
ConfigManager.setDynamicModulesMode(isDynamicModulesMode); ConfigManager.setDynamicModulesMode(isDynamicModulesMode);
PrebuiltMethodsDeopter.deoptBootMethods(); // do it once for secondary zygote
Router.prepare(false); Router.prepare(false);
// install bootstrap hooks for secondary zygote // install bootstrap hooks for secondary zygote
Router.installBootstrapHooks(false); Router.installBootstrapHooks(false);
@ -24,7 +27,7 @@ public class NormalProxy {
Main.closeFilesBeforeForkNative(); Main.closeFilesBeforeForkNative();
} }
public static void forkAndSpecializePost(int pid, String appDataDir, boolean isDynamicModulesMode) { public static void forkAndSpecializePost(int pid, String appDataDir) {
// TODO consider processes without forkAndSpecializePost called // TODO consider processes without forkAndSpecializePost called
Main.reopenFilesAfterForkNative(); Main.reopenFilesAfterForkNative();
Router.onEnterChildProcess(); Router.onEnterChildProcess();
@ -34,11 +37,12 @@ public class NormalProxy {
} }
public static void forkSystemServerPre(int uid, int gid, int[] gids, int debugFlags, int[][] rlimits, public static void forkSystemServerPre(int uid, int gid, int[] gids, int debugFlags, int[][] rlimits,
long permittedCapabilities, long effectiveCapabilities, long permittedCapabilities, long effectiveCapabilities) {
boolean isDynamicModulesMode) { final boolean isDynamicModulesMode = Main.isDynamicModulesEnabled();
Main.appDataDir = getDataPathPrefix() + "android"; Main.appDataDir = getDataPathPrefix() + "android";
ConfigManager.setDynamicModulesMode(isDynamicModulesMode); ConfigManager.setDynamicModulesMode(isDynamicModulesMode);
Router.prepare(true); Router.prepare(true);
PrebuiltMethodsDeopter.deoptBootMethods(); // do it once for main zygote
// install bootstrap hooks for main zygote as early as possible // install bootstrap hooks for main zygote as early as possible
// in case we miss some processes not forked via forkAndSpecialize // in case we miss some processes not forked via forkAndSpecialize
// for instance com.android.phone // for instance com.android.phone
@ -50,7 +54,7 @@ public class NormalProxy {
Main.closeFilesBeforeForkNative(); Main.closeFilesBeforeForkNative();
} }
public static void forkSystemServerPost(int pid, boolean isDynamicModulesMode) { public static void forkSystemServerPost(int pid) {
// in system_server process // in system_server process
Main.reopenFilesAfterForkNative(); Main.reopenFilesAfterForkNative();
Router.onEnterChildProcess(); Router.onEnterChildProcess();

View File

@ -0,0 +1,49 @@
package com.elderdrivers.riru.xposed.util;
import java.util.HashMap;
/**
* Providing a whitelist of methods which are the callers of the target methods we want to hook.
* Because the target methods are inlined into the callers, we deoptimize the callers to
* run in intercept mode to make target methods hookable.
* <p>
* Only for methods which are included in pre-compiled framework codes.
* TODO recompile system apps and priv-apps since their original dex files are available
*/
public class InlinedMethodCallers {
public static final String KEY_BOOT_IMAGE = "boot_image";
public static final String KEY_SYSTEM_SERVER = "system_server";
/**
* Key should be {@link #KEY_BOOT_IMAGE}, {@link #KEY_SYSTEM_SERVER}, or a package name
* of system apps or priv-apps i.e. com.android.systemui
*/
private static final HashMap<String, String[][]> CALLERS = new HashMap<>();
/**
* format for each row: {className, methodName, methodSig}
*/
private static final String[][] BOOT_IMAGE = {
// callers of Application#attach(Context)
{"android.app.Instrumentation", "newApplication", "(Ljava/lang/ClassLoader;Ljava/lang/String;Landroid/content/Context;)Landroid/app/Application;"}
};
private static final String[][] SYSTEM_SERVER = {};
private static final String[][] SYSTEM_UI = {};
static {
CALLERS.put(KEY_BOOT_IMAGE, BOOT_IMAGE);
CALLERS.put(KEY_SYSTEM_SERVER, SYSTEM_SERVER);
CALLERS.put("com.android.systemui", SYSTEM_UI);
}
public static HashMap<String, String[][]> getAll() {
return CALLERS;
}
public static String[][] get(String where) {
return CALLERS.get(where);
}
}

View File

@ -0,0 +1,39 @@
package com.elderdrivers.riru.xposed.util;
import com.elderdrivers.riru.xposed.Main;
import java.util.Arrays;
import de.robv.android.xposed.XposedHelpers;
import static com.elderdrivers.riru.xposed.util.InlinedMethodCallers.KEY_BOOT_IMAGE;
import static com.elderdrivers.riru.xposed.util.InlinedMethodCallers.KEY_SYSTEM_SERVER;
public class PrebuiltMethodsDeopter {
public static void deoptMethods(String where, ClassLoader cl) {
String[][] callers = InlinedMethodCallers.get(where);
if (callers == null) {
return;
}
for (String[] caller : callers) {
try {
Object method = Main.findMethodNative(
XposedHelpers.findClass(caller[0], cl), caller[1], caller[2]);
if (method != null) {
Main.deoptMethodNative(method);
}
} catch (Throwable throwable) {
Utils.logE("error when deopting method: " + Arrays.toString(caller), throwable);
}
}
}
public static void deoptBootMethods() {
deoptMethods(KEY_BOOT_IMAGE, null);
}
public static void deoptSystemServerMethods(ClassLoader sysCL) {
deoptMethods(KEY_SYSTEM_SERVER, sysCL);
}
}

View File

@ -2,6 +2,9 @@ package de.robv.android.xposed.callbacks;
import android.os.Bundle; import android.os.Bundle;
import com.elderdrivers.riru.xposed.entry.Router;
import com.elderdrivers.riru.xposed.util.PrebuiltMethodsDeopter;
import java.io.Serializable; import java.io.Serializable;
import de.robv.android.xposed.XposedBridge; import de.robv.android.xposed.XposedBridge;
@ -98,6 +101,14 @@ public abstract class XCallback implements Comparable<XCallback> {
/** @hide */ /** @hide */
public static void callAll(Param param) { public static void callAll(Param param) {
if (param instanceof XC_LoadPackage.LoadPackageParam) {
// deopt methods in system apps or priv-apps, this would be not necessary
// only if we found out how to recompile their apks
XC_LoadPackage.LoadPackageParam lpp = (XC_LoadPackage.LoadPackageParam) param;
PrebuiltMethodsDeopter.deoptMethods(lpp.packageName, lpp.classLoader);
}
if (param.callbacks == null) if (param.callbacks == null)
throw new IllegalStateException("This object was not created for use with callAll"); throw new IllegalStateException("This object was not created for use with callAll");

View File

@ -50,9 +50,8 @@ void onNativeForkSystemServerPre(JNIEnv *env, jclass clazz, uid_t uid, gid_t gid
} }
prepareJavaEnv(env); prepareJavaEnv(env);
// jump to java code // jump to java code
findAndCall(env, "forkSystemServerPre", "(II[II[[IJJZZ)V", uid, gid, gids, runtime_flags, findAndCall(env, "forkSystemServerPre", "(II[II[[IJJ)V", uid, gid, gids, runtime_flags,
rlimits, permittedCapabilities, effectiveCapabilities, rlimits, permittedCapabilities, effectiveCapabilities);
is_black_white_list_mode, is_dynamic_modules_mode);
} }
@ -63,8 +62,7 @@ int onNativeForkSystemServerPost(JNIEnv *env, jclass clazz, jint res) {
} }
prepareJavaEnv(env); prepareJavaEnv(env);
// only do work in child since findAndCall would print log // only do work in child since findAndCall would print log
findAndCall(env, "forkSystemServerPost", "(IZZ)V", res, findAndCall(env, "forkSystemServerPost", "(I)V", res);
is_black_white_list_enabled(), is_dynamic_modules_enabled());
} else { } else {
// in zygote process, res is child zygote pid // in zygote process, res is child zygote pid
// don't print log here, see https://github.com/RikkaApps/Riru/blob/77adfd6a4a6a81bfd20569c910bc4854f2f84f5e/riru-core/jni/main/jni_native_method.cpp#L55-L66 // don't print log here, see https://github.com/RikkaApps/Riru/blob/77adfd6a4a6a81bfd20569c910bc4854f2f84f5e/riru-core/jni/main/jni_native_method.cpp#L55-L66
@ -94,11 +92,10 @@ void onNativeForkAndSpecializePre(JNIEnv *env, jclass clazz,
} }
prepareJavaEnv(env); prepareJavaEnv(env);
findAndCall(env, "forkAndSpecializePre", findAndCall(env, "forkAndSpecializePre",
"(II[II[[IILjava/lang/String;Ljava/lang/String;[I[IZLjava/lang/String;Ljava/lang/String;ZZ)V", "(II[II[[IILjava/lang/String;Ljava/lang/String;[I[IZLjava/lang/String;Ljava/lang/String;)V",
uid, gid, gids, runtime_flags, rlimits, uid, gid, gids, runtime_flags, rlimits,
_mount_external, se_info, se_name, fdsToClose, fdsToIgnore, _mount_external, se_info, se_name, fdsToClose, fdsToIgnore,
is_child_zygote, instructionSet, appDataDir, is_child_zygote, instructionSet, appDataDir);
is_black_white_list_mode, is_dynamic_modules_mode);
} }
int onNativeForkAndSpecializePost(JNIEnv *env, jclass clazz, jint res) { int onNativeForkAndSpecializePost(JNIEnv *env, jclass clazz, jint res) {
@ -107,8 +104,7 @@ int onNativeForkAndSpecializePost(JNIEnv *env, jclass clazz, jint res) {
return 0; return 0;
} }
prepareJavaEnv(env); prepareJavaEnv(env);
findAndCall(env, "forkAndSpecializePost", "(ILjava/lang/String;ZZ)V", res, sAppDataDir, findAndCall(env, "forkAndSpecializePost", "(ILjava/lang/String;)V", res, sAppDataDir);
is_black_white_list_enabled(), is_dynamic_modules_enabled());
} else { } else {
// in zygote process, res is child zygote pid // in zygote process, res is child zygote pid
// don't print log here, see https://github.com/RikkaApps/Riru/blob/77adfd6a4a6a81bfd20569c910bc4854f2f84f5e/riru-core/jni/main/jni_native_method.cpp#L55-L66 // don't print log here, see https://github.com/RikkaApps/Riru/blob/77adfd6a4a6a81bfd20569c910bc4854f2f84f5e/riru-core/jni/main/jni_native_method.cpp#L55-L66

View File

@ -36,6 +36,22 @@ void reopenFilesAfterForkNative(JNIEnv*, jclass) {
gClosedFdTable = nullptr; gClosedFdTable = nullptr;
} }
jlong suspendAllThreads(JNIEnv *, jclass) {
if (!suspendAll) {
return 0;
}
ScopedSuspendAll *suspendAllObj = (ScopedSuspendAll *) malloc(sizeof(ScopedSuspendAll));
suspendAll(suspendAllObj, "edxp_stop_gc", false);
return reinterpret_cast<jlong>(suspendAllObj);
}
void resumeAllThreads(JNIEnv *, jclass, jlong obj) {
if (!resumeAll) {
return;
}
resumeAll(reinterpret_cast<ScopedSuspendAll *>(obj));
}
static JNINativeMethod hookMethods[] = { static JNINativeMethod hookMethods[] = {
{ {
"init", "init",
@ -57,6 +73,12 @@ static JNINativeMethod hookMethods[] = {
"(Ljava/lang/reflect/Method;Ljava/lang/reflect/Method;)V", "(Ljava/lang/reflect/Method;Ljava/lang/reflect/Method;)V",
(void *) Java_lab_galaxy_yahfa_HookMain_ensureMethodCached (void *) Java_lab_galaxy_yahfa_HookMain_ensureMethodCached
}, },
{
"isBlackWhiteListEnabled", "()Z", (void *) is_black_white_list_enabled
},
{
"isDynamicModulesEnabled", "()Z", (void *) is_dynamic_modules_enabled
},
{ {
"getInstallerPkgName", "()Ljava/lang/String;", (void *) get_installer_pkg_name "getInstallerPkgName", "()Ljava/lang/String;", (void *) get_installer_pkg_name
}, },
@ -68,6 +90,12 @@ static JNINativeMethod hookMethods[] = {
}, },
{ {
"deoptMethodNative", "(Ljava/lang/Object;)V", (void *) deoptimize_method "deoptMethodNative", "(Ljava/lang/Object;)V", (void *) deoptimize_method
},
{
"suspendAllThreads", "()J", (void *) suspendAllThreads
},
{
"resumeAllThreads", "(J)V", (void *) resumeAllThreads
} }
}; };
@ -106,7 +134,7 @@ void loadDexAndInit(JNIEnv *env, const char *dexPath) {
jclass entry_class = findClassFromLoader(env, myClassLoader, ENTRY_CLASS_NAME); jclass entry_class = findClassFromLoader(env, myClassLoader, ENTRY_CLASS_NAME);
if (NULL != entry_class) { if (NULL != entry_class) {
LOGD("HookEntry Class %p", entry_class); LOGD("HookEntry Class %p", entry_class);
env->RegisterNatives(entry_class, hookMethods, 8); env->RegisterNatives(entry_class, hookMethods, 12);
isInited = true; isInited = true;
LOGD("RegisterNatives succeed for HookEntry."); LOGD("RegisterNatives succeed for HookEntry.");
} else { } else {

View File

@ -212,6 +212,19 @@ void hookRuntime(int api_level, void *artHandle, void (*hookFun)(void *, void *,
} }
} }
void (*suspendAll)(ScopedSuspendAll*, const char*, bool) = nullptr;
void (*resumeAll)(ScopedSuspendAll*) = nullptr;
void getSuspendSyms(int api_level, void *artHandle, void (*hookFun)(void *, void *, void **)) {
if (api_level < ANDROID_N) {
return;
}
suspendAll = reinterpret_cast<void (*)(ScopedSuspendAll*,const char*, bool)>(dlsym(artHandle,
"_ZN3art16ScopedSuspendAllC2EPKcb"));
resumeAll = reinterpret_cast<void (*)(ScopedSuspendAll*)>(dlsym(artHandle,
"_ZN3art16ScopedSuspendAllD2Ev"));
}
void install_inline_hooks() { void install_inline_hooks() {
if (inlineHooksInstalled) { if (inlineHooksInstalled) {
LOGI("inline hooks installed, skip"); LOGI("inline hooks installed, skip");
@ -243,6 +256,7 @@ void install_inline_hooks() {
} }
hookRuntime(api_level, artHandle, hookFun); hookRuntime(api_level, artHandle, hookFun);
hookInstrumentation(api_level, artHandle, hookFun); hookInstrumentation(api_level, artHandle, hookFun);
getSuspendSyms(api_level, artHandle, hookFun);
hookIsInSamePackage(api_level, artHandle, hookFun); hookIsInSamePackage(api_level, artHandle, hookFun);
if (disableHiddenAPIPolicyImpl(api_level, artHandle, hookFun)) { if (disableHiddenAPIPolicyImpl(api_level, artHandle, hookFun)) {
LOGI("disableHiddenAPIPolicyImpl done."); LOGI("disableHiddenAPIPolicyImpl done.");

View File

@ -19,6 +19,13 @@ static constexpr const char *kLibWhalePath = "/system/lib/libwhale.so";
static ret (*old_##func)(__VA_ARGS__); \ static ret (*old_##func)(__VA_ARGS__); \
static ret new_##func(__VA_ARGS__) static ret new_##func(__VA_ARGS__)
class ScopedSuspendAll {
};
extern void (*suspendAll)(ScopedSuspendAll *, const char *, bool);
extern void (*resumeAll)(ScopedSuspendAll *);
void install_inline_hooks(); void install_inline_hooks();
void deoptimize_method(JNIEnv *env, jclass clazz, jobject method); void deoptimize_method(JNIEnv *env, jclass clazz, jobject method);

View File

@ -17,7 +17,7 @@ supolicy --live "allow system_server system_server process {execmem}"
supolicy --live "allow coredomain coredomain process {execmem}" supolicy --live "allow coredomain coredomain process {execmem}"
# read configs set in our app # read configs set in our app
supolicy --live "allow {zygote system_server} app_data_file * *" supolicy --live "allow coredomain app_data_file * *"
supolicy --live "attradd {system_app platform_app} mlstrustedsubject" supolicy --live "attradd {system_app platform_app} mlstrustedsubject"
# read module apk file in zygote # read module apk file in zygote