android 解碼混淆過的堆疊資訊

maweiliang發表於2019-03-01

  通常我們的程式碼都是通過ProGuard程式混淆的,混淆後每次修改編譯後在proguard資料夾下會生成下列檔案:

android 解碼混淆過的堆疊資訊

dump.txt:
描述.apk檔案中所有類檔案的內部結構
mapping.txt:
列出原始類的方法、欄位與混淆後的程式碼間的對映,這個檔案比較重要,如果你的程式碼混淆後會產生bug的話,log提示中是混淆後的程式碼,希望定位到原始碼的話就可以根據mapping.txt反推。
sends.txt:
列出了未被混淆的類和成員
usage.txt
列出了在apk中刪除的程式碼
  ReTrace是ProGuard的“去混淆”堆疊跟蹤的配套工具,ReTrace可以讀取一個混淆的堆疊資訊,並將其恢復到沒有混淆的情況。恢復基於ProGuard在混淆過程中可以寫出的對映檔案mapping.txt。對映檔案將原始類名和類成員名稱連結到其混淆名稱,它被放在/tools/proguard/lib/目錄下,大致工作流程如下圖:

android 解碼混淆過的堆疊資訊

執行的語法為:

java -jar retrace.jar [options...] mapping_file [stacktrace_file]複製程式碼

mapping_file
混淆時生成的對映檔案的名稱,
stacktrace_file
指定包含堆疊跟蹤的檔案的名稱

options:支援以下選項:
-verbose
指定列印更多資訊豐富的堆疊跟蹤,不僅包括方法名稱,還包括方法返回型別和引數,以及方法的行號等資訊,這個對於快速定位問題幫很有幫助,當然它得有個前期就是你在配置混淆的時候,保留行號資訊 -keepattributesSourceFile,LineNumberTable。
-regex regular_expression
指定用於解析堆疊跟蹤中的行的正規表示式。指定一個不同的正規表示式允許去除模糊更多的一般型別的輸入,而不僅僅是堆疊跟蹤。預設值適用於大多數JVM產生的堆疊跟蹤:

現在假設處理後的應用程式丟擲異常:

java.io.IOException: Can't read [dummy.jar] (No such file or directory)
    at proguard.y.a(MyApplication:188)
    at proguard.y.a(MyApplication:158)
    at proguard.y.a(MyApplication:136)
    at proguard.y.a(MyApplication:66)
    at proguard.ProGuard.c(MyApplication:218)
    at proguard.ProGuard.a(MyApplication:82)
    at proguard.ProGuard.main(MyApplication:538)
Caused by: java.io.IOException: No such file or directory
    at proguard.d.q.a(MyApplication:50)
    at proguard.y.a(MyApplication:184)
    ... 6 more複製程式碼

如果我們將堆疊跟蹤儲存在檔案中stacktrace.txt,我們可以使用以下命令恢復堆疊跟蹤:
java -jar retrace.jar mapping.txt stacktrace.txt
輸出將對應於原始堆疊跟蹤:

java.io.IOException: Can't read [dummy.jar] (No such file or directory)
    at proguard.InputReader.readInput(InputReader.java:188)
    at proguard.InputReader.readInput(InputReader.java:158)
    at proguard.InputReader.readInput(InputReader.java:136)
    at proguard.InputReader.execute(InputReader.java:66)
    at proguard.ProGuard.readInput(ProGuard.java:218)
    at proguard.ProGuard.execute(ProGuard.java:82)
    at proguard.ProGuard.main(ProGuard.java:538)
Caused by: java.io.IOException: No such file or directory
    at proguard.io.DirectoryPump.pumpDataEntries(DirectoryPump.java:50)
    at proguard.InputReader.readInput(InputReader.java:184)
    ... 6 more複製程式碼

使用行號恢復堆疊跟蹤(詳細)

在前面的例子中,我們也可以使用verbose標誌:

java -jar retrace.jar -verbose mapping.txt stacktrace.txt
輸出結果將如下所示:

java.io.IOException: Can't read [dummy.jar] (No such file or directory)
    at proguard.InputReader.void readInput(java.lang.String,proguard.ClassPathEntry,proguard.io.DataEntryReader)(InputReader.java:188)
    at proguard.InputReader.void readInput(java.lang.String,proguard.ClassPath,int,int,proguard.io.DataEntryReader)(InputReader.java:158)
    at proguard.InputReader.void readInput(java.lang.String,proguard.ClassPath,proguard.io.DataEntryReader)(InputReader.java:136)
    at proguard.InputReader.void execute(proguard.classfile.ClassPool,proguard.classfile.ClassPool)(InputReader.java:66)
    at proguard.ProGuard.void readInput()(ProGuard.java:218)
    at proguard.ProGuard.void execute()(ProGuard.java:82)
    at proguard.ProGuard.void main(java.lang.String[])(ProGuard.java:538)
Caused by: java.io.IOException: No such file or directory
    at proguard.io.DirectoryPump.void pumpDataEntries(proguard.io.DataEntryReader)(DirectoryPump.java:50)
    at proguard.InputReader.void readInput(java.lang.String,proguard.ClassPathEntry,proguard.io.DataEntryReader)(InputReader.java:184)
    ... 6 more複製程式碼

我們還可以在直接在程式中使用程式碼呼叫,我們只要將retrace.jar引入我們的工程,就可以愉快的使用了,直接來看程式碼:

public static void ReTrace(String mapFile,String crashFile,String outFile) {  
        try {  
            File file = new File(outFile);  
            FileOutputStream fis = new FileOutputStream(file, false);  
            PrintStream out = new PrintStream(fis);  
            //這個重定向我們的輸出到指定的位置
            System.setOut(out);  
            proguard.retrace.ReTrace localReTrace = new proguard.retrace.ReTrace(proguard.retrace.ReTrace.STACK_TRACE_EXPRESSION,  
                    true, new File(mapFile), new File(  
                            crashFile));  
            localReTrace.execute();  
            out.close();  
            fis.close();  
        } catch (IOException e) {  
            System.out.println("轉碼失敗");  
            e.printStackTrace();  
        }  
    }複製程式碼

通過呼叫它的ReTrace(String mapFile,String crashFile,String outFile)方法,
第一個引數為mapping檔案路徑地址
第二個引數為我們的堆疊資訊檔案地址
第三個檔案是我們要輸出解混淆後的檔案地址
參考資訊www.guardsquare.com/en/proguard…

相關文章