Handmade firmware
An original firmware for the routers Asus SL500/1000 allows to create an arp-table via console, but after reboot this table would be lost. Linux was chosen as the platform for SL-series routers, but it is mounted into read-only partitions, that makes configuration process more complicated. The only way out is the original firmware modification, which can be downloaded from the Asus web site. I had only Asus SL500 router, that’s why the article is about SL500 firmware modification, but the modification process for SL1000 is just the same. I chose SL500_1_1_72A_410 version of firmware, which was contained in the SL500_1_1_72A_410.bin file. Let’s take a brief look at the file structure. As program for binary file modifications WinHEX 12.85 SR-10 was used.
big endian 000-001 - 0000 002-003 - 91CF (depends on the device and firmware version (proprietary CRC)) 004-01F - BE73 1504 0000 0003 0002 0000 0000 0000 0000 0000 0040 0000 0100 0000 020-027 - 534C 3530 3000 0000 (device name SL500) 028-29F - 0000 2A0-2AB - 16 bit 3,2,3,0,0,B 2AC-309 - 0000 30A-329 - first file header 32A-349 - second file header 34A-369 - third file header 36A-487 - 0000 0488-...filesLeft column contains displacements from the beginning of the file in hex-mode and right column contains firmware parts. File header is a structure with the information about the file inside (displacement, length, file number).
u16 file number (1..3) u32 displacement from the beginning of the file u16 flag (00 for the first file, 01 for the second one and 3E for the third (last) one) u16 0000 u32 file length or 0 for EOF u144 18 zero-bytes;The headers of the three files in hex-mode are shown bellow.
0001 0000 0488 0000 0000 0000 F9A0 0000 0000 0000 0000 0000 0000 0000 0000 0000
0002 0000 FE28 0001 0000 003A 6000 0000 0000 0000 0000 0000 0000 0000 0000 0000
0003 003B 5E28 003E 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000
The first and the third files are of little interest here, let’s turn our attention to the second file that contains an image of the file system I’m going to modify. So I cut a part of the file from the FE28 displacement to the EOF.
This received file represents a compressed image of the device file system. At first, it is necessary to expand files from this image, that is unpack files from the cramfs. The file system contains hard links so the image extraction cannot be done under Windows operating systems. That’s why on the virtual machine I decided to use Linux for the file extraction, modification and assembling back to the image. As the virtual machine VMware Workstation (5.5.1 build 19175) was installed. Linux Fedora Core 5 (core version 2.6.15) was installed into it.

Now it is necessary to build an utility for an extraction. For this purpose cramfs-1.1 was used. Besides cramfs zlib-1.2.3 was also installed into the same directory. The complexity of such extraction is that the computer and the router have different endianness. To solve this problem I assembled all utilities with file cramfsck.c, which was modified by Igor Nesterov.
[root@localhost firmware]# pwd /fox/firmware [root@localhost firmware]# ls 2.bin cramfsck.c gzio.c inftrees.h projects zconf.in.h adler32.c cramfsck.c~ image0 linux qnx zlib.3 algorithm.txt crc32.c INDEX Makefile README zlib.h amiga crc32.h infback.c Makefile.in text zutil.c as400 deflate.c inffast.c make_vms.com text~ zutil.h ChangeLog deflate.h inffast.h minigzip.c trees.c compress.c example.c inffixed.h mkcramfs.c trees.h configure examples inflate.c msdos uncompr.c contrib FAQ inflate.h NOTES win32 COPYING GNUmakefile inftrees.c old zconf.h [root@localhost firmware]# ./configure Checking for gcc... Building static library libz.a version 1.2.3 with gcc. Checking for unistd.h... Yes. Checking whether to use vs[n]printf() or s[n]printf()... using vs[n]printf() Checking for vsnprintf() in stdio.h... Yes. Checking for return value of vsnprintf()... Yes. Checking for errno.h... Yes. Checking for mmap support... Yes. [root@localhost firmware]# make gcc -W -Wall -O2 -g -I. mkcramfs.c -lz -o mkcramfs mkcramfs.c: In function ‘parse_directory’: mkcramfs.c:287: warning: pointer targets in assignment differ in signedness mkcramfs.c: In function ‘write_superblock’: mkcramfs.c:399: warning: pointer targets in passing argument 1 of ‘__builtin_strncpy’ differ in signedness mkcramfs.c:401: warning: pointer targets in passing argument 1 of ‘__builtin_strncpy’ differ in signedness mkcramfs.c: In function ‘write_directory_structure’: mkcramfs.c:480: warning: pointer targets in passing argument 1 of ‘strlen’ differ in signedness mkcramfs.c: In function ‘do_compress’: mkcramfs.c:598: warning: pointer targets in passing argument 1 of ‘compress2’ differ in signedness mkcramfs.c:598: warning: pointer targets in passing argument 3 of ‘compress2’ differ in signedness mkcramfs.c: In function ‘write_data’: mkcramfs.c:647: warning: pointer targets in passing argument 3 of ‘do_compress’ differ in signedness mkcramfs.c: In function ‘main’: mkcramfs.c:825: warning: pointer targets in passing argument 2 of ‘crc32’ differ in signedness gcc -W -Wall -O2 -g -I. cramfsck.c -lz -o cramfsck [root@localhost firmware]# ls 2.bin cramfsck GNUmakefile inftrees.c NOTES win32 adler32.c cramfsck.c gzio.c inftrees.h old zconf.h algorithm.txt cramfsck.c~ image0 linux projects zconf.in.h amiga crc32.c INDEX Makefile qnx zlib.3 as400 crc32.h infback.c Makefile.in README zlib.h ChangeLog deflate.c inffast.c make_vms.com text zutil.c compress.c deflate.h inffast.h minigzip.c text~ zutil.h configure example.c inffixed.h mkcramfs trees.c contrib examples inflate.c mkcramfs.c trees.h COPYING FAQ inflate.h msdos uncompr.c [root@localhost firmware]#Now new utils can be used for the files extraction from the file system image to the directory /fox/extraction. Unnecessary files are not listed here.
[root@localhost firmware]# ./cramfsck usage: ./cramfsck [-hv] [-x dir] file -h print this help -x dir extract into dir -v be more verbose file file to test [root@localhost firmware]# ./cramfsck -v -x /fox/extraction 2.bin SS 13 warning: old cramfs format d 0755 344 0:0 /fox/extraction d 0755 392 0:0 /fox/extraction/bin l 0777 8 0:0 /fox/extraction/bin/bash -> /bin/msh f 0755 166484 1011:104 /fox/extraction/bin/busybox l 0777 8 0:0 /fox/extraction/log -> /tmp/log l 0777 17 0:0 /fox/extraction/firewall.cfg -> /tmp/firewall.cfg f 0755 999060 0:0 /fox/extraction/cpu1 d 0755 0 0:0 /fox/extraction/ramfs f 0755 1699436 0:0 /fox/extraction/vmlinux 2.bin: OK [root@localhost firmware]# ls 2.bin cramfsck GNUmakefile inftrees.c NOTES win32 adler32.c cramfsck.c gzio.c inftrees.h old zconf.h algorithm.txt cramfsck.c~ image0 linux projects zconf.in.h amiga crc32.c INDEX Makefile qnx zlib.3 as400 crc32.h infback.c Makefile.in README zlib.h ChangeLog deflate.c inffast.c make_vms.com text zutil.c compress.c deflate.h inffast.h minigzip.c text~ zutil.h configure example.c inffixed.h mkcramfs trees.c contrib examples inflate.c mkcramfs.c trees.h COPYING FAQ inflate.h msdos uncompr.c [root@localhost firmware]# cd .. [root@localhost fox]# ls cramfs-1.1 extraction firmware zlib-1.2.3 [root@localhost fox]# cd extraction [root@localhost extraction]# ls bin dev firewall.cfg home lib mnt proc root tmp var cpu1 etc flash0 jffs2 log opt ramfs sbin usr vmlinux [root@localhost extraction]#GOCstartup from the /etc/init.d directory is an automatically started script, that’s why all the necessary commands for the startup were placed in this file. At the beginning of the script the strings about the author of the firmware modifications were put. And at the end of the GOCstartup - the strings with the commands for the next script extraction, its mode change and running.
echo "Start my part."echo "Extracting file fox.script..." rfcutil xtract /tmp/fox.script fox.script echo "Changing script (fox.script) rights..." chmod 777 /tmp/fox.script echo "Runing script (fox.script)..." /tmp/fox.script echo "End my part."Such complexity of the startup scheme is explained by the fact that all system files are mounted in the read-only partition. Log and conf files are saved in the read-write partition, but during startup process nothing is loading from that part of the file system. As the real network conditions require frequent reconfigurations I decided to place the main script-file in the read-only area to extract and start addition scripts without firmware upgrade was made. This scheme allows to expand router functionality without laborious firmware assembling.
Now it’s time to create the file system image, which can be produced via recently built utility mkcramfs.
[root@localhost firmware]# ./mkcramfs --help ./mkcramfs: invalid option -- - usage: ./mkcramfs [-h] [-e edition] [-i file] [-n name] dirname outfile -h print this help -E make all warnings errors (non-zero exit status) -e edition set edition number (part of fsid) -i file insert a file image into the filesystem (requires >= 2.4.0) -n name set name of cramfs filesystem -p pad by 512 bytes for boot code -s sort directory entries (old option, ignored) -v be more verbose -z make explicit holes (requires >= 2.3.39) dirname root of the directory tree to be compressed outfile output file [root@localhost firmware]# ./mkcramfs /fox/extraction /fox/foxware.bin Directory data: 9008 bytes Everything: 3728 kilobytes Super block: 76 bytes CRC: ffadf25 [root@localhost firmware]# ls 2.bin cramfsck GNUmakefile inftrees.c NOTES win32 adler32.c cramfsck.c gzio.c inftrees.h old zconf.h algorithm.txt cramfsck.c~ image0 linux projects zconf.in.h amiga crc32.c INDEX Makefile qnx zlib.3 as400 crc32.h infback.c Makefile.in README zlib.h ChangeLog deflate.c inffast.c make_vms.com text zutil.c compress.c deflate.h inffast.h minigzip.c text~ zutil.h configure example.c inffixed.h mkcramfs trees.c contrib examples inflate.c mkcramfs.c trees.h COPYING FAQ inflate.h msdos uncompr.c [root@localhost firmware]# cd .. [root@localhost fox]# ls cramfs-1.1 extraction firmware foxware.bin zlib-1.2.3 [root@localhost fox]#As only the disassembling utility was modified it needs to “reverse” the assembled file system image. In the standard distributive of Fedora Core 5 I couldn’t find the convert utility for cramfs, that’s why this utility was transferred from the Debian distributives and was called cramfsswap.
[root@localhost firmware]# ./cramfsswap Usage: ./cramfsswap <in> <out>> [root@localhost firmware]# ./cramfsswap /fox/foxware.bin /fox/foxware_swapped.bin Filesystem is in hostorder. Filesystem contains 392 files. CRC: 0xa95c730f [root@localhost firmware]# cd .. [root@localhost fox]# ls cramfs-1.1 extraction firmware foxware.bin foxware_swapped.bin zlib-1.2.3 [root@localhost fox]#The resultant file foxware_swapped.bin is an image of the file system, which is ready for inserting into the firmware instead of the original image. For this purpose we need to add new image to the part of the original firmware without original file system image. This operation can be carried out under the Windows system with WinHex.
However the simple replacement of the original image by the handmade one is not quite sufficient. It is necessary to correct the file headers in the firmware. As it was mentioned above there are three file headers in the firmware, and the second of which corresponds to the file system image. The changes that should be done are the following: the second file length should correspond to the real file length (3A4000 instead of 3A6000); the third file displacement should also be changed (3B3E28 instead of 3B5E28). The corrected file headers are shown below.
0001 0000 0488 0000 0000 0000 F9A0 0000 0000 0000 0000 0000 0000 0000 0000 0000 0002 0000 FE28 0001 0000 003A 4000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0003 003B 3E28 003E 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000
There are two quite important steps left for the firmware preparing. As it was mentioned above, the third and the fourth bytes contain file checksum. Unfortunately I failed to understand how it is calculated. However the way out exists. For its “calculation” I upload the firmware-file into the router via FTP or TFTP and the current firmware version will show the required CRC. For this purpose TFTP server 3COM (3CServer 1.1.007) was used. It’s a freeware utility with the elementary settings. The upload log is shown below.
SL500(config)# upgrade tftp 192.168.1.3 foxware.bin Shutting down Event-Manager and Syslogd [ OK ] Successfully created and tested attach to shared memory block for software package ##Package Information: CRC = 0x91cf Magic No. = 0xbe731504 Min-Max Config. Size = 0x20000 noConfigBackup Flag = 0 Minimum Flash = 0x400000 Minimum RAM = 0x1000000 Version = LX_3.2.3_Comp_0_0_0_b Components = IRB, QoS, FW ##Models Supported: SL500 ## ##Images: BOOT: Offset [Package = 1160, Flash = 0x0], Size = 63904 CRAMFS: Offset [Package = 65064, Flash = 0x10000], Size = 3817472 CONFIG: Offset [Package = 3882536, Flash = 0x3e0000], Size = 0 ## ## Invalid package CRC. Expected 91cf, computed 68bc % Package validation error Restarting system.I opened the firmware file again and saw that third and the fourth bytes contain 91CF, instead of the expected value 68BC. After changing these bytes to 68BC (SL500_1_1_72A_410_final.bin) firmware can be upgraded via any available method (TFTP, FTP, HTTP). I tried to upload file via TFTP again. The full log of such upgrade is listed below.
ASUS CLI User Access Verification (none) login: admin Password : admin logged in SL500> ena SL500# conf t SL500(config)# up t 192.168.1.3 foxware.bin Shutting down Event-Manager and Syslogd [ OK ] Successfully created and tested attach to shared memory block for software packa ge ##Package Information: CRC = 0x68bc Magic No. = 0xbe731504 Min-Max Config. Size = 0x20000 noConfigBackup Flag = 0 Minimum Flash = 0x400000 Minimum RAM = 0x1000000 Version = LX_3.2.3_Comp_0_0_0_b Components = IRB, QoS, FW ##Models Supported: SL500 ## ##Images: BOOT: Offset [Package = 1160, Flash = 0x0], Size = 63904 CRAMFS: Offset [Package = 65064, Flash = 0x10000], Size = 3817472 CONFIG: Offset [Package = 3882536, Flash = 0x3e0000], Size = 0 ## ## Successfully uploaded new software image. System will now install the new softwa re and reset automatically with the CURRENT SAVED CONFIGURATION. Shutting down PPP Interfaces [ OK ] Shutting down PPP task [ OK ] Shutting down DB service 0:0:1:4: P PP : Exceptional exit from ppp_eventTask [ OK ] ##Package Information: Magic No. = 0xbe731504 Min-Max Config. Size = 0x20000 noConfigBackup Flag = 0 Minimum Flash = 0x400000 Minimum RAM = 0x1000000 ##Models Supported: SL500 ## ##Images: BOOT: Offset [Package = 1160, Flash = 0x0], Size = 63904 CRAMFS: Offset [Package = 65064, Flash = 0x10000], Size = 3817472 CONFIG: Offset [Package = 3882536, Flash = 0x3e0000], Size = 0 ## ## nobkup is 0, and CONFIG offset + size is identical to current values, hence do nothing for CONFIG partition Upgrading bootloader ..... Bootloader successfully upgraded Upgrading CRAMfs ..... 3a0000 bytes CRAMfs successfully upgraded SDRAM self-test Pass..... Hit Return to enter diagnostics Type II memory configuration Starting boot... Power on bss_start 8099DB40 bss_end 809A2270 Detected Memory: 16 MB Calibrating delay loop... 132.71 BogoMIPS Detected CFI Flash Chip 1 @0xBFC00000 Size(4 MB) Flash self-test pass. Boot: Detected cramfs filesystem SecureLink Boot Loader Software TYP_REL_BOOTSW.4.1.0, Mar 21 2006, 23:45:55 CPU ID 4 Revision 0 Loading CPU 0 ....... Loading CPU 1 .... Booting up system,please wait... Detected LX4189 (PRID: c401), Revision: 0000001e, 16 entry TLB. Board has been soft reset:0 times 9 MB SDRAM. Enabling MMU .......done Loading Lexra 4xxx/5xxx MMU routines. Determined physical RAM map: memory: 00988000 @ 00000000 (usable) memory: 00638000 @ 00988000 (reserved) memory: 00040000 @ 00fc0000 (usable) On node 0 totalpages: 4096 zone(0): 4096 pages. zone(1): 0 pages. zone(2): 0 pages. Linux version 2.4.2_hhl20 (root@gdk) (gcc version 2.95.3 20010315 (release/Monta Vista)) #1955 ¤G 3¤ë 21 23:46:00 CST 2006 rtsched version <20010618.0943.20> New MIPS time_init() invoked. Memory: 7640k/10016k available (1500k kernel code, 2376k reserved, 103k data, 44 k init) Dentry-cache hash table entries: 2048 (order: 2, 16384 bytes) Buffer-cache hash table entries: 1024 (order: 0, 4096 bytes) Page-cache hash table entries: 4096 (order: 2, 16384 bytes) Inode-cache hash table entries: 1024 (order: 1, 8192 bytes) Checking for 'wait' instruction... unavailable. POSIX conformance testing by UNIFIX Initializing RT netlink socket Starting kswapd v1.8 pty: 3 Unix98 ptys configured RTC to Sysclk synchronize Started. Amd/Fujitsu Extended Query Table v .166 at 0x0040ots per queue number of CFI chips: 1 Manufacturer ID: c2, Device ID: a8 IP: routing cache hash table of 512 buckets, 4Kbytes TCP: Hash tables configured (established 1024 bind 1024) IP-Config: No network devices available. Freeing unused kernel memory: 44k freedeadonly. 0:0:8:4: CPU 0 Software Reset IramStart=80000640,IramSize=39c0 Initializing Crypt..... Crypt Engine Initialized! Mode is IRB Initializing Database iBE optimized for ALL_ROUTER mode VPN Addfuncs2Iram IBE initialization done Kernel init for VPN successful ipm_RxTask: Waiting for ICCD MSG +³{6{s›{c«˜X›[dnÝØ¹ted: BusyBox v0.60.2 (2002.10.22-13:52+0000) multi-call bina ry c›sÖLض›Û· Starting pid 13, console /dev/console: '/etc/init.d/GOCstartup' Algorithmics/MIPS FPU Emulator v1.5a This firmware has been modified by Klimanov Maxim. Starting modified firmware... mounting /proc mounting /dev/pts setting system clock... Bringing up loopback interface...done Creating directories...done starting user_mgr starting fileconvertor starting firewall ...done bringing up the network starting evtmgr (syslogd also started) starting inetd starting dns starting ddns starting sntp starting l2f_server starting goahead Copyright (c) 2002 GoAhead Software Inc. All Rights Reserved starting dhcpd starting rip starting VPN starting igd starting pptp starting ppp starting monitor Start my part. Extracting file fox.script... assign_memory_buffer:0 rfc_lock:0 extract_file:0 xtract:0 rfc_unlock:0 Changing script (fox.script) rights... Runing scripStarting pid 120, console /dev/console: '/sbin/getty -L ttyS2 9600 vt100' ASUS CLI User Access Verification (none) login: admin Password : admin logged in SL500>The end of the log-file shows that the commands from the GOCstartup file are started, but at a certain moment the console program is loaded, which fully captures the output stream and makes script messages invisible. Let’s make and save the script-file fox.script itself.
This script runs a program, which users can see during console or telnet connections, and sends necessary commands for arp-table reconfigurations to it. I make individual file for these commands to send to the console program. The body of the main script is shown below.
#!/bin/sh rfcutil xtract /tmp/fox.console fox.console /usr/bin/clcli < /tmp/fox.consoleThe file of the addition script (fox.console) is also shown below.
admin admin ena conf t ip arp 192.168.1.2 00:11:22:33:44:55The first two strings contain username and password for the user, who has permission for console access.
The author would like to thank Nesterov Igor and Homutov Vladimir for their invaluable technical help over the whole life of the project. I would also like to acknowledge the help of Andreeva Maria, who corrected the english version of the article.








