android4.3 解压、打包boot.img新脚本

引自:http://blog.csdn.net/visionliao/article/details/25413411


解压boot.img需要用到三个文件:mkbootfs、mkbootimg、split_bootimg.pl。前两个是编译完系统后生成的可执行程序,存在于out/host/linux-x86/bin下面。split_bootimg.pl是一个Perl写的脚本。


    现在编译一个android4.3的系统,因为要改boot.img中的某个小东西又不想去重新编译boot,就想通过解压boot.img的方式来进行改动。在网上下载了一个split_bootimg.pl(分割boot的工具)文件,然后把系统中编译出来的mkbootfs(解压ramdisk的工具)和mkbootimg(重新打包签名boot.img的工具)拿出来,准备解压。

    执行步骤:1. split_bootimg.pl boot.img  (解压boot.img,得到boot.img-kernel,boot.img-ramdisk.gz)

                      2. mkdir ramdisk  (解压boot.img.ramdisk.gz)
                  cd ramdisk
                  gzip -dc ../boot.img-ramdisk.gz | cpio -i
                  cd ..

                      一般我们需要改动的东西都在这个ramdisk当中,比如开机log(开机动画显示前显示的图片)、init.rc(系统启动是开启的服务项)、default.prop(系统配置文件)等等。

                      3. ./mkbootfs ./ramdisk | gzip > ramdisk-new.gz (使用mkbootfs工具将修改后的ramdisk重新打包)

                      4. ./mkbootimg --cmdline 'console=115200,n8 androidboot.console=ttyHSL0 androidboot.hardware=qcom user_debug=31 msm_rtb.filter=0x37' --base 0x00000000 --kernel boot.img-kernel --ramdisk ramdisk-new.gz -o bootnew.img

                      第四步是使用mkbootimg工具对整个boot.img重新打包,其中的--cmdline后面的引用号里的值是执行第一步就会打印出来的信息。 --base 0x0000000基址,用于告诉手机从哪个地址开始,是准备给内存盘的入口,哪个地址是给kernel的入口。在boardconfig.h中存在地址偏移的define,一般是这个值,或者是0x00200000、0x20000000。


      问题来了,整个过程执行下来也没有报任何错误,但是升级到机器里系统就启动不起来了。原因是在android4.x的boot里面加入了一个叫dt.img(device tree)的东西,少了这个东西boot是启动不起来的。原因也可以在split_bootimg.pl中看到,下面是split_bootimg.pl的代码:

#!/usr/bin/perl
######################################################################
#
#   File          : split_bootimg.pl
#   Author(s)     : William Enck <enck@cse.psu.edu>
#   Description   : Split appart an Android boot image created 
#                   with mkbootimg. The format can be found in
#                   android-src/system/core/mkbootimg/bootimg.h
#
#                   Thanks to alansj on xda-developers.com for 
#                   identifying the format in bootimg.h and 
#                   describing initial instructions for splitting
#                   the boot.img file.
#
#   Last Modified : Tue Dec  2 23:36:25 EST 2008
#   By            : William Enck <enck@cse.psu.edu>
#
#   Copyright (c) 2008 William Enck
#
######################################################################

use strict;
use warnings;

# Turn on print flushing
$|++;

######################################################################
## Global Variables and Constants

my $SCRIPT = __FILE__;
my $IMAGE_FN = undef;

# Constants (from bootimg.h)
use constant BOOT_MAGIC => 'ANDROID!';
use constant BOOT_MAGIC_SIZE => 8;
use constant BOOT_NAME_SIZE => 16;
use constant BOOT_ARGS_SIZE => 512;

# Unsigned integers are 4 bytes
use constant UNSIGNED_SIZE => 4;

# Parsed Values
my $PAGE_SIZE = undef;          #page 大小
my $KERNEL_SIZE = undef;      #kernel 大小
my $RAMDISK_SIZE = undef;    #ramdisk 大小
my $SECOND_SIZE = undef;     #second 大小

######################################################################
## Main Code

&parse_cmdline();
&parse_header($IMAGE_FN);

=format (from bootimg.h)
** +-----------------+
** | boot header     | 1 page
** +-----------------+
** | kernel          | n pages
** +-----------------+
** | ramdisk         | m pages
** +-----------------+
** | second stage    | o pages
** +-----------------+
**
** n = (kernel_size + page_size - 1) / page_size
** m = (ramdisk_size + page_size - 1) / page_size
** o = (second_size + page_size - 1) / page_size
=cut

my $n = int(($KERNEL_SIZE + $PAGE_SIZE - 1) / $PAGE_SIZE);
my $m = int(($RAMDISK_SIZE + $PAGE_SIZE - 1) / $PAGE_SIZE);
my $o = int(($SECOND_SIZE + $PAGE_SIZE - 1) / $PAGE_SIZE);

my $k_offset = $PAGE_SIZE;                                    # kernel的偏移量
my $r_offset = $k_offset + ($n * $PAGE_SIZE);        # ramdisk的偏移量
my $s_offset = $r_offset + ($m * $PAGE_SIZE);       # second的偏移量


(my $base = $IMAGE_FN) =~ s/.*\/(.*)$/$1/;
my $k_file = $base . "-kernel";                        #解压出kernel后添加的名称后缀
my $r_file = $base . "-ramdisk.gz";                  # 解压出ramdisk.gz后添加的名称后缀
my $s_file = $base . "-second.gz";                  #解压出second.gz后添加的名称后缀

#调用dump_file方法根据kernel的偏移量截取出kernel
# The kernel is always there
print "Writing $k_file ...";
&dump_file($IMAGE_FN, $k_file, $k_offset, $KERNEL_SIZE);
print " complete.\n";

#调用dump_file方法根据ramdisk的偏移量截取出ramdisk
# The ramdisk is always there
print "Writing $r_file ...";
&dump_file($IMAGE_FN, $r_file, $r_offset, $RAMDISK_SIZE);
print " complete.\n";

#调用dump_file方法根据second的偏移量截取出second
# The Second stage bootloader is optional
unless ($SECOND_SIZE == 0) {
    print "Writing $s_file ...";
    &dump_file($IMAGE_FN, $s_file, $s_offset, $SECOND_SIZE);
    print " complete.\n";
}
######################################################################
## Supporting Subroutines

=header_format (from bootimg.h)
struct boot_img_hdr
{
    unsigned char magic[BOOT_MAGIC_SIZE];
    unsigned kernel_size;  /* size in bytes */
    unsigned kernel_addr;  /* physical load addr */

    unsigned ramdisk_size; /* size in bytes */
    unsigned ramdisk_addr; /* physical load addr */

    unsigned second_size;  /* size in bytes */
    unsigned second_addr;  /* physical load addr */

    unsigned tags_addr;    /* physical addr for kernel tags */
    unsigned page_size;    /* flash page size we assume */
    unsigned unused[2];    /* future expansion: should be 0 */

    unsigned char name[BOOT_NAME_SIZE]; /* asciiz product name */

    unsigned char cmdline[BOOT_ARGS_SIZE];

    unsigned id[8]; /* timestamp / checksum / sha1 / etc */
};
=cut
sub parse_header {
    my ($fn) = @_;
    my $buf = undef;

    open INF, $fn or die "Could not open $fn: $!\n";
    binmode INF;

    # Read the Magic
    read(INF, $buf, BOOT_MAGIC_SIZE);
    unless ($buf eq BOOT_MAGIC) {
die "Android Magic not found in $fn. Giving up.\n";
    }

    # Read kernel size and address (assume little-endian)
    read(INF, $buf, UNSIGNED_SIZE * 2);
    my ($k_size, $k_addr) = unpack("VV", $buf);

    # Read ramdisk size and address (assume little-endian)
    read(INF, $buf, UNSIGNED_SIZE * 2);
    my ($r_size, $r_addr) = unpack("VV", $buf);

    # Read second size and address (assume little-endian)
    read(INF, $buf, UNSIGNED_SIZE * 2);
    my ($s_size, $s_addr) = unpack("VV", $buf);

    # Ignore tags_addr
    read(INF, $buf, UNSIGNED_SIZE);

    # get the page size (assume little-endian)
    read(INF, $buf, UNSIGNED_SIZE);
    my ($p_size) = unpack("V", $buf);

    # Ignore unused
    read(INF, $buf, UNSIGNED_SIZE * 2);

    # Read the name (board name)
    read(INF, $buf, BOOT_NAME_SIZE);
    my $name = $buf;

    # Read the command line
    read(INF, $buf, BOOT_ARGS_SIZE);
    my $cmdline = $buf;

    # Ignore the id
    read(INF, $buf, UNSIGNED_SIZE * 8);

    # Close the file
    close INF;

    #打印一些基本信息,包括Command line,就是打包boot.img的时候需要的参数
    # Print important values
    printf "Page size: %d (0x%08x)\n", $p_size, $p_size;
    printf "Kernel size: %d (0x%08x)\n", $k_size, $k_size;
    printf "Ramdisk size: %d (0x%08x)\n", $r_size, $r_size;
    printf "Second size: %d (0x%08x)\n", $s_size, $s_size;
    printf "Board name: $name\n";
    printf "Command line: $cmdline\n";

    # Save the values
    $PAGE_SIZE = $p_size;
    $KERNEL_SIZE = $k_size;
    $RAMDISK_SIZE = $r_size;
    $SECOND_SIZE = $s_size;
}
sub dump_file {
    my ($infn, $outfn, $offset, $size) = @_;
    my $buf = undef;

    open INF, $infn or die "Could not open $infn: $!\n";
    open OUTF, ">$outfn" or die "Could not open $outfn: $!\n";

    binmode INF;
    binmode OUTF;

    seek(INF, $offset, 0) or die "Could not seek in $infn: $!\n";
    read(INF, $buf, $size) or die "Could not read $infn: $!\n";
    print OUTF $buf or die "Could not write $outfn: $!\n";

    close INF;
    close OUTF;
}


######################################################################
## Configuration Subroutines

sub parse_cmdline {
    unless ($#ARGV == 0) {
die "Usage: $SCRIPT boot.img\n";
    }
    $IMAGE_FN = $ARGV[0];
}


     以上文件做了点简单的注释,很明显,里面的代码只实现了解压kernel、ramdisk、second这几个文件出来,没有解压出dt.img,所以这个文件过时了,在新系统上不能适应。


    通过研究测试,终于把这个文件改好了,我就直接上改好的文件吧,懒得写注释了,文笔又不好,写的乱七八糟。


#!/usr/bin/perl
######################################################################
#
#   File          : split_bootimg.pl
#   Author(s)     : William Enck <enck@cse.psu.edu>
#   Description   : Split appart an Android boot image created 
#                   with mkbootimg. The format can be found in
#                   android-src/system/core/mkbootimg/bootimg.h
#
#                   Thanks to alansj on xda-developers.com for 
#                   identifying the format in bootimg.h and 
#                   describing initial instructions for splitting
#                   the boot.img file.
#
#   Last Modified : Tue Dec  2 23:36:25 EST 2008
#   By            : William Enck <enck@cse.psu.edu>
#
#   Copyright (c) 2008 William Enck
#
######################################################################

use strict;
use warnings;

# Turn on print flushing
$|++;

######################################################################
## Global Variables and Constants

my $SCRIPT = __FILE__;
my $IMAGE_FN = undef;

# Constants (from bootimg.h)
use constant BOOT_MAGIC => 'ANDROID!';
use constant BOOT_MAGIC_SIZE => 8;
use constant BOOT_NAME_SIZE => 16;
use constant BOOT_ARGS_SIZE => 512;

# Unsigned integers are 4 bytes
use constant UNSIGNED_SIZE => 4;

# Parsed Values
my $PAGE_SIZE = undef;
my $KERNEL_SIZE = undef;
my $RAMDISK_SIZE = undef;
my $SECOND_SIZE = undef;
my $DT_SIZE = undef;

######################################################################
## Main Code

&parse_cmdline();
&parse_header($IMAGE_FN);

=format (from bootimg.h)
** +-----------------+ 
** | boot header     | 1 page
** +-----------------+
** | kernel          | n pages  
** +-----------------+
** | ramdisk         | m pages  
** +-----------------+
** | second stage    | o pages
** +-----------------+
** | device tree     | p pages
** +-----------------+
**
** n = (kernel_size + page_size - 1) / page_size
** m = (ramdisk_size + page_size - 1) / page_size
** o = (second_size + page_size - 1) / page_size
** p = (dt_size + page_size - 1) / page_size
=cut

my $n = int(($KERNEL_SIZE + $PAGE_SIZE - 1) / $PAGE_SIZE);
my $m = int(($RAMDISK_SIZE + $PAGE_SIZE - 1) / $PAGE_SIZE);
my $o = int(($SECOND_SIZE + $PAGE_SIZE - 1) / $PAGE_SIZE);
my $p = int(($DT_SIZE + $PAGE_SIZE - 1) / $PAGE_SIZE);

my $k_offset = $PAGE_SIZE;
my $r_offset = $k_offset + ($n * $PAGE_SIZE);
my $s_offset = $r_offset + ($m * $PAGE_SIZE);
my $d_offset = $s_offset + ($o * $PAGE_SIZE);

(my $base = $IMAGE_FN) =~ s/.*\/(.*)$/$1/;
my $k_file = $base . "-kernel";
my $r_file = $base . "-ramdisk.gz";
my $s_file = $base . "-second.gz";
my $d_file = $base . "-dt.img";

# The kernel is always there
print "Writing $k_file ...";
&dump_file($IMAGE_FN, $k_file, $k_offset, $KERNEL_SIZE);
print " complete.\n";

# The ramdisk is always there
print "Writing $r_file ...";
&dump_file($IMAGE_FN, $r_file, $r_offset, $RAMDISK_SIZE);
print " complete.\n";

# The Second stage bootloader is optional
unless ($SECOND_SIZE == 0) {
    print "Writing $s_file ...";
    &dump_file($IMAGE_FN, $s_file, $s_offset, $SECOND_SIZE);
    print " complete.\n";
}

# The dt is always there
print "Writing $d_file ...";
&dump_file($IMAGE_FN, $d_file, $d_offset, $DT_SIZE);
print " complete.\n";
    
######################################################################
## Supporting Subroutines

=header_format (from bootimg.h)
struct boot_img_hdr
{
    unsigned char magic[BOOT_MAGIC_SIZE];

    unsigned kernel_size;  /* size in bytes */
    unsigned kernel_addr;  /* physical load addr */

    unsigned ramdisk_size; /* size in bytes */
    unsigned ramdisk_addr; /* physical load addr */

    unsigned second_size;  /* size in bytes */
    unsigned second_addr;  /* physical load addr */

    unsigned tags_addr;    /* physical addr for kernel tags */
    unsigned page_size;    /* flash page size we assume */
    unsigned dt size;    /* flash device tree size we assume */
    unsigned unused;    /* future expansion: should be 0 */

    unsigned char name[BOOT_NAME_SIZE]; /* asciiz product name *

    unsigned char cmdline[BOOT_ARGS_SIZE];

    unsigned id[8]; /* timestamp / checksum / sha1 / etc */
};
=cut
sub parse_header {
    my ($fn) = @_;
    my $buf = undef;

    open INF, $fn or die "Could not open $fn: $!\n";
    binmode INF;

    # Read the Magic
    read(INF, $buf, BOOT_MAGIC_SIZE);
    unless ($buf eq BOOT_MAGIC) {
die "Android Magic not found in $fn. Giving up.\n";
    }

    # Read kernel size and address (assume little-endian)
    read(INF, $buf, UNSIGNED_SIZE * 2);
    my ($k_size, $k_addr) = unpack("VV", $buf);

    # Read ramdisk size and address (assume little-endian)
    read(INF, $buf, UNSIGNED_SIZE * 2);
    my ($r_size, $r_addr) = unpack("VV", $buf);

    # Read second size and address (assume little-endian)
    read(INF, $buf, UNSIGNED_SIZE * 2);
    my ($s_size, $s_addr) = unpack("VV", $buf);
    
    # Ignore tags_addr
    read(INF, $buf, UNSIGNED_SIZE);

    # get the page size (assume little-endian)
    read(INF, $buf, UNSIGNED_SIZE);
    my ($p_size) = unpack("V", $buf);

    # Read device tree size (assume little-endian)
    read(INF, $buf, UNSIGNED_SIZE);
    my ($d_size) = unpack("V", $buf);
    
    # Ignore unused
    read(INF, $buf, UNSIGNED_SIZE);

    # Read the name (board name)
    read(INF, $buf, BOOT_NAME_SIZE);
    my $name = $buf;

    # Read the command line
    read(INF, $buf, BOOT_ARGS_SIZE);
    my $cmdline = $buf;

    # Ignore the id
    read(INF, $buf, UNSIGNED_SIZE * 8);

    # Close the file
    close INF;

    # Print important values
    printf "Page size: %d (0x%08x)\n", $p_size, $p_size;
    printf "Kernel size: %d (0x%08x)\n", $k_size, $k_size;
    printf "Ramdisk size: %d (0x%08x)\n", $r_size, $r_size;
    printf "Second size: %d (0x%08x)\n", $s_size, $s_size;
    printf "DT size: %d (0x%08x)\n", $d_size, $d_size;
    printf "Board name: $name\n";
    printf "Command line: $cmdline\n";
open(FD,">/tmp/command");
my $position = index($cmdline,"\0");
printf "==================== $position \n";
my $subs = substr($cmdline, 0, $position);
printf "==================== $subs \n";
$subs = $subs."\n";
print FD "$subs";
close FD;
    # Save the values
    $PAGE_SIZE = $p_size;
    $KERNEL_SIZE = $k_size;
    $RAMDISK_SIZE = $r_size;
    $SECOND_SIZE = $s_size;
    $DT_SIZE = $d_size;
}

sub dump_file {
    my ($infn, $outfn, $offset, $size) = @_;
    my $buf = undef;

    open INF, $infn or die "Could not open $infn: $!\n";
    open OUTF, ">$outfn" or die "Could not open $outfn: $!\n";

    binmode INF;
    binmode OUTF;

    seek(INF, $offset, 0) or die "Could not seek in $infn: $!\n";
    read(INF, $buf, $size) or die "Could not read $infn: $!\n";
    print OUTF $buf or die "Could not write $outfn: $!\n";

    close INF;
    close OUTF;
}

######################################################################
## Configuration Subroutines

sub parse_cmdline {
    unless ($#ARGV == 0) {
die "Usage: $SCRIPT boot.img\n";
    }
    $IMAGE_FN = $ARGV[0];
}


split_bootimg.pl:


<script src="https://code.csdn.net/snippets/483209.js"></script>

git@code.csdn.net:snippets/483209.git


    对比一下就会发现,下面的文件中加上了dt.img的相关信息,解压打包后的boot.img升级OK,验证通过。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Android系统的boot.img文件是Android固件中的一个重要部分,它包含了Android系统的内核和一些初始化脚本等文件。解包打包boot.img文件是进行Android固件定制或修改的重要步骤之一。 在解包打包boot.img文件时,可以使用一些工具集来辅助完成。以下是一些常用的工具集: 1. Android Kitchen:这是一个基于Linux系统的命令行工具集,可以用来解包打包boot.img文件。它提供了一系列的命令,如unpackbootimg用于解包boot.img,mkbootimg用于打包boot.img。使用Android Kitchen工具集需要一些基本的Linux命令行操作知识。 2. Magisk Manager:这是一个通用的Android系统修改工具,其中包含了解包打包boot.img文件的功能。Magisk Manager可以通过安装Magisk框架来实现对Android系统的修改,并且提供了可视化的操作界面,方便用户进行boot.img解包打包操作。 3. Android Image Kitchen:这是另一个基于Linux系统的命令行工具集,用于解包打包Android系统的映像文件,包括boot.img文件。Android Image Kitchen提供了一系列的命令,如unpackimg用于解包boot.img,repackimg用于打包boot.img。 除了上述工具集外,还有一些第三方的GUI工具可供使用,如Magisk Manager中提供的可视化操作界面,以及一些名为"bootimage-tools"的工具集。 总之,解包打包boot.img文件是进行Android固件定制或修改的重要环节之一,可以通过一些命令行工具集,如Android Kitchen、Android Image Kitchen等,或者一些GUI工具,如Magisk Manager等,来实现这一操作。这些工具集提供了相应的命令或操作界面,方便用户进行boot.img解包打包操作。 ### 回答2: Android boot.img解包打包工具集是用于对Android系统中的boot.img文件进行解包打包操作的一组工具集。 解包工具集包括: 1. binwalk:可以用于识别和提取boot.img文件中的各种结构和组件。 2. Unpackbootimg:可以将boot.img文件解包为ramdisk.img、kernel和cmdline等组成部分。 3. mkbootimg:可以重打包解包后的ramdisk.img、kernel和cmdline等组成部分为boot.img文件。 4. Android Image Kitchen:可以提取和重打包boot.img文件中的各种文件、分区和可执行程序。 5. Bootimg-tools:提供了一系列工具来处理boot.img文件,包括解包、打印信息、拆分和合并等操作。 使用这些工具集,可以将boot.img文件解包为其包含的ramdisk、kernel和cmdline等文件,可以对这些文件进行修改和定制。然后可以使用mkbootimgAndroid Image Kitchen将修改后的文件重打包boot.img文件。这样,就可以实现对Android系统启动过程中的各种配置和组件进行修改和定制。 这些工具集对于Android系统开发和定制非常有用,可以帮助开发者理解和修改Android系统的启动过程,同时也可以帮助厂商和用户改变和优化系统的启动行为。然而,由于涉及到系统底层,使用这些工具集需要谨慎操作,避免对系统造成损害。 ### 回答3: Androidboot.img是一个包含了Linux内核和设备树的镜像文件,用于引导Android设备的启动过程。解包打包boot.img需要使用一些专门的工具集。 解包boot.img的工具集主要包括以下几个工具: 1. mkbootimg工具:用于解析和生成Android boot.img文件,可以从boot.img中提取出内核、ramdisk、cmdline等信息。 2. unmkbootimg工具:用于解包boot.img文件,将其中的内核、ramdisk、cmdline等内容提取出来。可以使用该工具将boot.img解包boot.img-zImage(内核文件)、boot.img-ramdisk.gz(ramdisk文件)等。 3. simg2img工具:用于将boot.img中的system.img(系统分区镜像)解包为ext4格式的文件系统,以便进行修改和查看。 4. mkdtimg工具:用于打包设备树文件,依赖于设备树编译工具,可以将设备树编译成设备树二进制文件(.dtb)后再使用mkdtimg打包dt.img 文件,然后将dt.img文件与之前解包得到的zImage、ramdisk等文件一起打包boot.img打包boot.img的工具集主要包括以下几个工具: 1. mkbootimg工具:用于生成boot.img文件,需要提供的zImage(内核文件)、ramdisk(ramdisk文件)、cmdline等参数。 2. mkdtimg工具:用于打包设备树文件,将设备树二进制文件(.dtb)打包dt.img文件,然后将dt.img文件与zImage、ramdisk等文件一起打包boot.img。 以上是Android boot.img解包打包工具集的一些介绍。需要注意的是,操作boot.img需要一定的技术知识和经验,不当的操作可能导致设备变砖或无法正常启动,因此使用前请谨慎,并在了解清楚操作步骤后进行操作。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值