so靜態分析進階練習——一個CreakeMe的分析思路


i春秋作家:HAI_

原文來自:https://bbs.ichunqiu.com/thread-41371-1-1.html

說明

拿到一個CreakeMe,寫一個分析思路。CreakMe主要是對.so文件內容進行分析,當然很多學習Android逆向的在分析到smali代碼的時候就已經停止腳步了。在接觸到.so文件的時候才是開始進一步的逆向學習,當然這里就要學習ARM匯編了。關於ARM匯編在網上有很多的資料,這里就不再贅述。

導航

請使用:HAI手冊

0×01 分析邏輯

1.初始界面

image.png

2.輸入數字

image.png

3.輸入字符

 

4.總結

嘗試使用App得出這些結論。
1.我們需要一個key。
2.這個key是數字。

0×02 java層邏輯分析

逆向拿到smali代碼。
工具:Android Killer。

 

1.邏輯分析

找到入口MainActivity。

我們看到這里有一段代碼:

image.png這段代碼的作用就是調用so文件庫。我們猜測這個App很有可能把關鍵key寫在了so文件里。

我們從onClick方法定位到關鍵點。

image.png這里是判斷正誤的地方,這里看到如果v0和v2的值不相等的話就跳轉。並且這里v2的值是1。

我們向上看。

image.png這里有一個調用方法。

在這里我們看到這個是Native層的方法。並且這個方法會返回一個int數據,這里猜測可能會是0或者1。在這里還有一個就是傳入的是一個int型數據,根據我們之前的測試,知道這里就是我們從輸入框輸入的內容。

image.png

2.邏輯圖猜測

監聽事件——輸入key——key方法判斷——返回0或1

1為正確,0為錯誤。

但是我們依然沒有找到Key的是指內容。

0×02 Native層分析

so逆向
使用工具:ida

 

1. key方法分析

找到關鍵的Key函數。

image.png

這里可以看到ARM匯編比smali難的可不是一個度兩個度。

為了提升能力,我們還是一句一句的分析。如果是學習的話,請不要依賴F5。

PUSH            {R7,LR}

把R7寄存器和LR入棧。

R7的含義就是指向前一個保存的棧幀和鏈接寄存器在棧上的地址。

這里可能會對LR的作用不知道,簡單的說一下,LR的作用一個是保存子程序的返回地址。還有一個是當異常發生時,LR中保存的值等於異常發生時PC的值減4。LR相當於是一個備份。

MOV             R7, SP

這里的含義就是標志着caller棧幀的結束及callee的棧幀的開始。相當於是參數准備就緒,我們可以開始執行程序了。

SUB             SP, SP, #0x20

這里是給子程序開辟空間。

以上三步結束的時候ARM開始調用部分就結束了。

MOV             R3, R2

R2的值給R3。

MOV             R12, R1

R1的值給R12

MOV             LR, R0

R0=LR。

STR             R0, [SP,#0x28+var_10] STR             R1, [SP,#0x28+var_14] STR             R2, [SP,#0x28+var_18]

這三句一起看,意思就是把R0,R1,R2放入棧中。位置分別是,18,14,10。

LDR             R0, [SP,#0x28+var_18]

把棧上10位置的內容拿下來給R0寄存器,我們棧上10的位置是R2。相當於是R0=R2。

MOVS            R1, #0x80

R1賦值為80,這里movs和mov的區別在於movs會更改N,Z,C標志。N=0代表整數或者0,N=1代表是整數。此時R1>30,所以N為0。Z表示運算結果。R1不為0則z=1;C標志位一般不會通過加減改變。

STR             R0, [SP,#0x28+var_1C]

把R0的內容放在棧C。

MOV             R0, R1  ; int

R1的值給R0。

STR             R3, [SP,#0x28+var_20]

R3的值原本為R2,這里把這個值放在棧8。

STR.W           R12, [SP,#0x28+var_24]

把R12的值放入棧4中。
這里的.W 是wide。指定匯編器必須為這條指令選擇一個32位的編碼模式。如果辦不到,匯編器報錯。

STR.W           LR, [SP,#0x28+var_28]

LR存入棧0中

BLX             j__Z2uri

跳轉到 j__Z2uri。這里的注釋是ur(int),說明這個函數原型是ur(int)

 LDR             R1, [SP,#0x28+var_1C]

這里把棧c里的內容放到R1中。這個時候其實我們拿到是我們輸入的key。

CMP             R1, R0

然后用我們的key        和R0進行比較,這里的R0是最后ur的返回結果。

BNE             loc_4490

不一樣跳轉loc_4490

B               loc_448A

否則跳轉到loc_448A

這里我們就知道了關鍵方法就是ur(int)這個了。

最后我們來看一下流程圖。

image.png

2.ur(int)方法分析

說真的。。。分析這個是真的累,不過進步起來還是非常快的。

image.png

2.1 第一段分析

PUSH            {R7,LR} MOV             R7, SP SUB             SP, SP, #0x28

這三行之前說過,相當於ARM在准備階段。

MOV             R1, R0 STR             R0, [SP,#0x30+var_C] LDR             R0, [SP,#0x30+var_C] STR             R0, [SP,#0x30+var_10]

這一小部分完成之后的效果就是,R1=R0,棧24的部分存為R0,並且給R0重新復制為棧20

LDR             R0, [SP,#0x30+var_C]

把R0從棧24拿出來

STR             R0, [SP,#0x30+var_14]

然后把R0的值給棧2C的位置。

這里我們先來看一下流程圖。

image.png

如果之前自己分析過循環的話就知道這個肯定是一個循環邏輯。而且再循環里還嵌套了循環和if語句。

MOVS            R0, #2

把立即數2賦值給R0。

 STR             R0, [SP,#0x30+var_18]

把2這個立即數給棧18位置。

STR             R1, [SP,#0x30+var_1C]

我們的R1原本是R0的值,現在把R1的值給棧14位置。

B               loc_42E2

無條件跳轉到loc_42E2。

目前位置,總結一下,相當於寫了

i=2 sp[5]=128

來看loc_42E2部分。
image.png

LDR             R0, [SP,#0x30+var_18]

從棧18中拿到立即數#2。並且給R0。

MULS            R0, R0

將兩個理解書相乘。現在狀態R0=R0*R0,R0=4;

LDR             R1, [SP,#0x30+var_14]

從棧1C中拿出數據,這里的數據之前存的是R0的數據,R0則是128。這里有一個小疑問,為什么這里不從棧14出拿數據。

CMP             R0, R1

比較R0和R1

BGT             loc_433E

如果大於則跳轉loc_433E

B               loc_42EE

否則跳轉到loc_42EE

這個時候我們來再看看流程圖。

image.png

主要看框起來的內容,這里有一個分支結束了,證明這一個部分結束了。
而另外一邊則會返回loc_42E2,這說明什么情況,這個就是典型的for循環。
如果之后有需要就對所有可能出現的狀態邏輯圖進行一個梳理。

我們這里先來分析一下 loc_42EE部分。

image.png

LDR             R0, [SP,#0x30+var_14]

從棧1c處拿到數據。此時棧1c出存的數據是128。16進制顯示為80

LDR             R1, [SP,#0x30+var_18]

從棧18處拿到數據,此時棧18存儲的內容是2。

BL              sub_13FCC

跳轉到sub_13FCC,並且保存下一條的地址,可以使用mov PC,LR返回原處。

我們先來看sub_13FCC這個子程序。
image.png

CMP             R1, #0

R1和立即數0進行比較。我們來確定一下R1的數值。

BEQ             loc_13FBA

如果相等則跳轉loc_13FBA

PUSH.W          {R0,R1,LR}

把R0,R1,LR入棧

BL              sub_13F0C

跳轉sub_13F0C,保存LR。

之后還有很長一串,這里有興趣的可以繼續分析下去。這里直接說明結果就是對128進行取余操作。

128%i

我們還是回到之前的ur方法處繼續分析。

image.png

CMP             R1, #0

比較我們取余的結果。

STR             R0, [SP,#0x30+var_20]

把R0的值放入棧10,R0的值是128

BNE             loc_4334

如果不相等,則跳轉至loc_4334。

B               loc_42FE

否則跳轉loc_42FE

如果是跳轉到loc_4334。

image.png

直接進入第二次循環。

如果是跳轉到loc_42FE,則進行深一層次的判斷。

2.2 小結

總的來說這個CreakMe是這樣子的

for(int i;i*i<128) {         if(128%i==0)         {                 while()                 {                 }                 } } if() { } return ...

整體邏輯結構就是這個了。如果在這個時候進行動態分析的話,也可以很輕松的解決。

經過一些分析,發現這個CreakMe是在進行一個歐拉函數的計算。

就是在計算一個數的和這個數互質的個數。

這里也可以確定到128就是其中內嵌的一個歐拉函數。

那我們很簡單自己寫一個歐拉函數的計算方法就可以了。

0×03 注冊機編寫

所謂的注冊機,就是根據一定的邏輯來推算出正確結果。

這里我們需要寫一個程序來完成歐拉函數的計算。

int oula(int number) {     int res=number;     int a=number;     for(int i=2;i*i<=a;i++)     {         if(a%i==0){             res=res/i*(i-1);             while(a%i==0) a/=i;         }     }     if(a>1) res=res/a*(a-1);     return res; }

最后128的歐拉函數結果是64。

輸入之后

image.png

以上

i春秋推出優享會員制,開通會員可以免費暢享多類課程、實驗、CTF賽題等付費內容,並可享有包括會員日專屬福利、就業推薦等多種特權福利,更多活動詳情可點擊:https://bbs.ichunqiu.com/thread-40795-1-1.html了解哦~


免責聲明!

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



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