调试一款应用,使用重签名方案,很容易被第三方察觉。在越狱环境中,我们可以在不污染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
选项
开启允许调试的应用,例如
使用
Reveal
进行UI
调式在
Mac
电脑上,打开Reveal
软件。手机上,重新启动在电脑的
Reveal
中,出现两个WiFi
连接和USB
连接
点击
USB
连接的UI
调式,并且不会阻塞
debugserver
在越狱环境中,使用
Xcode
进行lldb
附加打开
Xcode
,随意打开一个项目,空工程也可以选择真机,在
Debug
菜单中,选择Attach to Process
,选择
显示
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
,附加找到
9651 ?? 0:08.88 /var/containers/Bundle/Application/454EA887-EB3B-43B3-ABFD-B9B2CA006981/WeChat.app/WeChat
使用
debugserver
附加./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.
解决办法:使用
ldid
对debugserver
配置权限进入手机中
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
找到
ps -A | grep WeChat ------------------------- 9727 ?? 0:07.27 /var/containers/Bundle/Application/454EA887-EB3B-43B3-ABFD-B9B2CA006981/WeChat.app/WeChat
使用
debugserver
,附加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
,附加./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
,停止
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
连接手机设备,找到ps -A | grep WeChat ------------------------- 9806 ?? 0:03.88 /var/containers/Bundle/Application/454EA887-EB3B-43B3-ABFD-B9B2CA006981/WeChat.app/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
打开在
Load Commands
中,找到LC_ENCRYPTION_INFO_64
,修改Crypt ID
为0
使用
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
打开工程,选择设备,附加获取
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.pl
→15
,创建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.tbd
的built for iOS Simulator
和for architecture arm64
问题,按目录找到CydiaSubstrate.tbd
文件,删除里面的i386
和x86_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
中,配置参数- 设置签名
- 编译项目并安装插件