您好,登錄后才能下訂單哦!
這期內(nèi)容當(dāng)中小編將會(huì)給大家?guī)碛嘘P(guān)so靜態(tài)分析中CreakeMe的分析思路是什么 ,文章內(nèi)容豐富且以專業(yè)的角度為大家分析和敘述,閱讀完這篇文章希望大家可以有所收獲。
拿到一個(gè)CreakeMe,寫一個(gè)分析思路。CreakMe主要是對.so文件內(nèi)容進(jìn)行分析,當(dāng)然很多學(xué)習(xí)Android逆向的在分析到smali代碼的時(shí)候就已經(jīng)停止腳步了。在接觸到.so文件的時(shí)候才是開始進(jìn)一步的逆向?qū)W習(xí),當(dāng)然這里就要學(xué)習(xí)ARM匯編了。關(guān)于ARM匯編在網(wǎng)上有很多的資料,這里就不再贅述。
請使用:HAI手冊
嘗試使用App得出這些結(jié)論。
1.我們需要一個(gè)key。
2.這個(gè)key是數(shù)字。
逆向拿到smali代碼。
工具:Android Killer。
找到入口MainActivity。
我們看到這里有一段代碼:
這段代碼的作用就是調(diào)用so文件庫。我們猜測這個(gè)App很有可能把關(guān)鍵key寫在了so文件里。
我們從onClick方法定位到關(guān)鍵點(diǎn)。
這里是判斷正誤的地方,這里看到如果v0和v2的值不相等的話就跳轉(zhuǎn)。并且這里v2的值是1。
我們向上看。
這里有一個(gè)調(diào)用方法。
在這里我們看到這個(gè)是Native層的方法。并且這個(gè)方法會(huì)返回一個(gè)int數(shù)據(jù),這里猜測可能會(huì)是0或者1。在這里還有一個(gè)就是傳入的是一個(gè)int型數(shù)據(jù),根據(jù)我們之前的測試,知道這里就是我們從輸入框輸入的內(nèi)容。
監(jiān)聽事件——輸入key——key方法判斷——返回0或1
1為正確,0為錯(cuò)誤。
但是我們依然沒有找到Key的是指內(nèi)容。
so逆向
使用工具:ida
找到關(guān)鍵的Key函數(shù)。
這里可以看到ARM匯編比smali難的可不是一個(gè)度兩個(gè)度。
為了提升能力,我們還是一句一句的分析。如果是學(xué)習(xí)的話,請不要依賴F5。
PUSH {R7,LR}
把R7寄存器和LR入棧。
R7的含義就是指向前一個(gè)保存的棧幀和鏈接寄存器在棧上的地址。
這里可能會(huì)對LR的作用不知道,簡單的說一下,LR的作用一個(gè)是保存子程序的返回地址。還有一個(gè)是當(dāng)異常發(fā)生時(shí),LR中保存的值等于異常發(fā)生時(shí)PC的值減4。LR相當(dāng)于是一個(gè)備份。
MOV R7, SP
這里的含義就是標(biāo)志著caller棧幀的結(jié)束及callee的棧幀的開始。相當(dāng)于是參數(shù)準(zhǔn)備就緒,我們可以開始執(zhí)行程序了。
SUB SP, SP, #0x20
這里是給子程序開辟空間。
以上三步結(jié)束的時(shí)候ARM開始調(diào)用部分就結(jié)束了。
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位置的內(nèi)容拿下來給R0寄存器,我們棧上10的位置是R2。相當(dāng)于是R0=R2。
MOVS R1, #0x80
R1賦值為80,這里movs和mov的區(qū)別在于movs會(huì)更改N,Z,C標(biāo)志。N=0代表整數(shù)或者0,N=1代表是整數(shù)。此時(shí)R1>30,所以N為0。Z表示運(yùn)算結(jié)果。R1不為0則z=1;C標(biāo)志位一般不會(huì)通過加減改變。
STR R0, [SP,#0x28+var_1C]
把R0的內(nèi)容放在棧C。
MOV R0, R1 ; int
R1的值給R0。
STR R3, [SP,#0x28+var_20]
R3的值原本為R2,這里把這個(gè)值放在棧8。
STR.W R12, [SP,#0x28+var_24]
把R12的值放入棧4中。
這里的.W 是wide。指定匯編器必須為這條指令選擇一個(gè)32位的編碼模式。如果辦不到,匯編器報(bào)錯(cuò)。
STR.W LR, [SP,#0x28+var_28]
LR存入棧0中
BLX j__Z2uri
跳轉(zhuǎn)到 j__Z2uri。這里的注釋是ur(int),說明這個(gè)函數(shù)原型是ur(int)
LDR R1, [SP,#0x28+var_1C]
這里把棧c里的內(nèi)容放到R1中。這個(gè)時(shí)候其實(shí)我們拿到是我們輸入的key。
CMP R1, R0
然后用我們的key 和R0進(jìn)行比較,這里的R0是最后ur的返回結(jié)果。
BNE loc_4490
不一樣跳轉(zhuǎn)loc_4490
B loc_448A
否則跳轉(zhuǎn)到loc_448A
這里我們就知道了關(guān)鍵方法就是ur(int)這個(gè)了。
最后我們來看一下流程圖。
說真的。。。分析這個(gè)是真的累,不過進(jìn)步起來還是非常快的。
PUSH {R7,LR}MOV R7, SPSUB SP, SP, #0x28
這三行之前說過,相當(dāng)于ARM在準(zhǔn)備階段。
MOV R1, R0STR R0, [SP,#0x30+var_C]LDR R0, [SP,#0x30+var_C]STR R0, [SP,#0x30+var_10]
這一小部分完成之后的效果就是,R1=R0,棧24的部分存為R0,并且給R0重新復(fù)制為棧20
LDR R0, [SP,#0x30+var_C]
把R0從棧24拿出來
STR R0, [SP,#0x30+var_14]
然后把R0的值給棧2C的位置。
這里我們先來看一下流程圖。
如果之前自己分析過循環(huán)的話就知道這個(gè)肯定是一個(gè)循環(huán)邏輯。而且再循環(huán)里還嵌套了循環(huán)和if語句。
MOVS R0, #2
把立即數(shù)2賦值給R0。
STR R0, [SP,#0x30+var_18]
把2這個(gè)立即數(shù)給棧18位置。
STR R1, [SP,#0x30+var_1C]
我們的R1原本是R0的值,現(xiàn)在把R1的值給棧14位置。
B loc_42E2
無條件跳轉(zhuǎn)到loc_42E2。
目前位置,總結(jié)一下,相當(dāng)于寫了
i=2sp[5]=128
來看loc_42E2部分。
LDR R0, [SP,#0x30+var_18]
從棧18中拿到立即數(shù)#2。并且給R0。
MULS R0, R0
將兩個(gè)理解書相乘?,F(xiàn)在狀態(tài)R0=R0*R0,R0=4;
LDR R1, [SP,#0x30+var_14]
從棧1C中拿出數(shù)據(jù),這里的數(shù)據(jù)之前存的是R0的數(shù)據(jù),R0則是128。這里有一個(gè)小疑問,為什么這里不從棧14出拿數(shù)據(jù)。
CMP R0, R1
比較R0和R1
BGT loc_433E
如果大于則跳轉(zhuǎn)loc_433E
B loc_42EE
否則跳轉(zhuǎn)到loc_42EE
這個(gè)時(shí)候我們來再看看流程圖。
主要看框起來的內(nèi)容,這里有一個(gè)分支結(jié)束了,證明這一個(gè)部分結(jié)束了。
而另外一邊則會(huì)返回loc_42E2,這說明什么情況,這個(gè)就是典型的for循環(huán)。
如果之后有需要就對所有可能出現(xiàn)的狀態(tài)邏輯圖進(jìn)行一個(gè)梳理。
我們這里先來分析一下 loc_42EE部分。
LDR R0, [SP,#0x30+var_14]
從棧1c處拿到數(shù)據(jù)。此時(shí)棧1c出存的數(shù)據(jù)是128。16進(jìn)制顯示為80
LDR R1, [SP,#0x30+var_18]
從棧18處拿到數(shù)據(jù),此時(shí)棧18存儲(chǔ)的內(nèi)容是2。
BL sub_13FCC
跳轉(zhuǎn)到sub_13FCC,并且保存下一條的地址,可以使用mov PC,LR返回原處。
我們先來看sub_13FCC這個(gè)子程序。
CMP R1, #0
R1和立即數(shù)0進(jìn)行比較。我們來確定一下R1的數(shù)值。
BEQ loc_13FBA
如果相等則跳轉(zhuǎn)loc_13FBA
PUSH.W {R0,R1,LR}
把R0,R1,LR入棧
BL sub_13F0C
跳轉(zhuǎn)sub_13F0C,保存LR。
之后還有很長一串,這里有興趣的可以繼續(xù)分析下去。這里直接說明結(jié)果就是對128進(jìn)行取余操作。
128%i
我們還是回到之前的ur方法處繼續(xù)分析。
CMP R1, #0
比較我們?nèi)∮嗟慕Y(jié)果。
STR R0, [SP,#0x30+var_20]
把R0的值放入棧10,R0的值是128
BNE loc_4334
如果不相等,則跳轉(zhuǎn)至loc_4334。
B loc_42FE
否則跳轉(zhuǎn)loc_42FE
如果是跳轉(zhuǎn)到loc_4334。
直接進(jìn)入第二次循環(huán)。
如果是跳轉(zhuǎn)到loc_42FE,則進(jìn)行深一層次的判斷。
總的來說這個(gè)CreakMe是這樣子的
for(int i;i*i<128) { if(128%i==0) { while() { } } }if() { }return ...
整體邏輯結(jié)構(gòu)就是這個(gè)了。如果在這個(gè)時(shí)候進(jìn)行動(dòng)態(tài)分析的話,也可以很輕松的解決。
經(jīng)過一些分析,發(fā)現(xiàn)這個(gè)CreakMe是在進(jìn)行一個(gè)歐拉函數(shù)的計(jì)算。
就是在計(jì)算一個(gè)數(shù)的和這個(gè)數(shù)互質(zhì)的個(gè)數(shù)。
這里也可以確定到128就是其中內(nèi)嵌的一個(gè)歐拉函數(shù)。
那我們很簡單自己寫一個(gè)歐拉函數(shù)的計(jì)算方法就可以了。
所謂的注冊機(jī),就是根據(jù)一定的邏輯來推算出正確結(jié)果。
這里我們需要寫一個(gè)程序來完成歐拉函數(shù)的計(jì)算。
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的歐拉函數(shù)結(jié)果是64。
輸入之后
上述就是小編為大家分享的so靜態(tài)分析中CreakeMe的分析思路是什么 了,如果剛好有類似的疑惑,不妨參照上述分析進(jìn)行理解。如果想知道更多相關(guān)知識,歡迎關(guān)注億速云行業(yè)資訊頻道。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。