Modifying The DD-WRT GUI

Although released under the GPL, DD-WRT is notoriously difficult to build from source. If you want to customize your DD-WRT installation, it is usually easier to extract files from the firmware image, change what you need, and then re-construct the image.

One exception here is the Web GUI. The DD-WRT Web pages (*.asp, *.htm, *.gif, *.css) in each firmware image are protected in order to prevent modification. Being able to customize the Web interface can be advantageous for those wishing to add compatibility with mobile/uncommon browsers, change themes, add links, etc.

And, despite claims to the contrary, that’s exactly what we’ll be doing.

DD-WRT Sporting the Hack-A-Day Logo

Starting on this project, my first assumption was that the Web pages were built into the httpd binary itself. However, taking a look at the source code, we can see that the function getWebsFile actually reads data from the file /etc/www:

263     FILE *getWebsFile(char *path)
264	{
265	        cprintf("opening %s\n", path);
266	        int i = 0;
267	        while (websRomPageIndex[i].path != NULL) {
268	                if (!strcmp(websRomPageIndex[i].path, path)) {
269	                        FILE *web = fopen("/tmp/www.debug", "rb");
270	                        if (!web)
271	                            web = fopen("/etc/www", "rb");
272	                        if (web == NULL)
273	                                return NULL;
274	                        fseek(web, websRomPageIndex[i].offset, 0);
275	                        cprintf("found %s\n", path);
276	                        return web;
277	                }
278	                i++;
279	        }
280	        cprintf("not found %s\n", path);
281	
282	        return NULL;
283	}

At build time, all of the Web files are concatenated into the /etc/www file; websRomPageIndex is used by the httpd code to identify where each file is located inside of /etc/www.

websRomPageIndex points to an array of data structures that each contain three elements: a pointer to a Web URL string, the size of the file, and the file’s location inside /etc/www:

82	typedef struct {
83	        char *path;             /* Web page URL path */
84	        unsigned int offset;    /* Web page data */
85	        unsigned int size;      /* Size of web page in bytes */
86	} websRomPageIndexType;

UPDATE:

Not long after this article was published, websRomPageIndexType was modified so that newer DD-WRT builds use the following structure:

82	typedef struct {
83	        char *path;             /* Web page URL path */
84	        unsigned int size;      /* Size of web page in bytes */
85	} websRomPageIndexType;

The offset is not explicitly specified and must be inferred based on the sizes of the previous files. Both the old and new formats are supported by webdecomp.

If we can locate websRomPageIndex in the httpd binary, we will be able to identify and extract each Web page from the /etc/www file and associate the extracted data with the appropriate file name.

There are several ways to locate websRomPageIndex. First, IDA resolves the name properly, making it easy to identify the virtual address of websRomPageIndex:


For MIPS binaries, readelf can also be used to identify the websRomPageIndex virtual address:

$ readelf --arch-specific httpd | grep websRomPageIndex
  004372e8 -31416(gp) <unknown> 004352c8 OBJECT   19 websRomPageIndex

These virtual addresses can be converted into file offsets by:

  1. Identifying the ELF program section where the address is located
  2. Subtracting the section virtual address and adding the section file offset to the address

Here, we see that the address 0x004352C8 is located in the second PT_LOAD section:

$ readelf --program-headers httpd

Elf file type is EXEC (Executable file)
Entry point 0x403950
There are 7 program headers, starting at offset 52

Program Headers:
  Type           Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align
  PHDR           0x000034 0x00400034 0x00400034 0x000e0 0x000e0 R E 0x4
  INTERP         0x000114 0x00400114 0x00400114 0x00014 0x00014 R   0x1
      [Requesting program interpreter: /lib/ld-uClibc.so.0]
  LOAD           0x000000 0x00400000 0x00400000 0x24e44 0x24e44 R E 0x10000
  LOAD           0x025000 0x00435000 0x00435000 0x023ab 0x084bc RW  0x10000
  DYNAMIC        0x000128 0x00400128 0x00400128 0x00128 0x00128 RWE 0x4
  GNU_EH_FRAME   0x0023ab 0x00424e30 0x00424e30 0x00000 0x00014 R   0x4
  NULL           0x000000 0x00000000 0x00000000 0x00000 0x00000     0x4

We can now calculate the file offset of websRomIndexPage:

$ echo "$((0x004352C8)) - $((0x00435000)) + $((0x025000))" | bc
152264

Since each structure in the websRomIndexPage array contains a pointer to the Web file path, another method of locating websRomIndexPage is to:

  1. Locate the offset of the first file path in the httpd binary (typically Alive.asp)
  2. Convert the physical offset of this string to a virtual address
  3. Search the binary for references to the virtual address

Once the websRomIndexPage location has been identified, we can simply walk through the structures and extract the corresponding file data from /etc/www until we find a structure with a NULL path, indicating the end of the structure array.

Looking at the first structure entry at offset 152264 (0x252C8), we see that the path pointer points to 0x0041F1F4, the offset into the /etc/www file is 0x00000000, and the file size is 0x00000C6C:

000252c0  04 3f 42 00 30 50 43 00  f4 f1 41 00 00 00 00 00  |.?B.0PC...A.....|
000252d0  6c 0c 00 00 00 f2 41 00  6c 0c 00 00 18 60 00 00  |l.....A.l....`..|

Converting the virtual pointer address 0x0041F1F4 to a physical file offset we get 0x1F1F4, which is where the string “Alive.asp” is located:

0001f1f0  25 3e 00 00 41 6c 69 76  65 2e 61 73 70 00 00 00  |%>..Alive.asp...|

We can now extract the contents of Alive.asp from /etc/www:

$ dd if=www bs=$((0xC6C)) count=1 of=Alive.asp
1+0 records in
1+0 records out
3180 bytes (3.2 kB) copied, 3.106e-05 s, 102 MB/s

And verify that the data looks correct:

<% do_pagehead("alive.titl"); %>
{m}
//<![CDATA[
function to_submit(F) {
F.save_button.value = sbutton.saving;
apply(F);
}
function to_apply(F) {
F.save_button.value = sbutton.saving;
applytake(F);
}
...
</div>
{e}"info"><% tran("share.time"); %>:  <span id="uptime"><% get_uptime(); %></span></div>
{e}"info">WAN<span id="ipinfo"><% show_wanipinfo(); %></span></div>
</div>
</div>
</div>
</body>
</html>

Looks good! We can now modify this file however we want, then copy it back into /etc/www. However, if we change the size of Alive.asp we will also need to update its file size, as well as the file offsets of all subsequent files, in the websRomPageIndex structure array.

Although this process is not terribly difficult, it is time consuming; obviously, some automation is in order. To that end, I’ve written webdecomp, a tool to automate the extraction and restoration of DD-WRT Web files. It has been added to the firmware-mod-kit, and allows you to change the Web pages however you wish, with the following restrictions:

  1. You cannot add files
  2. You cannot delete files (but you can have empty files)

So far it has been tested on various DD-WRT builds for ARMEB, MIPS and MIPSEL, but should work with most architectures and build versions without issue.

Tagged , , . Bookmark the permalink.

39 Responses to Modifying The DD-WRT GUI

  1. acki says:

    I don’t know whether this is the right place to ask… but I’m trying to dissect a firmware which is jungo’s openrg based. Have you guys dealt with those kind of firmwares ? Any plans to add them in the future to firmware-mod-kit ? Thanks.

    acki

    PS: If you want me to, I can upload a firmware sample for you to take a look (out of curiosity, of course).
    PS2: Excuse me for the “cross post”

  2. Craig says:

    The OpenRG firmware usually provides a telnet shell, which is what I’ve always used. Obviously not useful if you don’t have the device though. Which OpenRG-based device are you looking at? The MI-424WR?

  3. acki says:

    Craig,

    Yes, it does provide a telnet shell. I even have supersuser rights. The device is a “Sagem F@st 3504″, rebranded as “Livebox 2″, used in Spain and France by that name and in Belgium and Italy (at least) by other names. I have run binwalk against a firmware -and also against a copy of the whole flash- and very little shows up. Just the u-boot and the kernel. No track of squashfs images or anything at all.
    The point is: Have you guys ever tried to extract stuff from an OpenRG firmware ? Is it somehow in the roadmap of firmware-mod-kit ?

    Thanks.

  4. acki says:

    I forgot the say it, but I also ran latest firmware-mod-kit against the same files to no avail. (I guess it was implied, but just in case).

  5. acki says:

    Another thing I forgot to mention, doing a “strings” to the firmware this line shows up:

    root=/dev/mtdblock6 ro rootfstype=squashfs operational_start=0xbf760000 rescue_start=0x00000000 myfs_start=0xc0000000 type=operational

    So I guess we have another “patched” squashfs suite. Isn’t it a GPL violation ?

  6. Pingback: Modifying DD-WRT’s protected GUI - Hack a Day

  7. Pingback: Modifying DD-WRT’s protected GUI | You've been blogged!

  8. Craig says:

    acki:

    As far as I know, the FMK hasn’t been tested against a lot (any?) of the OpenRG firmware. I have a MI424WR lying around and I checked it out last night. It uses a CramFS file system, so it’s probably not the same OpenRG firmware as your router.

    Patching squashfs is pretty common I’m afraid. I have no idea why, seems to be more trouble than it’s worth. Sometimes the modifications are simple, sometimes more complicated. But it’s only a GPL violation if they don’t provide you with the modified source code.

    If you can provide links to the firmware image and/or GPL code, I can take a look at it. If GPL code is available, it’s usually pretty easy to add into the FMK.

  9. Pingback: Modifying DD-WRT’s protected GUI | The Depot of Talk

  10. acki says:

    Craig,

    The firmware you can find it here.

    http://www.megaupload.com/?d=0GH1FSBD

    Regarding openrg gpl’d source code, you can read this:

    http://www.jungo.com/openrg/download_gpl.html

    As you can see they provide the gpl’d part upon paying $15 and then they mail a CD. But as soon as they change versions, that source code for sure will become useless. Not sure it is a complete GPL violation, but it could perfeclty be.

    Regards.

  11. acki says:

    Craig:

    I don’t understand why, but my last message was removed. I’ll repeat it:

    Firmware is here:

    http://www.megaupload.com/?d=0GH1FSBD

    And then, jungo offers their GPL’d source code upon paying 15$. See here:

    http://www.jungo.com/openrg/download_gpl.html

    And the worst part of it. You get the CD with the modified sources… and then, for next version, what do you do? Pay another $15 every time ? Plus the fact that we don’t know what openrg version was used to build that firmware. I still think that this is a GPL violation because source code is not exactly publicly available.

  12. acki says:

    Craig,

    My last two comments were “moderated” though I don’t understand the reason. I was speaking about a possible GPL violation and posted a link with a firmware to prove it. I apologize for any inconvenience.

    If you want to discuss regarding this issue, you have my e-mail.

    Regards.

  13. Pingback: Modifying DD-WRT’s protected GUI | CisforComputers

  14. Pingback: Modifying DD-WRT’s protected GUI - Free Plans, Hacks, Howto's and other DIY stuff - Free Plans Online

  15. Pingback: Modifying DD-WRT’s protected GUI « FOOTBALL, SEX & ALCOHOL

  16. cbrown says:

    @acki:
    The filesystem in the firmware you’ve mentioned is not a squashfs. At offset 0x180 in the file openrg.img (http://www.megaupload.com/?d=0GH1FSBD) you’ll find a GZIP signature; crop the file from that point to the end of file and save as vmlinux.bin.gz. Then, decompress with ‘gunzip vmlinux.bin.gz’. The decompressed file (vmlinux.bin) contains a cramfs filesystem at offset 0x2f4000 (below you’ll see “Compressed ROMFS”); again, crop from that point to the end. Now you can extract its content using this utility: http://firmware-mod-kit.googlecode.com/issues/attachment?aid=-4083775365610407538&name=lzma-uncramfs.tar.gz&token=65209990128d32db53a91e866fe8de98

    Regards.

  17. Craig says:

    Well there you to acki. :)

    Sorry I haven’t gotten a chance to look at the firmware image yet, so thanks cbrown for jumping in and figuring it out!

  18. shiv says:

    i flashed ddwrt on dlink 615 bu i want to change the ddwrt to dlink in firmware. i downloaded the .bin file of ddwrt and when i try to extract its shows error “file not suppurted”..

  19. shiv says:

    i try to extract with power iso ned help plz

  20. shiv says:

    can u provide step by step guidies for newbies

  21. Craig says:

    @shiv:

    What tool gave you the “file not supported” error? That string is not in the webdecomp tool nor the extract scripts from the firmware mod kit.

    PowerISO is for working with ISO files. Firmware updates generally are not in ISO format.

    There are step-by-step examples of how to extract the firmware, modify the DD-WRT GUI and put it all back together again in the firmware mod kit’s wiki page (see the ‘Examples’ section at the bottom of the page): http://code.google.com/p/firmware-mod-kit/wiki/Documentation

  22. shiv says:

    so that mean have work u linux based to modify firmware..thx a lot for help..if any very i stuck i ask question again..thx again m8…

  23. fwhacking says:

    You can have a look here, and you’ll see how to extract the firmware: http://fwhacking.blogspot.com/search/label/Livebox%202

    uncramfs-lzma is required, and fortunately it’s found in firmware-mod-kit :)

  24. Zak says:

    I don’t know about building DD-WRT, but I didn’t have that much trouble building Open WRT.

    It took about a weeks of on and off reading and a couple of days of setting up the build chain.

    I was able to set up a working toolchain in Xbuntu in Virtual Box and had a working build for my router. And honestly that was the second time i’d ever build a kernal from source and the 1st time i’d ever cross compiled anything under *nix gcc toolchain.

    The hardest part was that the dependencies scripts were using wget which refused to use anything other than IPv6 which at the time, the shitty OME firmware on my router failed to work with. So i ended up having locally host ever dependency and add entries in the /etc/network/hosts file. Just to get the configure script to complete.

  25. John says:

    Not sure if you guys would be willing to help but…..

    Would it be possible to create a small webpage that would use the admin GUI webserver with redirect to the contents to the NAS?

    I have the most current version of dd-wrt:

    DD-WRT v24-sp2 (06/14/11) std
    (SVN revision 17201)

    I have a 1tb drive on the USB. Samba is enabled and I am able to see the share via my network. I have the share listed on my network as the z: drive and am able to read and write to it via the pc’S on my network.

    The problem I am having is I just got a Roku2 XS streaming media box. I was watching movies via the USB port on the Roku. What I didn’t relize is that in order to be able to stream movies from the NAS on my router the Roku must access the NAS via an http:// webserver

    Is there a simple way to webshare my NAS to my internal network?

    I found something that might help:

    http://www.dd-wrt.com/wiki/index.php/WEB_server

    Any help with this would be very helpful. I am sure there are others with a Roku box that this may help as well. These seem to be becoming very popular.

  26. no says:

    The latest version of Firmware Modification Kit supports extracting/rebuilding the latest dd-wrt webui but it doesn’t support adding/deleting/renaming files.

    Any tips on how to add/remove files from the web interface using this manual technique?

    • Craig says:

      The FMK doesn’t support adding/deleting/renaming files, as that would (in all but a few cases), cause the size of the data and/or structure array in the httpd binary to change, which would almost certainly cause it to crash. You can have files of zero length though.

  27. Lvbuser says:

    I found the comment http://www.devttys0.com/2011/09/modifying-the-dd-wrt-gui/#comment-1826 but Megaupload is off :(

    Anybody have the firmware fast3yyy_69127a for livebox 2? Thanks

  28. archer says:

    Everybody is searching the “fast3yyy_69127a” or any firmware from livebox2 for example: “fast3yyy_691288″. Please anybody could put a valid link, their help will be very apreciated.
    Thanks.

  29. borhanoddin says:

    i succely uncramfs a sagemfast3505’s image with the uncramfs-lzma , i did some modification , and i tried to rebuild the img , but i can’t find a reverse operation tool , i tried only to cramfs the modified directory , but the result image is bigger than the origin . does for exempe “mkcramfs-lzma” still not ready yet ? thnks .

  30. Aldo says:

    Hi great article, really interesting.
    Unfortunately this seems not to work with recent version of dd-wrt v24 preSP2..
    Any progress on that?
    Thank you

  31. John says:

    Hi Craig, where can I download firmware_mod_kit?

    Thank you.

  32. Alexander says:

    Hi! It’s a very amazing post! I was also trying to unpack my httpd of an OpenRG firmware. I managed to unpack the actual firmware and to mount the file system with httpd.
    Applying strings httpd I can see some variables and html code, but how to extract it and how to pack it back I have no idea. webdecomp doesnt work against it.
    Actually there is no websRomPageIndex function I can find, thats where im stuck..

  33. Marko says:

    Hi. Is there a way to decompile the nikon dslr firmware and include some features of the high end cameras into the cheaper ones?

  34. raag says:

    dear sir
    i want hire your service if u intrested. i want to change logo of a firmware of ddwrt kindly contact me at the provided email address thanx n regards
    raag

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>