前面在介绍class-dump时提到过,从AppStore下载的App(以下简称StoreApp)是被苹果加密过的(从其他渠道下载的一般没有加密),可执行文件被套上了一层保护壳,而class-dump无法作用于加密过的App。在这种情况下,想要获取头文件,需要先解密App的可执行文件,俗称“砸壳”。dumpdecrypted就是由越狱社区的知名人士Stefan Esser(@i0n1c)出品的一款砸壳工具,被越狱社区广泛运用在iOS逆向工程研究中。
dumpdecrypted在GitHub上开源了,得自行编译才能使用。下面就从零开始,以一个虚构的TargetApp.app为例,引导大家进行一次完整的App砸壳,请大家对着电脑,跟着笔者一起操作。
1)从GitHub下载dumpdecrypted源码,命令如下:
snakeninnysiMac:~ snakeninny$ cd /Users/snakeninny/Code/ snakeninnysiMac:Code snakeninny$ git clone git://github.com/stefanesser/dumpdecrypted/ Cloning into 'dumpdecrypted'... remote: Counting objects: 31, done. remote: Total 31 (delta 0), reused 0 (delta 0) Receiving objects: 100% (31/31), 6.50 KiB | 0 bytes/s, done. Resolving deltas: 100% (15/15), done. Checking connectivity... done
2)编译dumpdecrypted.dylib,命令如下:
snakeninnysiMac:~ snakeninny$ cd /Users/snakeninny/Code/dumpdecrypted/ snakeninnysiMac:dumpdecrypted snakeninny$ make `xcrun --sdk iphoneos --find gcc` -Os -Wimplicit -isysroot `xcrun --sdk iphoneos --show-sdk-path` -F`xcrun --sdk iphoneos --show-sdk-path`/System/Library/Frameworks -F`xcrun --sdk iphoneos --show-sdk-path`/System/Library/PrivateFrameworks -arch armv7 -arch armv7s -arch arm64 -c -o dumpdecrypted.o dumpdecrypted.c `xcrun --sdk iphoneos --find gcc` -Os -Wimplicit -isysroot `xcrun --sdk iphoneos --show-sdk-path` -F`xcrun --sdk iphoneos --show-sdk-path`/System/Library/Frameworks -F`xcrun --sdk iphoneos --show-sdk-path`/System/Library/PrivateFrameworks -arch armv7 -arch armv7s -arch arm64 -dynamiclib -o dumpdecrypted.dylib dumpdecrypted.o
上面的make命令执行完毕后,会在当前目录下生成一个dumpdecrypted.dylib文件,这就是等下砸壳所要用到的榔头。此文件生成一次即可,以后可以重复使用,下次砸壳时无须再重新编译。
3)用ps命令定位待砸壳的可执行文件。在iOS 8中,StoreApp全部位于/var/mobile/Containers/下,其中可执行文件位于/var/mobile/Containers/Bundle/Application/XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX/TargetApp.app/下。我们不知道X是什么,肉眼定位需要手工遍历所有目录,劳民伤财,但一个简单的小技巧就可以省时省力:首先在iOS中关掉所有StoreApp,然后打开Target,接着ssh到iOS上,打印出所有进程,如下:
snakeninnysiMac:~ snakeninny$ ssh root@iOSIP FunMaker-5:~ root# ps -e PID TTY TIME CMD 1 ?? 3:28.32 /sbin/launchd …… 5717 ?? 0:00.21 /System/Library/PrivateFrameworks/MediaServices.framework/Support/mediaartworkd 5905 ?? 0:00.20 sshd: root@ttys000 5909 ?? 0:01.86 /var/mobile/Containers/Bundle/Application/03B61840-2349-4559-B28E-0E2C6541F879/TargetApp.app/TargetApp 5911 ?? 0:00.07 /System/Library/Frameworks/UIKit.framework/Support/pasteboardd 5907 ttys000 0:00.03 -sh 5913 ttys000 0:00.01 ps –e
因为iOS上只打开了一个StoreApp,所以唯一的那个含有“/var/mobile/Containers/Bundle/Application/”字样的结果就是TargetApp可执行文件的全路径。
4)用Cycript找出TargetApp的Documents目录路径。StoreApp的Documents目录位于/var/mobile/Containers/Data/Application/YYYYYYYY-YYYY-YYYY-YYYY–YYYYYYYYYYYY/下,Y与之前的X值不同,而且这次PS也帮不上忙了。因此,需要借助强大的Cycript,让App告诉我们Documents的路径。命令如下:
FunMaker-5:~ root# cycript -p TargetApp cy# [[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask][0] #"file:///var/mobile/Containers/Data/Application/D41C4343-63AA-4BFF-904B-2146128611EE/Documents/"
5)将dumpdecrypted.dylib拷贝到Documents目录下。拷贝命令如下:
snakeninnysiMac:~ snakeninny$ scp /Users/snakeninny/Code/dumpdecrypted/dumpdecrypted.dylib root@iOSIP:/var/mobile/Containers/Data/Application/D41C4343-63AA-4BFF-904B-2146128611EE/Documents/ dumpdecrypted.dylib 100% 193KB 192.9KB/s 00:00
这里采用的是scp方式,也可以使用iFunBox等工具来操作。
6)开始砸壳。dumpdecrypted.dylib的用法是:
DYLD_INSERT_LIBRARIES=/path/to/dumpdecrypted.dylib /path/to/executable
实际操作起来就是:
FunMaker-5:~ root# cd /var/mobile/Containers/Data/Application/D41C4343-63AA-4BFF-904B-2146128611EE/Documents/ FunMaker-5:/var/mobile/Containers/Data/Application/D41C4343-63AA-4BFF-904B-2146128611EE/Documents root# DYLD_INSERT_LIBRARIES=dumpdecrypted.dylib /var/mobile/Containers/Bundle/Application/03B61840-2349-4559-B28E-0E2C6541F879/TargetApp.app/TargetApp mach-o decryption dumper DISCLAIMER: This tool is only meant for security research purposes, not for application crackers. [+] detected 32bit ARM binary in memory. [+] offset to cryptid found: @0x81a78(from 0x81000) = a78 [+] Found encrypted data at address 00004000 of length 6569984 bytes - type 1. [+] Opening /private/var/mobile/Containers/Bundle/Application/03B61840-2349-4559-B28E-0E2C6541F879/TargetApp.app/TargetApp for reading. [+] Reading header [+] Detecting header type [+] Executable is a plain MACH-O image [+] Opening TargetApp.decrypted for writing. [+] Copying the not encrypted start of the file [+] Dumping the decrypted data into the file [+] Copying the not encrypted remainder of the file [+] Setting the LC_ENCRYPTION_INFO->cryptid to 0 at offset a78 [+] Closing original file [+] Closing dump file
当前目录下会生成TargetApp.decrypted,即砸壳后的文件,如下:
FunMaker-5:/var/mobile/Containers/Data/Application/D41C4343-63AA-4BFF-904B-2146128611EE/Documents root# ls TargetApp.decrypted dumpdecrypted.dylib OtherFiles
赶紧把砸壳后的文件拷贝到OSX上备用吧,class-dump、IDA等工具已经迫不及待啦。
以上6步还算简洁明了,但可能会有朋友问,为什么要把dumpdecrypted.dylib拷贝到Documents目录下操作?
问得好。我们都知道,StoreApp对沙盒以外的绝大多数目录没有写权限。dumpdecrypted.dylib要写一个decrypted文件,但它是运行在StoreApp中的,与StoreApp的权限相同,那么它的写操作就必须发生在StoreApp拥有写权限的路径下才能成功。StoreApp一定是能写入其Documents目录的,因此在Documents目录下使用dumpdecrypted.dylib时,保证它能在当前目录下写一个decrypted文件,这就是把dumpdecrypted.dylib拷贝到Documents目录下操作的原因。
最后来看看如果不放在Documents目录下,可能会出现什么问题,如下:
FunMaker-5: /var/mobile/Containers/Data/Application/D41C4343-63AA-4BFF-904B-2146128611EE/Documents root# mv dumpdecrypted.dylib /var/tmp/ FunMaker-5: /var/mobile/Containers/Data/Application/D41C4343-63AA-4BFF-904B-2146128611EE/Documents root# cd /var/tmp FunMaker-5:/var/tmp root# DYLD_INSERT_LIBRARIES=dumpdecrypted.dylib /private/var/mobile/Containers/Bundle/Application/03B61840-2349-4559-B28E-0E2C6541F879/TargetApp.app/TargetApp dyld: could not load inserted library 'dumpdecrypted.dylib' because no suitable image found. Did find: dumpdecrypted.dylib: stat() failed with errno=1 Trace/BPT trap: 5
这里errno的值是1,即“Operation not permitted”,砸壳失败。如果你在使用dumpdecrypted的过程中碰到任何问题,或对它有进一步的研究,都欢迎来http://bbs.iosre.com 参与讨论。