前言:java
一、不少APK用apktool反編譯後,重打包失敗;shell
二、dex中smali指令硬編碼,安裝失敗;app
解決方法:工具
1、針對第一個問題,就是不反編譯APK,而是直接從APK包從用Zip工具(winzip)將classes.dex提取出來,再使用IDA等反編譯工具找到要修改指令的偏移,最後使用winhex等編輯工具修改指令,而後保存便可;ui
詳細修改指令的方法是將OPCODE直接填充到相應位置便可:編碼
原始JAVA代碼以下:code
public static void b(String arg4, String arg5, int arg6, Throwable arg7) { Log.d(arg4, arg5); return; }
IDA中此代碼的opcode以下:ip
2、針對第二個問題,在classes.dex硬編碼完成後,須要校訂checksum和signture,使用下面的java程序修正classes.dex,get
代碼以下:input
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刪除後,從新簽名,就能夠安裝成功。