应用的构建过程与签名
一、引言
在逆向开发的过程中,一些常用逆向工具和逆向分析的技巧已经被我们所熟知和运用,但其中所用到的理论基础往往容易被忽略。理论基础的储备能够拓宽逆向分析的思路,并在遇到问题时很快的找到原因和应对的方法,从而使得逆向开发的过程变得轻松。下面从基础的包结构、包构建以及包安装进行解读。
二、应用包的格式
苹果的应用包主要是ipa格式的,其本身就是zip的压缩包,右键“归档实用工具”即可解压包内的内容,拿讯飞输入法举例,它的应用包内容结构如下:
AestheticdeMBP:应用 aesthetic$ tree 讯飞输入法-8.0.2336 -L 2
讯?\236?\223?\205??\225-8.0.2336
├── META-INF
│ ├── com.apple.FixedZipMetadata.bin
│ └── com.apple.ZipMetadata.plist
├── Payload
│ └── iFlytekIME.app
├── iTunesArtwork
└── iTunesMetadata.plist
其中Payload目录下就是iFlytekIME.app文件夹,为应用包的主要成分,它的目录下主要有如下几类文件:
-
可执行文件: 它是应用的在iOS系统中的执行文件,是定义的MachO格式类型,就像ELF是Linux的可执行文件类型一样,它最终由dyld进行加载运行。
逆向层面:运用Hopper可用于进行静态代码的分析,修改Load Commands段以加载注入的动态库,运用懒加载符号绑定的特性进行函数的Hook等
-
Info.plist文件: 存储应用的相关设置、BundleID以及Executable file等。
逆向层面:在重签名的时候修改BundleID与新证书APPID一致以通过验证,获取该应用可执行文件名信息以对其进行操作,修改其他应用配置等
-
Frameworks文件夹: 当前应用使用的第三方Framework。
逆向层面:复制注入动态库到该文件夹让系统以@rpath相对路径的方式进行查找
-
PlugIns&Watch文件夹: 当前应用使用的Extension以及Watch手表相通的应用。
逆向层面:重签名时由于签名验证的原因需要对这些文件夹的文件都进行重签,因为Extension的BundleID需要以主BundleID作为suffix才能验证通过
-
资源文件: 其他文件,包括图片资源、PP配置文件、音视频资源以及其他本地化相关的文件
三、应用的构建
首先应用的构建我们可以通过Xcode来进行,按“Command+B”快捷键编译项目。接着,我们可以点击查看Xcode在编译时到底做了什么,如下图所示:
大体我们看到了整个编译过程:
(1)编译源文件:使用Clang编译项目中所有参与编译的源文件,生成目标文件。
(2)链接目标文件:将源文件编译生成的目标文件链接成一个可执行文件。
(3)复制编译资源文件:复制和编译项目中使用的资源文件。例如将storyboard文件编译成storyboardc文件。
(4)复制embedded.mobileprovision:将本地Provisioning\Profiles下的描述文件复制到生成的APP目录下。
(5)生成Entitlements:生成签名用的Entitlements文件。
(6)签名:使用生成的Entitlements文件对生成的APP进行签名
其实我们可以仿照Xcode通过makefile命令行的方式来自己构建一个App,具体如下:
compile:
#创建xxx.app文件
@rm -r -f xxx.app
@mkdir xxx.app
#Compile Objective-C file
@xcrun -sdk iphoneos clang -arch $(Architecture) -mios-version-min=8.0 -fmodules -fobjc-arc -c $(SRCROOT)/main.m -o xxx.app/main.o
...
link:
#链接目标文件
@xcrun -sdk iphoneos clang xxx.app/main.o -arch $(Architecture) -mios-version-min=8.0 -fobjc-arc -fmodules -o xxx.app/xxx
@rm xxx.app/main.o
...
storyboard:
#编译storyboard文件
@mkdir xxx.app/Base.lproj
@ibtool --compilation-directory xxx.app/Base.lproj xxx.app/Base.lproj/Main.storyboard
...
plist:
#plist写入信息 : App ID、name、version ...
@defaults write $(pwd)/xxx.app/Info CFBundleExecutable xxx
asset:
#复制图片资源
@cp -a $(SRCROOT)/images/. xxx.app/
dsym:
#生成dSYM文件
@dsymutil -arch $(Architecture) xxx.app/xxx -o xxx.app.dSYM
codesign:
#签名
@cp -f embedded.mobileprovision xxx.app
@codesign -fs $(CertificateName) --entitlements entitlements.plist xxx.app
package:
#打包ipa
@mkdir -p Payload @cp -r -f xxx.app Payload
@zip -r -q xxx.ipa Payload
@rm -f -r Payload/ @rm -f -r xxx.app
从makefile文件中可以看到,整个过程分为compile link storyboard plist asset dsym codesign package
这几个步骤,最终按顺序执行构建;不过这只是简单的列举了一下几个编译的主要过程,通过Xcode编译还涉及到其他的编译参数和步骤。
从上述的构建过程我们可以发现签名的过程也正在其中,这就给我们进行重签名和注入包有所启发;其实就是在Xcode构建的过程中,我们可以在签名步骤之前对plist文件进行修改以及注入所依赖的framework,这也是MonkeyDev实现的原理。
三、应用签名及安装
为了确保安装到手机上的应用都是经过认证的合法应用,苹果制定了一个签名机制。其中涉及到如下这些文件:CertificateSigningRequest、.cer文件、Entitlements授权文件、PP配置文件。
(1)CertificateSigningRequest
该文件包含申请者信息、申请者公钥、公钥加密算法。
(2).cer文件
该文件包括申请者信息、申请者公钥、通过苹果私钥加密的数字签名,其中数字签名是通过取出CertificateSigningRequest的公钥,添加账号信息,再通过hash算法生成一个信息摘要,使用苹果的CA私钥进行加密得到的。
在对应用进行签名时,先使用证书所对应的私钥对代码和资源文件等进行签名,苹果系统会通过公钥对应用的签名合法性进行验证。
(3)Entitlements授权文件
授权文件是一个沙盒的配置列表,其中列出了哪些行为会被允许、哪些行为会被拒绝。例如,在重签应用时常常需要调试器自动发夹,就会将文件里面的get-task-allow改为true。在签名时Xcode会将这个文件作为–entitlements参数的内容传给codesign。
(4)配置文件(Provisioning Profiles)
前面提到的证书包含在该文件里,配置文件在打包时会被复制到.app目录下,其包含App ID,授权文件,证书以及可安装的设备列表。
可以使用security cms -D -i embedded.mobileprovision
命令来查看。
当一个应用安装启动时,苹果系统会对其进行验证,其实主要就是检查配置文件和当前运行App的信息是否匹配,检查项大概如下所示:
BundleID(APP)–App ID、entitlements(APP)–entitlements、certificate(APP)–certificate、deviceID(系统)–device ID
在逆向开发中重签名的过程也就是让整个过程在验证的时候能够通过,在修改掉原来应用的代码或资源时,重新用自己的证书对该应用进行签名就可以了,唯一要做的就是需要将entitlements、BundleID这些检验项换成匹配新配置文件的内容就可以了。
四、总结
在重新梳理过这些基础的知识之后,我们也就对整个苹果安装包从始至终的形态有了一定的了解,这同时也对逆向的开发提供了坚实的基础。