【翻译】解析OpenWRT中uImage和sysupgrade 的区别

翻译自http://developers-club.com/posts/264843/,有删减

大家都知道,OpenWRT镜像的发布站点目录中存在两种类型的固件------uImage和sysupgrade,比如下面这两个:

openwrt-15.05-rc3-ramips-rt305x-dir-320-b1-initramfs-uImage.bin
openwrt-15.05-rc3-ramips-rt305x-dir-320-b1-squashfs-sysupgrade.bin

官方FAQ非常贪婪的(存疑)写了关于他们的区别:

不同格式的镜像有什么区别?
factory镜像是一个给bootloader升级用的
sysupgrade镜像(之前称之为trx镜像)是设计给openwrt自己升级用的。
两者拥有相同的内容,不过一个factory镜像拥有额外的头部信息或者该设备平台所需的任何东西。通常来说,factory镜像是需要刷机工具将它刷到设备上的。除此之外,使用升级镜像。

根据该文档,可以通过原厂固件web界面里的固件升级选项升级,不过得不是包含额外头部信息的factory镜像。

很好,我们来比较一下这两个固件的大小:

openwrt-15.05-rc3-ramips-rt305x-dir-320-b1-initramfs-uImage.bin — 3253035 字节.
openwrt-15.05-rc3-ramips-rt305x-dir-320-b1-squashfs-sysupgrade.bin — 3407876 字节.

sysupgrade差不多比uImage大了140KB,根据他们在文档中解释的关于大小的问题,uImage损失了它的“额外的信息”------似乎损失的有点多。

当然,可以从汇编脚本(存疑)来比较他们的不同点,但是,这是不切实际的。今天我们将会泛泛比较他们(类似黑盒测试?)仿佛我们没有源码一样,在文章的最后我们将会使用汇编脚本来证实我们的猜想。

我们分析固件的主要手段是通过linux下的一个分析工具binwalk。让我们先重命名固件的文件名,使我们更方便地去分析它,我们将开始研究他们。

> binwalk ./uImage.bin 
DECIMAL       HEXADECIMAL     DESCRIPTION
--------------------------------------------------------------------------------
0             0x0             uImage header, header size: 64 bytes, header CRC: 0x19DE1499, created: Fri Jul  3 22:16:00 2015, image size: 3252971 bytes, Data Address: 0x80000000, Entry Point: 0x80000000, data CRC: 0x886ADE01, OS: Linux, CPU: IPS, image type: OS Kernel Image, compression type: lzma, image name: "MIPS OpenWrt Linux-3.18.17"
64            0x40            LZMA compressed data, properties: 0x6D, dictionary size: 8388608 bytes, uncompressed size: 5479932 bytes

似乎整个镜像文件的内容都是uImage——在前64(0x40)字节,它表明其后的数据流采用了LZMA算法,并且大小是3252971字节。让我们将64和3252971相加,我们将会得到3253035字节,这正是我们下载的镜像的大小。因此,除了uImage镜像外,该文件中不包含别的内容。Binwalk可以解压发现的lzma数据流。原则上我们可以手动去解压,但是当我们拥有一个方便的工具的时候为何还累着自己呢?

> binwalk -e ./uImage.bin

让我们看看解压出来的东西

> ls -l ./_uImage.bin.extracted/
итого 8532                                                                                                                                                                          
-rw-r--r-- 1 user user 5479932 авг  8 23:10 40                                                                                                                                  
-rw-r--r-- 1 user user 3252971 авг  8 23:10 40.7z

名为40的那个文件,也可以解压,我们用binwalk来看下:
binwalk ./_uImage.bin.extracted/40

DECIMAL       HEXADECIMAL     DESCRIPTION
--------------------------------------------------------------------------------
2812692       0x2AEB14        Linux kernel version "3.18.17 (buildbot@builder1) (gcc version 4.8.3 (OpenWrt/Linaro c version 4.8.3 (OpenWrt/Linaro GCC 4.8-2014.04 r46018) ) #2 Fr"
2932132       0x2CBDA4        LZMA compressed data, properties: 0x5D, dictionary size: 16777216 bytes, missing uncompressed size
2936592       0x2CCF10        xz compressed data
3400392       0x33E2C8        LZMA compressed data, properties: 0x6D, dictionary size: 1048576 bytes, uncompressed size: -1 bytes

我们已经得到了一下东西,还不是很明晰——binwalk已经在0x2AEB14发现了linux内核并且有3个压缩包数据流在内核后面。(省略) 根据常识,linux内核地址从shift 0开始,并且后面跟随一个(只有一个)压缩后的数据流叫做initramfs——初始化最初的文件系统到内存中。内核文档中也这么说: 什么是initramfs? ——所有的2.6内核包含了一个gzip压缩过的“cpio”格式的档案,当内核启动的时候它将被解压到根文件系统。解压之后,内核检查跟文件系统中是否存在“init”文件,并且它是否以PID 1运行

进一步的
2.6内核构造程序总是创建一个gzip压缩过的cpio格式的档案并且将它链接到已存在的内核二进制文件(存疑)。默认情况下,这个档案是空的(在x86体系结构下占用134字节)。

这就是提到的CPIO格式

让我们看看binwalk能否将它提取出来:

binwalk -e ./_uImage.bin.extracted/40
ls -l ./_uImage.bin.extracted/_40.extracted/
итого 14028
-rw-r--r-- 1 user user 2547808 авг  8 23:25 2CBDA4.7z
-rw-r--r-- 1 user user 2543340 авг  8 23:25 2CCF10.tar
-rw-r--r-- 1 user user 7186944 авг  8 23:25 33E2C8
-rw-r--r-- 1 user user 2079540 авг  8 23:25 33E2C8.7z
那么,只有在33E2C8的那个压缩文件被成功解压了,如果所有人都操作对了,它应该是一个被CPIO包裹着的文件系统:
binwalk _uImage.bin.extracted/_40.extracted/33E2C8

DECIMAL       HEXADECIMAL     DESCRIPTION
--------------------------------------------------------------------------------
0             0x0             ASCII cpio archive (SVR4 with no CRC), file name: "dev", file name length: "0x00000004", file size: "0x00000000"
116           0x74            ASCII cpio archive (SVR4 with no CRC), file name: "dev/console", file name length: "0x0000000C", file size: "0x00000000"
240           0xF0            ASCII cpio archive (SVR4 with no CRC), file name: "lib", file name length: "0x00000004", file size: "0x00000000"
356           0x164           ASCII cpio archive (SVR4 with no CRC), file name: "lib/netifd", file name length: "0x0000000B", file size: "0x00000000"
480           0x1E0           ASCII cpio archive (SVR4 with no CRC), file name: "lib/netifd/netifd-wireless.sh", file name length: "0x0000001E", file size: "0x00001638"

***********Куча файлов***********

7186416       0x6DA7F0        ASCII cpio archive (SVR4 with no CRC), file name: "dev/urandom", file name length: "0x0000000C", file size: "0x00000000"
7186540       0x6DA86C        ASCII cpio archive (SVR4 with no CRC), file name: "dev/pts", file name length: "0x00000008", file size: "0x00000000"
7186660       0x6DA8E4        ASCII cpio archive (SVR4 with no CRC), file name: "TRAILER!!!", file name length: "0x0000000B", file size: "0x00000000"

在该档案的结尾我们看见一个名字为TRAILER!!!的文件,根据文档,他是一个档案文件的尾部标志。

意味着,一个initramfs-uImage固件的结构如下:

现在我们开始squashfs-sysupgrade的分析。从文件名来看,该镜像包含了(除去内核)squashfs文件系统,让我们来看看是否如此。

binwalk -e ./sysupgrade.bin 

DECIMAL       HEXADECIMAL     DESCRIPTION
--------------------------------------------------------------------------------
0             0x0             uImage header, header size: 64 bytes, header CRC: 0x66CC90D2, created: Mon Jul  6 21:54:35 2015, image size: 1142606 bytes, Data Address: 0x80000000, Entry Point: 0x80000000, data CRC: 0x91B77696, OS: Linux, CPU: MIPS, image type: OS Kernel Image, compression type: lzma, image name: "MIPS OpenWrt Linux-3.18.17"
64            0x40            LZMA compressed data, properties: 0x6D, dictionary size: 8388608 bytes, uncompressed size: 3396940 bytes
1142670       0x116F8E        Squashfs filesystem, little endian, version 4.0, compression:lzma (non-standard type definition), size: 2221946 bytes,  1132 inodes, blocksize: 262144 bytes, created: Mon Jul  6 21:54:02 2015
64 + 1142606 (镜像大小) = 1142670,刚好等于squashfs镜像的起始地址,而且它结束于1142670 + 2221946 = 3364616。整个bin的大小是3407876字节,有3407876-3364616=43260字节是binwalk所未能识别的。让我们使用hexdump看看那个位置。
hexdump -s 3364616 ./sysupgrade.bin 
0335708 ffff ffff ffff ffff ffff ffff ffff ffff
*
0335ff8 ffff ffff ffff ffff adde dec0 ffff ffff
0336008 ffff ffff ffff ffff ffff ffff ffff ffff
*
0337ff8 ffff ffff ffff ffff adde dec0 ffff ffff
0338008 ffff ffff ffff ffff ffff ffff ffff ffff
*
033fff8 ffff ffff ffff ffff adde dec0
0340004

此处很明显有一些存根(存疑),我们待会再回到这里。

我们先进入用binwalk解压操作所创建的目录

ls -l _sysupgrade.bin.extracted/
итого 8820
-rw-r--r-- 1 user user 2221946 авг  8 23:40 116F8E.squashfs
-rw-r--r-- 1 user user 3396940 авг  8 23:40 40
-rw-r--r-- 1 user user 3407812 авг  8 23:40 40.7z

解压文件“40”

binwalk -e _sysupgrade.bin.extracted/40

DECIMAL       HEXADECIMAL     DESCRIPTION
--------------------------------------------------------------------------------
2812644       0x2AEAE4        Linux kernel version "3.18.17 (buildbot@builder1) (gcc version 4.8.3 (OpenWrt/Linaro c version 4.8.3 (OpenWrt/Linaro GCC 4.8-2014.04 r46018) ) #1 Fr"
2932068       0x2CBD64        LZMA compressed data, properties: 0x5D, dictionary size: 16777216 bytes, missing uncompressed size
2936444       0x2CCE7C        xz compressed data
3396424       0x33D348        ASCII cpio archive (SVR4 with no CRC), file name: "dev", file name length: "0x00000004", file size: "0x00000000"
3396540       0x33D3BC        ASCII cpio archive (SVR4 with no CRC), file name: "dev/console", file name length: "0x0000000C", file size: "0x00000000"
3396664       0x33D438        ASCII cpio archive (SVR4 with no CRC), file name: "root", file name length: "0x00000005", file size: "0x00000000"
3396780       0x33D4AC        ASCII cpio archive (SVR4 with no CRC), file name: "TRAILER!!!", file name length: "0x0000000B", file size: "0x00000000"

我们得到了linux内核和小型的initramfs-image(只包含4个文件),其余的也许都移动到了squashfs镜像里了。

unsquashfs -i ./_sysupgrade.bin.extracted/116F8E.squashfs 
Parallel unsquashfs: Using 4 processors
1033 inodes (1034 blocks) to write

squashfs-root
squashfs-root/bin
squashfs-root/bin/ash
squashfs-root/bin/board_detect
squashfs-root/bin/busybox
***********Куча файлов***********

squashfs-root/www/luci-static/resources/load.svg
squashfs-root/www/luci-static/resources/wifirate.svg
squashfs-root/www/luci-static/resources/wireless.svg
squashfs-root/www/luci-static/resources/xhr.js

created 848 files
created 99 directories
created 184 symlinks
created 0 devices
created 0 fifos

果然,主要的文件系统都被包含进squashfs镜像了

...(英语捉急,翻译不下去了,感兴趣的请直接查看原文。。。)
posted @ 2018-07-17 16:37  sherlock-merlin  阅读(8362)  评论(0编辑  收藏  举报