NTFS 给取证分析师准备了三大元数据痕迹,而最稳妥的浪费一天的方法,就是为你真正面对的问题去读错了那一个。简短的版本:
| 痕迹 | 记录什么 | 时间跨度 | 粒度 | 位置 |
|---|---|---|---|---|
$MFT | 每个文件和目录的当前状态 — 名字、大小、时间戳、父级 | "此时此刻"加上最近删除的表项 | 按文件 | MFT 表项 0 |
$UsnJrnl:$J | 每次文件创建/删除/重命名/修改的循环日志 | 数天到数周 | 按操作 | \$Extend\$UsnJrnl:$J(备用数据流) |
$LogFile | NTFS 用于崩溃恢复的事务日志 — 元数据写入的原始 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(进程与对象事件)、Prefetch 与 AmCache(执行证据)、Shimcache(程序在某时点曾运行过)、注册表 hive、用于用户打开过文件的 LNK 文件 与 jump lists、浏览器历史、用于资源使用的 SRUM,以及 RecentFileCache 搭配使用。
延伸阅读
- Microsoft Learn — Master File Table 与 Change Journals。
- Brian Carrier, File System Forensic Analysis — NTFS 内部结构的书面级参考,至今仍然是首选。
- Joachim Metz,
libfsntfs文档 — 关于$LogFile内部最详细的开放参考。 - SANS DFIR — Windows Forensic Analysis 海报 是单页过塑参考,把整个痕迹栈摆在同一张纸上。