diff options
author | Evgeny Zinoviev <me@ch1p.com> | 2019-11-05 19:07:45 +0300 |
---|---|---|
committer | Evgeny Zinoviev <me@ch1p.com> | 2019-11-05 19:54:53 +0300 |
commit | 5977203387d1ffa5dbe1fbf0e83554dccfe08c20 (patch) | |
tree | d31cedf042c696ebdcdb3596fcc2c17f1c60cdc8 | |
parent | 97d4ccbe17ac8f90a3b9b99e59b5999bec210250 (diff) |
update text, add screenshots, add a copy of geteltorito script
-rw-r--r-- | README.md | 161 | ||||
-rw-r--r-- | screenshots/bios-legacy-first.jpg | bin | 0 -> 89778 bytes | |||
-rw-r--r-- | screenshots/bios-legacy-only.jpg | bin | 0 -> 91350 bytes | |||
-rw-r--r-- | screenshots/bios-uefi-first.jpg | bin | 0 -> 86495 bytes | |||
-rw-r--r-- | screenshots/bios-uefi-only.jpg | bin | 0 -> 90828 bytes | |||
-rw-r--r-- | screenshots/flashing1.jpg | bin | 0 -> 88342 bytes | |||
-rw-r--r-- | screenshots/flashing2.jpg | bin | 0 -> 80186 bytes | |||
-rwxr-xr-x | scripts/geteltorito | 228 |
8 files changed, 325 insertions, 64 deletions
@@ -1,18 +1,32 @@ This document describes known methods of flashing BIOS on xx20 and xx30 series of Lenovo ThinkPads without external programmer. The main goal is flashing coreboot while running stock BIOS. +# Table of Contents + +- [IvyBridge series (X230, T430, etc.)](#ivybridge-series-x230-t430-etc) + - [Introduction](#ivybridge-series-x230-t430-etc) + - [Requirements](#requirements) + - [BIOS versions](#bios-versions) + - [Downgrading BIOS](#downgrading-bios) + - [Examining and removing protections](#examining-and-removing-protections) + - [Theory](#theory) + - [Practice](#practice) +- [SandyBridge series (X220, T420, etc.): WIP](#sandybridge-series-x220-t420-etc-wip) +- [Troubleshooting](#troubleshooting) +- [Credits](#credits) + # IvyBridge series (X230, T430, etc.) Old versions of stock BIOS for these models have several security issues. In context of this guide, two of them are of interest. -**First** is the fact the SMM_BWP and BLE are not enabled in BIOS versions released before 2014. I have tested many versions on T430 (and some on X230) and I found out that SMM_BWP=1 only since the update, the changelog of which contains following line: +**First** is the fact the SMM_BWP and BLE are not enabled in BIOS versions released before 2014. I have tested many versions on T430 and X230 and found out that SMM_BWP=1 only since the update, the changelog of which contains following line: > (New) Improved the UEFI BIOS security feature. **Second** is [S3 Boot Script vulnerability](https://support.lenovo.com/eg/ru/product_security/s3_boot_protect), that was discovered and fixed later. -## Requirements: +## Requirements -- a USB drive (in case you need to downgrade BIOS) +- USB drive (in case you need to downgrade BIOS) - Linux install that (can be) loaded in UEFI mode ## BIOS versions @@ -25,13 +39,13 @@ Below is a list of BIOS versions that are vulnerable enough for our goals, per m **T530**: 2.60<br> **W530**: 2.58 -If your BIOS version is equal or lower, skip to the **Examining and removing protections** section. If not, go through the downgrade process, described next. +If your BIOS version is equal or lower, skip to the **[Examining and removing protections](#examining-and-removing-protections)** section. If not, go through the downgrade process, described next. ## Downgrading BIOS Go to the Lenovo web site and download BIOS Update Bootable CD for your machine of needed version (see above). -Lenovo states that BIOS has "security rollback prevention", meaning once you update it to some version X, you will not be able to downgrade it to pre-X version. That's not true. It seems that this is completely client-side restriction in flashing utilities (both Windows utility and Bootable CD). You just have to call winflash.exe or dosflash.exe directly. Therefore you need to modify the bootable CD image you just downloaded. +Lenovo states that BIOS has "security rollback prevention", meaning once you update it to some version X, you will not be able to downgrade it to pre-X version. That's not true. It seems that this is completely client-side restriction in flashing utilities (both Windows utility and Bootable CD). You just need to call `winflash.exe` or `dosflash.exe` directly. Therefore you need to modify the bootable CD image you just downloaded. Extract an El Torito image: ``` @@ -41,19 +55,19 @@ Mount the partition in that image: ``` sudo mount -t vfat ./bios.img /mnt -o loop,offset=16384 ``` -List files, find the AUTOEXEC.BAT file and the FLASH directory: +List files, find the `AUTOEXEC.BAT` file and the `FLASH` directory: ``` ls /mnt ls /mnt/FLASH ``` -Inside the FLASH directory, there should be a directory called G1ET93WW or similar (exact name depends on your ThinkPad model). See what's inside: +Inside the `FLASH` directory, there should be a directory called `G1ET93WW` or similar (exact name depends on your ThinkPad model). See what's inside: ``` ls /mnt/FLASH/G1ET93WW ``` -There must be a file with `.FL1` extension called $01D2000.FL1 or something similar. +There must be a file with `.FL1` extension called `$01D2000.FL1` or something similar. -Now open the AUTOEXEC.BAT file: +Now open the `AUTOEXEC.BAT` file: ``` sudo vim /mnt/AUTOEXEC.BAT ``` @@ -64,12 +78,12 @@ PROMPT $p$g cd c:\flash command.com ``` -Replace the last line (`command.com`) with this (change path to .FL1 file according to yours): +Replace the last line (`command.com`) with this (change path to the `.FL1` file according to yours): ``` dosflash.exe /sd /file G1ET93WW\$01D2000.FL1 ``` -Save the file and unmount the partition: +Save the file, then unmount the partition: ``` sudo unmount /mnt ``` @@ -79,25 +93,36 @@ Write this image to a USB drive (replace `/dev/sdX` with your USB drive device n dd if=./bios.img of=/dev/sdX bs=1M ``` -Now reboot and enter BIOS settings (press F1). Open the "Startup" tab and set the "UEFI/Legacy Boot" option to "Legacy Only" (or "Both" and "Legacy First"). +Now reboot and press F1 to enter BIOS settings. Open the **Startup** tab and set the startup mode to **Legacy Only** (or **Legacy First**): + +<a href="/screenshots/bios-legacy-only.jpg"><img src="/screenshots/bios-legacy-only.jpg" width="250px" /></a> +<a href="/screenshots/bios-legacy-first.jpg"><img src="/screenshots/bios-legacy-first.jpg" width="250px" /></a> Press F10 to save changes and reboot. Now, before you process, make sure that AC adapter is connected! If your battery will die during the process, you'll likely need external programmer to recover. -Boot from the USB drive (press F12 to select boot device), and BIOS flashing process should begin. +Boot from the USB drive (press F12 to select boot device), and BIOS flashing process should begin: + +<a href="/screenshots/flashing1.jpg"><img src="/screenshots/flashing1.jpg" width="250px" /></a> +<a href="/screenshots/flashing2.jpg"><img src="/screenshots/flashing2.jpg" width="250px" /></a> + +It may reboot a couple of times in the process. Do not interrupt it. ## Examining and removing protections ### Preparations -Enter BIOS settings and set the "UEFI/Legacy Boot" option to "UEFI Only", or to "Both" and "UEFI First". +Enter BIOS settings and set the startup mode to **UEFI Only** (or **UEFI First**). + +<a href="/screenshots/bios-uefi-only.jpg"><img src="/screenshots/bios-uefi-only.jpg" width="250px" /></a> +<a href="/screenshots/bios-uefi-first.jpg"><img src="/screenshots/bios-uefi-first.jpg" width="250px" /></a> Now boot to your Linux system and make sure that `/sys/firmware/efi` or `/sys/firmware/efivars` exist. [Install CHIPSEC](https://github.com/chipsec/chipsec/wiki/Installing-CHIPSEC-in-Linux). You will need two patches for it, as they are not merged yet: [#737](https://github.com/chipsec/chipsec/pull/737) and [#738](https://github.com/chipsec/chipsec/pull/738). Without those patches, s3script_modify will not work. -### Theory +### Theory There are two (or two and a half, lol) main ways that Intel platform provides to protect BIOS chip: - **BIOS_CNTL** register of LPC Interface Bridge Registers (accessible via PCI configuration space, offset 0xDC). It has: @@ -119,14 +144,14 @@ You should see that FLOCKDN=1: [x][ Module: SPI Flash Controller Configuration Locks [x][ ======================================================================= [*] HSFS = 0xE009 << Hardware Sequencing Flash Status Register (SPIBAR + 0x4) - [00] FDONE = 1 << Flash Cycle Done - [01] FCERR = 0 << Flash Cycle Error - [02] AEL = 0 << Access Error Log - [03] BERASE = 1 << Block/Sector Erase Size - [05] SCIP = 0 << SPI cycle in progress - [13] FDOPSS = 1 << Flash Descriptor Override Pin-Strap Status - [14] FDV = 1 << Flash Descriptor Valid - [15] FLOCKDN = 1 << Flash Configuration Lock-Down + [00] FDONE = 1 << Flash Cycle Done + [01] FCERR = 0 << Flash Cycle Error + [02] AEL = 0 << Access Error Log + [03] BERASE = 1 << Block/Sector Erase Size + [05] SCIP = 0 << SPI cycle in progress + [13] FDOPSS = 1 << Flash Descriptor Override Pin-Strap Status + [14] FDV = 1 << Flash Descriptor Valid + [15] FLOCKDN = 1 << Flash Configuration Lock-Down ``` Then check BIOS_CNTL and PR0-PR4: @@ -142,11 +167,11 @@ Bad news: there are 4 write protected SPI ranges: [x][ Module: BIOS Region Write Protection [x][ ======================================================================= [*] BC = 0x 8 << BIOS Control (b:d.f 00:31.0 + 0xDC) - [00] BIOSWE = 0 << BIOS Write Enable - [01] BLE = 0 << BIOS Lock Enable - [02] SRC = 2 << SPI Read Configuration - [04] TSS = 0 << Top Swap Status - [05] SMM_BWP = 0 << SMM BIOS Write Protection + [00] BIOSWE = 0 << BIOS Write Enable + [01] BLE = 0 << BIOS Lock Enable + [02] SRC = 2 << SPI Read Configuration + [04] TSS = 0 << Top Swap Status + [05] SMM_BWP = 0 << SMM BIOS Write Protection [-] BIOS region write protection is disabled! [*] BIOS Region: Base = 0x00500000, Limit = 0x00BFFFFF @@ -154,25 +179,29 @@ SPI Protected Ranges ------------------------------------------------------------ PRx (offset) | Value | Base | Limit | WP? | RP? ------------------------------------------------------------ -PR0 (74) | 00000000 | 00000000 | 00000000 | 0 | 0 -PR1 (78) | 8BFF0B40 | 00B40000 | 00BFFFFF | 1 | 0 -PR2 (7C) | 8B100B10 | 00B10000 | 00B10FFF | 1 | 0 -PR3 (80) | 8ADE0AD0 | 00AD0000 | 00ADEFFF | 1 | 0 -PR4 (84) | 8AAF0800 | 00800000 | 00AAFFFF | 1 | 0 +PR0 (74) | 00000000 | 00000000 | 00000000 | 0 | 0 +PR1 (78) | 8BFF0B40 | 00B40000 | 00BFFFFF | 1 | 0 +PR2 (7C) | 8B100B10 | 00B10000 | 00B10FFF | 1 | 0 +PR3 (80) | 8ADE0AD0 | 00AD0000 | 00ADEFFF | 1 | 0 +PR4 (84) | 8AAF0800 | 00800000 | 00AAFFFF | 1 | 0 ``` Other way to examine SPI configuration registers is to just dump SPIBAR: ``` sudo chipsec_util mmio dump SPIBAR ``` -You will see SPIBAR address and registers (for example, 00000004 is HSFS): +You will see SPIBAR address (0xFED1F800) and registers (for example, 00000004 is HSFS): ``` [mmio] MMIO register range [0x00000000FED1F800:0x00000000FED1F800+00000200]: +00000000: 0BFF0500 +00000004: 0004E009 ... ``` -Now the fun part! FLOCKDN may only be cleared by a hardware reset, which includes S3 state. On S3 resume boot path, the chipset configuration has to be restored and it's done by executing "S3 Boot Scripts". You can dump these scripts by executing: +As you can see, the only thing we need is to unset WP on PR0-PR4. But that cannot be done once FLOCKDN is set to 1. + +Now the fun part! + +FLOCKDN may only be cleared by a hardware reset, which includes S3 state. On S3 resume boot path, the chipset configuration has to be restored and it's done by executing so-called S3 Boot Scripts. You can dump these scripts by executing: ``` sudo chipsec_util uefi s3bootscript ``` @@ -180,8 +209,8 @@ There are many entries. Along them, you can find instructions to write to HSFS ( ``` Entry at offset 0x2B8F (len = 0x17, header len = 0x0): Data: -02 00 17 02 00 00 00 01 00 00 00 04 f8 d1 fe 00 | -00 00 00 09 e0 04 00 | +02 00 17 02 00 00 00 01 00 00 00 04 f8 d1 fe 00 | +00 00 00 09 e0 04 00 | Decoded: Opcode : S3_BOOTSCRIPT_MEM_WRITE (0x0002) Width : 0x02 (4 bytes) @@ -189,7 +218,7 @@ Decoded: Count : 0x1 Values : 0x0004E009 ``` -These scripts are located in memory. The vulnerability is that we can overwrite this memory, change these instructions and they will be executed on S3 resume. +These scripts are stored in memory. The vulnerability is that we can overwrite this memory, change these instructions and they will be executed on S3 resume. Once we patch that instruction to not set FLOCKDN bit, we will be able to write to PR0-PR4 registers. ### Practice The original script writes 0xE009 to HSFS. FLOCKDN is 15th bit, so let's write 0x6009 instead. @@ -203,34 +232,36 @@ You will get a lot of output and in the end you should see something like this: [*] Modifying S3 boot script entry at address 0x00000000DAF49B8F.. [mem] 0x00000000DAF49B8F [*] Original entry: - 2 0 17 2 0 0 0 1 0 0 0 4 f8 d1 fe 0 | - 0 0 0 9 e0 4 0 | + 2 0 17 2 0 0 0 1 0 0 0 4 f8 d1 fe 0 | + 0 0 0 9 e0 4 0 | [mem] buffer len = 0x17 to PA = 0x00000000DAF49B8F - 2 0 17 2 0 0 0 1 0 0 0 4 f8 d1 fe 0 | - 0 0 0 9 60 0 0 | ` + 2 0 17 2 0 0 0 1 0 0 0 4 f8 d1 fe 0 | + 0 0 0 9 60 0 0 | ` [mem] 0x00000000DAF49B8F [*] Modified entry: - 2 0 17 2 0 0 0 1 0 0 0 4 f8 d1 fe 0 | - 0 0 0 9 60 0 0 | ` -[*] After sleep/resume, check the value of register 0xFED1F804 is 0x6008 + 2 0 17 2 0 0 0 1 0 0 0 4 f8 d1 fe 0 | + 0 0 0 9 60 0 0 | ` +[*] After sleep/resume, check the value of register 0xFED1F804 is 0x6009 [+] PASSED: The script has been modified. Go to sleep.. ``` Now go to S3, then resume and check FLOCKDN. It should be 0: ``` sudo chipsec_main -m chipsec.modules.common.spi_lock +``` +``` ... [x][ ======================================================================= [x][ Module: SPI Flash Controller Configuration Locks [x][ ======================================================================= [*] HSFS = 0x6008 << Hardware Sequencing Flash Status Register (SPIBAR + 0x4) - [00] FDONE = 0 << Flash Cycle Done - [01] FCERR = 0 << Flash Cycle Error - [02] AEL = 0 << Access Error Log - [03] BERASE = 1 << Block/Sector Erase Size - [05] SCIP = 0 << SPI cycle in progress - [13] FDOPSS = 1 << Flash Descriptor Override Pin-Strap Status - [14] FDV = 1 << Flash Descriptor Valid - [15] FLOCKDN = 0 << Flash Configuration Lock-Down + [00] FDONE = 0 << Flash Cycle Done + [01] FCERR = 0 << Flash Cycle Error + [02] AEL = 0 << Access Error Log + [03] BERASE = 1 << Block/Sector Erase Size + [05] SCIP = 0 << SPI cycle in progress + [13] FDOPSS = 1 << Flash Descriptor Override Pin-Strap Status + [14] FDV = 1 << Flash Descriptor Valid + [15] FLOCKDN = 0 << Flash Configuration Lock-Down [-] SPI Flash Controller configuration is not locked [-] FAILED: SPI Flash Controller not locked correctly. ... @@ -255,11 +286,11 @@ sudo chipsec_main -m common.bios_wp [x][ Module: BIOS Region Write Protection [x][ ======================================================================= [*] BC = 0x 9 << BIOS Control (b:d.f 00:31.0 + 0xDC) - [00] BIOSWE = 1 << BIOS Write Enable - [01] BLE = 0 << BIOS Lock Enable - [02] SRC = 2 << SPI Read Configuration - [04] TSS = 0 << Top Swap Status - [05] SMM_BWP = 0 << SMM BIOS Write Protection + [00] BIOSWE = 1 << BIOS Write Enable + [01] BLE = 0 << BIOS Lock Enable + [02] SRC = 2 << SPI Read Configuration + [04] TSS = 0 << Top Swap Status + [05] SMM_BWP = 0 << SMM BIOS Write Protection [-] BIOS region write protection is disabled! [*] BIOS Region: Base = 0x00500000, Limit = 0x00BFFFFF @@ -267,11 +298,11 @@ SPI Protected Ranges ------------------------------------------------------------ PRx (offset) | Value | Base | Limit | WP? | RP? ------------------------------------------------------------ -PR0 (74) | 0AAF0800 | 00800000 | 00AAF000 | 0 | 0 -PR1 (78) | 0ADE0AD0 | 00AD0000 | 00ADE000 | 0 | 0 -PR2 (7C) | 0B100B10 | 00B10000 | 00B10000 | 0 | 0 -PR3 (80) | 0BFF0B40 | 00B40000 | 00BFF000 | 0 | 0 -PR4 (84) | 00000000 | 00000000 | 00000000 | 0 | 0 +PR0 (74) | 0AAF0800 | 00800000 | 00AAF000 | 0 | 0 +PR1 (78) | 0ADE0AD0 | 00AD0000 | 00ADE000 | 0 | 0 +PR2 (7C) | 0B100B10 | 00B10000 | 00B10000 | 0 | 0 +PR3 (80) | 0BFF0B40 | 00B40000 | 00BFF000 | 0 | 0 +PR4 (84) | 00000000 | 00000000 | 00000000 | 0 | 0 ``` Bingo! @@ -281,7 +312,9 @@ Now you can flash coreboot (or anything else) with flashrom. Remember to flash only `bios` region (use `--ifd -i bios -N`). `fd` and `me` are still locked. # SandyBridge series (X220, T420, etc.): WIP -S3 Boot Scripts are unprotected on these models too (even on the most recent BIOS versions), but it's not useful, because FLOCKDN and SPI protected ranges are set by **LenovoFlashProtectPei** UEFI module. It is trivial to patch it, but it resides in protected range, so it can only be flashed externally. Currenly there are no known methods to unlock PRs on these devices, but investigation is ongoing. +S3 Boot Scripts are unprotected on these models too (even on the most recent BIOS versions), but it's not useful, because FLOCKDN and SPI protected ranges are set by **LenovoFlashProtectPei** UEFI module. It is trivial to patch it, but it resides in protected range, so it can only be flashed externally. + +Currenly there are no known methods to unlock PRs on these devices internally, but investigation is ongoing. # Troubleshooting If something doesn't work, please let me know by creating an issue, or ask me on #coreboot. diff --git a/screenshots/bios-legacy-first.jpg b/screenshots/bios-legacy-first.jpg Binary files differnew file mode 100644 index 0000000..ced7453 --- /dev/null +++ b/screenshots/bios-legacy-first.jpg diff --git a/screenshots/bios-legacy-only.jpg b/screenshots/bios-legacy-only.jpg Binary files differnew file mode 100644 index 0000000..81041ed --- /dev/null +++ b/screenshots/bios-legacy-only.jpg diff --git a/screenshots/bios-uefi-first.jpg b/screenshots/bios-uefi-first.jpg Binary files differnew file mode 100644 index 0000000..02fc2f9 --- /dev/null +++ b/screenshots/bios-uefi-first.jpg diff --git a/screenshots/bios-uefi-only.jpg b/screenshots/bios-uefi-only.jpg Binary files differnew file mode 100644 index 0000000..3a78250 --- /dev/null +++ b/screenshots/bios-uefi-only.jpg diff --git a/screenshots/flashing1.jpg b/screenshots/flashing1.jpg Binary files differnew file mode 100644 index 0000000..b2c9fdc --- /dev/null +++ b/screenshots/flashing1.jpg diff --git a/screenshots/flashing2.jpg b/screenshots/flashing2.jpg Binary files differnew file mode 100644 index 0000000..203de69 --- /dev/null +++ b/screenshots/flashing2.jpg diff --git a/scripts/geteltorito b/scripts/geteltorito new file mode 100755 index 0000000..fec18fa --- /dev/null +++ b/scripts/geteltorito @@ -0,0 +1,228 @@ +#!/usr/bin/perl + +use Getopt::Std; + +# +# geteltorito.pl: a bootimage extractor +# Script that will extract the first El Torito bootimage from a +# bootable CD image +# R. Krienke 08/2001 +# krienke@uni-koblenz.de +# License: GPL +# +# Get latest version from: +# http://userpages.uni-koblenz.de/~krienke/ftp/noarch/geteltorito +# +$utilVersion="0.6"; +# +# Version 0.6 +# 2015/02/25 +# I included a patch by Daniel Kekez, daniel.kekez@utoronto.ca to make geteltorito +# better compatible with windows: +# "To run this Perl script using using Strawberry Perl under Windows, I +# found it was necessary to explicitly open the files in binary mode since +# Windows will default to text mode when open() is called." +# Version 0.5 +# 2009/06/22 +# A patch for harddisk emulation images from <colimit@gmail.com>. +# For BootMediaType=4 (harddisk emulation) SectorCount is always 1, and geteltorito.pl +# returns just MBR. This patch guesses the correct bootimage size +# from MBR (offset+size of the first partitition). +# Version 0.4 +# 2007/02/01 +# A patch from Santiago Garcia <manty@debian.org> to use a virtual sector +# size (vSecSize) of 512 bytes, as defined on "El Torito" specs and change +# unpack of the sector count from n to v to get the correct sector count. +# Version 0.3 +# 2006/02/21 +# A patch from Ben Collins <bcollins@ubuntu.com> to make the +# utility work on PPC machines (change from 'L'-encoding in pack to 'V') +# Version 0.2 +# Several patches included from Nathan Stratton Treadway(nathant@ontko.com) +# to adjust the platform output as well as fixes for other minor bugs +# Version 0.1 +# Initial release +# +# For information on El Torito see +# http://en.wikipedia.org/wiki/El_torito + +$vSecSize=512; +$secSize=2048; +$ret=undef;$version=undef;$opt_h=undef;$loadSegment=undef;$systemType=undef; + +# +# Read a particular sector from a file +# sector counting starts at 0, not 1 +# +sub getSector{ + my ($secNum, $secCount, $file)=@_; + my ($sec, $count); + + open(FILE, "<:raw", $file) || die "Cannot open \"$file\" \n"; + + seek(FILE, $secNum*$secSize, 0); + $count=read(FILE, $sec, $vSecSize*$secCount, 0) ; + if( $count != $vSecSize*$secCount ){ + warn "Error reading from file \"$file\"\n"; + } + close(FILE); + + return($sec); +} + + +# +# Write eltorito data into a file +# +sub writeOutputFile{ + my($name)=shift; + my($value)=shift; + + open(OUT, ">:raw", $name)|| die "$0: Cannot open outputfile \"$name\" for writing. Stop."; + print OUT $value; + close(OUT); +} + + +# +# Usage +# +sub usage{ + warn "\n$0 [-hv] [-o outputfilename] cd-image \n", + "Script will try to extract an El Torito image from a \n", + "bootable CD (or cd-image) given by <cd-image> and write \n", + "the data extracted to STDOUT or to a file.\n", + " -h: This help. \n", + " -v: Print version of script and exit.\n", + " -o <file>: Write extracted data to file <file> instead of STDOUT.\n", + "\n\n"; + exit 0; +} + + +# --------------------------------------------------------------------- +$ret=getopts('hvo:'); + +if( defined($opt_v) ){ + warn "Version: $utilVersion \n"; + exit 0; +} + +if( defined($opt_h) || $#ARGV <0 ){ + usage(0); +} + +if( defined($opt_o) ){ + $outputFilename="$opt_o"; +} + +$imageFile=$ARGV[0]; + +if( ! -r $imageFile ){ + die "Cannot read image/device \"$imageFile\". Aborting\n"; +} + +# +# Read Sector 17 from CD which should contain a Boot Record Volume +# descriptor. This descriptor contains at its start the text ($isoIdent) +# CD001 and ($toritoSpec) +# EL TORITO SPECIFICATION +# see http://www.cdpage.com/Compact_Disc_Variations/eltoritoi.html +# for details +# + +$sector=getSector(17, 1, $imageFile ); +($boot, $isoIdent, $version, $toritoSpec, + $unUsed, $bootP)= unpack( "Ca5CA32A32V", $sector ); + +if( $isoIdent ne "CD001" || $toritoSpec ne "EL TORITO SPECIFICATION" ){ + die "This data image does not seem to be a bootable CD-image\n"; +} + +# +# Now fetch the sector of the booting catalog +# +$sector=getSector($bootP, 1, $imageFile ); + +print STDERR "Booting catalog starts at sector: $bootP \n"; + +# The first 32 bytes of this sector contains the validation entry for a +# boot. The first byte has to be 01, the next byte determines the +# architecture the image is designed for, where 00 is i86, 01 is PowerPC +# and 02 is Mac. More data give info about manufacturer, etc. The +# final two bytes must contain 0x55 and 0xAA respectively (as +# defined by the El Torito standard). + +$validateEntry=substr($sector, 0, 32); + +($header, $platform, $unUsed, $manufact, $unUsed, $five, $aa)= + unpack( "CCvA24vCC", $validateEntry); + +if( $header != 1 || $five != 0x55 || $aa != 0xaa ){ + die "Invalid Validation Entry on image \n"; +} + +print STDERR "Manufacturer of CD: $manufact\n"; +print STDERR "Image architecture: "; +print STDERR "x86" if( $platform == 0 ); +print STDERR "PowerPC" if( $platform == 1 ); +print STDERR "Mac" if( $platform == 2 ); +print STDERR "unknown ($platform)" if( $platform > 2 ); +print STDERR "\n"; + +# +# Now we examine the initial/defaultentry which follows the validate +# entry and has a size of 32 bytes. + +$initialEntry=substr($sector, 32, 32); + +($boot, $media, $loadSegment, $systemType, $unUsed, + $sCount, $imgStart, $unUsed)=unpack( "CCvCCvVC", $initialEntry); + +if( $boot != 0x88 ){ + die "Boot indicator in Initial/Default-Entry is not 0x88. CD is not bootable. \n"; +} + +print STDERR "Boot media type is: "; +if( $media == 0 ){ + print STDERR "no emulation"; + $count=0; +} +if( $media == 1 ){ + print STDERR "1.2meg floppy"; + $count=1200*1024/$vSecSize; +} +if( $media == 2 ){ + print STDERR "1.44meg floppy"; + $count=1440*1024/$vSecSize; +} +if( $media == 3 ){ + print STDERR "2.88meg floppy"; + $count=2880*1024/$vSecSize; +} +if( $media == 4 ){ + print STDERR "harddisk"; + $MBR=getSector($imgStart, 1, $imageFile ); + $partition1=substr($MBR, 446, 16); + ($unUsed, $firstSector, $partitionSize) = unpack( "A8VV", $partition1); + $count=$firstSector + $partitionSize; +} +print STDERR "\n"; + +# Only use the internal sector counter if the real size is unknown +# ($count==0) +$cnt=$count==0?$sCount:$count; + +print STDERR "El Torito image starts at sector $imgStart and has $cnt sector(s) of $vSecSize Bytes\n"; + +# We are there: +# Now read the bootimage to stdout +$image=getSector($imgStart, $cnt, $imageFile); + +if( length($outputFilename) ){ + writeOutputFile($outputFilename, $image); + print STDERR "\nImage has been written to file \"$outputFilename\".\n"; +}else{ + print "$image"; + print STDERR "Image has been written to stdout ....\n"; +} |