原文:?iOS逆向-支付寶螞蟻森林
發現iOS支付寶逆向的分析并不多,螞蟻森林基于H5應用 套著UIWebView 基本也沒這類JS和原生交互分析的帖子,就拿此練手吧 作技術分享
去掉 ptrace 和 __RESTRICT section 兩個保護
脫殼和dump頭文件
分析和調試
編寫Tweak
總結
MacBook,iPhone6,iOS 9.3.3越獄, iOS支付寶10.1.5
theos
Tweak制作工具
xcode
用lldb來附加調試
class-dump
導出頭文件
dumpdecrypted
脫appstore的殼
iHex
二進制編輯器
去掉 __RESTRICT section 和 ptrace 兩個保護
去掉 __RESTRICT section 步驟
ssh到手機 執行命令ps -e
找到/var/containers/Bundle/Application/DD6D8BA3-95F2-4C6D-BFD7-0E20420A6E9C/AlipayWallet.app/AlipayWallet
切換到mac電腦 使用scp命令 把執行文件拷到電腦上scp root@192.168.2.2:/var/containers/Bundle/Application/C6F2DD99-6450-4838-98B8-2899E8EBC1A4/AlipayWallet.app/AlipayWallet /Users/hack/Desktop/wz
打開iHex 查找command+f 把 __RESTRICT和__restrict替換為其他值(比如:__RRRRRRRR和__rrrrrrrr。保證長度不變就行啦)看圖1
拷貝文件回去scp /Users/hack/Desktop/wz/AlipayWallet root@192.168.2.2:/var/containers/Bundle/Application/C6F2DD99-6450-4838-98B8-2899E8EBC1A4/AlipayWallet.app/AlipayWallet
如果打開閃退 請Cydia中安裝 AppSync
去除ptrace保護
使用theos 創建Tweak 代碼如下 安裝到手機就可以
#import#importstaticint(*orig_ptrace) (intrequest, pid_t pid, caddr_t addr,intdata);staticintmy_ptrace (intrequest, pid_t pid, caddr_t addr,intdata){if(request ==31){NSLog(@"[AntiAntiDebug] - ptrace request is PT_DENY_ATTACH");return0;? ? }returnorig_ptrace(request,pid,addr,data);}%ctor{? MSHookFunction((void*)MSFindSymbol(NULL,"_ptrace"),(void*)my_ptrace,(void**)&orig_ptrace);NSLog(@"[AntiAntiDebug] Module loaded!!!");}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
執行命令cycript -p AlipayWallet注入支付寶進程
執行命令[[NSFileManager defaultManager]URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask][0]
看到返回/var/mobile/Containers/Data/Application/5E744C4A-5B05-4280-A21C-9E6EFE8EF51D/Documents/
執行命令cd /var/mobile/Containers/Data/Application/5E744C4A-5B05-4280-A21C-9E6EFE8EF51D/Documents/
把 dumpdecrypted.dylib拷貝進去scp /Users/cardlan/Downloads/dumpdecrypted-master/dumpdecrypted.dylib root@192.168.2.2:/var/mobile/Containers/Data/Application/5E744C4A-5B05-4280-A21C-9E6EFE8EF51D/Documents/
執行命令DYLD_INSERT_LIBRARIES=dumpdecrypted.dylib /var/containers/Bundle/Application/DD6D8BA3-95F2-4C6D-BFD7-0E20420A6E9C/AlipayWallet.app/AlipayWallet
如果發現提示Killed: 9 切換su mobile再試 提示成功如下
DISCLAIMER: This toolisonly meantforsecurity research purposes,notforapplicationcrackers.[+] detected64bit ARM binaryinmemory.[+]offsettocryptid found: @0x100034d90(from0x100034000) = d90[+] Found encrypted dataataddress00004000oflength56786944bytes - type1.[+] Opening /private/var/containers/Bundle/Application/C6F2DD99-6450-4838-98B8-2899E8EBC1A4/AlipayWallet.app/AlipayWalletforreading.[+] Reading header[+] Detecting header type[+] Executableisa plain MACH-O image[+] Opening AlipayWallet.decryptedforwriting.[+] Copyingthenotencrypted startofthefile[+] Dumpingthedecrypted dataintothefile[+] Copyingthenotencrypted remainderofthefile[+] SettingtheLC_ENCRYPTION_INFO->cryptidto0atoffsetd90[+] Closing originalfile[+] Closing dumpfile
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
執行ls找到 AlipayWallet.decrypted scp拷貝到電腦就可以
接下來使用 class-dump 導出頭文件到當前文件夾
class-dump -H AlipayWallet.decrypted -o ./
打開支付寶到螞蟻森林界面 cycript -p AlipayWallet
我們從UI入手 執行[[UIApp keyWindow]recursiveDescription]看到
我們返回上面找控制器[#0x1386dc970 nextResponder]看到
我們去之前導出的頭文件翻翻 找到這個控制器 看看有什么敏感的方法和屬性,我們的目要找到關鍵的點擊事件或者相關的邏輯
我們使用choose(H5WebViewController)拿到實例 測試一下頭文件的方法看看
看了一大圈真沒什么什么進展,url 無法直接打開的 再想想UIWebView和原生交互的方法,如下代碼獲取個Html源碼來看看
類似于WebViewJavascriptBridge 咱們找下callback方法或者send方法試試
[#0x136a28400 lastMainRequest]" { URL: https://60000002.h5app.alipay.com/app/src/home.html?__webview_options__=transparentTitle%3Dauto%26canPullDown%3DNO}"[#0x136a28400 h5WebView]#">"[#0x136a28400 stringByEvaluatingJavaScriptFromString:"document.documentElement.innerHTML"]
1
2
3
4
5
6
7
8
我們來使用THEOS 自帶的logify.pl 生成H5WebViewController的全部方法調用和參數日志
/opt/theos/bin/logify.plH5WebViewController.h>Tweak.xm
1
編譯 Tweak.xm 注意:有編譯出錯 有些類和代理block是不認識的 出錯的刪掉就可以
CDUnknownBlockType 作參數的可以替換成 id 繼承于 DTViewController 替換成
安裝之后 手機連上我們電腦 打開xcode -菜單Window-Devices-Simulators
我們點擊那個能量按鈕收取別人的能量看看
接下來我們使用xcode 自帶的lldb來調試支付寶(默認xcode無法調試第三方應用)我們接下來給app加個權限
沒權限提示
Ensure“AlipayWallet”isnotalready running,andcardlan_yuhuajunhaspermissiontodebug it.
1
注意:要使用脫殼之后的AlipayWallet執行下面的命令,也就是AlipayWallet.decrypted 重命名為AlipayWallet(否則閃退)
將應用程序從設備上拷貝到本地利用 ldid 將應用程序的 code sign 導出:ldid-eAlipayWallet>>AlipayWallet.xml在 AlipayWallet.xml文件中添加 get-task-allow權限get-task-allow利用 ldid 對應用進行重簽名 ldid-SAlipayWallet.xml./AlipayWallet將應用拷回設備,將設置可執行權限 chmod755AlipayWallet完成
1
2
3
4
5
6
7
8
(圖3)
ps:如果如上操作還閃退 請重啟iphone
然后我們連上手機 xcode 隨便弄個工程 選擇iphone 看圖來開始附加AlipayWallet(圖4) 點到森林界面點擊xcode自帶的看界面工具 然后再xcode 右下角自帶的lldb 下斷點
我們先試著下斷函數
b-[H5WebViewController reportClickTime]
1
提示找不到no locations 我們隨便找個地址 看看堆棧信息
po[H5WebViewController _shortMethodDescription]
1
找一個地址
b 0x1057daab0
1
重開頁面 觸發斷點 ,點開xcode的堆棧窗口如(圖5)
發現很多地址是沒函數名的 當然也無法直接對函數名下斷點 我們借用大神寫的工具來恢復這些信息 文章鏈接如下
http://www.lxweimin.com/p/967b6631756c
之后 再附加一下
下這個斷點
b-[H5WebViewController reportClickTime]
1
發現是可以成功下斷了 繼續查看堆棧信息 現在函數名全部全了
(圖6)
往上回溯 思路 因為我們想找到是js過來的參數和調用原生方法是哪里過來的
畢竟 reportClickTime 不是我們要分析的
看到PSDJsBride 調用了很多次 而且看參數和函數名 很有可能 中轉了消息和參數 為了驗證我們的猜想 ,我們使用logify.pl 來生成tweak 打印他全部的調用日志
安裝到手機之后,我們取消斷電 打開xcode的日志看打印 有沒有敏感的信息調用
brdelete
1
點擊好友的那個能量收取 把日志全部copy 到Sublime text
看圖(7)
我們看到這個英文單詞 收集的意思 我們猜想這個就是收集能量的命令,看參數體有friedID 確定性90%了
- 證實猜想 我們用cycript 來試試 拿到PSDJsBridge 的實例 可以用choose也可以用日志打印那個
[#0x14a0bed80 _doFlushMessageQueue:@"把參數拷貝過來(自己處理轉義 里面有/"號)" url:@"第二個參數"];
提供下我日志的
_doFlushMessageQueue:[{"handlerName":"remoteLog","data":{"seedId":"ANTFOREST-BEHAVIOR-CLICK-COLLECT","param1":"shareBiz=none^bubbleId=26219984^actionUserId=2088322012980000^type=behavior^currentTimestamp=1510797618289","param2":"monitor_type=clicked^remoteType=info^pageName=home.html^pageState=friend2088322012980000_enterhomeOff","bizType":"antForest"},"callbackId":"remoteLog_15107976182890.5985529306344688"},{"handlerName":"rpc","data":{"operationType":"alipay.antmember.forest.h5.collectEnergy","requestData":[{"userId":2088322012987680,"bubbleIds":[26219984],"av":"5","ct":"ios"}],"disableLimitView":true},"callbackId":"rpc_15107976182910.0005478465463966131"}] url:https://60000002.h5app.alipay.com/app/src/home.html?userId=2088322012980000]
1
2
3
我們執行 看看日志打印 有日志輸出 看recv這些參數 和剛剛是有點差別 但是大致一樣(這個能量只能收一次)來看bubbleId 這個猜一下是能量的ID
來找怎么獲取的能量ID 我們打開一個有能量的好友,看日志 有獲取的調用沒
由于日志比較多 我們就是著重找有返回bubbleId和friedID 的列表,找到之后往上找調用著參數
[m -[ transformResponseData:{? ? ? ? bizNo ="092c5f8c-ee77-49ad-a3a2-dd3c059ee579-1510798661871";? ? ? ? bubbles =? ? (? ? ? ? ? ? ? ? ? ? {? ? ? ? ? ? ? ? business =? ? ? ? ? ? {? ? ? ? ? ? ? ? ? ? bigIconDisplayName ="\U884c\U8d70";? ? ? ? ? ? ? ? ? ? bizType = xingzou;? ? ? ? ? ? ? ? ? ? dayIconUrl ="https://zos.alipayobjects.com/rmsportal/xxx.png";id=9;? ? ? ? ? ? ? ? ? ? nightIconUrl ="https://zos.alipayobjects.com/rmsportal/xxx.png";? ? ? ? ? ? ? ? ? ? smallIconDisplayName ="\U884c\U8d70";? ? ? ? ? ? ? ? };? ? ? ? ? ? ? ? collectStatus = AVAILABLE;? ? ? ? ? ? ? ? fullEnergy =92;id=26343893;? ? ? ? ? ? ? ? produceTime =1510788093000;? ? ? ? ? ? ? ? remainEnergy =72;? ? ? ? ? ? ? ? userId =208890214255xxxx;? ? ? ? ? ? }? ? ? ? );? ? ? ? needGuide =0;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
結果有了 找調用
_doFlushMessageQueue:[{"handlerName":"remoteLog","data":{"seedId":"ANTFOREST-PAGE-READY-home","param1":"shareBiz=none^type=behavior^currentTimestamp=1510798661779","param2":"monitor_type=openPage^remoteType=info","bizType":"antForest"},"callbackId":"remoteLog_15107986617880.34833956067450345"},{"handlerName":"getSystemInfo","data":{},"callbackId":"getSystemInfo_15107986617920.08668778464198112"},{"handlerName":"hideOptionMenu","data":{},"callbackId":"hideOptionMenu_15107986617920.562577509554103"},{"handlerName":"setToolbarMenu","data":{"menus":[],"override":true},"callbackId":"setToolbarMenu_15107986617920.03417412145063281"},{"handlerName":"setGestureBack","data":{"val":true},"callbackId":"setGestureBack_15107986617920.6238974309526384"},{"handlerName":"remoteLog","data":{"seedId":"ANTFOREST-H5_PAGE_SET_PAGE_NAME","param1":"shareBiz=none^type=behavior^currentTimestamp=1510798661796","param2":"monitor_type=clicked^remoteType=info^pageName=home.html","bizType":"antForest"},"callbackId":"remoteLog_15107986617960.3546153837814927"},{"handlerName":"addNotifyListener","data":{"name":"NEBULANOTIFY_AFRefresh"},"callbackId":"addNotifyListener_15107986617960.04098325059749186"},{"handlerName":"rpc","data":{"operationType":"alipay.antmember.forest.h5.queryNextAction","requestData":[{"userId":"208890214255xxxx","av":"5","ct":"ios"}],"disableLimitView":true},"callbackId":"rpc_15107986617970.8864813686814159"}]url:https://60000002.h5app.alipay.com/app/src/home.html?userId=208890214255xxxx]
1
2
用cycript 測試這個方法 。結果如我們所愿 日志返回了我們需要的能量ID和好友ID 可以構造第一個找到那個方法 實現收一個好友的能量
- 由于這個方法需要好友ID的參數 我們需要拿到全部好友的ID 這樣才能實現我們的一鍵全部收取
- 這里我偷個懶 不去往下折騰 點擊頁面在PSDJsBridge transformResponseData
取top 10的好友ID(打開頁面他本身執行了 friendRanking系列方法 )
整理下流程,進頁面 他自身調用Top10的好友列表 我們拿到這10個用戶的UID
拿到UID之后執行上面分析的第二個方法 拿到指定用戶可以收的能量 collectStatus=AVAILABLE 返回參數中有 我們看字段就能猜到
拿到UID和能量ID 我們就可以執行收能量的功能了
具體的代碼不一一分析 下面會提供代碼下載地址
看成功圖8
UIWebView的應用不同于原生的應用 有正向開發經驗能通過UI層能輕易找到觸發事件
其實很多時候都在試錯和猜想 ,逐步的去驗證自己的猜想 直到找到答案
這個Tweak只作技術分析,并沒有完善 Top10用戶收取還不夠用 大家可以試著動手 獲取下一頁好友 和全部好友 看日志找到字段是可以輕易實現的 還有其他功能比如 每天定時啟動收取啥的
這是代碼GitHub地址
https://github.com/hackxhj/alipayForestTweak.git
歡迎star