定位:本文讨论在设备已锁定、ADB 无 root、无法常规提取的条件下,如何通过第三方 recovery 拿到全分区物理镜像,以及拿到之后如何把它变成可用的取证材料。
前置警告:本流程会改变设备状态(在 recovery 或 boot 分区写入一个 recovery 镜像)。这些操作在多数情形下不触碰 userdata,但并非绝对安全,且可能触及 FRP(出厂重置保护)锁、运营商锁、引导加载器锁等状态。本文的读者是已取得合法授权的取证人员;授权范围、设备所有权、以及「是否允许改变设备状态」必须事先确认。
与本板块其他文章的关系:Android 数据存储总览 讲了数据在哪,本文讲怎么把它完整取出来;应用私有数据与 SharedPreferences 讲的是拿到之后怎么分析应用数据。
关键词:TWRP · NANDroid 备份 · recovery · A/B 分区 · 动态分区 super · lpunpack · FBE 文件级加密 · metadata 分区 · Odin · fastboot · boot 镜像
一、概述
Android 设备的提取难度是分层的。常见的可用手段按「对设备状态的改变」从轻到重排列:
| 手段 |
需要条件 |
对设备状态的影响 |
拿到的证据 |
| 常规逻辑提取 |
已解锁 + ADB 授权 |
几乎无(开关一次 USB 调试) |
应用数据、文件、数据库、日志 |
| root 提取 |
已 root |
无(但使用痕迹会留在系统里) |
完整 /data,可读取其他应用私有目录 |
| recovery 物理镜像 |
bootloader 可解锁,或可进 download 模式 |
会写入 recovery / boot 分区 |
全分区原始镜像(含已删除内容) |
| 硬件提取(JTAG / ISP / 芯片脱焊) |
需拆机、专业设备 |
物理破坏 |
全部 flash,含被锁死的分区 |
只有第三种和第四种能绕过锁屏密码。 具体来说:
- 锁屏密码与屏幕锁定(PIN / 图案 / 密码)会加密
userdata(FBE 场景下还涉及 metadata 分区)。recovery 若能成功解密,锁屏就等于被绕过了——因为 recovery 走的是启动早期的路径,不经过 Android 的锁屏凭据输入流程。
- FRP 锁(Factory Reset Protection)与 bootloader 锁是另一回事:FRP 锁的是「恢复出厂后需原 Google 账号」,bootloader 锁的是「能否刷写分区」。recovery 提取不需要解锁 bootloader(部分机型),但可能触碰 FRP 状态。
- 加密等级(
FLAG_SECURE_BOOT / Verified Boot)在部分新机型上会阻止第三方 recovery 启动。
所以适用场景是明确的:设备屏幕锁定、用户要求提取设备内数据、且已确认 recovery 路径可行。
拿到物理镜像有三条路,各有明确的适用边界:
| 路线 |
适用设备 |
前提 |
输出 |
| NANDroid 备份(TWRP 内置功能) |
绝大多数可进 recovery 的设备 |
recovery 可启动 |
tar / 压缩 / 加密的备份文件 |
dd 直读块设备 |
同上 |
recovery 可启动、能挂载外部介质 |
与物理镜像等价的整盘 dump |
| 网络传输(netcat / adb) |
同上 |
有 USB 数据线、无外部 SD 卡槽 |
通过 adb 端口转发传到工作站 |
三条路不冲突。常见做法是先做 NANDroid 备份(快、可靠、带元数据),再对需要的分区做 dd 直读。dd 的优势是能精确控制读哪几个分区,不至于把巨大的 system 一起拉出来。
有三件事不在这条路径的范围内:不讨论如何解锁 bootloader、不提供 FRP 绕过、不涉及任何移除 FRP 锁的技巧。理由不是技术做不到,而是绕过 FRP 的实质是在未获授权的情况下取得他人设备数据,这不属于取证范畴。
设备若因 FRP 或运营商锁无法处理,正确的做法是停止操作、记录设备状态、回到委托方沟通,而不是寻找技术手段。判据很简单:一个取证流程如果需要绕过设备所有者的保护机制,那它本质上已经是攻击而非取证。
真正要处理的技术内容是三块:recovery 的分区原理、备份产物格式、以及拿到备份后如何正确解析成可分析的材料。这一部分是纯取证工程,且对已经拿到设备但需要完整提取的合法场景有实际价值。
二、核心原理
2.1 Android 分区布局的三个演进阶段
要理解 recovery 能做什么,必须先理解现代 Android 的分区布局。
它经历了三个阶段。不同年代的设备差异极大,这是 recovery 步骤对不上号的主要原因:
阶段一:单槽固定分区(Android 6 及更早)
userdata boot system cache recovery ...
每个分区都是 GPT 里的物理分区,尺寸固定。recovery 是独立分区。
阶段二:A/B 双槽(Android 7–9)
boot_a boot_b
system_a system_b
... (关键分区成对出现)
userdata(只有一个)
引入 A/B 是为了「无缝更新」:更新写进非活动槽,重启切换,失败可回滚。A/B 设备开始,recovery 分区可能被取消,recovery 内容并入 boot。
阶段三:动态分区 super(Android 10+)
super(一个物理分区,里面装着一堆逻辑分区)
├── system_a system_b
├── vendor_a vendor_b
├── product_a product_b
├── system_ext_a
└── odm_a
userdata
metadata
system、vendor 等变成了 super 里的逻辑分区,尺寸可动态调整。
这对取证有直接影响:GPT 里不再有 system 分区,只有一个 super。 拿到裸镜像后,必须用 lpunpack 把 super 拆开才能看到里面的逻辑分区(见 3.8)。
关键转折点是 Android 12/13 引入的 init_boot 与 vendor_boot 分离,以及 Android 11+ 的 Virtual A/B(快照机制)——后者让 OTA 不再需要完整的第二份副本,而是用写时复制快照,进一步改变了分区布局。
2.2 A/B 双槽:为什么恢复镜像会「消失」
这一节解释一个新手最常遇到的困惑:明明刷了 TWRP,重启一次就没了。
原因在 2.1 的阶段二里。Android 有一个机制叫启动时的完整性校验与恢复:
- 官方 ROM 的
boot 分区里带有一个恢复出厂 recovery 的逻辑(在某些机型上是 boot 里包含 stock recovery ramdisk,或由 vbmeta 校验);
- 官方系统每次正常启动时,会检查 recovery 是否被修改,若检测到非官方 recovery 并配置了自动还原,会用 stock recovery 覆盖回去;
- 因此正确的操作纪律是:刷完 TWRP 后不要让它正常启动进 Android,直接手动按键进入 recovery。
对取证而言这条纪律有另一层意义:TWRP 只要停留在 recovery 里不被启动还原,就不影响 userdata。
反过来说,如果设备已经被重启进 Android 且 TWRP 被覆盖,需要重新刷一次。但这个「重刷」动作本身会在设备上留下痕迹(见 2.7),所以尽量一次做对。
2.3 动态分区 super 与逻辑分区
super 分区里的逻辑分区由一套「元数据」描述。这套元数据是取证时必须单独提取的东西:
- 几何元数据(geometry):描述
super 的几何布局(块大小、几何版本号)。
- LP 元数据(metadata):一个头部 + 若干分区表项,列出每个逻辑分区的名字、起始块号、大小、属性、group。
提取方法:lpdump 打印元数据,lpunpack 解出逻辑分区镜像。
取证价值:LP 元数据 本身是一个高价值的小工件。
它记录了设备的完整分区布局与更新组划分,是重建设备系统结构的依据,体积只有几 KB。把它单独导出并哈希留档,成本极低,收益明确。
A/B 设备的元数据是两份(每个 slot 一份),互相对应的分区名带 _a / _b 后缀。分析时必须两个 slot 都导出,否则只能看到一半的布局。
2.4 文件级加密 FBE:能不能读取决于 recovery 能力
这一节是全文最容易被误解的地方,单独讲。
FBE(File-Based Encryption,Android 7+)的工作方式:
- 密钥不是一个全盘密钥,而是按文件派生。每个文件有自己的加密密钥,密钥本身用「用户凭据派生密钥」再加密一次(称为「凭据加密」)。
- 密钥材料存放在
metadata 分区(加 /data 下的 metadata 目录,以及 /data/misc/keystore)。metadata 分区本身是被整体加密的,需由 TWRP/系统解密。
- 每个文件的密钥还与路径名绑定——同一个文件被改名后,其密钥派生就变了。这是 FBE 的一个重要特征(见陷阱 3.11)。
因此对取证的实际影响是:
| 情况 |
recovery 能否解密 userdata |
| 用户从未设置过锁屏密码 |
能(凭据加密层不生效或用默认密钥) |
| 设置了锁屏密码,但设备已解锁过一次 |
能(TWRP 拿到的是已解锁态的密钥) |
| 设置了锁屏密码,设备重启后未解锁 |
取决于 recovery 构建版本 |
最后一行是 2026 年的现实。 新 Android 版本对 FBE 做了加固,很多 TWRP 构建已经解不开了。
表现是:进 recovery 后 userdata 显示挂载成功,但 Android/data 下的文件名是乱码、文件打不开,或者整个 /data 读出来全是零。
遇到这种情况,正确的做法不是继续折腾 recovery,而是:
- 记录现象(挂载成功但文件名乱码 / 读取返回
EIO / 大小为 0)——这本身就是一个有价值的观察结果;
- 转向其他分区——
system、vendor、cache、persist、efs 等分区往往不受 FBE 保护,仍有取证价值;
- 评估是否需要硬件提取(JTAG/ISP)——这是一个成本与授权的决策,不是技术尝试。
绝对不要在报告里写「已提取全部用户数据」——除非 TWRP 明确显示解密成功且文件可读、可校验。
2.5 NANDroid 备份的三种产物与它们的区别
TWRP 的备份不是单一格式,而是按分区的文件系统类型选择不同的备份方式。这个区分对解析至关重要:
| 备份方式 |
内部枚举 |
适用分区 |
产物形态 |
| BM_FILES |
文件级备份 |
挂载为文件系统的分区(data / system / cache 等) |
tar 归档(可选 gzip 压缩) |
| BM_DD |
块级备份 |
boot、recovery、无文件系统的分区 |
原始镜像(raw image) |
| BM_FLASH_UTILS |
MTD 备份 |
NAND/MTD 闪存设备(老机型) |
厂商工具格式 |
NANDroid 产物文件名的编码规则(这决定了怎么判断产物类型):
{分区名}.{文件系统类型}.win{分片号}
{分区名}.{文件系统类型}.win{分片号}.{压缩或加密标记}
实例:
data.ext4.win000 ← 未压缩未加密
data.ext4.win000.gz ← gzip 压缩
data.ext4.win000.enc ← AES 加密
boot.emmc.win000 ← 块级原始镜像
cache.ext4.win000 ← 同 data
⚠️ 注意 .win 里的数字是分片序号,不是大小。 超过单个文件大小限制的 tar 会被切成 win000、win001、win002……多个分片必须按序号拼回一个完整归档才能解包,顺序错了会解出垃圾。这是解析备份时最高频的错误来源。 见陷阱 4.6。
TWRP 备份还会自动排除一部分路径(如缓存目录、系统预装的部分应用)。这些排除规则在 metadata/exclude.list 里。
做完整性评估时要把它读出来——被排除的内容在备份里根本没有,报告里不能宣称「已备份全部分区内容」。
2.6 备份加密的机制与现实约束
TWRP 支持对备份做加密(编译期可用 TW_EXCLUDE_ENCRYPTED_BACKUPS 关闭)。机制是:
用户密码 P
→ PBKDF2 派生密钥 K(salt 与迭代次数存在备份元数据里)
→ AES-256 加密备份数据流
关键现实约束:
- 密码丢了,备份就永久不可恢复。 没有后门、没有暴力破解的「技术后门」(PBKDF2 迭代次数虽有限,但面对高质量密码仍是天文数字级)。
- TWRP 官方不建议、也不鼓励对取证备份加密。 因为一旦出事,分析人员自己也打不开。
- 如果检材方提供了加密备份的密码,正确做法是让设备方或委托方在 TWRP 里执行恢复操作解密,而不是让分析方离线破解。
工业实践是:备份不加密,取证过程的保密靠访问控制与保管链,不靠加密备份。
对本文读者的实操建议:取证备份一律不加密。 如果 TWRP 提示是否加密,选「否」。需要保护数据的话,在工作站侧对整个备份目录做加密(比如加密卷或归档加密),这样既能保护数据,又不影响后续分析。
2.7 检测层:设备被做过 TWRP 操作后留下什么
取证人员要清楚一个双向问题:既要知道怎么用 TWRP,也要知道别人用过 TWRP 会留下什么。
设备上会留下的痕迹:
| 位置 |
痕迹 |
说明 |
recovery / boot 分区 |
recovery 镜像被替换 |
与官方镜像哈希不符 |
backup 目录 |
/data/media/0/TWRP/BACKUPS/… |
如果用户之前做过 NANDroid 备份,会留下完整备份 |
TWRP 目录 |
/data/media/0/TWRP/ 下的配置与日志 |
可能含操作历史 |
| 挂载点 |
recovery 挂载分区时写入的 lost+found |
证明该分区曾被以读写方式挂载 |
| 系统分区 |
若用户刷过包,system 下有第三方应用 |
需与官方镜像对比 |
关键洞察:如果一台可疑设备上已经存在 TWRP 目录和 NANDroid 备份,这些备份本身就是极其重要的证据。
它们可能由另一个人、同一套流程在更早的时间点提取过,时间点比本次委托更早,价值可能更高。
发现这类遗留备份时,先停下自己的备份操作,把原始备份完整保留下来。
反过来,如果本方做了 TWRP 提取,必须在报告里如实记录这次设备状态改变。 见陷阱 4.1。
三、操作步骤
3.1 采集前的状态固定与合法性确认
全文最容易跳过、风险最高的一步。
★ 不可逆操作,进入前必须确认。
1. 确认设备当前状态并留档(此步不改变设备)
记录:屏幕锁定状态、USB 调试状态、bootloader 状态、连接电脑时的设备标识
确认清单(逐项打勾,任一不满足则停止):
- 已取得书面授权,且授权范围明确包含「改变设备状态」(不只是「提取数据」)
- 已告知委托方本操作会写入 recovery / boot 分区及其风险
- 已在同型号的备用机上完整跑通流程(见 3.3 陷阱)
- 设备电量充足(见 3.4)
- 设备外观已拍照留档(操作前状态)
- 已记录设备型号、序号、IMEI 等标识
设备状态记录的具体内容(在连接电脑时采集):
Android 侧(若能连上)
adb devices -l
adb shell getprop ro.product.model
adb shell getprop ro.build.version.release
adb shell getprop ro.boot.verifiedbootstate # green / orange / red
adb shell getprop ro.boot.flash.locked # 1 = 已锁
adb shell getprop ro.boot.vbmeta.device_state # locked / unlocked
adb shell getprop ro.boot.slot_suffix # _a / _b
bootloader 侧
fastboot devices
fastboot getvar current-slot # a / b
fastboot getvar slot-count # 通常 2
fastboot getvar is-userspace # 区分 bootloader fastboot 与 fastbootd
fastboot getvar product # 确认机型,必须与 recovery 镜像型号一致
⚠️ ro.boot.verifiedbootstate 是关键前置判断:值为 red 表示启动链校验失败,第三方 recovery 很可能无法启动;orange 表示 bootloader 已解锁但校验被破坏,recovery 通常可启动。这个值要在动设备之前就记录下来,作为后续分析「为什么 recovery 启动失败」的依据。
3.2 用 fastboot 只读导出分区布局
在任何写操作之前,先用只读命令把分区布局取出来。这是一份纯读取的、高价值的工件:
进入 bootloader(不是 fastbootd)
adb reboot bootloader
列出所有分区(只读)
fastboot getvar all 2>&1 | tee device-vars.txt
读 GPT 表(物理分区布局)
fastboot getvar partition-type:boot
fastboot getvar partition-size:userdata
fastboot getvar has-slot:boot
动态分区设备需要进 fastbootd
fastboot reboot fastboot
fastboot getvar is-userspace # 应为 yes
fastboot getvar snapshot-update-status # none / snapshotted / merging
把 fastboot getvar all 的完整输出保存下来。 它包含分区大小、slot 状态、校验状态、机型标识,是后续所有分析的事实基础。
这个动作完全不改变设备(只读),所以即使后续因授权问题终止,这一步的产物依然有效。
3.3 安装 recovery 的三条路径与选择依据
★ 这一步会写入设备,bootloader / recovery 分区内容会改变。
先判断设备布局类型:
Q: fastboot getvar has-slot:boot 返回什么?
返回 1 / true → A/B 设备,按 A/B 流程
返回空或无此变量 → A-only 老设备,按老流程
Q: fastboot getvar is-userspace 返回 yes?
是 → 动态分区设备(super),刷写需在 fastbootd 里做
Q: fastboot getvar current-slot 返回什么?
a / b → 记下当前 slot,**不要盲目 --slot=all**
路径一:A-only 设备(独立 recovery 分区)—— 最简单
fastboot flash recovery twrp.img
不要 fastboot reboot!直接拔线,手动按键进 recovery
路径二:A/B 设备(无独立 recovery 分区,recovery 在 boot 里)
方案 A:一次性启动(推荐,不写设备)
fastboot boot twrp.img
方案 B:永久写入