#!/usr/bin/perl use Getopt::Std; # # Script that will extract the first El Torito bootimage from a # bootable CD image # R. Krienke 08/2001 # krienke@uni-koblenz.de # Version 0.1 # # For information on Eltorito see # http://www.cdpage.com/Compact_Disc_Variations/eltoritoi.html $secSize=2048; # # 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, $file) || die "Cannot open \"$file\" \n"; seek(FILE, $secNum*$secSize, 0); $count=read(FILE, $sec, $secSize*$secCount, 0) ; if( $count != $secSize*$secCount ){ warn "Error reading $secSize bytes from file \"$file\"\n"; } close(FILE); return($sec); } # # Usage # sub usage{ die "\n$0 [-h] cd-image \n", " Script will try to extract an El Torito image from a \n", " bootable CD (or cd-image) and write the data extracted to STDOUT\n\n"; } # --------------------------------------------------------------------- $ret=getopts('hmncs:b:r:u:p:f:'); if( defined($opt_h) || $#ARGV <0 ){ usage(0); } $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( "Ca5CA32A32L", $sector ); if( $isoIdent ne "CD001" || $toritoSpec ne "EL TORITO SPECIFICATION" ){ die "This data image does not seem to be an bootable CD-image\n"; } print STDERR "First entry in Bootcataloge is sector number $bootP\n"; # # Now fetch the sector of the bootcatalog # $sector=getSector($bootP, 1, $imageFile ); print STDERR "Bootcataloge start at sector: $bootP \n"; # The first 32 Bytes of this sector contains the validate entry for a # boot. The first Byte hast tobe 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 $validateEntry=substr($sector, 0, 32); ($header, $platform, $unUsed, $manufact, $unUsed, $five, $aa)= unpack( "CCSA24SCC", $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 "x86" if( $platform == 1 ); print STDERR "x86" 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( "CCSCCnLC", $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 "none"; $count=0; } if( $media == 1 ){ print STDERR "1.2meg floppy"; $count=1200*1024/$secSize; } if( $media == 2 ){ print STDERR "1.44meg floppy"; $count=1440*1024/$secSize; } if( $media == 3 ){ print STDERR "2.88meg floppy"; $count=2880*1024/$secSize; } if( $media == 4 ){ print STDERR "harddisk"; $count=0; } print STDERR "\n"; # Only use the inernal sector counter if the real size is unknown # ($count==0) $cnt=$count==0?$sCount:$count; print STDERR "Torito image starts at sector $imgStart and has $cnt sector(s) of $secSize Bytes \n"; # We are there: # Now read the bootimage to stdout $image=getSector($imgStart, $cnt, $imageFile); print "$image"; print STDERR "Image has been written to stdout ....\n";