so逆向深化及IDA靜態(tài)分析-3 :
IDA靜態(tài)分析之so逆向進階實戰(zhàn)
本文介紹一個CackMe的分析過程,不再是單純的分析邏輯,還包括還原算法。
<該樣本為個人編寫,如果引用請?zhí)崆案嬷?,謝謝>
0x1.java層分析
我們首先打開樣本,了解一下情況,方便確認突破口。
左側(cè)圖為打開后的界面,右側(cè)為輸入任意密碼并提交后的界面,此時我們可以定位首個關(guān)鍵字 “密碼錯誤”。
接下來我們將樣本拖拽到AndroidKiller之中逆向,然后文本轉(zhuǎn)Unicode,搜索該關(guān)鍵字:
搜索到關(guān)鍵字后,我們可以借助其java源碼協(xié)助分析,也可以直接分析smali。下面以java源碼為例:
在Android Killer中點擊java源碼對應(yīng)的圖標,打開jd-GUI查看該樣本的java源碼。
根據(jù)上圖步驟一步步定位到了關(guān)鍵函數(shù)setCode,我們進一步追蹤。
最終定位到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,或者修改判斷條件,本文重點是算法分析,此處不再贅述。
0x3.算法還原
在算出520的時候,我們已經(jīng)對算法進行了還原。主要是幾個固定條件:
① 密碼長度 a4 = 3 ;
② (a3 - 500) ≤ 99 ;
③
(a3 - 500) / 10 = a3 / 100 - 3 ;
④
a3 - 515 = a3 / 100 。
以上算法比較簡單就不需要單獨寫程序來算出密碼了,對于比較復(fù)雜的運算我們需要編寫程序算出密碼,也就是所謂的注冊機。
0x4.總結(jié)
在靜態(tài)分析中,我們通常從java層入手,順著邏輯追蹤到so層,再對so層進行分析,結(jié)合java層的函數(shù)找出我們需要的算法,
必要的時候根據(jù)密碼驗證算法進行逆運算,導(dǎo)出密碼。