有点标题党了,起始不是要详细介绍格式,只是今天才发现它的格式有点诡异。之前如果有个 ISO 格式的光盘映像,想从里面提取文件的话,那就是把 UltraISO 祭出来,几乎都能搞定,今天如法炮制 ThinkPad E545 的官网 BIOS 1.18 升级光盘的映像,结果吃了瘪,打开一看是空的。
搜了搜,发现 Linux 下有个命令叫 geteltorito
,可以从这种 .iso 文件里把其中的磁盘映像文件 .img 剥离出来,后者就可以用 7z 打开了。可以参考 ISO 9660 – Wikipedia。
还搜到很早有个老外写过一段脚本,跟上面的命令干的差不多是同一件事,在这儿:Extracting BIOS images and tools from ThinkPad update ISOs – James Henstridge (gnome.org)。脚本使用 Python 写就,抄录如下。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 |
import struct import sys SECTOR_SIZE = 2048 def find_image(fp): # el-torito boot record descriptor fp.seek(0x11 * SECTOR_SIZE) data = fp.read(SECTOR_SIZE) assert data[:0x47] == b'\x00CD001\x01EL TORITO SPECIFICATION' + b'\x0' * 41 boot_catalog_sector = struct.unpack('<L', data[0x47:0x4B])[0] # check the validation entry in the catalog fp.seek(boot_catalog_sector * SECTOR_SIZE) data = fp.read(0x20) assert data[0:1] == b'\x01' assert data[0x1e:0x20] == b'\x55\xAA' assert sum(struct.unpack('<16H', data)) % 0x10000 == 0 # Read the initial/default entry data = fp.read(0x20) (bootable, image_type, load_segment, system_type, sector_count, image_sector) = struct.unpack('<BBHBxHL', data[:12]) image_offset = image_sector * SECTOR_SIZE if image_type == 1: # 1.2MB floppy image_size = 1200 * 1024 elif image_type == 2: # 1.44MB floppy image_size = 1440 * 1024 elif image_type == 3: # 2.88MB floppy image_size = 2880 * 1024 elif image_type == 4: # Hard disk image. Read the MBR partition table to locate file system fp.seek(image_offset) data = fp.read(512) # Read the first partition entry (bootable, part_type, part_start, part_size) = struct.unpack_from( '<BxxxBxxxLL', data, 0x1BE) assert bootable == 0x80 # is partition bootable? image_offset += part_start * 512 image_size = part_size * 512 else: raise AssertionError('unhandled image format: %d' % image_type) fp.seek(image_offset) return fp.read(image_size) if __name__ == '__main__': with open(sys.argv[1], 'rb') as iso, open(sys.argv[2], 'wb') as img: img.write(find_image(iso)) |