Skip to content

Instantly share code, notes, and snippets.

@Forgo7ten
Created November 23, 2021 00:19
Show Gist options
  • Save Forgo7ten/12a12f2edf300f5b9c6e3cb6a7ebe14c to your computer and use it in GitHub Desktop.
Save Forgo7ten/12a12f2edf300f5b9c6e3cb6a7ebe14c to your computer and use it in GitHub Desktop.
修改dex文件并修复 CheckSum、filesize、sha1;将某文件添加到dex文件的末尾
import java.io.*;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.zip.Adler32;
public class FirstShellTool {
private static final String originApk = "C:\\Users\\Palmer\\Desktop\\classes3.dex";
private static final String shellDex = "C:\\Users\\Palmer\\Desktop\\app-debug\\classes3.dex";
private static final String outDex = "C:\\Users\\Palmer\\Desktop\\classes_out.dex";
public static void main(String[] args) {
// TODO Auto-generated method stub
try {
//需要加壳的程序
File payloadSrcFile = new File(originApk);
System.out.println("apk size:" + Long.toHexString(payloadSrcFile.length()));
// 壳dex
File unShellDexFile = new File(shellDex);
// 读apk的字节
byte[] apkBytes = readFileBytes(payloadSrcFile);
// 对源apk字节进行加密
byte[] payloadArray = encrpt(apkBytes);
// 读出壳dex的字节
byte[] unShellDexArray = readFileBytes(unShellDexFile);
// 获取apk字节的长度
int payloadLen = payloadArray.length;
// 获取壳dex字节的长度
int unShellDexLen = unShellDexArray.length;
// 构造新dex字节长度,多出的4字节存放源zip的长度
int totalLen = payloadLen + unShellDexLen + 4;
// 申请相应大小的空间
byte[] newdex = new byte[totalLen];
// 先拷贝壳dex内容,添加解壳代码
System.arraycopy(unShellDexArray, 0, newdex, 0, unShellDexLen);
// 再在dex内容后面拷贝apk的内容
System.arraycopy(payloadArray, 0, newdex, unShellDexLen, payloadLen);
// 添加apk长度
System.arraycopy(intToByte(payloadLen), 0, newdex, totalLen - 4, 4);
//修改DEX file size文件头
fixFileSizeHeader(newdex);
//修改DEX SHA1 文件头
fixSHA1Header(newdex);
//修改DEX CheckSum文件头
fixCheckSumHeader(newdex);
File file = new File(outDex);
if (!file.exists()) {
file.createNewFile();
}
FileOutputStream localFileOutputStream = new FileOutputStream(outDex);
localFileOutputStream.write(newdex);
localFileOutputStream.flush();
localFileOutputStream.close();
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("Done!");
}
// 对源apk字节进行加密的方法,这里没有进行加密
private static byte[] encrpt(byte[] srcdata) {
return srcdata;
}
/**
* 修改dex头,CheckSum 校验码
* @param dexBytes
*/
private static void fixCheckSumHeader(byte[] dexBytes) {
Adler32 adler = new Adler32();
// 从12到文件末尾计算校验码
adler.update(dexBytes, 12, dexBytes.length - 12);
long value = adler.getValue();
int va = (int) value;
byte[] newcs = intToByte(va);
// 高位在前,低位在前掉个
byte[] recs = new byte[4];
for (int i = 0; i < 4; i++) {
recs[i] = newcs[newcs.length - 1 - i];
}
// 效验码赋值(8-11)
System.arraycopy(recs, 0, dexBytes, 8, 4);
System.out.println("CheckSum: "+Long.toHexString(value));
}
/**
* int 转byte[]
*
* @param number
* @return
*/
public static byte[] intToByte(int number) {
byte[] b = new byte[4];
for (int i = 3; i >= 0; i--) {
b[i] = (byte) (number % 256);
number >>= 8;
}
return b;
}
/**
* 修改dex头 sha1值
*
* @param dexBytes
* @throws NoSuchAlgorithmException
*/
private static void fixSHA1Header(byte[] dexBytes)
throws NoSuchAlgorithmException {
MessageDigest md = MessageDigest.getInstance("SHA-1");
// 从32为到结束计算sha-1
md.update(dexBytes, 32, dexBytes.length - 32);
byte[] newdt = md.digest();
// 修改sha-1值(12-31)
System.arraycopy(newdt, 0, dexBytes, 12, 20);
//输出sha-1值,可有可无
String hexstr = "";
for (int i = 0; i < newdt.length; i++) {
hexstr += Integer.toString((newdt[i] & 0xff) + 0x100, 16)
.substring(1);
}
System.out.println("sha1: " + hexstr);
}
/**
* 修改dex头 file_size值
* @param dexBytes
*/
private static void fixFileSizeHeader(byte[] dexBytes) {
//新文件长度
byte[] newfs = intToByte(dexBytes.length);
System.out.println("file_size: " + Integer.toHexString(dexBytes.length));
byte[] refs = new byte[4];
// 高位在高地址,低位在低地址
for (int i = 0; i < 4; i++) {
refs[i] = newfs[newfs.length - 1 - i];
}
// 修改(32-35)
System.arraycopy(refs, 0, dexBytes, 32, 4);
}
/**
* 以二进制读出文件内容
*
* @param file
* @return
* @throws IOException
*/
private static byte[] readFileBytes(File file) throws IOException {
byte[] arrayOfByte = new byte[1024];
ByteArrayOutputStream localByteArrayOutputStream = new ByteArrayOutputStream();
FileInputStream fis = new FileInputStream(file);
while (true) {
int i = fis.read(arrayOfByte);
if (i != -1) {
localByteArrayOutputStream.write(arrayOfByte, 0, i);
} else {
return localByteArrayOutputStream.toByteArray();
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment