上回說到了安卓平臺上基于Dalvik指令的反編譯技術,以及面對破壞者的反編譯攻擊如何比較有效的防范。這篇文章作為上一講的擴展內容,講講破壞者是如何利用工具進行安卓平臺上Native代碼部分的攻擊篡改。
一、什么是安卓平臺的Native代碼?
安卓平臺的Native代碼說的有些含糊,因為Native代碼不區分平臺,都是代指C/C++語言編寫的代碼。因為是底層語言,和硬件銜接的比較緊密,所以稱為Native。
安卓平臺上面的Native代碼是需要Android NDK來進行編譯,以生成*.so動態庫來供java層調用的,而java層與Native層的數據通信是通過jni技術實現的。這個過程,或者說這項技術不止在Android平臺上,Windows/linux上面也是適用的。
關于如何編寫安卓平臺的Native代碼,以及如何生成*.so文件不在本文介紹范圍,有興趣的可以在論壇搜索學習。
二、什么樣的程序會用到Native代碼呢?
這個問題回答起來比較泛泛,一般來說,需要使用C/C++來提升程序的運行效率時會考慮使用Native代碼。當然,如果用C/C++寫出的庫文件可以方便地進行移植,比如作者的項目里,我寫的圖形控制部分可以輕松的布置到Android和IOS上運行。
除去運行效率不說,由于C語言天生的不可反編回源代碼的特性,Native語言在Android平臺上也經常被用于保護APP中關鍵代碼部分,比如注冊、收費部分。
三、APP的NDK保護及逆向演練
由于對逆向工程比較感興趣,所以對Android平臺的程序逆向比較關心,今年年初的時候在群里有妹子共享了一個apk,號稱是他們公司內部的一個比賽,能破解的人可以得到XXX獎勵。
忍不住內心的好奇,下載下來看了一下,初步斷定限制關口是一個類似收費的sp通道,通過發送短信達到注冊(收費)的目的后,去除程序限制。當然由于是個比賽性質,發送的短信不是收費短信,而是給寫程序的這個人,本帖的最后會附上這個apk,有興趣的可以試試如何去除限制,當然,最好在離線模式下測試,以免發出短信~~~
其實上面的場景短信限制場景非常普遍,早在java功能手機上就有類似的技術,所以這個限制關口的破解理論上也很簡單——在程序監聽短信是否發送成功的代碼處做文章就可以了。于是拿來apk,反編classes,找到關鍵入口處進行修改,之后打包簽名。一切看上去很簡單,但是在程序運行的時候尷尬了,程序根本無法啟動,在用eclipse查看日志輸出的時候還有截圖中的文字。。。。。。瞬時惱火。
仔細分析了一下apk的文件結構,基本判定這個apk是做了NDK保護的,而在assets目錄下的defense.data文件就是存放某些特征值的文本文件。如下圖:
于是,深深的覺得,這個東西需要做Native代碼的逆向破解了。
3.1 Native逆向的工具準備
1)使用arm-linux-androideabi-objdump工具
如果你技術比較牛的話,可以使用Android NDK自帶的arm-linux-androideabi-objdump.exe進行反匯編(Windows環境),該工具位于NDK根目錄的toolchains\arm-linux-androideabi-4.6\prebuilt\windows-x86_64\bin路勁下,這里推薦使用arm-linux-androideabi-4.6版本,因為一般的NDK編譯默認使用這個版本。
使用方法:
Cmd窗口命令cd到該exe所在路徑運行arm-linux-androideabi-objdump -dS libicg.so>dump.txt,當然,你首先需要把要反編譯的so文件放在相應的路徑下,我的是和工具放在了同目錄下。運行完成后,反匯編結果在同級目錄下生成。
看到了反編譯過來的結果是不是很頭疼?先留個懸念,我們下面介紹另一個工具。
2)使用IDA進行So文件的靜態分析
IDA很有名,可以分析很多文件類型,如果你有看過我的第一篇文章的話應該有印象,那里面也有提過,今天我們就要用它來幫助我們進行so文件的靜態分析。
軟件的下載安裝過程我們省去不說了,直接打開ida,把要分析的SO文件拖進IDA里面。我用的版本是6.4。一直點確定,等IDA分析完成后會顯示如圖界面:
主界面顯示的是各個方法間的調用關系。查看最左側的Function Name,我們在里面發現了Verfication函數,這個函數的命名就很直觀嘛,應該就是它了,如果你在實際的操作過程中沒有發現一些具有明顯特征的函數名,那就要一點一點分析了,比如我們上一篇里講到的特征字符串啊,動態調試之類的,這些東西需要一定的經驗,說起來不是很清楚,有興趣的可以找個實際工程體會一下。
好,我們點擊那個方法名,主界面會跳到該方法下,顯示的仍然是調用關系。
我們鼠標點擊verification,也就是圖中綠色部分,然后按空格,主界面會進入該方法,顯示的仍然是調用關系,只不過會更加詳細。如下圖:
如果我們想回到剛才的那個大界面的話,使用ctrl+1,點第二項:Proximity browser可以回到上一界面。
來到verification這個方法后,我們發現這里的東西好像和我們用arm-linux-androideabi-objdump反匯編出來的東西類似呢?沒錯,其實它們都是Arm的指令集。只不過在IDA里面,每段指令間的調用關系都用箭頭標出了,在視覺上更加清楚、明了。
在IDA里面先不忙著動手,我們從頭到尾觀察一下這個方法。
在方法的接近尾部我們發現了圖中的指令段:
IDA非常人性化地把調用文字以注釋的方式顯示了出來(在用arm-linux-androideabi-objdump反匯編的文件里沒有顯示注釋,這也是為什么IDA強大的原因)。ICG-FUCk。。。。。這個不就是前面我們修改過classes之后運行APP打印出來的東西么?
統觀這個方法,一共有兩處調用了這個字符串資源,一處是上圖所示,一處是在方法的最后。那倒是哪個才是判斷Classes被修改之后的輸出呢?我們比對一下兩處指令:
第一份截圖不知大家能不能看清,在比較指令(CMP)的上方是調用了(BL)zip_fopen,我們這里推測,zip_fopen是一個方法,它應該會返回zip文件是不是被成功打開了,結合cmp指令,這里的BEQ應該判斷的是zip文件是不是成功打開了,如果沒有則跳轉到LOC_33d4,也就是輸出icg-fuck。。。。所以說,這處應該不是判斷classes文件是否被修改的地方,那么關鍵代碼部分應該是第二份截圖的代碼段了,這段指令接近方法最后,按理說,是關鍵指令沒錯。在觀察cmp指令的上一指令,bl了一個decoding的方法,按照這個方法名,應該是把某字符串進行了編碼操作,回想起在assets目錄下的defense.data文件,這個地方應該就是那段莫名其妙的字符串生成的地方了。到此,關鍵指令定位成功。
3.2 開始修改so文件
找到了關鍵代碼,那么就很簡單了,只需要把BEQ這個跳轉指令修改為B(無條件跳轉)即可,我們單擊BEQ后按空格,界面跳轉到16進制顯示。
在16進制顯示中的幾個重要參數我在圖片中已經明確表明了,大家注意看,尤其是左下角的偏移量。
找到了關鍵指令位置,我們用16進制編輯器打開SO文件,我用的是HEX Workshop,打開SO文件后按Ctrl+g進行偏移定位,在偏移量中填寫剛才在IDA里看到的32ec,選擇16進制并選擇從文件開頭處開始:
轉到位置后我們看機器碼3800000A,和我們在IDA中看到的一樣,說明我們定位準確:
下一步,我們只需要把BEQ對應的機器碼0A改成B(無條件跳轉)對應的EA即可,改完后記得保存。
3.3 文件打包
打包很簡單,把修改過的SO文件放回原位(winrar就可以)并進行簽名就可以運行測試了。
至此,安卓平臺的Native逆向技術就介紹完了,想想,其實SO文件的逆向也不是很難。
四、總結及加固建議
本文通過向大家展示一個完整的SO文件逆向工程,來讓大家了解“破壞者”的攻擊手段,以提醒開發者在實際開發過程中注意自身的代碼安全。
宏觀來開,不論是java文件的逆向,還是Native的逆向都是不難的,要想通過代碼手段來阻止“破壞者”的攻擊基本是不可能的,但是我們可以把關鍵代碼部分寫的復雜些,邏輯判斷更復雜些以擾亂“破壞者”的思路,達到讓他放棄攻擊的目的。
看到這里有人可能會問,對于Native本身的保護怎么辦呢?答案是可以給SO文件加殼,而這個內容已然超出本文討論范圍,這里不再贅述。
clxy 2014-07-25 19:33:22