翻譯自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 201564 + 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鏡像了
...(英語捉急,翻譯不下去了,感興趣的請直接查看原文。。。)