处理 USN 日志最难的部分通常不是解析,而是先把文件搞到手。$UsnJrnl:$J 是备用数据流,不是普通文件,因此它不出现在资源管理器里,简单的 copy 不会带走它,robocopy 还会默默骗你说已经拿到了。这是按照你通常会遇到它的三个地方分门别类的实操指南:取证镜像、已挂载卷、运行中的机器。
你要找的东西
日志位于:
\$Extend\$UsnJrnl:$J
$Extend 是隐藏的 NTFS 元数据目录,$J 是 $UsnJrnl 元数据文件上两个备用数据流之一。另一个数据流叫 $Max,只保存日志配置的最大大小和 allocation delta — 没有任何记录。如果误抓了 $Max,你只会拿到几字节没用的配置。一定要选 $J。
Microsoft 在 Change Journals 参考 和 USN_RECORD_V2 结构参考 中文档化了布局。典型的 $J 在 30 MB 到几个 GB 之间,取决于安装时 fsutil usn 是怎么配置的。Windows 客户端默认约 32 MB;服务器常被设置为 1 GB 或更大。
抓 $J 时,顺手从同卷抓一份 $MFT。没有它,解析器只能给你末端文件名 — 每条记录绑定到父 MFT 表项号,而不是路径。两份文件都有,就能免费得到完整路径。
从取证磁盘镜像 (E01、dd、AFF4)
DFIR 中最常见的情况。选你已经持有许可证的工具。
FTK Imager (免费, GUI)
File → Add Evidence Item,打开镜像。- 一路展开到
[root]/$Extend/$UsnJrnl。 - 面板里
$J和$Max显示为兄弟行。右击$J并选择 Export Files。
"兄弟行"这个细节是新手常踩的坑:右击父文件并导出默认流(空的)很容易发生。请明确选中 $J 那一行。
X-Ways Forensics (商业)
展开 Root directory → $Extend → $UsnJrnl。$J 流出现在下面。Recover/Copy 把它写出来。同样的路径,同样的坑。
The Sleuth Kit (免费, 命令行, 跨平台)
大多数 Mac/Linux 分析师会用的工具。TSK 的 icat 是标准工具:
# 找到 $UsnJrnl 的 MFT 表项
fls -r -p image.dd | grep '\$UsnJrnl'
# 假设报告 inode 为 81,$J 流是属性 128-2:
icat image.dd 81-128-2 > UsnJrnl-J.bin
<inode>-<type>-<id> 三元组是 TSK 寻址备用数据流的方式。属性名以 :$J 结尾的那一个就是你要的;fls 的长输出会显示出来。
Velociraptor 与 KAPE
用于大范围分诊采集时,Velociraptor 的 Windows.NTFS.MFT 工件包和 Kroll 的 KAPE 都会自动抓日志。KAPE 用 target 文件(!ALL 或 USNJournal);Velociraptor 用 parse_ntfs 插件。两者也会同一轮一起抓 $MFT 和 $LogFile,这正是你真正想要的。
从已挂载的卷
如果镜像通过 Linux 的 ntfs-3g 或 Windows 的 Arsenal Image Mounter 只读挂载,元数据路径会以普通文件的形式出现,但大多数工具拒绝透明地读取备用数据流。
在使用 ntfs-3g 的 Linux 上,数据流可以直接读:
sudo cat '/mnt/image/$Extend/$UsnJrnl:$J' > UsnJrnl-J.bin
根据 streams_interface 挂载选项,:$J 可能会显示为单独的路径组件。先用 ls -la /mnt/image/\$Extend/ 检查一下。
从运行中的 Windows 主机
需要管理员权限和一个懂 NTFS 的读取器,因为 Windows 即便对管理员进程也屏蔽对元数据文件的普通访问。
RawCopy
Eric Zimmerman 的工具套件包含 RawCopy.exe(以及 RawCopy64.exe),它会绕过标准文件 API:
RawCopy.exe /FileNamePath:"C:\$Extend\$UsnJrnl:$J" /OutputPath:"D:\Out"
KAPE 的 USNJournal target 在底层用的就是它。
PowerForensics (纯 PowerShell)
如果不能落地二进制,PowerForensics 用纯 PowerShell 读取原始 NTFS 结构:
Import-Module PowerForensics
Get-ForensicFileRecord -Path 'C:\$Extend\$UsnJrnl' |
ForEach-Object { $_.GetContent() } |
Set-Content -Path 'C:\Out\UsnJrnl-J.bin' -Encoding Byte
内置 fsutil(用于验证, 而非提取)
fsutil usn 是日志受支持的控制面,但不是提取工具。它能读取、查询和删除记录,但不能流式输出完整的 $J 块。它的用处在于尝试提取之前先确认日志已启用且大小已配置:
fsutil usn queryjournal C:
Status: 0x00000000 且 Maximum Size 非零表示日志处于活动状态。0x80000005 表示已禁用,且在 fsutil usn createjournal 创建之前没有东西可提取。生命周期命令及其权限要求,请见 fsutil usn 参考。
提取之后
拿到 $J 文件后,把它拖到本页顶部的解析器中,或喂给你信任的任一离线工具:usnrs、PoorBillionaire/USN-Journal-Parser,或 Eric Zimmerman 的 MFTECmd(虽然名字这样,它也解析 $J)。
同时抓 $MFT(表项 0,与 $Extend 相邻的位置)。两份文件都提供后,上述任一解析器都能沿父引用链解析出每条日志记录的完整路径。没有 $MFT,你只能孤零零地读文件名。
抓取 NTFS 元数据时,如能顺便抓 $LogFile也不要客气。它很小,周转很快,在仅靠日志回溯不够的事件中,$LogFile 就是你的兜底。USN journal vs MFT vs LogFile 一文 说明了三者各自何时派得上用场。
常见陷阱
资源管理器复制。 对 $UsnJrnl 拖放复制的是默认无名数据流,空的。不会有警告。请改用上面的任一工具。
日志已禁用。 工作组机器和过度精简的镜像有时会把日志关掉。fsutil usn queryjournal 是最便宜的飞行前检查。
前导稀疏零字节。 日志是稀疏数据流。刚雕刻出的 $J 前几百兆字节可能全是零,直到第一条真实记录才出现。usnrs、本页解析器以及大多数其他工具会自动跳过。如果你从零写解析器,扫描第一个非零字,然后查找一个合理的 RecordLength 值。
环形缓冲区回卷。 根据活动量,日志可能已经回卷 — 较旧的条目消失了。文件中最小的 USN 告诉你该卷的历史实际能回溯多远。把它当作硬性下限。
误抓 $Max。 同一个父文件,但没有记录。如果你的雕刻得到一个很小的文件(几字节到几 KB),那基本可以确定你抓错了数据流。
延伸阅读
- Microsoft Learn — API 表面与生命周期请见 Change Journals。
- Eric Zimmerman 的工具文档 — RawCopy 与其余套件 端到端覆盖了活动主机采集。
- The Sleuth Kit 的
fls与icat手册页 — 镜像级提取的权威命令行参考。 - KAPE 文档 — Kroll 公开了包括
USNJournal和!BasicCollection在内的 target 文件;阅读 target 的 XML 是了解一次彻底分诊采集的最快方式。