support Avoiding package siganture veriication
This commit is contained in:
parent
0d62107b36
commit
bf9db1ee30
Binary file not shown.
|
|
@ -3,6 +3,7 @@ package com.storm.wind.xpatch;
|
||||||
import com.storm.wind.xpatch.base.BaseCommand;
|
import com.storm.wind.xpatch.base.BaseCommand;
|
||||||
import com.storm.wind.xpatch.task.ApkModifyTask;
|
import com.storm.wind.xpatch.task.ApkModifyTask;
|
||||||
import com.storm.wind.xpatch.task.BuildAndSignApkTask;
|
import com.storm.wind.xpatch.task.BuildAndSignApkTask;
|
||||||
|
import com.storm.wind.xpatch.task.SaveApkSignatureTask;
|
||||||
import com.storm.wind.xpatch.task.SoAndDexCopyTask;
|
import com.storm.wind.xpatch.task.SoAndDexCopyTask;
|
||||||
import com.storm.wind.xpatch.util.FileUtils;
|
import com.storm.wind.xpatch.util.FileUtils;
|
||||||
import com.storm.wind.xpatch.util.ManifestParser;
|
import com.storm.wind.xpatch.util.ManifestParser;
|
||||||
|
|
@ -34,6 +35,10 @@ public class MainCommand extends BaseCommand {
|
||||||
@Opt(opt = "l", longOpt = "log", hasArg = false, description = "show all the debug logs")
|
@Opt(opt = "l", longOpt = "log", hasArg = false, description = "show all the debug logs")
|
||||||
private boolean showAllLogs = false;
|
private boolean showAllLogs = false;
|
||||||
|
|
||||||
|
@Opt(opt = "c", longOpt = "crach", hasArg = false,
|
||||||
|
description = "disable craching the apk's signature.")
|
||||||
|
private boolean disableCrackSignature = false;
|
||||||
|
|
||||||
// 原来apk中dex文件的数量
|
// 原来apk中dex文件的数量
|
||||||
private int dexFileCount = 0;
|
private int dexFileCount = 0;
|
||||||
|
|
||||||
|
|
@ -93,12 +98,14 @@ public class MainCommand extends BaseCommand {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
System.out.println(" !!!!! output apk path --> " + output);
|
System.out.println(" !!!!! output apk path --> " + output +
|
||||||
|
" disableCrackSignature --> " + disableCrackSignature);
|
||||||
|
|
||||||
String apkFileName = getBaseName(srcApkFile);
|
String apkFileName = getBaseName(srcApkFile);
|
||||||
|
|
||||||
// 中间文件临时存储的位置
|
// 中间文件临时存储的位置
|
||||||
String tempFilePath = srcApkFileParentPath + File.separator + currentTimeStr() + "-tmp" + File.separator;
|
String tempFilePath = srcApkFileParentPath + File.separator +
|
||||||
|
currentTimeStr() + "-tmp" + File.separator;
|
||||||
|
|
||||||
// apk文件解压的目录
|
// apk文件解压的目录
|
||||||
unzipApkFilePath = tempFilePath + apkFileName + "-" + UNZIP_APK_FILE_NAME + File.separator;
|
unzipApkFilePath = tempFilePath + apkFileName + "-" + UNZIP_APK_FILE_NAME + File.separator;
|
||||||
|
|
@ -108,6 +115,11 @@ public class MainCommand extends BaseCommand {
|
||||||
"\n unzipApkFilePath = " + unzipApkFilePath);
|
"\n unzipApkFilePath = " + unzipApkFilePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!disableCrackSignature) {
|
||||||
|
// save the apk original signature info, to support crach signature.
|
||||||
|
new SaveApkSignatureTask(apkPath, unzipApkFilePath).run();
|
||||||
|
}
|
||||||
|
|
||||||
// 先解压apk到指定目录下
|
// 先解压apk到指定目录下
|
||||||
FileUtils.decompressZip(apkPath, unzipApkFilePath);
|
FileUtils.decompressZip(apkPath, unzipApkFilePath);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,41 @@
|
||||||
|
package com.storm.wind.xpatch.task;
|
||||||
|
|
||||||
|
import com.storm.wind.xpatch.util.ApkSignatureHelper;
|
||||||
|
import com.storm.wind.xpatch.util.FileUtils;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by Wind
|
||||||
|
*/
|
||||||
|
public class SaveApkSignatureTask implements Runnable {
|
||||||
|
|
||||||
|
private String apkPath;
|
||||||
|
private String dstFilePath;
|
||||||
|
|
||||||
|
private final static String SIGNATURE_INFO_ASSET_PATH = "assets/xpatch_asset/original_signature_info.ini";
|
||||||
|
|
||||||
|
public SaveApkSignatureTask(String apkPath, String unzipApkFilePath) {
|
||||||
|
this.apkPath = apkPath;
|
||||||
|
this.dstFilePath = (unzipApkFilePath + SIGNATURE_INFO_ASSET_PATH).replace("/", File.separator);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
// First, get the original signature
|
||||||
|
String originalSignature = ApkSignatureHelper.getApkSignInfo(apkPath);
|
||||||
|
if (originalSignature == null || originalSignature.isEmpty()) {
|
||||||
|
System.out.println(" Get original signature failed !!!!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Then, save the signature chars to the asset file
|
||||||
|
File file = new File(dstFilePath);
|
||||||
|
File fileParent = file.getParentFile();
|
||||||
|
if (!fileParent.exists()) {
|
||||||
|
fileParent.mkdirs();
|
||||||
|
}
|
||||||
|
|
||||||
|
FileUtils.writeFile(dstFilePath, originalSignature);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,82 @@
|
||||||
|
package com.storm.wind.xpatch.util;
|
||||||
|
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.security.cert.Certificate;
|
||||||
|
import java.util.Enumeration;
|
||||||
|
import java.util.jar.JarEntry;
|
||||||
|
import java.util.jar.JarFile;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by Wind
|
||||||
|
*/
|
||||||
|
public class ApkSignatureHelper {
|
||||||
|
|
||||||
|
private static char[] toChars(byte[] mSignature) {
|
||||||
|
byte[] sig = mSignature;
|
||||||
|
final int N = sig.length;
|
||||||
|
final int N2 = N * 2;
|
||||||
|
char[] text = new char[N2];
|
||||||
|
for (int j = 0; j < N; j++) {
|
||||||
|
byte v = sig[j];
|
||||||
|
int d = (v >> 4) & 0xf;
|
||||||
|
text[j * 2] = (char) (d >= 10 ? ('a' + d - 10) : ('0' + d));
|
||||||
|
d = v & 0xf;
|
||||||
|
text[j * 2 + 1] = (char) (d >= 10 ? ('a' + d - 10) : ('0' + d));
|
||||||
|
}
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Certificate[] loadCertificates(JarFile jarFile, JarEntry je, byte[] readBuffer) {
|
||||||
|
try {
|
||||||
|
InputStream is = jarFile.getInputStream(je);
|
||||||
|
while (is.read(readBuffer, 0, readBuffer.length) != -1) {
|
||||||
|
}
|
||||||
|
is.close();
|
||||||
|
return (Certificate[]) (je != null ? je.getCertificates() : null);
|
||||||
|
} catch (Exception e) {
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getApkSignInfo(String apkFilePath) {
|
||||||
|
byte[] readBuffer = new byte[8192];
|
||||||
|
Certificate[] certs = null;
|
||||||
|
try {
|
||||||
|
JarFile jarFile = new JarFile(apkFilePath);
|
||||||
|
Enumeration<?> entries = jarFile.entries();
|
||||||
|
while (entries.hasMoreElements()) {
|
||||||
|
JarEntry je = (JarEntry) entries.nextElement();
|
||||||
|
if (je.isDirectory()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (je.getName().startsWith("META-INF/")) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
Certificate[] localCerts = loadCertificates(jarFile, je, readBuffer);
|
||||||
|
if (certs == null) {
|
||||||
|
certs = localCerts;
|
||||||
|
} else {
|
||||||
|
for (int i = 0; i < certs.length; i++) {
|
||||||
|
boolean found = false;
|
||||||
|
for (int j = 0; j < localCerts.length; j++) {
|
||||||
|
if (certs[i] != null && certs[i].equals(localCerts[j])) {
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!found || certs.length != localCerts.length) {
|
||||||
|
jarFile.close();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
jarFile.close();
|
||||||
|
System.out.println(" getApkSignInfo result --> " + certs[0]);
|
||||||
|
return new String(toChars(certs[0].getEncoded()));
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -2,6 +2,7 @@ package com.storm.wind.xpatch.util;
|
||||||
|
|
||||||
import java.io.BufferedInputStream;
|
import java.io.BufferedInputStream;
|
||||||
import java.io.BufferedOutputStream;
|
import java.io.BufferedOutputStream;
|
||||||
|
import java.io.BufferedWriter;
|
||||||
import java.io.Closeable;
|
import java.io.Closeable;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
|
|
@ -9,6 +10,7 @@ import java.io.FileOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
|
import java.io.OutputStreamWriter;
|
||||||
import java.nio.charset.Charset;
|
import java.nio.charset.Charset;
|
||||||
import java.util.Enumeration;
|
import java.util.Enumeration;
|
||||||
import java.util.zip.CRC32;
|
import java.util.zip.CRC32;
|
||||||
|
|
@ -205,6 +207,35 @@ public class FileUtils {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void writeFile(String filePath, String content) {
|
||||||
|
if (filePath == null || filePath.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (content == null || content.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
File dstFile = new File(filePath);
|
||||||
|
|
||||||
|
if (!dstFile.getParentFile().exists()) {
|
||||||
|
dstFile.getParentFile().mkdirs();
|
||||||
|
}
|
||||||
|
|
||||||
|
FileOutputStream outputStream = null;
|
||||||
|
BufferedWriter writer = null;
|
||||||
|
try {
|
||||||
|
outputStream = new FileOutputStream(dstFile);
|
||||||
|
writer = new BufferedWriter(new OutputStreamWriter(outputStream));
|
||||||
|
writer.write(content);
|
||||||
|
writer.flush();
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
} finally {
|
||||||
|
close(outputStream);
|
||||||
|
close(writer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static void close(Closeable closeable) {
|
private static void close(Closeable closeable) {
|
||||||
try {
|
try {
|
||||||
if (closeable != null) {
|
if (closeable != null) {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue