iOS逆向工程——基础篇
iOS文件系统
iOS由OSX演化而来,而OSX又是基于UNIX的,它们都是类UNIX操作系统。类UNIX操作系统有一套标准的文件系统——Filesystem Hierarchy Standard(FHS),其常用目录结构如下所示:
/
:根目录/bin
:binary,存放用户级基础功能的二进制文件,如ls
、ps
等/boot
:存放能使系统成功启动的所有文件。iOS中此目录为空/dev
:device,存放BSD设备文件。每个文件代表系统的一个块设备或字符设备。块设备以块为单位传输数据,如硬盘;字符设备以字符为单位传输数据,如调制解调器/sbin
:system binaries,存放提供系统级基础功的二进制文件,如netstat
、reboot
等/etc
:法语Et Cetera(and so on的意思),存放系统脚本及配置文件,如passwd
、hosts
。iOS中,/etc
是一个符号链接,实际指向/private/etc
/lib
:存放系统库文件、内核模块及设备驱动等。iOS中此目录为空/mnt
:mount,存放临时的文件系统挂载点。iOS中此目录为空/private
:存放两个目录,分别是/private/etc
和/private/var
/tmp
:临时目录。iOS中,/tmp
是一个符号链接,实际指向/private/var/tmp
/usr
:包含大多数用户和程序。/usr/bin
:包含那些/bin
和/sbin
中未出现的基础功能,如nm
、killall
等/usr/include
:包含所有的标准C头文件/usr/lib
:存放库文件
/var
:variable,存放一些经常更改的文件,如日志、用户数据、临时文件等。/var/mobile
:存放了mobile用户的文件。逆向工程重点关注目录/var/root
:存放了root用户的文件
iOS独有目录
下图所示分别是OSX和iOS的根目录结构,与FHS还是有一定的区别。
对于iOS,其独有的目录如下思维导图所示:
/Applications
:存放所有的系统App和来自于Cydia的App,不包括StoreApp/Developer
:如果一台设备连接Xcode后被指定为调试机,Xcode就会在iOS中生成该目录/Developer/Applications
/Developer/Library
/Developer/Tools
/Developer/usr
/Library
:存放一些提供系统支持的数据/Library/MobileSubstrate/DynamicLibraries
:存放Cydia安装程序的.plist
和.dylib
文件
/System/Library
:iOS文件系统中最重要的目录之一,存放大量系统组件/System/Library/Frameworks
:存放iOS中各种日常使用的framework/System/Library/PrivateFrameworks
:存放iOS中未公开的私有framework/System/Library/CoreServices/SpringBoard.app
:iOS桌面管理器
/User
:用户目录(mobile
用户的home
目录),实际指向/var/mobile
,存放大量用户数据/var/mobile/Media/DCIM
:存放照片/var/mobile/Media/Recording
:存放录音文件/var/mobile/Library/SMS
:存放短信数据库/var/mobile/Library/Mail
:存放邮件数据/var/mobile/Containers
:存放StoreApp。/var/mobile/Containers/Bundle
:存放所有StoreApp的可执行文件和相关资源/var/mobile/Containers/Data
:存放所有StoreApp的数据,沙盒目录的真实目录
iOS应用(StoreApp)沙盒
出于安全考虑,iOS系统把每个应用(StoreApp)以及数据都放到一个沙盒(sandbox)里面,应用只能访问自己沙盒目录里面的文件、网络资源等(也有例外,比如系统通讯录、照相机、照片等能在用户授权的情况下被第三方应用访问)。
上图所示为沙盒结构,沙盒在逻辑上包含两个部分:Bundle Container
和Data Container
,两者在iOS文件系统中的位置是平行的,分别是/var/mobile/Containers/Bundle
和/var/mobile/Containers/Data
。实际开发中,通过NSHomeDirectory()
方法获取到沙盒根目录对应的是Data Container
的路径。
Bundle Container
bundle的概念源自于NeXTSTEP,它是一个按某种标准结构来组织的目录,其中包含了二进制文件及运行所需的资源。正向开发中常见的App和framework都是以bundle的形式存在。在越狱iOS中常见的PreferenceBundle是一种依附于Settings的App,结构与App类似,本质也是bundle。Framework也是bundle,但framework的bundle中存放的是一个dylib(动态库),而非可执行文件。
在正向开发时,我们上传至App Store的ipa(iPhone
Application)包,解压后会有一个Payload
目录,其内部又包含一个.app
目录,这个目录就是一个App的目录结构,也是一个bundle。
Bundle Container
位于/var/mobile/Containers/Bundle/Application/XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX/
主要用于存放静态资源,主要包含以下目录和文件:
MyApp.app
存放可执行文件和资源文件,包括:打包时的资源文件、本地文件、可执行文件、.plist
文件。这个目录不会被iTunes同步。iTunesArtWork
iTunesMetadata.plist
Data Container
Data Container
位于/var/mobile/Containers/Data/Application/YYYYYYYY-YYYY-YYYY-YYYYYYYYYYYY/
,主要用于存放App运行时产生的动态数据,其主要包含以下目录和文件:
Documents
存放应用运行时生成的并且需要保存的不可再生数据。注:iTunes或iCloud同步设备时会备份该目录Library
Library/Caches
存放应用运行时生成且需要保存的可再生数据,比如网络请求,用户需要负责删除对应文件。iTunes或iCloud不同步。Library/Preferences
存放偏好设置。使用NSUserDefaults
写的设置数据都会保存在该目录下的一个plist
文件中。iTunes或iCloud同步设备时备份该目录。
tmp
存放应用下次启动不再需要的临时文件。当应用不再需要这些文件的时候,需要主动将其删除。(当应用不再运行的时候,系统可能会将此目录清空。)这个目录不会被iTunes同步。
在正向开发时,沙盒目录路径均有相应的获取方式,具体如下所示:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18// 沙盒目录
NSLog(@"%@",NSHomeDirectory());
// MyApp.app
NSLog(@"%@",[[NSBundle mainBundle] bundlePath]);
// Documents
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *docPath = [paths objectAtIndex:0];
NSLog(@"%@",docPath);
// Library
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES);
NSString *libPath = [paths objectAtIndex:0];
NSLog(@"%@",libPath);
// tmp
NSLog(@"%@",NSTemporaryDirectory());
在逆向工程中,可以通过以下方式获取相关的目录: 1
2
3
4
5
6// 获取App的Bundle路径
iphone: root# ps -e | grep appname
// 获取App的Data路径
iphone: root# cycript -p appname
cy# directory = NSHomeDirectory()
iOS二进制文件类型
iOS逆向的目标主要包含三类二进制文件:Application
、Dynamic Library
、Daemon
。
Application
Application,即我们最熟悉的App。App的Bundle目录有以下三个部分比较重要:
Info.plist
Info.plist记录了App的基本信息,如:bundle identifier
、可执行文件名、图标文件名等。可执行文件
查看Info.plist,即可定位可执行文件lproj目录
lproj目录下存放的是各种本地化的字符串。
系统App VS. StoreApp
/Applications/
目录下存放系统App(包括CydiaApp);/var/mobile/Containers/
目录下存放StoreApp。其区别在于:
目录结构
两种App的Bundle目录区别不大,都含有Info.plist、可执行文件、lproj目录等。只是Data目录的位置不同:StoreApp的数据目录在/var/mobile/Containers/Data/
下,以mobile权限运行的系统App的数据目录在/var/mobile/
下,以root权限运行的系统App的数据目录在/var/root/
下。安装格式和权限
Cydia App的安装格式一般是deb,StoreApp的安装格式一般是ipa。前者的属主用户和属主组一般是root和admin,能够以root权限运行;后者的属主用户和属主组都是mobile,只能以mobile权限运行。
Dynamic Library
Dynamic Library简称dylib,即动态链接库。在正向开发中,在Xcode工程中导入的各种framework,链接的各种lib,其本质都是dylib。
在iOS中,lib分为static和dynamic两种,其中static lib在编译阶段成为App可执行文件的一部分,会增加可执行文件的大小。dylib则不会改变可执行文件的大小,只有当App运行时调用到dylib时,iOS才会把它加载进内存,成为App进程的一部分。
dylib是逆向工程的重要目标类型,但其本身并不是可执行文件,不能独立运行,只能为别的进程服务,而且它们寄生在别的进程里,成为这个进程的一部分。因此,dylib的权限是由它寄生的那个App决定的,同一个dylib寄生在系统App和StoreApp里时的权限是不同的。
越狱iOS中,Cydia里的各种tweak无一不是以dylib的形式工作的。
Daemon
iOS的daemon主要由一个可执行文件和一个plist文件构成。iOS的根进程是launchd,其会在开机时检查/System/Library/LaunchDaemons
和/Library/LaunchDaemons
下所有格式符合规定的plist文件,然后启动对应的daemon。这里的plist文件与App中的Info.plist
文件作用类似,即记录Daemon的基本信息。