搜索全站

输入至少 2 个字符,查找相关内容。

↑↓ 选择 Enter 打开Esc 关闭

文件雕刻与签名恢复

文件雕刻(file carving)是在完全不使用文件系统元数据的前提下,仅凭文件内容的字节模式(魔数与结束标记)从磁盘中"切"出文件。 它解决的问题很具体:文件的目录项被删了、文件系统损坏了、元数据库被格式化了——但数据块还在盘上,而且它们的字节排列没变。

最后更新 2026-10-09版本 v2.0维护 DigiForensics查看历史 1

一、概述

文件雕刻(file carving)是在完全不使用文件系统元数据的前提下,仅凭文件内容的字节模式(魔数与结束标记)从磁盘中"切"出文件。 它解决的问题很具体:文件的目录项被删了、文件系统损坏了、元数据库被格式化了——但数据块还在盘上,而且它们的字节排列没变。

为什么值得做:文件系统层面的删除只改元数据,数据块的内容在真正被覆盖之前是完好的。这给了一个"绕过文件系统直接读数据"的路径。

在文件系统被恶意破坏、加密卷已解密、数据库被清空的场景下,carving 常常是唯一的路径。

但必须先建立一个正确的心理预期,否则整个流程会走向错误的结论:

carving 产出的是"符合某格式签名的字节区间",与完整文件有本质区别。这道差距就是本篇要讲透的核心。

差距具体体现在四处:

丢失的东西 后果
原始文件名 产物叫 00012345.jpg,你永远不知道它原来叫什么、在哪个目录、谁改过它
时间戳 文件系统里那个文件"何时创建、何时修改"完全不可得(除非格式内嵌)
边界精度 尾簇残留、填充字节都会导致多切或少切,哈希必然与原文件不同
上下文 它属于哪个用户、哪个案件、哪个软件——这些恰恰是取证最需要回答的

工具宣传里几乎不提最后这条证据效力问题,只强调"恢复了多少个文件"。另外,恢复出来的图片能不能当庭出示,取决于 EXIF 是否完整——尾标记切不准时 EXIF 往往跟着一起坏掉,剩下的只是一个能看的 JPEG。

本篇把它作为核心:carving 产物是重建产物(reconstructed artifact),不是原件(original),在证据提交和司法鉴定中有明确的效力边界。

在取证流程中的位置:本篇是恢复手段,不是默认路径。它排在最后——只有在元数据路径全部走不通(文件系统损坏、目录项被清除、$MFT 不可解析)时才开始,第一步永远是"先尝试定位元数据"。定位策略上,先从未分配空间与空闲块找起,而不是全盘 carve:全盘 carve 会把系统文件也切出来,产出量淹没真正相关的东西,这是 2.4 与 2.7 要讲的事。上游依赖是 文件头与文件签名(魔数与结束标记的判据表)与 NTFS 结构与 MFT 解析(元数据可用时优先走元数据);未分配空间的提取方式见 只读挂载与安全接入;产物后续的去重与验证按 近似匹配与模糊哈希 做。

本篇处理的证据形态,carving 的输入不是文件而是字节区间,按来源分三类:

来源 特点 注意
未分配空间 / 空闲块 已删除文件残留的聚集区,carving 的主战场 内容可能交错,同一文件的多段可能不连续,尾簇常有残留数据
镜像的连续原始区域 全盘 carve 的对象 会连系统文件一起切出来,需要按路径与内容过滤
分页文件与内存镜像 内存里存的是解页后的内容,跨页/跨页表边界的文件内容会被打断 必须按页大小对齐处理,否则 carve 出的大文件全是碎片

按格式分,产物能否成功取决于该格式有没有可用签名:有魔数 + 有尾标记的(ZIP、DOCX/XLSX/PPTX、PDF、GZIP、JPEG)基础 carving 就能切;只有魔数没有尾标记的(TIFF、MP4、部分容器格式)必须靠大小约束、页结构或邻接关系推断,切不准的概率很高;完全无签名的(纯文本碎片、部分数据库页)只能靠特征提取(bulk_extractor 那条路子),这时产物连"是不是一个完整文件"都无法判断。

某类文件的内容在这块盘上是否还存在、大致的字节范围与内容片段、删除前的部分内容(聊天记录片段、文档段落、照片缩略)、在元数据彻底不可用时保住一部分可读内容。

"carve 到了"不等于"这就是原来的文件"——没有文件名、没有路径、没有归属用户、没有原始时间戳(除非格式内嵌,比如 JPEG 的 EXIF、部分 PDF 的元数据),也就无法建立它与案件事实的联系。哈希必然与原文件不同,所以 carve 产物的哈希不能用于威胁库比对,只能用于去重和一致性自检。阴性结果覆盖范围极窄:"在未分配空间 carve 中未见某格式"只说明那块区域里没有该格式的完整签名区间,被覆盖、被分区表划走、不带签名的格式、部分残留的碎片,全都在覆盖之外。carving 也无法证明某个文件从未存在——它只能证明"这些字节现在不在可搜索的区域里"。而且 carving 本身会污染证据:全盘 carve 会产生海量与案件无关的产物,报告里堆上几千个无归属的碎片,会让真正相关的两三个文件被淹没。

读者前提:需要能读十六进制并理解魔数在文件头的具体位置(不是"看到关键字"就行,得知道偏移与字节序);需要理解未分配空间、簇、slack 空间这些概念,明白文件系统删除只改元数据而数据块还在;需要接受"产物哈希与原文件必然不同"这个事实,并能在报告里按标准表述写清楚它是重建产物——不具备这个判读能力的读者,carve 出来的文件很容易被当成原件上报,这是本领域最贵的错误之一。

二、核心原理

2.1 carving 的两种策略

策略 A:头尾定界(header/footer carving)——foremost / scalpel
  扫描 → 找到头 FF D8 FF → 找到下一个尾 FF D9 → [头, 尾] 切出
  优点:快、简单、边界较准
  缺点:需要尾标记;无尾标记的格式无法用

策略 B:定长切分(size/fragment carving)——photorec
  扫描 → 找到头 → 依据该格式的"典型大小/结构规则"向后切
  优点:不需要尾标记,能处理无尾格式
  缺点:边界靠猜,必然过度切分

策略 C:特征提取(feature extraction)——bulk_extractor
  不追求"文件",只提取"特征":邮箱、URL、IP、卡号、EXIF 坐标
  优点:能发现不成其为文件的痕迹;能钻进压缩包内部
  缺点:产出是文本/坐标列表,不是可提交的文件

策略选择的实务逻辑:

目标 选择
恢复有明确头尾的图片/文档 A(foremost/scalpel)
恢复无尾标记的格式(Office、文本、碎片) B(photorec)
找联系方式、URL、地理位置、密钥线索 C(bulk_extractor)
元数据完好,只是想批量导出 都不用,用 tsk_recover(见 2.7)

2.2 基础 carving 的三大局限(必须写进报告)

这是本篇的核心内容。 每一条都直接决定 carving 结论能走多远。

局限一:碎片化(Fragmentation)——原理上无法克服

carving 假设"文件的字节在盘上是连续的"。一旦文件被碎片化存放到不连续的簇上,这个假设就不成立了。

真实存储(4 个碎片):
簇 1024 [文件前 8 KB]  簇 99840 [中间]  簇 55 [中间]  簇 300200 [末尾]

carving 看到的:
簇 1024 [文件前 8 KB]  簇 1025 [其他文件的数据]  ← 边界就在这里断了
                          工具在此处判定"文件结束",产出截断的残片

问题的严重性要算一下:现代文件系统普遍碎片化。一个 20 MB 的视频几乎必然是碎片化的——它有 4 万个簇,分散在整个卷上。基础 carving 对它的恢复率接近于零。

必须说清的技术事实:这不是"工具不够好"的问题,是 carving 这种方法论本身的限制。 唯一的补救是碎片重组(file carving with defragmentation)——利用已知的前后片段特征(如 JPEG 的重启标记、MP4 的 moov 原子、ZIP 的局部头)尝试重新拼接。但重组结果的正确性无法证明,只能靠内容合理性判断。

局限二:内容被覆盖——数据真的没了

删除文件后,其数据簇进入空闲池。后续任何写入都可能覆盖它们。 覆盖一旦发生,原内容彻底消失,没有任何技术手段可以恢复(除非涉及闪存物理层的磨损分析,属专业实验室范畴)。

情形 可恢复性
刚删除,未做大量写入 可恢复
删除后设备持续使用数天 大概率已被覆盖
删除后被 TRIM/闪存 GC 几乎必然已丢失

特别提醒闪存设备:手机、平板、现代 SSD 的 TRIM 与垃圾回收(GC)会在删除后很短时间内回收块——eMMC/UFS 上的 TRIM 可能几秒内就完成。这是"从手机恢复已删照片"成功率远低于电脑的根本原因,不是技术问题。

评估必做:carving 之前必须问清**"删除后设备使用时长"**。这直接决定预期,不能事后才发现。

局限三:无尾标记或无格式 —— 根本识别不了

不是所有数据都有可识别的魔数。 这些内容 carving 完全无能为力:

类型 为什么识别不了
纯文本、CSV、代码 无魔数(file 报 ASCII text,靠内容而非签名)
SQLite 数据库片段 有魔数,但必须完整才能解析,半截库文件打不开
未写完的文档 无完整结构
加密后的数据 密文无魔数(见 crypto)
已损坏/被部分覆盖的文件 头可能已被覆盖

实务结论:carving 的召回率远低于 100%,且无法事先知道漏了什么。 报告里绝不能写"已恢复所有删除的文件"。

2.3 证据效力:为什么哈希必然不同(本篇的灵魂)

这是最容易被忽视、后果却最严重的问题。核心事实只有一句:

carving 产出的文件,其哈希值必然与原始文件的哈希值不同——只要文件有任何碎片化、任何边界误差。

哈希是"逐字节"的指纹。 只要有一个字节对不上,sha256sum 就完全不同。

这意味着 carving 产物无法通过"与已知原文件哈希比对"来证明其身份。

造成哈希不同的五个具体原因:

原因 机制 例证
① 尾部过度切分 carving 切到下一个魔数之前,包含了同簇/后续簇的残留数据 应为 48 KB,实际切出 64 KB(多 16 KB 垃圾)
② 头部过度切分 头向前一个无关结构之后开始,包含了前导垃圾 文件前多出 1 KB 无关数据
③ 碎片化截断 文件分散在多个簇,工具在第一个非连续处停止 应为 20 MB,得到 8 KB 片段
④ 填充/对齐字节 文件系统可能填充簇尾,carving 把填充也算进文件 末尾多出 00 填充
⑤ 原始文件本身带元数据 部分格式在文件尾存储私有元数据,carving 可能截掉或截多 PDF 的增量更新区、ZIP 的注释区

一个具体的对照。这是必须在报告中呈现的形态:

原始文件(真实内容 48,000 字节,存于 12 个簇,末簇只用了 9,056 字节):
┌──────────────────────────────────────────────┐
│ [真正的 48,000 字节内容]        │ 9,056 字节  │ 9,600 字节的簇
│                                  │ 残留 9,600 │ ← 下一个文件的数据
└──────────────────────────────────────────────┘

foremost 切出的结果:
┌──────────────────────────────────────────────┐
│ [48,000 字节内容]                │ 9,600 字节 │ ← 尾部混入了别的文件
└──────────────────────────────────────────────┘
   实际大小 = 57,600 字节

sha256sum 原始文件  = a3f5...9c2e
sha256sum carving件 = 7b1d...4e88     ← 完全不同!无法与原文件哈希匹配

因此,"用 carving 结果的哈希去和嫌疑人电脑上的文件哈希比对"是行不通的——两者本来就不可能相等。

那 carving 产物到底是什么?

法律与取证实务中的定位是"重建产物"(reconstructed artifact):

维度 原件(original) carving 产物(reconstructed)
字节级同一性 ✅ ❌ 边界必然有偏差
哈希 唯一、权威 只是这个重建件的指纹,不能代表原文件
文件名 已知 完全丢失
时间戳 完整 丢失(除非格式内嵌)
归属/上下文 完整 完全丢失
可提交为"该文件的原件"吗 ✅ ❌ 不能

正确的处置方式(必须写进报告):

  1. 明确标注性质:"以下文件为 carving 重建产物,非原件;其哈希值仅代表该重建件本身。"
  2. 记录完整坐标:文件名(工具生成)、在镜像中的起始偏移与长度、提取时间、工具版本、配置(审计文件)。
  3. 内容层面的结论可以采信,但必须表述为内容特征而非文件身份:"该区域存在一段 JPEG 图像数据,可解码为 1920×1080,内容为……"——而不是"恢复了原始照片 X.jpg"。
  4. 绝不与原件哈希混用:不要把 carving 产物的哈希填进"证据文件哈希表"而不加区分。
  5. 作为线索而非结论:carving 的价值是发现(发现这里有可疑内容),后续需要用其他证据(元数据、日志、供述)来印证它的身份和来源。

一句话总结:carving 告诉你"盘上这里有东西",但它无法告诉你"这东西曾经叫什么、属于谁、何时产生"。 后者必须靠文件系统元数据、用户活动记录、时间线交叉分析来补(见 computer 与 fundamentals 板块)。把 carving 产物当原件提交,是取证流程中性质最严重的错误之一。

2.4 目标选择:carve 什么、carve 哪里

盲目对整盘 carve 会产出海量垃圾(GB 级 jpeg),淹没真正有价值的内容。必须有策略:

(1)按目标格式(最基本)

foremost -t jpg,pdf,doc -i /work/DigiForensics.dd -o /evidence/carve

(2) carve 未分配空间(而非整盘)

整盘 carve 会把当前存在的所有文件也切一遍——它们本身完好,用 tsk_recover 导出更完整(保留文件名和路径)。carve 的价值只在于捞出"元数据已失、但数据还在"的东西。

用 blkls 提取未分配空间,再对这块 carve

blkls -o 2048 /work/DigiForensics.dd > /evidence/unalloc.dd

然后对 unalloc.dd carve

foremost -t jpg -i /evidence/unalloc.dd -o /evidence/carve-unalloc

这是很多流程做错的一步:直接对整盘 foremost,然后花大量时间筛选"哪些是已删除的"——实际上当前文件用 tsk_recover 导出(保留完整元数据),carve 只管未分配空间。 两者定位不同、产物性质不同,报告里必须分开呈现。

(3)按格式特性选择区域(进阶,参考 07 的段类型分析)

大媒体文件(视频)在碎片少的大簇区域;小文件(日志、配置)在热区。F2FS 上可按段类型、C/APFS 上可按 CoW 旧块来缩小范围。

2.5 未分配空间:carve 的主战场

分区空间构成:

┌──────────────────┬──────────────────┬──────────────────┐
│  已分配(文件占用)│  未分配(空闲池)   │ 元数据区          │
│  → 用 tsk_recover  │  → ★ 用 carving  │ → 用 fsstat 解析  │
│  (保留文件名)     │  (数据还在这)    │                  │
└──────────────────┴──────────────────┴──────────────────┘
       ↓
  被删除文件的数据落在这里,直到被新数据覆盖

提取未分配空间的工具:

TSK:提取未分配簇(blkls = block listing)

blkls -o 2048 /work/DigiForensics.dd > /evidence/unalloc.dd

或用 fls 的未分配视图(slack 等)

注意区分"未分配"与"Slack":Slack 是已分配簇的尾部未使用空间(文件大小小于簇大小的剩余),blkls 默认也会导出。Slack 里常有小文件的残片(如被删除的小配置、注册表碎片),有时比整个未分配池更有针对性。

未分配空间的数量本身是取证指标:一个正常使用一段时间的系统,未分配空间占比应在合理范围;如果几乎为 0,可能说明设备刚做过 TRIM/安全擦除,或被反取证工具清理过。

2.6 分页(page)问题:内存镜像与大文件的特殊处理

"分页"在 carving 语境下指两类不同的分页问题,容易混淆:

(1)工具内部的分页读取:大镜像不可能一次读入内存,工具按固定块(如 16 MB)分块读取,逐块扫描。跨块的魔数(正好在块边界)必须被正确处理,否则会漏检或重复。

(2)运行分页文件(page file):内存镜像和 Windows/Linux 的交换文件(pagefile.sys、swapfile.sys)是分页存储的——内存内容被切块写入这些文件。这与普通文件不同,carving 需要特殊处理:

Windows 交换文件(不释放内存内容 → 大量已关闭程序的残留)

icat -o 2048 /work/DigiForensics.dd 263 -r > /evidence/pagefile.bin

然后对 pagefile.bin carve

foremost -t doc,zip,pdf -i /evidence/pagefile.bin -o /evidence/carve-page

swap 文件的特殊价值:swap 里可能有"已加密卷的明文"——用户在 BitLocker 卷中打开文件,数据在内存中被加密前曾驻留 swap。这是破解加密卷的一条现实途径(见 crypto 板块)。

bulk_extractor 对分页有专门支持:

-G <页大小>:指定分页大小(字节),让工具在正确的页边界上匹配

(许多"特征"跨页出现,页大小不对会导致漏检)

bulk_extractor -o /evidence/be-out -G 4096 /work/DigiForensics.dd

分页文件 carving 的注意事项:

事项 说明
不按"文件大小"切 交换文件里的"内容"没有完整文件边界,按魔数切会切出大量碎片
关注"散落"的证据 关键可能只是一个 URL、一段命令行——用 bulk_extractor 而非 foremost
重复是常态 同一页面多次换入换出会产生重复,必须去重
不要期待完整性 绝大多数"文件"是残片,任何"恢复出完整文件"的表述都需极度谨慎

2.7 定位策略:优先元数据,其次 carving

这是流程层面的核心建议:carving 不是万能钥匙,它是文件系统路径失败后的兜底。正确顺序:

第 1 优先:文件系统元数据完整时
  tsk_recover(保留文件名、路径、时间戳)
  ↓ 失效?↓
第 2 优先:文件系统部分损坏时
  fls/istat/icat 定向提取已删除项(保留尽可能多的元数据)
  ↓ 失效?↓
第 3 优先:文件系统完全不可解析时
  carving(★ 只有内容,丢失全部上下文)

tsk_recover 的正确用法(很多流程直接跳过它跑 foremost,是本末倒置):

只提取已删除文件(默认行为)

tsk_recover -o 2048 /work/DigiForensics.dd /evidence/recover-deleted/

提取所有文件(含已分配)

tsk_recover -e -o 2048 /work/DigiForensics.dd /evidence/recover-all/

保留目录结构(默认行为,优于扁平化)

tsk_recover 产物与 carving 产物的证据效力完全不同:前者保留了原始文件名、路径、部分时间戳(因为这些来自未被覆盖的元数据),其性质接近原件;后者是纯重建产物。报告里必须分别标注,不能混为一谈。


三、操作步骤

3.1 第 1 步:评估可行性(决定是否 carve)

carve 之前必须先回答四个问题,否则可能在无意义的工序上消耗大量时间:

① 文件系统是否还能解析?(决定优先用 tsk_recover 还是 carving)

fsstat -o 2048 /work/DigiForensics.dd | head -20 fls -o 2048 /work/DigiForensics.dd | wc -l # 能列出多少项

② 未分配空间有多大?(决定 carve 的产出规模)

blkls -o 2048 /work/DigiForensics.dd | wc -c # 字节数

若为 0 → 设备可能已 TRIM / 擦除,carving 无意义

③ 卷层是否有未分配区间(另一处藏身点)

mmls /work/DigiForensics.dd # 看 Unallocated 行

④ 元数据优先:能直接恢复的先恢复

tsk_recover -o 2048 /work/DigiForensics.dd /evidence/recover-deleted/ find /evidence/recover-deleted -type f | wc -l

决策表:

情况 策略
fls 能列出大量文件,blkls 体积正常 优先 tsk_recover,carve 作为补充
fsstat 报错或文件数为 0,但 blkls 有大量数据 文件系统损坏 → 以 carve 为主
blkls 输出接近 0 数据已被覆盖/TRIM → carve 无用,应转向日志、云端、其他设备

3.2 第 2 步:提取未分配空间并 carve

① 提取未分配空间

blkls -o 2048 /work/DigiForensics.dd > /evidence/unalloc.dd ls -lh /evidence/unalloc.dd

② foremost 雕刻(-i 输入,-o 输出目录,-t 类型,-v 详细)

注意拼写是 foremost(前置 f),不是 formost

foremost -t jpg,pdf,doc,zip,png -i /evidence/unalloc.dd -