Created
November 23, 2021 00:19
-
-
Save Forgo7ten/12a12f2edf300f5b9c6e3cb6a7ebe14c to your computer and use it in GitHub Desktop.
修改dex文件并修复 CheckSum、filesize、sha1;将某文件添加到dex文件的末尾
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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