利用Xcode在非越狱机器上动态调试第三方APP

0x00 问题起源

分析Office Lens和系统相机拍照时,发现物理设备旋转时,Office Lens和系统相机的statusbar方向会相应进行变化,但界面上相机控制区域元素又看不到明显变化,仿佛是界面没有进行方向变化一样,遂决定分析Lens和系统相机APP,查看其实现思路。

0x01 准备脱壳的ipa

App Store上的应用都使用了FairPlay DRM数字版权加密保护技术,动态调试之前需要先将其解密。

解密使用的工具:Clutch

Clutch: A high-speed iOS decryption tool.

Clutch解密原理,把应用运行时的内存数据按照一定格式导出。

Clutch是开源的,可以从github上免费获取。

1
2
源码 https://github.com/KJCracks/Clutch
编译好的可执行文件 https://github.com/KJCracks/Clutch/releases

解密步骤:

1. 准备一台越狱机器,并安装openSSH
2. 获取clutch可执行文件(从源码编译或者直接下载编译好的可执行文件)
3. 拷贝clutch可执行文件至越狱设备的/usr/bin/目录
1
scp /path/to/clutch root@<your.device.ip>:/usr/bin/
4. 导出脱壳IPA
1
2
3
ssh root@<your.device.ip>
clutch -i //列出设备上已安装APP
clutch -d [n] //解密,并导致IPA

解密成功后,clutch会提示解密后ipa文件的存放位置,整个过程如下图所示。
脱壳过程

5. 将解密后的ipa文件拷贝出来即可得到脱壳ipa
1
scp root@<your.device.ip>:/path/to/xx.ipa /User/xx/Desktop

0x02 新建一个同名空白工程

下面以动态调试Kindle为例来演示整个动态调试过程。

  1. 首先通过0x01获取脱壳的Kindle.ipa文件。
  2. 然后新建一个工程,名称Kindle(Bundle ID前缀任意),结构如下:

空白工程结构

0x03 添加自定义脚本

在Target “Kindle”的Build Phases里添加Run Script,

偷梁换柱脚本

该脚本实现偷梁换柱魔法

首先将第三方app拷贝替换我们新建工程生成的app

然后对第三方app使用我们的证书进行签名

最后将签名后的第三方app安装至物理机器上

仿佛是在运行我们自己编写的app

从Xcode的Build日志可以看出整个过程,如下图所示:

Bulid 日志

0x04 动态调试第三方APP

添加完脚本后,先clean整个工程,然后Run,可以在非越狱机器上

点击查看视图结构, lldb进行动态调试。

查看视图结构

还可以通过反编译找到特定符号的内存地址,然后根据内存地址设置断点,实现各种神奇的调试偷窥效果。

0x05 遇到的问题

1. clutch无执行权限
1
chmod +x clutch
2. Plugins中一些Extension签名失败

Kindle和微信都存在这种情况。

从Xcode日志中看到如下类似信息:

1
2
3
NSLocalizedDescription=Failed to verify code signature of 
<MIPluginKitPluginBundle : path = /private/var/mobile/Library/Caches/com.apple.mobile.installd.staging/temp.l4X8Bg/extracted/Kindle.app/PlugIns/KindleToday.appex
identifier = com.amazon.Lassen.KindleTodayExtension type = 7> : 0xe8008001 (Unknown error)}

从日志可以看出,通过上述方式运行的APP不会对Plugins里面的插件进行签名。

解决方法有两种:

1) 删除提示错误的Plugins文件夹,一般对动态调试没有什么意义。
2) 类比创建一个同名Extension,通过脚本替换成第三方app的Extension。
  • File->New->Target->Today Extension

添加TodayExtension

  • 在target “KindleToday”的Build Phases添加Run Script。

拷贝Extension

  • 将target “Kindle”的Build Phases中的Run Script移至Embed App Extensions之前。

Run Script位置

  • 若APP中有其他Extension或Watch APP可同样处理。