Reverse Engineering the firmware on a Kenwood DDX9903S

I bought and really like my Kenwood Excelon DDX9903S headunit. I had it in my WRX, and moved it to my LS430. It supports Android Auto and CarPlay, which I find really useful when driving.

However, it has a nag screen every time it boots up. This got me curious as to how it worked, and see if it could be patched to skip this disclaimer. I figured it probably ran Linux on a SoC, as pretty much everything does nowadays. So I grabbed the latest firmware for it (mine was already updated to it), and started probing.

S_V2_7_0008_0600_AT1.zip

Extract that and you get 3 folders under S_V2_7_0008_0600/:

BOOT_V2_7_0008_0600_release/
MAIN_V1_0_2758_0400/
SOC_V2_7_0008_0600/

In each there’s a .nfu file, which I’ve never encountered before. I ran binwalk on each:

[BOOT_V2_7_0008_0600_release]$ binwalk Boot_2.7.0008.0600.nfu
DECIMAL HEXADECIMAL DESCRIPTION
--------------------------------------------------------------------------------
248776 0x3CBC8 Android bootimg, kernel size: 0 bytes, kernel addr: 0x4F525245, ramdisk size: 1226848850 bytes, ramdisk addr: 0x6C61766E, product name: "ERROR: Cannot read kernel image"
1571592 0x17FB08 ELF, 64-bit LSB shared object, AMD x86-64, version 1 (SYSV)
2358024 0x23FB08 ELF, 64-bit LSB shared object, AMD x86-64, version 1 (SYSV)
3209992 0x30FB08 ELF, 64-bit LSB shared object, AMD x86-64, version 1 (SYSV)

Surprise, surprise, it runs Android. But, I’m thinking this image is possibly just the firmware updater, and not what I am looking for.

[SOC_V2_7_0008_0600]$ binwalk Soc_V2_7_0008_0600.nfu
DECIMAL HEXADECIMAL DESCRIPTION
--------------------------------------------------------------------------------
5767936 0x580300 Android bootimg, kernel size: 16823168 bytes, kernel addr: 0x80008000, ramdisk size: 0 bytes, ramdisk addr: 0x81000000, product name: ""
5784320 0x584300 Linux kernel ARM boot executable zImage (little-endian)
5800283 0x58815B gzip compressed data, maximum compression, from Unix, last modified: 1970-01-01 00:00:00 (null date)
41943040 0x2800000 Zip archive data, at least v2.0 to extract, compressed size: 14612206, uncompressed size: 14696448, name: 16dnx_2.5s_fbios_bootimg.img
56555332 0x35EF744 Zip archive data, at least v2.0 to extract, compressed size: 16765150, uncompressed size: 16842752, name: TCC893X_recovery.img
73320560 0x45EC870 Zip archive data, at least v2.0 to extract, compressed size: 210950775, uncompressed size: 1825360896, name: automotive-linux-16DDX-image.ext4
284271426 0x10F1A342 Zip archive data, at least v2.0 to extract, compressed size: 87690, uncompressed size: 524288, name: fbios_dual.bin
284359188 0x10F2FA14 Zip archive data, at least v2.0 to extract, compressed size: 168, uncompressed size: 223, name: filelist.txt
284359426 0x10F2FB02 Zip archive data, at least v2.0 to extract, compressed size: 29903609, uncompressed size: 39549952, name: qboot_ddx.bin
314263106 0x12BB4642 Zip archive data, at least v2.0 to extract, compressed size: 33193, uncompressed size: 5242880, name: sbios_dual.bin
314296995 0x12BBCAA3 End of Zip archive, footer length: 22

Here we go. A kernel with a sane size and name string, some recovery images, and what looks like a filesystem image! qboot_ddx.bin must be part of Ubiquitous’ QuickBoot software. It does boot awfully fast, so that explains that. Would be interesting to see full kernel and init output on a stereo headunit. Well, once anyway.

Running binwalk on MAIN_V1_0_2758_0400/MainFw_1.0.2758.0400.mfu didn’t output anything. Not sure what that is.

I tried unzip to extract Soc_V2_7_0008_0600.nfu. Seemed to work, though it complained about a 41MB extra bytes at the beginning. I was really just interested in the filesystem image for the moment:

[SOC_V2_7_0008_0600]$ unzip Soc_V2_7_0008_0600.nfu
Archive: Soc_V2_7_0008_0600.nfu
warning [Soc_V2_7_0008_0600.nfu]: 41943040 extra bytes at beginning or within zipfile
(attempting to process anyway)
inflating: 16dnx_2.5s_fbios_bootimg.img
inflating: TCC893X_recovery.img
inflating: automotive-linux-16DDX-image.ext4
inflating: fbios_dual.bin
inflating: filelist.txt
inflating: qboot_ddx.bin
inflating: sbios_dual.bin

Running binwalk on the .ext4 verifies it is an ext4 filesystem image. I ran binwalk on the others and nothing was notable except the presumed QuickBoot file, qboot_ddx.bin which had images, and what looks like Qt library .qml files for some type of GUI. Also a Pandora image and other images. Hmm…

I decided to mount the ext4 image to take a look.

[SOC_V2_7_0008_0600]$ sudo mount -o loop automotive-linux-16DDX-image.ext4 /mnt/temp
[SOC_V2_7_0008_0600]$ cd /mnt/temp/
[temp]$ ls
bin dev home lost+found Music proc sbin sys temp usr
boot etc IMG_DEC_WORK media nand1 RAMDISK sdcard Syslog Temp var
DB filesave lib mnt opt run share system tmp

Interesting things appear to be in: /opt/jkpf:

bin dbg_daemon_starter.sh etc kill_applications.sh lib rsc script system_init.sh

That appears to be where lots of magic happens. Whenever I’m done disassembling the rest of the car for a particularly annoying remote start installation, I’ll come back to it.

4 thoughts on “Reverse Engineering the firmware on a Kenwood DDX9903S

  1. I know its been a couple of months but I’m also very interested in where you are going with this. I found your post because I started poking around on the firmware on my DNX693s which is very similar…. I’m not a programmer though so I just started hunting for strings to begin with. Then I tried extracting the big one with 7zip but that gave me the opposite. It extracted 42mb and ignored the rest… I ended up with the linux arm kernel config. lol

    On a side note – the DNX693S and if you like the larger screen a couple of other models have Garmin GPS built in. On these models with the Garmin GPS that part is quite easy to get into and mess with. Shoot me an email and I’ll send you info on that end of it. I really would love to get rid of the annoying startup caution. The prior year models did not have that. I think it might be mandated by Apple for their Carplay…

  2. Hello,

    If you develop any decoding processes or scripts, consider adding them to a GitHub repository. I have a theory that a lot of these head units are similar and possibly interchangeable once extracted far enough. Specifically the DDX9903s might be able to run the newer firmware of the DDX9904s. Of course there might be side effects (since the 9904s doesn’t have an HDMI input), but I would imagine if done properly the process could be reverted if the main OS was loadable.

    I was personally investigating this same process myself for my DDX9702S. I wanted to see if I could leverage the firmware of the DDX9704S (with a two year newer firmware). Personally, I want the updated Android App, so some other losses in functionally might be worth it to me.

    Thanks for your post, it saved me some digging.

  3. My file structure looks like this:

    fbios_dual.bin
    filelist.txt
    picdata.bin
    qboot_ddx.bin
    sbios_dual.bin
    automotive-linux-17DDX-image.ext
    TCC893X_recovery.img

    Also take a look at this link!
    Its an open source application to open the automotive-linux-17DDX-image.ext image

    https://www.automotivelinux.org/software/download

    Now I guess I need to install a Linux distort to see what’s different.

  4. @Joe,

    I haven’t looked at it in a while, but I would be sure to post any scripts or progress.

    Two problems remain:
    -Finding the point in the binary where the warning screen is shown
    -Modifying that binary

    I found the Qt QML files where the warning is, with the help of the other commentator. But without a debugger attached it will be hard to determine what part of the binary to modify.

    If I can get access via a JTAG/UART (likely), or run the firmware in a virtual environment (unlikely), I can progress more.

Leave a Reply

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

Time limit is exhausted. Please reload the CAPTCHA.