Load module context

This commit is contained in:
LoveSy 2022-12-26 19:09:14 +08:00 committed by LoveSy
parent a2be0bd030
commit 14f31b604a
9 changed files with 106 additions and 4 deletions

View File

@ -221,7 +221,7 @@ public final class XposedInit {
} }
public static void loadModules() { public static void loadModules() {
var moduleList = serviceClient.getModulesList(); var moduleList = serviceClient.getLegacyModulesList();
moduleList.forEach(module -> { moduleList.forEach(module -> {
var apk = module.apkPath; var apk = module.apkPath;
var name = module.packageName; var name = module.packageName;
@ -286,7 +286,7 @@ public final class XposedInit {
* in <code>assets/xposed_init</code>. * in <code>assets/xposed_init</code>.
*/ */
private static boolean loadModule(String name, String apk, PreLoadedApk file) { private static boolean loadModule(String name, String apk, PreLoadedApk file) {
Log.i(TAG, "Loading module " + name + " from " + apk); Log.i(TAG, "Loading legacy module " + name + " from " + apk);
var sb = new StringBuilder(); var sb = new StringBuilder();
var abis = Process.is64Bit() ? Build.SUPPORTED_64_BIT_ABIS : Build.SUPPORTED_32_BIT_ABIS; var abis = Process.is64Bit() ? Build.SUPPORTED_64_BIT_ABIS : Build.SUPPORTED_32_BIT_ABIS;

View File

@ -66,6 +66,15 @@ public class ApplicationServiceClient implements ILSPApplicationService, IBinder
return null; return null;
} }
@Override
public List<Module> getLegacyModulesList() {
try {
return service.getLegacyModulesList();
} catch (RemoteException | NullPointerException ignored) {
}
return Collections.emptyList();
}
@Override @Override
public List<Module> getModulesList() { public List<Module> getModulesList() {
try { try {

View File

@ -28,6 +28,7 @@ import android.content.res.CompatibilityInfo;
import com.android.internal.os.ZygoteInit; import com.android.internal.os.ZygoteInit;
import org.lsposed.lspd.deopt.PrebuiltMethodsDeopter; import org.lsposed.lspd.deopt.PrebuiltMethodsDeopter;
import org.lsposed.lspd.hooker.AttachHooker;
import org.lsposed.lspd.hooker.CrashDumpHooker; import org.lsposed.lspd.hooker.CrashDumpHooker;
import org.lsposed.lspd.hooker.HandleSystemServerProcessHooker; import org.lsposed.lspd.hooker.HandleSystemServerProcessHooker;
import org.lsposed.lspd.hooker.LoadedApkCtorHooker; import org.lsposed.lspd.hooker.LoadedApkCtorHooker;
@ -59,6 +60,8 @@ public class Startup {
ActivityThread.class, ApplicationInfo.class, CompatibilityInfo.class, ActivityThread.class, ApplicationInfo.class, CompatibilityInfo.class,
ClassLoader.class, boolean.class, boolean.class, boolean.class, ClassLoader.class, boolean.class, boolean.class, boolean.class,
new LoadedApkCtorHooker()); new LoadedApkCtorHooker());
XposedHelpers.findAndHookMethod(ActivityThread.class, "attach", boolean.class,
long.class, new AttachHooker());
} }
public static void bootstrapXposed() { public static void bootstrapXposed() {

View File

@ -0,0 +1,72 @@
package org.lsposed.lspd.hooker;
import static org.lsposed.lspd.core.ApplicationServiceClient.serviceClient;
import android.app.ActivityThread;
import android.app.LoadedApk;
import android.content.Context;
import android.content.ContextParams;
import android.os.Build;
import android.os.Process;
import org.lsposed.lspd.util.Hookers;
import org.lsposed.lspd.util.LspModuleClassLoader;
import java.io.File;
import de.robv.android.xposed.XC_MethodHook;
import de.robv.android.xposed.XposedHelpers;
import de.robv.android.xposed.XposedInit;
public class AttachHooker extends XC_MethodHook {
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
var at = (ActivityThread) param.thisObject;
var moduleList = serviceClient.getModulesList();
moduleList.forEach(module -> {
try {
XposedInit.getLoadedModules().add(module.packageName);
var loadedApk = at.getPackageInfoNoCheck(module.applicationInfo, null);
var sb = new StringBuilder();
var abis = Process.is64Bit() ? Build.SUPPORTED_64_BIT_ABIS : Build.SUPPORTED_32_BIT_ABIS;
for (String abi : abis) {
sb.append(module.apkPath).append("!/lib/").append(abi).append(File.pathSeparator);
}
var librarySearchPath = sb.toString();
var initLoader = XposedInit.class.getClassLoader();
var mcl = LspModuleClassLoader.loadApk(module.apkPath, module.file.preLoadedDexes, librarySearchPath, initLoader);
XposedHelpers.setObjectField(loadedApk, "mClassLoader", mcl);
var c = Class.forName("android.app.ContextImpl");
var ctor = c.getDeclaredConstructors()[0];
ctor.setAccessible(true);
var args = new Object[ctor.getParameterTypes().length];
for (int i = 0; i < ctor.getParameterTypes().length; ++i) {
if (ctor.getParameterTypes()[i] == LoadedApk.class) {
args[i] = loadedApk;
continue;
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
if (ctor.getParameterTypes()[i] == ContextParams.class) {
args[i] = new ContextParams.Builder().build();
continue;
}
}
if (ctor.getParameterTypes()[i] == ActivityThread.class) {
args[i] = at;
continue;
}
if (ctor.getParameterTypes()[i] == int.class) {
args[i] = 0;
continue;
}
args[i] = null;
}
var ctx = (Context) ctor.newInstance(args);
Hookers.logD("Loaded module " + module.packageName + ": " + ctx);
} catch (Throwable e) {
Hookers.logE("Loading module " + module.packageName, e);
}
});
}
}

View File

@ -40,6 +40,9 @@ public class LoadedApkCtorHooker extends XC_MethodHook {
try { try {
LoadedApk loadedApk = (LoadedApk) param.thisObject; LoadedApk loadedApk = (LoadedApk) param.thisObject;
String packageName = loadedApk.getPackageName(); String packageName = loadedApk.getPackageName();
if (XposedInit.getLoadedModules().contains(packageName)) {
return;
}
Object mAppDir = XposedHelpers.getObjectField(loadedApk, "mAppDir"); Object mAppDir = XposedHelpers.getObjectField(loadedApk, "mAppDir");
Hookers.logD("LoadedApk#<init> ends: " + mAppDir); Hookers.logD("LoadedApk#<init> ends: " + mAppDir);

View File

@ -368,9 +368,11 @@ public class ConfigFileManager {
// TODO: we can store more info like api version, module description, etc. in META-INF // TODO: we can store more info like api version, module description, etc. in META-INF
readName(apkFile, "META-INF/xposed/xposed_init", moduleClassNames); readName(apkFile, "META-INF/xposed/xposed_init", moduleClassNames);
if (moduleClassNames.isEmpty()) { if (moduleClassNames.isEmpty()) {
file.usingContext = false;
readName(apkFile, "assets/xposed_init", moduleClassNames); readName(apkFile, "assets/xposed_init", moduleClassNames);
readName(apkFile, "assets/native_init", moduleLibraryNames); readName(apkFile, "assets/native_init", moduleLibraryNames);
} else { } else {
file.usingContext = true;
readName(apkFile, "META-INF/xposed/native_init", moduleLibraryNames); readName(apkFile, "META-INF/xposed/native_init", moduleLibraryNames);
} }
} catch (IOException e) { } catch (IOException e) {

View File

@ -37,6 +37,7 @@ import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
public class LSPApplicationService extends ILSPApplicationService.Stub { public class LSPApplicationService extends ILSPApplicationService.Stub {
final static int DEX_TRANSACTION_CODE = 1310096052; final static int DEX_TRANSACTION_CODE = 1310096052;
@ -115,8 +116,7 @@ public class LSPApplicationService extends ILSPApplicationService.Stub {
} }
} }
@Override private List<Module> getAllModulesList() throws RemoteException {
public List<Module> getModulesList() throws RemoteException {
var processInfo = ensureRegistered(); var processInfo = ensureRegistered();
if (processInfo.uid == 1000 && processInfo.processName.equals("android")) { if (processInfo.uid == 1000 && processInfo.processName.equals("android")) {
return ConfigManager.getInstance().getModulesForSystemServer(); return ConfigManager.getInstance().getModulesForSystemServer();
@ -126,6 +126,16 @@ public class LSPApplicationService extends ILSPApplicationService.Stub {
return ConfigManager.getInstance().getModulesForProcess(processInfo.processName, processInfo.uid); return ConfigManager.getInstance().getModulesForProcess(processInfo.processName, processInfo.uid);
} }
@Override
public List<Module> getLegacyModulesList() throws RemoteException {
return getAllModulesList().stream().filter(m -> !m.file.usingContext).collect(Collectors.toList());
}
@Override
public List<Module> getModulesList() throws RemoteException {
return getAllModulesList().stream().filter(m -> m.file.usingContext).collect(Collectors.toList());
}
@Override @Override
public String getPrefsPath(String packageName) throws RemoteException { public String getPrefsPath(String packageName) throws RemoteException {
ensureRegistered(); ensureRegistered();

View File

@ -4,4 +4,5 @@ parcelable PreLoadedApk {
List<SharedMemory> preLoadedDexes; List<SharedMemory> preLoadedDexes;
List<String> moduleClassNames; List<String> moduleClassNames;
List<String> moduleLibraryNames; List<String> moduleLibraryNames;
boolean usingContext;
} }

View File

@ -5,6 +5,8 @@ import org.lsposed.lspd.models.Module;
interface ILSPApplicationService { interface ILSPApplicationService {
IBinder requestModuleBinder(String name); IBinder requestModuleBinder(String name);
List<Module> getLegacyModulesList();
List<Module> getModulesList(); List<Module> getModulesList();
String getPrefsPath(String packageName); String getPrefsPath(String packageName);