RK3288 Android 系统 boot.img 镜像解压方法
android 6.0 boot.img 解包
file
file指令可以显示文件类型,但是对于特定封装的文件无能为力,比如Android系统编译出的boot.img
$ file boot.img
boot.img: data
binwalk
binwalk
是一款非常强大的用于解析 bin
文件格式工具,可以通过扫描 bin
文件分析出文件的封装格式,列出 bin
文件中包含的不同类型的文件以及文件在bin中的偏移量。
- 安装 binwalk
# 128M disk space will be used
sudo apt install binwalk
binwalk
可以用来分析 Android6
的 boot.img
.
$ binwalk boot.img
DECIMAL HEXADECIMAL DESCRIPTION
--------------------------------------------------------------------------------
8 0x8 gzip compressed data, from Unix, NULL date (1970-01-01 00:00:00)
从以上输出可知,boot.img实际上只有一个gzip压缩文件,但是有 8 个字节的偏移量。
通过 hexdump
指令可知这8个字节其实就是 KRNLT
字符串,对应Kernel.
$ hexdump -C boot.img|head -1
00000000 4b 52 4e 4c 54 9f 0f 00 1f 8b 08 00 00 00 00 00 |KRNLT...........|
dd
使用 binwalk
得知了 boot.img 格式,接下来就可以用 dd 去截取里面的 gzip 文件,当然要注意偏移量 8
个字节。
$ dd if=boot.img of=ramdisk.gz bs=1 skip=8
1023832+0 records in
1023832+0 records out
1023832 bytes (1.0 MB, 1000 KiB) copied, 0.798888 s, 1.3 MB/s
说明: 除了dd 外,也可以是用
binwalk -e boot.img
提取文件,解压后的文件以偏移量命名。
gunzip
此时得到的 ramdisk.gz
就是一个 gzip
压缩文件。
$ file ramdisk.gz
ramdisk.gz: gzip compressed data, from Unix
接下来使用 gunzip 进行解压。
$ gunzip ramdisk.gz
gzip: ramdisk.gz: decompression OK, trailing garbage ignored
$ ls
boot.img ramdisk
cpio
解压后的 ramdisk 是一个 cpio 压缩文件。
$ file ramdisk
ramdisk: ASCII cpio archive (SVR4 with no CRC)
所以需要进一步解压。
$ mkdir tmp && cd tmp
$ cpio -i < ../ramdisk
3586 blocks
至此 boot.img 中的ramdisk就完全解压出来了。
$ ls
charger init.rk30board.bootmode.emmc.rc property_contexts
data init.rk30board.bootmode.unknown.rc res
default.prop init.rk30board.environment.rc rk30xxnand_ko.ko
dev init.rk30board.rc sbin
drmboot.ko init.rk30board.usb.rc seapp_contexts
file_contexts init.rockchip.rc selinux_version
fstab.rk30board.bootmode.emmc init.trace.rc sepolicy
fstab.rk30board.bootmode.unknown init.usb.configfs.rc service_contexts
init init.usb.rc sys
init.connectivity.rc init.zygote32.rc system
init.environ.rc oem ueventd.rc
init.rc proc ueventd.rk30board.rc
android 10.0 boot.img 解包
Android 10 的 boot.img 与Android6不太一样。
$ file boot.img
boot.img: Android bootimg, kernel (0x10008000), ramdisk (0x11000000), second stage (0x10f00000), page size: 2048, cmdline (console=ttyFIQ0 androidboot.baseband=N/A androidboot.selinux=pe)
这里显示是 Android bootimg
,包含内核、ramdisk, second stage, cmdline.
使用 binwalk
解析。
$ binwalk boot.img
DECIMAL HEXADECIMAL DESCRIPTION
--------------------------------------------------------------------------------
0 0x0 Android bootimg, kernel size: 9021432 bytes, kernel addr: 0x10008000, ramdisk size: 17130613 bytes, ramdisk addr: 0x11000000, product name: ""
2084 0x824 Linux kernel ARM boot executable zImage (little-endian), load address: "0x00000000", end address: "0x0089A7F8"
110790 0x1B0C6 SHA256 hash constants, little endian
2842390 0x2B5F16 Certificate in DER format (x509 v3), header length: 4, sequence length: 5388
3314737 0x329431 Certificate in DER format (x509 v3), header length: 4, sequence length: 3
3682009 0x382ED9 Certificate in DER format (x509 v3), header length: 4, sequence length: 4355
4739912 0x485348 Cisco IOS microcode, for "Z"
7044069 0x6B7BE5 Certificate in DER format (x509 v3), header length: 4, sequence length: 676
7180231 0x6D8FC7 Certificate in DER format (x509 v3), header length: 4, sequence length: 108
7180235 0x6D8FCB Certificate in DER format (x509 v3), header length: 4, sequence length: 132
7826614 0x776CB6 Cisco IOS microcode, for "8_MAXj"
7881005 0x78412D Unix path: /505V/F505/F707/F717/P8'
9023488 0x89B000 gzip compressed data, from Unix, NULL date (1970-01-01 00:00:00)
26220684 0x190188C Unix path: /thermal-zones/soc-thermal/trips/trip-point@0
26240000 0x1906400 PC bitmap, Windows 3.x format,, 550 x 550 x 8
可以看到很多段数据,内核、证书、hash、gzip文件、位图等。
unmkbootimg
由于是Android bootimg
文件,可以使用 unmkbootimg
工具解压该文件。
$ unmkbootimg -i boot.img
kernel written to 'kernel' (9021432 bytes)
ramdisk written to 'ramdisk.cpio.gz' (17130613 bytes)
second bootloader written to 'second_bootloader' (1298944 bytes)
SHA1 HASH MISMATCH!
Expected : b73cd581ccb1ef4f50bad1fba9372d529391a894
Got : 67e49399c284be902dc217d564b039d222aabc8b
To rebuild this boot image, you can use the command:
mkbootimg --base 0x10000000 --pagesize 2048 --cmdline 'console=ttyFIQ0 androidboot.baseband=N/A androidboot.selinux=permissive androidboot.wificountrycode=US androidboot.veritymode=enforcing androidboot.hardware=rk30board androidboot.console=ttyFIQ0 firmware_class.path=/vendor/etc/firmware init=/init' --kernel kernel --ramdisk ramdisk.cpio.gz --second second_bootloader -o boot.img
此时再看文件列表,解压出来3个文件。
$ ls
boot.img kernel ramdisk.cpio.gz second_bootloader
针对 ramdisk.cpio.gz
,从命名就知道这是通过cpio, gzip 双重压缩得到,所以只要逆向解压即可。
$ gunzip ramdisk.cpio.gz
$ mkdir tmp && cd tmp
$ cpio -i < ../ramdisk.cpio
69463 blocks
至此解压完毕。
$ ls
acct etc plat_file_contexts sepolicy
apex first_stage_ramdisk plat_property_contexts storage
bin init postinstall sys
bugreports init.rc proc system
cache init.recovery.rk30board.rc product tmp
charger metadata product_file_contexts ueventd.rc
config mnt product_property_contexts vendor
d odm product_services vendor_file_contexts
data odm_file_contexts prop.default vendor_property_contexts
debug_ramdisk odm_property_contexts res
default.prop oem sbin
dev pcba sdcard
Android10 recovery.img 解包
安装 abootimg
apt install abootimg
解包 recovery.img
$ abootimg -x recovery.img
writing boot image config in bootimg.cfg
extracting kernel in zImage
extracting ramdisk in initrd.img
extracting second stage image in stage2.img
$ ls
bootimg.cfg initrd.img recovery.img stage2.img zImage
$ file *
bootimg.cfg: ASCII text, with very long lines
initrd.img: gzip compressed data, from Unix
recovery.img: Android bootimg, kernel (0x10008000), ramdisk (0x11000000), second stage (0x10f00000), page size: 2048, cmdline (console=ttyFIQ0 androidboot.baseband=N/A androidboot.selinux=pe)
stage2.img: data
zImage: data
解包 initrd.img
$ abootimg-unpack-initrd initrd.img
39014 blocks
$ ls -F
bootimg.cfg initrd.img ramdisk/ recovery.img stage2.img zImage
多出来的 ramdisk/
目录就是解包后的initrd.img
.
也可以将initrd.img 重命名为initrd.gz, 然后通过gunzip和cpio进行解压。
boot.img 打包
android 6.0
SDK/mkimage.sh
if [ $IMG_TARGET == 'boot' ] || [ $IMG_TARGET == 'all' ];then
if [ $TARGET == $BOOT_OTA ]
then
echo "make ota images... "
echo -n "create boot.img with kernel... "
[ -d $OUT/root ] && \
mkbootfs $OUT/root | minigzip > $OUT/ramdisk.img && \
truncate -s "%4" $OUT/ramdisk.img && \
mkbootimg --kernel $OUT/kernel --ramdisk $OUT/ramdisk.img --second kernel/resource.img --output $OUT/boot.img && \
cp -a $OUT/boot.img $IMAGE_PATH/
echo "done."
else
echo -n "create boot.img without kernel... "
[ -d $OUT/root ] && \
mkbootfs $OUT/root | minigzip > $OUT/ramdisk.img && \
truncate -s "%4" $OUT/ramdisk.img && \
rkst/mkkrnlimg $OUT/ramdisk.img $IMAGE_PATH/boot.img >/dev/null
echo "done."
fi
fi #### boot
不考虑 OTA 情况下,Android6只会打包 ramdisk.img, 该镜像源文件位于 $OUT/root
目录。使用 mkbootfs 和 minigzip 生成 ramdisk.img, 然后通过 truncate 调整尺寸. 最后通过 RK 自带的工具 rkst/mkkrnlimg
添加特定的头部信息,也就是前面提到的 KRNL
.
rkst/mkkrnlimg
会给输入文件添加两部分数据:
- 头部添加 KRNL.... 前缀 (8个字节)
- 尾部添加 CRC校验 (4个字节)
android 10.0
SDK/mkimage.sh
echo "create boot.img.... "
if [ "$BOARD_AVB_ENABLE" = "true" ]; then
cp -a $OUT/boot.img $IMAGE_PATH/boot.img
cp -a $OUT/boot-debug.img $IMAGE_PATH/boot-debug.img
else
echo "BOARD_AVB_ENABLE is false, make boot.img from kernel."
mkbootimg --kernel $KERNEL_DEBUG --ramdisk $OUT/ramdisk.img --second kernel/resource.img --os_version $PLATFORM_VERSION --header_version $BOARD_BOOTIMG_HEADER_VERSION --os_patch_level $PLATFORM_SECURITY_PATCH --cmdline "$BOARD_KERNEL_CMDLINE" --output $OUT/boot.img && \
cp -a $OUT/boot.img $IMAGE_PATH/boot.img
fi
echo "done."
从以上脚本可知,Android10里的打包使用的是通用的 mkbootimg
工具,所以使用 file
指令可以看出是 Android bootimg
,所以解压也可以通过官方工具实现。
reference
版权声明:本博客所有文章除特殊声明外,均采用 CC BY-NC 4.0 许可协议。转载请注明出处 litreily的博客!