remove duplicated codes in edxp-sandhook
use the ones from `edxp-common` instead
This commit is contained in:
parent
12c74f165d
commit
9695a983b8
|
|
@ -1,24 +1,22 @@
|
|||
package com.swift.sandhook.xposedcompat;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.os.Process;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import com.elderdrivers.riru.edxp.config.ConfigManager;
|
||||
import com.elderdrivers.riru.edxp.util.FileUtils;
|
||||
import com.elderdrivers.riru.edxp.util.ProcessUtils;
|
||||
import com.elderdrivers.riru.edxp.util.ProxyClassLoader;
|
||||
import com.swift.sandhook.wrapper.HookWrapper;
|
||||
import com.swift.sandhook.xposedcompat.methodgen.SandHookXposedBridge;
|
||||
import com.swift.sandhook.xposedcompat.utils.ApplicationUtils;
|
||||
import com.swift.sandhook.xposedcompat.utils.FileUtils;
|
||||
import com.swift.sandhook.xposedcompat.utils.ProcessUtils;
|
||||
|
||||
import java.io.File;
|
||||
import java.lang.reflect.Member;
|
||||
|
||||
import de.robv.android.xposed.XposedBridge;
|
||||
|
||||
import static com.elderdrivers.riru.edxp.util.ProcessUtils.PER_USER_RANGE;
|
||||
import static com.swift.sandhook.xposedcompat.utils.FileUtils.IS_USING_PROTECTED_STORAGE;
|
||||
import static com.elderdrivers.riru.edxp.util.FileUtils.getDataPathPrefix;
|
||||
|
||||
public class XposedCompat {
|
||||
|
||||
|
|
@ -54,7 +52,7 @@ public class XposedCompat {
|
|||
if (cacheDir == null) {
|
||||
String fixedAppDataDir = getDataPathPrefix() + getPackageName(ConfigManager.appDataDir) + "/";
|
||||
cacheDir = new File(fixedAppDataDir, "/cache/sandhook/"
|
||||
+ ProcessUtils.getProcessName().replace(":", "_") + "/");
|
||||
+ ProcessUtils.getProcessName(Process.myPid()).replace(":", "_") + "/");
|
||||
}
|
||||
return cacheDir;
|
||||
}
|
||||
|
|
@ -104,12 +102,4 @@ public class XposedCompat {
|
|||
return dataDir.substring(lastIndex + 1);
|
||||
}
|
||||
|
||||
// FIXME: Although multi-users is considered here, but compat mode doesn't support other users' apps on Oreo and later yet.
|
||||
@SuppressLint("SdCardPath")
|
||||
public static String getDataPathPrefix() {
|
||||
int userId = Process.myUid() / PER_USER_RANGE;
|
||||
String format = IS_USING_PROTECTED_STORAGE ? "/data/user_de/%d/" : "/data/user/%d/";
|
||||
return String.format(format, userId);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import android.os.Trace;
|
|||
import android.util.Log;
|
||||
|
||||
import com.elderdrivers.riru.edxp.util.ClassLoaderUtils;
|
||||
import com.elderdrivers.riru.edxp.util.FileUtils;
|
||||
import com.swift.sandhook.SandHook;
|
||||
import com.swift.sandhook.SandHookConfig;
|
||||
import com.swift.sandhook.blacklist.HookBlackList;
|
||||
|
|
@ -14,7 +15,6 @@ import com.swift.sandhook.xposedcompat.XposedCompat;
|
|||
import com.swift.sandhook.xposedcompat.hookstub.HookMethodEntity;
|
||||
import com.swift.sandhook.xposedcompat.hookstub.HookStubManager;
|
||||
import com.swift.sandhook.xposedcompat.utils.DexLog;
|
||||
import com.swift.sandhook.xposedcompat.utils.FileUtils;
|
||||
|
||||
import java.io.File;
|
||||
import java.lang.reflect.Constructor;
|
||||
|
|
|
|||
|
|
@ -1,106 +0,0 @@
|
|||
package com.swift.sandhook.xposedcompat.utils;
|
||||
|
||||
import android.os.Build;
|
||||
import android.util.ArrayMap;
|
||||
|
||||
import com.elderdrivers.riru.edxp.sandhook.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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,66 +0,0 @@
|
|||
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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,77 +0,0 @@
|
|||
package com.swift.sandhook.xposedcompat.utils;
|
||||
|
||||
import android.os.Build;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.File;
|
||||
import java.io.FileReader;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
|
||||
public class FileUtils {
|
||||
|
||||
public static final boolean IS_USING_PROTECTED_STORAGE = Build.VERSION.SDK_INT >= Build.VERSION_CODES.N;
|
||||
|
||||
/**
|
||||
* Delete a file or a directory and its children.
|
||||
*
|
||||
* @param file The directory to delete.
|
||||
* @throws IOException Exception when problem occurs during deleting the directory.
|
||||
*/
|
||||
public static void delete(File file) throws IOException {
|
||||
|
||||
for (File childFile : file.listFiles()) {
|
||||
|
||||
if (childFile.isDirectory()) {
|
||||
delete(childFile);
|
||||
} else {
|
||||
if (!childFile.delete()) {
|
||||
throw new IOException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!file.delete()) {
|
||||
throw new IOException();
|
||||
}
|
||||
}
|
||||
|
||||
public static String readLine(File file) {
|
||||
try (BufferedReader reader = new BufferedReader(new FileReader(file))) {
|
||||
return reader.readLine();
|
||||
} catch (Throwable throwable) {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
public static void writeLine(File file, String line) {
|
||||
try {
|
||||
file.createNewFile();
|
||||
} catch (IOException ex) {
|
||||
}
|
||||
try (BufferedWriter writer = new BufferedWriter(new FileWriter(file))) {
|
||||
writer.write(line);
|
||||
writer.flush();
|
||||
} catch (Throwable throwable) {
|
||||
DexLog.e("error writing line to file " + file + ": " + throwable.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public static String getPackageName(String dataDir) {
|
||||
if (TextUtils.isEmpty(dataDir)) {
|
||||
DexLog.e("getPackageName using empty dataDir");
|
||||
return "";
|
||||
}
|
||||
int lastIndex = dataDir.lastIndexOf("/");
|
||||
if (lastIndex < 0) {
|
||||
return dataDir;
|
||||
}
|
||||
return dataDir.substring(lastIndex + 1);
|
||||
}
|
||||
|
||||
public static String getDataPathPrefix() {
|
||||
return IS_USING_PROTECTED_STORAGE ? "/data/user_de/0/" : "/data/data/";
|
||||
}
|
||||
}
|
||||
|
|
@ -1,90 +0,0 @@
|
|||
package com.swift.sandhook.xposedcompat.utils;
|
||||
|
||||
import android.app.ActivityManager;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.ResolveInfo;
|
||||
import android.os.Process;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by swift_gan on 2017/11/23.
|
||||
*/
|
||||
|
||||
public class ProcessUtils {
|
||||
|
||||
public static String getProcessName() {
|
||||
return getProcessName(Process.myPid());
|
||||
}
|
||||
|
||||
private static String doGetProcessName(Context context) {
|
||||
ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
|
||||
List<ActivityManager.RunningAppProcessInfo> runningApps = am.getRunningAppProcesses();
|
||||
if (runningApps == null) {
|
||||
return null;
|
||||
}
|
||||
for (ActivityManager.RunningAppProcessInfo proInfo : runningApps) {
|
||||
if (proInfo.pid == android.os.Process.myPid()) {
|
||||
if (proInfo.processName != null) {
|
||||
return proInfo.processName;
|
||||
}
|
||||
}
|
||||
}
|
||||
return context.getPackageName();
|
||||
}
|
||||
|
||||
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 isMainProcess(Context context) {
|
||||
String processName = getProcessName();
|
||||
String pkgName = context.getPackageName();
|
||||
if (!TextUtils.isEmpty(processName) && !TextUtils.equals(processName, pkgName)) {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public static List<ResolveInfo> findActivitiesForPackage(Context context, String packageName) {
|
||||
final PackageManager packageManager = context.getPackageManager();
|
||||
|
||||
final Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);
|
||||
mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);
|
||||
mainIntent.setPackage(packageName);
|
||||
|
||||
final List<ResolveInfo> apps = packageManager.queryIntentActivities(mainIntent, 0);
|
||||
return apps != null ? apps : new ArrayList<ResolveInfo>();
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue