修复bug
This commit is contained in:
parent
0f2645ee04
commit
863739ea27
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -189,7 +189,13 @@ public class MainCommand extends BaseCommand {
|
||||||
manifestFile.renameTo(manifestFileNew);
|
manifestFile.renameTo(manifestFileNew);
|
||||||
|
|
||||||
modifyManifestFile(manifestFilePathNew, manifestFilePath, applicationName);
|
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
|
// save original main application name to asset file
|
||||||
if (isNotEmpty(applicationName)) {
|
if (isNotEmpty(applicationName)) {
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,7 @@ public class ApkModifyTask implements Runnable {
|
||||||
|
|
||||||
String jarOutputPath = unzipApkFile.getParent() + File.separator + JAR_FILE_NAME;
|
String jarOutputPath = unzipApkFile.getParent() + File.separator + JAR_FILE_NAME;
|
||||||
|
|
||||||
// classes-1.0.dex
|
// classes.dex
|
||||||
String targetDexFileName = dumpJarFile(dexFileCount, unzipApkFilePath, jarOutputPath, applicationName);
|
String targetDexFileName = dumpJarFile(dexFileCount, unzipApkFilePath, jarOutputPath, applicationName);
|
||||||
|
|
||||||
if (showAllLogs) {
|
if (showAllLogs) {
|
||||||
|
|
@ -104,12 +104,12 @@ public class ApkModifyTask implements Runnable {
|
||||||
cmd.doMain(args);
|
cmd.doMain(args);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 列出目录下所有dex文件,classes-1.0.dex,classes2.dex,classes3.dex .....
|
// 列出目录下所有dex文件,classes.dex,classes2.dex,classes3.dex .....
|
||||||
private ArrayList<String> createClassesDotDexFileList(int dexFileCount) {
|
private ArrayList<String> createClassesDotDexFileList(int dexFileCount) {
|
||||||
ArrayList<String> list = new ArrayList<>();
|
ArrayList<String> list = new ArrayList<>();
|
||||||
for (int i = 0; i < dexFileCount; i++) {
|
for (int i = 0; i < dexFileCount; i++) {
|
||||||
if (i == 0) {
|
if (i == 0) {
|
||||||
list.add("classes-1.0.dex");
|
list.add("classes.dex");
|
||||||
} else {
|
} else {
|
||||||
list.add("classes" + (i + 1) + ".dex");
|
list.add("classes" + (i + 1) + ".dex");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -58,7 +58,7 @@ public class BuildAndSignApkTask implements Runnable {
|
||||||
if (isAndroid()) {
|
if (isAndroid()) {
|
||||||
boolean success = true;
|
boolean success = true;
|
||||||
try {
|
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
|
net.fornwall.apksigner.Main.main
|
||||||
("--password", "123456", keyStorePath, apkPath, signedApkPath);
|
("--password", "123456", keyStorePath, apkPath, signedApkPath);
|
||||||
} catch (Exception e1) {
|
} catch (Exception e1) {
|
||||||
|
|
@ -83,7 +83,7 @@ public class BuildAndSignApkTask implements Runnable {
|
||||||
String localJarsignerPath = (new File(apkPath)).getParent() + File.separator + "jarsigner-081688";
|
String localJarsignerPath = (new File(apkPath)).getParent() + File.separator + "jarsigner-081688";
|
||||||
localJarsignerFile = new File(localJarsignerPath);
|
localJarsignerFile = new File(localJarsignerPath);
|
||||||
FileUtils.copyFileFromJar("assets/jarsigner", 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);
|
// ShellCmdUtil.execCmd("chmod -R 777 " + localJarsignerPath, null);
|
||||||
signCmd = new StringBuilder(localJarsignerPath + " ");
|
signCmd = new StringBuilder(localJarsignerPath + " ");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,9 @@ public class SoAndDexCopyTask implements Runnable {
|
||||||
private static final String SANDHOOK_SO_FILE_NAME = "libsandhook";
|
private static final String SANDHOOK_SO_FILE_NAME = "libsandhook";
|
||||||
private static final String WHALE_SO_FILE_NAME = "libwhale";
|
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 XPOSED_MODULE_FILE_NAME_PREFIX = "libxpatch_xp_module_";
|
||||||
private static final String SO_FILE_SUFFIX = ".so";
|
private static final String SO_FILE_SUFFIX = ".so";
|
||||||
|
|
||||||
|
|
@ -28,11 +30,14 @@ public class SoAndDexCopyTask implements Runnable {
|
||||||
private String unzipApkFilePath;
|
private String unzipApkFilePath;
|
||||||
private String[] xposedModuleArray;
|
private String[] xposedModuleArray;
|
||||||
|
|
||||||
|
private boolean useWhaleHookFramework;
|
||||||
|
|
||||||
public SoAndDexCopyTask(int dexFileCount, String unzipApkFilePath,
|
public SoAndDexCopyTask(int dexFileCount, String unzipApkFilePath,
|
||||||
String[] xposedModuleArray, boolean useWhaleHookFramework) {
|
String[] xposedModuleArray, boolean useWhaleHookFramework) {
|
||||||
this.dexFileCount = dexFileCount;
|
this.dexFileCount = dexFileCount;
|
||||||
this.unzipApkFilePath = unzipApkFilePath;
|
this.unzipApkFilePath = unzipApkFilePath;
|
||||||
this.xposedModuleArray = xposedModuleArray;
|
this.xposedModuleArray = xposedModuleArray;
|
||||||
|
this.useWhaleHookFramework = useWhaleHookFramework;
|
||||||
|
|
||||||
String soFileName;
|
String soFileName;
|
||||||
if (useWhaleHookFramework) {
|
if (useWhaleHookFramework) {
|
||||||
|
|
@ -113,7 +118,13 @@ public class SoAndDexCopyTask implements Runnable {
|
||||||
// copy dex file to root dir, rename it first
|
// copy dex file to root dir, rename it first
|
||||||
String copiedDexFileName = "classes" + (dexFileCount + 1) + ".dex";
|
String copiedDexFileName = "classes" + (dexFileCount + 1) + ".dex";
|
||||||
// assets/classes.dex分隔符不能使用File.seperater,否则在windows上无法读取到文件,IOException
|
// 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) {
|
private String fullLibPath(String libPath) {
|
||||||
|
|
@ -129,7 +140,12 @@ public class SoAndDexCopyTask implements Runnable {
|
||||||
// get the file name first
|
// get the file name first
|
||||||
// int lastIndex = srcSoPath.lastIndexOf('/');
|
// int lastIndex = srcSoPath.lastIndexOf('/');
|
||||||
// int length = srcSoPath.length();
|
// 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
|
// do copy
|
||||||
FileUtils.copyFileFromJar(srcSoPath, new File(apkSoParentFile, soFileName).getAbsolutePath());
|
FileUtils.copyFileFromJar(srcSoPath, new File(apkSoParentFile, soFileName).getAbsolutePath());
|
||||||
|
|
|
||||||
|
|
@ -3,12 +3,7 @@ package com.storm.wind.xpatch.util;
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.lang.reflect.InvocationTargetException;
|
import java.lang.reflect.InvocationTargetException;
|
||||||
import java.lang.reflect.Method;
|
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 {
|
public class ReflectUtils {
|
||||||
|
|
||||||
//获取类的实例的变量的值
|
//获取类的实例的变量的值
|
||||||
|
|
@ -269,88 +264,4 @@ public class ReflectUtils {
|
||||||
return findField(base, name);
|
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> 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> 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.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -57,6 +57,15 @@ public class ShellCmdUtil {
|
||||||
return result.toString();
|
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 {
|
public static void chmod(String path, int mode) throws Exception {
|
||||||
chmodOnAndroid(path, mode);
|
chmodOnAndroid(path, mode);
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue