firmware modification and compilation record

Posted by barello at 2020-02-27

Generally speaking, it's easy to unpack the firmware, but it's difficult to modify the firmware and brush it back to the device. This paper studies several methods of modifying firmware and swiping it back to the device.

Take the firmware of dcs921l as an example. First, use binwalk to analyze its structure:

The structure is very obvious, the kernel system of u-boot plus uimage header plus LZMA package. The simple structure is as follows:

OK, the structure analysis is finished. Now you can unpack the firmware and make some small changes before packaging. Unpack a command:

binwalk -Me dcs932l_v1.14.04.bin

Enter the file system directory, modify the file according to your own needs, and package it into CPIO compressed file:

find . | cpio -H newc -o > ../initrd.cpio

Use LZMA for compression. You can download the corresponding version of LZMA SDK here. Note that LZMA compression of the original firmware specifies the dictionary size. We need to use the same dictionary size as it. Use the - D parameter to specify the dictionary size:

-d ./lzma e initrd.cpio initrd.cpio.lzma -d20

Intercept the data before the kernel file system and splice it to our file system:

dd if=50040 of=kernelHead bs=1 count=4038656 cp ./kernelHead ./kernel cat initrd.cpio.lzma >> kernel

Then compress the kernel:

./lzma e ./kernel ./kernel.lzma -d25

Before splicing the uimage header to the kernel compressed file:

dd if=dcs of=uImageHeader bs=1 count=64 cp uImageHeader uImage cat kernel.lzma >> uImage

Note that the uimage header has CRC validation. We need to calculate the CRC checksum and modify the uimage header information ourselves. When WinHex is opened, the following circled bits are header CRC, image size and data CRC:

First calculate the data CRC, select the part after the uimage header, and select CRC32 in tools - > compute hash to calculate:

Change data CRC to the value we calculated, and fill in the value of image size at the same time:

After that, calculate the value of header CRC, overwrite the original value with 00, and then calculate:

Of course, there are also methods that do not need to manually change CRC. Install u-boot-tools under Ubuntu, and then use the mkimage command to automatically generate the uimage header:

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

The parameters of mkimage are as follows:

-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) // 设置执行位置

If you can enter the device u-boot through TTL, the firmware package will go to this step. If you want to update the firmware through the web interface, you need to add the previous section of u-boot, which will not be covered here.

Starting the device, you can see the following information printed on the serial interface:

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: -------------------------------------------- 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.

Here we choose 1. Write the system firmware to the memory through TFTP instead of flash, otherwise the wrong firmware will be cold. The process of building TFTP server is not described here.

1: System Load Linux to SDRAM via TFTP. Please Input new ones /or Ctrl-C to discard Input device IP ( ==: Input server IP ( ==: Input Linux Kernel filename () ==:uImage

After downloading the firmware from the TFTP server, the device will automatically start the system

To brush in the openwrt firmware to the device, you need to go to the openwrt official website to find out whether the device is supported. You can download the firmware supporting the device directly on the official website, or you can compile it by yourself. Download source package

git clone

Install the corresponding dependencies:

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

Upgrade and install the extension software:

./scripts/feeds update -a ./scripts/feeds install -a make package/symlinks

Use the default compilation environment:

make defconfig

To configure:

make menuconfig

Select the corresponding target platform, device chip model and device specific model, etc

When compiling, openwrt will help you download and install the required package, and generate the corresponding firmware package, which usually takes 4-5 hours:

make V=99

After compiling, the compiled firmware file can be found in. / bin / targets / ramips / rt305x /. There is a configured file directory system in. / build ﹣ dir / target mipsel ﹣ 24kc ﹣ musl / root ramips directory.

Successfully swipe in the device through u-boot:

Dcs932l uses the main controller of Ralink rt3052. We can customize our firmware by compiling the Ralink SDK.

Ralink SDK development manual and source package download: (y9u0)

Tool chain installation configuration

Copy the builderoot source package to the / opt directory, and extract it

cp RT288x_SDK/toolchain/buildroot-gcc342.tar.bz2 /opt tar jxvf buildroot-gcc342.tar.bz2

Compile and install LZMA

tar xvfz RT288x_SDK/toolchain/lzma-4.32.7.tar.gz cd RT288x_SDK/toolchain/lzma-4.32.7 ./configure make make install

Compile and install mksquashfs

cd RT288x_SDK/toolchain/mksquash_lzma-3.2 make make install

In addition, it's better to change the make version of this machine to a lower version, or make will fail to recognize the makefile statement of the old version of the kernel (of course, you can directly change makefiles one by one, which is just a few mistakes)

Source configuration compilation

make menuconfig

Select the product you wish to target -- > select the corresponding hardware chip model:

Kernel / library / defaults selection - > select whether to configure kernel, library, and busybox. You can select one-time settings for the first compilation:

Kernel configuration

Here are the options my device needs to be configured for reference only.

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

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

Other configurations

Busybox Settings ---> Build Options ---> Build BusyBox as a static binary (no shared libs) (编译成静态文件)

Other choices are as needed. The basic choices of uclibc configuration and uclibc + + configuration are the default ones.


make dep make

After compilation, you can find the root image image file in the source / images directory, and the file system exists in the source / romfs directory.

File system modification of Ralink SDK

Just compiling the firmware can not meet our requirements, but also can modify the startup script and add our own files. Open the makefile in the source / vendors / Ralink / rt3052 directory to see that it creates a file directory system and copies some required files into it:

Then we can edit our own file system by modifying the makefile and the files in the directory. The following files can be modified as needed:

rcS: 启动脚本 inittab: init进程配置文件 motd: Ralink图标 fstab:文件系统信息 RT2860_default_vlan:nvram默认配置文件

Add the directory after romfs? Dirs, and add the file after $(romfsinst) / etc? Ro / MOTD (note that the file here needs to be placed in the source / vendors / Ralink / rt3052 directory):

Check the makefile in the source / user / rt2880 "app / scripts directory to find that it has configured the executable and script files in the / SBIN Directory:

To add scripts, just copy them to the source / user / rt2880 "app / scripts directory.

Start script configuration

My startup script configuration is as follows and commented for reference only:

#!/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/ \$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 $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 ifconfig ra0 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 if [ "$gw" == "" ]; then gw="" fi if [ "$gw" != "" ]; then route add default gw $gw gpio gw $gw else route add default gw $ip fi # 后台启动alphapd服务 sleep 3 # 后台运行调度器 killall -q schedule schedule & #for telnet debugging telnetd #for syslogd mkdir -p /var/log