You're welcome. If you decide to proceed in Linux with this, feel free to ping me (message or email); I can help you with the exact commands you need.
For anyone interested, the first 512 bytes (the very first sector) in the image is (using e.g. hexdump -C):
00000000 52 4b 46 50 e3 07 08 1d 0e 2d 0c 00 01 00 30 0f |RKFP.....-....0.|
00000010 00 02 00 00 01 00 00 00 00 d0 00 00 80 00 00 00 |................|
00000020 07 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 |................|
00000030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
:::::::: :: :: :: :: :: :: :: :: :: :: :: :: :: :: :: :: (all zeros)
000001e0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
000001f0 00 00 00 00 00 00 00 00 18 36 b5 c2 ea 96 53 62 |.........6....Sb|
Offset 0x24 (marked red) contains the sector number, least significant byte first (so 01 23 45 67 = 0x67452301), and offset 0x28 (marked blue) contains the size in sectors, least significant byte first.
This is followed by seven 128-byte descriptors in a similar format (and we'll see this again later on, under the resource descriptor); the latter half (last 64 bytes) of each descriptor is zero, so I'll omit those.
00000200 76 65 6e 64 6f 72 00 00 00 00 00 00 00 00 00 00 |vendor..........|
00000210 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000220 01 00 00 00 08 00 00 00 38 00 00 00 00 70 00 00 |........8....p..|
00000230 00 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 |................|
00000280 49 44 42 6c 6f 63 6b 00 00 00 00 00 00 00 00 00 |IDBlock.........|
00000290 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
000002a0 02 00 00 00 40 00 00 00 00 08 00 00 00 b0 07 00 |....@...........|
000002b0 00 00 00 00 00 00 00 00 00 bc 15 00 00 37 8c 07 |.............7..|
00000300 6b 65 72 6e 65 6c 00 00 00 00 00 00 00 00 00 00 |kernel..........|
00000310 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000320 04 00 00 00 00 20 00 00 00 30 00 00 e0 74 4a 00 |..... ...0...tJ.|
00000330 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000380 72 6f 6f 74 66 73 00 00 00 00 00 00 00 00 00 00 |rootfs..........|
00000390 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
000003a0 08 00 00 00 00 50 00 00 00 70 00 00 00 00 a6 00 |.....P...p......|
000003b0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000400 72 65 73 6f 75 72 63 65 00 00 00 00 00 00 00 00 |resource........|
00000410 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000420 20 00 00 00 00 c0 00 00 00 10 00 00 00 40 0a 00 | ............@..|
00000430 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000480 75 73 65 72 00 00 00 00 00 00 00 00 00 00 00 00 |user............|
00000490 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
000004a0 00 00 00 80 00 e0 00 00 00 00 04 00 00 00 00 00 |................|
000004b0 00 00 00 00 05 00 00 00 00 00 00 00 00 00 00 00 |................|
00000500 75 73 65 72 00 00 00 00 00 00 00 00 00 00 00 00 |user............|
00000510 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000520 00 00 00 80 00 00 05 00 ff ff ff ff 00 00 00 00 |................|
00000530 00 00 00 00 05 00 00 00 00 00 00 00 00 00 00 00 |................|
To extract say the kernel part to a separate file, we note the offset sector is 00 20 00 00 = 0x00002000, and the number of sectors is 00 30 00 00 = 0x00003000 (remember, least significant byte is listed first!). Then,
dd if=Firmware.img of=kernel.bin bs=512 skip=$[0x2000] count=$[0x3000]
Similarly for the other descriptors.
To replace it with file kernel.new, we first create a copy of the original image,
cp Firmware.img firmware.new
overwrite the old content with zeroes (just in case the new one is shorter),
dd if=/dev/zero of=firmware.new bs=512 seek=$[0x2000] count=$[0x3000]
noting that this time we use seek instead of skip, because skip= sets input offset, and seek= sets output offset.
Then, assuming the new kernel.new is not too long, we just insert it in:
dd if=kernel.new of=firmware.new bs=512 seek=$[0x2000]
noting that we leave count out, so that the entire file is inserted.
The rootfs is a Squash filesystem. Since we know it starts at offset 0x5000, i.e. at byte $[0x5000*512] = 10485760, and is 0x7000 sectors long, $[0x7000*512] = 14680064 bytes, we can use the Linux loopback device to mount the filesystem directly in the new image, and modify the files however we like:
mkdir squash
dev=$(sudo losetup --find --show firmware.new -o $[0x5000*512] --sizelimit $[0x7000*512]) && echo "Using device $dev"
sudo mount $dev squash
You can now read and write to the squash filesystem under directory squash. Note that the firmware.new file gets modified when you access and modify the contents. You can mount it read-only adding -r flag to losetup (sudo losetup -r --find --show ...) and -o ro to mount (sudo mount -o ro $dev squash), in which case the original file is not modified.
When you are done, just run
sudo umount squash
sudo losetup -d $dev
which also makes sure all modifications (unless mounted read-only) are committed to the firmware.new file.
The resource descriptor refers to 0x1000 sectors starting at sector 0xc000. Sector 0xc000 is all zeros except for an initial 16-byte part,
01800000 52 53 43 45 00 00 00 00 01 01 01 00 0b 00 00 00 |RSCE............|
That 0x0000000b = 11 seems to indicate 11 sectors follow, each with one entry. It looks like each of these 512-byte sectors contain a file name in the first 256 bytes, padded with zeroes, followed by four zero bytes, the sector offset (32-bit little-endian), file length (in bytes, 32-bit little-endian), and rest of the sector zeroes:
01800200 45 4e 54 52 72 6b 2d 6b 65 72 6e 65 6c 2e 64 74 |ENTRrk-kernel.dt|
01800210 62 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |b...............|
01800300 00 00 00 00 0c 00 00 00 e1 77 01 00 00 00 00 00 |.........w......|
01800400 45 4e 54 52 62 61 74 74 65 72 79 5f 31 2e 62 6d |ENTRbattery_1.bm|
01800410 70 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |p...............|
01800500 00 00 00 00 c8 00 00 00 b6 74 00 00 00 00 00 00 |.........t......|
01800600 45 4e 54 52 62 61 74 74 65 72 79 5f 32 2e 62 6d |ENTRbattery_2.bm|
01800610 70 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |p...............|
01800700 00 00 00 00 03 01 00 00 b6 74 00 00 00 00 00 00 |.........t......|
01800800 45 4e 54 52 62 61 74 74 65 72 79 5f 33 2e 62 6d |ENTRbattery_3.bm|
01800810 70 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |p...............|
01800900 00 00 00 00 3e 01 00 00 b6 74 00 00 00 00 00 00 |....>....t......|
01800a00 45 4e 54 52 62 61 74 74 65 72 79 5f 34 2e 62 6d |ENTRbattery_4.bm|
01800a10 70 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |p...............|
01800b00 00 00 00 00 79 01 00 00 b6 74 00 00 00 00 00 00 |....y....t......|
01800c00 45 4e 54 52 62 61 74 74 65 72 79 5f 35 2e 62 6d |ENTRbattery_5.bm|
01800c10 70 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |p...............|
01800d00 00 00 00 00 b4 01 00 00 b6 74 00 00 00 00 00 00 |.........t......|
01800e00 45 4e 54 52 62 61 74 74 65 72 79 5f 66 61 69 6c |ENTRbattery_fail|
01800e10 2e 62 6d 70 00 00 00 00 00 00 00 00 00 00 00 00 |.bmp............|
01800f00 00 00 00 00 ef 01 00 00 b6 74 00 00 00 00 00 00 |.........t......|
01801000 45 4e 54 52 62 61 74 74 65 72 79 5f 6e 75 6c 6c |ENTRbattery_null|
01801010 2e 62 6d 70 00 00 00 00 00 00 00 00 00 00 00 00 |.bmp............|
01801100 00 00 00 00 2a 02 00 00 b6 74 00 00 00 00 00 00 |....*....t......|
01801200 45 4e 54 52 6c 6f 67 6f 2e 62 6d 70 00 00 00 00 |ENTRlogo.bmp....|
01801210 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
01801300 00 00 00 00 65 02 00 00 36 b4 04 00 00 00 00 00 |....e...6.......|
01801400 45 4e 54 52 6c 6f 67 6f 5f 6b 65 72 6e 65 6c 2e |ENTRlogo_kernel.|
01801410 62 6d 70 00 00 00 00 00 00 00 00 00 00 00 00 00 |bmp.............|
01801500 00 00 00 00 c0 04 00 00 d8 4a 00 00 00 00 00 00 |.........J......|
01801600 45 4e 54 52 62 61 74 74 65 72 79 5f 30 2e 62 6d |ENTRbattery_0.bm|
01801610 70 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |p...............|
01801700 00 00 00 00 e6 04 00 00 8a 73 00 00 00 00 00 00 |.........s......|
Note that the red sector number is offset to the starting sector, 0xc000, but the green is the length in bytes. Assuming ENTR is the identifier for the sector and not part of the file name, then we should expect rk-kernel.dtb start at sector 0xc00c and be 0x177e1 bytes long:
dd if=Firmware.img of=rk-kernel.dtb bs=1 skip=$[(0xc000+0x000c)*512] count=$[0x177e1]
and indeed it is. For example, we can also extract the logo_kernel.bmp via
dd if=Firmware.img of=logo_kernel.bmp bs=1 skip=$[(0xc000+0x04c0)*512] count=$[0x4ad8]
which indeed is a 654×258 Windows 3.x format 8-bit bitmap image (Rockchip kernel in white on black background, with yellow stylizing in the dot of the i).
If one wants to modify the images, this format is uncompressed, so a replacement image is exactly the same size. (Note that while the images have a palette of 256 colors out of 16M, you probably want to make sure entry 0 is black.)
To reinsert a modified logo_kernel.bmp to firmware.new, we simply reverse the command (noting skip becomes seek),
dd if=logo_kernel.bmp of=firmware.new bs=1 seek=$[0xc000+0x04c0)*512] count=$[0x4ad8]
We can modify the size and relocate these resource files by modifying that RSCE sector and the corresponding ENTR sectors, but it becomes a bit more complicated. Note that a replacement rk-kernel.dtb can be up to 96256 bytes long (0x17800) before the rest of the resource files need to be bumped to another sector.
Note that this is just my initial efforts in reverse engineering this file format out of pure curiosity, and I suspect there might be checksums in some of the sectors to verify the validity. (This would be done by the Rockchip developers, as such checking would be part of the BIOS/loader, not the Linux userspace code managed by those who cobbled this device together.)
However, the information above is already sufficient to write a C or Python utility to replace given resource files, the kernel image, or the Squash filesystem. I don't have the hardware, so I can't tell whether such modified firmware images would work or not, but looking at the ~ 500 files in the Squash filesystem (comprising of the Linux system running on the device), I can definitely understand why one would like to experiment: it looks like someone took a RockChip development board dev environment, and did the minimal changes necessary, augmented by spittle, bubblegum and hope, to get a shippable product. Don't take my word for it, though; feel free to take a look yourself.