本文首发于少数派:https://sspai.com/post/79029
iTunes 备份内容结构浅析
2022 年初,我的 iPhone 8 在勤恳服役三年后,以一次落地坠入不可挽救的冷寂1,使其继任者 iPhone 13 mini 面临数据缺失造成的起步困难,于是数日前的 iTunes 备份有了用武之地,应用列表、聊天记录等除少量损失外,基本如数恢复。不久,手持新机的喜悦占领高地,新的折腾又已开启。
既然这些数据能够被 iTunes 备份及恢复,数据内容必然就存放在备份文件中,但应用千奇百怪,iTunes 又是如何组织备份数据结构的呢?不如同我一道,打开备份瞧瞧。
准备
首先,我们需要准备一个备份以供后续分析。使用 USB 将 iPhone 或 iPad 连接电脑,然后根据自己的电脑系统进行备份操作。可参考官方文档:
对于 macOS,自 Catalina 起,原本的 iTunes 已不复存在,其核心的音乐媒体功能变更为 Music,移动设备备份功能则交棒给了 Finder。为表述一致,本文仍将 Mac 和 PC 两平台的 Apple 移动设备备份统称为 iTunes 备份。
出于方便分析的目的,备份时请不要勾选加密备份。
定位初窥
完成备份后,我们可以通过文件系统定位到备份所在路径:
- macOS 为
~/Library/Application Support/MobileSync/Backup
- Windows 为
%APPDATA%\Apple Computer\MobileSync\Backup
(部分电脑%APPDATA
下无Apple Computer
文件夹,则应替换为Apple
)2
插一句,由于
Backup
路径固定,可以通过软链接的方式将 iTunes 备份移至外部储存,以节省本机硬盘空间,参考 一日一技 | 怎样将 iPhone 备份保存到 Mac 的外部存储设备。可以看到,
Backup
路径下有一个名似 UUID 的文件夹,想必就是我们刚刚的备份文件了。如果你曾有多个设备通过 iTunes 备份至同一台电脑,那么 Backup
路径下将会有对应数量的文件夹。不难猜测,每个文件夹便对应一台移动设备,文件夹名实为设备标识码 UDID 3。打开设备文件夹,我们将看到一大串以两个字符命名的文件夹,可能从
00
到 ff
。熟悉十六进制的朋友已有警觉,这看上去应该就是排列好的哈希头啊。先行跳过,看看除文件夹外还剩的几个文件:Info.plist
Manifest.db
Manifest.plist
Status.plist
。其中最大的 db
文件,想必是保存主要数据的一个 SQLite 数据库;另外三个为 plist
文件,常用于在 iOS 和 macOS 应用中保存配置、状态等信息,从中应该能够获取到一些有关备份和应用的数据。尝试深挖
尽管都以
.plist
结尾,但 Manifest.plist
与 Status.plist
是二进制文件,需借助 Xcode(Mac) 或开源跨平台的 ProperTree(依赖 Python 环境)、Xplist 等软件打开,而 Info.plist
是形似 XML 的文本文件,除前述软件外,也可用直接在文本编辑器中查看。Info.plist
首先是
Info.plist
,Xcode 打开后可以清晰地看出,该文件保存了我们所备份设备的各种信息:Applications
和Installed Applications
分别以字典和列表的方式保存了设备上已安装的应用,前者还为每个应用保存了一些元数据;
Device Name
/Display Name
、Build Version
显示了设备名、系统版本;
- Product 相关字段是设备出厂时厂商所赋予的标识;
Last Backup Date
与 iTunes 相关内容则记录了最近一次备份日期及一些备份相关信息。
Status.plist
Status.plist
的内容较为简单,主要记录当前备份状态:IsFullBackup
指示这次备份是否为全量备份(上图为增量备份);
Manifest.plist
Manifest.plist
更侧重于备份文件内容的对照:Applications
部分为应用元数据,与Info.plist
中的 98 项不同,此处删减之前多达 994 项,其将各应用的数据按照域、组、插件等做了更为细致的拆分。元数据字段中也有更多信息,比如根据 Google Maps 路径可知其打包后应用文件名为maps.app
,因为放在专属的容器中,不会与其他家的地图混淆;
LockDown
部分保留了一些设备和备份的相关信息;
Date
记录了该设备第一次在此电脑备份的时间;
IsEncrypted
表示备份是否加密;
Manifest.db
来到核心的
Manifest.db
,这是一个 SQLite 文件型数据库,可使用任意支持 SQLite 的数据库软件读取查询,如 TablePlus(Mac)、DBeaver(开源跨平台)。Manifest 数据库由 Files 和 Properties 两个数据表组成,后者暂无数据,故让我们聚焦于 Files 表。其保存了近 15 万行数据,表结构并不复杂,共有 5 个字段:
domain
是各应用、应用组所属的域,与Manifest.plist
中Applications
的子项对应;
relativePath
可读性较高,记录了文件相对路径,相对于什么父路径呢?联想到 Google Maps 的例子,父路径应该是domain
域所对应的容器;
flags
:结合relativePath
总结规律,1
表示文件,2
表示文件夹;
fileID
看起来像是一串哈希值,不禁让我们想起设备文件夹下的双字符子文件夹。从relativePath
中随便找个文件验证一下:比如mapcfg_logo_zh_3_icon@2x.png
对应的fileID
开头为 000199xxxxxx,进入00
文件夹查找 000199xxxxxx,将所得文件拷贝出来,更改文件名以.png
结尾,便能顺利打开看到了一张模糊的图片;
file
为二进制数据,存放了诸如文件大小、创建时间之类的信息。
总体而言,若你关注备份状态及设备信息,可从
Status.plist
和 Info.plist
两个文件了解,通过后者还能便捷地获取设备的应用列表。而如果你想在备份文件中找到一些有用的数据,则需依赖 Manifest 数据库内的 Files 数据表,其为 iTunes 备份的所有文件建立了路径映射关系,可通过 domain
锁定应用,基于 relativePath
查找具体文件,再由对应的 fileID
定位文件在磁盘上的真实路径,设法读取即可。一览无余
通过层层深入,我们已经挖掘到了 iTunes 备份的末梢,即每一个具体的应用文件。那么是时候起身俯瞰,纵览这套备份了。
应用目录树
还记得刚刚的
relativePath
字段,它标明了某一应用具体文件相对应用域的路径,如果我们将备份中该应用的所有相关文件组织在一起,然后对 relativePath
加以整理呢?没错,我们就得到了这个应用的文件目录树。把备份中所有应用的目录树合在一起,整个 iTunes 备份的结构就非常完整清晰了。再加一点点可视化——
Space Sniffer
Windows 平台曾有款名为 SpaceSniffer 的软件,可以帮助用户直观地看到磁盘空间占用,轻巧实用,深得我心。既然我们已经得到了目录结构,不妨再补上文件大小,以类似的形式看看各应用所占空间。文件大小的获取有两种方式,一种是解析
Manifest.db
Files 表中的 file
字段,从中读取文件大小相关键值;另一种更为直接,通过 fileID
定位真实路径后查看文件大小即可,不做赘述。完成可视化之后便是下面这个样子——
可以看出,微信(com.tencent.xin)在我的 iPad 备份空间中几乎占据半壁江山,其次是哔哩哔哩、京东等,以及大隐隐于图的真·小而美应用们。
结语
我们整个探索是基于未加密的 iTunes 备份,如你所见,未加密备份中的绝大部分应用数据可被设法读取,这不可避免地给隐私及安全造成一丝威胁。若执行备份的电脑不足够可靠,请务必勾选加密备份。按照 官方对加密备份的说明,密码、健康、通话记录等数据在你勾选加密后会添加至备份中,未加密备份并不会包含这些内容。尽管以这种方式被窃取数据的可能性似乎微乎其微,但还是记得给加密备份选个安全的密码吧。
笔者并非 iOS/macOS 开发者,对于相关应用底层逻辑不甚了解,难免谬误,敬请指正。
参考附注
- 天才吧检测后表示坚持修只能返场大换内脏,衡量成本后放弃