SecurityRonin/ntfs-forensic
GitHub: SecurityRonin/ntfs-forensic
从零实现的 NTFS 取证读取器与分级异常审计器,能在不可信磁盘镜像上检测时间戳篡改、已删除记录、MFT 篡改等取证异常并从 USN 日志重构已删除文件的完整路径。
Stars: 0 | Forks: 0
# ntfs-forensic
[](https://crates.io/crates/ntfs-core)
[](https://crates.io/crates/ntfs-forensic)
[](https://docs.rs/ntfs-forensic)
[](LICENSE)
[](https://github.com/SecurityRonin/ntfs-forensic/actions)
[](https://github.com/sponsors/h4x0r)
**一个从零开始构建的 NTFS 读取器和分级异常审计器 —— 从 `$UsnJrnl:$J` 更改日志中重构完整的文件路径(即使对于已删除、MFT 复用的文件),并呈现“干净”的文件系统驱动程序旨在隐藏的时间戳篡改、备用数据流、已删除记录和 MFT 残留空间。**
一个工作区,两个 crate:
- **[`ntfs-core`](https://crates.io/crates/ntfs-core)** —— 读取器:`$MFT`、属性、索引、数据运行、LZNT1、`$UsnJrnl:$J` 更改日志记录解码,以及在任何 `Read + Seek` 源上进行 `NtfsFs` 路径导航。不使用 `unsafe`,没有 C 绑定。
- **[`ntfs-forensic`](https://crates.io/crates/ntfs-forensic)** —— 审计器:将解析后的 MFT 记录转换为严重性分级的 [`forensicnomicon::report::Finding`](https://crates.io/crates/forensicnomicon),以便 NTFS 卷的异常能与分区层和容器层统一汇总。
## 在 30 秒内审计原始 MFT 记录
```
[dependencies]
ntfs-forensic = "0.5" # pulls in ntfs-core
```
```
use ntfs_forensic::audit_record;
use forensicnomicon::report::Source;
let src = Source { analyzer: "ntfs-forensic".into(), scope: "NTFS".into(), version: None };
// Feed it a single raw 1024-byte MFT record; get back graded anomalies.
for anomaly in audit_record(&mft_record_bytes) {
let finding = anomaly.to_finding(src.clone());
println!("[{:?}] {} — {}", finding.severity, finding.code, finding.note);
// e.g. [Some(High)] NTFS-TIMESTOMP — $SI created before $FN …
}
```
`audit_record` 解析头部和属性,提取 `$STANDARD_INFORMATION`/`$FILE_NAME`,并对其发现进行评级。头部未能解析的记录不会产生异常(结构性损坏由读取器/雕刻器呈现,绝不会引发 panic)。
## 异常代码
每个异常都是一个**观察结果**(“与……一致”);由检查人员得出结论。代码是稳定、公开的契约。
| 代码 | 严重性 | 观察内容 |
|---|---|---|
| `NTFS-TIMESTOMP` | 高 | `$STANDARD_INFORMATION` 时间显示与更难伪造的 `$FILE_NAME` 时间相比存在伪造痕迹(`$SI` 早于 `$FN`,或精确到整秒) |
| `NTFS-ADS` | 低 | 命名的 `$DATA` 属性 —— 备用数据流(也有良性用途,例如 `Zone.Identifier`) |
| `NTFS-SLACK-RESIDUE` | 低 | MFT 记录中超出其已用大小的残留空间中存在非零残留数据 |
| `NTFS-DELETED-RECORD` | 信息 | 未被使用的 MFT 记录 —— 可恢复的已删除文件 |
| `NTFS-MFTMIRR-MISMATCH` | 高 | `$MFT` 中的系统记录与其 `$MFTMirr` 副本不同 |
| `NTFS-LOGFILE-CLEARED` | 中 | `$LogFile` 显示的重启区域间隙与日志被清除的情况一致 |
每条记录的异常来自 `audit_record` / `audit_components`;卷级别的配对(`NTFS-MFTMIRR-MISMATCH`,`NTFS-LOGFILE-CLEARED`)来自 `audit_mft_mirror($MFT, $MFTMirr)` 和 `audit_logfile($LogFile)`。
## 读取器:导航卷
`NtfsFs`(在 `ntfs-core` 中,作为 `ntfs_core` 导入)从任何 `Read + Seek` 源读取文件和目录:
```
use ntfs_core::NtfsFs;
use std::fs::File;
let mut fs = NtfsFs::open(File::open("ntfs.img")?)?;
// Read a file by path…
let hosts = fs.read_file(r"\Windows\System32\drivers\etc\hosts")?;
// …or list the root directory (MFT record 5).
let root = fs.read_record(5)?;
for entry in fs.directory_entries(&root)? {
if let Some(name) = entry.file_name {
println!("{}", name.name);
}
}
# Ok::<(), ntfs_core::NtfsError>(())
```
crates.io 上名为 `ntfs` 的原始 crate 是 Colin Finck 的通用读取器,因此此 crate 以 `ntfs-core` 发布并作为 `ntfs_core` 导入。
### 在整个磁盘内打开分区
`OffsetReader` 将分区重新基定到偏移量 0,并且**在结构上无法读取超出分区边界的内容** —— 将来自 [`mbr-forensic`](https://github.com/SecurityRonin/mbr-forensic) / [`gpt-partition-forensic`](https://github.com/SecurityRonin/gpt-partition-forensic) 的偏移量和长度提供给它:
```
use ntfs_core::{NtfsFs, OffsetReader};
use std::fs::File;
let part = OffsetReader::new(File::open("disk.img")?, 1_048_576, 500_000_000)?;
let mut fs = NtfsFs::open(part)?;
# Ok::<(), ntfs_core::NtfsError>(())
```
## 这与通用 NTFS crate 有何不同
大多数 NTFS crate 只回答一个问题:“这个卷上有什么文件?”而此工作区回答的是数字取证检查人员真正需要的问题:
| 功能 | 通用 NTFS crate | 此工作区 |
|---|---|---|
| MFT 记录 + 属性解析 | ✅ | ✅ |
| 目录索引遍历(`$INDEX_ROOT` / INDX) | ✅ | ✅ |
| 数据运行、稀疏文件、LZNT1 解压缩 | ✅ | ✅ |
| `$ATTRIBUTE_LIST`(严重碎片化的文件) | 部分 | ✅ |
| `$SI`-与-`$FN` 时间戳篡改检测 | ✗ | ✅ |
| 备用数据流枚举 | ✗ | ✅ |
| 已删除记录雕刻(未分配的 `FILE`/`BAAD`) | ✗ | ✅ |
| MFT 记录残留空间提取 | ✗ | ✅ |
| `$MFTMirr` / `$LogFile` 篡改检查 | ✗ | ✅ |
| 更新序列(修复)撕裂写入检测 | ✗ | ✅ |
| `$UsnJrnl:$J` 更改日志记录解码(创建 / 删除 / 重命名 / 覆盖历史) | ✗ | ✅ |
| **`$UsnJrnl:$J` 完整路径重构**(*Rewind* 算法 —— 即使对于已删除 + MFT 复用文件也能提供完整路径) | ✗ | ✅ |
| USN 流式读取器 + 空闲空间 USN 记录雕刻 | ✗ | ✅ |
| ReFS USN V3(128 位文件引用) | ✗ | ✅ |
| 分区窗口隔离(无法读取超出卷的内容) | ✗ | ✅ |
| 严重性分级的 `report::Finding` 输出 | ✗ | ✅ |
| `#![forbid(unsafe_code)]` | — | ✅ |
## `$UsnJrnl:$J`:重构完整路径 —— 即使是已删除的文件
USN 更改日志记录了*什么*发生了更改以及*哪个* MFT 条目 —— 但仅限于文件**自己的名称**,而不是其路径。`ntfs-core` 通过使用 *Rewind* 算法遍历日志,重构每个日志事件的**完整路径**,包括那些已被删除且其 `$MFT` 记录后来被重用的文件:
```
use ntfs_core::mft::MftData;
// Seed from the live $MFT, then rewind the $UsnJrnl:$J event stream.
let mut engine = MftData::parse(&mft_bytes)?.seed_rewind();
for resolved in engine.rewind(&ntfs_core::usn::parse_usn_journal(&usn_bytes)?) {
println!("{:<10?} {:<12?} {}", resolved.source, resolved.record.reason, resolved.full_path);
// Allocated FILE_DELETE \Users\victim\AppData\Local\Temp\evil.exe
}
# Ok::<(), ntfs_core::NtfsError>(())
```
`RewindEngine` 运行**两次遍历 —— 先反向,再正向** —— 因此在日志中途的重命名或 MFT 条目复用,在每个时间点都能解析为*正确*的路径。父目录在实时 `$MFT` 中已不存在的事件,仍然可以从日志自身的创建/重命名历史中解析,并标记为 `RecordSource::Carved` 或 `Ghost`。对于太大而无法保存在内存中的日志,`UsnJournalReader` 会对它们进行流式传输;`carve_usn_records` 从日志残留空间和未分配空间中恢复事件;而 `RefsAnalyzer` 处理 ReFS 的 128 位 USN V3 引用。
## 读取器 API(`ntfs-core`)
| 条目 | 用途 |
|---|---|
| `NtfsFs::open` / `read_file` / `read_record` / `directory_entries` / `resolve_path` / `read_named_stream` | 按路径或 MFT 记录号导航卷 |
| `BootSector` | 卷引导记录(BPB / 扩展 BPB) |
| `MftRecordHeader` / `apply_fixup` | FILE 记录和更新序列数组修复 |
| `parse_attributes` / `Attribute` | 驻留和非驻留属性遍历 |
| `StandardInformation` / `FileName` | 两组时间戳集 |
| `decode_runlist` / `read_attribute_value` / `read_runs` | 数据运行(VCN→LCN)、稀疏 + 非驻留读取 |
| `IndexRoot` / `parse_index_buffer` / `parse_entries` | 目录 B 树(`$INDEX_ROOT` / INDX) |
| `parse_attribute_list` | 用于碎片化文件的扩展记录 |
| `decompress` | LZNT1 解压缩 |
| `carve_mft_entries` | 从原始 `$MFT` 区域雕刻 `FILE`/`BAAD` 记录 |
| `compare_mft_mirror` / `parse_logfile` / `detect_journal_clearing` | `$MFTMirr` / `$LogFile` 解析原语 |
| `parse_usn_record_v2` / `parse_usn_journal` / `UsnRecord` / `UsnReason` / `FileAttributes` | 解码 `$UsnJrnl:$J` 更改日志记录(V2/V3) —— 每个事件的 MFT + 父 MFT 引用、原因标志、文件名、属性和时间戳 |
| `UsnJournalReader` | 在过大而无法整体加载的 `$J` 流上的流式、低内存迭代器 |
| `carve_usn_records` | 从日志残留空间和未分配空间恢复 USN 记录 |
| `MftData` / `MftEntry` | 高级 `$MFT` 聚合器(`$SI`/`$FN` 时间戳、ADS、路径解析);为 Rewind 引擎提供种子 |
| `RewindEngine` / `ResolvedRecord` | 从 USN 日志进行**完整路径重构**(*Rewind* 算法 —— 两次遍历,支持重命名和 MFT 复用感知) |
| `RefsAnalyzer` / `RefsFileId` | ReFS USN V3(128 位文件引用),仅支持日志 Rewind 的路径重构 |
| `OffsetReader` | 有界分区窗口 |
审计器原语 —— `detect_timestomp`、`alternate_data_streams`、`record_slack`、`is_deleted`、`carve_file_records` —— 位于 `ntfs-forensic` 中 `audit_record` 旁边。
## 信任,但要验证
`ntfs-forensic` 专为处理来自潜在被入侵系统的不可信磁盘映像而构建:
- **`#![forbid(unsafe_code)]`** 覆盖两个 crate —— 没有 C 绑定,没有 FFI。
- **恶意输入下不引发 panic** —— 每个长度和偏移量都会根据结构声明的尺寸和实际缓冲区进行验证;该工作区在生产代码中禁用了 `clippy::unwrap_used` 和 `clippy::expect_used`。
- **模糊测试** —— 七个 `cargo-fuzz` 目标(`boot`、`record`、`attributes`、`attribute_list`、`runlist`、`index_buffer`、`compress`);一个 `fuzz.yml` CI 工作流构建并对每个目标进行冒烟运行。
- **在真实工件上验证** —— 启动解析器在真实磁盘映像上(`tests/real_image.rs`)与 The Sleuth Kit 进行了交叉验证,MFT 解析与 `mft` crate 作为独立预言机进行了交叉核对(`tests/parity_mft.rs`)。
- **在 CI 中强制执行 100% 行覆盖率**(`cargo llvm-cov --lib`,任何零命中行都会导致失败)。
```
cargo test
cargo +nightly fuzz run record # requires nightly + cargo-fuzz
```
## 这适用的场景
`ntfs-core` 是 SecurityRonin 取证系列的 NTFS FS 层基础。完整的 `$UsnJrnl:$J` 读取器堆栈 —— 解码、流式传输、雕刻和 *Rewind* 完整路径重构 —— 位于 **`ntfs-core`** 中;[`usnjrnl-forensic`](https://github.com/SecurityRonin/usnjrnl-forensic) 现在是位于其上的一个轻量级 CLI 外壳(输出格式、实时监控),而 [`issen`](https://github.com/SecurityRonin/issen) 将此工作区作为其单一的、可审计的 NTFS 引擎使用。要获取对磁盘映像的 `Read + Seek` 并定位其中的 NTFS 分区,这些 crate 在上游组合:
| Crate | 角色 |
|---|---|
| [`disk-forensic`](https://github.com/SecurityRonin/disk-forensic) | **编排器** —— 自动检测 MBR / GPT / APM 并输出每个分区的偏移量 / 长度 |
| [`mbr-forensic`](https://github.com/SecurityRonin/mbr-forensic) | MBR 分区表 → NTFS 分区偏移量 / 长度 |
| [`gpt-partition-forensic`](https://github.com/SecurityRonin/gpt-partition-forensic) | GPT 分区表 → NTFS 分区偏移量 / 长度 |
| [`ewf-forensic`]( ) | E01 / Expert Witness Format 容器 |
| [`vhdx-forensic`](https://github.com/SecurityRonin/vhdx-forensic) | VHDX 容器 |
[隐私政策](https://securityronin.github.io/ntfs-forensic/privacy/) · [服务条款](https://securityronin.github.io/ntfs-forensic/terms/) · © 2026 Security Ronin Ltd
标签:NTFS, Rust, 可视化界面, 子域名变形, 数字取证, 文件系统, 网络流量审计, 自动化脚本, 通知系统