← 返回博客

证明一份文件曾经存在——尽管它现在已经不在磁盘上

· 阅读 2 分钟

取证工作常常围绕一个问题展开:这个文件曾经在这台电脑上吗?不是"它现在在不在"(那是 dir 的工作)。更难的问题:我们能不能证明它昨天、上周、去年在过?对 NTFS 卷而言,答案通常是能,而 $MFT 是最强的单一来源。常常文件的内容也能一并恢复。

下面是从实务者视角看:仅凭 MFT 元数据能证明什么、journals 又能补上什么佐证,以及自信的结论会在何处于审阅中崩塌。

删除中保留下来的东西

NTFS 上一份文件被删除时,记录头中的 IN_USE 位被清掉,父目录的索引条目被移除。记录本身留着,承载:

  • $FILE_NAME:原始文件名以及父目录的 MFT 记录引用。
  • 八个时间戳$STANDARD_INFORMATION 中四个,$FILE_NAME 中四个),凝固在删除瞬间。
  • 文件数据的 逻辑大小与物理大小
  • 对于小文件($DATA 不超过约 700 字节),整份文件内容 内联存于记录中。见 resident data
  • 对于较大文件,曾承载数据的簇的 runlist。那些簇是否仍保留原始字节并不确定。
  • 记录的 序列号,可以证明你看到的是当时住在那一槽位的那个文件(而不是后来的住户)。

一条已删除的 MFT 记录:$FILE_NAME = secret-plan.docx,父引用解析到 \Users\bob\Documents,SI created 为 2024-11-03T14:02:11Z,就能表明那一天在那个目录中存在过这样名字的文件。记录就是证据,而该证据在某种意义上由 NTFS 自己签名——它是文件系统驱动写下的。

让证据可辩护的属性

让 MFT 记录在有人试图打破你案件的审阅中立得住,靠这三条性质:

  1. NTFS 自己写,而非用户。 记录无法通过正常 Windows API 让用户编辑。被告无法可信地宣称单条记录是被栽赃的,除非他们主张整份 $MFT 都被伪造,而结合下文的 journal 交叉校验,这门槛非常高。
  2. 八个时间戳互相校验。 操控通常会留痕。SI 改了 FN 没改是教科书式的 timestomping 签名;见 四个 MFT 时间戳。SI created 早于 FN created 在自然条件下不可能出现。
  3. $UsnJrnl$LogFile 佐证。 如果 $MFT 说文件在时刻 T 创建,USN journal 应该在同一时刻记录到 FILE_CREATE。不一致本身就是证据(要么是伪造,要么是解析器错误;无论哪种都值得追下去)。
  4. VSS 快照是独立的。 删除前的快照里有一份 MFT 副本,其中文件是 IN_USE=1。该快照在已知时刻由 VSS 写入。两个独立证人(在线 $MFT + 快照 $MFT)指向同一份文件,比任一单独的证据强得多。见 Volume Shadow Copy 与 $MFT

第四点值得多说几句。在严肃案件里我总会去找 VSS 快照。它把一次观察变成一系列在不同时间点上的观察,并且由与在线 MFT 完全不同的代码路径写入。要同时一致地伪造两者很难。

仅凭 $MFT 还无法证明的事

MFT 证明文件在某个特定目录、某个特定时间存在,并具有记录中记录到的特定大小与时间戳。但它无法证明:

  • 谁创建或访问了它。 这需要安全事件日志(在 SACL 已配置时的 4663、Sysmon Event ID 11/15,或在文件被命令行命名时的带命令行的 4688 进程创建)。
  • 是哪个程序生产了它。 PrefetchAmcacheShimcache 在此有用。如果启用了 Sysmon Event ID 1,那是最佳证据。
  • 对较大文件,文件里有什么内容——除非你恢复了数据簇。常驻文件可直接给出字节;非常驻文件则需要簇 runlist 仍指向未分配、未覆盖的空间。
  • 用户是否真的打开过它。 这种情况下,跳转列表LNK 文件RecentFileCache 更有用。
  • 除目录所有者外是否还有人看过它。 这需要 ACL 审计日志。

完整答案通常要把 MFT 与周边工件融合起来。MFT 之所以是基石,是因为没有它别的碎片就没法落地。对 secret-tool.exe 的 Prefetch 命中是有意思的;同一个命中如果再配上一条 MFT 记录,表明 secret-tool.exe 在同一分钟被某进程丢进 \Temp\,而该进程的 Sysmon Event ID 1 也出现在时间线里,那就是决定性的。

能在审阅中立住的工作流程

  1. 采集 $MFT$UsnJrnl:$J$LogFile,以及所有 VSS 快照。 对一切做哈希(SHA-256)。把采集时间记录下来。
  2. 解析 MFT。 找出目标文件对应的记录,无论它是活的还是已删除的。提取序列号、父引用、所有八个时间戳、若有常驻 $DATA,否则提取簇 runlist。
  3. 解析父引用:沿父记录跳,循环直到走到记录 5(根)。所得到的链就是目录路径。把它与你从日志或证人陈述中获得的任何路径做交叉比对。
  4. 与 USN journal 交叉比对。 对相同的记录/序列对,列出每一条 USN 条目。FILE_CREATE 给你最初创建,FILE_DELETE 给你删除。中间的原因就是文件的历史。
  5. 与 VSS 快照 MFT 比较。 每一份快照里同一记录的副本就是一个 checkpoint。如果三份快照都显示该记录 IN_USE=1 且时间戳一致,而在线 MFT 显示 IN_USE=0,那么你就有四位独立证人同意文件存在过、一位证人指证它被删除。
  6. 把你排除的不可能性记录下来。 SI/FN 不一致已检查。序列号一致。快照时间戳协调。被告方要推翻你的结论,就必须把这些都解释清楚。

最后一步是把发现与论证分开的关键。把你检查了什么、排除了什么列出来,会让推理链条变得可见。

容易咬人的特例

硬链接。 一个带多个硬链接的文件分散在多个 $FILE_NAME 属性中。删掉一个链接只是去掉那个名字;文件仍然存在。请确认你追踪的那次删除确实对应着文件消失,而不是仅仅去掉一个名字。

删除前被改名的文件。 一些 dropper 会在删除前立刻把暂存文件改名为无害名字,希望残留的 $FILE_NAME 看起来人畜无害。USN journal 保留 RENAME_OLD_NAME / RENAME_NEW_NAME 这一对。把它取出来。

记录槽位被复用。 已删除文件的槽位被新文件认领。当前 MFT 记录是序列 N 的新文件;journal 引用的是序列 N-1 的旧文件。用序列号来消歧。指向与当前不同序列的引用,指的是前任住户。

文件从未存在,而有人在撒谎。 不太常见,但值得知道。在 MFT、USN 与 VSS 之间一致地伪造纯元数据很难,但有管理员权限且决心很大的人有相应的工具。请寻找本应一致的工件之间的不一致。

延伸阅读

外部资源