一般来说要解包固件都很简单,但是要对固件进行修改并重新刷回设备就有一定的难度了。本文研究了几种修改固件并刷回设备的方法。
拿dcs921l的固件来举例,先用binwalk分析下它的结构:
结构很明显,U-Boot加上uImage头加上lzma打包的内核系统。简单的结构图如下:
ok,结构分析完了,现在可以解包固件做点小修改再进行打包了。解包一条命令搞定:
binwalk -Me dcs932l_v1.14.04.bin
进入文件系统目录,根据自己需要修改文件,打包成cpio压缩文件:
find . | cpio -H newc -o > ../initrd.cpio
再用lzma进行压缩,可在这里下载对应版本的lzma sdk,注意原固件的lzma压缩指定了字典大小,我们需要使用和它一致的字典大小,用-d
参数指定字典大小:
./lzma e initrd.cpio initrd.cpio.lzma -d20
截取内核文件系统前的数据再拼接到我们的文件系统前:
dd if=50040 of=kernelHead bs=1 count=4038656
cp ./kernelHead ./kernel
cat initrd.cpio.lzma >> kernel
再对内核进行压缩:
./lzma e ./kernel ./kernel.lzma -d25
截取uImage头拼接到内核压缩文件前:
dd if=dcs of=uImageHeader bs=1 count=64
cp uImageHeader uImage
cat kernel.lzma >> uImage
注意uImage头这里是有CRC验证的,我们需要自己计算一下CRC校验和并修改uImage头的信息。WinHex打开,下图圈起来的几位分别是header CRC,image大小和data CRC:
先计算data CRC,选中uImage头之后的部分,在Tools->Compute Hash中选择CRC32进行计算:
把data CRC修改为我们计算的值,同时填上image大小的值:
之后计算header CRC的值,把原来的值都用00来覆盖再计算就行了:
当然,也有不需要手动改CRC的方法。在ubuntu下安装u-boot-tools,再用mkimage命令就可以自动生成uImage头:
sudo apt-get install u-boot-tools
mkimage -A MIPS -O linux -T kernel -C lzma -a 0x80000000 -e 0x803B8000 -n "Linux Kernel Image" -d kernel.lzma uImage
mkimage各参数信息如下:
-A ==> set architecture to 'arch' // 用于指定CPU类型
-O ==> set operating system to 'os' // 用于指定操作系统
-T ==> set image type to 'type' // 用于指定image类型
-C ==> set compression type 'comp' // 指定压缩类型
-a ==> set load address to 'addr' (hex) // 指定image的加载地址
-e ==> set entry point to 'ep' (hex) // 指定内核的入口地址
-n ==> set image name to 'name' // image在头结构中的命名
-d ==> use image data from 'datafile' // 无头信息的image文件名
-x ==> set XIP (execute in place) // 设置执行位置
如果你能通过TTL进设备U-Boot的话固件打包到这一步就行了,如果要通过web界面更新固件就需要再加上前面的一段U-Boot了,这里不再赘述。
启动设备,在串行界面可以看到打印如下信息:
U-Boot 1.1.3
Board: Ralink APSoC DRAM: 32 MB
relocate_code Pointer at: 81fac000
config usb..
Set info->start[0]=BF000000
flash_protect ON: from 0xBF000000 to 0xBF021767
flash_protect ON: from 0xBF030000 to 0xBF030FFF
*** Warning - bad CRC, using default environment
============================================
Ralink UBoot Version: 3.5.2.0
--------------------------------------------
ASIC 3052_MP2 (Port5<->None)
DRAM component: 256 Mbits SDR
DRAM bus: 16 bit
Total memory: 32 MBytes
Flash component: NOR Flash
============================================
icache: sets:256, ways:4, linesz:32 ,total:32768
dcache: sets:128, ways:4, linesz:32 ,total:16384
##### The CPU freq = 320 MHZ ####
estimate memory size =32 Mbytes
Signature: DCS-930 932L Release 1.11 (2011-05-31)
Please choose the operation:
1: Load system code to SDRAM via TFTP.
2: Load system code then write to Flash via TFTP.
3: Boot system code via Flash (default).
4: Entr boot command line interface.
7: Load Boot Loader code then write to Flash via Serial.
9: Load Boot Loader code then write to Flash via TFTP.
这里我们选择1,通过TFTP写入系统固件到内存中,不要刷到flash里,不然刷错固件就凉了。搭建TFTP服务器的过程这里就不赘述了。
1: System Load Linux to SDRAM via TFTP.
Please Input new ones /or Ctrl-C to discard
Input device IP (192.168.1.1) ==:192.168.0.100
Input server IP (192.168.1.100) ==:192.168.0.103
Input Linux Kernel filename () ==:uImage
设备从tftp服务器上下载完固件后就会自动启动系统了:
要向设备中刷入openwrt固件需要先去openwrt官网查找是否支持此设备。你可以直接在官网下载支持设备的固件,也可以自己动手编译。
下载源码包
git clone https://github.com/openwrt/openwrt
安装相应的依赖:
sudo apt-get install gcc g++ binutils patch bzip2 flex bison make autoconf gettext texinfo unzip zip unrar p7zip p7zip-rar p7zip-full sharutils subversion libncurses5-dev ncurses-term zlib1g-dev gawk git-core libssl-dev
升级安装扩展软件:
./scripts/feeds update -a
./scripts/feeds install -a
make package/symlinks
使用默认编译环境:
make defconfig
配置:
make menuconfig
选择相应的目标平台,设备芯片型号和设备具体型号等:
编译,Openwrt会帮你把需要的包下载安装好,并生成对应的固件包,一般需要4-5个小时:
make V=99
编译完成后可在./bin/targets/ramips/rt305x/下找到编译好的固件文件,在./build_dir/target-mipsel_24kc_musl/root-ramips目录下有配置好的文件目录系统。
通过u-boot成功刷入设备:
dcs932l使用的是Ralink RT3052的主控,我们可以通过编译Ralink SDK来定制自己的固件。
Ralink SDK开发手册以及源码包下载:https://pan.baidu.com/s/1VenLy-YM2f-sTOy-aLkJSw (y9u0)
复制buildroot源码包到/opt目录下,并解压
cp RT288x_SDK/toolchain/buildroot-gcc342.tar.bz2 /opt
tar jxvf buildroot-gcc342.tar.bz2
编译安装LZMA
tar xvfz RT288x_SDK/toolchain/lzma-4.32.7.tar.gz
cd RT288x_SDK/toolchain/lzma-4.32.7
./configure
make
make install
编译安装MKSQUASHFS
cd RT288x_SDK/toolchain/mksquash_lzma-3.2
make
make install
另外最好将本机的make版本换成低版本的,不然会出现make无法识别旧版本内核的Makefile语句的问题(当然也可以直接一个个改Makefile,也就那么几句错误)
make menuconfig
Select the Product you wish to target-->选择对应的硬件芯片型号:
Kernel/Library/Defaults Selection --->选择是否配置Kernel,library,busybox,头一次编译可以都选上一次性设置完:
下面是我的设备需要配置的选项,仅作为参考。
Machine selection --->
System type--> (选择板子型号)
DRAM Size (32M) ---> (选择内存大小)
Kernel NVRAM (启用NVRAM)
Compress ramdisk by lzma instead of gzip (用lzma打包镜像文件)
General setup --->
Kernel->user space relay support (formerly relayfs) (启用内核空间到用户空间的relay支持)
Block layer --->
Enable the block layer (启用通用块层)
IO Schedulers --->
Default I/O scheduler (No-op) ---> (默认I/O调度器为No-op *适合闪存设备和嵌入式系统的I/O调度器)
No-op
Networking --->
Networking options --->
Packet socket
Unix domain sockets(同一主机进程间通信)
TCP/IP networking
Generic IEEE 802.11 Networking Stack(无线网络支持)
IEEE 802.11 WEP encryption (802.1x)
Device Drivers --->
Network device support --->
Network device support (启用网络设备支持)
Character devices --->
Ralink GPIO Support
Ralink GPIO LED Support
USB support --->
Support for Host-side USB
USB device filesystem
File systems --->
Kernel automounter support (内核自动挂载支持)
Kernel automounter version 4 support (also supports v3)
Filesystem in Userspace support
Pseudo filesystems --->
/proc file system support
/proc/kcore support
Sysctl support (/proc/sys)
sysfs file system support
Library Configuration ---> (选择需要的Lib库)
Network Applications ---> (选择需要的网络相关软件)
storage(enable chmod, fdisk in busybox)
proftpd (FTP Server)
iptables
openssl
pppd
l2tp client
pptp
uvc_stream
Miscellaneous Applications --->
busybox
mtd write
Proprietary Application --->
NVRAM
GPIO
Busybox Settings --->
Build Options --->
Build BusyBox as a static binary (no shared libs) (编译成静态文件)
其他的根据需要进行选择就行了。
uClibc Configuration 和 uClibc++ Configuration基本选默认的就行。
make dep
make
编译完成后可在source/images目录下找到root_uImage镜像文件,在source/romfs下存在文件系统。
光编译好固件可不能满足我们的要求,还要能修改启动脚本,添加我们自己的文件才行。
打开source/vendors/Ralink/RT3052目录下的Makefile可以看到它创建了文件目录系统,并把一些需要的文件拷进去了:
那么我们就可以通过修改Makefile和目录下的文件来编辑自己的文件系统。可根据需要修改下面几个文件:
rcS: 启动脚本
inittab: init进程配置文件
motd: Ralink图标
fstab:文件系统信息
RT2860_default_vlan:nvram默认配置文件
在ROMFS_DIRS后添加目录,在$(ROMFSINST) /etc_ro/motd后添加文件(注意这里的文件需要放在source/vendors/Ralink/RT3052目录下):
查看source/user/rt2880_app/scripts目录下的Makefile可以发现它配置了/sbin目录下的可执行文件和脚本文件:
要添加脚本只需复制到source/user/rt2880_app/scripts目录下即可。
下面我的启动脚本配置,并进行了注释,仅作为参考:
#!/bin/sh
mount -a #挂载所有的文件系统,在fstab文件中有配置
mkdir -p /var/run
cat /etc_ro/motd
# Linux 2.6 uses udev instead of devfs, we have to create static dev node by myself
# 创建静态dev节点
mounted=`mount | grep mdev | wc -l`
if [ $mounted -eq 0 ]; then
mount -t ramfs mdev /dev
mkdir /dev/pts
mount -t devpts devpts /dev/pts
mdev -s
fi
# 创建设备文件
mknod /dev/spiS0 c 217 0
mknod /dev/i2cM0 c 218 0
mknod /dev/rdm0 c 254 0
mknod /dev/flash0 c 200 0
mknod /dev/swnat0 c 210 0
mknod /dev/hwnat0 c 220 0
mknod /dev/acl0 c 230 0
mknod /dev/ac0 c 240 0
mknod /dev/mtr0 c 250 0
mknod /dev/nvram c 251 0
mknod /dev/gpio c 252 0
mknod /dev/PCM c 233 0
mknod /dev/I2S c 234 0
echo "# <device regex> <uid>:<gid> <octal permissions> [<@|$|*> <command>]" > /etc/mdev.conf
echo "# The special characters have the meaning:" >> /etc/mdev.conf
echo "# @ Run after creating the device." >> /etc/mdev.conf
echo "# $ Run before removing the device." >> /etc/mdev.conf
echo "# * Run both after creating and before removing the device." >> /etc/mdev.conf
echo "sd[a-z][1-9] 0:0 0660 */sbin/automount.sh \$MDEV" >> /etc/mdev.conf
#enable usb hot-plug feature
echo "/sbin/mdev" > /proc/sys/kernel/hotplug
# 启动nvram_daemon进程
nvram_daemon&
# 从nvram配置文件中获取用户名和密码并设置系统用户
login=`nvram_get 2860 Login`
pass=`nvram_get 2860 Password`
echo "$login::0:0:Adminstrator:/:/bin/sh" > /etc/passwd
echo "$login:x:0:$login" > /etc/group
chpasswd.sh $login $pass
# audio
pcmcmd -s &
# video
uvc_stream -b &
sleep 2
# Set RT3050 to dump switch mode (restore to no VLAN partition)
switch reg w 14 5555
switch reg w 40 1001
switch reg w 44 1001
switch reg w 48 1001
switch reg w 4c 1
switch reg w 50 2001
switch reg w 70 ffffffff
switch reg w 98 7f7f
switch reg w e4 7f
lan_if="br0"
# lo interface up -- mydlink need it
ifconfig lo up
# setup bridge, lan and wlan interface, and fast forwarding time (setfd, setmaxage)
ifconfig eth2 0.0.0.0
ifconfig ra0 0.0.0.0
brctl addbr br0
brctl addif br0 ra0
brctl addif br0 eth2
brctl setfd br0 1
brctl setmaxage br0 1
# setup wlan enable/disable
gpio wlan 1
# 配置ip地址
ip=`nvram_get 2860 wan_ipaddr`
nm=`nvram_get 2860 wan_netmask`
gw=`nvram_get 2860 wan_gateway`
ifconfig $lan_if $ip netmask $nm
route del default
gpio gw 0.0.0.0
if [ "$gw" == "0.0.0.0" ]; then
gw=""
fi
if [ "$gw" != "" ]; then
route add default gw $gw
gpio gw $gw
else
route add default gw $ip
fi
# 后台启动alphapd服务
web.sh
sleep 3
# 后台运行调度器
killall -q schedule
schedule &
#for telnet debugging
telnetd
#for syslogd
mkdir -p /var/log