25-越狱调试

前言

本篇文章给大家演示一下,如何在越狱机上进行第三方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=
 debugserver /path/file --attach=
 debugserver host:port --attach=
 debugserver /path/file --attach=

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. 添加四项权限
   task_for_pid-allow
   
   get-task-allow
   
   platform-application
   
   run-unsigned-code
   

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





    com.apple.springboard.debugapplications
    
    com.apple.backboardd.launchapplications
    
    com.apple.backboardd.debugapplications
    
    com.apple.frontboard.launchapplications
    
    com.apple.frontboard.debugapplications
    
    com.apple.diagnosticd.diagnostic
    
    com.apple.private.memorystatus
    
    com.apple.private.cs.debugger
    
    platform-application
    
    get-task-allow
    
    task_for_pid-allow
    
    run-unsigned-code
    
    com.apple.system-task-ports
    






    com.apple.springboard.debugapplications
    
    com.apple.backboardd.launchapplications
    
    com.apple.backboardd.debugapplications
    
    com.apple.frontboard.launchapplications
    
    com.apple.frontboard.debugapplications
    
    com.apple.diagnosticd.diagnostic
    
    com.apple.private.memorystatus
    
    com.apple.private.cs.debugger
    
    platform-application
    
    get-task-allow
    
    task_for_pid-allow
    
    run-unsigned-code
    
    com.apple.system-task-ports
    


  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 
#import "AppDelegate.h"

int main(int argc, char * argv[]) {
   
   for (int intIndex=0; intIndex
  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
  • cryptid0表示应用已砸壳
  • 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 [email protected]:/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()
#""
cy# #0x10329c780.view.recursiveDescription().toString()
  • 在结果中搜索SBIconParallaxBadgeView

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

=; =; }; layer = >\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 

%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-越狱调试)