0x8.so逆向深化及IDA靜態(tài)分析-3

so逆向深化及IDA靜態(tài)分析-3 : IDA靜態(tài)分析之so逆向進(jìn)階實(shí)戰(zhàn)


本文介紹一個CackMe的分析過程,不再是單純的分析邏輯,還包括還原算法。


本文樣本鏈接:https://pan.baidu.com/s/1lKNATw_PLhYQyUT-BBbUrw  提取碼:xmu1 
<該樣本為個人編寫,如果引用請?zhí)崆案嬷?,謝謝>

0x1.java層分析
我們首先打開樣本,了解一下情況,方便確認(rèn)突破口。
     

左側(cè)圖為打開后的界面,右側(cè)為輸入任意密碼并提交后的界面,此時我們可以定位首個關(guān)鍵字 “密碼錯誤”。
接下來我們將樣本拖拽到AndroidKiller之中逆向,然后文本轉(zhuǎn)Unicode,搜索該關(guān)鍵字: 


搜索到關(guān)鍵字后,我們可以借助其java源碼協(xié)助分析,也可以直接分析smali。下面以java源碼為例:
在Android Killer中點(diǎn)擊java源碼對應(yīng)的圖標(biāo),打開jd-GUI查看該樣本的java源碼。


根據(jù)上圖步驟一步步定位到了關(guān)鍵函數(shù)setCode,我們進(jìn)一步追蹤。


最終定位到native函數(shù)setCode,并確定其所在的so文件為“l(fā)ibJniSoDemo.so”。

0x2.so層分析
定位到so文件的native函數(shù)后,我們開始分析so文件(以此路徑為例>SoDemo_killer>Project>lib>armeabi-v7a),
將其拖入IDA后,在Exports一欄找到setCode函數(shù)


雙擊查看函數(shù)中的ARM指令如下:


接下來我們看下這段ARM指令(具體指令可查詢之前共享的指令集或者百度):
.text:00000EA4                 EXPORT Java_com_kanxue_sodemo_jnisodemo_setCode
.text:00000EA4 Java_com_kanxue_sodemo_jnisodemo_setCode
.text:00000EA4                                         ; DATA XREF: LOAD:000001BC↑o
.text:00000EA4 ; __unwind {
.text:00000EA4                 MOVS            R0, #0                                         // R0=0
.text:00000EA6                 CMP             R3, #3                                         // 比較R3與3
.text:00000EA8                 BNE             locret_EEA                                         // 如果R3≠3,跳轉(zhuǎn)到locret_EEA
.text:00000EAA                 SUB.W           R1, R2, #0x1F4                                         // R1=R2-500
.text:00000EAE                 CMP             R1, #0x63 ; 'c'                                         // 比較R1和99
.text:00000EB0                 BHI             locret_EEA                                         // 如果R1大于99,跳轉(zhuǎn)到locret_EEA
.text:00000EB2                 MOV             R0, #0x66666667                                         // R0=0x66666667
.text:00000EBA                 SMMUL.W         R0, R1, R0                                         // R0=R1*R0
.text:00000EBE                 MOV             R1, #0x51EB851F                                         // R1=0x51EB851F
.text:00000EC6                 SMMUL.W         R1, R2, R1                                         // R1=R2*R1
.text:00000ECA                 ASRS            R3, R0, #2                                         // R3=(R0>>2)
.text:00000ECC                 ADD.W           R12, R3, R0,LSR#31                                         // R12=R3+(R0>>31)
.text:00000ED0                 ASRS            R0, R1, #5                                         // R0=(R1>>5)
.text:00000ED2                 ADD.W           R1, R0, R1,LSR#31                                         // R1=R0+(R1>>31)
.text:00000ED6                 SUBS            R3, R1, #3                                         // R3=R1-3
.text:00000ED8                 MOVS            R0, #0                                         // R0=0
.text:00000EDA                 CMP             R12, R3                                         // 比較R12和R3
.text:00000EDC                 IT NE                                         // IT(If-Then) NE(Not-Equal) 如果不相等則執(zhí)行下一句
.text:00000EDE                 BXNE            LR                                         // 承接上一句的條件,函數(shù)返回
.text:00000EE0                 SUBW            R2, R2, #0x203                                         // R2=R2-515
.text:00000EE4                 CMP             R2, R1                                         // 比較R2和R1
.text:00000EE6                 IT EQ                                         // 如果相等則執(zhí)行下一句
.text:00000EE8                 MOVEQ           R0, #1                                         // 承接上一句的條件,R0=1
.text:00000EEA
.text:00000EEA locret_EEA                              ; CODE XREF: Java_com_kanxue_sodemo_jnisodemo_setCode+4↑j
.text:00000EEA                                         ; Java_com_kanxue_sodemo_jnisodemo_setCode+C↑j
.text:00000EEA                 BX              LR                                         // 函數(shù)返回
.text:00000EEA ; End of function Java_com_kanxue_sodemo_jnisodemo_setCode
可參考偽代碼插件,按下F5,看到C代碼如下:


在函數(shù)中,我們只看到了a3和a4,顯然a3和a4是我們傳入給setCode的兩個參數(shù)。
參考jd-GUI中的java源碼,我們可以得知兩個參數(shù)是什么。


在setCode中,首先判斷了位數(shù)是否為3,即 a4 == 3
然后判斷了第一位是否為5,即 (a3-500)≤ 99
不同時滿足以上兩個,則返回0,即 密碼有三位,且第一位是5。
后面 if ( (a3 - 500) / 10 == a3 / 100 - 3 && a3 - 515 == a3 / 100 )
則是判斷第二位是2,第三位是0,得出密碼為520。

以上是算法分析,如果是單純邏輯分析的話,可以修改邏輯一直返回1,或者修改判斷條件,本文重點(diǎn)是算法分析,此處不再贅述。

0x3.算法還原
在算出520的時候,我們已經(jīng)對算法進(jìn)行了還原。主要是幾個固定條件:
① 密碼長度 a4 = 3 ;
② (a3 - 500) ≤ 99 ;
③ (a3 - 500) / 10 = a3 / 100 - 3 ;
④  a3 - 515 = a3 / 100 。

以上算法比較簡單就不需要單獨(dú)寫程序來算出密碼了,對于比較復(fù)雜的運(yùn)算我們需要編寫程序算出密碼,也就是所謂的注冊機(jī)。

0x4.總結(jié)
在靜態(tài)分析中,我們通常從java層入手,順著邏輯追蹤到so層,再對so層進(jìn)行分析,結(jié)合java層的函數(shù)找出我們需要的算法,
必要的時候根據(jù)密碼驗(yàn)證算法進(jìn)行逆運(yùn)算,導(dǎo)出密碼。

?