美文网首页
25-越狱调试

25-越狱调试

作者: 深圳_你要的昵称 | 来源:发表于2021-06-09 07:35 被阅读0次

    前言

    本篇文章给大家演示一下,如何在越狱机上进行第三方App的调试。期间会利用一些很常用的动态调试的工具,例如RevealCycriptlldb等。

    一、Reveal

    首先给大家介绍Reveal,它是一款UI调试神器,对iOS逆向开发非常有帮助。这里使用Version 4(8796)版本。

    Reveal官网直接下载安装,可以用试用版。

    1.1安装

    1.1.1 Mac端

    下载完成后,打开,输入邮箱,接收试用key👇🏻


    去到邮箱,接收并输入试用key👇🏻

    主界面👇🏻

    1.1.2 手机端

    打开Cydia,安装Reveal Loader插件👇🏻

    1.2 使用

    导入dylib文件
    1. 在手机上,进入/Library,创建RHRevealLoader目录
    mkdir RHRevealLoader
    
    1. 在Mac电脑上,打开Reveal👇🏻

    找到RevealServer路径

    1. 打开终端,将RevealServer拷贝到手机的/Library/RHRevealLoader目录下,重命名为libReveal.dylib
    scp -P 12345 ./RevealServer root@localhost:/Library/RHRevealLoader/libReveal.dylib
    
    开启允许调试的应用
    1. 打开设置,找到Reveal选项
    1. 开启允许调试的应用,例如WeChat
    使用Reveal进行UI调式
    1. 在Mac电脑上,打开Reveal软件。手机上重新启动WeChat

    2. 在电脑的Reveal中,出现两个WeChat,分别是WiFi连接和USB连接。

    1. 点击USB连接的WeChat,可进行UI调式,并且不会阻塞WeChat的进程

    至此,我们就能在上面很直接的看到微信的UI层级了,使用起来XCodeDebug View相似度很高。

    二、debugserver

    2.1 lldb附加

    接下来,我们看看在越狱环境中,是如何使用Xcode利用lldb进行进程附加的。

    1. 打开Xcode,随意打开一个项目,空工程也可以
    2. 选择真机调试,在Debug菜单中,选择Attach to Process,选择WeChat进程

    显示Running,表示附加成功👇🏻

    1. 使用lldb将应用暂停👇🏻
    1. 使用Debug View进行UI调试

    2.2 lldb原理

    上面之所以能通过lldb进行进程附加,调试手机中的应用,是因为手机中的debugserver开启了相关服务。

    1. Xcode中有lldb给手机中的debugserver发送指令。
    2. 手机中的debugserver会附加App,读App中的内容做一系列操作。
    3. debugserver将读取到的结果给到lldb显示。

    在越狱环境中,我们只需要开启debugserver服务,就可以利用lldb远程调试三方应用了。

    2.3 探索debugserver

    Mac端

    1. 找到Mac电脑中的debugserver,进入以下目录👇🏻
    /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/DeviceSupport
    
    1. 可以找到不同iOS系统版本,所对应的镜像文件👇🏻
    1. 进入设备对应的系统目录,找到dmg文件(我的设备是12.1.2版本)👇🏻
    1. 打开dmg文件,进入usr/bin目录可以看到debugserver。这就是Xcode安装到真机中的文件👇🏻

    手机端

    在手机系统中,也存在一个debugserver。当Xcode第一次连接手机,就会将对应版本的debugserver安装到手机系统中。

    进入手机的/Developer/usr/bin目录下👇🏻

    2.4 copy debugserver

    1. 手机中的debugserver拷贝到Mac电脑
    scp -P 12345 root@localhost:/Developer/usr/bin/debugserver ./
    
    1. 将拷贝后的debugserver生成md5值
    md5 debugserver
    
    1. 找到Mac电脑中的debugserver
    cd /Volumes/DeveloperDiskImage/usr/bin
    
    1. 将Mac电脑中的debugserver生成md5值
    md5 debugserver
    

    上图可见,手机端和Mac端的debugserver文件的Hash一致,说明手机中的debugserver就是Mac电脑中指定系统目录下的debugserver

    2.5 USB启动debugserver

    2.5.1 iPhone中开启debugserver服务

    Mac电脑中的lldb连接手机上的debugserver,需要配置IP和端口号

    在手机中,查看debugserver命令

    ./debugserver
    -------------------------
    debugserver-@(#)PROGRAM:LLDB  PROJECT:lldb-900.3.87
    for arm64.
    Usage:
     debugserver host:port [program-name program-arg1 program-arg2 ...]
     debugserver /path/file [program-name program-arg1 program-arg2 ...]
     debugserver host:port --attach=<pid>
     debugserver /path/file --attach=<pid>
     debugserver host:port --attach=<process_name>
     debugserver /path/file --attach=<process_name>
    

    debugserver 主机地址:端口号 –a 应用进程

    • 由于主机地址是当前手机,可以使用localhost代替
    • 端口号 👉🏻 启动server服务开放端口,让远程的lldb通过sever调试进程

    2.5.2 附加WeChat应用

    接下来,我们来使用手机上的debugserver,进行附加WeChat应用。

    1. 找到WeChat进程
    1. 使用debugserver附加WeChat应用

    遇到错误👇🏻

    Failed to get connection from a remote gdb process.
    

    解决方法 👉🏻 使用ldiddebugserver配置权限

    1. 进入手机中debugserver拷贝到Mac电脑的目录(上面执行过)
    2. 导出debugserver的权限
    ldid -e debugserver > debugserver.entitlements
    

    我导出来的entitlements中,有2个plist,因为在iOS 12之后debugserver包含两个架构arm64arm64e

    我们可以拆分架构生成重签对应架构的debugserver(当然不拆也没有问题,不拆plist中两份配置都要改,我选择的不拆)👇🏻

    lipo -thin arm64 debugserver  -output debugserver_arm64
    
    1. 删除三项权限👇🏻
      • seatbelt-profiles
      • com.apple.security.network.server
      • com.apple.security.network.client
    2. 添加四项权限👇🏻
       <key>task_for_pid-allow</key>
       <true/>
       <key>get-task-allow</key>
       <true/>
       <key>platform-application</key>
       <true/>
       <key>run-unsigned-code</key>
       <true/>
    

    那么,修改后的debugserver.entitlements文件👇🏻

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
    <plist version="1.0">
    <dict>
        <key>com.apple.springboard.debugapplications</key>
        <true/>
        <key>com.apple.backboardd.launchapplications</key>
        <true/>
        <key>com.apple.backboardd.debugapplications</key>
        <true/>
        <key>com.apple.frontboard.launchapplications</key>
        <true/>
        <key>com.apple.frontboard.debugapplications</key>
        <true/>
        <key>com.apple.diagnosticd.diagnostic</key>
        <true/>
        <key>com.apple.private.memorystatus</key>
        <true/>
        <key>com.apple.private.cs.debugger</key>
        <true/>
        <key>platform-application</key>
        <true/>
        <key>get-task-allow</key>
        <true/>
        <key>task_for_pid-allow</key>
        <true/>
        <key>run-unsigned-code</key>
        <true/>
        <key>com.apple.system-task-ports</key>
        <true/>
    </dict>
    </plist>
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
    <plist version="1.0">
    <dict>
        <key>com.apple.springboard.debugapplications</key>
        <true/>
        <key>com.apple.backboardd.launchapplications</key>
        <true/>
        <key>com.apple.backboardd.debugapplications</key>
        <true/>
        <key>com.apple.frontboard.launchapplications</key>
        <true/>
        <key>com.apple.frontboard.debugapplications</key>
        <true/>
        <key>com.apple.diagnosticd.diagnostic</key>
        <true/>
        <key>com.apple.private.memorystatus</key>
        <true/>
        <key>com.apple.private.cs.debugger</key>
        <true/>
        <key>platform-application</key>
        <true/>
        <key>get-task-allow</key>
        <true/>
        <key>task_for_pid-allow</key>
        <true/>
        <key>run-unsigned-code</key>
        <true/>
        <key>com.apple.system-task-ports</key>
        <true/>
    </dict>
    </plist>
    
    1. 导入权限文件到debugserver
    ldid -Sdebugserver.entitlements debugserver
    

    回到之前的附加流程👇🏻

    1. 接下来就是将debugserver拷贝回手机

    ⚠️注意:手机中的/Developer/usr/bin目录,有权限问题,不能直接拷贝。

    那么,就拷贝到手机的/usr/bin目录,拷贝后可全局使用👇🏻

    scp -P 12345 ./debugserver root@localhost:/usr/bin/debugserver
    
    1. 接着,在手机端上找到WeChat进程👇🏻
    ps -A | grep WeChat
    
    1. 最后,使用debugserver,再次附加WeChat应用👇🏻
    debugserver localhost:12346 -a 11656
    -------------------------
    debugserver-@(#)PROGRAM:LLDB  PROJECT:lldb-900.3.87
    for arm64.
    Attaching to process 11656...
    Listening to port 12346 for a connection from localhost...
    
    1. 使用lldb连接debugserver
    • 在Mac电脑上,进入lldb环境
    lldb
    
    • 连接debugserver
    process connect connect://10.165.45.19:12346
    

    错误 👉🏻 error: Failed to connect port
    我们使用USB端口映射,修改usbConnect.sh脚本,增加12346的端口映射

    python /Users/aronm1/python-client/tcprelay.py -t 22:12345 12346:12346
    

    使用USB连接

    1. 手机上使用debugserver,附加WeChat应用
    ./debugserver localhost:12346 -a 11733
    

    再一次,Mac电脑上,进入lldb环境

    lldb
    

    使用lldb连接debugserver

    process connect connect://localhost:12346
    -------------------------
    Process 11733 stopped
    * thread #1, queue = 'com.apple.main-thread', stop reason = signal SIGSTOP
       frame #0: 0x00000001a3e740f4 libsystem_kernel.dylib`mach_msg_trap + 8
    libsystem_kernel.dylib`mach_msg_trap:
    ->  0x1a3e740f4 <+8>: ret
    
    libsystem_kernel.dylib`mach_msg_overwrite_trap:
       0x1a3e740f8 <+0>: mov    x16, #-0x20
       0x1a3e740fc <+4>: svc    #0x80
       0x1a3e74100 <+8>: ret
    Target 0: (WeChat) stopped.
    

    连接成功,输入c,继续运行

    c
    -------------------------
    Process 11733 resuming
    

    输入process interrupt,暂停

    process interrupt
    

    使用command + w停止WeChat附加,但不杀掉应用

    三、class-dump

    class-dump之前文章就使用过了,它是一个命令行工具,最高版本为class-dump 3.5 (64 bit),已经停止更新

    查看class-dump的路径👇🏻

    which class-dump
    

    上图可见,来自MonkeyDev框架。

    3.1 class-dump的使用

    在MonkeyDev中,class-dump如何使用?

    1. 搭建MonkeyDev项目
    2. Build Settings中,将MONKEYDEV_CLASS_DUMP默认的NO修改为YES
    1. 编译项目,主工程下生成Headers目录,自动导出头文件(以微信为例)

    ⚠️注意:工程目录下不要包含中文,否则Headers目录以及头文件无法生成。

    四、命令行工具

    接下来,给大家演示一下 👉🏻 搭建自定义的命令行工具。

    1. 创建App项目,命名FuncDemo
    2. 打开main.m文件,写入以下代码👇🏻
    #import <UIKit/UIKit.h>
    #import "AppDelegate.h"
    
    int main(int argc, char * argv[]) {
       
       for (int intIndex=0; intIndex<argc; intIndex++) {
           printf("参数%i:%s\n",intIndex, argv[intIndex]);
       }
       
       return 0;
    }
    
    1. 编译项目,将MachO文件拷贝到手机上

    需要将MachO文件copy出来

    scp -P 12345 ./FuncDemo root@localhost:~/
    
    1. USB连接手机设备
    usb-iphone8.sh
    
    1. 使用自定义命令行工具
    ./FuncDemo -v
    -------------------------
    参数0:./FuncDemo
    参数1:-v
    

    上图可见,参数0为默认,显示当前MachO

    五、lldb手动砸壳

    砸壳之前讲过,有很多方式可以进行。逆向分析一个应用,第一步就是对应用砸壳
    例如,查看WeChatcrypt信息👇🏻

    otool -l WeChat | grep crypt
    -------------------------
         cryptoff 16384
        cryptsize 187236352
          cryptid 1
    
    • cryptid 👉🏻 为0表示应用已砸壳
    • cryptoff 👉🏻 表示开始加密的偏移位置
    • cryptsize 👉🏻 表示加密长度

    将应用砸壳后,才能使用class-dump导出头文件。

    5.1 查看手机中的MachO

    1. USB连接手机设备,找到WeChat沙盒路径
    ps -A | grep WeChat
    -------------------------
    11783 ??         0:52.19 /var/containers/Bundle/Application/B9046860-DDDA-44B4-AFF5-AF20FFA6FC9D/WeChat.app/WeChat
    
    1. WeChat拷贝到Mac电脑
    scp -P 12345 root@localhost:/var/containers/Bundle/Application/B9046860-DDDA-44B4-AFF5-AF20FFA6FC9D/WeChat.app/WeChat ./
    
    1. 查看MachO文件中的crypt信息
    otool -l WeChat | grep crypt
    

    5.2 方式一:修改cryptid砸壳

    1. 使用MachOView打开WeChat

    2. Load Commands中,找到LC_ENCRYPTION_INFO_64,修改Crypt ID为0

    1. 使用class-dump导出头文件
    class-dump -H WeChat -o ./header
    

    ⚠️注意:建议千万别试,会不停的循环输出乱码

    所以,仅修改cryptid,无法导出头文件。因此砸壳的关键,并不是cryptid,而是将加密的代码段进行解密

    5.3 方式二:lldb手动砸壳

    接下来,我们尝试lldb手动砸壳,我们知道 👇🏻

    砸壳的逻辑,是从内存中读取cryptoff位置cryptsize长度的数据,然后将其覆盖原始MachO文件。

    1. 使用Xcode打开工程,选择真机设备,附加WeChat进程
    2. image list获取MachO的首地址
    (lldb) image list
    [  0] EB606691-98E6-384F-BABB-F46E7BC265F9 0x0000000102378000 /var/containers/Bundle/Application/B9046860-DDDA-44B4-AFF5-AF20FFA6FC9D/WeChat.app/WeChat (0x0000000102378000)
    

    首地址是 👉🏻 0x0000000102378000

    1. 从内存中,将加密部分的代码段,导出到WeChat.bin文件。因为已读取到内存中,相当于已解密。
    memory read --force --outfile ~/Downloads/WeChat.bin --binary --count 187236352 0x0000000102378000+16384
    

    代码段加密的开始位置 👉🏻 MachO首地址 + 加密偏移地址

    1. WeChat.bin文件,复制到WeChatMachO文件相同的目录,然后将其写入到MachO文件中相同位置,相当于用解密后的数据,覆盖原始的加密数据
    dd seek=16384 bs=1 conv=notrunc if=./WeChat.bin of=WeChat
    
    • seek 👉🏻 从输出文件开头跳过x个块后再开始复制
    • bs 👉🏻 同时设置读入/输出的块大小为x个字节
    • conv=notrunc 👉🏻 不截断输出文件
    • if 👉🏻 输入文件名,默认为标准输入。即指定源文件
    • of 👉🏻 输出文件名,默认为标准输出。即指定目的文件

    耗时比较久,共计500多秒。接着对WeChatMachO文件的cryptid修改为0,可以成功导出头文件👇🏻

    六、Tweak屏蔽Badge红点气泡

    接下来,我们创建Tweak插件,来屏蔽应用的红点气泡👇🏻

    实现该功能的前提是需要附加系统的桌面程序SpringBoard

    1. USB连接手机,找到SpringBoard进程
    1. SpringBoard拷贝到Mac电脑
    scp -P 12345 root@127.0.0.1:/System/Library/CoreServices/SpringBoard.app/SpringBoard ./
    
    1. 查看SpringBoardMachO文件中的crypt信息

    上图可见,MachO中没有加密信息,说明SpringBoard原本就没有加壳

    1. 既然没有加壳,我们尝试使用class-dump导出头文件
    class-dump -H SpringBoard -o ./header
    

    果然,可以dump出头文件,所以SpringBoard没有加壳的。

    1. 动态调试,定位找出红点气泡相关的类。
      现在我们已知的动态调试有3种方式👇🏻
    • Reveal 👉🏻 SpringBoard无法显示在Mac端的Reveal客户端中,不可用!
    • Cycript 👉🏻 采用附加SpringBoard进程的方式,然后通过cy指令查找定位红点UI,需要手动搜索,很不直观,不建议使用!
    • lldb 👉🏻 使用lldb附加SpringBoard进程,然后通过Debug View找到红点对象,很直接,建议使用!

    我们定位到红点对象的类 👉🏻 SBIconParallaxBadgeView

    1. 验证是否为 SBIconParallaxBadgeView
    • usb连接手机,进入cy环境
    • 导入自定义cy脚本
    • 打印当前vc视图层级
    cy# currentVC()
    #"<SBHomeScreenViewController: 0x10329c780>"
    cy# #0x10329c780.view.recursiveDescription().toString()
    
    • 在结果中搜索SBIconParallaxBadgeView

    结果只有1处,因为当前页面只有一处红点气泡。

    <SBIconParallaxBadgeView: 0x112192f20; frame = (45 -11; 26 26); animations = { <UIInterpolatingMotionEffect: 0x283402300>=<CABasicAnimation: 0x281749280>; <UIInterpolatingMotionEffect: 0x2834065d0>=<CABasicAnimation: 0x28174aca0>; }; layer = <CALayer: 0x2816ba7e0>>\n
    
    • 将其设置为隐藏
    #0x112192f20.hidden=YES
    

    然后手机上的红点气泡没了👇🏻

    1. 接下来我们通过Hook的方式,实现隐藏气泡
    • 在导出的头文件中,找到SBIconParallaxBadgeView.h文件
    • SBIconParallaxBadgeViewinit方法进行HOOK,破坏它,即可隐藏红点气泡

    七、Tweak插件实现隐藏气泡

    要实现对SBIconParallaxBadgeViewinit方法进行HOOK,需要搭建Tweak插件。

    1. 使用nic.pl→15,创建Tweak插件
    1. Makefile文件中,增加IP和端口

    小技巧:配置到环境变量,一劳永逸。

    vim ~/.zshrc
    export THEOS_DEVICE_IP=localhost
    export THEOS_DEVICE_PORT=12345
    source ~/.zshrc
    
    1. 打开Tweak.x文件,写入以下代码👇🏻
    %hook SBIconParallaxBadgeView
    
    - (id)init {
      return nil;
    }
    
    %end
    
    1. 编译、打包、安装插件
     cd badgedemo
    make
    
    make package;make install
    

    ⚠️注意:安装这一步需要USB连接手机设备!

    安装完成后,手机会重启桌面,再次进入桌面时,气泡全部消失。同时,在Cydia中会显示已安装的BadgeDemo插件👇🏻

    八、MonkeyDev搭建Tweak插件

    最后,我们使用MonkeyDev插件,来创建Tweak插件

    1. 新建Logos Tweak项目

    项目名称 👉🏻 BadgeMonkeyDemo

    1. 项目结构
    • BadgeMonkeyDemo.xm 👉🏻 代码
    • control 👉🏻 配置信息,版本号、作者名称等
    • BadgeMonkeyDemo.plist 👉🏻 附加应用的包名称等信息
    1. Build Settings中,搜索Monkey,找到Tweak的设置👇🏻

    有以下自定义的配置项👇🏻

    • MonkeyDevBuildPackageOnAnyBuild 👉🏻 每次编译时打包
    • MonkeyDevClearUiCacheOnInstall 👉🏻 安装时清除缓存
    • MonkeyDevCopyOnBuild 👉🏻 编译时拷贝包到目录
    • MonkeyDevDeviceIP 👉🏻 设备IP
    • MonkeyDevDevicePassword 👉🏻 设备密码
    • MonkeyDevDevicePort 👉🏻 设备端口
    • MonkeyDevInstallOnAnyBuild 👉🏻 每次编译时安装
    • MonkeyDevkillProcessOnInstall 👉🏻 安装成功后杀掉的进程
    1. 和写Tweak插件时一样,设置IP和端口,同样将这两项配置在环境变量中👇🏻
    export MonkeyDevDeviceIP=localhost
    export MonkeyDevDevicePort=12345
    
    1. 同样,打开BadgeTweakDemo.xm文件,写入以下代码👇🏻
    #import <UIKit/UIKit.h>
    
    %hook SBIconParallaxBadgeView
    
    - (id)init {
       return nil;
    }
    
    %end
    
    1. Build Settings中,搜索signing设置签名

    Code Signing Identity设置为iOS Developer 👇🏻

    1. 编译项目

    如果报错👇🏻

    解决 👉🏻 按目录找到CydiaSubstrate.tbd文件,删除里面的i386和x86_64👇🏻

    再次run项目,成功安装Tweak插件,红点气泡全部隐藏。

    总结

    • Reveal

      • iOS安装插件
      • Mac安装客户端App
      • 将动态库导入iPhone
    • USB启动debugserver

      • 终端附加
        ◦ 手机,使用debugserver 主机名称:端口 -a 进程id
        Mac电脑,启动lldb,使用process connect connect://主机名称:端口
        USB端口映射

      • Xcode附加
        ◦ 打开工程
        ◦ 选择设备
        ◦ 附加进程(菜单栏Debug->Attach to process ->选择进程)

    • debugserver权限问题

      • 导出权限文件,查看文件
        ldid -e debugserver > debugserver.entitlements
      • 删除权限
        seatbelt-profiles
        com.apple.security.network.server
        com.apple.security.network.client
      • 添加权限
        task_for_pid-allow设置为YES
        get-task-allow设置为YES
        platform-application设置为YES
        run-unsigned-code设置为YES
      • 导入权限文件
        ldid -Sdebugserver.entitlements debugserver
    • class-dump

      • class-dump -H MachO文件路径 -o 头文件路径
      • MonkeyDev中,可以快速使用class-dump
    • 命令行工具

      • argc:参数个数
      • argv:参数数组
    • lldb手动砸壳

      • memory read命令
        ◦ 通过--outfile参数,导出文件
        ◦ 通过--count参数,指定导出的大小
      • dd命令
        ◦ 写入源文件
        seek指定偏移,也就是跳过多少开始写入
        conv保留没有替换的部分
    • Tweak修改系统行为

      • Reveal无法使用,在手机设置页的Reveal选项中,没有SpringBoard应用
      • Cycript可以使用,但定位UI不直观
      • lldb可以使用,最简单的方式
    • MonkeyDev搭建Tweak插件

      • Build Settings中,配置参数
      • 设置签名
      • 编译项目并安装插件

    相关文章

      网友评论

          本文标题:25-越狱调试

          本文链接:https://www.haomeiwen.com/subject/zfzkeltx.html