#!perl -w # (C) 2003-2007 Willem Jan Hengeveld # Web: http://www.xs4all.nl/~itsme/ # http://wiki.xda-developers.com/ # # $Id: $ # use strict; use IO::File; use Getopt::Long; use XdaDevelopers::BADMD5 qw(badmd5); sub usage { return <<__EOF__; Usage: wallabysd [-w] [-k] [--ce= ] [--bl= ] [--gsm= ] -r imgname : read image(s) from sd/mmc-disk -w imgname : write image(s) to sd/mmc-disk -k : add flashkey when writing ( for bootloader >= 5.17 ) -a : extract all images __EOF__ } my @actions; my %params; $params{counter} = 0; GetOptions( "ce=s" => sub { $params{ceimagename}= $_[1]; }, "bl=s" => sub { $params{blimagename}= $_[1]; }, "gsm=s" => sub { $params{gsmimagename}= $_[1]; }, "diag=s" => sub { $params{diagimagename}= $_[1]; }, "all|a" => sub { $params{allimages}= 1; }, "write|w=s" => sub { $params{sdimgname}= $_[1]; push @actions, \&ActionWriteImagesToSD; }, "read|r=s" => sub { $params{sdimgname}= $_[1]; push @actions, \&ActionReadImagesFromSD; }, "key|k=s" => sub { $params{bl517}=1; $params{addkey}= 1; $params{cardid}= pack("H*", $_[1]); }, "n=s" => sub { $params{counter}= eval($_[1]); }, ) or die usage(); die usage() if (!@actions); for (@actions) { $_->(%params); } exit(0); ############################################################################### ## actions sub resize { if (length($_[0])>$_[1]) { substr($_[0], $_[1])= ""; } elsif (length($_[0])<$_[1]) { $_[0] .= "\x00" x ($_[1] - length($_[0])); } } sub ActionWriteImagesToSD { my (%params)= @_; my $fh= IO::File->new($params{sdimgname}, "w") or die "$params{sdimgname}: $!\n"; binmode $fh; my @cfg;# diag, gsm, ce, boot $cfg[0][0][0][1]= { magic=>'HTC$WALLABY00', blsize=>0x40000 }; # 0x400 = bl $cfg[0][0][1][0]= { magic=>'HTC$WALLABY11', cesize=>0x1fc0000}; # 0x400 = os $cfg[0][0][1][1]= { magic=>'HTC$WALLABY22', cesize=>0x1fc0000, blsize=>0x40000 }; # 0x400 = bl, 0x40400 = os $cfg[1][0][0][0]= { magic=>'HTC$WALLABY33', diagsize=>6144 }; # diag $cfg[0][1][0][0]= { magic=>'HTC$WALLABY44', }; # gsm $cfg[0][1][1][0]= { magic=>'HTC$WALLABY55', cesize=>0x1fc0000 }; # gsm + ce # todo: this is wrong, check image names iso sizes. my $header= $cfg[$params{diagimagename}?1:0][$params{gsmimagename}?1:0][$params{ceimagename}?1:0][$params{blimagename}?1:0]; if (!$header) { die "invalid combinatian of images\n"; } my $base= 0; if ($params{addkey}) { $base= 5*0x200; $fh->seek(0*512, SEEK_SET); $fh->write(pack("a16", "HTC FLASH KEY\0")); $fh->seek(1*512, SEEK_SET); $fh->write(badmd5(unpack("H*", $params{cardid}))); $fh->seek(2*512, SEEK_SET); $fh->write(pack("V", $params{counter})); $fh->seek(3*512, SEEK_SET); $fh->write(badmd5(sprintf("%08lx", $params{counter}))); $fh->seek(4*512, SEEK_SET); $fh->write("N"); } # write simple header. $fh->seek($base+0*512, SEEK_SET); $fh->write(pack("a16", $header->{magic})); $fh->seek($base+2*512, SEEK_SET); my @checksums; if ($params{blimagename}) { my $bootloader= ReadImage($params{blimagename}); resize($bootloader, $header->{blsize}); $fh->write($bootloader); push @checksums, unpack("%32V*", $bootloader); } if ($params{ceimagename}) { my $ce= ReadImage($params{ceimagename}); resize($ce, $header->{cesize}); $fh->write($ce); if ($params{bl517}) { push @checksums, unpack("%32V*", substr($ce, 0, 0xe00)); # 80040e00-80041000 is not added in the checksum for 5.17 bootloaders. push @checksums, unpack("%32V*", substr($ce, 0x1000)); } else { push @checksums, unpack("%32V*", $ce); } } if ($params{diagimagename}) { my $diag= ReadImage($params{diagimagename}); resize($diag, $header->{diagsize}); $fh->write($diag); } my $checksum= unpack("%32V*", pack("V*", @checksums)); $fh->seek($base+1*512, SEEK_SET); $fh->write(pack("V", $checksum)); $fh->seek(0, SEEK_END); $fh->close(); } sub ActionReadImagesFromSD { my (%params)= @_; my $fh= IO::File->new($params{sdimgname}, "r") or die "$params{sdimgname}: $!\n"; binmode $fh; # read 7 headerblocks, followed by bootloader, followed by ce-rom my $header; $fh->seek(0*512, SEEK_SET); $fh->read($header, 7*512); my %info; if (substr($header, 0, 16) eq pack("a16", "HTC FLASH KEY")) { $info{haskey}= 1; $info{headersize}= 7*512; $header= substr($header, 5*512); $fh->seek(1*512, SEEK_SET); $fh->read($info{cidmd5}, 16); my $cntdata; $fh->seek(2*512, SEEK_SET); $fh->read($cntdata, 4); $info{counter}= unpack("V", $cntdata); $fh->seek(3*512, SEEK_SET); $fh->read($info{countermd5}, 16); # block 4 contains 'N' } else { $info{headersize}= 2*512; } # todo: this is cfg info, move to separate function if (substr($header, 0, 16) eq pack("a16", 'HTC$WALLABY00')) { $info{bootloadersize}= 0x40000; } elsif (substr($header, 0, 16) eq pack("a16", 'HTC$WALLABY11')) { $info{cesize}= 0x01fc0000; } elsif (substr($header, 0, 16) eq pack("a16", 'HTC$WALLABY22')) { $info{bootloadersize}= 0x40000; $info{cesize}= 0x01fc0000; } elsif (substr($header, 0, 16) eq pack("a16", 'HTC$WALLABY33')) { $info{diagnosticssize}= 6144; # ??? just guessing. $info{headersize} -= 512; } elsif (substr($header, 0, 16) eq pack("a16", 'HTC$WALLABY44')) { $info{hasgsmrom}= 1; } elsif (substr($header, 0, 16) eq pack("a16", 'HTC$WALLABY55')) { $info{hasgsmrom}= 1; $info{cesize}= 0x01fc0000; } $fh->close(); return \%info; } sub ReadImage { my $fn= shift; my $fh= IO::File->new($fn, "r") or die "$fn: $!\n"; binmode $fh; my $data; $fh->read($data, -s $fh); $fh->close(); return $data; } =pod card with keysignature have the following structure: block0: "HTC FLASH KEY\0" block1: starts with 16 byte buggy_md5sum of hex representation of first 16 bytes of cardid block2: start with 4 byte value block3: starts with buggy_md5sum of hex representation of first 4 bytes of block2 block4: "N" block5: "HTC$WALLABYnn" block6: checksum block7: start of data or ( != 5.17) block0: "HTC$WALLABYnn" block1: checksum block2: start of data =cut