处理 USN 日志最难的部分往往不是解析,而是先拿到文件。$UsnJrnl:$J 是一个 替代数据流,不是普通文件 — 资源管理器中看不到,简单的 copy 也搞不定。本文走过在三种现实场景下提取它的可行方式:取证磁盘镜像、已挂载卷,以及活动主机。
你要找什么
日志位于路径:
\$Extend\$UsnJrnl:$J
$Extend 是 NTFS 隐藏的元数据目录,$J 是元数据文件 $UsnJrnl 上的两个替代流之一 (另一个 $Max 只保存大小元数据)。Microsoft 在 NTFS 内部参考 和 USN_RECORD_V2 结构 中文档化了该布局。
真实世界的 $J 通常在 30 MB 到几 GB 之间,取决于 fsutil usn 的配置。
从取证磁盘镜像 (E01、dd、AFF4)
DFIR 中最常见的场景。
FTK Imager (免费,GUI)
- 打开镜像 (
File → Add Evidence Item)。 - 进入
[root]/$Extend/$UsnJrnl。 - 右键点击
$J数据流 → Export Files。
FTK Imager 把替代数据流当作一等公民 — 它们以与文件并列的行显示。务必选中 $J 那一行 (而不是 $Max)。
X-Ways Forensics (商业)
X-Ways 暴露同样的路径。在目录树中展开 Root directory → $Extend → $UsnJrnl,选中 $J 流并执行 Recover/Copy。
The Sleuth Kit (免费,CLI,跨平台)
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 寻址替代流的方式。你想要的 type/id 是名称以 :$J 结尾的那个属性 — fls 的长输出会显示它。
Velociraptor / KAPE
做大规模分析采集时,Velociraptor 的 Windows.NTFS.MFT artifact 与 KAPE 都会自动拉取日志。KAPE 使用 target (!ALL 或 USNJournal);Velociraptor 使用 parse_ntfs 插件。
从已挂载卷
如果镜像被只读挂载 (Linux 上的 mount -t ntfs-3g,或 Windows 上的 Arsenal Image Mounter),路径会显示成普通文件,但多数工具不会透明地读取替代流。
Linux 上配合 ntfs-3g,可以直接读取流:
sudo cat '/mnt/image/$Extend/$UsnJrnl:$J' > UsnJrnl-J.bin
视 streams_interface 挂载选项而定,:$J 可能作为单独的路径分量出现而非后缀 — 用 ls -la /mnt/image/\$Extend/ 确认。
从活动 Windows 主机
你需要管理员权限和懂 NTFS 的读取手段,因为 Windows 阻止对元数据文件的普通访问。
使用原始卷读取的 PowerShell
Eric Zimmerman 的工具集 包含 RawCopy.exe (或 RawCopy64.exe),它绕过标准文件 API:
RawCopy.exe /FileNamePath:"C:\$Extend\$UsnJrnl:$J" /OutputPath:"D:\Out"
如果不能落地二进制,PowerForensics 用纯 PowerShell 做同样的事:
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 参考。
提取之后
拿到 $J 文件后,把它扔到本站,或交给你选用的工具。雕刻得到的字节正是 usnrs、PoorBillionaire/USN-Journal-Parser 或 Eric Zimmerman 的 MFTECmd 所期望的输入。
如果同时获取了 $MFT (同一 $Extend 邻里,MFT 表项 0),就能解析出每条记录的完整路径而不只是文件名 — 见 usnrs 中的完整路径解析机制 与本站解析器的 $MFT 入口。
常见坑
- 用资源管理器复制: 拖拽
$UsnJrnl会静默地复制默认未命名流 (空) 而不是$J。总是使用取证工具。 - 日志被禁用: 工作组环境下的机器有时关闭了日志。
fsutil usn queryjournal是最便宜的检查。 $J起始处有稀疏零: 日志是 sparse 流 — 在第一条真实记录前,前几百 MB 可能全是零。usnrs、本站解析器以及大多数其他工具会自动跳过。若自写解析器,usnrs 中的Skip::find_first_record是最短的参考实现。- 流回环: 视卷的活动量,日志的环形缓冲可能已经绕了一圈 — 较早的条目已被覆盖。你能找到的最小 USN 标示了可用历史能追溯到多远。