方法论

USN Parser 如何把 $J 字节流转换为结构化记录 — 算法、校验步骤、已知限制。

本页记录 USN Parser 对你的输入做了什么、为何可以信任输出、限制在哪里。它意在支撑一条取证证据链 — 若你在报告中引用 USN Parser,这是该参考的页面。

输入

  • $UsnJrnl:$J:必需。从卷根 \$Extend\$UsnJrnl 提取出的稀疏替代数据流。必须是 $J 流 — $Max 仅承载日志大小元数据。
  • $MFT:可选。同卷的主文件表。仅用于把父目录引用解析为完整路径。

两份文件都被读入内存,交给 WebAssembly 解析器。浏览器通过 postMessage 配合显式 transfer 列表把字节缓冲交给 worker — 更快,也避免在内存中留下无关副本。

解析算法

我们把 usnrs (Airbus CERT,Apache-2.0) 编译到 wasm32-unknown-unknown。它实现的是 Microsoft NTFS 参考 文档化的 USN_RECORD_V2 结构。

读取过程:

  1. 跳过开头的稀疏零区,直到第一个非零字节(第一条记录的开始)。
  2. 向前推进,在每个偏移读取 4 字节的 RecordLength,跨到下一条记录。
  3. 遇到 4 个连续的零字节即停止(有效记录结束)。
  4. 对每条记录,校验主/次版本号为 2.0,然后解码定长头部和变长文件名。

当提供了 $MFT,我们通过沿父引用链回溯来解析完整路径。只有当解析得到的末端名称与日志中的文件名相符时,才采用完整路径 — 避免一条过期的 MFT 记录给出错误置信度的路径。

输出

每条记录暴露的字段:

  • usn (u64):在日志中的位置
  • timestampMs (i64):Windows FILETIME 转换为 UTC Unix 毫秒
  • filename(UTF-16 解码)
  • fullPath(字符串或 null):仅在提供了 $MFT 且匹配时
  • reasons (string[]):Reason 位掩码展开为可读名
  • attributes (string[]):文件上设置的 NTFS 属性
  • mftEntrymftSequenceparentMftEntryparentMftSequence

输出留在浏览器内存中,直到你关闭标签页。

限制

  • 尚未支持 USN_RECORD_V3 V3(变长文件引用,随 ReFS 引入)在标准 NTFS 卷上不会生成,因此在实务中很少有影响。
  • 环形缓冲的回环不可见:最旧记录之前覆盖了什么我们无从得知。若需要更深的历史,请交叉使用 $LogFile 与卷影副本。
  • 不做时间戳校验:我们信任记录里的 FILETIME。要检测 timestomping,SI vs FN 文章 描述了与 $MFT 的标准交叉对比。

证据链

如果你在报告里需要引用:USN Parser 的版本可通过 GitHub 仓库底部展示的部署提交哈希识别。wasm 产物可通过 wasm-pack build --release 由源码可复现;.wasm 的哈希在每个源码版本上是稳定的。