【翻译】解析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镜像了