Generating the BMW CIC Navigation FSC

The BMW CIC is the Premium headunit from ~2009 – 2013, and included navigation stored on an internal hard drive. BMW released annual map updates for the CIC until ~2021, however these maps were not free of charge. Any attempt to install the map through the USB glovebox results in a request for a 20-character activation code. Although free key generators are available online, I thought it would be interesting to see if I could make an activation code and create a keygen by reverse engineering the firmware.

Since there are a number of available keygens already, the source code for the key generation routine is available here: https://www.reverseeng.dev/Files/CIC/create_cic_fsc.7z

1. Download the E89 spDaten pack intended for Rheingold updates, and extract 9283426A.0pb from the data\CI63F1 folder. I assumed the “CI” folder set was for the “CIC”, and this file was chosen as the “9283….0pb” files were the largest in the folder, and “…426A” was the highest revision of the “9283…” series.

2. Unpacking the 9283426A.0pb file.

QNX uses IFS files to store firmware. Conveniently, QNX dumpifs source code was available here: https://github.com/askac/dumpifs However, when used “/full/path/to/dumpifs/dumpIfs.sh 9283426A.0pb 9283426A_dump” it only dumped part of the firmware, and did not appear to contain the elf needed for CICHigh.

The 0x00FF7EEB is the magic number signature for the IFS file structure from the dumpifs source code, sys\startup.h. The first and second “imagefs” signatures are shown, where the first “imagefs” is the file/folder structure is linked to the IFS header.

Inspecting the 0pb shows the second “imagefs” file structure later in the file at 0x00580004, which is not dumped by dumpifs. Cutting the file with “dd skip=5767171 if=9283426A.0pb of=9283426A_2nd.bin bs=1M iflag=skip_bytes” and using dumpifs, still did not allow the imagefs to be dumped. However, as the imagefs does not appear to be compressed, simply commenting out the detection of the ifs header in dumpifs.c allows the imagefs to be dumped.

Success, the full structure is dumped, and the “CicHighAsnSecond” appears to hold the navigation elf.

3. Disassemble “CicHighAsnSecond” with Ghidra. For some reason, this seems to take a really long time to fully process.

4. Look for common byte strings used in encryption routines. The first one I came across was the MD5 init seed “0x67452301”, and used it to locate the main Key Routine.

5. The unique vehicle RSA Key is located in /mnt/persistence and a copy of the Navigation key is saved on the hard drive (partition 10 – hbdebug) in the data03 file. Following the address reference (labeled FSC_TYPE_1B_CIC) goes to data “0x01 0x00 0x1B 0x00”.

6. I added function names for the core key routines to better understand the process. When following memory address links, I made an assumption that two of the locations were RSA E and Modulo, based on the size of the data and how it is referenced.

6. Once the functions were labelled, it was not difficult to determine that the overall process to generate a navigation key is:

A. Get the vehicle specifc RSA key from the 1B file.
B. Get the vehicle VIN.
C. RSA Mod Exp : The vehicle specific RSA Key with the hardcoded RSA E and Modulo.
D. First MD5 Hash : MD5 hash of the result from RSA Mod Exp.
E. Second MD5 Hash : MD5 hash of the VIN and the Map Region and Year (Looked online and found that the Region and Year are hex codes from the Lookup.xml file)
F. Third MD5 Hash : A looped combination of the First and Second MD5 Hash.
G. DES : Use the result from the Third MD5 Hash to create a DES Key that encrypts a message containing the Map Region and Year.
H. ASCII Conversion : Convert the binary result from the DES encryption into an 20-character ASCII key.

7. The overall key generation was implemented as pictured

8. Following the third MD5 subroutine shows the MD5 digest being hashed multiple times, and was reimplemented as pictured.