$npx -y skills add killvxk/cybersecurity-skills-zh --skill analyzing-mft-for-deleted-file-recovery通过检查 MFT 记录条目、$LogFile、$UsnJrnl 和 MFT 松弛空间,使用 MFTECmd、analyzeMFT 和 X-Ways Forensics 分析 NTFS 主文件表($MFT)以恢复已删除文件的元数据和内容。
| 1 | # 分析 MFT 用于已删除文件恢复 |
| 2 | |
| 3 | ## 概述 |
| 4 | |
| 5 | NTFS 主文件表($MFT)是 NTFS 卷上每个文件和目录的中央元数据存储库。每个文件至少由一条 1024 字节的 MFT 记录表示,其中包含 $STANDARD_INFORMATION(时间戳、权限)、$FILE_NAME(名称、父目录、时间戳)和 $DATA(文件内容或簇运行指针)等属性。文件被删除时,其 MFT 记录被标记为非活动状态(InUse 标志清除),但元数据保留到被新文件的条目覆盖为止。这种持久性使 MFT 分析成为恢复已删除文件证据、重建文件系统时间线以及检测反取证活动(如时间戳篡改)的主要技术。 |
| 6 | |
| 7 | ## 前置条件 |
| 8 | |
| 9 | - 取证磁盘镜像(E01、raw/dd、VMDK 或 VHDX 格式) |
| 10 | - MFTECmd(Eric Zimmerman 工具)或 analyzeMFT(基于 Python) |
| 11 | - FTK Imager、Arsenal Image Mounter 或类似工具用于挂载镜像 |
| 12 | - Timeline Explorer 或 Excel 用于 CSV 分析 |
| 13 | - Python 3.8+ 用于自定义分析脚本 |
| 14 | - 了解 NTFS 文件系统内部结构 |
| 15 | |
| 16 | ## MFT 结构和记录布局 |
| 17 | |
| 18 | ### MFT 记录头部 |
| 19 | |
| 20 | 每条 MFT 记录以签名"FILE"(0x46494C45)开头,包含: |
| 21 | |
| 22 | | 偏移量 | 大小 | 字段 | |
| 23 | |--------|------|------| |
| 24 | | 0x00 | 4 字节 | 签名("FILE") | |
| 25 | | 0x04 | 2 字节 | 更新序列偏移量 | |
| 26 | | 0x06 | 2 字节 | 更新序列大小 | |
| 27 | | 0x08 | 8 字节 | $LogFile 序列号 | |
| 28 | | 0x10 | 2 字节 | 序列号 | |
| 29 | | 0x12 | 2 字节 | 硬链接计数 | |
| 30 | | 0x14 | 2 字节 | 第一个属性偏移量 | |
| 31 | | 0x16 | 2 字节 | 标志(0x01 = 使用中,0x02 = 目录) | |
| 32 | | 0x18 | 4 字节 | MFT 记录已用大小 | |
| 33 | | 0x1C | 4 字节 | MFT 记录已分配大小 | |
| 34 | | 0x20 | 8 字节 | 基础文件记录引用 | |
| 35 | | 0x28 | 2 字节 | 下一个属性 ID | |
| 36 | |
| 37 | ### 关键 MFT 属性 |
| 38 | |
| 39 | | 类型 ID | 名称 | 描述 | |
| 40 | |---------|------|------| |
| 41 | | 0x10 | $STANDARD_INFORMATION | 时间戳、标志、所有者 ID、安全 ID | |
| 42 | | 0x30 | $FILE_NAME | 文件名、父目录 MFT 引用、时间戳 | |
| 43 | | 0x40 | $OBJECT_ID | 文件的唯一 GUID | |
| 44 | | 0x50 | $SECURITY_DESCRIPTOR | ACL 权限 | |
| 45 | | 0x60 | $VOLUME_NAME | 卷标(仅卷元数据文件) | |
| 46 | | 0x80 | $DATA | 文件内容(小于 700 字节时为驻留型)或簇运行列表 | |
| 47 | | 0x90 | $INDEX_ROOT | 目录的 B 树索引根 | |
| 48 | | 0xA0 | $INDEX_ALLOCATION | 大型目录的 B 树索引条目 | |
| 49 | | 0xB0 | $BITMAP | 索引或 MFT 的分配位图 | |
| 50 | |
| 51 | ## 已删除文件恢复技术 |
| 52 | |
| 53 | ### 技术 1:使用 MFTECmd 进行 MFT 记录分析 |
| 54 | |
| 55 | ```powershell |
| 56 | # 使用 KAPE 或 FTK Imager 从取证镜像提取 $MFT |
| 57 | # 使用 MFTECmd 解析 $MFT |
| 58 | MFTECmd.exe -f "C:\Evidence\$MFT" --csv C:\Output --csvf mft_full.csv |
| 59 | |
| 60 | # 在 Timeline Explorer 中过滤已删除文件(InUse = FALSE) |
| 61 | # 查找 InUse 列为 False 的条目 |
| 62 | ``` |
| 63 | |
| 64 | **在 CSV 输出中识别已删除文件:** |
| 65 | - `InUse` = False 表示已删除或已重新分配的记录 |
| 66 | - `ParentPath` 显示删除前的原始文件位置 |
| 67 | - `FileSize` 显示原始大小(可能仍可恢复) |
| 68 | - `$STANDARD_INFORMATION` 和 `$FILE_NAME` 属性中的时间戳持续存在 |
| 69 | |
| 70 | ### 技术 2:USN 日志($UsnJrnl:$J)分析 |
| 71 | |
| 72 | USN 日志记录 NTFS 卷上文件的所有更改,包括创建、删除、重命名和数据修改事件。 |
| 73 | |
| 74 | ```powershell |
| 75 | # 使用 MFTECmd 解析 USN 日志 |
| 76 | MFTECmd.exe -f "C:\Evidence\$J" --csv C:\Output --csvf usn_journal.csv |
| 77 | |
| 78 | # 删除证据的关键 USN 原因代码: |
| 79 | # USN_REASON_FILE_DELETE = 0x00000200 |
| 80 | # USN_REASON_CLOSE = 0x80000000 |
| 81 | # USN_REASON_RENAME_OLD_NAME = 0x00001000 |
| 82 | # USN_REASON_RENAME_NEW_NAME = 0x00002000 |
| 83 | ``` |
| 84 | |
| 85 | ### 技术 3:$LogFile 事务分析 |
| 86 | |
| 87 | $LogFile 存储 NTFS 事务记录,即使 USN 日志已循环,也能揭示文件操作。 |
| 88 | |
| 89 | ```powershell |
| 90 | # 使用 LogFileParser 解析 $LogFile |
| 91 | LogFileParser.exe -l "C:\Evidence\$LogFile" -o C:\Output |
| 92 | |
| 93 | # 查找表示文件删除的 REDO 和 UNDO 操作: |
| 94 | # - DeallocateFileRecordSegment(释放文件记录段) |
| 95 | # - DeleteAttribute(删除属性) |
| 96 | # - UpdateResidentValue(清除 InUse 标志) |
| 97 | ``` |
| 98 | |
| 99 | ### 技术 4:MFT 松弛空间分析 |
| 100 | |
| 101 | MFT 松弛空间存在于 MFT 记录已用部分末尾和已分配 1024 字节末尾之间。该区域可能包含之前文件记录的残留数据。 |
| 102 | |
| 103 | ```python |
| 104 | import struct |
| 105 | |
| 106 | def parse_mft_slack(mft_path: str, output_path: str): |
| 107 | """提取并分析 MFT 松弛空间中已删除文件的残留数据。""" |
| 108 | with open(mft_path, "rb") as f: |
| 109 | record_size = 1024 |
| 110 | record_num = 0 |
| 111 | slack_findings = [] |
| 112 | |
| 113 | while True: |
| 114 | record = f.read(record_size) |
| 115 | if len(record) < record_size: |
| 116 | break |
| 117 | |
| 118 | # 验证 FILE 签名 |
| 119 | if record[:4] != b"FILE": |
| 120 | record_num += 1 |
| 121 | continue |
| 122 | |
| 123 | # 从偏移量 0x18 获取已用大小 |
| 124 | used_size = struct.unpack("<I", record[0x18:0x1C])[0] |
| 125 | |
| 126 | if used_size < record_size: |
| 127 | slack = record[used_size:] |
| 128 | # 检查松弛空间是否包含可读字符串或属性头部 |
| 129 | if any(c > 0x20 and c < 0x7F for c in slack[:50]): |
| 130 | slack_findings.append({ |
| 131 | "record": record_num, |
| 132 | "used_size": used_size, |
| 133 | "slack_size": record_size - used_size, |
| 134 | "slack_preview": slack[:100].hex() |
| 135 | }) |
| 136 | |
| 137 | record_num += 1 |
| 138 | |
| 139 | return slack_findings |
| 140 | ``` |
| 141 | |
| 142 | ## 与支持性痕迹的关联 |
| 143 | |
| 144 | ### 与 $Recycle.Bin 交叉引用 |
| 145 | |
| 146 | ```powershell |
| 147 | # 使用 RBCmd 解析回收站 |
| 148 | RBCmd.exe -d "C:\Evidence\$Recycle.Bin" --csv C:\Output --csvf recycle_bin.csv |
| 149 | |
| 150 | # 关联: $I 文件包含原始路径和删除时间戳 |
| 151 | # 将 $R 文件中的 MFT 条目号匹配回原始 MFT 记录 |
| 152 | ``` |
| 153 | |
| 154 | ### 与卷影副本交叉引用 |
| 155 | |
| 156 | ```powershell |
| 157 | # 列出卷影副本 |
| 158 | vssadmin list shadows |
| 159 | |
| 160 | # 挂载卷影副本并从每个副本提取 $MFT |
| 161 | # 比较不同卷影副本中的 MFT 记录以追踪文件随时间的变化 |
| 162 | ``` |
| 163 | |
| 164 | ## 取证价值 |
| 165 | |
| 166 | - **已删除文件元数据恢复**:原始文件名、路径、大小和时间戳 |
| 167 | - **时间线重建**:文件创建、修改、访问和删除事件 |
| 168 | - **时间戳篡改检测**:比较 $SI 和 $FN 时间戳 |
| 169 | - **数据雕刻引导**:MFT 簇运行指向磁盘上的文件内容 |
| 170 | - **反取证检测**:识别被擦除或被篡改的 MFT 记录 |
| 171 | |
| 172 | ## 参考资料 |
| 173 | |
| 174 | - NTFS MFT 高级取证分析: https://www.deaddisk.com/posts/ntfs-mft-advanced-forensic-analysis-guide/ |
| 175 | - MFT 松弛空间的取证价值: https://www.sygnia.co/blog/the-forensic-value-of-mft-slack-space/ |
| 176 | - MFTECmd 文档: https://ericzimmerman.github.io/ |
| 177 | - SANS FOR500: Windows 取证分析 |