目录
- 前言
- 一、检测是否脱壳
- 1.1 使用otool检测
- 1.2 使用MachOView检测
- 二、Clutch
- 2.1 安装Clutch
- 2.2 Clutch脱壳实战
- 三、dumpdecrypted
- 3.1 编译dumpdecrypted
- 3.2 dumpdecrypted脱壳实战
- 四、bfinject
- 4.1 安装bfinject
- 4.2 bfinject脱壳实战
- 4.3 修复闪退
- 五、CrackerXI(iOS11~iOS13)
- 六、Frida-ios-dump
- 6.1 一键快速脱壳
- 6.2 完美修复闪退
- 6.3 ipa文件安装失败处理
- 七、使用lipo分离架构
前言
iOS端App
在上线之前会由苹果商店进行FairPlayDRM
数字版权加密保护(简称“加壳”)。要对应用进行分析,就必须先解密(成为“脱壳”),从而得到原始未加密的二进制文件。本节将讨论各种各样的脱壳技术。
一、检测是否脱壳
如何检测应用是否加壳了呢?我们采用两种常规的方式检测
1.1 使用otool检测
用otool
可以看到二进制文件的信息里面有一个cryptid
字段,cryptid=1
表示已加壳,cryptid=0
表示未加壳。在终端使用命令行查看,具体如下:
$ otool -l xxtx| grep crypt
cryptoff 16384
cryptsize 41582592
cryptid 0
1.2 使用MachOView检测
如果不想输入命令行,则可以使用MachOView
来查看,将目标文件拖入MachOView
,展开Load Commands
节点,选择LC_ENCRYPTION_INFO_64
选项,右边可以看到Crypt ID
,
二、Clutch
Clutch
是一款全自动脱壳工具,其原理是把应用运行时的内存数据按照一定格式导出,并重新打包成ipa文件。
2.1 安装Clutch
从官网直接下载最新版,复制到iOS设备的/usr/bin/
目录,然后添加执行权限,操作如下:
# mac执行
scp -p 2222 -r ./Clutch root@localhost:/usr/bin
# iOS执行
$ chmod x /usr/bin/Clutch
在iOS设备上输入Clutch
命令,如果输出了帮助信息则表示安装配置成功,具体如下:
$ Clutch
Usage:Clutch [OPTIONS]
-b --binary-dump <value> Only dump binary files from specified bundleID
-d --dump <value> Dump specified bundleID into .ipa file
-i --print-installed Print installed applications
--clean Clean /var/tmp/clutch directory
--version Display version and exit
-? --help Display this help and exit
-n --no-color Print with colors disabled
2.2 Clutch脱壳实战
使用-i
参数打印从App Store
安装的所有应用列表:
$ Clutch -i
Installed apps:
1: WhatsApp Messenger <net.whatsapp.WhatsApp>
...
这里用序号为1
的WhatsApp Messenger
进行脱壳演示:
$ Clutch -d net.whatsapp.WhatsApp
Zipping WhatsApp.app
ASLR slids:0x100010000
Dumping <WhatsApp> (arm64)
Patched cryptid (64bit segment)
Writing new checksum
...
DONE:/private/var/mobile/Documents/Dumped/net.whatsapp.WhatsApp-iOS7.0-(Clutch-2.0.4).ipa
Finished dumping net.whatsapp.WhatsApp in 32.9 seconds
上述信息提示脱壳完成,重新打包后的文件为/private/var/mobile/Documents/Dumped/net.whatsapp.WhatsApp-iOS7.0-(Clutch-2.0.4).ipa
。
值得一提的是,最终脱壳出的文件架构和使用的iOS设备有关,如笔者的设备脱壳出来的是ARM64架构,如果放到ARMv7架构的设备上是不能正常运行的。如果需要多架构可用,则需要再准备一台ARMv7架构的设备进行脱壳,然后用lipo
命令将两个架构进行合并。
三、dumpdecrypted
上面提到的Clutch
使用过程是“傻瓜式”的,但是很多应用使用它脱壳会失败,这里介绍另外一款脱壳工具dumpdecrypted
,它在使用上比Clutch
会稍微麻烦一些,但是非常灵活,效果也不错。
3.1 编译dumpdecrypted
dumpdecrypted
是开源的,需要先编译、签名,再将其复制到iOS设备中,从官网可下载最新源代码。
到此为止,准备工作就完成了。
3.2 dumpdecrypted脱壳实战
为了操作方便,笔者选择先进入tmp
目录(如果脱壳失败,请进入沙盒的Documents再进行),脱壳后的文件就会保存与此。接口用ps
命令查看目标文件的完整路径,最后使用DYLD_INSERT_LIBRARIES
环境变量将dumpdecrypted.dylib
注入就可以脱壳了。操作如下:
$ cd /tmp
$ ps -ax | grep WhatsApp
1108 ?? 0:00.99 /var/contaniners/Bundle/Applications/8A9F2580-5919-1ACF11CD8/WhatsApp.app/WhatsApp
$ DYLD_INSERT_LIBRARIES=/usr/lib/dumpdecrypted.dylib /var/contaniners/Bundle/Applications/8A9F2580-5919-1ACF11CD8/WhatsApp.app/WhatsApp
mach-o decryption dumper
...
...
[ ] Closing original file
[ ] Closing dump file
$ ls -al
-rw-r--r-- 1 root wheel 23927 May 12 20:26 WhatsApp.descryped
WhatsApp.descryped
为脱壳后的文件,使用scp
命令或者pp助手导出到mac上即可。
四、bfinject
如果当前的设备系统是iOS11及以上版本,那么Clutch
、dumpdecrypted
不进行改造的,目前都无法正常使用,这时候可以选择bfinject
工具包,它集成了脱壳工具及Cycript
等。
4.1 安装bfinject
github
上有两个版本的bfinject
,官网中是原始版本,只能支持iOS11iOS11.1.2,[官网](https://github.com/MJavad/bfinject)中是修改版本,已经完成支持iOS11iOS11.4.1。
至此,bfinject
就已经安装好了。
4.2 bfinject脱壳实战
依然使用WhatsApp
来做实验,先确保目标App已经运行,并进入bfinject
目录,终端进入iOS设备使用如下命令进行脱壳。
$ ./bfinject -P WhatsApp -L decrypt
[ ] Electra detected.
[ ] Injecting into '/var/containers/Bundle/Application/8A9F2580-5919-1ACF11CD8/WhatsApp.app/WhatsApp'
...
[bfinject4realz] Success! Library was loaded at 0x1c43e0000
[ ] So long and thanks for all the fish.
如果顺利完成,界面会弹出Decryption Complete
对话框。脱壳完成的文件存放在应用沙盒的Documents
目录下,名为decrypted-app.ipa
,如果打开了控制台就能更加快捷地从日志进行定位,使用scp
命令将decrypted-app.ipa
复制到mac
,利用PP助手或者Xcode安装decrypted-app.ipa
,如果能正常运行则到此结束,否则看下面。
4.3 修复闪退
如果脱壳后的ipa包安装后运行闪退,则需要稍微处理一下,具体如下:
重新安装处理后的WhatsApp_ok.ipa
即可解决闪退问题。至此,bfinject
的脱壳过程全部完成。
五、CrackerXI(iOS11~iOS13)
CrackerXI
是脱壳工具的后起之秀,专为iOS11~iOS13量身打造,是目前为止最为傻瓜式的脱壳工具。
CrackerXI
的安装比较简单,直接在Cydia
中添加源(网址为:http://cydia.iphonecake.com/
),然后搜索安装即可。
安装完成后,会在桌面出现CrackerXI
图标,打开后会呈现已安装的App列表。在脱壳之前,进入Settings
页面进行一些必要的设置,将CrackerXI Hook
、Remove UISupportedDevices
、Set Minimum iOS version 10.0
、Remove Watch App
都打开。如果安装后没有出现相应图标,则进入终端执行uicache-a
即可。
现在进入“AppList”页面,单击需要脱壳的App,在随后弹出的对话框中单击YES,Full IPA
按钮,即会自动进行脱壳并重新打包成ipa文件,完成后会弹出一个成功的提示框。
至此,脱壳就很简单的完成了。
六、Frida-ios-dump
Frida-ios-dump
基于Frida
(一个跨平台的轻量级Hook框架)提供的强大功能,通过注入JS实现内存dump
,然后利用Python
自动复制到mac
生成最终的ipa文件
6.1 一键快速脱壳
Frida-ios-dump
的原理和dumpdecrypted
一样,都是通过把内存中已解密的数据dump
再修复Mach-O
,但是dumpdecrypted
仅能dump
主程序,对于框架需要自行修改源代码才能完成,而且操作上比较麻烦。而Frida
提供的强大功能,使得Frida-ios-dump
只需一键即可快速完成脱壳。
首先从github下载Frida-ios-dump
,并查看帮助:
$ git clone https://github.com/AloneMonkey/frida-ios-dump
$ cd frida-ios-dump
$ ./dump.py -h
usage: dump.py [-h] [-l] [-o OUTPUT_IPA] [-target]
frida-ios-dump (by AloneMonkey v2.0)
positional arguments:
target Bundle identifier or display name of the target app
optional arguments:
-h, --help show this help message and exit
-l, --list List the insstalled apps
-o OUTPUT_IPA, --output OUTPUT_IPA Specify name of the decrypted IPA
Frida-ios-dump
支持直接填写应用名或者Bundle ID
进行脱壳,参数-o
指定ipa文件输出路径,参数-l
显示所有已安装的应用。
以微信脱壳为例,命令如下:
$ ./dump.py 微信 -o ./Wechat_Decrypted.ipa
6.2 完美修复闪退
笔者发现由当前Frida-ios-dump
版本脱壳后的Wechat_Decrypted.ipa
仅能在iOS8上运行,其他系统上会出现Service exited due to signal:Killed 9
错误(闪退)。
使用dumpdecrtypted
和bfinject
脱壳后同样会发生闪退情况,之前都是用codesign
重签处理,既然重签能够运行,就说明闪退是由于签名校验失败后导致的,下面将从根源上解决这个问题。
Clutch
脱壳的程序是能正常运行的,对其源代码研究后发现它进行了hash
(散列,由叫“哈希”)值的修正处理。在学习Mach-O
文件格式时讲过,LC_CODE_SIGNATURE
加载命令存放的是一些与签名有关的数据,而里面最重要的是CSSLOT_CODEDIRECTORY
和CSSLOG_ALTERNATE_CODEDIRECTORIES
,它们包含了代码段的SHA-1
和SHA-256
校验信息。Clutch
源码里面有一个步骤修正了SHA-1
的hash
值,所以在iOS9上运行没有问题,但是iOS11校验了SHA-256
的hash
值,而该值又没有修正,所以仍然会闪退。
所以我们需要根据校验原理编写一个mac端工具,它能自动修正签名段的hash
值,然后修改dump.py
文件,让脚本在生成ipa文件之前先调用我们编写的工具。
6.3 ipa文件安装失败处理
如果将脱壳后的ipa文件安装到不同类型的设备,有可能会出现DeviceNotSupported
错误。这是因为设备支持列表中没有目标设备的类型。将ipa文件解压,找到Info.plist
文件,在UISupportedDevices
项添加自己的设备类型(或者直接删除UISupportedDevices
项)。将处理后的Info.plist
文件重新打包放入ipa文件再安装即可。
七、使用lipo分离架构
前文已经说过了,最终脱壳出的文件架构和使用的iOS设备有关。Mach-O
是胖文件格式,可能存在多种架构,那些没被脱壳的架构已经没有存在的意义,将其剔除还可以节省不少空间。mac
自带的lipo
工具就是负责这项工作的。
lipo
的功能非常强大,不但能合并多个Mach-O
文件到一个胖文件格式,也能从一个胖文件格式中分离指定架构的Mach-O
文件,下面的例子使用lipo
工具的-info
参数查看目标文件的架构,然后使用-thin
参数分离ARMv7
和ARM64
架构:
$ lipo -info WeChat
Architectures in the fat file:WeChat are: arm7 arm64
$ lipo WeChat -thin armv7 -output WeChat_armv7
$ lipo WeChat -thin arm64 -output WeChat_arm64
另外,如果想在64位设备上运行32位程序,只需要提取ARMv7
架构即可,因为在iOS11系统之前,指令集都是向下兼容的,但是到了iOS11及以后的系统,就只保留了ARM64
架构。