User Rating: 0 / 5

Star InactiveStar InactiveStar InactiveStar InactiveStar Inactive
 

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

Left 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.console

The 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:55

The first two strings contain username and password for the user, who has permission for console access.

The author would like to thank Igor Nesterov and Vladimir Homutov for their invaluable technical help over the whole life of the project. I would also like to acknowledge the help of Maria Andreeva, who corrected the english version of the article.

Add comment


Security code
Refresh

Found a typo? Please select it and press Ctrl + Enter.