home  wiki

MinitarHacking


Code Organization



The source code released seems to be either "cleaned" or it is from an early stage in the development of the device. I suspect it has been cleaned, there are some obvious things that should be there such as Makefiles in the Linux and AP directories as well as some packages and files that you would expect to be there to make a working image.

The release has three parts:


As well as the code there is the build environment. This is a third archive that has instructions to load it into /usr/local ( yeah right - not this little black duck).
Looking through the build stuff it seems a bit of a mess. They have zipped up the entire /usr/local from the build machine. Some interesting things in there - looks like the thought about using eCos at some stage as there is a directory fo it there. eCos is an Redhat offering for embedded systems.

ROM size and building the image


So, initally I though there was a limit on the image being 1MB when compressed (well a little smaller, 1MB less the 0x0000-0x10000 (64 KB) that is reserved for the boot code). I found when making an image that some of the files were zero size, turns out that the embedded filesystem that is built in the AP code tree needs to be big enough to fit it all in.

The ROM image is a bit under 1MB when packed for flashing. As the Flash on my unit is 2MB, it is probably safe to make a biger image and load it on. I suspect that the initial units had a 1Mbyte flash and so they are trying to keep the image within that size.

Need to build a test for the size of the image to make sure we allocate enough blocks

Embedded ramdisk


The kernel has an embedded ramdisk that contains all the application code. When the kernel is built the ramdisk is packed into the kernel and is uncompressed and copied to ram as the kernel loads.

Usually a ramdisk like this is used for getting the system up and initializing the disk subsystem etc. Once the normal filesystem is loaded then the root is mounted at the appropriate place. In this case, this is the only file system that is created and loaded.
The script that builds it and loads in the applications (mkimg) calls appimg with an option -b that is labeled block-size, it is -b number of blocks to make the image filesystem. appimg seems to be some sort of munged binary that calls mk2fs then runs through the app_script loading the files into the newly created and mounted filesystem (mounted over /mnt). After the filesystem is created t is unmounted and zipped

You can change the size of the ramdisk by changing the number of blocks. There is an upper limit of 4000 Blocks due to mkimg using the ramfs device to make the filesystem. a better way is to use the loopback device and you are not limited to this size.

If you are building a ramdisk make sure you mount it and check it is not full before trying to use it as the mkimg binary won't complain if the device is full, you end up with a lot of zero length files.

Bootloader


The bootloader (well if they are really using the one made from the source) is in the btcode directory. The boot code is built first in the boot dir than a file boot.img is dumped into the btcode directory. running make in btcode finishes building the bootloader.

The assembly code in Start.S is the first thing executed. Does a bit of houskeeping then copies the boot code to RAM

after that it jumps to the boot code

       la k0, 0x80000000   --> set the address to jump to
       jr k0               --> jump to the start of the boot code
       nop


The boot image is tftp'd to the device and left in RAM, then you use the FLW command to write it to ROM. FLW <dst> <src> <size> the dst is 000000 the src will be 80500000 and the size what is reported by the tftp

Notice the unusual copy semantics here :)

The <dst> is the offset from the base of the ROM, not an absolute address.

Memory map



ROM base is at 0x2bf0000 (or is it 0x00ff0000)

Found 1 x 2M Byte MXIC MX29LV160AB at 0xbe000000

There is 2MB ROM 0x000000 -> 0x200000

 +-----------------------------+
 |   2|   0|   0|   0|   0|   0| Digit counting for hex challenged
 |0000|0000|0000|0000|0000|0000|
 |    |1M  |64K |4K  |256 |16  |
 +-----------------------------+


in the boot loader code there is some mention of partitions in the rom - This is in the first 64K of space 0x00000 to 0x010000.

ROM is partitioned into 4 chunks:

 from        for
 0x000000 -> 0x004000  ( 16K )
 0x004000 -> 0x002000  ( 8K )  + 8K unalloc
 0x008000 -> 0x008000  ( 32K )
 0x010000 -> 0x010000  ( 64K )


This partition map ( as documented in the source) is wrong. The bootloader is a little under 24 KB and is followed by the HS (Hardware Settings), DS (Default Settings), CS (Current Settings) to make up the first 64KB.

It's something like this:
 from        for
 0x000000 -> 0x006000  ( 24K ) Bootloader
 0x006000 -> 0x000400  (  1K ) HS Hardware settings
 0x006400 -> 0x001C00  (  7K ) DS Default settings
 0x008000 -> 0x008000  ( 32K ) CS Current settings 
 0x010000 -> 0x010000  ( 64K ) Web pages (depricated in most firmware)
 0x020000 ->                   Space for CSYS image(s)


The map is a little cramped, My custom bootloader is bigger than 24K now so I chain to it from the default bootloader rather than overwrite it. Ideally the the partition should be enlarged to 32K and the HS, DS and CS partitions "slipped" a bit.

It's supposed to be DANGEROUS to flash from address 0x000000 - boot loader space here.
The firmware image is supposed to be flashed from 0x020000, so it is after the four partitions mentioned in the map above.

It looks like the tftp that is included in the release is modified so when it is launched from the web admin page it performs the transfer, a validation then flashes the image. It expects a full image (WEBS and CSYS) and so would flash from 0x10000. This tftp is different to the one launched by the board boot code, the boot tftp will upload an image to 0x80500000 in RAM and not do anything else with it. It will also download an image in response to a get but only if a previous upload has been performed (do a put of a filename of a certain size and then do a get filename and it knows the last uploaded size, so will retrieve what is in RAM from 80500000 for the size number of bytes: - you may be able to extract ROM contents by writing a dummy file of the appropriate size, doing a FLR 80500000 00000 <size> then the tftp get)

RAM base is at 0x80000000

80000000--- boot loader ? On startup it is copied to here then the code jumps to here

80100000---

80200000---

80500000--- current system upload load point. The image that is uploaded will have a CSYS header that contains the load memory address. When the image has been written to FLASH the boot code looks for the CSYS headder in a number of locations then reads the image load address (in my case it was 80350000) and the size of the image.

from the boot messages:
Memory: 4836k/8192k available (1320k kernal code, 3356k reserved, 1696k data, 44k init, 0k highmem)

Building the embedded ramdisk


The ramdisk is built using mke2fs. There is a binary that is provided in the
SDK for building it but it is kind of restrictive.

dd if=/dev/zero of=/dev/ram bs=1k count=$block_count
mke2fs /dev/ram $block_count
mount -t ext2 /dev/ram /mnt
sh $script_file
umount /dev/ram
dd if=/dev/ram bs=1k count=$block_count of=$temp_file
rename $temp_file, $image_file
gzip -9v -f $image_file
rename "$image_file.gz", $target_file


A perl script to do the same is at the External linkSourceforge Forum

Building the filesystem encounters problems when trying to run mke2fs with more than 4096 blocks. It complains about the size of the underlying device name="console_login">

Console login


The console login was cracked on earlier versions:

2.32 user: super passwd: lance@edimax.com.tw

When the system boots busybox starts, normally there is direct access to the console, and the login screen did not seem to be part of the busybox application?
It comes from a binary /bin/setup.
Ok so how is it invoked? Also how is the "real" system setup called from when the kernel finished loading?

Busybox init.c shows that normally init runs the runlevels as defined in /etc/init.d but in the case where there is not an init.d that it runs some default settings and starts a shell on the system console. The hack is that in /etc/profile (should be .profile? rather than a normal "shell" configuration the /etc/init.sh script is called.

profile runs init.sh starts the webserver and then runs setup. As it is a script then it should be possible to either patch the firmware to comment out the setup call or patch the image once it has been loaded but before we jump to it.

Setup dosn't seem to use the FLASH variables for super login, the password stored in FLASH in the DS and CS sections didn't work. SO the setup binary is a prime candidate for disassembling to work out where it gets it's password from. I suspect that after the last one was cracked so easily they have stopped putting it in clear text, though even if they use someting simple like crypt, then crypt needs to be on the box.

A dump of the file flash.inc shows DS and CS settings for both the super and admin users. Unfortunately the password there ( user: super passwd: APR@xuniL ) did not work for the login but it did give me a clue to how it was being done.


Flash Variables


When running 2.32 on a Unit that came installed with 2.39 I was looking at a script called create_flash.sh. This script pulls out the data stored in the HS DS and CS segments of the Flash memory and puts them in a file /etc/flash.inc. Thsi file is not present in the firmware, it is created on the fly as the system boots.

# cat flash.inc

HW_BOARD_ID=3
HW_NIC0_ADDR=0050fcd7089d
HW_NIC1_ADDR=000000000000
HW_WLAN_ADDR=0050fcd7089d
HW_REG_DOMAIN=3
HW_RF_TYPE=3
HW_TX_POWER=1,1,1,0,0,0,0,0,0,0,0,0,0,0
HW_ANT_DIVERSITY=0
HW_TX_ANT=0
HW_CS_THRESHOLD=11
HW_CCA_MODE=1
HW_PHY_TYPE=0
HW_WLAN_LED_TYPE=0
DEF_DHCP_CLIENT_START='192.168.2.100'
DEF_DHCP_CLIENT_END='192.168.2.200'
DEF_RSER_ENABLED=0
DEF_RSER_CLT_TBL_NUM=0
DEF_RSER_USR_TBL_NUM=0
DEF_ELAN_MAC_ADDR=000000000000
DEF_WLAN_MAC_ADDR=000000000000
DEF_SSID='default'
DEF_CHANNEL=11
DEF_WEP=0
DEF_WEP64_KEY1=0000000000
DEF_WEP64_KEY2=0000000000
DEF_WEP64_KEY3=0000000000
DEF_WEP64_KEY4=0000000000
DEF_WEP128_KEY1=00000000000000000000000000
DEF_WEP128_KEY2=00000000000000000000000000
DEF_WEP128_KEY3=00000000000000000000000000
DEF_WEP128_KEY4=00000000000000000000000000
DEF_WEP_DEFAULT_KEY=0
DEF_WEP_KEY_TYPE=1
DEF_FRAG_THRESHOLD=2346
DEF_SUPPORTED_RATES=15
DEF_BEACON_INTERVAL=100
DEF_PREAMBLE_TYPE=0
DEF_BASIC_RATES=3 
DEF_RTS_THRESHOLD=2347
DEF_AUTH_TYPE=2
DEF_HIDDEN_SSID=0
DEF_WLAN_DISABLED=0
DEF_INACTIVITY_TIME=30000
DEF_RATE_ADAPTIVE_ENABLED=1
DEF_DTIM_PERIOD=127
DEF_WLAN_MODE=255
DEF_NETWORK_TYPE=255
DEF_IAPP_DISABLED=0
DEF_AP_MODE=0
DEF_AP_MODE_TEMP=0
DEF_SECURITY_MODE=0
DEF_CLIENT_IP_DISABLED=0
DEF_WL_LINKMAC1=000000000000
DEF_WL_LINKMAC2=000000000000
DEF_WL_LINKMAC3=000000000000
DEF_WL_LINKMAC4=000000000000
DEF_WL_LINKMAC5=000000000000
DEF_WL_LINKMAC6=000000000000
DEF_WLAN_ENCRYPT=255
DEF_WLAN_ENABLE_SUPP_NONWPA=3
DEF_WLAN_SUPP_NONWPA=0
DEF_WLAN_WPA_AUTH=0
DEF_WLAN_WPA_CIPHER_SUITE=0
DEF_WLAN_WPA_PSK=''
DEF_WLAN_WPA_GROUP_REKEY_TIME=0
DEF_MAC_AUTH_ENABLED=0
DEF_RS_IP='0.1.81.128'
DEF_RS_PORT=0
DEF_RS_PASSWORD=''
DEF_RS_MAXRETRY=0
DEF_RS_INTERVAL_TIME=60
DEF_ACCOUNT_RS_ENABLED=0
DEF_ACCOUNT_RS_IP='0.0.0.0'
DEF_ACCOUNT_RS_PORT=0
DEF_ACCOUNT_RS_PASSWORD=''
DEF_ACCOUNT_RS_UPDATE_ENABLED=0
DEF_ACCOUNT_RS_UPDATE_DELAY=0
DEF_ACCOUNT_RS_MAXRETRY=0
DEF_ACCOUNT_RS_INTERVAL_TIME=768
DEF_WLAN_ENABLE_1X=0
DEF_WLAN_PSK_FORMAT=0
DEF_ALIAS_NAME='Wireless AP'
DEF_IP_ADDR='192.168.2.1'
DEF_DHCPGATEWAYIP_ADDR='0.0.0.0'
DEF_DHCPNAMESERVER_ADDR='0.0.0.0'
DEF_DOMAIN_NAME=''
DEF_LAN_LEASE_TIME=84082693
DEF_SUBNET_MASK='255.255.255.0'
DEF_DEFAULT_GATEWAY='0.0.0.0'
DEF_DHCP=0
DEF_STP_ENABLED=0
DEF_WLAN_MACAC_NUM=0
DEF_WLAN_MACAC_ENABLED=0
DEF_SUPER_NAME='super'
DEF_SUPER_PASSWORD='APR@xuniL'
DEF_USER_NAME='admin'
DEF_USER_PASSWORD='1234'
DHCP_CLIENT_START='192.168.2.100'
DHCP_CLIENT_END='192.168.2.200'
RSER_ENABLED=0
RSER_CLT_TBL_NUM=0
RSER_USR_TBL_NUM=0
ELAN_MAC_ADDR=000000000000
WLAN_MAC_ADDR=000000000000
SSID='HYA-L1'
CHANNEL=1
WEP=0
WEP64_KEY1=0000000000
WEP64_KEY2=0000000000
WEP64_KEY3=0000000000
WEP64_KEY4=0000000000
WEP128_KEY1=00000000000000000000000000
WEP128_KEY2=00000000000000000000000000
WEP128_KEY3=00000000000000000000000000
WEP128_KEY4=00000000000000000000000000
WEP_DEFAULT_KEY=0
WEP_KEY_TYPE=1
FRAG_THRESHOLD=2346
SUPPORTED_RATES=15
BEACON_INTERVAL=100
PREAMBLE_TYPE=0
BASIC_RATES=3
RTS_THRESHOLD=2347
AUTH_TYPE=2
HIDDEN_SSID=0
WLAN_DISABLED=0
INACTIVITY_TIME=30000
RATE_ADAPTIVE_ENABLED=1
DTIM_PERIOD=127
WLAN_MODE=255
NETWORK_TYPE=255
IAPP_DISABLED=0
AP_MODE=0
AP_MODE_TEMP=0
SECURITY_MODE=0
CLIENT_IP_DISABLED=0
WL_LINKMAC1=000000000000
WL_LINKMAC2=000000000000
WL_LINKMAC3=000000000000
WL_LINKMAC4=000000000000
WL_LINKMAC5=000000000000
WL_LINKMAC6=000000000000
WLAN_ENCRYPT=255
WLAN_ENABLE_SUPP_NONWPA=3
WLAN_SUPP_NONWPA=0
WLAN_WPA_AUTH=0
WLAN_WPA_CIPHER_SUITE=0
WLAN_WPA_PSK=''
WLAN_WPA_GROUP_REKEY_TIME=0
MAC_AUTH_ENABLED=0
RS_IP='0.1.81.128'
RS_PORT=0
RS_PASSWORD=''
RS_MAXRETRY=0
RS_INTERVAL_TIME=60
ACCOUNT_RS_ENABLED=0
ACCOUNT_RS_IP='0.0.0.0'
ACCOUNT_RS_PORT=0
ACCOUNT_RS_PASSWORD=''
ACCOUNT_RS_UPDATE_ENABLED=0
ACCOUNT_RS_UPDATE_DELAY=0
ACCOUNT_RS_MAXRETRY=0
ACCOUNT_RS_INTERVAL_TIME=768
WLAN_ENABLE_1X=0
WLAN_PSK_FORMAT=0
ALIAS_NAME=''
IP_ADDR='192.168.2.1'
DHCPGATEWAYIP_ADDR='0.0.0.0'
DHCPNAMESERVER_ADDR='0.0.0.0'
DOMAIN_NAME=''
LAN_LEASE_TIME=84082693
SUBNET_MASK='255.255.255.0'
DEFAULT_GATEWAY='0.0.0.0'
DHCP=0
STP_ENABLED=0
WLAN_MACAC_NUM=0
WLAN_MACAC_ENABLED=0
SUPER_NAME='super'
SUPER_PASSWORD='APR@xuniL'
USER_NAME='admin'
USER_PASSWORD='1234'



Builtin tftp


The builtin tftp that is invoked from the web interface loads, verifies?, flashes and reboots. No source is provided for this binary.

This is not so useful as we would really like to do two things here:
  1. load and execute (not flash) - may not be possible due to space constraints
  2. load an arbitary binary - if you have a console who cares?


What is on this box?


Looks like the earlier firmware had a bunch of stuff for both an AP and a Gateway (Router). This was changed somewhere along the way and the 2.49 firmware is stripped right down. The following is what I have cobbled together from the 2.32 firmware + some other packages.



brctl Bridge utility. This manges and controls bridging tables for joining the wireless and ethernet interfaces together as one LAN

pppd ppp daemon, Hmm, why is this here?

pppoed ppp over ethernet daemon, even curiouser. Tis can be used to connect to a DSL modem or tunnel through to somewhere else

dhcpd DHCP daemon for serving IP addresses to the wireless clients and probablly also to wired clients

dhcpc DHCP client, so we can get an address from ??

webs tiny webserver for the admin pages

iptables interface to netfilter tables. Needs to have support in the kernel

iwpriv Wir eless tools

flash Flash seems to be a utility that allows the get and set of parameters; no source to this - extracted from the firmware. The typical use is in scripts where it is run like: eval `flash get WLAN_MODE` This sets an environment variable $WLAN_MODE that is used after the get

Things that are prebuilt


Uh, these are things that I extracted from the firmware. No source is available for
any of them.

auth ??

disc_server

flash Very important. This is the binary that is used to write stuff to flash - oh and also to read. Assuming it is something like the flash that is included in the boot code (but driven from the command line rather than linked in). There are examples of it's useage in the scripts in the firmware.

iapp ??

iwcontrol ??

pptp Client for the proprietary Microsoft Point-to-point Tunneling Protocol PPTP (Allows connection to a PPTP based VPN -- or a cable or DSL service)

setup Custom login binary that is executed from /etc/profile as the system comes up. Presents a login screen using non-standard methods.

upnpd Universal plug and play daemon. Supposed to help things like MSN Messenger work from behind a firewall

Web pages


The web pages used to be in an external archive that was loaded into flash at an address 64K before the CSYS image. Somewhere arround 2.39 this changed. In 2.49 the web pages are in the ramdisk image in /web

Two things of interest with the web interface, firstly how are the settings and ROM values extracted for the web server to display?
  1. In the asp pages there is the use fo a function "getInfo" that seems to return the parameters needed. Where is this command, is it a bit of Java script that is not included with the source? Is it some other function - I suspect that the flash values are retrieved from the flash dump in /etc
  2. Secondly how are changes applied back to the system?
After almost any change the system reboots, so it is probably a safe bet that changes are vlidated then written to ROM and they system rebooted.

The GoAhead webserver has a special type of CGI procesing. It accepts a POST command with the target of /goform/pagename. This is for an embedded function that proceses the POST data. A function is added to the configuration using the websFormDefine function and a jump table is built of the embedded forms. Each ASP page in the webs configuration uses this mechanism to pass variables (configuration changes) to the embedded functions in the webserver.

The webs binary in the 2.39 image is 238272 bytes
The webs built in the 1.6-SDK tree is 225196 bytes

partial dump of the 2.49 webs binary. Note: these are just the strings form the bss section of the binary, the code that implements these functions is elsewhere. The binary is stripped maing it a bit difficult to reverse engineer the functionality of the forms.

00002a30  66 6f 72 6d 57 6c 61 6e 53 65 74 75 70 00 77 65  |formWlanSetup.we|
00002a40  62 73 46 6f 72 6d 44 65 66 69 6e 65 00 66 6f 72  |bsFormDefine.for|
00002a50  6d 57 6c 61 6e 54 65 6d 70 00 66 6f 72 6d 57 65  |mWlanTemp.formWe|
00002a60  70 00 66 6f 72 6d 57 64 73 57 65 70 00 66 6f 72  |p.formWdsWep.for|
00002a70  6d 54 63 70 69 70 53 65 74 75 70 00 67 65 74 49  |mTcpipSetup.getI|
00002a80  6e 66 6f 00 77 65 62 73 41 73 70 44 65 66 69 6e  |nfo.websAspDefin|
00002a90  65 00 67 65 74 49 6e 64 65 78 00 77 6c 41 63 4c  |e.getIndex.wlAcL|
00002aa0  69 73 74 00 66 6f 72 6d 50 61 73 73 77 6f 72 64  |ist.formPassword|
00002ab0  53 65 74 75 70 00 66 6f 72 6d 55 70 6c 6f 61 64  |Setup.formUpload|
00002ac0  00 66 6f 72 6d 57 6c 41 63 00 66 6f 72 6d 41 64  |.formWlAc.formAd|
00002ad0  76 61 6e 63 65 53 65 74 75 70 00 66 6f 72 6d 53  |vanceSetup.formS|
00002ae0  65 63 4c 6f 67 00 66 6f 72 6d 53 79 73 4c 6f 67  |ecLog.formSysLog|
00002af0  00 66 6f 72 6d 44 65 62 75 67 00 66 6f 72 6d 53  |.formDebug.formS|
00002b00  61 76 65 43 6f 6e 66 69 67 00 66 6f 72 6d 57 6c  |aveConfig.formWl|
00002b10  53 69 74 65 53 75 72 76 65 79 00 77 6c 53 69 74  |SiteSurvey.wlSit|
00002b20  65 53 75 72 76 65 79 54 62 6c 00 66 6f 72 6d 57  |eSurveyTbl.formW|
00002b30  6c 45 6e 63 72 79 70 74 00 66 6f 72 6d 52 61 64  |lEncrypt.formRad|
00002b40  69 75 73 00 52 61 64 69 75 73 43 6c 74 4c 69 73  |ius.RadiusCltLis|
00002b50  74 00 52 61 64 69 75 73 55 73 72 4c 69 73 74 00  |t.RadiusUsrList.|
00002b60  66 6f 72 6d 52 65 62 6f 6f 74 00 66 6f 72 6d 41  |formReboot.formA|
00002b70  63 63 65 70 74 00 66 6f 72 6d 4c 69 63 65 6e 63  |ccept.formLicenc|
00002b80  65 00 77 69 72 65 6c 65 73 73 43 6c 69 65 6e 74  |e.wirelessClient|
00002b90  4c 69 73 74 00 66 6f 72 6d 57 69 72 65 6c 65 73  |List.formWireles|
00002ba0  73 54 62 6c 00 66 6f 72 6d 53 74 61 74 73 00 69  |sTbl.formStats.i| 
00002bd0  49 70 61 64 64 72 00 77 65 62 73 53 65 74 48 6f  |Ipaddr.websSetHo|



Forms called from 2.49 web pages
formSaveConfig contool.asp
formWep encryption.asp
encryption1.asp
encryption2.asp
wlwdk.asp
wlwep.asp
wlwsk.asp
formWlAc macfilter1.asp
formRadius radius.asp
formReboot reset.asp
formTcpipSetup sysutility.asp
formUpload upgrade.asp
formWlEncrypt wl1x.asp
wlars.asp
wlencrypt.asp
wlpsk.asp
wlsec.asp
formAdvanceSetup wla.asp
wlaipc.asp
formWlanSetup wlbasic.asp
formWirelessTbl wlstatbl.asp
formWlSiteSurvey wlsurvey.asp
formWdsWep wlwdswep.asp

Firmware decomposition


This section is a dump of some stuff I did about 4 months ago. Some of it is a bit wrong. and needs some formatting. Thought I would get it out here though.
The firmware image is a single binary file that is loaded onto the AP then burnt into flash at a specified address. The start of the binary file is a structure that contains some information about the image ( 12 bytes)
From previous attempts at decomposing the image there is a number of archives in the file.

Header structure

---from main.c in /boot/init --------

firmware signiture "CSYS"           at 0x0010000


firmware image header
 signiture     (len 4)
 start address (len 4) unsigned long
 length        (len 4) unsigned long


This is the 12 bytes that are at the start of the image. The next bytes are the start of the compressed image (gzip header).


setting image header 
 tag           (len 1)
 version       (len 2) 
 length        (len 2)


ROM partitions

There are four partitions in the ROM image. The partitions are used to store different settings, At the ROM base is the initial boot jump - this is the address where execution starts as the processor is powered up. From that a jump is to the boot loader.

flash base         0x2bf0000


The boot section of the ROM is from offset 0x00000 to 0x010000

 0x000000 -> 0x004000 (16K) - boot code ? 
 0x004000 -> 0x006000 ( 8K) - ??
 0x004000 -> 0x006000 ( 8K) - ??


 0x006000 -> 0x006400 ( 1K) - HS (Hardware settings)
 0x006400 -> 0x008000 ( 7K) - DS (Default settings)
 0x008000 -> 0x010000 (32K) - CS (Current settings)


hw      signiture "HS 0x00 0x00"   at 0x0006000


sw D    signiture "DS 0x00 0x00"   at 0x0006400
sw C    signiture "CS 0x00 0x00"   at 0x0008000


code image offset  0x0010000
code image offset2 0x0020000
code image offset3 0x0030000
code image offset4 0x0008000


The image offsets are used to locate the image during the boot sequence. Each offset is checked in turn to find the firmware image header. When booting we see the message "No image found at 10000" - this is confusing as the image seems to be located there (check by dumping the ROM contents to RAM then dumping to the console).

The alternative offsets are obviously planning for growth of the firmware defaults or image (the offset4 location chews into the "reserved space of the ROM by 32K

The image offsets are used to locate the image during the boot sequence. Each offset is checked in turn to find the firmware image header. When booting we see the message "No image found at 10000" - this is confusing as the image seems to be located there (check by dumping the ROM contents to RAM then dumping to the console).

The alternative offsets are obviously planning for growth of the firmware defaults or image (the offset4 location chews into the "reserved space of the ROM by 32K.

Note: the code as it stands would not work. The function to check the image check_system_image() should return the starting address contained in the image header. Inside the function the checksum is computed and it returns(0) if there is a sum. This code is obviously an early snapshot - as this would always return without an address.

Boot sequence (main.c )


start_kernel

checks for the image at the image offsets and returns the address of the image the firmware image header is returned and then the image is copied to RAM (from returned address to start address in ram (0x80300000) and number of bytes 0x000eb802

 00010000  43 53 59 53 80 30 00 00  00 0e b8 02 00 00 80 21  |CSYS.0.........!|


Backing up settings

From the web interface you can back up the settings. This leaves a file config.bin on your computer. the file has a 4 byte header CS07 then is a gziped image.

Note the HS and DS are not backed up

Version 2.32

Version 2.32 had some sort of compressed web page volume at the start of the archive the instructions to use dd | zcat always results in trailing garbage - it looks like there is a data segment that starts at

0x00000 WEBP 00 01 00 00 00 00


then a size and name of the output file webpages-app.bin

0x0000d -> 0x07300


then null until the next image in the file

0x00010000 CSYS.0 00 00 00


Version 2.34


00018000  00 00 00 00 00 00 00 00 00 00 00 00 1f 8b 08 08  |................|
00018010  83 48 af 3f 02 03 76 6d 6c 69 6e 75 78 5f 69 6d  |......vmlinux_im|
00018020  67 00 ec 5b 6b 70 5c d5 7d ff df c7 4a 6b 7b 2d  |g......kp-......|
00018030  ae e5 95 d8 12 19 ef 95 ae d6 8b a3 24 0b 55 41  |..............UA|


Start of gzipped linux image. 1f b8 is zip "magic"

   +--+--+--+--+--------+--+--+--
   |1f|8b|08|08|8348af3f|02|03|
   +--+--+--+--+--------+--+--+--
 
 ID1 - 1f
 ID2 - 8b
 CM  - compression method 08 = Deflate 
 FLAG - bit flag  0  0  0  0  1  0  0  0  LSB
                  |  |  |  |  |  |  |  +- FTEXT
                  |  |  |  |  |  |  +---- FHCRC
                  |  |  |  |  |  +------- FEXTRA
                  |  |  |  |  +---------- FNAME
                  |  |  |  +------------- FCOMMENT
 MTIME - modification time
 XFL   - extra flag 2 = max compress, 4 = fast compress
 OS    - 03 = UNIX



last 8 bytes of the archive are the orig_crc (4) and orig_len (4)


Version 2.39

Version 2.39 has only a portion of the webpages (512bytes) then nothing. It seems that the way of loading web pages has changed. I suspect that the loading code is still there but the real pages are in the ramdisk filesystem now.

00000000 WEBP ......
00000120  00 00 00 00 00 .....
00010000 CSYS.5....
0001d060 00 00 03 5a 00 00 01 6c 00 00 03 a8 00 00 02 7e |...Z...l.......~| 0001d070 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| * 0001d400 00 00 00 00 00 00 00 00 00 00 00 00 42 5a 68 39 |............BZh9| 0001d410 31 41 59 26 53 59 16 60 bf 77 00 6d 8d 7f ff ff |1AY&SY.`.w.m....|


compressed bzip2 image at 0x1d40c
uncompress then find our markers:

0013d200 .ELF ....


0016cee0  04 04 04 04 04 04 04 04 04 04 10 10 10 10 10 10  |................|
0016cef0  10 41 41 41 41 41 41 01 01 01 01 01 01 01 01 01  |.AAAAAA.........|
0016cf00  01 01 01 01 01 01 01 01 01 01 01 10 10 10 10 10  |................|
0016cf10  10 42 42 42 42 42 42 02 02 02 02 02 02 02 02 02  |.BBBBBB.........|
0016cf20  02 02 02 02 02 02 02 02 02 02 02 10 10 10 10 08  |................|
0017d910 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| * 0017dc00 7f 45 4c 46 01 02 01 00 00 00 00 00 00 00 00 00 |.ELF............| 0017dc10 00 02 00 08 00 00 00 01 00 40 2b 20 00 00 00 34 |.........@+ ...4| 0017dc20 00 05 57 4c 00 00 00 05 00 34 00 20 00 06 00 28 |..WL.....4. ...(|

od -s 0x16ce00 someimg.out | more | grep -B 1 -e ^\* > gaps
to find the gaps in the binary data

Version 2.49

pull out the vmlinux image as before

The ramdisk is not at the same location (16d000) in the vmlinux.image so my guess is that they have changed the type of the filesystem beingused for the ramdisk. (Could be cramfs or squishfs).

The kernel code has some obvious markers in it just before the ramdisk:

0016fb90  04 04 04 04 04 04 04 04 04 04 10 10 10 10 10 10  |................|
0016fba0  10 41 41 41 41 41 41 01 01 01 01 01 01 01 01 01  |.AAAAAA.........|
0016fbb0  01 01 01 01 01 01 01 01 01 01 01 10 10 10 10 10  |................|
0016fbc0  10 42 42 42 42 42 42 02 02 02 02 02 02 02 02 02  |.BBBBBB.........|
0016fbd0  02 02 02 02 02 02 02 02 02 02 02 10 10 10 10 08  |................|


then a bunch of nulls and then some new data starting at 0x00170000

0016fc60  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  |................|
*
00170000  42 5a 68 39 31 41 59 26 53 59 fb 62 b7 aa 00 93  |BZh91AY&SY.b....|
00170010  56 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |V...............|
00170020  ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|


yep, pulling that part of the file out you get a Bzip2 file. when you bunzip2 it
you get the good old ext2 filesystem.

mount as per previous instructions

This suggests that there is probably not any change in the boot loader, the fact that the original web section of the binary is still there ( any wasting space ) means that the /web uncompress still runs though it only unpacks a simple header.

They have squashed the size of the image down considerably from previous versions, this is the uncompressed and mounted fs - perhaps they have taken out the routing software?

Version 2.53


Smaller image again.
strip of the webp.bin archive from the start

dd if=MNWAPB.bin bs=1 skip=$((0x10000)) > 2-53-csys.bin


the csys image has the 12 byte header and checksum at the end.

<12 byte header><rtkrom image><2 byte checksum>


0x0000 -> 0x08000 (32K) is the secondary boot loader


0x08000 ->  zipfile of vmlinux.img


 if8b        ID1 ID2
 08          DEFLATE
 08          FNAME
 a3 1c 23 41 MTIME
 02          XFLG
 03          UNIX


 76 6d 6c 69 6e 75 78 5f 69 6d 67 vmlinux_img

The end of the zipfile has 8 bytes of zipdata 4 bytes of crc and 4 bytes of orig length.

dd if=2-59-csys.bin bs=1 skip=$((0x800C)) > vmlinux.img.gz 
gunzip vmlinux.img.gz
gunzip warns about trailing garbage - padding of 00 00 and the 2 bytes of the csys checksum


dd if=vmlinux.img bs=1 skip=$((0x170000)) > ramdisk.bz2
bunzip2 ramdisk.bz2
bunzip2 warns about trailing garbage - padding of 00 00 00 to 32k boundary?


and there is our favorite ext2 filesystem

mkdir mnt
mount -t ext2 -o loop ramdisk ./mnt -o rw,nodev,nosuid,noexec

the ramdisk is 1646 blocks (of 1K) with 1405 used

edited the /etc/profile (remove last line where setup is run
rebzip2 the file it is slightly larger 0x575xx compared to 0x57420
as extracted from the vmlinux.img the bzip2 file was padded out to 0x58000 (32K boundary?)

this must be because I didn't specify the -9 argument to bzip2
added padding to the end of the new bzip file
concatenated the kernel and the bzip
gzip -9 vmlinux.img
pad to 0xE1400
 

this resulted in a partial success. kernel started to uncompress but then it gave an error ran out of data. The ramdisk I built is slightly smaller than the original (higher compression? ) checking the System.map there is a size of ramdisk symbol checking the build the appimg.o get created as an elf it adds 0x1000 at the start and 0x01C0 to the end of the binary "image" the stuff at the end is the symbol table - this gets stripped away building the final image. The stuff at the start is an ELF header,it includes the size of the ramdisk image.


the error comes from the code where a character is retrieved from the input file. It indicates that we have tried to read beyond the end of the compressed file - but I havent found where the end is set yet. This dosn't make sense as the gzip file is made from the concatenated kernel and ramdisk.

I'll try re-joining an unmodified ramdisk and see if that works - this is to see if the uncompress is Ok on the gzip and bzip I am using. I fthis proves Ok then I need to work ut why the modified ramdisk is causing the uncompress to choke.
could try with a modified one that is a little bigger than the orig rather than a little smaller.

Sofar so good the bzip is the same size, padded and attached to the kernel is Ok, same size, adding the padding

Web download of image

What I haven't worked out is how the image is decomposed when downloaded. The download is a simple TFTP, a single composite image is loaded into RAM. The TFTP reports the start address and the size. The image is made up of a bunch of things:

000000 Web page archive
080000 CSYS image start
010000
018000 start of gzipped vmlinux image

extract the vmlinux image and it is made up of a number of parts also


000000 ?? kernel
16xxxx start of embeded ram disk (gzip in 2.23,2.32,2.34,bzip2 2.49

junk at the end ???
From the rtkload dir in the Linux kernal source the "target" is linux.bin
backtrack through this to find where everything gets put


linux.bin = cvimg rtkrom linux.bin 80300000
                looks like cvimg <infile> <outfile> <start address>
                I suspect this relocates the code to the specified address (sets relative jumps)


rtkrom = mips-linux-objcopy -Obinary memload-full rtkrom
                object copy -O binary generates raw binary file, a memory dump of the
                contents of the input file. All symbols and relocation information is
                discarded. The dump starts at the load address of the lowest section
                copied into the output file


memload-full = cp memload-partial memload-full
                vestigal step?


memload-partial =
   mips-linux-gcc -fno-pic -mno-abicalls -O2 -fomit-frame-pointer -DKERNEL -EB -c
   vmlinux_img.c -o vmlinux_img.o
                 creates an (almost) empty binary, used to set the relocation base? as
                 the remainder if the kernal is added?


   mips-linux-objcopy --add-section .vmlinux=vmlinux_img.gz vmlinux_img.o
                 Add the compressed Kernel(and embeded RAM disk) to the binary


   $(LD) -G 0 -T $(LDSCRIPT) -o memload-partial start.o hfload.o read_memory.o
   vsprintf.o prom_printf.o string.o ctype.o  display.o misc.o vmlinux_img.o


  $(NM) memload-partial
     produces the system.map (for information only, as binary gets stripped later)


vmlinux_img.gz =
   cp $(KERNEL_ROOT)/vmlinux vmlinux-stripped
     copy the kernal image here
     copy the kernal image here
   mips-linux-strip vmlinux-stripped
     strip it 
   mips-linux-objcopy -Obinary vmlinux-stripped vmlinux_img
     strip it again and remove relocation information
   rm -f vmlinux_img.gz
     clean up
   gzip -9v vmlinux_img
     compress it


Building the initrd image

in the AP dir the mkimg directory is where the ramdisk image is built.
run the mkdir script
 ./buildfs -b 2800 -s app_script -o ../../linux-2.4.18/appimg/appimg


The mkimg script calls buildfs and leaves the resulting file in the linux tree
to get included when the kernel builds. This is why the kernal is built first then re-built after the applications are built.

buildfs seems to be some sort of composite binary, or compiled script (perl?).
If you run it as a nonpriveledged user you see a bunch of erros that let you know what is going on.

Makes a ext2 filesystem called appimg of size -b number of 1k blocks. (need to be careful here as if you have more stuff than will fit it creates the nodes in the filesystem but there is no data - all files added after the fs is full are zero size).

You can check this by mounting the created fs and checking there is free space with df
   

Once the filesystem is made it is mounted on /mnt then the app_script is run to load the applications into the fs at the required location.

Note: the released source contains a few binary only applications. Also when comparing the source to the images extracted from the various firmware versions there are a few more binaries and a bunch of scripts that are not in the source. These are now in the AP/binary and AP/script directories and are loaded back in by the app_script


What to add to this unit?


Well apart from just being able to build and modify the firmware, what I was looking for is to add a few features that make it a bit more useable and useful.

Useable

Means allowing someone that doesn't want to mod the hardware to upload custom firmware. This may be a two step process. Use the web interface to load a firmware version that allows access to the box (telnet of ssh).

Need to investigate how the web pages interact with the device. Interested in how settings are changed, change is affected and how the firmware upload is done

From there a new bootloader could be installed that provides the boot wait functionality that would allow recovery after a problem.


Useful

In a community wireless environment there are two possible uses of this box, one as a public AP and the second as a backlink to a higher order node. In addition it might be fun to use it as a WLAN only Gateway device - turn the LAN port into a WAN port - all the software is therebut not configured correctly.




Software Modifications


These are software modifications I have been working on.

Boot_wait

The serial port modification is a giant pain in the arse. Modification to the boot loader to provide the same type of boot_wait functionality as we have on the LINKSYS would be a good start.






To do this we need to re-flash the boot loader - For now build the functionality we want, use the existing loader to copy it to RAM then jump to it. See if we can get it to work then flash it.

For mass use the approach would be to distribute a firmware that has the boot loaded image and a little utility.

Use the web download to put it on the machine then ssh in and run the utility. This would then load the new boot loader.

Need to understand what get's flashed from the web interface (seems to take the image including the web pages probably loads to 0x10000.


Route not Bridge

The bridging rules are set up in a script that calls brutils. This can be easily changed to remove the bridge between the WLAN and the LAN interface. The script has code for a WAN interface (not physicaly on this unit) that is a good template of what is wanted here. Need to the set the WLAN and LAN addresses seperately

System access

You can turn on the telnet daemon in busybox, useful for the initial exploration. Not sure if the password protection on the serial port is in the busybox code or a wrapper.

Once I have had a look around then dropbear looks like the way to go. Using the code from the LINKSYS I have been able to build it in the tree - need to make a script to do the setup. (crib the linksys rc code). The start script first creates the server key (if it is not present) the runs it.

?????? need to understand how the flash utility works - assume it allows storing values in flash but how big and how much space is available and how much is used - probably one of those partitions in the boot sector of the flash.

Monitoring

Snort for intrusion detection.

Traffic management

Frottle, as the other nodes are likely to be using this.

Routing

Bird or Quagga for all routing.

Reality Check

After another month or so of playing with this thing, I have realized that 8MB of RAM is very tight. You loose almost 2MB for the kernel, a further 3-4MB with the ramdisk and each application that is loaded chews however much it needs. I could run bird (OSPF daemon) but nothing else. So the reality check is that while a hypothetical device could have configurations for the three uses described above the reality is that with some reletively minor modifications this device can be used for a cheap and cheerful backlink but it's not really worth spending time trying to use it for a captive portal or an Internet gateway.

One thing that could change this is the addition of a second RAM chip. It was suggested to me that you could take a chip of a PC133 SDRAM (the RAM chip is a standard SDRAM 54 pin TSOP2 package). Adding a second chip 64MBit gives you another 8MB RAM or replacing the existing chip with a 128MBit and adding a second takes you up to the max 32MB supported by the processor.

Using CRAMFS or a tiny bootdisk & NFS are also ways of getting back a bit of RAM .

I'll post up the modified boot loader, I'm adding DHCP client support to it so you can have the device boot from a TFTP server and a minimal ramdisk to use it as a backlink radio


Version 5 (old) modified Mon, 26 Jul 2021 12:49:28 +0000 by capatana
[EditText] [Spelling] [Current] [Raw] [Code] [Diff] [Subscribe] [VersionHistory] [Revert] [Delete] [RecentChanges]
> home> about> events> files> members> maps> wiki board   > home   > categories   > search   > changes   > formatting   > extras> site map

Username
Password

 Remember me.
>

> forgotten password?
> register?
currently 0 users online
Node Statistics
building132
gathering192
interested515
operational242
testing216