010 Editor 实操流程
加载模板
- 打开镜像文件(
File → Open File,dd/raw 镜像直接打开;File → Open Drive可直接开物理U盘) Templates → Template Repository在线安装模板:Drive.bt(MBR/GPT)、FAT.bt(FAT12/16/32)、NTFS.bt、exFAT.bt- 光标定位到要解析的扇区开头,按
F5运行模板,下方Template Results面板即把每个字段按名字+值列出,点字段自动跳到对应十六进制字节
模板解析的是”光标处开始的数据”,所以:
- 解析分区表 → 光标放 0x000
- 解析 DBR → 光标放
分区起始扇区 × 512处(见 1 MBR分区表) - 解析 MFT 记录 → 光标放该记录开头(对齐到 1024)
标准解析顺序(每道镜像题照这个走)
1. mmls image.dd → 分区表(无输出 = 软盘模式,0扇区直接是DBR)
2. fsstat -o <偏移> image.dd → 文件系统类型 + 全部结构字段一次出齐
3. 010 Editor 对照本目录笔记核对字段 → 找被篡改/异常值
4. fls -r -o <偏移> image.dd → 列文件(含已删除,标 * 的)
5. photorec / foremost → 雕刻已删除文件
6. 手工:未分配空间、分区间隙、备份扇区 → 藏数据区域兜底
工具解析失败(挂载报错、fsstat 输出明显荒谬)时,就是出题人改了结构字段,转入下面的手工核对。
CTF 高频篡改点与后果
| 被改字段 | 位置 | 后果 | 修复思路 |
|---|---|---|---|
| 每簇扇区数 | FAT DBR 0x0D | 数据区定位全错,恢复出的文件是乱码 | 必须是 1/2/4/8…128(2的幂),试值重算 |
| 保留扇区数 | FAT DBR 0x0E | FAT表起点错 → 全链路错 | FAT32 通常 32,FAT12/16 通常 1 |
| 根目录项数 | FAT DBR 0x11 | FAT12/16 数据区起点错 | 通常 224 或 512;FAT32 必须为 0 |
| 每FAT扇区数 | FAT DBR 0x16/0x24 | 根目录/数据区起点错 | FAT32 与 6 号扇区备份 DBR 的同款字段对比 |
| 结束标志 | 各引导类扇区 0x1FE(MBR/EBR/DBR/$Boot) | 工具拒绝识别 | 补 55 AA |
| DBR 整体破坏 | 分区0扇区 | 无法挂载 | FAT32 从 6号扇区备份DBR 拷回;exFAT 从 12号扇区备份区 恢复 |
| 分区表项 | MBR 0x1BE | 找不到分区 | 全盘搜 55 AA + OEM 串找 DBR 反推分区起点 |
| exFAT 校验和 | 校验和扇区 | Windows 拒绝挂载 | 改字段后需按规范重算前11扇区校验和 |
| MFT 记录标志 | NTFS 记录头 0x16 | 删除文件被”复活”或正常文件被隐藏 | 对照序列号与 $FILE_NAME 交叉验证 |
手工定位公式速查
以下公式中”扇区”均指相对分区起点的逻辑扇区,乘 512 得字节偏移,再加分区在镜像中的物理偏移。
FAT(详见 2 FAT文件系统):
根目录区大小(扇区) = (根目录项数 × 32) / 每扇区字节数 # FAT12/16 才有
FAT表起点扇区 = 保留扇区数
根目录起点扇区 = 保留扇区数 + FAT份数 × 每FAT扇区数 # FAT12/16
数据区起点扇区 = 保留扇区数 + FAT份数 × 每FAT扇区数 + 根目录区大小
# FAT32 根目录项数=0,数据区起点直接到簇2
簇N 的起点扇区 = 数据区起点 + (N - 2) × 每簇扇区数
exFAT(详见 3 exFAT文件系统):
簇N 的起点扇区 = 簇堆偏移 + (N - 2) × 2^每簇扇区数移位值
NTFS(详见 4 NTFS文件系统):
MFT 起点扇区 = $MFT起始簇号 × 每簇扇区数
记录大小 = 每MFT记录簇数 > 0 ? 簇数×每簇扇区数×每扇区字节数
: 2^(-该值) 字节 # 负数为2的幂
第N条MFT记录 = MFT起点 + N × 记录大小
FAT 目录项时间戳解码(时:分:秒打包):
时间(2字节): bits15-11=时, bits10-5=分, bits4-0=秒/2
日期(2字节): bits15-9=年-1980, bits8-5=月, bits4-0=日
例: 0x5D7A → 01011101 01111010 → 11:43:52
藏数据区域检查清单
出题人藏 flag/证据的位置按命中率排序:
- 未分配簇:
blkls -o <偏移> image.dd > unalloc.bin,再 strings/雕刻 - 分区间隙:分区表之后、第一个分区之前(LBA 1~2047);分区结束之后
- 备份引导扇区:FAT32 的 6 号扇区、exFAT 的 12~23 扇区——与主 DBR
diff,不一致处就是改动点 - 文件 Slacks:文件末尾到簇尾的空隙(RAM slack / file slack)
- FAT2:两份 FAT
diff,差异处藏着被改的链 - 根目录区残留(FAT12/16):已删除目录项(0xE5 开头)批量扫描
- NTFS:Extend$UsnJrnl、MFT 记录空隙、命名 $DATA 流(ADS 备用数据流,文件名后跟
:streamname;短流常驻在 MFT 记录内,工具常漏)
痕迹关联(证明”这个U盘干过什么”)
- 卷序列号:FAT12/16 DBR 0x27、FAT32 DBR 0x43 / exFAT 0x64 / NTFS 0x48(8字节)→ 关联注册表
HKLM\SYSTEM\MountedDevices、LNK 文件、HKEY_CURRENT_USER\...\MountPoints2 - 磁盘签名:MBR 0x1B8 → 同样关联 MountedDevices
- Windows USB 插拔痕迹:
HKLM\SYSTEM\CurrentControlSet\Enum\USBSTOR(设备序列号+首次安装时间)、setupapi.dev.log、Event ID 20001/20100 - 文件时间戳矛盾:STANDARD_INFORMATION → timestomp 反取证痕迹
端序判断(大小端)
U盘取证涉及的全部结构(MBR/FAT12/16/32/exFAT/NTFS)都是 x86 体系制定的,多字节整数一律小端序,不需要逐字段判断。容易混淆的只有三类:
- 整数 → 永远小端。如
00 02= 512。 - ASCII 字符串(OEM名、文件名、卷标、
"FAT32 ")→ 字节序列,按显示顺序直接读,端序概念不适用。 - 签名/魔数(
55 AA、"FILE"、"EXFAT ")→ 记磁盘字节序即可;若当作整数读,55 AA的小端值是 0xAA55(微软文档写法)。不要对签名套端序转换。
陌生格式的经验判定法——锚点字段反推:找一个值必然已知的字段试读,读出来荒谬就是端序反了:
| 锚点字段 | 磁盘字节 | 小端读 | 大端读 |
|---|---|---|---|
| FAT 每扇区字节数 (0x0B) | 00 02 | 512 ✓ | 2 ✗ |
| MBR 分区总扇区数 | 实测 | ≈U盘容量 ✓ | 荒谬 ✗ |
| exFAT 卷总扇区数 (0x48) | 实测 | ≈镜像大小 ✓ | 荒谬 ✗ |
大端只在网络协议包、HFS+、部分 RAID 元数据里出现,U盘取证范围遇不到。010 Editor 模板默认 LittleEndian,Template Results 面板的值已转好,直接用,不要再手动反转;只有在十六进制区手工拼整数时才需要心算反转。
恢复已删除文件(手工三板斧)
- FAT:扫目录区找 0xE5 开头的目录项 → 读出起始簇+文件大小 → FAT 链已被清零,假设连续存放直接 dump
起始簇 × 大小;碎片文件用 photorec 按文件头雕刻 - exFAT:找类型码 0x05/0x40/0x41 的目录项 → 若 NoFatChain 标志置位(连续文件常见)直接按起始簇+长度 dump,恢复率极高
- NTFS:扫 MFT 找标志位 0x01 被清除的记录 → 属性还在 → 常驻 $DATA 直接读;非常驻按 Data Run 解 LCN dump