Android ProGuard解析,能夠混淆成中文?

ProGuard是一個壓縮、優化和混淆Java字節碼文件的免費的工具,是Android平臺重要的防禦手段之一。java

ProGuard功能

ProGuard主要功能及執行流程以下圖所示: android

image

  1. 輸入jar或者aar等格式的java字節碼文件集合而且傳入自定義配置
  2. shrink流程刪除無用的類、方法和屬性
  3. optimize流程進一步優化字節碼,主要表現爲優化邏輯
  4. obfuscate流程對優化後的字節碼進行混淆,將類、方法和屬性名稱從新命名爲短的且無心義的名字,縮減包大小而且進行防禦
  5. preverify爲提早校驗的過程,而且將校驗的信息添加到類文件中

重點介紹一下上述流程的工做機制安全

  • Shrink
    Shrink是壓縮字節碼的過程,主要是刪除Java字節碼集合中沒用的類、方法和屬性定義。該過程和Java的GC判斷流程很像,從ROOT搜索,走過的路徑可被稱爲調用鏈,經過調用鏈判斷哪些類、方法和屬性沒有被使用,而後刪除掉。那麼這些ROOT到底是怎麼被定義的? 先看下Android中proguard文件中的配置片斷:
-keepattributes *Annotation*
-keepclasseswithmembernames class * {
    native <methods>;
}
-keepclassmembers public class * extends android.view.View {
   void set*(***);
   *** get*();
}
複製代碼

看到這裏是否是忽然明白,在proguard文件中都是輸入到ProGuard庫中的參數集合,全部添加keep標籤的類、方法以及屬性都是ROOT,被認爲調用入口。bash

  • Optimize
    Optimize進一步優化字節碼,該過程主要優化代碼邏輯,好比if判斷中條件始終爲true,則能夠把false分之的邏輯刪除,好比一個類中的只有一個方法且只被調用一次,這個時候就能夠將方法塊移到調用處而且刪除原來的類和方法。該過程也須要知道調用鏈,確認好調用鏈才能優化代碼邏輯。
  • Obfuscate
    Obfuscate將類、方法和屬性重命名成簡短且無心義的名字,這一過程進一步壓縮字節碼大小,別切混淆邏輯,是經常使用的防禦手段。
  • Preverify
    Preverify爲提早校驗,而且將校驗的類信息添加到類文件中,該過程在Android裏默認是關閉的。

混淆分析

目前在Android中主要使用ProGuard庫中的混淆功能,經過混淆壓縮字節碼大小而且進行防禦,以前分析一個樣本,經過JADX打開後以下: app

image
上圖中成員變量被混淆成中文,而且方法中有中文也有英文,這裏主要分析一下ProGuard混淆邏輯及如何訂製本身的混淆字符庫。

ProGuard混淆邏輯

使用JADX打開ProGuard.jar而且找到入口類: 工具

image
這裏分享一個找入口的技巧:運行jar包且不輸入任何參數,這個時候jar包確定會輸出錯誤信息而且退出,全局搜索錯誤信息就能找到入口類,如上圖中會輸出「Usage: java proguard.ProGuard [options ...]」錯誤。
經過上面的main方法找到以下處理:
image

這裏能夠很清晰看出ProGuard按順序執行shrink,Optimize,Obfuscate,Preverify過程,直接看obfuscate方法:
image
在類Obfuscator中的execute方法找到上圖設置NameFactory過程,先判斷外部是否設置了NameFactory,若是有就使用外部設置,若是沒有則使用SimpleNameFactory做爲庫輸出名子,先看下SimpleNameFactory輸出名字的邏輯,外部調用nextName獲取名稱,重點看下newName方法:

private String newName(int i) {
        int i2 = this.generateMixedCaseNames ? 52 : CHARACTER_COUNT;
        int i3 = i / i2;
        char charAt = charAt(i % i2);
        if (i3 != 0) {
            return new StringBuffer().append(name(i3 - 1)).append(charAt).toString();
        }
        return new String(new char[]{charAt});
    }
複製代碼

其中CHARACTER_COUNT值爲26,這裏的意思爲是否只使用a-z共26字符仍是使用a-z和A-Z共52字符,生成名字的邏輯也很簡單:如如今使用26字符集合且生成的名字爲z,則下一個名字爲aa,依次類推當字符用到最後則增長一位。
上面SimpleNameFactory分析完成,再分析一下另外一個分支DictionaryNameFactory中生成名字的方法:
測試

image
這裏邏輯很簡單,若是當前list中有足夠的字符就使用當前,若是不夠了則使用nameFactory的字符生成方法,這裏有2個事情須要搞清楚:

  1. list字符集合怎麼生成?
  2. nameFactory的字符生成方法?

看下DictionaryNameFactory的構造方法:
優化

image
看到這裏就明白:list字符是從文件中讀取的而且去重,nameFactory是外面傳過來的, 全局搜一下DictionaryNameFactory構造方法被調用處,最後找到3處調用:
image

傳入的NameFactory都是SimpleFactory,文件參數分別是packageNameFactory,classNameFactory和ObfucationDictionary,再跟進去看發如今Configuration中有以下定義:

public static final String OBFUSCATION_DICTIONARY_OPTION = "-obfuscationdictionary";
public static final String CLASS_OBFUSCATION_DICTIONARY_OPTION = "-classobfuscationdictionary";
public static final String PACKAGE_OBFUSCATION_DICTIONARY_OPTION = "-packageobfuscationdictionary";
複製代碼

看到這裏應該明白了,能夠經過設置字符集配置完成包名,類名,方法名以及屬性名配置。
這裏總結一下:ui

  • 若是不設置混淆字典,則默認使用a-z 26位英文字母混淆包名,類名,方法名,屬性名
  • 能夠經過配置分別設置包名,類名,方法名,屬性名混淆字符集,當配置的字符集不夠用時,會使用a-z命名

混淆升級

上面介紹了混淆的機制以及設置自定義混淆字符集的方法,這裏介紹兩種設置字符集的方法而且對比優缺點。this

  • 直接在配置文件中設置字符集

在DEMO工程中的proguard-rules.pro中添加以下信息:

-obfuscationdictionary ./dictionary
-classobfuscationdictionary ./dictionary
-packageobfuscationdictionary ./dictionary
複製代碼

而後再在同級目錄建立dictionary文件,裏面設置測試字符集:

_
__
___
____
_____
______
複製代碼

這裏是下劃線,看下最後的效果:

image
哈哈哈,看看如今這個混淆結果,你得有多大的耐心才能分析這樣的樣本。

  • 修改ProGuard.jar
    直接修改SimpleNameFactory中生成字符的方法生成新的ProGuard.jar

修改ProGuard.jar方案我沒有親自試,修改也比較簡單。
這裏對比一下上述兩種方案:

方案 優勢 缺點
配置中設置字典 方便配置 當字符集使用完會使用默認的a-z
修改ProGuard.jar 可以徹底掌握字符集使用 須要修改庫

總結

本篇主要介紹ProGaurd庫的功能,重點講解了一下混淆相關,以及如何利用混淆功能提升應用安全防禦, 這裏提醒一下:設置字符集的時候也要注意包大小,原生a-z都是佔用1個字節,若是設置中文或者其餘字符就要衡量一下了。

相關文章
相關標籤/搜索