diff --git a/xpatch/src/main/assets/classes-1.0.dex b/xpatch/src/main/assets/classes-1.0.dex deleted file mode 100644 index 1710f6b..0000000 Binary files a/xpatch/src/main/assets/classes-1.0.dex and /dev/null differ diff --git a/xpatch/src/main/assets/dex/sandhook/classes-1.0.dex b/xpatch/src/main/assets/dex/sandhook/classes-1.0.dex new file mode 100644 index 0000000..852447c Binary files /dev/null and b/xpatch/src/main/assets/dex/sandhook/classes-1.0.dex differ diff --git a/xpatch/src/main/assets/dex/whale/classes-1.0.dex b/xpatch/src/main/assets/dex/whale/classes-1.0.dex new file mode 100644 index 0000000..61dca4d Binary files /dev/null and b/xpatch/src/main/assets/dex/whale/classes-1.0.dex differ diff --git a/xpatch/src/main/java/com/storm/wind/xpatch/MainCommand.java b/xpatch/src/main/java/com/storm/wind/xpatch/MainCommand.java index 3ade4f6..3ca255b 100644 --- a/xpatch/src/main/java/com/storm/wind/xpatch/MainCommand.java +++ b/xpatch/src/main/java/com/storm/wind/xpatch/MainCommand.java @@ -189,7 +189,13 @@ public class MainCommand extends BaseCommand { manifestFile.renameTo(manifestFileNew); modifyManifestFile(manifestFilePathNew, manifestFilePath, applicationName); - manifestFileNew.delete(); + + // new manifest may not exist + if (manifestFile.exists() && manifestFile.length() > 0) { + manifestFileNew.delete(); + } else { + manifestFileNew.renameTo(manifestFile); + } // save original main application name to asset file if (isNotEmpty(applicationName)) { diff --git a/xpatch/src/main/java/com/storm/wind/xpatch/task/ApkModifyTask.java b/xpatch/src/main/java/com/storm/wind/xpatch/task/ApkModifyTask.java index d13a98f..89941eb 100644 --- a/xpatch/src/main/java/com/storm/wind/xpatch/task/ApkModifyTask.java +++ b/xpatch/src/main/java/com/storm/wind/xpatch/task/ApkModifyTask.java @@ -36,7 +36,7 @@ public class ApkModifyTask implements Runnable { String jarOutputPath = unzipApkFile.getParent() + File.separator + JAR_FILE_NAME; - // classes-1.0.dex + // classes.dex String targetDexFileName = dumpJarFile(dexFileCount, unzipApkFilePath, jarOutputPath, applicationName); if (showAllLogs) { @@ -104,12 +104,12 @@ public class ApkModifyTask implements Runnable { cmd.doMain(args); } - // 列出目录下所有dex文件,classes-1.0.dex,classes2.dex,classes3.dex ..... + // 列出目录下所有dex文件,classes.dex,classes2.dex,classes3.dex ..... private ArrayList createClassesDotDexFileList(int dexFileCount) { ArrayList list = new ArrayList<>(); for (int i = 0; i < dexFileCount; i++) { if (i == 0) { - list.add("classes-1.0.dex"); + list.add("classes.dex"); } else { list.add("classes" + (i + 1) + ".dex"); } diff --git a/xpatch/src/main/java/com/storm/wind/xpatch/task/BuildAndSignApkTask.java b/xpatch/src/main/java/com/storm/wind/xpatch/task/BuildAndSignApkTask.java index ab76f72..0f80f0f 100644 --- a/xpatch/src/main/java/com/storm/wind/xpatch/task/BuildAndSignApkTask.java +++ b/xpatch/src/main/java/com/storm/wind/xpatch/task/BuildAndSignApkTask.java @@ -58,7 +58,7 @@ public class BuildAndSignApkTask implements Runnable { if (isAndroid()) { boolean success = true; try { - ShellCmdUtil.chmod((new File(apkPath)).getParent(), ShellCmdUtil.FileMode.MODE_755); + ShellCmdUtil.chmodNoException((new File(apkPath)).getParent(), ShellCmdUtil.FileMode.MODE_755); net.fornwall.apksigner.Main.main ("--password", "123456", keyStorePath, apkPath, signedApkPath); } catch (Exception e1) { @@ -83,7 +83,7 @@ public class BuildAndSignApkTask implements Runnable { String localJarsignerPath = (new File(apkPath)).getParent() + File.separator + "jarsigner-081688"; localJarsignerFile = new File(localJarsignerPath); FileUtils.copyFileFromJar("assets/jarsigner", localJarsignerPath); - ShellCmdUtil.chmod(localJarsignerPath, ShellCmdUtil.FileMode.MODE_755); + ShellCmdUtil.chmodNoException(localJarsignerPath, ShellCmdUtil.FileMode.MODE_755); // ShellCmdUtil.execCmd("chmod -R 777 " + localJarsignerPath, null); signCmd = new StringBuilder(localJarsignerPath + " "); } diff --git a/xpatch/src/main/java/com/storm/wind/xpatch/task/SoAndDexCopyTask.java b/xpatch/src/main/java/com/storm/wind/xpatch/task/SoAndDexCopyTask.java index 18456fa..66a92f2 100644 --- a/xpatch/src/main/java/com/storm/wind/xpatch/task/SoAndDexCopyTask.java +++ b/xpatch/src/main/java/com/storm/wind/xpatch/task/SoAndDexCopyTask.java @@ -13,7 +13,9 @@ public class SoAndDexCopyTask implements Runnable { private static final String SANDHOOK_SO_FILE_NAME = "libsandhook"; private static final String WHALE_SO_FILE_NAME = "libwhale"; - private static final String SO_FILE_NAME_WITH_SUFFIX = "libsandhook"; + private static final String SANDHOOK_SO_FILE_NAME_WITH_SUFFIX = "libsandhook.so"; + private static final String WHALE_SO_FILE_NAME_WITH_SUFFIX = "libwhale.so"; + private static final String XPOSED_MODULE_FILE_NAME_PREFIX = "libxpatch_xp_module_"; private static final String SO_FILE_SUFFIX = ".so"; @@ -28,11 +30,14 @@ public class SoAndDexCopyTask implements Runnable { private String unzipApkFilePath; private String[] xposedModuleArray; + private boolean useWhaleHookFramework; + public SoAndDexCopyTask(int dexFileCount, String unzipApkFilePath, String[] xposedModuleArray, boolean useWhaleHookFramework) { this.dexFileCount = dexFileCount; this.unzipApkFilePath = unzipApkFilePath; this.xposedModuleArray = xposedModuleArray; + this.useWhaleHookFramework = useWhaleHookFramework; String soFileName; if (useWhaleHookFramework) { @@ -113,7 +118,13 @@ public class SoAndDexCopyTask implements Runnable { // copy dex file to root dir, rename it first String copiedDexFileName = "classes" + (dexFileCount + 1) + ".dex"; // assets/classes.dex分隔符不能使用File.seperater,否则在windows上无法读取到文件,IOException - FileUtils.copyFileFromJar("assets/classes-1.0.dex", unzipApkFilePath + copiedDexFileName); + String dexAssetPath; + if (useWhaleHookFramework) { + dexAssetPath = "assets/dex/whale/classes-1.0.dex"; + } else { + dexAssetPath = "assets/dex/sandhook/classes-1.0.dex"; + } + FileUtils.copyFileFromJar(dexAssetPath, unzipApkFilePath + copiedDexFileName); } private String fullLibPath(String libPath) { @@ -129,7 +140,12 @@ public class SoAndDexCopyTask implements Runnable { // get the file name first // int lastIndex = srcSoPath.lastIndexOf('/'); // int length = srcSoPath.length(); - String soFileName = SO_FILE_NAME_WITH_SUFFIX; + String soFileName; + if (useWhaleHookFramework) { + soFileName = WHALE_SO_FILE_NAME_WITH_SUFFIX; + } else { + soFileName = SANDHOOK_SO_FILE_NAME_WITH_SUFFIX; + } // do copy FileUtils.copyFileFromJar(srcSoPath, new File(apkSoParentFile, soFileName).getAbsolutePath()); diff --git a/xpatch/src/main/java/com/storm/wind/xpatch/util/ReflectUtils.java b/xpatch/src/main/java/com/storm/wind/xpatch/util/ReflectUtils.java index 8049bcf..e684877 100644 --- a/xpatch/src/main/java/com/storm/wind/xpatch/util/ReflectUtils.java +++ b/xpatch/src/main/java/com/storm/wind/xpatch/util/ReflectUtils.java @@ -3,12 +3,7 @@ package com.storm.wind.xpatch.util; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; -import java.lang.reflect.ParameterizedType; -import java.lang.reflect.Type; -/** - * Created by xiawanli on 2018/8/25 - */ public class ReflectUtils { //获取类的实例的变量的值 @@ -269,88 +264,4 @@ public class ReflectUtils { return findField(base, name); } } - - //表示Field或者Class是编译器自动生成的 - private static final int SYNTHETIC = 0x00001000; - //表示Field是final的 - private static final int FINAL = 0x00000010; - //内部类持有的外部类对象一定有这两个属性 - private static final int SYNTHETIC_AND_FINAL = SYNTHETIC | FINAL; - - private static boolean checkModifier(int mod) { - return (mod & SYNTHETIC_AND_FINAL) == SYNTHETIC_AND_FINAL; - } - - //获取内部类实例持有的外部类对象 - public static T getExternalField(Object innerObj) { - return getExternalField(innerObj, null); - } - - /** - * 内部类持有的外部类对象的形式为: - * final Outer this$0; - * flags: ACC_FINAL, ACC_SYNTHETIC - * 参考:https://www.jianshu.com/p/9335c15c43cf - * And:https://www.2cto.com/kf/201402/281879.html - * - * @param innerObj 内部类对象 - * @param name 内部类持有的外部类名称,默认是"this$0" - * @return 内部类持有的外部类对象 - */ - private static T getExternalField(Object innerObj, String name) { - Class clazz = innerObj.getClass(); - if (name == null || name.isEmpty()) { - name = "this$0"; - } - Field field; - try { - field = clazz.getDeclaredField(name); - } catch (NoSuchFieldException e) { - e.printStackTrace(); - return null; - } - field.setAccessible(true); - if (checkModifier(field.getModifiers())) { - try { - return (T) field.get(innerObj); - } catch (IllegalAccessException e) { - throw new RuntimeException(e); - } - } - return getExternalField(innerObj, name + "$"); - } - - //获取当前对象的泛型类 added by xia wanli - public static Class getParameterizedClassType(Object object) { - Class clazz; - //getGenericSuperclass()获得带有泛型的父类 - //Type是 Java 中所有类型的公共高级接口。包括原始类型、参数化类型、数组类型、类型变量和基本类型。 - Type genericSuperclass = object.getClass().getGenericSuperclass(); - if (genericSuperclass instanceof ParameterizedType) { - //ParameterizedType参数化类型,即泛型 - ParameterizedType parameterizedType = (ParameterizedType) genericSuperclass; - //getActualTypeArguments获取参数化类型的数组,泛型可能有多个 - Type[] actualTypeArguments = parameterizedType.getActualTypeArguments(); - clazz = (Class) actualTypeArguments[0]; - } else { - clazz = (Class) genericSuperclass; - } - return clazz; - } - - //获取当前对象的泛型类 added by xia wanli - public static Type getObjectParameterizedType(Object object) { - //getGenericSuperclass()获得带有泛型的父类 - //Type是 Java 中所有类型的公共高级接口。包括原始类型、参数化类型、数组类型、类型变量和基本类型。 - Type genericSuperclass = object.getClass().getGenericSuperclass(); - if (genericSuperclass instanceof ParameterizedType) { - //ParameterizedType参数化类型,即泛型 - ParameterizedType parameterizedType = (ParameterizedType) genericSuperclass; - //getActualTypeArguments获取参数化类型的数组,泛型可能有多个 - Type[] actualTypeArguments = parameterizedType.getActualTypeArguments(); - return actualTypeArguments[0]; - } else { - throw new RuntimeException("Missing type parameter."); - } - } } diff --git a/xpatch/src/main/java/com/storm/wind/xpatch/util/ShellCmdUtil.java b/xpatch/src/main/java/com/storm/wind/xpatch/util/ShellCmdUtil.java index 9a57e82..f17b7c8 100644 --- a/xpatch/src/main/java/com/storm/wind/xpatch/util/ShellCmdUtil.java +++ b/xpatch/src/main/java/com/storm/wind/xpatch/util/ShellCmdUtil.java @@ -57,6 +57,15 @@ public class ShellCmdUtil { return result.toString(); } + public static void chmodNoException(String path, int mode) { + try { + chmod(path, mode); + } catch (Exception e) { + e.printStackTrace(); + System.err.println("chmod exception path --> " + path + " exception -->" + e.getMessage()); + } + } + public static void chmod(String path, int mode) throws Exception { chmodOnAndroid(path, mode);