Engine Control Units

A sizable reverse-engineering community works on engine ECUs, pushed along by the aftermarket tuning scene and by curiosity about the trust chains that protect factory firmware. In public research, no ECU is documented as thoroughly as the Simos 18 and its Infineon TriCore TC1791.

Simos 18

Simos 18 SBOOT

Bri3d (Brian Ledbetter), GitHub 2020+ [1]

The Simos 18 ECU runs on the Infineon TC1791S. Flash sits inside the processor, guarded by passwords burned into a One Time Programmed (OTP) region at the factory. There is no way to read it directly through hardware, so an attacker needs an exploit.

The supplier bootloader (SBOOT) lives in the lowest 0x14000 bytes of program flash. At startup it reads the CBOOT validity flags, and when a verified CBOOT update is waiting it promotes it. SBOOT also hides a recovery shell. To reach it you apply two phase-shifted 3.2 kHz PWM signals to two harness pins at boot; the TriCore GPTA peripheral measures the phase offset, and if it matches, a command shell opens over ISO-TP on CAN.

The shell is gated by a seed/key exchange. The ECU produces 256 bytes from a Mersenne Twister PRNG, encrypts them under an RSA public key, and returns the ciphertext; recovering the seed is meant to require the matching RSA private key. The weakness is in the seeding. The PRNG draws only on the system timer, which caps the seed space at 2^31. With tight CAN timing, a tester can predict the timer value and brute-force that window in seconds on a laptop.

Past that gate sits a second flaw. The pre-signature CRC validator accepts an address header whose bounds are barely checked, and with no start-address check the checksum can be pointed at the OTP region. CRC32 is reversible, so four bytes at a time can be back-calculated from the checksum. Iterating across the password area, with a CPU reset between steps, recovers the flash-access passwords.

Two 3.2 kHz PWM signals a quarter-period out of phase, the input that unlocks the Simos 18 SBOOT recovery shell. Figure from Brian Ledbetter (bri3d), 2020 (Simos18_SBOOT).Two 3.2 kHz PWM signals a quarter-period out of phase, the input that unlocks the Simos 18 SBOOT recovery shell. Figure from Brian Ledbetter (bri3d), 2020 (Simos18_SBOOT).

Simos 18 CBOOT and VW_Flash

Bri3d (Brian Ledbetter), GitHub 2020+ [2]

CBOOT is VW's standard firmware update interface. It runs the UDS flashing sequence covered in the ECU Flashing chapter: extended session, SA2 seed/key, erase, block download with Encryption A (AES-128-CBC) and Compression A (LZSS), then RSA signature verification. Each block's OK flag sits immediately after the block in flash, outside the erased range.

The bug is a state-machine oversight. CBOOT insists on an Erase before a Download, but it never checks that the block you download is the block you erased. So a tester erases block N and downloads into block M. The TriCore flash controller writes straight to program flash as chunks arrive, so the data lands in M while M's OK flag stays untouched. The following CRC and RSA check fails, yet on the next boot CBOOT still treats M as valid. That gives arbitrary code execution in a block the trust chain believes is signed.

Writing into non-erased TriCore flash comes with limits. Bits can only flip from zero to one, and the ECC codes obey the same rule. The workable approach is to find runs of 0x00 bytes (NOP on TriCore) and drop a jump plus a small payload into that space, keeping the ECC consistent.

bri3d packaged both exploit chains into VW_Flash, an open-source Python toolkit. It automates the full flashing pipeline for Simos 18 and several other VW Group ECUs, and it takes care of SA2 key computation, FRF/ODX parsing, Encryption A, Compression A, and the UDS transfer sequence.

References