前言

本篇将对 Ext3 文件系统的超级块进行分析,学习恢复损坏 0 号超级块的 Ext3 文件系统。

知识点总览

  • Ext3 文件系统的超级块分析

  • Ext3 文件系统的块组描述符分析

  • 实例:恢复损坏 0 号超级块的 Ext3 文件系统

Ext3 文件系统的超级块分析

Ext3 文件系统的超级块起始于 2 号扇区,占用两个扇区。

当文件系统的块大小不同时,超级块所在块号是不同的。

文件系统块大小 超级块所在块号 超级块起始扇区
1KB(2 扇区) 2 4
2KB(4 扇区) 4 8
4KB(8 扇区) 8 16

当块大小为两个扇区时,0 号块是引导程序块或者保留块,超级块起始于 1 号块;
当块大小为 4 个扇区时,超级块起始于 0 号块,其位于 0 号块的后两个扇区,前两个扇区是引导程序或者保留扇区;
当块大小为 8 个扇区时,超级块也起始于 0 号块,其位于 0 号块的 2 ~ 3 号扇区,0 ~ 1 号扇区是引导程序或者保留扇区,4 ~ 7 号扇区则是空闲的。

上图为 Ext3 文件系统的前半个超级块,在 Ext3 文件系统的超级块中,关键参数为 0x00~0x5B 处

Ext3 文件系统的超级块关键参数

Ext3 文件系统 0x00~0x5B 处的关键参数如下图所示:

字节偏移
字段长度
(字节)
字段名和定义
0x00 ~ 0x03 4 i-节点总数
0x04 ~ 0x07 4 总块数
0x08 ~ 0x0B 4 保留块数
0x0C ~ 0x0F 4 空闲块数
0x10 ~ 0x13 4 空闲 I-节点数
0x14 ~ 0x17 4 第一个数据块(即 0 号块组起始块号)
0x18 ~ 0x1B 4 块大小描述值
0x1C ~ 0x1F 4 段大小描述值(与“块大小描述值”相同)
0x20 ~ 0x23 4 每块组包含的块数
0x24 ~ 0x27 4 每块组包含的段数
0x28 ~ 0x2B 4 每块组包含的 i-节点数
0x2C ~ 0x2F 4 最后挂载时间
0x30 ~ 0x33 4 最后写入时间
0x34 ~ 0x35 2 挂载次数
0x36 ~ 0x37 2 最大挂载数
0x38 ~ 0x39 2 签名值
0x3A ~ 0x3B 2 文件系统状态
0x3C ~ 0x3D 2 错误处理方式
0x3E ~ 0x3F 2 次版本号
0x40 ~ 0x43 4 最后检查时间
0x44 ~ 0x47 4 强迫一致性检查的最大间隔时间
0x48 ~ 0x4B 4 创建文件系统的操作系统类型
0x4C ~ 0x4F 4 主版本号
0x50 ~ 0x51 2 用户 ID 保留块
0x52 ~ 0x53 2 组 ID 保留块
0x54 ~ 0x57 4 第一个非保留 i-节点
0x58 ~ 0x59 2 i-节点大小
0x5A ~ 0x5B 2 当前超级块所在块组

对超级块的关键参数进一步解释如下:

  1. 0x00 ~ 0x03:i-节点总数。是指当前文件系统中包含的 i-节点总数。

  2. 0x04 ~ 0x07:总块数。是指当前文件系统中包含的总块数。

  3. 0x08 ~ 0x0B:保留块数。是指为避免分区用完而给文件系统保留的块数,其数量一般为文件系统总块数的百分之五。

  4. 0x0C ~ 0x0F:空闲块数。是指当前文件系统未分配的块数。

  5. 0x10 ~ 0x13:空闲 i-节点数。是指当前文件系统未分配的 i-节点数目。

  6. 0x14 ~ 0x17:第一个数据块。是指 0 号块组起始块号。

  7. 0x18 ~ 0x1B:块大小描述值。用来描述文件系统每个块的字节数,具体描述方法为:当此参数的值为 N 时,块大小就等于 2^N×1024 字节。例如,该参数等于 2 时,块大小等于 4096 字节。

  8. 0x1C ~ 0x1F:段大小描述值。段大小是 UFS 中的一个概念,因为 Ext 文件系统来源于 UFS,所以超级块中保留了这个参数,但在文件系统中并不使用,该参数跟“块大小描述值”保持一致。

  9. 0x20 ~ 0x23:每块组包含的块数。是指文件系统每个块组中包含块的数量。

  10. 0x24 ~ 0x27:每块组包含的段数。因为“段”的概念在 Ext3 文件系统中已不再使用,所以该参数也跟“每块组包含的块数”保持一致。

  11. 0x28 ~ 0x2B:每块组包含的 i-节点数。是指文件系统每个块组中包含 i-节点的数量。

  12. 0x2C ~ 0x2F:最后挂载时间。是指文件系统最后一次挂载的时间。

  13. 0x30 ~ 0x33:最后写入时间。是指文件系统最后一次写入数据的时间。

  14. 0x34 ~ 0x35:挂载次数。是指文件系统到目前为止挂载的次数总和。

  15. 0x36 ~ 0x37:最大挂载数。是指文件系统挂载的最大次数。

  16. 0x38 ~ 0x39:签名值。是指文件系统的标志值,固定为十六进制数值“53 EF”。

  17. 0x3A ~ 0x3B:文件系统状态:

状态值 状态描述
0x0001 文件系统是干净的
0x0002 文件系统存在错误
0x0004 正在恢复孤立的 i-节点
  1. 0x3C ~ 0x3D:错误处理方式。是指当文件系统出错时,操作系统应该采取的处理方法。这个值在文件系统创建时被设置,它有三种处理方式:
数值 处理方式
0x0001 继续运行
0x0002 以只读方式重新挂载
0x0003 紧急处理
  1. 0x3E ~ 0x3F:小版本号,文件系统中的小版本号(minor revision level)

  2. 0x40 ~ 0x43:最后检查时间。是指文件系统最后一次运行一致性检查的时间。

  3. 0x44 ~ 0x47:强迫一致性检查的最大间隔时间。是指对文件系统强制运行一致性检查的最大间隔时间,以秒为单位。

  4. 0x48 ~ 0x4B:创建文件系统的操作系统类型。是指当前文件系统是由哪一种操作系统创建的。

数值 操作系统类型
0x00 Linux
0x01 GNU Hurd
0x02 Masix
0x03 Free BSD
0x04 Lites
  1. 0x4C ~ 0x4F:版本号,文件系统中的主版本号,为 Ext2 文件系统中遗留项。(Revision level)

    ext2_fs 源码 中的 #302 行定义了主版本号的两种取值

    1
    2
    3
    4
    5
    /*
    * Revision levels
    */
    #define EXT2_GOOD_OLD_REV 0 /* The good old (original) format */
    #define EXT2_DYNAMIC_REV 1 /* V2 format w/ dynamic inode sizes */

    在 #54 #57 行调用了主版本号,当 主版本号 == 1 时,i- 节点大小为 128 字节,超级块中偏移 54H ~ 5BH 处的参数才有效,这部分参数属于“扩展超级块”。

    1
    2
    3
    4
    5
    6
    #define EXT2_INODE_SIZE(s)    (((s).s_rev_level == EXT2_GOOD_OLD_REV) ? \
    EXT2_GOOD_OLD_INODE_SIZE : \
    (s).s_inode_size)
    #define EXT2_FIRST_INO(s) (((s).s_rev_level == EXT2_GOOD_OLD_REV) ? \
    EXT2_GOOD_OLD_FIRST_INO : \
    (s).s_first_ino)

    在 ext3_fs 中没有该逻辑,因此该项在 ext3 中无效。

  2. 0x50 ~ 0x51:用户 ID 保留块。是指用户 ID 可以使用的保留块数。

  3. 0x52 ~ 0x53:组 ID 保留块。是指组 ID 可以使用的保留块数。

  4. 0x54 ~ 0x57:第一个非保留 i-节点。是指用户数据可以使用的第一个 i-节点号,一般都是 11 号 i-节点。

  5. 0x58 ~ 0x59:i-节点大小。是指文件系统中每个 i-节点的字节数。

  6. 0x5A ~ 0x5B:当前超级块所在块组。因为超级块在很多块组中有备份,该参数用来描述当前超级块所在的块组号。

Ext3 文件系统的超级块非关键参数

在超级块的 0x5C~0x1FF 之间,是 Ext3 文件系统的非关键参数,在进行分区恢复时,这些参数不是非常重要的,故本小节可以略过。

字节偏移
字段长度
(字节)
字段名和定义
0x5C ~ 0x5F 4 兼容性特征标志
0x60 ~ 0x63 4 非兼容性特征标志
0x64 ~ 0x67 4 只读兼容性特征标志
0x68 ~ 0x77 16 卷的 UUID(全局 ID)
0x78 ~ 0x87 16 卷名
0x88 ~ 0xC7 64 最后挂载路径
0xC8 ~ 0xCB 4 位图算法
0xCC ~ 0xCC 1 文件预分配块数
0xCD ~ 0xCD 1 目录预分配块数
0xCE ~ 0xCF 2 未用
0xD0 ~ 0xDF 16 日志的 UUID
0xE0 ~ 0xE3 4 日志的 i-节点
0xE4 ~ 0xE7 4 日志设备号
0xE8 ~ 0xEB 4 最后的孤立 i-节点
0xEC ~ 0xEF 4 Hash 种子 1
0xF0 ~ 0xF3 4 Hash 种子 2
0xF4 ~ 0xF7 4 Hash 种子 3
0xF8 ~ 0xFB 4 Hash 种子 4
0xFC ~ 0xFF 4 默认 Hash 版本
0x100 ~ 0x103 4 默认挂载选项
0x104 ~ 0x107 4 第一个元数据块的块组
0x108 ~ 0x10B 4 文件系统创建时间
0x10C ~ 0x14F 68 日志节点信息备份

对超级块非关键参数进一步解释如下:

  1. 0x5C ~ 0x5F:兼容性特征标志。操作系统在挂载文件系统时,会检查其特征,如果存在兼容性特征标志,就将其挂载为正常的文件系统。

    兼容性特征描述

数值 兼容性特征
0x0001 给目录预分配块以减少碎片
0x0002 存在 AFA 服务 i-节点
0x0004 文件系统包含日志,即 Ext3 文件系统
0x0008 i-节点有扩展属性
0x0010 文件系统能够调整大小
0x0020 目录使用 hash 树
  1. 0x60 ~ 0x63:非兼容性特征标志。操作系统在挂载文件系统时,如果发现文件系统存在非兼容性特征标志,将不对其挂载。

    非兼容性特征描述

数值 非兼容性特征
0x02 目录项中包含文件类型
0x40 文件系统使用盘区结构
0x80 文件系统使用 64 位块号
  1. 0x64 ~ 0x67:只读兼容性特征标志。操作系统在挂载文件系统时,如果发现文件系统存在只读兼容性特征标志,将对其以只读方式挂载。

    只读兼容性特征描述

数值 只读兼容性特征
0x01 稀疏超级块方式
0x02 文件系统中有大文件
0x04 目录结构使用 B-树管理
  1. 0x68 ~ 0x77:卷的 UUID。这是卷的全局 ID,用 16 个字节描述。

  2. 0x78 ~ 0x87:卷名。是指文件系统的名称。

  3. 0x88 ~ 0xC7:最后挂载路径。是指文件系统最后一次挂载的路径。

  4. 0xC8 ~ 0xCB:位图算法。是指文件系统中位图使用的算法。

  5. 0xCC ~ 0xCC:文件预分配块数。是指文件系统为文件预分配的块数。

  6. 0xCD ~ 0xCD:目录预分配块数。是指文件系统为目录预分配的块数。

  7. 0xD0 ~ 0xDF:日志的 UUID。是指文件系统中日志的全局 ID。

  8. 0xE0 ~ 0xE3:日志的 i-节点。是指文件系统中日志的 i-节点号。

  9. 0xE4 ~ 0xE7:日志设备号。是指文件系统中日志的设备号。

  10. 0xE8 ~ 0xEB:最后的孤立 i-节点。是指文件系统中最后的孤立 i-节点号。

  11. 0x104 ~ 0x107:第一个元数据块的块组。是指文件系统中存放元数据的第一个块组号。

  12. 0x108 ~ 0x10B:文件系统创建时间。是指创建该文件系统的具体时间信息。

  13. 0x10C ~ 0x14F:日志节点信息备份。这是超级块为日志节点信息做的备份

Ext3 文件系统的块组描述符分析

Ext 类文件系统的块组来源于 UFS 文件系统的柱面组,所以 Ext3 文件系统的块组描述符相当于 UFS 文件系统的柱面组概要项。

每个块组都对应一个块组描述符,用来描述块组的相关信息,所有的块组描述符组成了一个列表,称为块组描述符表

块组描述符的结构

Ext3 文件系统的每个块组描述符占用 32 字节,用以描述块组中的位图起始地址、i-节点表起始地址、空闲块数、空闲 i-节点数等信息,每个块组都有这样的一个块组描述符,所有的块组描述符集中存放,组成块组描述符表。

块组描述符的结构如下图所示:

块组描述符表的起始地址位于超级块所在块的下一个块,在整个文件系统中有很多块组描述符表的备份,备份的方式具体分为两种:

  1. 文件系统不具备稀疏超级块特性

如果文件系统不具备稀疏超级块特性,那么在每个块组中都会有一个超级块的备份,同时也有块组描述符表的备份。

  1. 文件系统具备稀疏超级块特性

如果文件系统具备稀疏超级块特性,那么只在块组号是 3、5、7 的幂的块组(如 1、3、5、7、9、25、49 等)内才对超级块和块组描述符表做备份,其他块组内则没有备份。

通过块组描述符计算分区大小

在 Ext3 文件系统中,块组描述符表 所表示的是整个分区的块组信息,分区里每个块组在表内都有一条记录,所以可以通过块组描述符表的大小来计算分区的大小。

假定一个分区的块组内有 32768 个块,每块扇区数为 8,块组描述符表占 41696 字节,则可以通过:

块组描述符表所占字节 ÷ 32 = 分区块组数

与 FAT32 分区相似,Ext3 文件系统的最后一个块组内不一定是满的,为了减小误差,可以将分区块组数减 1。

(分区块组数 - 1) * 每块组块数 * 每块扇区数 = 分区大小

从分区起始跳转此时计算出的分区大小为该分区最后一个块组的起始位置,需要向下搜索 !00 以到达下一个分区

TIP: 在分区不过大/过小的通常情况下 每块组块数 的值为 32768,每块扇区数 的值为 8

实例:恢复损坏 0 号超级块的 Ext3 文件系统

你可以在 https://winhex.im0o.top/ 中查看所有例题文件

从题库下载题目:221123 - 恢复损坏 0 号超级块的 Ext3 文件系统

涉及知识点

  • Ext3 文件系统的超级块结构

  • Ext3 文件系统的块组描述符表结构

  • 从备份超级块恢复 Ext3 文件系统的 0 号超级块

恢复要求

恢复根目录下的文件 Kristina_Bell_6452.png

附加磁盘文件

导入题目后可以从 计算机管理 —— 磁盘管理 中看到该虚拟磁盘显示位 “没有初始化”,其大小为 10GB,均未分配分区,可以初步判断该虚拟磁盘的 MBR(主引导扇区)损坏。

使用 Winhex 打开虚拟磁盘

使用 Winhex 打开该虚拟磁盘后可以观察到,主引导扇区损坏,首先填写位于最后两个字节的结束标志 55 AA

寻找分区

从 1 扇区向下搜索 !00,可以找到第一个分区的起始位置,观察到该扇区的结构为 EXT3 文件系统的超级块,可以初步判断该分区为 EXT3 文件系统。

观察教程中提供的超级块结构,可以发现该分区的 0 号超级块损坏,因此需要从备份超级块恢复 0 号超级块。

寻找备份超级块

向上跳转 2 扇区,到达分区起始位置,在记事本中记下分区类型,分区位置。

向下跳转 32768 (每块组块数) * 8 (每块扇区数) = 262144 (每块组扇区数) 个扇区

你也可以向下进行偏移搜索 53 EF,可以找到该分区的备份超级块,将其复制到 0 号超级块的位置。

但在此次实例中,向下搜索 53 EF 的第一个搜索结果为 .journal (日志)内的数据,如果需要寻找备份超级块,需要向下继续搜索

当然日志内的备份也是可以使用的

通过跳转/搜索后,可以找到该分区的备份超级块,将其复制到 0 号超级块的位置。

需要注意的是,备份超级块的 当前超级块所在块组 需要修改为 0。

计算分区大小,填写分区表

查看超级块中的 总块数,计算分区大小,填写分区表。

总块数 * 每块扇区数 = 分区大小

2,621,184 * 8 = 20,969,472

故该分区数据为

分区类型 分区起始位置 分区大小
83 2048 20,969,472

填入 MBR 后,保存后重新打开磁盘,可以发现分区已经恢复。

打开分区,恢复文件

打开分区,找到 Kristina_Bell.png 文件,右键恢复。