1. 程式人生 > >Android安全/應用逆向--33--使用IDA Pro進行脫殼

Android安全/應用逆向--33--使用IDA Pro進行脫殼

7-10、使用IDA Pro進行脫殼

注:本文之針對加密殼(教學級),高階商業殼的複雜度遠遠超出想象,目前難以搞定

加殼是為了讓自身的classes.dex得到保護,防止APK的原始碼被偷窺。

脫殼總目標:到達dvmDexFileOpenPartial 函式處,dump出記憶體中的dex檔案。這也是脫殼的核心思想

Apk脫殼方法有兩種:

(1)使用脫殼神器ZjDroid進行脫殼(現在此方法不是很好使,因為很多應用都同步更新自己的防禦機制,個人覺得熟練脫殼還是得使用 IDA 進行操練)。
(2)使用 IDA Pro 在 dvmDexFileOpenPartial 這個函式下斷點進行脫殼。(大殺技)

雖然加殼能防止原始碼被偷窺,但是這隻能防止靜態分析,無法防止動態除錯。不管怎麼加殼保護,原始的classes.dex在App執行時都要載入到記憶體中。所以如果在App載入classes.dex處下個斷點,然後再把classes.dex對應記憶體中的內容摳出來還原成原始的classes.dex檔案,就能達到脫殼的目的了。

獲取libdbm.so檔案

adb pull system/lib/libdvm.so E:/sensor               
//注意:直接在命令列下執行,不需要先執行adb shell。同時主機路徑不能是磁碟的根目錄,必須要先建資料夾

批註:
adb pull 安卓裝置路徑 主機路徑 		//從安卓裝置中讀出檔案
adb push 主機路徑 安卓裝置路徑 		//向安卓裝置中寫入檔案
脫殼步驟:
一、架設除錯橋
1、上傳IDA除錯伺服器地址:G:\daimashenji\IDAPro70\dbgsrv\android_server
2、cmd進入到該目錄下: G:\daimashenji\IDAPro70\dbgsrv
3、匯入IDA除錯伺服器:adb push android_server /data/local/tmp
4、adb shell 
5、cd到/data/local/tmp下:chmod 777 android_server
6、./android_server(如果失敗重啟手機)
二、部署安卓
1、埠轉發:adb forward tcp:23946 tcp:23946
2、adb shell下執行:am start -D -n com.e.te/com.e.te.MainActivity(包名/啟動頁面)啟動頁面不一定是這樣
3、會彈出框
三、部署IDA(此時開啟IDA就行,不要新增任何東西)
1、IDA-debugger-Attach-remote ARMlinux/Android debugger
2、填入IP(localhost/手機IP地址)、密碼沒有不用填,儲存預設網路設定
3、高階設定:左邊345,右邊:235,下面:3。儲存設定
4、點選要除錯的包名選入
5、此時相關的應用程式將顯示紅色蜘蛛,如果遇到彈窗,一律點選取消Cancel,以及Apply

注意:此時可以再開一個IDA32位,用於靜態分析libdvm.so
四、開始下斷

1、此時已經進入動態除錯頁面

2、IDA--debugger--debugger windows--module list,查詢libdvm.so並雙擊進入
注:在Dalvik虛擬機器中是libdvm.so在ART虛擬機器中是libart.so,Android4.4開始加入ART執行時(虛擬機器),Android5.0開始ART虛擬機器已經完全替代Dalvik虛擬機器。

3、alt+T,搜尋dvmDexFileOpenPartial函式,並進入該函式

4、在該函式處第一個可下斷點之處下斷點。靜態分析得到該函式的相對地址,在動態除錯的IDA中使用ctrl+S找到libdvm.so直接檢視基地址,兩地址相加得到絕對地址,使用G鍵跳轉,然後下斷點

大多教材是將第五步的命令執行和第四步顛倒,實際上可能沒有順序

五、除錯拷貝

1、執行IDA,讓IDA跑起來,如果彈出視窗,一律點選取消Cancel,以及Apply

2、開啟命令視窗,執行:

jdb -connect com.sun.jdi.SocketAttach:port=8700,hostname=localhost

3、此時IDA將停止。R0暫存器出現debug字樣(或者是其他字樣),則可以開始正常進行脫殼

4、執行程式。包括F7、F8、F9等快捷鍵。重點關注所下的斷點。主要是分析其中的執行判斷邏輯,同時執行成功後才能將常規程式碼載入記憶體,以便dump記憶體資料。注意:可能會遇到反除錯檢測,遇到則按照之前的方法進行繞過

5、IDA --file --script command --編寫指令碼 --run

6、指令碼如下:

auto fp, dex_addr, end_addr;
    fp = fopen("f:\\dump.dex", "wb");
    end_addr = r0 +r1;
    for (dex_addr = r0; dex_addr< end_addr; dex_addr ++)
       		fputc(Byte(dex_addr), fp);

7、編寫完指令碼之後,使用shift+F2調出IDA指令碼,執行指令碼

8、找到dump.dex,並對其進行smali分析

六、應用還原

1、修改反編譯之後的AndroidManifest.xml內容

android:name=”com.shell.superApplication”       //刪除該段,大多是後面也是用這個名字

如果有自己的Application,就改成自己的Application即可

2、刪除多餘的APK變種檔案。即之前所說的存放在assets、libs等資料夾下的獨立多餘的檔案。

3、使用apktool進行回編譯,保留未簽名檔案

4、將dump.dex該命為classes.dex檔案,並使用壓縮軟體開啟未簽名檔案,替換掉未簽名APK下的dex檔案

5、簽名APK,至此完成還原,脫殼結束。

七、後續步驟

1、分析dump.dex,如果不能使用dex2jar等工具分析Java程式碼,則分析Smali程式碼。分析時注意log資訊等

2、在手機文字中輸入多內容時,可以藉助命令:adb shell input text “要輸入的內容”
注意:必須要有雙引號,必須是英文,測試不識別中文

逆向加固應用的知識總結

APK加固的兩種方式:一種是對源APK整體做一個加固,放到指定位置,執行的時候再解密動態載入;還有一種是對so進行加固,在so載入記憶體的時候進行解密釋放。

一個APK加固,外面肯定得套一個殼,這個殼必須是自定義的Application類,它需要做一些初始化操作,一般加固的APK殼的Application類都喜歡叫StubApplication。

步驟如下:

1、檢視是否加固

首先解壓出classes.dex檔案,使用dex2jar工具檢視Java程式碼,發現只有一個Application類,所以猜測APK被加殼了
然後用APKtool來反編譯APK,得到它的資原始檔和AndroidManifest.xml內容,包括包名和入口的Activity類,記住這些內容

2、尋找加固之後的源APK程式

加固APK一般存放在3個地方:

1、應用的asset目錄中。這個目錄是不參與APK的資源編譯過程的,所以很多加固的應用會把加密之後的源APK放到這裡,存放形式可能是jar檔案也可能是其他非常規資原始檔
2、應用的libs中的so檔案中。把源APK進行拆分,存到so檔案中,加大分析難度,存放形式是不被應用載入的so檔案
3、把源APK加密放到殼的dex檔案尾部。這種方式會導致用dex2jar工具解析dex失敗
直接開啟看即可。有難度時這一步是不會有任何收穫的

3、獲取到記憶體中的dex檔案(解密後的dex檔案)

使用動態除錯,給libdvm.so中的函式dvmDexFileOpenPartial下斷點,得到dex檔案在記憶體中的起始地址和大小。因為記憶體中的資料肯定是沒有加密的(這似乎也說明了即時加密技術基本上是不存在的),而這個函式是最終分析dex檔案,載入到記憶體中的函式:

int dvmDexFileOpenPartial(const void* addr,int len,DvmDex** ppDvmDex);

第一個引數是dex記憶體的起始地址,第二個引數是dex大小。程式碼執行到該函式處會解密dex檔案到記憶體,而之後會繼續向後執行,記憶體資料將被覆蓋或回收等導致變化,因此在此處下斷點會暫停在解密的dex檔案的那一刻,使得dex檔案在記憶體中不會變化,所以在該函式處下斷點可以dump出記憶體中的dex檔案

知識點:本地盤中的資料是加密的,載入到記憶體的時候要進行解密,如此機器才能識別資料