Linux 下解包华为固件包UPDATE.APP

注:本文所有图片保存EverNote 印象笔记(www.yinxiang.com)当中, 如果有其帐号登录后即可查看全部图片。 如没有帐号可用e-mail >>点击注册免费印象笔记


Linux 下解包华为固件包UPDATE.APP

一.关于华为固件包

最近因为需要分析一个特殊的Apk,需要从华为固件升级包抽取出来。

下载后发现华为固件包有两种,一种标准的update.zip卡刷包,这个用标准recovery 升级。解压后从system/app 直接拷贝出相应的apk即可。
另外一种是华为自家包格式dlload格式,每个升级包含配置文件和单个数据文件UPDATE.APP

华为官方的固件全部用这个格式发布,但是这种格式没有公开,因为很简单,很早就被人破解了。

这里三篇是讲如何在Windows下使用perl脚本解出system.img进而抽出其中文件来,思路都是一样的.

《[GUIDE] How to extract Huawei firmware (update.app)》
http://forum.xda-developers.com/showthread.php?t=2315547
《华为mate官方固件update.app专用解包工具及教程 (转)》
http://cn.club.vmall.com/thread-78177-1-1.html
《华为官方固件解包教程...提前官方系统程序》
http://tieba.baidu.com/p/2734923332

二.解析脚本

这几个都是使用split_updata.pl这个perl脚本来解开包。实践发现update.app 实际上是多个img文件合并成的。一般有10个文件。

对比其中不同产品spl_update.pl中的system.img 在不同位置上,这也是造成同一个脚本解析华为不同产品的system.img不对的原因, 在第一篇教程中有一个识别分区image文件脚本
HuaweiFinder https://docs.google.com/file/d/0B5LJgOGBjYOBLWlKcC1sOHkzRzA/edit?usp=sharing ,但是我无法下载,实际操作发现,不用这么复杂,通常尺寸最大是userdata.img,华为改名为cust.img ,第二大就是system.img 这两个通常有50M上下,1-3M大小是boot.img 即内核格式。

这个可以用工具快速测试。

use strict;
use warnings;

# 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 called "UPDATA.APP". 
my $FILENAME = undef;
if ($#ARGV == -1) {
    $FILENAME = "UPDATE.APP";
}
else {
    $FILENAME = $ARGV[0];
}

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 $BASEPATH = "output/";
mkdir $BASEPATH;

# These filenames are guessed. Feel free to correct.
&dump_file($BASEPATH."1.img");
&dump_file($BASEPATH."2.img");
&dump_file($BASEPATH."3.img");
&dump_file($BASEPATH."4.img");
&dump_file($BASEPATH."5.img");
&dump_file($BASEPATH."6.img");
&dump_file($BASEPATH."7.img"); # 40byte header
&dump_file($BASEPATH."8.img"); 
&dump_file($BASEPATH."9.img");
&dump_file($BASEPATH."10.img");
&dump_file($BASEPATH."11.img");
&dump_file($BASEPATH."12.img"); # 40byte header
&dump_file($BASEPATH."13.img");
&dump_file($BASEPATH."14.img"); # 40byte header

close INFILE;


# Unpack a file block and output the payload to a file.
sub dump_file {
    my ($outfilename) = @_;
    my $buffer = undef;

# Verify the identifier matches.
read(INFILE, $buffer, UINT_SIZE);
unless ($buffer eq "\x55\xAA\x5A\xA5") {
    die "Unrecognised file format. Wrong identifier.\n";
}

# Extract the packet length.
read(INFILE, $buffer, UINT_SIZE);
my ($packetLength) = unpack("V", $buffer);

# Ignore the next 16 bytes.
read(INFILE, $buffer, 16);

# Extract the length of the data file.
read(INFILE, $buffer, UINT_SIZE);
my ($dataLength) = unpack("V", $buffer);

# Ignore the rest of the packet. We've already read the first 28 bytes.
read(INFILE, $buffer, $packetLength-28);

# Dump the payload.
read(INFILE, $buffer, $dataLength);
open(OUTFILE, ">$outfilename") or die "Unable to create $outfilename: $!\n";
binmode OUTFILE;
print OUTFILE $buffer;
close OUTFILE;

# 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);
    }

    print STDOUT "Extracted $outfilename\n";
}    

不过我发现有一个C程序编译后也能达到同样效果

http://www.cnblogs.com/GentlemanMod/p/3272580.html
这里我修改一下源码,把itoa 改成snprintf,以便在linux可以编译通过

#include<stdio.h>
#include<stdlib.h>
#include<string.h>

#define MAXLEN 10240

void usage();
int main(int argc,char *argv[])
{
    int count,packetLength,dataLength,olddataLength,datasum,line,remainder,*Length;
    char *FILENAME,*OUTNAME;
    char int2char[10];
    unsigned char buffer[MAXLEN];
    FILE *INFILE,*OUTFILE;

    //获取输入的参数
    if(argc == 1)
        FILENAME="UPDATE.APP";
    else
        FILENAME=argv[1];

    //用二进制打开输入文件
    if((INFILE = fopen(FILENAME, "rb")) == NULL) usage();

    //创建文件夹并进入目录
    mkdir("output");
    chdir("output");

    //跳过92空字节
    fseek(INFILE, 92, 0);

    for(count=1;INFILE != NULL;count++)
    {
        //判断是否为华为固件索引头
        fread(buffer, 4, 1, INFILE);
        if(buffer[0] != 0x55) break;
        if(buffer[1] != 0XAA) break;
        if(buffer[2] != 0x5A) break;
        if(buffer[3] != 0xA5) break;

        //获取头文件长度
        fread(buffer, 4, 1, INFILE);
        Length = (int *)buffer;
        packetLength=*Length;

        //跳过16字节
        fseek(INFILE, 16, 1);

        //获取内容长度
        fread(buffer, 4, 1, INFILE);
        Length = (int *) buffer;
        dataLength=*Length;

        //把整数和字符串连接并复制给文件名
        #itoa(count, int2char, 10);
      snprintf(int2char,sizeof(int2char),"%d",count);
        OUTNAME=strcat(int2char, ".img");

        //跳到头文件末尾
        fseek(INFILE, packetLength-28, 1);

        //创建文件
        if((OUTFILE = fopen(OUTNAME, "wb")) == NULL)
        {
            printf("Unrecognised file format. Wrong identifier.\n");
            return -1;
        } else printf("Extracted output/%s\n",OUTNAME);

        //把内容数据分成多个部分
        datasum=dataLength/MAXLEN;

        for(line=0;line <= datasum;line++)
        {
            //获取内容数据
            if(datasum == line)
                fread(buffer, dataLength % MAXLEN, 1, INFILE);
            else
            fread(buffer, MAXLEN, 1, INFILE);

            //输出文件
            if(datasum == line)
                fwrite(buffer, dataLength % MAXLEN, 1, OUTFILE);
            else
            fwrite(buffer, MAXLEN, 1, OUTFILE);
        }

        //关闭输出文件
        fclose(OUTFILE);

        //指针取整,4的倍数
        remainder = 4 - (ftell(INFILE) % 4);
        if (remainder < 4)
        {
            //进行填充剩余的字节
            fseek(INFILE, remainder, 1);
        }
    }
    //关闭输入文件
    fclose(INFILE);
    return 0;
}

void usage()
{
    //帮助函数
    printf("uasge: unpack_update.exe [UPDATE.APP|UPDATA.APP]\n");
    exit(0);
}

三.Linux下解包

前面教程都是因为windows下缺少必要工具perl解析器以及mount工具,才会如此大费周章,实际上Linux操作相当简单,只要传spl_update.pl 脚本即可。而且如果是一个专业的Android内核开发人员,用Linux比用windows机会更多吧。

  • 解包

    把spl_update.pl和UDPATE.APP放在一个目录下,执行
    perl spl_update.pl UPDATE.APP

  • 挂载操作system.img

    Linux下是可以用mount 直接把一个文件当成文件系统挂载的,假设3.img 是system.img格式,

直接用mount 命令
mount -t ext4 -o loop 3.img /mnt
以上命令把system.img 挂载到/mnt目录,打开这个目录/system的各种结构就是展示在你眼前!

Alt text

最后,如果你觉得印象笔记好用,请用这个链接注册一个吧,最好的跨平台笔记软件(Android/iOS/Mac/Windows/网页版),我也赚点印象分获得高级帐号,当我升级,你也同步升级 https://app.yinxiang.com/referral/Registration.action?uid=436771&sig=c8049c851d63432b15e096b5fb449dfb

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值