iOS逆向实战--031:越狱调试

调试一款应用,使用重签名方案,很容易被第三方察觉。在越狱环境中,我们可以在不污染App的情况下,对第三方程序进行动态调试。

Reveal

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

Mac电脑中,安装Reveal软件

在手机中,安装Reveal插件

打开Cydia,安装Reveal Loader插件

导入dylib文件

在手机上,进入/Library,创建RHRevealLoader目录

mkdir RHRevealLoader

Mac电脑上,打开Reveal,找到iOS Library选项

找到RevealServer路径

打开终端,将RevealServer拷贝到手机的/Library/RHRevealLoader目录下,重命名为libReveal.dylib

scp -P 12345 ./RevealServer root@localhost:/Library/RHRevealLoader/libReveal.dylib
-------------------------
RevealServer                                                                                                                           100% 9100KB  35.5MB/s   00:00

开启允许调试的应用

打开设置,找到Reveal选项

开启允许调试的应用,例如WeChat

使用Reveal进行UI调式

Mac电脑上,打开Reveal软件。手机上,重新启动WeChat

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

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

debugserver

在越狱环境中,使用Xcode进行lldb附加

打开Xcode,随意打开一个项目,空工程也可以

选择真机,在Debug菜单中,选择Attach to Process,选择WeChat进程

显示Running,表示附加成功

使用lldb将应用暂停

使用Debug View进行UI调试

lldb原理

Xcode中的lldb可以调试手机中的应用,是因为手机中的debugserver开启了相关服务

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

探索debugserver

找到Mac电脑中的debugserver,进入以下目录:

/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/DeviceSupport

可以找到不同iOS系统版本,所对应的镜像文件

进入设备对应的系统目录,找到dmg文件

打开dmg文件,进入usr/bin目录可以看到debugserver。这就是Xcode安装到真机中的文件

手机设备中的debugserver

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

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

将手机中的debugserver拷贝到Mac电脑中

scp -P 12345 root@localhost:/Developer/usr/bin/debugserver ./
-------------------------
debugserver                                   100% 9505KB  33.8MB/s   00:00

将拷贝后的debugserver生成md5

md5 debugserver
-------------------------
MD5 (debugserver) = b771aad8917de2ff41feb5acfe4a9b15

找到Mac电脑中的debugserver

cd /Volumes/DeveloperDiskImage/usr/bin

Mac电脑中的debugserver生成md5

md5 debugserver
-------------------------
MD5 (debugserver) = b771aad8917de2ff41feb5acfe4a9b15

两个文件的Hash一致,说明手机中的debugserver,就是Mac电脑中指定系统目录下的debugserver

USB启动debugserver

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调试进程

使用手机上的debugserver,附加WeChat应用

找到WeChat进程

9651 ??         0:08.88 /var/containers/Bundle/Application/454EA887-EB3B-43B3-ABFD-B9B2CA006981/WeChat.app/WeChat

使用debugserver附加WeChat应用

./debugserver localhost:12346 -a 9651
-------------------------
debugserver-@(#)PROGRAM:LLDB  PROJECT:lldb-900.3.87
for arm64.
Attaching to process 9651...
Listening to port 12346 for a connection from localhost...
Failed to get connection from a remote gdb process.
Exiting.

遇到错误:Failed to get connection from a remote gdb process.

解决办法:使用ldiddebugserver配置权限

进入手机中debugserver拷贝到Mac电脑的目录

导出debugserver的权限

ldid -e debugserver > debugserver.entitlements

删除三项权限

seatbelt-profiles
com.apple.security.network.server
com.apple.security.network.client

添加四项权限

   <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文件

导入权限文件到debugserver

ldid -Sdebugserver.entitlements debugserver

手机中的/Developer/usr/bin目录,有权限问题,不能直接拷贝

debugserver拷贝到手机的/usr/bin目录,拷贝后可全局使用

scp -P 12345 ./debugserver root@localhost:/usr/bin/debugserver
-------------------------
debugserver                                   100% 9544KB  35.9MB/s   00:00

找到WeChat进程

ps -A | grep WeChat
-------------------------
9727 ??         0:07.27 /var/containers/Bundle/Application/454EA887-EB3B-43B3-ABFD-B9B2CA006981/WeChat.app/WeChat

使用debugserver,附加WeChat应用

debugserver localhost:12346 -a 9727
-------------------------
debugserver-@(#)PROGRAM:LLDB  PROJECT:lldb-900.3.87
for arm64.
Attaching to process 9727...
Listening to port 12346 for a connection from localhost...

使用lldb连接debugserver

Mac电脑上,进入lldb环境

lldb

连接debugserver

process connect connect://10.165.45.19:12346

遇到错误:error: Failed to connect port

解决办法:使用USB端口映射

修改usbConnect.sh脚本

python /Users/zang/Zang/Tools/python-client/tcprelay.py -t 22:12345 12346:12346
  • 增加12346的端口映射

使用USB连接

usbConnect.sh
-------------------------
Forwarding local port 12345 to remote port 22
Forwarding local port 12346 to remote port 12346

手机上,使用debugserver,附加WeChat应用

./debugserver localhost:12346 -a 9727

Mac电脑上,进入lldb环境

lldb

使用lldb连接debugserver

process connect connect://localhost:12346
-------------------------
Process 9752 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 9752 resuming

输入process interrupt,暂停

process interrupt

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

class-dump

class-dump是一个命令行工具,最高版本为class-dump 3.5 (64 bit),已经停止更新

查看class-dump的路径

which class-dump
-------------------------
/Users/zang/Zang/Tools/MonkeyDev/bin/class-dump
  • 来自MonkeyDev框架

MonkeyDev中,class-dump的使用

搭建MonkeyDev项目

Build Settings中,将MONKEYDEV_CLASS_DUMP默认为NO

将其修改为YES

编译项目,主工程下生成Headers目录,自动导出头文件

工程目录下不要包含中文,否则Headers目录以及头文件无法生成

命令行工具

搭建自定义的命令行工具

创建App项目,命名FuncDemo

打开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;
}
  • argc:参数个数
  • argv:参数数组

编译项目,将MachO文件,拷贝到手机上

scp -P 12345 ./FuncDemo root@localhost:~/
-------------------------
FuncDemo                                    100%  150KB   5.9MB/s   00:00

USB连接手机设备

usb-6p.sh

使用自定义命令行工具

./FuncDemo -v
-------------------------
参数0:./FuncDemo
参数1:-v
  • 参数0为默认,显示当前MachO
lldb手动砸壳

逆向分析一个应用,第一步就是应用砸壳

查看MachO文件中的crypt信息

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

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

查看加壳的MachO文件

USB连接手机设备,找到WeChat的沙盒路径

ps -A | grep WeChat
-------------------------
9806 ??         0:03.88 /var/containers/Bundle/Application/454EA887-EB3B-43B3-ABFD-B9B2CA006981/WeChat.app/WeChat

WeChat拷贝到Mac电脑

scp -P 12345 root@localhost:/var/containers/Bundle/Application/454EA887-EB3B-43B3-ABFD-B9B2CA006981/WeChat.app/WeChat ./
-------------------------
WeChat                                        100%  184MB  39.0MB/s   00:04

查看MachO文件中的crypt信息

otool -l WeChat | grep crypt
-------------------------
    cryptoff 16384
   cryptsize 154255360
     cryptid 1

尝试不砸壳,只修改cryptid,能否使用class-dump导出头文件

使用MachOView打开WeChat

Load Commands中,找到LC_ENCRYPTION_INFO_64,修改Crypt ID0

使用class-dump导出头文件

class-dump -H WeChat -o ./header
-------------------------
2021-05-31 17:59:37.344 class-dump[70836:43071318] Warning: Parsing method types failed, ¨
...

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

使用lldb手动砸壳

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

使用Xcode打开工程,选择设备,附加WeChat进程

获取MachO的首地址

image list
-------------------------
[  0] 2B07ABCB-9885-3FF1-943C-B88A763C03C5 0x00000001008e0000 /var/containers/Bundle/Application/454EA887-EB3B-43B3-ABFD-B9B2CA006981/WeChat.app/WeChat (0x00000001008e0000)
...
  • MachO首地址为0x1008e0000

从内存中,将加密部分的代码段,导出到WeChat.bin文件。因为已读取到内存中,相当于已解密

memory read --force --outfile ~/Downloads/WeChat.bin --binary --count 154255360 0x00000001008e0000+16384
-------------------------
154255360 bytes written to '/Users/zang/Downloads/WeChat.bin'
  • 代码段加密的开始位置:MachO首地址 + 加密偏移地址

WeChat.bin文件,写入到MachO文件中相同位置,相当于用解密后的数据,覆盖原始的加密数据

dd seek=16384 bs=1 conv=notrunc if=./WeChat.bin of=WeChat
-------------------------
154255360+0 records in
154255360+0 records out
154255360 bytes transferred in 768.025931 secs (200847 bytes/sec)
  • seek:从输出文件开头跳过x个块后再开始复制
  • bs:同时设置读入/输出的块大小为x个字节
  • conv=notrunc:不截断输出文件
  • if:输入文件名,默认为标准输入。即指定源文件
  • of:输出文件名,默认为标准输出。即指定目的文件

文件写入成功,将MachO文件的cryptid修改为0,成功导出头文件

Tweak修改系统行为

搭建Tweak插件,屏蔽应用的红点气泡

屏蔽应用的红点气泡,需要附加的应用是系统的桌面程序SpringBoard

USB连接手机,找到SpringBoard进程

ps -A | grep SpringBoard
-------------------------
10262 ??         0:10.04 /System/Library/CoreServices/SpringBoard.app/SpringBoard

SpringBoard拷贝到Mac电脑

scp -P 12345 root@127.0.0.1:/System/Library/CoreServices/SpringBoard.app/SpringBoard ./
-------------------------
SpringBoard                                   100% 7374KB  38.9MB/s   00:00

查看MachO文件中的crypt信息

otool -l SpringBoard | grep crypt
-------------------------

  • MachO中找不到加密信息,说明SpringBoard原本就没有加壳

使用class-dump导出头文件

class-dump -H SpringBoard -o ./header

成功导出SpringBoard应用的头文件

动态调试

我们可以使用的动态调试工具有三种:

  • Reveal
  • Cycript
  • lldb

使用Reveal无法动态调试,因为在手机设置页的Reveal选项中,并没有SpringBoard应用

使用Cycript,可以成功附加SpringBoard进程,但定位红点UI,并不直观

最简单的方式,使用lldb附加SpringBoard进程,通过Debug View找到红点对象

  • 红点对象:SBIconParallaxBadgeView

cy环境中验证

导入自定义cy脚本

@import com.zang.cur_vc
currentVC()
#0x10145e3a0.view.recursiveDescription() .toString ()

在结果中搜索SBIconParallaxBadgeView

3个红点,刚好对应3个控件

选择其中一个对象,将其设置为隐藏

#0x10a623710.hidden=YES

App Store上的红点被成功隐藏

在导出的头文件中,找到SBIconParallaxBadgeView.h文件

  • SBIconParallaxBadgeView进行HOOK,破坏它的init方法,即可隐藏红点气泡

搭建Tweak插件

使用nic.pl15,创建Tweak插件

Makefile文件中,增加IP和端口

为了一劳永逸,将这两项配置在环境变量中

vim ~/.zshrc
export THEOS_DEVICE_IP=localhost
export THEOS_DEVICE_PORT=12345

打开Tweak.x文件,写入以下代码:

%hook SBIconParallaxBadgeView

- (id)init {
  return nil;
}

%end

编译、打包、安装插件

cd reddemo
make
make package;make install

成功安装Tweak插件,红点气泡全部隐藏

MonkeyDev搭建Tweak插件

使用MonkeyDev创建Tweak插件

项目命名:BadgeTweakDemo

  • BadgeTweakDemo.xm:代码
  • control:配置信息,版本号、作者名称等
  • BadgeTweakDemo.plist:附加应用的包名称

Build Settings中,搜索Monkey,找到Tweak的设置

  • MonkeyDevBuildPackageOnAnyBuild:每次编译时打包
  • MonkeyDevClearUiCacheOnInstall:安装时清除缓存
  • MonkeyDevCopyOnBuild:编译时拷贝包到目录
  • MonkeyDevDeviceIP:设备IP
  • MonkeyDevDevicePassword:设备密码
  • MonkeyDevDevicePort:设备端口
  • MonkeyDevInstallOnAnyBuild:每次编译时安装
  • MonkeyDevkillProcessOnInstall:安装成功后杀掉的进程

设置IP和端口,同样将这两项配置在环境变量中

vim ~/.zshrc
export MonkeyDevDeviceIP=localhost
export MonkeyDevDevicePort=12345

打开BadgeTweakDemo.xm文件,写入以下代码:

#import <UIKit/UIKit.h>

%hook SBIconParallaxBadgeView

- (id)init {
   return nil;
}

%end

Build Settings中,搜索signing,设置签名

  • Code Signing Identity:设置为iOS Developer

编译项目时,如果遇到CydiaSubstrate.tbdbuilt for iOS Simulatorfor architecture arm64问题,按目录找到CydiaSubstrate.tbd文件,删除里面的i386x86_64

编译项目,成功安装Tweak插件,红点气泡全部隐藏

总结

Reveal

  • iOS安装插件
  • Mac安装App
  • 将动态库导入iPhone

USB启动debugserver

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

  • Xcode附加
    ◦ 打开工程
    ◦ 选择设备
    ◦ 附加进程

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参数,导出文件。lldb的环境在Mac
    ◦ 通过--count参数,指定导出的大小

  • dd命令
    ◦ 写入源文件
    seek指定偏移,也就是跳过多少开始写入
    conv保留没有替换的部分

Tweak修改系统行为

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

MonkeyDev搭建Tweak插件

  • Build Settings中,配置参数
  • 设置签名
  • 编译项目并安装插件
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,332评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,508评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,812评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,607评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,728评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,919评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,071评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,802评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,256评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,576评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,712评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,389评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,032评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,798评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,026评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,473评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,606评论 2 350

推荐阅读更多精彩内容