Created
April 18, 2013 13:35
-
-
Save janimo/5412727 to your computer and use it in GitHub Desktop.
Script to unpack Huawei UPDATE.APP Android firmware blobs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/perl | |
###################################################################### | |
# | |
# File : split_updata.pl | |
# Author(s) : McSpoon | |
# Description : Unpack a Huawei U8220 'UPDATA.APP' file. | |
# http://pulse.modaco.com | |
# | |
# Last Modified : Thu 24 December 2009 | |
# By : McSpoon | |
# | |
# Last Modified : Wed 18 June 2010 | |
# By : ZeBadger (z e b a d g e r @ h o t m a i l . c o m) | |
# Comment : Added filename selection | |
# | |
# Last Modified : Wed 19 June 2010 | |
# By : ZeBadger (z e b a d g e r @ h o t m a i l . c o m) | |
# Comment : Added CRC checking | |
# | |
###################################################################### | |
use strict; | |
use warnings; | |
my $CRC_CHECK= -e "crc" && -x _; | |
my %fileHash=( "\x00\x00\x00\x00", "system.img", | |
"\x00\x00\x00\x10","appsboot.mbn", | |
"\x00\x00\x00\x20","file25.mbn", | |
"\x00\x00\x00\x30","testing.img", | |
"\x00\x00\x00\x40","recovery.img", | |
"\x00\x00\x00\x50","userdata.img", | |
"\x00\x00\x00\x70","unicom.img", | |
"\x00\x00\x00\xB0","FactoryImage.img", | |
"\x00\x00\x00\xC0","file11.mbn", | |
"\x00\x00\x00\xD0","amss.mbn", | |
"\x00\x00\x00\xE0","oemsbl.mbn", | |
"\x00\x00\x00\xE4","splash.raw565", | |
"\x00\x00\x00\xF0","file04.mbn", #oemsblhd.mbn? | |
"\x00\x00\x00\xF1","file07.mbn", | |
"\x00\x00\x00\xF3","file01.mbn", | |
"\x00\x00\x00\xF4","file02.mbn", | |
"\x00\x00\x00\xF5","file14.mbn", | |
"\x00\x00\x00\xF6","boot_versions.txt", | |
"\x00\x00\x00\xF7","upgradable_versions.txt", | |
"\x00\x00\x00\xF8","file09.mbn", | |
"\x00\x00\x00\xF9","version.txt", | |
"\x00\x00\x00\xFA","file20.mbn", | |
"\x00\x00\x00\xFB","appsboothd.mbn", | |
"\x00\x00\x00\xFC","boot.img", | |
"\x00\x00\x00\xFD","file16.mbn", | |
"\x00\x00\x00\xFE","file18.mbn", | |
"\x00\x00\x00\xFF","file21.mbn", | |
"\x00\x00\x10\xF6","file22.txt", | |
); | |
my $unknown_count=0; | |
# Turn on print flushing. | |
$|++; | |
# Unsigned integers are 4 bytes. | |
use constant UINT_SIZE => 4; | |
# If a filename wasn't specified on the commmand line then | |
# assume the file to be unpacked is under current directory. | |
my $FILENAME = undef; | |
if (@ARGV) { | |
$FILENAME = $ARGV[0]; | |
} | |
else { | |
my @files = `ls`; | |
$FILENAME = $ARGV[0]; | |
foreach (@files){ | |
if(/updata.app/i){ | |
$FILENAME=$_; | |
} | |
} | |
} | |
open(INFILE, $FILENAME) or die "Cannot open $FILENAME: $!\n"; | |
binmode INFILE; | |
# Skip the first 92 bytes, they're blank. | |
#seek(INFILE, 92, 0); | |
# We'll dump the files into a folder called "output". | |
my $fileLoc=0; | |
my $BASEPATH = "output/"; | |
mkdir $BASEPATH; | |
while (!eof(INFILE)) | |
{ | |
$fileLoc=&find_next_file($fileLoc); | |
#printf "fileLoc=%x\n",$fileLoc; | |
seek(INFILE, $fileLoc, 0); | |
$fileLoc=&dump_file(); | |
} | |
close INFILE; | |
# Find the next file block in the main file | |
sub find_next_file | |
{ | |
my ($_fileLoc) = @_; | |
my $_buffer = undef; | |
my $_skipped=0; | |
read(INFILE, $_buffer, UINT_SIZE); | |
while ($_buffer ne "\x55\xAA\x5A\xA5" && !eof(INFILE)) | |
{ | |
read(INFILE, $_buffer, UINT_SIZE); | |
$_skipped+=UINT_SIZE; | |
} | |
return($_fileLoc + $_skipped); | |
} | |
# Unpack a file block and output the payload to a file. | |
sub dump_file { | |
my $buffer = undef; | |
my $outfilename = undef; | |
my $fileSeq; | |
my $calculatedcrc = undef; | |
my $sourcecrc = undef; | |
my $fileChecksum; | |
# Verify the identifier matches. | |
read(INFILE, $buffer, UINT_SIZE); # Packet Identifier | |
unless ($buffer eq "\x55\xAA\x5A\xA5") { die "Unrecognised file format. Wrong identifier.\n"; } | |
read(INFILE, $buffer, UINT_SIZE); # Packet Length. | |
my ($headerLength) = unpack("V", $buffer); | |
read(INFILE, $buffer, 4); # Always 1 | |
read(INFILE, $buffer, 8); # Hardware ID | |
read(INFILE, $fileSeq, 4); # File Sequence | |
#my ($temp)=unpack("V",$fileSeq); | |
#print "fileSeq=$temp\n"; | |
if (exists($fileHash{$fileSeq})) { | |
$outfilename=$fileHash{$fileSeq}; | |
} else { | |
$outfilename="unknown_file.$unknown_count"; | |
printf "Unknown file %s found", slimhexdump($fileSeq); | |
$unknown_count++; | |
} | |
read(INFILE, $buffer, UINT_SIZE); # Data file length | |
my ($dataLength) = unpack("V", $buffer); | |
read(INFILE, $buffer, 16); # File date | |
read(INFILE, $buffer, 16); # File time | |
read(INFILE, $buffer, 16); # The word INPUT ? | |
read(INFILE, $buffer, 16); # Blank | |
read(INFILE, $buffer, 2); # Checksum of the header maybe? | |
read(INFILE, $buffer, 2); # Always 1? | |
read(INFILE, $buffer, 2); # Blank | |
# Grab the checksum of the file | |
read(INFILE, $fileChecksum, $headerLength-98); | |
$sourcecrc=slimhexdump($fileChecksum); | |
# Dump the payload. | |
read(INFILE, $buffer, $dataLength); | |
open(OUTFILE, ">$BASEPATH$outfilename") or die "Unable to create $outfilename: $!\n"; | |
binmode OUTFILE; | |
print OUTFILE $buffer; | |
close OUTFILE; | |
$calculatedcrc=`./crc $BASEPATH$outfilename` if $CRC_CHECK; | |
chomp($calculatedcrc) if $CRC_CHECK; | |
print STDOUT "Extracted $outfilename"; | |
print "\n" if !$CRC_CHECK; | |
if($CRC_CHECK){ | |
if ($calculatedcrc eq $sourcecrc) | |
{ | |
print " - CRC Okay\n"; | |
} | |
else | |
{ | |
print " - ERROR: CRC did not match\n"; | |
} | |
} | |
# Ensure we finish on a 4 byte boundary alignment. | |
my $remainder = UINT_SIZE - (tell(INFILE) % UINT_SIZE); | |
if ($remainder < UINT_SIZE) { | |
# We can ignore the remaining padding. | |
read(INFILE, $buffer, $remainder); | |
} | |
return (tell(INFILE)); | |
} | |
sub hexdump () | |
{ | |
my $num=0; | |
my $i; | |
my $rhs; | |
my $lhs; | |
my ($buf) = @_; | |
my $ret_str=""; | |
foreach $i ($buf =~ m/./gs) | |
{ | |
# This loop is to process each character at a time. | |
# | |
$lhs .= sprintf(" %02X",ord($i)); | |
if ($i =~ m/[ -~]/) | |
{ | |
$rhs .= $i; | |
} | |
else | |
{ | |
$rhs .= "."; | |
} | |
$num++; | |
if (($num % 16) == 0) | |
{ | |
$ret_str.=sprintf("%-50s %s\n",$lhs,$rhs); | |
$lhs=""; | |
$rhs=""; | |
} | |
} | |
if (($num % 16) != 0) | |
{ | |
$ret_str.=sprintf("%-50s %s\n",$lhs,$rhs); | |
} | |
return ($ret_str); | |
} | |
sub slimhexdump () | |
{ | |
my $i; | |
my ($buf) = @_; | |
my $ret_str=""; | |
foreach $i ($buf =~ m/./gs) | |
{ | |
# This loop is to process each character at a time. | |
# | |
$ret_str .= sprintf("%02X",ord($i)); | |
} | |
return ($ret_str); | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
What type script is it? Should it change extension for this file?Is It bat file?