Android程序的反編譯對抗研究


轉自: http://www.freebuf.com/tools/76884.html

 

一、前言

對抗反編譯是指讓apk文件或者dex文件無法正常通過反編譯工具,而且有可能導致工具異常或者崩潰,如apktool、baksmali、dex2jar、JEB等等工具,如下圖dex2jar無法正常工作。

二、Dex文件格式解析

目前大多數android軟件的反編譯工具都是開源的,比如apktool、Dex2jar、baksamli,大家可以非常方便的從github下載並源閱讀代碼,然后找到可以利用的點,再在自己的軟件中加入干擾代碼,讓反編譯工具出現異常或者無法正常閱讀代碼。

接下來讓我們先來熟悉一下dex文件格式 ,一個dex文件由以下幾個部份組成:

1.     Dex Header:    Dex結構頭它指定了dex文件的一些基本屬性,並記錄了部份數據表在dex文件中的物理偏移。
2.     String Table:  字符串表,存儲字符串的索引和個數
3.     Type Table:   類型表,存儲類型的索引和個數
4.     Proto Table:  函數元型表,存儲函數元型索引和個數
5.     Field Table:  字段表,存儲字段索引和個數
6.     Method Table:  方法表,存儲方法索引和個數
7.     Class def Table:類定義表,存儲類定義索引和個數
8.     Data Section:  存儲數據,由以上類型的索引查找

有興趣的可以直接翻看android的源碼或者參考以下鏈接:

http://www.netmite.com/android/mydroid/dalvik/docs/dex-format.html

既然要在代碼中添加干擾指令,接下的DexClassDef結構,肯定是要了解的非常清楚。

結構中包含了類的類型偏移、訪問標志、父類類型索引、接口偏移、注釋、靜態類型的偏移信息,整體結構圖定義如下:

struct DexClassDef {      u4 classIdx        u4 accessFlags    u4 superclassIdx     u4 interfacesOff      u4 sourcefileIdx     u4 annotationsOff      u4 classDataOff        u4 staticValuesOff }

DexClassDef結構字段詳細說明:

classIdx    字段是一個索引值,類的類型,做為下標索引在DexTypeID結構列表中查找
accessFlags   字段是類的訪問標志,以ACC_開頭的枚舉值
superclassIdx  字段是父類的類型,做為下標索引在DexTypeID結構列表中查找
interfacesOff  字段是接口類型,做為下標索引在DexTypeList結構列表中查找
sourcefileIdx  字段是源文件名,做為下標索引在DexTypeList結構列表中查找
annotationsOff 字段是注釋信息的偏移,指向DexAnnotationsDirectoryItem結構
classdataOff  字段是指向了DexClassData結構體的偏移
staticValuesOff 字段是指向DexEncodeArray結構體的偏移,記錄靜態數據的信息

DexClassData結構說明:

struct DexClassData {    DexClassDataHeader header;    DexField*  staticFields     //靜態字段,DexField結構    DexField*  instanceFields   //實例字段,DexField結構    DexMethod* directMethods    //直接方法,DexMethod結構    DexMethod* virtualMethods   //虛方法,  DexMethod結構 }

DexClassData結構中的DexMethod類型描述了:方法的原型、名稱、訪問標志以及代碼數據塊,codeOff字段指向了一個DexCode結構,它描述了方法更詳細的信息以及方法中指令的內容。

DexMethod結構聲明如下

struct DexMethod {   u4 methodIdx  //指向DexMethodId的索引    u4 accessFlags//訪問標志 u4 codeOff    //指向dexCode的結構偏移 } struct DexCode {   ushort  registerSsize//使用的寄存器的數目   ushort  insSize      //傳入參數的數目   unshort outsSize     //調用其他方法時使用的寄存器個數   unshort triesSize    //try/catch異常塊個數   uint    debugInfoOff //調試信息的偏移   uint    insnsSize    //指令集個數   ushort  insns[1];     //指令集數組,變長數組 }

DexClassData樹型結構圖:

三、調試dex2jar工程

1. 將dex2jar源碼導入IntelliJ IDEA,導入后IntelliJ IDEA會自動查找對應 Grable並下載,需要比較長的時間等待

源碼地址: https://github.com/pxb1988/dex2jar

2.  選中Grable中的dex2jar/dex2jar/Tasks/other/antlr2java進行編譯 

3. 點擊工具欄的 Project Structure, 然后選擇Modules -> d2j-smali -> build,然后點擊Excluded

4. 選擇 build/generated-sources/antlr, 然后點擊 Sources

5. 最后打開Excluded Gradle Task彈出對話框,運行clean distZip 命令

執行完Gradl clean distZip命令后會在\dex2jar-2.x\dex-tools\build\distributions目錄下生成 dex-tools-2.1-SNAPSHOT.zip,壓縮包內是編譯完后生成的jar文件和一些配置信息文件。大家請參考dex2jar.sh文件,它向我們說明需要使用lib目錄下的所有jar文件和入口函數com.googlecode.dex2jar.tools.Dex2jarCmd 才能將dex文件轉換成jar文件

6.將dex文件轉換成jar文件需要執行轉換命令

格式如下:

java -Xms512m -Xmx1024m -classpath  .\lib\*.jar com.googlecode.dex2jar.tools.Dex2jarCmd classdex.dex

根據以上的命令,來配置調試參數,設置如下:

7.設置完成后,就可以開始調試

四、dex2jar反編譯失敗原因分析

1.首先我們從解包失敗的錯誤異常入手,定位崩潰處的代碼。

通過錯誤提示可以定位到dex2jar崩潰處的代碼,源碼位置如下:

dex-ir\src\main\java\com\googlecode\dex2jar\ir\TypeClass.java

2. 在崩潰的函數處下斷點,開始調試。

a)通過拋出的異常的說明“cant not merge I and Z”,以及整個調用堆棧。

我們可以看出造成這個異常的原因是函數調用時,實參的類型和形參類型不匹配引起的。因為在Java語法中,將實參是布爾類型傳遞給形參是int類型。這樣是不合法的,所以導致dex2jar在檢查的參數類型的時候失敗。

b)知道了崩潰的原因,那我們就需要確定它具體是使用怎樣的方法做到的,通過dex2jar生成的error異常信息詳細說明文件得知該dex文件中的每一個函數頭部都加了一句這樣的代碼Exit.b(Exit.a())請看Ida,現在大致能猜到混淆者所做的工作:

1.首先解析dex文件格式,定位到DexCode結構中的insns成員

2.向代碼中添加一個類成員對象名字叫Exit,然后添加代碼Exit.b(Exit.a())

3.明白了怎么添加干擾代碼,接下來分析一下dex2jar的工作流程,dex2jar轉換成jar文件這個過程中會驗證,函數調用時的形參和實參的合法性,請看下圖,解析到INVOKE_開頭的指令時,會開始解析返回值,供給參數,和實參等信息,具體邏輯和代碼大家有興趣可以詳細地研究一下dex2jar源碼。

4.merge負責的工作是參數類型的驗證,如果兩個類型相同,返回形參的類型,形參為UNKONW返回實參,實參為UNKONW返回形參,兩個類型都不相同,則匹配異常

5.最后在dex2jar里添加代碼,使dex文件能正確的被反編譯成功。這里給出一段可以成功讓dex2jar反編譯的出jar文件的代碼(其實方法有很多)

下圖是成功反編譯的jar文件


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM