#!perl -w # (C) 2003-2007 Willem Jan Hengeveld # Web: http://www.xs4all.nl/~itsme/ # http://wiki.xda-developers.com/ # # $Id: $ # # this script analyzes an IBMPC style partition table # # todo: add option to specify a different sector size # use strict; use IO::File; use Getopt::Long; my %typelist= ( 0x00=>'Empty', 0x01=>'FAT-12', 0x02=>'XENIX', 0x03=>'XENIX', 0x04=>'FAT-16', 0x05=>'Extended Partition', 0x06=>'DOS >32Meg', 0x07=>'NTFS', 0x0A=>'Boot Manager', 0x0B=>'FAT-32', 0x0e=>'WIN95: DOS 16-bit FAT, LBA', 0x0f=>'WIN95: Extpartition, LBA', 0x11=>'hid FAT-12', 0x14=>'hid FAT-16', 0x17=>'hid OS/2 HPFS', 0x1B=>'hid FAT-32', 0x1c=>'Hid WIN95 OSR2 FAT32, LBA', 0x1e=>'hid WIN95: DOS 16-bit FAT, LBA', 0x1f=>'hid WIN95: Ext partition, LBA', 0x41=>'linux/minix', 0x82=>'linux/swap', 0x83=>'linux/native', 0x64=>'Novell', 0x75=>'PCIX', 0xDB=>'CPM/Concurrent', 0xFF=>'BBT', ); sub usage { return <<__EOF__ Usage: dumpptable [-o OFFSET] [-b SECSIZE] __EOF__ } my $offset=0; my $sectorsize=0x200; GetOptions( "o=s" => sub { $offset=eval($_[1]); }, "b=s" => sub { $sectorsize=eval($_[1]); }, ) or die usage(); my $fn= shift or die "need filename\n"; my $fh= IO::File->new($fn, "r") or die "$fn: $!\n"; binmode $fh; $fh->seek($offset, SEEK_SET); my $data; $fh->read($data, 512); $fh->close(); if (substr($data, 510, 2) ne "\x55\xaa") { warn "missing 55aa signature at end of ptable\n"; } for (0..3) { my $pdata= substr($data, 0x1be+0x10*$_, 0x10); next if ($pdata eq "\x00" x 16); my $ptab= parsepentry($pdata); printpentry($ptab); } sub printpentry { my $pent= shift; printf("%1s (%s) - (%s) %08lx %08lx %s\n", $pent->{bootable}?"B":"", chs_asstring($pent->{startchs}), chs_asstring($pent->{endchs}), $pent->{startsector}, $pent->{nrsectors}, type_asstring($pent->{type})); printf("offset: %08lx00 - %08lx00 l=%08lx00\n", $offset/0x100+$pent->{startsector}*($sectorsize/0x100), $offset/0x100+$pent->{startsector}*($sectorsize/0x100)+ $pent->{nrsectors}*($sectorsize/0x100), $pent->{nrsectors}*($sectorsize/0x100)); } sub chs_asstring { my $chs= shift; return sprintf("%03x:%02x:%02x", $chs->{cyl}, $chs->{side}, $chs->{sect}); } sub type_asstring { my $type= shift; if (exists $typelist{$type}) { return $typelist{$type}; } return sprintf("%02x", $type); } sub parsepentry { my $pdata= shift; my %pent; my ($startchs, $endchs); ( $pent{bootable}, $startchs, $pent{type}, $endchs, $pent{startsector}, $pent{nrsectors}, ) = unpack("Ca3Ca3VV", $pdata); $pent{startchs}= parsechs($startchs); $pent{endchs}= parsechs($endchs); return \%pent; } sub parsechs { my @chsdata= unpack("C*", shift); return { side=>$chsdata[0], cyl=>(($chsdata[1]&0xc0)<<2) | $chsdata[2], sect=>$chsdata[1]&0x3f, }; }