Commit 3615f339 authored by swift_gan's avatar swift_gan

done compat for xposed

parent 8e0774b6
......@@ -27,4 +27,5 @@ dependencies {
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
implementation project(':hooklib')
implementation project(':xposedcompat')
}
package com.swift.sandhook;
import android.app.Activity;
import android.app.Application;
import android.util.Log;
import com.swift.sandhook.testHookers.ActivityHooker;
import com.swift.sandhook.testHookers.CtrHook;
......@@ -9,13 +11,17 @@ import com.swift.sandhook.testHookers.JniHooker;
import com.swift.sandhook.testHookers.LogHooker;
import com.swift.sandhook.testHookers.ObjectHooker;
import com.swift.sandhook.wrapper.HookErrorException;
import com.swift.sandhook.xposedcompat.XposedCompat;
import dalvik.system.DexClassLoader;
import de.robv.android.xposed.XC_MethodHook;
import de.robv.android.xposed.XposedHelpers;
public class MyApp extends Application {
@Override
public void onCreate() {
super.onCreate();
try {
SandHook.addHookClass(JniHooker.class,
CtrHook.class,
......@@ -27,6 +33,26 @@ public class MyApp extends Application {
e.printStackTrace();
}
//setup for xposed
XposedCompat.cacheDir = getCacheDir();
XposedCompat.context = this;
XposedCompat.classLoader = getClassLoader();
XposedCompat.isFirstApplication= true;
XposedHelpers.findAndHookMethod(Activity.class, "onResume", new XC_MethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
super.beforeHookedMethod(param);
Log.e("XposedCompat", "beforeHookedMethod: " + param.method.getName());
}
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
super.afterHookedMethod(param);
Log.e("XposedCompat", "afterHookedMethod: " + param.method.getName());
}
});
try {
ClassLoader classLoader = getClassLoader();
DexClassLoader dexClassLoader = new DexClassLoader("/sdcard/hookers-debug.apk",
......
......@@ -10,9 +10,13 @@ import java.lang.reflect.Field;
import java.lang.reflect.Member;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
public class SandHook {
static Map<Member,HookWrapper.HookEntity> globalHookEntityMap = new ConcurrentHashMap<>();
public static Class artMethodClass;
public static Field nativePeerField;
......@@ -55,6 +59,15 @@ public class SandHook {
HookWrapper.addHookClass(classLoader, hookWrapperClass);
}
public static void hook(HookWrapper.HookEntity entity) throws HookErrorException {
if (entity.target != null && entity.hook != null) {
if (!SandHook.hook(entity.target, entity.hook, entity.backup)) {
throw new HookErrorException("hook method <" + entity.target.getName() + "> error in native!");
}
globalHookEntityMap.put(entity.target, entity);
}
}
public static boolean hook(Member target, Method hook, Method backup) {
if (target == null || hook == null)
return false;
......
......@@ -21,8 +21,6 @@ import java.util.concurrent.ConcurrentHashMap;
public class HookWrapper {
static Map<Member,HookEntity> globalHookEntityMap = new ConcurrentHashMap<>();
public static void addHookClass(Class<?>... classes) throws HookErrorException {
addHookClass(null, classes);
}
......@@ -40,12 +38,7 @@ public class HookWrapper {
Map<Member,HookEntity> hookEntityMap = getHookMethods(classLoader, targetHookClass, clazz);
fillBackupMethod(classLoader, clazz, hookEntityMap);
for (HookEntity entity:hookEntityMap.values()) {
if (entity.target != null && entity.hook != null) {
if (!SandHook.hook(entity.target, entity.hook, entity.backup)) {
throw new HookErrorException("hook method <" + entity.target.getName() + "> error in native!");
}
globalHookEntityMap.put(entity.target, entity);
}
SandHook.hook(entity);
}
}
......@@ -285,6 +278,11 @@ public class HookWrapper {
this.target = target;
}
public HookEntity(Member target, Method hook, Method backup) {
this.target = target;
this.hook = hook;
this.backup = backup;
}
public boolean isCtor() {
return target instanceof Constructor;
......
......@@ -25,6 +25,7 @@ android {
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation fileTree(include: ['*.jar'], dir: 'libs')
implementation 'com.linkedin.dexmaker:dexmaker:2.21.0'
compileOnly project(':hooklib')
}
package com.swift.sandhook.xposedcompat;
import android.app.ActivityManager;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.text.TextUtils;
import java.util.ArrayList;
import java.util.List;
/**
* Created by swift_gan on 2017/11/23.
*/
public class ProcessUtils {
private static volatile String processName = null;
public static String getProcessName(Context context) {
if (!TextUtils.isEmpty(processName))
return processName;
processName = doGetProcessName(context);
return processName;
}
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 boolean isMainProcess(Context context) {
String processName = getProcessName(context);
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>();
}
}
package com.swift.sandhook.xposedcompat;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import java.io.File;
public class XposedCompat {
public static File cacheDir;
public static Context context;
public static ClassLoader classLoader;
public static boolean isFirstApplication;
}
package com.swift.sandhook.xposedcompat.methodgen;
import android.util.Log;
import com.swift.sandhook.xposedcompat.BuildConfig;
public class DexLog {
public static final String TAG = "SandXposed-dexmaker";
public static int v(String s) {
return Log.v(TAG, s);
}
public static int i(String s) {
return Log.i(TAG, s);
}
public static int d(String s) {
if (BuildConfig.DEBUG) {
return Log.d(TAG, s);
}
return 0;
}
public static int w(String s) {
return Log.w(TAG, s);
}
public static int e(String s) {
return Log.e(TAG, s);
}
public static int e(String s, Throwable t) {
return Log.e(TAG, s, t);
}
}
......@@ -225,6 +225,7 @@ public class DexMakerUtils {
if (addInstMethod == null) {
try {
addInstMethod = Code.class.getDeclaredMethod("addInstruction", Insn.class);
addInstMethod.setAccessible(true);
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
......@@ -240,6 +241,7 @@ public class DexMakerUtils {
if (specMethod == null) {
try {
specMethod = Local.class.getDeclaredMethod("spec");
specMethod.setAccessible(true);
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
......
package com.swift.sandhook.xposedcompat.methodgen;
import com.swift.sandhook.xposedcompat.XposedCompat;
import java.io.File;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Member;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.HashMap;
import java.util.concurrent.atomic.AtomicBoolean;
import de.robv.android.xposed.XposedBridge;
public final class DynamicBridge {
private static final HashMap<Member, Method> hookedInfo = new HashMap<>();
private static final HookerDexMaker dexMaker = new HookerDexMaker();
private static final AtomicBoolean dexPathInited = new AtomicBoolean(false);
private static File dexDir;
private static File dexOptDir;
public static void onForkPost() {
dexPathInited.set(false);
}
public static synchronized void hookMethod(Member hookMethod, XposedBridge.AdditionalHookInfo additionalHookInfo) {
if (!checkMember(hookMethod)) {
return;
}
if (hookedInfo.containsKey(hookMethod)) {
DexLog.w("already hook method:" + hookMethod.toString());
return;
}
DexLog.d("start to generate class for: " + hookMethod);
try {
// using file based DexClassLoader
if (dexPathInited.compareAndSet(false, true)) {
// delete previous compiled dex to prevent potential crashing
// TODO find a way to reuse them in consideration of performance
try {
// we always choose to use device encrypted storage data on android N and later
// in case some app is installing hooks before phone is unlocked
String fixedAppDataDir = XposedCompat.cacheDir.getAbsolutePath();
dexDir = new File(fixedAppDataDir, "/sandxposed/");
dexOptDir = new File(dexDir, "oat");
dexDir.mkdirs();
try {
FileUtils.delete(dexOptDir);
} catch (Throwable throwable) {
}
} catch (Throwable throwable) {
DexLog.e("error when init dex path", throwable);
}
}
dexMaker.start(hookMethod, additionalHookInfo,
hookMethod.getDeclaringClass().getClassLoader(), dexDir == null ? null : dexDir.getAbsolutePath());
hookedInfo.put(hookMethod, dexMaker.getCallBackupMethod());
} catch (Exception e) {
DexLog.e("error occur when generating dex. dexDir=" + dexDir, e);
}
}
private static boolean checkMember(Member member) {
if (member instanceof Method) {
return true;
} else if (member instanceof Constructor<?>) {
return true;
} else if (member.getDeclaringClass().isInterface()) {
DexLog.e("Cannot hook interfaces: " + member.toString());
return false;
} else if (Modifier.isAbstract(member.getModifiers())) {
DexLog.e("Cannot hook abstract methods: " + member.toString());
return false;
} else {
DexLog.e("Only methods and constructors can be hooked: " + member.toString());
return false;
}
}
public static Object invokeOriginalMethod(Member method, Object thisObject, Object[] args)
throws InvocationTargetException, IllegalAccessException {
Method callBackup = hookedInfo.get(method);
if (callBackup == null) {
throw new IllegalStateException("method not hooked, cannot call original method.");
}
if (!Modifier.isStatic(callBackup.getModifiers())) {
throw new IllegalStateException("original method is not static, something must be wrong!");
}
callBackup.setAccessible(true);
if (args == null) {
args = new Object[0];
}
final int argsSize = args.length;
if (Modifier.isStatic(method.getModifiers())) {
return callBackup.invoke(null, args);
} else {
Object[] newArgs = new Object[argsSize + 1];
newArgs[0] = thisObject;
for (int i = 1; i < newArgs.length; i++) {
newArgs[i] = args[i - 1];
}
return callBackup.invoke(null, newArgs);
}
}
}
package com.swift.sandhook.xposedcompat.methodgen;
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/";
}
}
......@@ -11,6 +11,8 @@ import com.android.dx.Label;
import com.android.dx.Local;
import com.android.dx.MethodId;
import com.android.dx.TypeId;
import com.swift.sandhook.SandHook;
import com.swift.sandhook.wrapper.HookWrapper;
import java.io.File;
import java.lang.reflect.Constructor;
......@@ -37,7 +39,7 @@ public class HookerDexMaker {
public static final String METHOD_NAME_SETUP = "setup";
public static final TypeId<Object[]> objArrayTypeId = TypeId.get(Object[].class);
private static final String CLASS_DESC_PREFIX = "L";
private static final String CLASS_NAME_PREFIX = "EdHooker";
private static final String CLASS_NAME_PREFIX = "SandHooker";
private static final String FIELD_NAME_HOOK_INFO = "additionalHookInfo";
private static final String FIELD_NAME_METHOD = "method";
private static final String PARAMS_FIELD_NAME_METHOD = "method";
......@@ -203,7 +205,7 @@ public class HookerDexMaker {
mHookMethod = mHookClass.getMethod(METHOD_NAME_HOOK, mActualParameterTypes);
mBackupMethod = mHookClass.getMethod(METHOD_NAME_BACKUP, mActualParameterTypes);
mCallBackupMethod = mHookClass.getMethod(METHOD_NAME_CALL_BACKUP, mActualParameterTypes);
//HookMain.backupAndHook(mMember, mHookMethod, mBackupMethod);
SandHook.hook(new HookWrapper.HookEntity(mMember, mHookMethod, mBackupMethod));
}
public Method getHookMethod() {
......
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 de.robv.android.xposed;
import android.content.res.XResources;
//import android.content.res.XResources;
import de.robv.android.xposed.callbacks.XC_InitPackageResources;
import de.robv.android.xposed.callbacks.XC_InitPackageResources.InitPackageResourcesParam;
......
package de.robv.android.xposed;
import android.os.SELinux;
//import android.os.SELinux;
import de.robv.android.xposed.services.BaseService;
import de.robv.android.xposed.services.DirectAccessService;
......@@ -25,18 +25,18 @@ public final class SELinuxHelper {
*
* @return A boolean indicating whether SELinux is enforcing.
*/
public static boolean isSELinuxEnforced() {
return sIsSELinuxEnabled && SELinux.isSELinuxEnforced();
}
// public static boolean isSELinuxEnforced() {
// return sIsSELinuxEnabled && SELinux.isSELinuxEnforced();
// }
/**
* Gets the security context of the current process.
*
* @return A String representing the security context of the current process.
*/
public static String getContext() {
return sIsSELinuxEnabled ? SELinux.getContext() : null;
}
// public static String getContext() {
// return sIsSELinuxEnabled ? SELinux.getContext() : null;
// }
/**
* Retrieve the service to be used when accessing files in {@code /data/data/*}.
......
......@@ -7,7 +7,6 @@ import android.os.Environment;
import android.preference.PreferenceManager;
import android.util.Log;
import com.android.internal.util.XmlUtils;
import org.xmlpull.v1.XmlPullParserException;
......@@ -121,14 +120,12 @@ public final class XSharedPreferences implements SharedPreferences {
try {
result = SELinuxHelper.getAppDataFileService().getFileInputStream(mFilename, mFileSize, mLastModified);
if (result.stream != null) {
map = XmlUtils.readMapXml(result.stream);
//map = XmlUtils.readMapXml(result.stream);
result.stream.close();
} else {
// The file is unchanged, keep the current values
map = mMap;
}
} catch (XmlPullParserException e) {
Log.w(TAG, "getSharedPreferences", e);
} catch (FileNotFoundException ignored) {
// SharedPreferencesImpl has a canRead() check, so it doesn't log anything in case the file doesn't exist
} catch (IOException e) {
......
......@@ -4,6 +4,8 @@ import android.annotation.SuppressLint;
import android.util.Log;
import com.swift.sandhook.xposedcompat.methodgen.DynamicBridge;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.AccessibleObject;
......@@ -151,7 +153,6 @@ public final class XposedBridge {
* @see #hookAllConstructors
*/
public static XC_MethodHook.Unhook hookMethod(Member hookMethod, XC_MethodHook callback) {
hookMethod = MethodHookUtils.preCheck(hookMethod);
if (!(hookMethod instanceof Method) && !(hookMethod instanceof Constructor<?>)) {
throw new IllegalArgumentException("Only methods and constructors can be hooked: " + hookMethod.toString());
} else if (hookMethod.getDeclaringClass().isInterface()) {
......@@ -196,16 +197,7 @@ public final class XposedBridge {
}
AdditionalHookInfo additionalInfo = new AdditionalHookInfo(callbacks, parameterTypes, returnType);
MethodInfo methodInfo = new MethodInfo(hookMethod);
declaringClass = methodInfo.getClassForSure();
Member reflectMethod = (Member) HookMain.findMethod(
declaringClass, methodInfo.methodName, methodInfo.methodSig);
if (reflectMethod == null) {
Log.e(TAG, "method not found: name="
+ methodInfo.methodName + ", sig=" + methodInfo.methodSig);
reflectMethod = hookMethod;
}
hookMethodNative(reflectMethod, declaringClass, slot, additionalInfo);
hookMethodNative(hookMethod, declaringClass, slot, additionalInfo);
}
return callback.new Unhook(hookMethod);
......
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.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;
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*/
public static void initForZygote(boolean isSystem) throws Throwable {
if (!bootstrapHooked.compareAndSet(false, true)) {
return;
}
startsSystemServer = isSystem;
Router.startBootstrapHook(isSystem);
// MIUI
if (findFieldIfExists(ZygoteInit.class, "BOOT_START_TIME") != null) {
setStaticLongField(ZygoteInit.class, "BOOT_START_TIME", XposedBridge.BOOT_START_TIME);
}
// Samsung
if (Build.VERSION.SDK_INT >= 24) {
Class<?> zygote = findClass("com.android.internal.os.Zygote", null);
try {
setStaticBooleanField(zygote, "isEnhancedZygoteASLREnabled", false);
} catch (NoSuchFieldError ignored) {
}
}
}
/*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) {
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);
}
// 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;
// }
// startsSystemServer = isSystem;
// Router.startBootstrapHook(isSystem);
// // MIUI
// if (findFieldIfExists(ZygoteInit.class, "BOOT_START_TIME") != null) {
// setStaticLongField(ZygoteInit.class, "BOOT_START_TIME", XposedBridge.BOOT_START_TIME);
// }
//
// // Samsung
// if (Build.VERSION.SDK_INT >= 24) {
// Class<?> zygote = findClass("com.android.internal.os.Zygote", null);
// try {
// setStaticBooleanField(zygote, "isEnhancedZygoteASLREnabled", false);
// } catch (NoSuchFieldError ignored) {
// }
// }
// }
//
// /*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) {
// 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);
// }
}
package de.robv.android.xposed.callbacks;
import android.content.res.XResources;
//import android.content.res.XResources;
import de.robv.android.xposed.IXposedHookInitPackageResources;
import de.robv.android.xposed.XposedBridge.CopyOnWriteSortedSet;
......@@ -45,7 +45,7 @@ public abstract class XC_InitPackageResources extends XCallback implements IXpos
* Reference to the resources that can be used for calls to
* {@link XResources#setReplacement(String, String, String, Object)}.
*/
public XResources res;
//public XResources res;
}
/** @hide */
......
package de.robv.android.xposed.callbacks;
import android.content.res.XResources;
import android.content.res.XResources.ResourceNames;
//import android.content.res.XResources;
//import android.content.res.XResources.ResourceNames;
import android.view.View;
import de.robv.android.xposed.XposedBridge.CopyOnWriteSortedSet;
......@@ -41,13 +41,13 @@ public abstract class XC_LayoutInflated extends XCallback {
public View view;
/** Container with the ID and name of the underlying resource. */
public ResourceNames resNames;
// public ResourceNames resNames;
/** Directory from which the layout was actually loaded (e.g. "layout-sw600dp"). */
public String variant;
// public String variant;
/** Resources containing the layout. */
public XResources res;
// public XResources res;
}
/** @hide */
......@@ -92,7 +92,7 @@ public abstract class XC_LayoutInflated extends XCallback {
@Override
public void unhook() {
XResources.unhookLayout(resDir, id, XC_LayoutInflated.this);
// XResources.unhookLayout(resDir, id, XC_LayoutInflated.this);
}
}
......
......@@ -2,6 +2,9 @@ package de.robv.android.xposed.callbacks;
import android.content.pm.ApplicationInfo;
import com.swift.sandhook.xposedcompat.ProcessUtils;
import com.swift.sandhook.xposedcompat.XposedCompat;
import de.robv.android.xposed.IXposedHookLoadPackage;
import de.robv.android.xposed.XposedBridge.CopyOnWriteSortedSet;
......@@ -39,19 +42,19 @@ public abstract class XC_LoadPackage extends XCallback implements IXposedHookLoa
}
/** The name of the package being loaded. */
public String packageName;
public String packageName = XposedCompat.context.getPackageName();
/** The process in which the package is executed. */
public String processName;
public String processName = ProcessUtils.getProcessName(XposedCompat.context);
/** The ClassLoader used for this package. */
public ClassLoader classLoader;
public ClassLoader classLoader = XposedCompat.classLoader;
/** More information about the application being loaded. */
public ApplicationInfo appInfo;
public ApplicationInfo appInfo = XposedCompat.context.getApplicationInfo();
/** Set to {@code true} if this is the first (and main) application for this process. */
public boolean isFirstApplication;
public boolean isFirstApplication = XposedCompat.isFirstApplication;
}
/** @hide */
......
......@@ -3,7 +3,7 @@ package de.robv.android.xposed.services;
import android.os.IBinder;
import android.os.Parcel;
import android.os.RemoteException;
import android.os.ServiceManager;
//import android.os.ServiceManager;
import java.io.IOException;
......@@ -158,7 +158,7 @@ public final class BinderService extends BaseService {
private final IBinder mRemote;
private BinderService(int target) {
IBinder binder = ServiceManager.getService(SERVICE_NAMES[target]);
IBinder binder = null; //ServiceManager.getService(SERVICE_NAMES[target]);
if (binder == null)
throw new IllegalStateException("Service " + SERVICE_NAMES[target] + " does not exist");
this.mRemote = binder;
......
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