Commit 786ed74f authored by swift_gan's avatar swift_gan

tweak xposed loadModule

parent 87f376ea
package com.swift.sandhook.xposedcompat;
import android.app.Application;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import com.swift.sandhook.xposedcompat.classloaders.ComposeClassLoader;
import com.swift.sandhook.xposedcompat.classloaders.XposedClassLoader;
import com.swift.sandhook.xposedcompat.utils.ApplicationUtils;
import com.swift.sandhook.xposedcompat.utils.ProcessUtils;
import java.io.File;
import de.robv.android.xposed.IXposedHookLoadPackage;
import de.robv.android.xposed.XposedBridge;
import de.robv.android.xposed.XposedInit;
import de.robv.android.xposed.callbacks.XC_LoadPackage;
public class XposedCompat {
public static File cacheDir;
public static Context context;
public static ClassLoader classLoader;
public static boolean isFirstApplication;
private static ClassLoader sandHookXposedClassLoader;
public static void loadModule(String apkPath, ClassLoader classLoader) {
XposedInit.loadModule(apkPath, classLoader);
}
public static void addXposedModuleCallback(IXposedHookLoadPackage module) {
XposedBridge.hookLoadPackage(new IXposedHookLoadPackage.Wrapper(module));
}
public static void callXposedModuleInit() throws Throwable {
//prepare LoadPackageParam
XC_LoadPackage.LoadPackageParam packageParam = new XC_LoadPackage.LoadPackageParam(XposedBridge.sLoadedPackageCallbacks);
Application application = ApplicationUtils.currentApplication();
if (application != null) {
if (packageParam.processName == null) {
packageParam.processName = ProcessUtils.getProcessName(application);
}
if (packageParam.classLoader == null) {
packageParam.classLoader = application.getClassLoader();
}
if (packageParam.appInfo == null) {
packageParam.appInfo = application.getApplicationInfo();
}
if (cacheDir == null) {
application.getCacheDir();
}
}
XC_LoadPackage.callAll(packageParam);
}
public static ClassLoader getSandHookXposedClassLoader(ClassLoader appOriginClassLoader, ClassLoader sandBoxHostClassLoader) {
if (sandHookXposedClassLoader != null) {
return sandHookXposedClassLoader;
} else {
ClassLoader xposedClassLoader = getXposedClassLoader(sandBoxHostClassLoader);
sandHookXposedClassLoader = new ComposeClassLoader(xposedClassLoader, appOriginClassLoader);
return sandHookXposedClassLoader;
}
}
private static XposedClassLoader xposedClassLoader;
public static synchronized ClassLoader getXposedClassLoader(ClassLoader hostClassLoader) {
if (xposedClassLoader == null) {
xposedClassLoader = new XposedClassLoader(hostClassLoader);
}
return xposedClassLoader;
}
}
package com.swift.sandhook.xposedcompat.classloaders;
/**
* Created by weishu on 17/11/30.
*/
public class ComposeClassLoader extends ClassLoader {
private final ClassLoader mAppClassLoader;
public ComposeClassLoader(ClassLoader parent, ClassLoader appClassLoader) {
super(parent);
mAppClassLoader = appClassLoader;
}
@Override
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
Class clazz = null;
try {
clazz = mAppClassLoader.loadClass(name);
} catch (ClassNotFoundException e) {
// IGNORE.
}
if (clazz == null) {
clazz = super.loadClass(name, resolve);
}
if (clazz == null) {
throw new ClassNotFoundException();
}
return clazz;
}
}
package com.swift.sandhook.xposedcompat.classloaders;
/**
* XposedClassLoader: make sure load xposed class in sandhook
*/
public class XposedClassLoader extends ClassLoader {
private ClassLoader mHostClassLoader;
public XposedClassLoader(ClassLoader hostClassLoader) {
super(ClassLoader.getSystemClassLoader()); // parent is BootClassLoader
mHostClassLoader = hostClassLoader;
}
@Override
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
if (name.startsWith("de.robv.android.xposed") || name.startsWith("android")) {
return mHostClassLoader.loadClass(name);
}
return super.loadClass(name, resolve);
}
}
package com.swift.sandhook.xposedcompat.methodgen;
import com.swift.sandhook.xposedcompat.XposedCompat;
import com.swift.sandhook.xposedcompat.utils.DexLog;
import com.swift.sandhook.xposedcompat.utils.FileUtils;
import java.io.File;
import java.lang.reflect.Constructor;
......
......@@ -25,11 +25,11 @@ import java.util.concurrent.atomic.AtomicLong;
import de.robv.android.xposed.XC_MethodHook;
import de.robv.android.xposed.XposedBridge;
import static com.swift.sandhook.xposedcompat.methodgen.DexMakerUtils.autoBoxIfNecessary;
import static com.swift.sandhook.xposedcompat.methodgen.DexMakerUtils.autoUnboxIfNecessary;
import static com.swift.sandhook.xposedcompat.methodgen.DexMakerUtils.createResultLocals;
import static com.swift.sandhook.xposedcompat.methodgen.DexMakerUtils.getObjTypeIdIfPrimitive;
import static com.swift.sandhook.xposedcompat.methodgen.DexMakerUtils.moveException;
import static com.swift.sandhook.xposedcompat.utils.DexMakerUtils.autoBoxIfNecessary;
import static com.swift.sandhook.xposedcompat.utils.DexMakerUtils.autoUnboxIfNecessary;
import static com.swift.sandhook.xposedcompat.utils.DexMakerUtils.createResultLocals;
import static com.swift.sandhook.xposedcompat.utils.DexMakerUtils.getObjTypeIdIfPrimitive;
import static com.swift.sandhook.xposedcompat.utils.DexMakerUtils.moveException;
public class HookerDexMaker {
......
package com.swift.sandhook.xposedcompat.methodgen;
import android.os.Process;
import android.text.TextUtils;
//import com.elderdrivers.riru.xposed.Main;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStreamReader;
public class ProcessUtils {
public static String getCurrentProcessName() {
String prettyName = null;//Main.sAppProcessName;
if (!TextUtils.isEmpty(prettyName)) {
return prettyName;
}
return getProcessName(Process.myPid());
}
/**
* a common solution from https://stackoverflow.com/a/21389402
* <p>
* use {@link com.elderdrivers.riru.xposed.Main#sAppProcessName} to get current process name
*/
public static String getProcessName(int pid) {
BufferedReader cmdlineReader = null;
try {
cmdlineReader = new BufferedReader(new InputStreamReader(
new FileInputStream(
"/proc/" + pid + "/cmdline"),
"iso-8859-1"));
int c;
StringBuilder processName = new StringBuilder();
while ((c = cmdlineReader.read()) > 0) {
processName.append((char) c);
}
return processName.toString();
} catch (Throwable throwable) {
DexLog.w("getProcessName: " + throwable.getMessage());
} finally {
try {
if (cmdlineReader != null) {
cmdlineReader.close();
}
} catch (Throwable throwable) {
DexLog.e("getProcessName: " + throwable.getMessage());
}
}
return "";
}
public static boolean isLastPidAlive(File lastPidFile) {
String lastPidInfo = FileUtils.readLine(lastPidFile);
try {
String[] split = lastPidInfo.split(":", 2);
return checkProcessAlive(Integer.parseInt(split[0]), split[1]);
} catch (Throwable throwable) {
DexLog.w("error when check last pid " + lastPidFile + ": " + throwable.getMessage());
return false;
}
}
public static void saveLastPidInfo(File lastPidFile, int pid, String processName) {
try {
if (!lastPidFile.exists()) {
lastPidFile.getParentFile().mkdirs();
lastPidFile.createNewFile();
}
} catch (Throwable throwable) {
}
FileUtils.writeLine(lastPidFile, pid + ":" + processName);
}
public static boolean checkProcessAlive(int pid, String processName) {
String existsPrcName = getProcessName(pid);
DexLog.w("checking pid alive: " + pid + ", " + processName + ", processName=" + existsPrcName);
return existsPrcName.equals(processName);
}
}
package com.swift.sandhook.xposedcompat.utils;
import android.app.Application;
import java.lang.reflect.Method;
public class ApplicationUtils {
private static Class classActivityThread;
private static Method currentApplicationMethod;
static Application application;
public static Application currentApplication() {
if (application != null)
return application;
if (currentApplicationMethod == null) {
try {
classActivityThread = Class.forName("android.app.ActivityThread");
currentApplicationMethod = classActivityThread.getDeclaredMethod("currentApplication");
} catch (Exception e) {
e.printStackTrace();
}
}
if (currentApplicationMethod == null)
return null;
try {
application = (Application) currentApplicationMethod.invoke(null);
} catch (Exception e) {
}
return application;
}
}
package com.swift.sandhook.xposedcompat.utils;
import android.os.Build;
import android.util.ArrayMap;
import com.swift.sandhook.xposedcompat.BuildConfig;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import dalvik.system.PathClassLoader;
public class ClassLoaderUtils {
public static final String DEXPATH = "/system/framework/edxposed.dex:/system/framework/eddalvikdx.dex:/system/framework/eddexmaker.dex";
public static void replaceParentClassLoader(ClassLoader appClassLoader) {
if (appClassLoader == null) {
DexLog.e("appClassLoader is null, you might be kidding me?");
return;
}
try {
ClassLoader curCL = ClassLoaderUtils.class.getClassLoader();
ClassLoader parent = appClassLoader;
ClassLoader lastChild = appClassLoader;
while (parent != null) {
ClassLoader tmp = parent.getParent();
if (tmp == curCL) {
DexLog.d("replacing has been done before, skip.");
return;
}
if (tmp == null) {
DexLog.d("before replacing =========================================>");
dumpClassLoaders(appClassLoader);
Field parentField = ClassLoader.class.getDeclaredField("parent");
parentField.setAccessible(true);
parentField.set(curCL, parent);
parentField.set(lastChild, curCL);
DexLog.d("after replacing ==========================================>");
dumpClassLoaders(appClassLoader);
}
lastChild = parent;
parent = tmp;
}
} catch (Throwable throwable) {
DexLog.e("error when replacing class loader.", throwable);
}
}
private static void dumpClassLoaders(ClassLoader classLoader) {
if (BuildConfig.DEBUG) {
while (classLoader != null) {
DexLog.d(classLoader + " =>");
classLoader = classLoader.getParent();
}
}
}
public static List<ClassLoader> getAppClassLoader() {
List<ClassLoader> cacheLoaders = new ArrayList<>(0);
try {
DexLog.d("start getting app classloader");
Class appLoadersClass = Class.forName("android.app.ApplicationLoaders");
Field loadersField = appLoadersClass.getDeclaredField("gApplicationLoaders");
loadersField.setAccessible(true);
Object loaders = loadersField.get(null);
Field mLoaderMapField = loaders.getClass().getDeclaredField("mLoaders");
mLoaderMapField.setAccessible(true);
ArrayMap<String, ClassLoader> mLoaderMap = (ArrayMap<String, ClassLoader>) mLoaderMapField.get(loaders);
DexLog.d("mLoaders size = " + mLoaderMap.size());
cacheLoaders = new ArrayList<>(mLoaderMap.values());
} catch (Exception ex) {
DexLog.e("error get app class loader.", ex);
}
return cacheLoaders;
}
private static HashSet<ClassLoader> classLoaders = new HashSet<>();
public static boolean addPathToClassLoader(ClassLoader classLoader) {
if (!(classLoader instanceof PathClassLoader)) {
DexLog.w(classLoader + " is not a BaseDexClassLoader!!!");
return false;
}
if (classLoaders.contains(classLoader)) {
DexLog.d(classLoader + " has been hooked before");
return true;
}
try {
PathClassLoader baseDexClassLoader = (PathClassLoader) classLoader;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
//baseDexClassLoader.addDexPath(DEXPATH);
} else {
DexUtils.injectDexAtFirst(DEXPATH, baseDexClassLoader);
}
classLoaders.add(classLoader);
return true;
} catch (Throwable throwable) {
DexLog.e("error when addPath to ClassLoader: " + classLoader, throwable);
}
return false;
}
}
package com.swift.sandhook.xposedcompat.methodgen;
package com.swift.sandhook.xposedcompat.utils;
import android.util.Log;
......
package com.swift.sandhook.xposedcompat.methodgen;
package com.swift.sandhook.xposedcompat.utils;
import com.android.dx.Code;
import com.android.dx.Local;
import com.android.dx.TypeId;
......
package com.swift.sandhook.xposedcompat.utils;
import android.annotation.TargetApi;
import android.os.Build;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import dalvik.system.BaseDexClassLoader;
import dalvik.system.DexClassLoader;
/**
* For 6.0 only.
*/
@TargetApi(Build.VERSION_CODES.M)
public class DexUtils {
public static void injectDexAtFirst(String dexPath, BaseDexClassLoader classLoader) throws NoSuchFieldException, IllegalAccessException, ClassNotFoundException {
DexClassLoader dexClassLoader = new DexClassLoader(dexPath, null, dexPath, classLoader);
Object baseDexElements = getDexElements(getPathList(classLoader));
Object newDexElements = getDexElements(getPathList(dexClassLoader));
Object allDexElements = combineArray(newDexElements, baseDexElements);
Object pathList = getPathList(classLoader);
setField(pathList, pathList.getClass(), "dexElements", allDexElements);
}
private static Object getDexElements(Object paramObject)
throws IllegalArgumentException, NoSuchFieldException, IllegalAccessException {
return getField(paramObject, paramObject.getClass(), "dexElements");
}
private static Object getPathList(Object baseDexClassLoader)
throws IllegalArgumentException, NoSuchFieldException, IllegalAccessException, ClassNotFoundException {
return getField(baseDexClassLoader, Class.forName("dalvik.system.BaseDexClassLoader"), "pathList");
}
private static Object combineArray(Object firstArray, Object secondArray) {
Class<?> localClass = firstArray.getClass().getComponentType();
int firstArrayLength = Array.getLength(firstArray);
int allLength = firstArrayLength + Array.getLength(secondArray);
Object result = Array.newInstance(localClass, allLength);
for (int k = 0; k < allLength; ++k) {
if (k < firstArrayLength) {
Array.set(result, k, Array.get(firstArray, k));
} else {
Array.set(result, k, Array.get(secondArray, k - firstArrayLength));
}
}
return result;
}
public static Object getField(Object obj, Class<?> cl, String field)
throws NoSuchFieldException, IllegalArgumentException, IllegalAccessException {
Field localField = cl.getDeclaredField(field);
localField.setAccessible(true);
return localField.get(obj);
}
public static void setField(Object obj, Class<?> cl, String field, Object value)
throws NoSuchFieldException, IllegalArgumentException, IllegalAccessException {
Field localField = cl.getDeclaredField(field);
localField.setAccessible(true);
localField.set(obj, value);
}
}
\ No newline at end of file
package com.swift.sandhook.xposedcompat.methodgen;
package com.swift.sandhook.xposedcompat.utils;
import android.os.Build;
import android.text.TextUtils;
......
package com.swift.sandhook.xposedcompat;
package com.swift.sandhook.xposedcompat.utils;
import android.app.ActivityManager;
import android.content.Context;
......
package de.robv.android.xposed;
//import android.annotation.SuppressLint;
//import android.app.AndroidAppHelper;
//import android.os.Build;
//import android.text.TextUtils;
//import android.util.Log;
//
//import com.android.internal.os.ZygoteInit;
//import com.elderdrivers.riru.xposed.BuildConfig;
//import com.elderdrivers.riru.xposed.entry.Router;
//import com.elderdrivers.riru.xposed.util.Utils;
//
//import java.io.BufferedReader;
//import java.io.File;
//import java.io.IOException;
//import java.io.InputStream;
//import java.io.InputStreamReader;
//import java.util.HashSet;
//import java.util.concurrent.atomic.AtomicBoolean;
//import java.util.zip.ZipEntry;
//import java.util.zip.ZipFile;
//
//import dalvik.system.DexFile;
//import dalvik.system.PathClassLoader;
//import de.robv.android.xposed.services.BaseService;
//
//import static com.elderdrivers.riru.xposed.entry.hooker.XposedBlackListHooker.BLACK_LIST_PACKAGE_NAME;
//import static de.robv.android.xposed.XposedHelpers.closeSilently;
//import static de.robv.android.xposed.XposedHelpers.findClass;
//import static de.robv.android.xposed.XposedHelpers.findFieldIfExists;
//import static de.robv.android.xposed.XposedHelpers.setStaticBooleanField;
//import static de.robv.android.xposed.XposedHelpers.setStaticLongField;
import android.annotation.SuppressLint;
import android.os.Build;
import android.util.Log;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.HashSet;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import dalvik.system.DexFile;
import dalvik.system.PathClassLoader;
import de.robv.android.xposed.services.BaseService;
import static de.robv.android.xposed.XposedHelpers.closeSilently;
public final class XposedInit {
// private static final String TAG = XposedBridge.TAG;
// private static boolean startsSystemServer = false;
// private static final String startClassName = ""; // ed: no support for tool process anymore
//
// public static final String INSTALLER_PACKAGE_NAME = "com.solohsu.android.edxp.manager";
// public static final String INSTALLER_LEGACY_PACKAGE_NAME = "de.robv.android.xposed.installer";
// @SuppressLint("SdCardPath")
// public static final String INSTALLER_DATA_BASE_DIR = Build.VERSION.SDK_INT >= 24
// ? "/data/user_de/0/" + INSTALLER_PACKAGE_NAME + "/"
// : "/data/data/" + INSTALLER_PACKAGE_NAME + "/";
// private static final String INSTANT_RUN_CLASS = "com.android.tools.fd.runtime.BootstrapApplication";
// // TODO not supported yet
// private static boolean disableResources = true;
// private static final String[] XRESOURCES_CONFLICTING_PACKAGES = {"com.sygic.aura"};
//
// private XposedInit() {
// }
//
// private static volatile AtomicBoolean bootstrapHooked = new AtomicBoolean(false);
//
// /**
// * Hook some methods which we want to create an easier interface for developers.
// */
// /*package*/
private static final String TAG = XposedBridge.TAG;
private static boolean startsSystemServer = false;
private static final String startClassName = ""; // ed: no support for tool process anymore
public static final String INSTALLER_PACKAGE_NAME = "com.solohsu.android.edxp.manager";
public static final String INSTALLER_LEGACY_PACKAGE_NAME = "de.robv.android.xposed.installer";
@SuppressLint("SdCardPath")
public static final String INSTALLER_DATA_BASE_DIR = Build.VERSION.SDK_INT >= 24
? "/data/user_de/0/" + INSTALLER_PACKAGE_NAME + "/"
: "/data/data/" + INSTALLER_PACKAGE_NAME + "/";
private static final String INSTANT_RUN_CLASS = "com.android.tools.fd.runtime.BootstrapApplication";
// TODO not supported yet
private static boolean disableResources = true;
private static final String[] XRESOURCES_CONFLICTING_PACKAGES = {"com.sygic.aura"};
private XposedInit() {
}
private static volatile AtomicBoolean bootstrapHooked = new AtomicBoolean(false);
/**
* Hook some methods which we want to create an easier interface for developers.
*/
/*package*/
// public static void initForZygote(boolean isSystem) throws Throwable {
// if (!bootstrapHooked.compareAndSet(false, true)) {
// return;
......@@ -77,175 +65,166 @@ public final class XposedInit {
// }
// }
// }
//
// /*package*/
// static void hookResources() throws Throwable {
// // ed: not for now
// }
//
// private static boolean needsToCloseFilesForFork() {
// // ed: we always start to do our work after forking finishes
// return false;
// }
//
// /**
// * Try to load all modules defined in <code>INSTALLER_DATA_BASE_DIR/conf/modules.list</code>
// */
// private static volatile AtomicBoolean modulesLoaded = new AtomicBoolean(false);
//
// public static void loadModules() throws IOException {
// if (!modulesLoaded.compareAndSet(false, true)) {
// return;
// }
// final String filename = INSTALLER_DATA_BASE_DIR + "conf/modules.list";
// BaseService service = SELinuxHelper.getAppDataFileService();
// if (!service.checkFileExists(filename)) {
// Log.e(TAG, "Cannot load any modules because " + filename + " was not found");
// return;
// }
//
// ClassLoader topClassLoader = XposedBridge.BOOTCLASSLOADER;
// ClassLoader parent;
// while ((parent = topClassLoader.getParent()) != null) {
// topClassLoader = parent;
// }
//
// InputStream stream = service.getFileInputStream(filename);
// BufferedReader apks = new BufferedReader(new InputStreamReader(stream));
// String apk;
// while ((apk = apks.readLine()) != null) {
// loadModule(apk, topClassLoader);
// }
// apks.close();
// }
//
//
// /**
// * Load a module from an APK by calling the init(String) method for all classes defined
// * in <code>assets/xposed_init</code>.
// */
// private static void loadModule(String apk, ClassLoader topClassLoader) {
// if (BuildConfig.DEBUG)
// Log.i(TAG, "Loading modules from " + apk);
//
// if (!TextUtils.isEmpty(apk) && apk.contains(BLACK_LIST_PACKAGE_NAME)) {
// if (BuildConfig.DEBUG)
// Log.i(TAG, "We are going to take over black list's job...");
// return;
// }
//
// if (!new File(apk).exists()) {
// Log.e(TAG, " File does not exist");
// return;
// }
//
// DexFile dexFile;
// try {
// dexFile = new DexFile(apk);
// } catch (IOException e) {
// Log.e(TAG, " Cannot load module", e);
// return;
// }
//
// if (dexFile.loadClass(INSTANT_RUN_CLASS, topClassLoader) != null) {
// Log.e(TAG, " Cannot load module, please disable \"Instant Run\" in Android Studio.");
// closeSilently(dexFile);
// return;
// }
//
// if (dexFile.loadClass(XposedBridge.class.getName(), topClassLoader) != null) {
// Log.e(TAG, " Cannot load module:");
// Log.e(TAG, " The Xposed API classes are compiled into the module's APK.");
// Log.e(TAG, " This may cause strange issues and must be fixed by the module developer.");
// Log.e(TAG, " For details, see: http://api.xposed.info/using.html");
// closeSilently(dexFile);
// return;
// }
//
// closeSilently(dexFile);
//
// ZipFile zipFile = null;
// InputStream is;
// try {
// zipFile = new ZipFile(apk);
// ZipEntry zipEntry = zipFile.getEntry("assets/xposed_init");
// if (zipEntry == null) {
// Log.e(TAG, " assets/xposed_init not found in the APK");
// closeSilently(zipFile);
// return;
// }
// is = zipFile.getInputStream(zipEntry);
// } catch (IOException e) {
// Log.e(TAG, " Cannot read assets/xposed_init in the APK", e);
// closeSilently(zipFile);
// return;
// }
//
// ClassLoader mcl = new PathClassLoader(apk, XposedInit.class.getClassLoader());
// BufferedReader moduleClassesReader = new BufferedReader(new InputStreamReader(is));
// try {
// String moduleClassName;
// while ((moduleClassName = moduleClassesReader.readLine()) != null) {
// moduleClassName = moduleClassName.trim();
// if (moduleClassName.isEmpty() || moduleClassName.startsWith("#"))
// continue;
//
// try {
// if (BuildConfig.DEBUG)
// Log.i(TAG, " Loading class " + moduleClassName);
// Class<?> moduleClass = mcl.loadClass(moduleClassName);
//
// if (!IXposedMod.class.isAssignableFrom(moduleClass)) {
// Log.e(TAG, " This class doesn't implement any sub-interface of IXposedMod, skipping it");
// continue;
// } else if (disableResources && IXposedHookInitPackageResources.class.isAssignableFrom(moduleClass)) {
// Log.e(TAG, " This class requires resource-related hooks (which are disabled), skipping it.");
// continue;
// }
//
// final Object moduleInstance = moduleClass.newInstance();
// if (XposedBridge.isZygote) {
// if (moduleInstance instanceof IXposedHookZygoteInit) {
// IXposedHookZygoteInit.StartupParam param = new IXposedHookZygoteInit.StartupParam();
// param.modulePath = apk;
// param.startsSystemServer = startsSystemServer;
// ((IXposedHookZygoteInit) moduleInstance).initZygote(param);
// }
//
// if (moduleInstance instanceof IXposedHookLoadPackage)
// XposedBridge.hookLoadPackage(new IXposedHookLoadPackage.Wrapper((IXposedHookLoadPackage) moduleInstance));
//
// if (moduleInstance instanceof IXposedHookInitPackageResources)
// XposedBridge.hookInitPackageResources(new IXposedHookInitPackageResources.Wrapper((IXposedHookInitPackageResources) moduleInstance));
// } else {
// if (moduleInstance instanceof IXposedHookCmdInit) {
/*package*/
static void hookResources() throws Throwable {
// ed: not for now
}
private static boolean needsToCloseFilesForFork() {
// ed: we always start to do our work after forking finishes
return false;
}
/**
* Try to load all modules defined in <code>INSTALLER_DATA_BASE_DIR/conf/modules.list</code>
*/
private static volatile AtomicBoolean modulesLoaded = new AtomicBoolean(false);
public static void loadModules() throws IOException {
if (!modulesLoaded.compareAndSet(false, true)) {
return;
}
final String filename = INSTALLER_DATA_BASE_DIR + "conf/modules.list";
BaseService service = SELinuxHelper.getAppDataFileService();
if (!service.checkFileExists(filename)) {
Log.e(TAG, "Cannot load any modules because " + filename + " was not found");
return;
}
ClassLoader topClassLoader = XposedBridge.BOOTCLASSLOADER;
ClassLoader parent;
while ((parent = topClassLoader.getParent()) != null) {
topClassLoader = parent;
}
InputStream stream = service.getFileInputStream(filename);
BufferedReader apks = new BufferedReader(new InputStreamReader(stream));
String apk;
while ((apk = apks.readLine()) != null) {
loadModule(apk, topClassLoader);
}
apks.close();
}
/**
* Load a module from an APK by calling the init(String) method for all classes defined
* in <code>assets/xposed_init</code>.
*/
public static void loadModule(String apk, ClassLoader topClassLoader) {
if (!new File(apk).exists()) {
Log.e(TAG, " File does not exist");
return;
}
DexFile dexFile;
try {
dexFile = new DexFile(apk);
} catch (IOException e) {
Log.e(TAG, " Cannot load module", e);
return;
}
if (dexFile.loadClass(INSTANT_RUN_CLASS, topClassLoader) != null) {
Log.e(TAG, " Cannot load module, please disable \"Instant Run\" in Android Studio.");
closeSilently(dexFile);
return;
}
if (dexFile.loadClass(XposedBridge.class.getName(), topClassLoader) != null) {
Log.e(TAG, " Cannot load module:");
Log.e(TAG, " The Xposed API classes are compiled into the module's APK.");
Log.e(TAG, " This may cause strange issues and must be fixed by the module developer.");
Log.e(TAG, " For details, see: http://api.xposed.info/using.html");
closeSilently(dexFile);
return;
}
closeSilently(dexFile);
ZipFile zipFile = null;
InputStream is;
try {
zipFile = new ZipFile(apk);
ZipEntry zipEntry = zipFile.getEntry("assets/xposed_init");
if (zipEntry == null) {
Log.e(TAG, " assets/xposed_init not found in the APK");
closeSilently(zipFile);
return;
}
is = zipFile.getInputStream(zipEntry);
} catch (IOException e) {
Log.e(TAG, " Cannot read assets/xposed_init in the APK", e);
closeSilently(zipFile);
return;
}
ClassLoader mcl = new PathClassLoader(apk, XposedInit.class.getClassLoader());
BufferedReader moduleClassesReader = new BufferedReader(new InputStreamReader(is));
try {
String moduleClassName;
while ((moduleClassName = moduleClassesReader.readLine()) != null) {
moduleClassName = moduleClassName.trim();
if (moduleClassName.isEmpty() || moduleClassName.startsWith("#"))
continue;
try {
Log.i(TAG, " Loading class " + moduleClassName);
Class<?> moduleClass = mcl.loadClass(moduleClassName);
if (!IXposedMod.class.isAssignableFrom(moduleClass)) {
Log.e(TAG, " This class doesn't implement any sub-interface of IXposedMod, skipping it");
continue;
} else if (disableResources && IXposedHookInitPackageResources.class.isAssignableFrom(moduleClass)) {
Log.e(TAG, " This class requires resource-related hooks (which are disabled), skipping it.");
continue;
}
final Object moduleInstance = moduleClass.newInstance();
if (true) {
//fake
if (moduleInstance instanceof IXposedHookZygoteInit) {
IXposedHookZygoteInit.StartupParam param = new IXposedHookZygoteInit.StartupParam();
param.modulePath = apk;
param.startsSystemServer = false;
((IXposedHookZygoteInit) moduleInstance).initZygote(param);
}
if (moduleInstance instanceof IXposedHookLoadPackage)
XposedBridge.hookLoadPackage(new IXposedHookLoadPackage.Wrapper((IXposedHookLoadPackage) moduleInstance));
//not support now
//so off
if (moduleInstance instanceof IXposedHookInitPackageResources) {
throw new UnsupportedOperationException("can not hook resource!");
//XposedBridge.hookInitPackageResources(new IXposedHookInitPackageResources.Wrapper((IXposedHookInitPackageResources) moduleInstance));
}
} else {
//not support now
//so off
if (moduleInstance instanceof IXposedHookCmdInit) {
throw new UnsupportedOperationException("can not hook cmd!");
// IXposedHookCmdInit.StartupParam param = new IXposedHookCmdInit.StartupParam();
// param.modulePath = apk;
// param.startClassName = startClassName;
// ((IXposedHookCmdInit) moduleInstance).initCmdApp(param);
// }
// }
// } catch (Throwable t) {
// Log.e(TAG, " Failed to load class " + moduleClassName, t);
// }
// }
// } catch (IOException e) {
// Log.e(TAG, " Failed to load module from " + apk, e);
// } finally {
// closeSilently(is);
// closeSilently(zipFile);
// }
// }
//
// public final static HashSet<String> loadedPackagesInProcess = new HashSet<>(1);
//
// public static void logD(String prefix) {
// Utils.logD(String.format("%s: pkg=%s, prc=%s", prefix, AndroidAppHelper.currentPackageName(),
// AndroidAppHelper.currentProcessName()));
// }
//
// public static void logE(String prefix, Throwable throwable) {
// Utils.logE(String.format("%s: pkg=%s, prc=%s", prefix, AndroidAppHelper.currentPackageName(),
// AndroidAppHelper.currentProcessName()), throwable);
// }
}
}
} catch (Throwable t) {
Log.e(TAG, " Failed to load class " + moduleClassName, t);
}
}
} catch (IOException e) {
Log.e(TAG, " Failed to load module from " + apk, e);
} finally {
closeSilently(is);
closeSilently(zipFile);
}
}
public final static HashSet<String> loadedPackagesInProcess = new HashSet<>(1);
}
......@@ -2,7 +2,7 @@ package de.robv.android.xposed.callbacks;
import android.content.pm.ApplicationInfo;
import com.swift.sandhook.xposedcompat.ProcessUtils;
import com.swift.sandhook.xposedcompat.utils.ProcessUtils;
import com.swift.sandhook.xposedcompat.XposedCompat;
import de.robv.android.xposed.IXposedHookLoadPackage;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment