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() {
var moduleList = serviceClient.getModulesList();
var moduleList = serviceClient.getLegacyModulesList();
moduleList.forEach(module -> {
var apk = module.apkPath;
var name = module.packageName;
@ -286,7 +286,7 @@ public final class XposedInit {
* in <code>assets/xposed_init</code>.
*/
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 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;
}
@Override
public List<Module> getLegacyModulesList() {
try {
return service.getLegacyModulesList();
} catch (RemoteException | NullPointerException ignored) {
}
return Collections.emptyList();
}
@Override
public List<Module> getModulesList() {
try {

View File

@ -28,6 +28,7 @@ import android.content.res.CompatibilityInfo;
import com.android.internal.os.ZygoteInit;
import org.lsposed.lspd.deopt.PrebuiltMethodsDeopter;
import org.lsposed.lspd.hooker.AttachHooker;
import org.lsposed.lspd.hooker.CrashDumpHooker;
import org.lsposed.lspd.hooker.HandleSystemServerProcessHooker;
import org.lsposed.lspd.hooker.LoadedApkCtorHooker;
@ -59,6 +60,8 @@ public class Startup {
ActivityThread.class, ApplicationInfo.class, CompatibilityInfo.class,
ClassLoader.class, boolean.class, boolean.class, boolean.class,
new LoadedApkCtorHooker());
XposedHelpers.findAndHookMethod(ActivityThread.class, "attach", boolean.class,
long.class, new AttachHooker());
}
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 {
LoadedApk loadedApk = (LoadedApk) param.thisObject;
String packageName = loadedApk.getPackageName();
if (XposedInit.getLoadedModules().contains(packageName)) {
return;
}
Object mAppDir = XposedHelpers.getObjectField(loadedApk, "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
readName(apkFile, "META-INF/xposed/xposed_init", moduleClassNames);
if (moduleClassNames.isEmpty()) {
file.usingContext = false;
readName(apkFile, "assets/xposed_init", moduleClassNames);
readName(apkFile, "assets/native_init", moduleLibraryNames);
} else {
file.usingContext = true;
readName(apkFile, "META-INF/xposed/native_init", moduleLibraryNames);
}
} catch (IOException e) {

View File

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

View File

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

View File

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