← 返回博客

如何从磁盘镜像 (或活动系统) 中提取 $UsnJrnl:$J

实战指南:从取证镜像、已挂载卷或运行中的 Windows 主机里拿出 NTFS USN 日志 — 使用 FTK Imager、X-Ways、The Sleuth Kit、fsutil 与 PowerShell。

阅读约 2 分钟

处理 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)

  1. 打开镜像 (File → Add Evidence Item)。
  2. 进入 [root]/$Extend/$UsnJrnl
  3. 右键点击 $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 分析师常用的选择。相关工具是 TSKicat:

# 找到 $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 artifactKAPE 都会自动拉取日志。KAPE 使用 target (!ALLUSNJournal);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: 0x00000000Maximum Size 非零,说明日志在运行。若是 0x80000005 之类,意味着日志被禁用,没有可提取的内容 — 生命周期命令参见 fsutil usn 参考

提取之后

拿到 $J 文件后,把它扔到本站,或交给你选用的工具。雕刻得到的字节正是 usnrsPoorBillionaire/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 标示了可用历史能追溯到多远。