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;
......
......@@ -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