技术宅的结界

 找回密码
 立即注册→加入我们

QQ登录

只需一步,快速开始

搜索
热搜: 下载 VB C 实现 编写
查看: 154|回复: 1
收起左侧

【光盘】解析ISO文件格式

[复制链接]

59

主题

109

回帖

1万

积分

用户组: 超级版主

OS与VM研究学者

UID
1043
精华
33
威望
751 点
宅币
7479 个
贡献
1053 次
宅之契约
0 份
在线时间
1780 小时
注册时间
2015-8-15
发表于 2022-12-23 04:43:20 | 显示全部楼层 |阅读模式

欢迎访问技术宅的结界,请注册或者登录吧。

您需要 登录 才可以下载或查看,没有账号?立即注册→加入我们

x
本帖最后由 tangptr@126.com 于 2022-12-23 04:45 编辑

前言

先说结论:ISO文件(光驱映像)本身没有格式。有格式的东西是光盘。
本质上和FLP文件(软驱映像)格式一样,ISO文件的格式可以认为是Flat Binary。

光盘定义

通常说硬盘的时候,一个扇区是512字节。但是在光盘上,一个扇区是2048字节。
光盘有虚拟扇区的定义,意义在于模拟硬盘,软盘等。一个虚拟扇区大小是512字节。

ISO-9660标准没有特别规定只使用何种字节序,但是会明确指出某个字段会使用何种字节序。某些字段甚至会给出小端序和大端序两份数值。

ISO-9660标准

在ISO-9660标准(即CDFS文件系统)下,光盘的前16个扇区不使用,第0x10个扇区开始,每个扇区存放一个卷描述符(Volume Descriptor)。
卷描述符的前7个字节的定义是一致的。

  • +0x000处的一个字节是一个整数,用于描述该卷描述符的类型。
  • +0x001处的五个字节是一个字符串,是一个签名标识符,应当是CD001
  • +0x006处的一个字节用于描述版本,目前只有一个版本,就是1

卷描述符类型

卷描述符有以下类型:

描述
0 启动记录
1 主要卷描述符
2 补充卷描述符
3 卷分区描述符
4-254 保留未用
255 终止描述符

一般而言,启动记录必须在第0x11个扇区上,主要卷描述符必须在第0x10个扇区上。终止描述符用于表示光盘里的最后一个卷描述符。

启动记录

目前而言,光盘启动记录至今就只有一种规范,即El Torito规范,即便是UEFI也遵守该规范来启动程序。
如无说明,则整数以小端序表示。
遵守El Torito规范的启动记录所在扇区内容不多。
从第0x07至第0x26个字节,是一个EL TORITO SPECIFICATION字符串。第0x27至第0x46个字节保留不用。
第0x47至第0x4A个字节是一个32位的整数,用于描述启动目录(Booting Catalog)所在扇区。

启动目录

启动目录本质是“启动目录项”的数组,每个项均为32字节。
第一项为“验证项”(Validation Entry):

偏移量 类型 描述
0x00 字节 项标识符,验证项的标识符必须为0x01
0x01 字节 平台标识符,0表示80x86,1表示PowerPC,2表示Mac
0x02 16位字 保留不用
0x04 字符串 该光盘的制造商/开发者
0x1C 16位整数 校验和
0x1E 16位整数 0xAA55,注意校验和包含了0xAA55

随后是初始项/默认项(Initial/Default Entry):

偏移量 类型 描述
0x00 字节 启动指示量:0x88表示可启动,0x00表示不可启动
0x01 字节 启动媒介类型。高四位保留不用,低四位表示类型:0为光盘模式(无模拟),1为模拟1.2M软盘,2为模拟1.44M软盘,3为模拟2.88M软盘,4为模拟硬盘
0x02 16位整数 启动段选择子。对于平坦内存模型的处理器上,表示启动地址/16。为0时,则段选择子为0x7C0
0x04 字节 系统类型
0x05 字节 保留
0x06 16位整数 启动时固件加载到内存里的模拟扇区数(一个扇区512字节)
0x08 32位整数 启动扇区号
0x0C 字节数组 保留不用

在初始项之后是节(Section),每个节带一个节头(Section Header)。但需要注意的是启动记录里未必有节。

偏移量 类型 描述
0x00 字节 节头指示量: 0x90表示这是个节,0x91表示这是最后一节
0x01 字节 平台标识符
0x02 16位字 该节中有多少个项
0x04 字符串 节ID

节里放的是节项(Section Entry),内容和初始项相似,重复内容不在赘述,可参考初始项。

偏移量 类型 描述
0x00 字节 启动指示量:0x88表示可启动,0x00表示不可启动
0x01 字节 启动媒介类型。低四位表示类型;第4位保留不用;第5位表示该项有节项拓展(Section Entry Extension);第6位表示映像包含ATAPI驱动;第7位表示映像包含SCSI驱动
0x02 16位整数 启动段选择子
0x04 字节 系统类型
0x05 字节 保留
0x06 16位整数 启动时固件加载到内存里的模拟扇区数
0x08 32位整数 启动扇区号
0x0C 字节 选择标准:0表示无标准,1表示IBM的语言与版本信息,其他值保留不用
0x0D 字节数组 发行者的选择标准信息,如果0x13个字节不够,可以使用节项拓展

节项拓展定义如下:

偏移量 类型 描述
0x00 字节 节项拓展指示量:必须是0x44
0x01 字节 第五位置位时表示后面还有节项拓展,复位表示无节项拓展。其余位保留不用
0x02 字节数组 发行者的选择标准信息,如果0x1E个字节不够,可以继续使用节项拓展

简单总结一下,El Torito标准下,一个启动目录里,每个项均为32个字节,以验证项(Validation Entry)开头,紧跟一个初始项/默认项(Initial/Default Entry)。启动目录里可能会有一个或多个节,节头的指示量会表示这是否是最后一个节,以及该节之内有多少个节项。每个节项可能会有一个或多个扩展项,见第1个字节的第5位,节项扩展的第1节第5位会指示是否位最后一个扩展项。
最后,由于默认光盘启动的入口是0x7C0:0,不是0:0x7C00,因此如果你的实模式启动代码要兼容光盘的话,必须用远跳把cs段选择子切到0x0上。EFI启动无需考虑这一条。

主要卷描述符

如果需要枚举光盘里的文件,就有必要解析这个卷描述符了。

偏移量 类型 描述
0x000 字节 卷描述符类型标识符,此处为0x00
0x001 字符串 卷描述符标识符,必须为CD001
0x006 字节 版本,一直为0x01
0x007 字节 保留不用,一直为0
0x008 字符串 系统标识符
0x028 字符串 卷标识符
0x048 保留不用,一直为0
0x050 32位整数-小大端 卷内的扇区数量
0x058 保留不用,一直为0
0x078 16位整数-小大端 卷内磁盘数量
0x07C 16位整数-小大端 卷内磁盘序号
0x080 16位整数-小大端 扇区大小
0x084 32位整数-小大端 路径表大小
0x08C 32位小端整数 小端路径表扇区号
0x090 32位小端整数 小端可选路径表扇区号
0x094 32位大端整数 大端路径表扇区号
0x098 32位大端整数 大端可选路径表扇区号
0x09C 目录结构 根目录
0x0BE 字符串 卷集
0x13E 字符串 出版社
0x1BE 字符串 数据准备者
0x23E 字符串 应用
0x2BE 字符串 版权所有者
0x2E3 字符串 摘要
0x308 字符串 引用
0x32D 字符串 创建时间
0x33E 字符串 修改时间
0x34F 字符串 过期时间
0x360 字符串 有效时间
0x371 字节 文件结构版本
0x372 字节 保留不用,一直为0
0x373 随意使用,ISO不使用
0x573 由ISO标准保留

目录

我们具体看+0x09C偏移的根目录项,其类型为目录结构,定义如下:

偏移量 类型 描述
0x00 字节 记录长度
0x01 字节 扩展属性长度
0x02 32位整数-小大端 扇区号
0x0A 32位整数-小大端 数据大小
0x12 字节数组 日期
0x19 字节 文件标志位
0x1A 字节 Interleaved模式下,文件大小单位。非Interleaved模式下保留不用
0x1B 字节 Interleaved模式下,文件间隙大小。非Interleaved模式下保留不用
0x1C 16位整数-小大端 卷序列号
0x20 字节 文件名长度
0x21 字符串 文件名
可变 字节 2字节对齐:如果字符串长度为奇数,则该字节不用
可变 系统使用:ISO-9660标准的扩展定义,如SUSP协议,RRIP协议等

每个目录项最小34字节,最大254个字节,以2字节对齐紧凑排列。ISO-9660不允许目录结构跨扇区,故扇区结尾不足以存放一个目录结构时,需要把目录结构延后到下一个扇区存储。
前两个目录结构均为34字节:前者的文件名长度为0,表示当前目录,即.;后者的文件名长度为1,表示上一个目录,即..
后续目录结构存放的目录之下的所有文件。

文件标志位定义如下:

描述
0 文件是否隐藏
1 文件是否为目录
2 文件是为“关联文件”
3 文件是否包含扩展属性
4 文件是否包含所有者权限信息
5,6 保留不用
7 该目录项未完成描述一个文件,比如超过4G的文件

文件日期的结构如下:

字节 描述
0 年-1900
1
2
3
4
5
6 相对于格林威治时区的偏移量,以15分钟为单位

路径表

ISO-9660还定义了个路径表,这张表里包含的是目录关联表,不包含文件。一式两份,大小端各一份,定义如下:

偏移量 类型 描述
0x0 字节 目录名长度
0x1 字节 扩展属性长度
0x2 32位整数 扇区号
0x6 16位整数 上级目录索引
0x8 字符串 目录名
可变 字节 2字节对齐:如果字符串长度为偶数,则该字节不用

每个路径表项最小10字节,以2字节对齐紧凑排列。ISO-9660允许路径表结构跨扇区
注意:目录索引以1为底。
由于索引号是16位数,以1为底,故标准的ISO-9660光盘不得存放多于65536个目录。
扇区存储的内容为目录结构表。

查找文件

由于存在着两套结构,因此查找文件的时候也有两个套路。
一种方式是递归式地照着目录结构顺路径序查找。
另一种方式是根据路径表逆路径序查找。
两者的理论时间复杂度均为准矩形复杂度,但前者的时间复杂度是$O(x\cdot\log(y+z))$,而后者是$O(x\cdot\log(y)+\log(z))$,其中$x$是路径深度,$y$为目录数量,$z$为文件数量。(注意这里已经按名称排过序了,因此可以结合strncmp函数来二分查找)
在理论层面上,显然路径表要有优势。在实践层面上,由于路径表的体积比目录结构要小得多,走路径表来查找文件的方式可以更好地利用缓存来加速搜索。

ISO-13346标准

ISO-13346即UDF光盘文件系统,但篇幅所限,本文并不想讲这个标准。
ISO-13346通常可以和ISO-9660兼容,但仅支持ISO-9660的光盘读取器在枚举文件的时候往往只会枚举到一个README.TXT,里面写着:

This disc contains a "UDF" file system and requires an operating system
that supports the ISO-13346 "UDF" file system specification.

ISO-13346标准与El Torito兼容,因此固件仍能以老套路加载ISO-13346光盘里的OS启动器,但这个光盘里的OS启动器必须要能正确解析ISO-13346格式。

总结

光盘有ISO-9660和ISO-13346两种文件格式,前者为CDFS文件系统,后者为UDF文件系统。
以光盘启动时,入口地址一般为0x7C0:0,而非0:0x7C00。因此如果你的启动器需要兼容光盘启动,需要用远跳指令修正cs段选择子。
本文未讲述UEFI启动时El Torito的工作原理,以后和ISO-13346一并解析。

评分

参与人数 5威望 +160 宅币 +220 贡献 +165 收起 理由
DeHby + 30 + 5 屌!
cnHopeStudio + 30 完美!终于明白了!
啊喵~ + 30 + 30 + 30
Golden Blonde + 100 + 100 + 100 赞!
0xAA55 + 30 + 30 + 30 屌!

查看全部评分

回复

使用道具 举报

52

主题

231

回帖

8973

积分

用户组: 管理员

UID
77
精华
16
威望
237 点
宅币
7890 个
贡献
246 次
宅之契约
0 份
在线时间
229 小时
注册时间
2014-2-22
发表于 2022-12-25 14:32:28 | 显示全部楼层
在REACTOS的boot\freeldr\freeldr\lib\fs目录下有解析iso文件的C语言代码。

除此之外,还有解析FAT、NTFS和EXT2的代码。

本版积分规则

QQ|申请友链||Archiver|手机版|小黑屋|技术宅的结界 ( 滇ICP备16008837号 )|网站地图

GMT+8, 2023-2-5 22:02 , Processed in 0.038860 second(s), 30 queries , Gzip On.

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表