USN 日志 vs $MFT vs $LogFile:对应哪个问题该用哪个 NTFS 痕迹?

三个 NTFS 元数据痕迹的对照参考 — 每一次 Windows 取证调查最终都会触及它们。各自记录什么、不记录什么,以及何时取用哪个。

作者: 阅读约 2 分钟

NTFS 给取证分析师准备了三大元数据痕迹,而最稳妥的浪费一天的方法,就是为你真正面对的问题去读错了那一个。简短的版本:

痕迹记录什么时间跨度粒度位置
$MFT每个文件和目录的当前状态 — 名字、大小、时间戳、父级"此时此刻"加上最近删除的表项按文件MFT 表项 0
$UsnJrnl:$J每次文件创建/删除/重命名/修改的循环日志数天到数周按操作\$Extend\$UsnJrnl:$J(备用数据流)
$LogFileNTFS 用于崩溃恢复的事务日志 — 元数据写入的原始 before/after 镜像数分钟到数小时按元数据事务\$LogFile(MFT 表项 2)

接下来是我实际在用的决策树,以及每一种痕迹单独使用时为什么会让你失望。

$MFT — "现在,什么存在"

Master File Table 是 NTFS 的脊柱。每个文件或目录至少有一个 1024 字节的表项,里面有 $STANDARD_INFORMATION、一个或多个 $FILE_NAME 属性,以及指向实际内容的 data runs。

当问题如下时,选 $MFT:

  • 这个卷上现在存在什么,包括尚未被复用的、最近被删除的表项。
  • 某个具体文件的四个 NTFS 时间戳($STANDARD_INFORMATION$FILE_NAME 中的 M/A/C/B)是什么。
  • 一个表项仍然分配的、已删除文件的字节能否恢复。
  • 一条只携带父引用号的记录的完整路径 — 这正是本页解析器在你也把 $MFT 拖入时解析 USN 记录的方式。

无论怎么瞪眼,它都不会告诉你的事:

  • 上周二 14:32 那个文件发生了什么。这四个时间戳是末态,不是历史。它们告诉你文件何时被创建、何时被最后触碰。但不会告诉你它被重命名、又改回来、被截断、被覆盖、被删除,然后同一 MFT 表项又被新文件复用了。

工具:Eric Zimmerman 的 MFTECmd 是事实上的解析器。Omer BenAmram 的 mft Rust crate 与 David Kovar 的 analyzeMFT Python 脚本覆盖了开源一侧。

$UsnJrnl:$J — "发生了什么,以什么顺序"

Update Sequence Number 日志记录卷上发生的每一次创建、删除、重命名、截断、属性变更和关闭。背景方面,入门文章 介绍磁盘格式,reason 码文章 是逐比特的字段参考。

当问题如下时,选它:

  • 这个文件在被删除之前的生命周期(包括重命名)是什么。
  • 这个卷上是否有什么东西批量加密了文件 — 见 勒索软件检测
  • 是否有什么东西批量暂存并归档文件用于外泄 — 见 外泄检测
  • 时间戳是否被改过 — 见 timestomping
  • 14:00 到 16:00 之间用户在做什么 — 见 活动时间线重建

它不会告诉你:

  • 谁做了什么。没有用户、进程、命令行。需与 Security.evtx 4663(仅在配置了 SACL 时)或 Sysmon 事件 11 关联。
  • 任何文件的内容。日志记录数据流发生过变化,而不是之前那里有哪些字节。
  • 早于环形缓冲区窗口的任何内容。默认从精简客户端上的 ~10 MB,到一台合理大小的服务器上的 1 GB+,对应数天到数周的历史。

工具:Airbus CERT 的 usnrs、PoorBillionaire 的 USN-Journal-Parser、Eric Zimmerman 的 MFTECmd(它也解析 $J),以及本页的 WebAssembly 解析器。

$LogFile — "NTFS 即将做什么"

这是 NTFS 用于崩溃恢复的元数据日志。它记录每一次元数据写入 — INDEX_ALLOCATION 更新、属性变更、MFT 表项重写 — 的 before/after 镜像。格式未文档化,但已有非常充分的逆向工程;Joachim Metz 的 libfsntfs 是最详尽的开放参考。

当出现以下情况时取它:

  • 一个文件在相同的几千条事务内被创建并被删除,而父目录条目已经被覆盖。$LogFile 可能仍保留带有末端名与父级的"before"镜像。
  • 你怀疑直接的 $MFT 篡改。即便事后可见状态干净,$LogFile 也会记录原始写入。
  • 日志太稀疏(太小或最近被轮换过)无法覆盖关注的瞬间,但事件发生在最近一小时内。

它不会给你:

  • 轮换窗口之外的任何东西。$LogFile 很小且被高频重用。在繁忙的文件服务器上,整段事务历史可能在不到一小时内就翻完一轮。
  • 文件内容。before/after 镜像只是元数据。

工具:Jonas Schicht 的 LogFileParser 以及任何基于 libfsntfs 构建的解析器。

我实际在用的决策树

你知道是哪个文件吗?
├── 是 → 想要当前状态? → $MFT(路径、时间戳、大小)
│        想要历史?      → 先 $UsnJrnl,极近的过去用 $LogFile
└── 否 → 时间窗?
         ├── 最近几分钟  → $LogFile(粒度最细)
         ├── 最近几天/几周 → $UsnJrnl(信噪比最好)
         └── 很久以前    → 仅 $MFT,准备好接受末态时间戳

是否要在大量文件之间做关联?
└── 三者中,$UsnJrnl 是唯一具备可排序的按操作时间线的痕迹。

文件被删除,而你需要证明它存在过?
└── 先 $UsnJrnl(FileDelete 记录携带父引用和时间戳)
    删除较新时用 $LogFile 兜底
    仅当表项尚未被复用时用 $MFT

真正的工作发生在把它们组合起来的时候

三种痕迹组合得很好,这部分在需要之前没人强调。

$MFT + $UsnJrnl 是经典搭配。MFT 提供用于路径解析的目录树;日志提供操作历史。本页解析器在你把两个文件都拖进来时,会为每条日志记录自动解析完整路径。同时获取它们;十之八九能省下一次返回再取的过程。

$LogFile 是兜底。当日志太小,无法覆盖关注瞬间;或者你怀疑有人直接篡改 MFT 时 — 你就该伸手去取它。

更广的语境下,把三种 NTFS 痕迹与 EVTX(进程与对象事件)、PrefetchAmCache(执行证据)、Shimcache(程序在某时点曾运行过)、注册表 hive、用于用户打开过文件的 LNK 文件jump lists浏览器历史、用于资源使用的 SRUM,以及 RecentFileCache 搭配使用。

延伸阅读