DWR-921 Stock Image Cracking

Under Construction!
This page is currently under construction. You can edit the article to help completing it.

The layout into the flash device is the following:

0x000000000000-0x000000010000 : "Bootloader"
0x000000010000-0x000000150000 : "Kernel"
0x000000180000-0x000000f10000 : "RootFS"

The Kernel partition is formatted by two block:

  1. Image Header
  2. Linux lzma image

The Image Header provides some informations to the jboot (stock) bootloader to execute the bootstrap of the linux lzma image.

The Image Header located in the flash is 0x38 byte long. The Image size is variable and its value is reported in one field of the Image Header. I'm currently able to decode only some field present in the Image Header, but not all.

With reference to the oem fw available from dlink DWR-921_RevC_Firmware3.01b07.bin, the Image Header is formatted as described below:

00000000: 04 04 24 2b	magic
00000004: 74 77 bd 08	Timestamp : (UTC_TIME-0x35016f00)/4
00000008: 3c de 13 00	size(kernel.bin)+0x28
0000000c: 38 b8         ~jboot_checksum(start value: 0, start address: 0x00000010, length: size(kernel.bin)+0x28) -> jboot_checksum description below
0000000e: 1d ba         ~jboot_checksum(start value: 0, start address: 0x00000000, length: 0x0c) -> jboot_checksum description below
00000010: 24 21 03 02	magic ?
00000014: 00 00 00 80	kernel ram load address
00000018: 14 de 13 00	size(kernel.bin)
0000001c: 7c 61 6e 69	crc32(kernel.bin)
00000020: 00 00 00 80	start ram address 
00000024: 00 00 18 bc 	root.squashfs flash load address
00000028: 00 a0 75 00 	size(root.squashfs)
0000002c: 10 5a e6 1a	crc32(root.squashfs)
00000030: fb 8d 6b e6	crc32 (area 0x20 -> 0x37, 0x30->0x33 replaced with zero)* -> see below
00000034: 28 00 00 00 	magic 
00000038: 5d 00 00 00 	<- 0x38 kernel (in lzma format) start
0000003c: 02 64 27 3a

The understanding of the word generation at offset 0x0c and 0x30 shall be enough to generate a firmware image accepted by jboot during the boot process.

(*) To calculate crc32 from 0x30 You must set 0x30-0x33 to zero. Example:

00000020: 00 00 00 80	 
00000024: 00 00 18 bc 
00000028: 00 a0 75 00 
0000002c: 10 5a e6 1a	
00000030: 00 00 00 00	
00000034: 28 00 00 00

What is jboot_checksum? It make sum of 16-bit data. If counter is above 0xFFFF, is added extra “1”. See c code:

uint16_t checksum(uint16_t start_val, uint16_t *data, int size)
{
  uint32_t counter;
  uint16_t  *ptr;
 
  counter = start_val;
  ptr = data;
  while ( size > 1 )
  {
    counter += *ptr;
    ++ptr;
    while ( counter >> 16 )
      counter = (uint16_t) counter + (counter >> 16);
    size -= 2;
  }
  if ( size > 0 )
    counter += *(uint8_t *)ptr;
  while ( counter >> 16 )
    counter = (uint16_t) counter + (counter >> 16);
  return counter;
}

The squashfs rootfs is stored at the (absolute) location provided in the word at offset 0x24:

bc180000: 68 73 71 73 6a 05 00 00 d1 4c f7 57 00 00 02 00  hsqsj....L.W....    <- squashfs signature
bc180010: 41 00 00 00 01 00 11 00 c0 00 01 00 04 00 00 00  A...............
[ ... ]

At power on reset the jboot should perform the foolowing operations:

  1. verify the crc of the kernel and rootfs image
  2. decompress the lzma image at the location reported in the field at 0x14 or 0x20 in the image
  3. bootstrap the kernel with cmd line: console=ttyS1,57600n8 root=/dev/mtdblock3
This is the early log from the bootstrap:

...................
Starting kernel @80000000...

LINUX started...

THIS IS ASIC
Linux version 2.6.36 (tja@localhost.localdomain) (gcc version 4.3.5 (Buildroot 2011.05) ) #19 Thu Jul 7 15:20:08 CST 2016
CMD_LINE:console=ttyS1,57600n8 root=/dev/mtdblock3

The jboot can be used to replace the fw image. To activate this function it is enough to send a character over the console during the firs seconds of the bootstrap. In this way the standard bootstrap process is interrupted and a web page appears at address 192.168.1.243. This web page can load a “fw update file” and flash the new image accordingly.

The “fw update file” have a specific format and can be generated using the dlink binboy tool.

The “fw update file” is the concatenation of the following blocks:

  1. specific file headers (0x50 bytes long)
  2. kernel headers (almost identical to the one stored in the kernel flash partition) (0x38 bytes long)
  3. kernel image in lzma format (variable size)
  4. squashfs rootfs headers (0x50 bytes long)
  5. squashfs rootfs image (variable size)

The file headers should be used to verify the file integrity and authenticity. Indeed jboot refuses the file if it is not properly formatted.

Currently the “specific file headers” is completely undecoded.

The kernel headers embedded in the “fw update file” is identical to the Kernel Image Header described in the previous section. The only differences is on the first byte: 0xff into the file, 0x04 into the flash.

With reference to the oem fw available from dlink DWR-921_RevC_Firmware3.01b07.bin:

[flash kernel partition]      [fw update file] 
00000000: 04 04 24 2b         00000050: ff 04 24 2b
00000004: 74 77 bd 08         00000054: 74 77 bd 08 
00000008: 3c de 13 00         00000058: 3c de 13 00 

Using the binboy tool found in the GPL Source Code is it possible to generate the “fw update file” accepted by the standard jboot bootloader.

With reference to the lede distribution, the “fw update file” can be generated in this way:

cp <LEDE_DIR>/build_dir/target-mipsel_24kc_musl/linux-ramips_mt7620/dwr-921-kernel.bin .
mv dwr-921-kernel.bin zImage.lzma
cp <LEDE_DIR>/build_dir/target-mipsel_24kc_musl/linux-ramips_mt7620/root.squashfs .
mv root.squashfs squashfs.o
./binboy-static @linux
./binboy-static @rootfs
./binboy-static @mydlink
./binboy-static @all

The File generatedconcatenate the kernel lzma compressed, the rootfs and FIXME

This website uses cookies. By using the website, you agree with storing cookies on your computer. Also you acknowledge that you have read and understand our Privacy Policy. If you do not agree leave the website.More information about cookies
  • Last modified: 2018/06/01 10:41
  • by tmomas