iOS逆向-手把手教你写支付宝蚂蚁森林收集能量助手

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 [email protected]:/var/containers/Bundle/Application/C6F2DD99-6450-4838-98B8-2899E8EBC1A4/AlipayWallet.app/AlipayWallet /Users/hack/Desktop/wz

  • 打开iHex 查找command+f 把 __RESTRICT和__restrict替换为其他值(比如:__RRRRRRRR和__rrrrrrrr。保证长度不变就行啦)看图1

    iOS逆向-手把手教你写支付宝蚂蚁森林收集能量助手_第1张图片

  • 拷贝文件回去scp /Users/hack/Desktop/wz/AlipayWallet [email protected]:/var/containers/Bundle/Application/C6F2DD99-6450-4838-98B8-2899E8EBC1A4/AlipayWallet.app/AlipayWallet

  • 如果打开闪退 请Cydia中安装 AppSync

  • 去除ptrace保护

  • 使用theos 创建Tweak 代码如下 安装到手机就可以
#import 
#import 
static int (*orig_ptrace) (int request, pid_t pid, caddr_t addr, int data);
static int my_ptrace (int request, pid_t pid, caddr_t addr, int data){
    if(request == 31){
     NSLog(@"[AntiAntiDebug] - ptrace request is PT_DENY_ATTACH");
    return 0;
    }
   return orig_ptrace(request,pid,addr,data);
}

%ctor{
   MSHookFunction((void *)MSFindSymbol(NULL,"_ptrace"),(void*)my_ptrace,(void**)&orig_ptrace);
   NSLog(@"[AntiAntiDebug] Module loaded!!!");
}

脱壳和dump头文件

  • 执行命令 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 [email protected]:/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 tool is only meant for security research purposes, not for application crackers.

[+] detected 64bit ARM binary in memory.
[+] offset to cryptid found: @0x100034d90(from 0x100034000) = d90
[+] Found encrypted data at address 00004000 of length 56786944 bytes - type 1.
[+] Opening /private/var/containers/Bundle/Application/C6F2DD99-6450-4838-98B8-2899E8EBC1A4/AlipayWallet.app/AlipayWallet for reading.
[+] Reading header
[+] Detecting header type
[+] Executable is a plain MACH-O image
[+] Opening AlipayWallet.decrypted for writing.
[+] Copying the not encrypted start of the file
[+] Dumping the decrypted data into the file
[+] Copying the not encrypted remainder of the file
[+] Setting the LC_ENCRYPTION_INFO->cryptid to 0 at offset d90
[+] Closing original file
[+] Closing dump file
  • 执行ls 找到 AlipayWallet.decrypted scp拷贝到电脑就可以
  • 接下来使用 class-dump 导出头文件到当前文件夹
    class-dump -H AlipayWallet.decrypted -o ./

分析和调试

  • 打开支付宝到蚂蚁森林界面 cycript -p AlipayWallet

  • 我们从UI入手 执行[[UIApp keyWindow]recursiveDescription] 看到 看来是H5的应用
    我们返回上面找控制器[#0x1386dc970 nextResponder] 看到 继续[#0x1378d6210 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"]
  • 我们来使用THEOS 自带的logify.pl 生成H5WebViewController的全部方法调用和参数日志
/opt/theos/bin/logify.pl H5WebViewController.h >Tweak.xm

编译 Tweak.xm 注意:有编译出错 有些类和代理block是不认识的 出错的删掉就可以
CDUnknownBlockType 作参数的可以替换成 id 继承于 DTViewController 替换成

安装之后 手机连上我们电脑 打开xcode -菜单Window-Devices-Simulators

我们点击那个能量按钮收取别人的能量看看

iOS逆向-手把手教你写支付宝蚂蚁森林收集能量助手_第2张图片

  • 接下来我们使用xcode 自带的lldb来调试支付宝(默认xcode无法调试第三方应用)我们接下来给app加个权限
    没权限提示
Ensure “AlipayWallet” is not already running, and cardlan_yuhuajun has permission to debug it.

注意:要使用脱壳之后的AlipayWallet执行下面的命令,也就是AlipayWallet.decrypted 重命名为AlipayWallet(否则闪退)

将应用程序从设备上拷贝到本地
利用 ldid 将应用程序的 code sign 导出:ldid -e AlipayWallet >> AlipayWallet.xml
在 AlipayWallet.xml 文件中添加 get-task-allow 权限  
 <key>get-task-allow</key> <true/>

利用 ldid 对应用进行重签名 ldid -SAlipayWallet.xml ./AlipayWallet
将应用拷回设备,将设置可执行权限 chmod 755 AlipayWallet
完成

(图3)
iOS逆向-手把手教你写支付宝蚂蚁森林收集能量助手_第3张图片

ps:如果如上操作还闪退 请重启iphone

  • 然后我们连上手机 xcode 随便弄个工程 选择iphone 看图来开始附加AlipayWallet(图4) 点到森林界面点击xcode自带的看界面工具 然后再xcode 右下角自带的lldb 下断点
    我们先试着下断函数

    iOS逆向-手把手教你写支付宝蚂蚁森林收集能量助手_第4张图片

b -[H5WebViewController reportClickTime]

提示找不到no locations 我们随便找个地址 看看堆栈信息

po [H5WebViewController _shortMethodDescription] 

找一个地址

b 0x1057daab0

重开页面 触发断点 ,点开xcode的堆栈窗口如(图5)

iOS逆向-手把手教你写支付宝蚂蚁森林收集能量助手_第5张图片

发现很多地址是没函数名的 当然也无法直接对函数名下断点 我们借用大神写的工具来恢复这些信息 文章链接如下
http://www.jianshu.com/p/967b6631756c
之后 再附加一下
下这个断点

b -[H5WebViewController reportClickTime]

发现是可以成功下断了 继续查看堆栈信息 现在函数名全部全了

(图6)
iOS逆向-手把手教你写支付宝蚂蚁森林收集能量助手_第6张图片

往上回溯 思路 因为我们想找到是js过来的参数和调用原生方法是哪里过来的
毕竟 reportClickTime 不是我们要分析的

看到PSDJsBride 调用了很多次 而且看参数和函数名 很有可能 中转了消息和参数 为了验证我们的猜想 ,我们使用logify.pl 来生成tweak 打印他全部的调用日志
安装到手机之后,我们取消断电 打开xcode的日志看打印 有没有敏感的信息调用

br delete

点击好友的那个能量收取 把日志全部copy 到Sublime text

看图(7)
iOS逆向-手把手教你写支付宝蚂蚁森林收集能量助手_第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]

我们执行 看看日志打印 有日志输出 看recv这些参数 和刚刚是有点差别 但是大致一样(这个能量只能收一次)来看bubbleId 这个猜一下是能量的ID

  • 来找怎么获取的能量ID 我们打开一个有能量的好友,看日志 有获取的调用没
    由于日志比较多 我们就是着重找有返回bubbleId和friedID 的列表,找到之后往上找调用着参数
[m -[0x14a1cbce0> 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;

结果有了 找调用

_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]

用cycript 测试这个方法 。结果如我们所愿 日志返回了我们需要的能量ID和好友ID 可以构造第一个找到那个方法 实现收一个好友的能量
- 由于这个方法需要好友ID的参数 我们需要拿到全部好友的ID 这样才能实现我们的一键全部收取
- 这里我偷个懒 不去往下折腾 点击页面在PSDJsBridge transformResponseData
取top 10的好友ID(打开页面他本身执行了 friendRanking系列方法 )

编写Tweak

  • 整理下流程,进页面 他自身调用Top10的好友列表 我们拿到这10个用户的UID
  • 拿到UID之后执行上面分析的第二个方法 拿到指定用户可以收的能量 collectStatus=AVAILABLE 返回参数中有 我们看字段就能猜到
  • 拿到UID和能量ID 我们就可以执行收能量的功能了
  • 具体的代码不一一分析 下面会提供代码下载地址
    看成功图8
    iOS逆向-手把手教你写支付宝蚂蚁森林收集能量助手_第8张图片

总结

  • UIWebView的应用不同于原生的应用 有正向开发经验能通过UI层能轻易找到触发事件

  • 其实很多时候都在试错和猜想 ,逐步的去验证自己的猜想 直到找到答案

  • 这个Tweak只作技术分析,并没有完善 Top10用户收取还不够用 大家可以试着动手 获取下一页好友 和全部好友 看日志找到字段是可以轻易实现的 还有其他功能比如 每天定时启动收取啥的

这是代码GitHub地址
https://github.com/hackxhj/alipayForestTweak.git
欢迎star

你可能感兴趣的:(IOS)