一、概述
拿到一块镜像,问"里面有什么"表面上是文件恢复,实际拆开是三层:镜像 → 卷(分区 / LVM / RAID)→ 文件系统。只有第三层才决定"文件叫什么、多大、什么时候改过、删到哪里去了"。
文件系统是数据在磁盘上的组织约定。它规定字节如何被解释成目录、文件、簇、inode,也决定了空间何时被复用——删除痕迹之所以能残留,根源就在这里。反取证软件的藏身点几乎都建立在"复用的时机"上,而那个时机由文件系统定义。
同一块磁盘,用 NTFS 解析和用 ext4 解析,得到的目录树可以完全不同。选错文件系统等于全部结论作废,不是"效果差一点",是归零。
这一层判定落在分析环节的最前端。上游输入是卷层:镜像格式(E01 还是 raw,转换见证据格式与转换)与接入方式(见只读挂载与安全接入)。判定完成后按类型分流——NTFS 进 NTFS 结构与 MFT 解析、NTFS 数据流与隐藏数据、Steady-State 与 LogFile 还原,ext4 进 ext4 结构与 inode,FAT 进 FAT 系列结构,APFS 进 APFS 容器与快照,F2FS 进 F2FS 结构,内容识别进 文件头与文件签名。这一层负责判定"这是什么",各分支负责"把它读透"。
判定依据是有确定偏移的特征字段,不是抽象分类:
NTFS 在卷起始偏移 3 —— Boot sector 的 OEM ID(55 4F 46 53 20 20 20)
0xEF53 在卷起始偏移 1024(0x400) —— ext2/3/4 超级块的 s_magic。前面 1024 字节是引导区,所以偏移是 1024 不是 0,这是最常记错的一个
NXSB 在分区 + 32(0x20) —— APFS 容器头。注意是分区偏移,不是卷偏移
APSB 在卷首偏移 0 —— 每个 APFS 卷各自一份
FAT12 / FAT16 / FAT32 文本 preceded by 跳转指令 0xE9 / 0xEB —— FAT 家族
EXFAT 在偏移 3 —— exFAT。它没有标准 BPB,别按 FAT32 的 BPB 去读
H+(0x482B)在偏移 1024 —— HFS+(嵌入式场景 +18)
SWAPSPACE2 / SWAP-SPACE —— Linux swap,swap 也要单独 dump
LABELONE —— LVM2 元数据区
mmls 的 Unallocated 行 vs blkls 的未分配簇 —— 卷层的"未分配"与文件系统层的"未分配"是两回事,前者是分区表没占的区间,后者是文件系统内部还没分配的簇。反取证软件最常见的藏身点就是这两处
- 第三章 3.6 的熵检测 ——
ent -b 的 Shannon 熵接近 8.0 几乎必然是加密或已随机化填充。读不出文件名但熵很高,说明是加密而不是空白
判定之后能回答的是这些:卷上跑的是什么文件系统(靠魔数、靠结构区,不靠扩展名也不靠体积)、一块盘上有多套系统该怎么逐卷处理,以及——最关键的——怎么判断自己是不是解析错了。
最后一条来自 2.5 那句"部分正确、部分错误最危险":判断标准应是目录数量和文件数量是否合理,而不是"命令有没有报错"。偏移少加一个扇区时,工具偶尔仍能出目录名,这种"看起来成功"比明确报错危害大得多——它让人以为已经检查过了。
有几件事不归这一层管:任何一种文件系统的具体结构,解析在分支篇里;LVM / 动态磁盘 / RAID 的重组,2.4 表格里写了"需 mmstat 或专有工具重组";加密卷的内容,识别出 BitLocker 之后怎么解是加密篇的事;时间戳怎么读,这里只判定"这是 NTFS",$STANDARD_INFORMATION 里四个时间戳的语义在时间戳篇。
往下读之前,需要分区表(MBR / GPT)与卷层概念,以及基本的十六进制读取能力——全程都在"相对卷起始的偏移"上计算,而最容易出的错就是偏移的基址搞混(分区起始 vs 卷起始 vs 磁盘起始)。
另外强烈建议先读一遍取证流程与原则的检验阶段:这里的全部命令都是在工作副本上跑的,不是原始介质。 第三章步骤 5 那个"卷清单"登记表之所以要记 Slot、起始扇区、文件系统类型、目录条目数四项,就是为了让复核者能重走一遍——登记格式本身就是可追溯性。
二、核心原理
2.1 三层结构与工具对应
| 层 |
回答的问题 |
Sleuth Kit 工具 |
典型失败模式 |
| Image |
镜像格式、扇区大小 |
img_stat |
E01 当 raw 读,全盘乱码 |
| Volume |
分区表、LVM、RAID |
mmls / mmstat |
把分区间隙当数据 |
| File System |
目录树、元数据、内容 |
fsstat / fls / icat |
偏移错位、类型误判 |
关键点:卷层的"未分配"和文件系统层的"未分配"是两回事。前者是分区表没占用的区间(mmls 的 Unallocated 行),后者是文件系统内部还没分配的簇/块(需 blkls)。
反取证软件最常见的藏身点就是这两处。
2.2 三大主流系统对比
| 维度 |
NTFS |
ext4 |
APFS |
| 平台 |
Windows / Linux 双系统 |
Linux |
macOS / iOS |
| 核心数据库 |
$MFT(每文件一条 1024 字节记录) |
inode 表(分散于块组) |
APFS B-tree(对象容器) |
| 元数据集中度 |
极高,几乎全在 $MFT |
中,inode + 目录散落 |
极高,单一 B-tree |
| 删除痕迹 |
$FILE_NAME 保留原名+父引用 |
inode 保留时间戳+大小,文件名易丢 |
B-tree 中对象可残留 |
| 内建版本机制 |
卷影副本(快照) |
无(日志 + 备份工具) |
原生快照 + checkpoint |
| 加密支持 |
BitLocker / EFS(卷级/文件级) |
LUKS/dm-crypt(卷级) |
原生整容器加密 |
| 时间戳 |
4 个(创建/修改/访问/变更) |
常见 3–4 个(纳秒精度) |
created / modified |
| 日志/日志还原 |
$LogFile(可回放元数据) |
journal(可回放) |
checkpoint 映射 + B-tree 事务 |
| 取证友好度 |
★★★★★ 工具最全 |
★★★★ 工具成熟 |
★★★ 工具少、加密普遍 |
| 恢复难度 |
低(有明确元数据记录) |
中 |
高(加密 + 工具少) |
一个反直觉但重要的点:APFS 在"元数据集中度"上比 NTFS 更高——它把所有文件、目录、符号链接的属性统一塞进 B-tree 节点。
这理论上更利于完整解析,实际却因为加密默认开启 + 公开解析工具少而更难取证。
2.3 文件系统识别:靠魔数,不靠扩展名或体积
判别顺序永远是先看结构区,再看特征字段。以下为各系统在卷起始处的签名(偏移均相对卷/文件系统起始,不是磁盘起始):
| 文件系统 |
相对偏移 |
签名/特征 |
备注 |
| NTFS |
偏移 3 |
NTFS (55 4F 46 53 20 20 20) |
Boot sector OEM ID |
| ext2/3/4 |
偏移 1024(0x400) |
超级块 s_magic = 0xEF53 |
前面 1024 字节是引导区 |
| APFS 容器 |
偏移 32(0x20) |
NXSB |
容器头 magic;APSB 是卷超级块 |
| APFS 超级块 |
偏移 0(卷首) |
APSB |
每个 APFS 卷各自一份 |
| FAT12/16/32 |
偏移 0 |
跳转指令 + FAT12/FAT16/FAT32 文本 |
0xE9/0xEB 开头 |
| exFAT |
偏移 3 |
EXFAT |
Boot sector |
| HFS+ |
偏移 1024(0x400) |
H+ (0x482B) |
嵌入式场景 +18 |
| swap |
偏移 0/页尾 |
SWAPSPACE2 / SWAP-SPACE |
Linux swap |
| LVM2 |
元数据区 |
LABELONE |
卷组元数据区 |
判不要用命令:
mmls /evidence/DigiForensics.dd # ① 卷层:TSK 直接给出类型判断
fsstat -o 63 /evidence/DigiForensics.dd # ② 文件系统层:读超级块
xxd -l 1024 -s $((63*512)) /evidence/DigiForensics.dd | head -20 # ③ 兜底:看魔数
sudo blkid -p -o full /evidence/DigiForensics.dd # ④ Linux 侧独立判定
注意区分:file 只能识别整个镜像文件,不能识别镜像内的分区。要判断分区类型必须用 blkid -p(探测模式)或 TSK 的 fsstat。
2.4 多卷 / 多分区场景
| 布局 |
典型来源 |
处理要点 |
| EFI + 系统 + 数据(3 分区) |
Windows 现代安装 |
每个分区独立 fsstat/fls |
| 共享 + 家庭 + 恢复(3 分区) |
Windows OEM |
恢复分区可能是 FAT32 小卷 |
| GPT + ESP(FAT32) + root(ext4) + swap |
Linux |
swap 也要单独 dump |
| APFS 容器(1 分区内多卷) |
macOS |
见 06 |
| LVM 逻辑卷 / 动态磁盘 / RAID |
服务器 |
需 mmstat 或专有工具重组 |
处理原则:逐卷独立解析,结果用「卷标识 + 元数据坐标」双重引用。
例如"卷 2(NTFS)MFT 条目 11443"比"某文件"精确得多,且可复核。
2.5 为什么"选错文件系统"是灾难性错误
| 误判 |
表现 |
危害 |
| 把 APFS 容器当 ext4 |
目录树全空 + 大量 I/O 错误 |
误判为"已擦除"而结案 |
| 把 BitLocker 卷当 NTFS |
文件名全乱码 |
误判"文件已损坏" |
| 偏移少加一个扇区 |
偶尔能出目录名 |
最危险:部分正确、部分错误,结论互相矛盾 |
| 用 FAT 解析器读 exFAT |
只能列出根目录 |
漏掉深层数据 |
最后一条最危险:部分解析成功会给人"已经检查过"的错觉。判断依据应是目录数量和文件数量是否合理,而不是"命令有没有报错"。
三、操作步骤
3.1 第 1 步:确认镜像本身
# 镜像格式、扇区大小、总容量
img_stat /evidence/DigiForensics.dd
# 分配 E01 → raw
ewfverify /evidence/DigiForensics.E01 # 先验证完整性
ewfexport -t raw -u /tmp/ewf1 /evidence/DigiForensics.E01 -f /work/DigiForensics.dd
img_stat /work/DigiForensics.dd
3.2 第 2 步:解析分区表(卷层)
# MBR/GPT 通吃
mmls /work/DigiForensics.dd
# 输出示例(务必逐列记录)
# Slot Start End Length Description
# 00: Meta 0000000000 0000000000 0000000001 Primary Table (#0)
# 01: ----- 0000000000 0000000062 0000000063 Unallocated
# 02: 00:00 0000000063 0009510479 0009510417 NTFS (0x07)
# 03: ----- 0009510480 0009514259 0000003780 Unallocated
记录规范:把 mmls 完整输出作为附件存档,后续所有操作都引用 Slot 与起始扇区。
3.3 第 3 步:逐卷判定文件系统类型
对每个非 Unallocated 的 Slot 逐一执行:
# 以 Slot 02(起始扇区 63)为例
fsstat -o 63 /work/DigiForensics.dd
# 关键字段:
# NTFS → File System Type: NTFS / MFT Cluster / Boot Sector Cluster
# ext4 → File System Type: Ext4 / Block Size / Inode Size / Journal Inode
# FAT → File System Type: FAT / Cluster Size / Root Directory Sector
# APFS → APFS 容器需用专门工具(见 06 篇)
若 fsstat 报"Cannot determine file system type",按下列顺序排查: