Android SO逆向2-实例分析
[TOC]
這篇文章主要介紹幾個簡單的例子,來逆向分析so,當然有些破解可以在smali里直接修改,但是這里均采用逆向so的方式。
0x01 ARM—HEX轉換
1.將ARM指令轉換為Hex時,可以使用工具Arm_Asm,如下圖:
2.可以根據ARM參考手冊,手動轉換。比如add的指令格式如下:
當執行add r0,#1時,Rdn為0,imm8為1,所以二進制為00110000 00000001,轉換為16進制就是3001,所以Hex code就是0130
3.百度文庫上有人上傳了一份整理好的thumb指令集,如果不想到ARM參考手冊上找,可以看看這個。
| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136 | vis?immed_valuen?isRnmis?Rms?isRsris?register_listc?iscondition??????表一:按指令字母升序排列01000001?01mmmddd?--ADC?Rd,Rm0001?110vvvnn?nddd--?ADDRd,Rn,#immed_300110ddd?vvvvvvvv?--ADD?Rd,#immed_80001?100mmmnn?nddd--?ADDRd,Rn,Rm01000100?hhmmmddd?--ADD?Rd,Rm??h1h2,h1is?msbfor?Rd,h2is?msbfor?Rm1010?0dddvvvv?vvvv--?ADDRd,PC,#immed_8*410101ddd?vvvvvvvv?--ADD?Rd,SP,#immed_8*41011?00000vvv?vvvv--?ADDSP,#immed_7*401000000?00mmmddd?--AND?Rd,Rm0001?0vvvvvmm?mddd--?ASRRd,Rm,#immed_501000001?00sssddd?--ASR?Rd,Rs1101?ccccvvvv?vvvv--?Bccsigned_immed_811100vvv?vvvvvvvv?--B???signed_immed_110100?001110mm?mddd--?BICRd,Rm10111110?vvvvvvvv?--BKPT?immed_8111h?hvvvvvvv?vvvv--?BL(X)immed_1101000111?1hmmmSBZ?--BLX?Rm0100?01110Hmm?mSBZ--?BXRm01000010?11mmmnnn?--CMN?Rn,Rm0010?1nnnvvvv?vvvv--?CMPRn,#immed_801000010?10mmmnnn?--CMP?Rn,Rm0100?0101hhmm?mnnn--?CMPRn,Rm01000000?01mmmddd?--EOR?Rd,Rm1100?1nnnrrrr?rrrr--?LDMIARn!,reg_list01101vvv?vvnnnddd?--LDR?Rd,[Rn+#immed_5*4]0101?100mmmnn?nddd--?LDRRd,[Rn,Rm]01001ddd?vvvvvvvv?--LDR?Rd,[PC+#immed_5*4]1001?1dddvvvv?vvvv--?LDRRd,[SP,#immed_8*4]01111vvv?vvnnnmmm?--LDRB?Rd,[Rn,#immed_5*4]0101?110mmmnn?nddd--?LDRVRd,[Rn,Rm]10001vvv?vvnnnddd?--LDRH?Rd,[Rn,#immed_5*2]0101?101mmmnn?nddd--?LDRHRd,[Rn,Rm]0101011m?mmnnnddd?--LDRSB?Rd,[Rn,Rm]0101?111mmmnn?nddd--?LDRSHRd,[Rn,Rm]00000vvv?vvmmmnnn?--LSL?Rd,Rm,#immed_50100?000010ss?sddd--?LSLRd,Rs00001vvv?vvmmmddd?--LSR?Rd,Rm,#immed_50100?000011ss?sddd--?LSRRd,Rs00100ddd?vvvvvvvv?--MOV?Rd,#immed_80001?110000nn?nddd--?MOVRd,Rn01000110?hhmmmddd?--MOV?Rd,Rm0100?001101mm?mddd--?MULRd,Rm01000011?11mmmddd?--MVN?Rd,Rm0100?001001mm?mddd--?NEGRd,Rm01000011?00mmmddd?--ORR?Rd,Rm1011?110Rrrrr?rrrr--?POPreg_list1011010R?rrrrrrrr?--PUSH?reg_list0100?000111ss?sddd--?RORRd,Rs01000001?10mmmddd?--SBC?Rd,Rm1100?0nnnrrrr?rrrr--?STMIARn!,reg_list01100vvv?vvnnnddd?--STR?Rd,[Rn,#immed_5*4]0101?000mmmnn?nddd--?STRRd,[Rn,Rm]10010ddd?vvvvvvvv?--STR?Rd,[SP,#immed_8*4]0111?0vvvvvnn?nddd--?STRBRd,[Rn,#immed_5]0101010m?mmnnnddd?--STRB?Rd,[Rn,Rm]1000?0vvvvvnn?nddd--?STRHRd,[Rn,#immed_5*2]0101001m?mmnnnddd?--STRH?Rd,[Rn,Rm]0001?111vvvnn?nddd--?SUBRd,Rn,#immed_300111ddd?vvvvvvvv?--SUB?Rd,#immed_80001?101mmmnn?nddd--?SUBRd,Rn,Rm10110000?1vvvvvvv?--SUB?Sp,#immed_7*41101?1111vvvv?vvvv--?SWIimmed_801000010?00mmmnnn?--TST?Rn,Rm表二:按指令機器碼升序排列0000?0vvvvvmm?mnnn--?LSLRd,Rm,#immed_500001vvv?vvmmmddd?--LSR?Rd,Rm,#immed_50001?0vvvvvmm?mddd--?ASRRd,Rm,#immed_50001100m?mmnnnddd?--ADD?Rd,Rn,Rm0001?101mmmnn?nddd--?SUBRd,Rn,Rm0001110v?vvnnnddd?--ADD?Rd,Rn,#immed_30001?111vvvnn?nddd--?SUBRd,Rn,#immed_300011100?00nnnddd?--MOV?Rd,Rn0010?0dddvvvv?vvvv--?MOVRd,#immed_800101nnn?vvvvvvvv?--CMP?Rn,#immed_80011?0dddvvvv?vvvv--?ADDRd,#immed_800111ddd?vvvvvvvv?--SUB?Rd,#immed_80100?000000mm?mddd--?ANDRd,Rm01000000?01mmmddd?--EOR?Rd,Rm0100?000010ss?sddd--?LSLRd,Rs01000000?11sssddd?--LSR?Rd,Rs0100?000100ss?sddd--?ASRRd,Rs01000001?01mmmddd?--ADC?Rd,Rm0100?000110mm?mddd--?SBCRd,Rm01000001?11sssddd?--ROR?Rd,Rs0100?001000mm?mnnn--?TSTRn,Rm01000010?01mmmddd?--NEG?Rd,Rm0100?001100mm?mddd--?ORRRd,Rm01000010?10mmmnnn?--CMP?Rn,Rm0100?001011mm?mnnn--?CMNRn,Rm01000011?01mmmddd?--MUL?Rd,Rm0100?001110mm?mddd--?BICRd,Rm01000011?11mmmddd?--MVN?Rd,Rm0100?0100hhmm?mddd--?ADDRd,Rm??h1h2,h1is?msbfor?Rd,h2is?msbfor?Rm01000101?hhmmmnnn?--CMP?Rn,Rm0100?0110hhmm?mddd--?MOVRd,Rm01000111?0HmmmSBZ?--BX?Rm0100?01111hmm?mSBZ--?BLXRm01001ddd?vvvvvvvv?--LDR?Rd,[PC+#immed_5*4]0101?000mmmnn?nddd--?STRRd,[Rn,Rm]0101001m?mmnnnddd?--STRH?Rd,[Rn,Rm]0101?010mmmnn?nddd--?STRBRd,[Rn,Rm]0101011m?mmnnnddd?--LDRSB?Rd,[Rn,Rm]0101?100mmmnn?nddd--?LDRRd,[Rn,Rm]0101101m?mmnnnddd?--LDRH?Rd,[Rn,Rm]0101?110mmmnn?nddd--?LDRVRd,[Rn,Rm]0101111m?mmnnnddd?--LDRSH?Rd,[Rn,Rm]0110?0vvvvvnn?nddd--?STRRd,[Rn,#immed_5*4]01101vvv?vvnnnddd?--LDR?Rd,[Rn+#immed_5*4]0111?1vvvvvnn?nmmm--?LDRBRd,[Rn,#immed_5*4]01110vvv?vvnnnddd?--STRB?Rd,[Rn,#immed_5]1000?0vvvvvnn?nddd--?STRHRd,[Rn,#immed_5*2]10001vvv?vvnnnddd?--LDRH?Rd,[Rn,#immed_5*2]1001?0dddvvvv?vvvv--?STRRd,[SP,#immed_8*4]10011ddd?vvvvvvvv?--LDR?Rd,[SP,#immed_8*4]1010?0dddvvvv?vvvv--?ADDRd,PC,#immed_8*410101ddd?vvvvvvvv?--ADD?Rd,SP,#immed_8*41011?00000vvv?vvvv--?ADDSP,#immed_7*410110000?1vvvvvvv?--SUB?Sp,#immed_7*41011?010Rrrrr?rrrr--?PUSHreg_list1011110R?rrrrrrrr?--POP?reg_list1011?1110vvvv?vvvv--?BKPTimmed_811000nnn?rrrrrrrr?--STMIA?Rn!,reg_list1100?1nnnrrrr?rrrr--?LDMIARn!,reg_list1101cccc?vvvv?vvvv--?Bccsigned_immed_81101?1111vvvv?vvvv--?SWIimmed_811100vvv?vvvvvvvv?--B???signed_immed_11111h?hvvvvvvv?vvvv--?BL(X)immed_11 |
0x02 示例
先對上篇文章中的switch分支進行逆向。
getSwitch()的代碼如下:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | JNIEXPORTjint?JNICALL?Java_com_example_hellojni_GetSwitch_getSwitch ??(JNIEnv*,jclass,jint?a,jint?b,jint?i){ ????switch(i){ ????????case1: ????????????returna?+b; ????????????break; ????????case2: ????????????returna?-b; ????????????break; ????????case3: ????????????returna?*b; ????????????break; ????????case4: ????????????returna?/b; ????????????break; ????????default: ????????????returna?+b; ????????????break; ????????} } |
1.逆向APK后,使用IDA打開libs目錄下的libHelloJNI.so,alt+t找到GetSwitch函數
2.當我們傳入的參數是4,2,2是,執行的是a – b,所以返回的結果是2
3.現在,我們將a – b改為a + b,就是要返回結果為6,找到i=2的減法分支,計算add ro,r2,r3的hex為D018
4.然后切換到Hex View,修改Hex為D018,再回到圖形模式時,可以看到SUBS R0,R2,R3已經更改為ADDS R0,R2,R3了
5.使用010editor,ctrl+g跳轉到104A的地址,修改Hex為D018,然后保存。
6.重新編譯成APK,運行時,發現結果已經變為6了。
0x03 內購破解
1.正常情況下,購買金幣時,是需要付費的,因為使用的是模擬器,所以顯示付費失敗。
2.從smali中找到相應的so,IDA打開。找到函數GameCoin,先F5看一下,看到關鍵點GameMain::GameCoin = v3 + v1,就是當前游戲的金幣數量,對應的匯編為:ADDS R0,R0,R6
3.我們知道R0是返回值,R6是計算出的當前金幣數,所以我們把此處改為ADDS R0,#255,所以每次都會增加255個金幣,Hex為FF30
4.修改后,初始金幣為10,點擊一次后,增加了255個。
0x04 加密解密
這篇文章是從吾愛破解(http://www.52pojie.cn/thread-396463-1-1.html)看到的,作者是adslxyz。
準備工具:
手機連上wifi,與電腦處于同一局域網,然后設置好Fiddler,具體步驟不詳述。打開寶寶樹孕育6.2.1版本,進入登陸窗口,輸入賬號密碼點登陸,在電腦查看封包。可以得到請求URL:http://www.babytree.com/api/muser/login
| 1 | POST:android_id=d77c45cb6182db0e&build_serial=mmmm&local_ts=1438682239&source_channel=pc_pregnancy_tongyong_app_140729&longitude=122.535462&latitude=35.582332&phone_number=buROv8rMh50AdCj7mYdAZwWv9YEpsIR2mClGrO43QK6E5GHko7aEZwtZMT%2F2nvyuUCYsFtx%2Bkz1kwpthbRlpZecGXjkbyaaeIE4ocYjolDyLXLduydRCjnG%2Bk9OEfBr3QCShaiJ2Z%2BeDQIeqgTssdlzZqzFfpHzsg3oWpdF3RbMLF3O93RzGWntJgkgvzjzK7BfwvRF8p8o6Se2l7mX7malpYrn35H2kh4mEAaLaBGoj2naCxcSXCn6X6w9za6hofkhogCtB7PpY6pulzY%2BOhejwG1jdoCpqRxcctRcsFPWNz72SD8Mmqkq6wRVeLYX5ZIoWNafwEJuPobuRtmvhQzg%3D%3D&version=6.2.1&imei=90000451032112&secret=b8a310e750c8af5187197c279a7e0241&email=zLkZURsmEpT8fGCGGNADu2KAZ79zkZI3b%2FMBDh5i1vCAbvFmKoGu7L4nBPsOvnzzsnWtuOJipiITnoRQ5w%2FNTy%2FvEx%2BX%2FO8Ff8jcU2qBAXTzGgd0x1lZ8PsGuan0944ax5n1douoaTC370Hv4A%2F58IhP8rhcQWnO4FzFol8FC%2FXQ%2Fd1%2FoAQOycwdLeBUm0JJ5tRKiaT2nBwD1z7Dn1CShswWCNN2zDCvYgtJ7Ig3JIQipUahL9OaR%2FQnzUzk%2BmaC%2Fm6iRr1q4wkiz9lexJkXFHf1g5VuFqshCNgxdgeDw%2BZHuagedfj5MakZD96Lj%2BtZtRf6GhaLbY29tSL65EdSgsg%3D%3D&password=AhOxbuypr6JYDgpP%2Fw%2BLhVlfzwusSMOaE0137YBOvOAZkk%2BbCHwzfduzqsjasx6zrhZUkZv3aoZ27HDIFAebdgsRS9lh2eeuxXiIxZdkaVPy47UNMdLHo1fFnuUEOCbE144H%2FL%2B2EeY%2BjbE8Ebjg0gXuZ7ziNZ%2Bmrgt4%2FrN8YbizcbyCx7A%2Fue3GD3p58GV3ztnlxWp9d4D1IlMT5V%2B8qxi3VDpQMr0Ghi4MaDTkH%2FV8fcRSCBqutHTDsEs%2F5AfBgksHFT6Dcxl3tpBIIfdgEmU4EZ%2BpqLqVxVFLdjPA0MJOhzE36P8NqTPiKEXzTuJcmaaS5qU34d2dHGYP2wc7Dg%3D%3D&client_type=android&app_id=pregnancy&mac=5c%3A51%5A57%3A55%3A26%3A4d&client_baby_status=1&bpreg_brithday=2100-01-01 |
分析可知:phone_number,password,email,secret四個參數為加密,其他參數均為固定或者地理位置信息等參數。所以此次目標就為這4個參數
圖上可以看到,目標應用的端口為8631.
從圖中可以看到,左下角為函數的調用堆棧,從 登陸按鈕 按下(OnClick),到api.user.login整個的調用過程。展開右下角的p0,可以看到此時已經生成了3個參數,
說明在斷點之前,參數已經生成好了。所以我們按照函數的調用棧,挨個查看調用過的函數。查閱一番后可以發現。Login對象是在LoginActivity中的.method public a(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V方法創建的。在new-instance v0, Lcom/babytree/platform/api/muser/Login;處下斷點,重新點擊登陸按鈕,如圖:
此時v1.v2.v3寄存器分別出現了加密的結果,由上可知,分別對應phone_number,password,email三個參數。
所以加密的函數應該就在上面。往上下斷點,重新來一次觀察一下加密的過程。
可知:
| 1 | iget-objectv0,p0,Lcom/babytree/apps/pregnancy/activity/LoginActivity;->u:Ljava/lang/String; |
這一句函數調用之后,v0是一串固定字符串。
| 1 | invoke-static{p1,v0},Lcom/babytree/apps/pregnancy/h/a;->a(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String; |
調用之后,v1為加密結果。查看a函數:
為RSA加密,所以之前的v0就是RSA的pubKey了。在a函數中下斷點,看一看加密的參數是什么:
一切盡收眼底。由此可知phone_number,password,email三個參數的算法。
回到AndroidKiller搜索關鍵字,定位到com/babytree/platform/api/ApiCommonParams;大致看一下,這個是API通用參數生成的類。且加載了一個so:api_encrypt.so在secret關鍵字附近看一下,調用了so的invoke-static {v1, v2}, Lcom/babytree/platform/api/ApiCommonParams;->nativeGetParam(Landroid/content/Context;Ljava/util/List;)Ljava/lang/String;方法。
我們先在這句上面下個斷點,看看傳給so函數的是什么參數。斷點斷下后,看到傳遞給so的參數是一個List,POST參數中除secret之外的所有參數。參數知道了,調用點知道了。分析一下so,看看需不需要動態調試。載入ida,找到調用的nativeGetParam函數。大致看一下,發現又調用了java的md5函數,好了,調試so的步驟剩下了。
回到IntelliJ IDEA,在getMD5Str處下斷點,繼續調試:
很快我們可以知道,p0中就是進行md5的參數啦。
分析一下可知,secret就是 MD5(時間戳+所有參數排序+&asdf12341dfas!@#$%()(Ujjlasdflasdfj;asjdf23412313kljajsdflasjdflasjdflajsdf;lajsdf2342234sdfsdfffds)
總結:
動態調試apk的方式讓我們了解apk運作的過程,通過動靜結合的分析方式,快速找到想要的東西~
0x05 簽名校驗
將關鍵代碼放到so中,在底層獲取簽名信息并驗證。因為獲取和驗證的方法都封閉在更安全的so庫里面,能夠起到一定意義上的保護作用。實例如下:
轉載自:http://drops.wooyun.org/mobile/10010 ? ?原文作者:3xpl0it
總結
以上是生活随笔為你收集整理的Android SO逆向2-实例分析的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Android SO逆向1-ARM介绍
- 下一篇: android sina oauth2.