前言:
1、很多APK用apktool反编译后,重打包失败;
2、dex中smali指令硬编码,安装失败;
解决方法:
一、针对第一个问题,就是不反编译APK,而是直接从APK包从用Zip工具(winzip)将classes.dex提取出来,再使用IDA等反编译工具找到要修改指令的偏移,最后使用winhex等编辑工具修改指令,然后保存即可;
详细修改指令的方法是将OPCODE直接填充到相应位置即可:
原始JAVA代码如下:
public static void b(String arg4, String arg5, int arg6, Throwable arg7) { Log.d(arg4, arg5); return; }
IDA中此代码的opcode如下:
二、针对第二个问题,在classes.dex硬编码完成后,需要校正checksum和signture,使用下面的java程序修正classes.dex,
代码如下:
package javaproject; import java.security.*; import java.util.zip.Adler32; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.BufferedReader; import java.io.InputStreamReader; import java.io.FileOutputStream; public class ReDEX { public static void main(String[] args) { if (args.length == 1) { try { File file = new File(args[0]); byte[] barr = null; barr = getBytesFromFile(file); System.out.print("Original Checksum: "); for(int i = 8; i<12; i+=4) System.out.printf("0x%02X%02X%02X%02X ", barr[i+3], barr[i+2], barr[i+1], barr[i]); System.out.print("\nOriginal Signature: 0x"); for(int i = 12; i<32; i+=4) System.out.printf("%02X%02X%02X%02X ", barr[i], barr[i+1], barr[i+2], barr[i+3]); calcSignature(barr); calcChecksum(barr); System.out.print("\n\nNew Checksum: "); for(int i = 8; i<12; i+=4) System.out.printf("0x%02X%02X%02X%02X ", barr[i+3], barr[i+2], barr[i+1], barr[i]); System.out.print("\nNew Signature: 0x"); for(int i = 12; i<32; i+=4) System.out.printf("%02X%02X%02X%02X ", barr[i], barr[i+1], barr[i+2], barr[i+3]); try{ String str = readUserInput("\nSave it(Yes or No):"); if (str.equalsIgnoreCase("yes")) { putBytesToFile(barr, args[0]); System.err.println("\nFixed."); System.err.println(args[0]); } else{ System.err.println("\nNothing"); } } catch(IOException except) { except.printStackTrace(); } } catch (Exception e) { System.err.println("File input error"); } } else System.out.println("Invalid parameters"); } private static String readUserInput(String prompt) throws IOException { System.out.print(prompt); InputStreamReader is_reader = new InputStreamReader(System.in); return new BufferedReader(is_reader).readLine(); } public static byte[] getBytesFromFile(File file) throws IOException { InputStream is = new FileInputStream(file); // Get the size of the file long length = file.length(); if (length > Integer.MAX_VALUE) { // File is too large } // Create the byte array to hold the data byte[] bytes = new byte[(int)length]; // Read in the bytes int offset = 0; int numRead = 0; while (offset < bytes.length && (numRead=is.read(bytes, offset, bytes.length-offset)) >= 0) { offset += numRead; } // Ensure all the bytes have been read in if (offset < bytes.length) { throw new IOException("Could not completely read file "+file.getName()); } // Close the input stream and return bytes is.close(); return bytes; } public static void putBytesToFile(byte[] data, String outfile) throws IOException { File destinationFile = new File(outfile); if (destinationFile.exists()) { System.out.println("overwrite"); } FileOutputStream fos = new FileOutputStream(destinationFile); try { fos.write(data, 0, data.length); fos.flush(); fos.close(); } catch (IOException e) { System.out.println(e); } } private static void calcSignature(byte bytes[]) { MessageDigest md; try { md = MessageDigest.getInstance("SHA-1"); } catch(NoSuchAlgorithmException ex) { throw new RuntimeException(ex); } md.update(bytes, 32, bytes.length - 32); try { int amt = md.digest(bytes, 12, 20); if(amt != 20) throw new RuntimeException((new StringBuilder()).append("unexpected digest write:").append(amt).append("bytes").toString()); } catch(DigestException ex) { throw new RuntimeException(ex); } } private static void calcChecksum(byte bytes[]) { Adler32 a32 = new Adler32(); a32.update(bytes, 12, bytes.length - 12); int sum = (int)a32.getValue(); bytes[8] = (byte)sum; bytes[9] = (byte)(sum >> 8); bytes[10] = (byte)(sum >> 16); bytes[11] = (byte)(sum >> 24); } }
将修正好的dex直接替换进原始的APK中,重新签名安装会报INSTALL_PARSE_FAILED_NO_CERTIFICATES错误,此时使用jdk中jarsigner验证APK中签名问题,如下:
$jarsigner.exe -verify mod_sign.apk jarsigner: java.lang.SecurityException: invalid SHA1 signature file digest for classes.dex
提示这种错误是因为原始APK中的签名文件没有删除掉,将META-INF下面的*.RSA、*.SF删除后,重新签名,就可以安装成功。