f.zz.de
posts /

Extract EFI Boot Image from iso file

Posted Thu Mar 24 14:33:01 2022 Florian Lohoff
in

Trying to repack Ubuntu images with addons i had the problem of extracting the EFI boot image from the iso. There are tools like "geteltorito" which basically fail. So i quickly rolled my own with the help of perl and sfdisk.

One issue is that the Ubuntu 20.04 image contains an DOS label, whereas the upcoming 22.04 contains an GPT label. So we need to support both.

#!/usr/bin/perl -w

use strict;
use Fcntl qw/SEEK_CUR O_CREAT O_TRUNC O_WRONLY O_RDONLY/;
use Data::Dumper;
use Capture::Tiny qw/capture/;
use JSON;

my $image=$ARGV[0];
my $output=$ARGV[1];

if (!defined($image) || !defined($output) || $image eq '' || $output eq '') {
        printf("extractefi input.iso efi.img\n");
        exit 1;
}

printf("Using sfdisk to get partition layout\n");
my ($stdout, $stderr, $exit)=capture {
        system(sprintf("/usr/sbin/sfdisk -J %s", $image));
};

if ($exit != 0) {
        printf("Failed to execute sfdisk on image\n%s\n", $stderr);
        exit 1;
}

my $sf=from_json($stdout);

my $efipart;
if ($sf->{partitiontable}{label} eq 'dos') {
        my @efis=grep { $_->{type} eq 'ef' } @{$sf->{partitiontable}{partitions}};
        $efipart=shift @efis;
} elsif ($sf->{partitiontable}{label} eq 'gpt') {
        my @efis=grep { $_->{type} eq 'C12A7328-F81F-11D2-BA4B-00A0C93EC93B' } @{$sf->{partitiontable}{partitions}};
        $efipart=shift @efis;
}

if (!defined($efipart)) {
        printf("Could not find EFI System Partition with UUID C12A7328-F81F-11D2-BA4B-00A0C93EC93B\n");
        exit 1;
}

my $start=$sf->{partitiontable}{sectorsize}*$efipart->{start};
my $size=$sf->{partitiontable}{sectorsize}*$efipart->{size};

printf("Opening file %s to read efi image from offset %d length %d\n", $image, $start, $size);

my $img;
sysopen(my $i, $image, O_RDONLY);
sysseek($i, $start, SEEK_CUR);
my $j=sysread($i, $img, $size);

if ($j != $size) {
        printf("Short read while trying to read EFI system partition\n");
        exit 1;
}
close($i);

printf("Writing efi image %s size %d\n", $output, $size);
sysopen(my $o, $output, O_CREAT|O_TRUNC|O_WRONLY);
syswrite($o, $img, $size);
close($o);