Skip to content

Instantly share code, notes, and snippets.

@raptium
Created September 19, 2012 10:56
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save raptium/3749027 to your computer and use it in GitHub Desktop.
Save raptium/3749027 to your computer and use it in GitHub Desktop.
UPDATE.APP unpacker for Huawei G330D
#!/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