Pages: [1]
Author Topic: Component Protection Research  (Read 185 times)
dspl1236
Jr. Member
**

Karma: +5/-2
Offline Offline

Posts: 35


« on: Yesterday at 08:48:22 AM »

Audi C7 (4G) Component Protection — full firmware RE of the HVAC + Gateway, a captured ODIS/GeKo session, and the ONE piece I still need
I've been doing Component Protection research on my own C7 for a while and I'm close to an offline solution — but I need community help on the last piece. Full write-up, captured data, firmware analysis, keys and tooling below. Everything is open-source (links at the bottom). This is all on my own car, going back to my ORIGINAL part — pure right-to-repair.

The backstory
2013 Audi A6 C7, 3.0T TFSI (CGWB), VIN WAUGGAFC7DN120188. I swapped my 2-zone Climatronic for a 4-zone unit and used ODIS + GeKo (dealer session, Feb 2024) to clear CP. A week later I swapped in matching heated/cooled seats and ran ODIS again — CP cleared, all good. Now I want to put my ORIGINAL 2-zone HVAC back in, and of course it's CP-locked. My ODIS VM wiped itself between sessions, so I only captured ONE diagnostic protocol (DPROT) file. That file has the handshakes and the resulting key blob — but the GeKo-side derivation is masked. So I went into the firmware to understand the whole thing. Here's what I found.

═══ 1. THE CAPTURED ODIS/GeKo SESSION (Feb 27, 2024) ═══
Code:
Tool:        ODIS-S Patch 23.0.1, VAS 6154A VCI over USB
Dealer:      17483 (importer 219), Tester AGJ1E
Car:         2013 A6 C7, 3.0T TFSI CGWB, built Neckarsulm
Result:      12 modules CP-cleared in one atomic session
The 12 modules cleared together (CP is car-wide, not per-module):
J136 seat memory, J518 Kessy, J255 Climatronic, J519 BCM, J234 airbag, J285 cluster, J525 sound, R radio, J794 MMI, J854 + J855 belt tensioners, J533 gateway.
What ODIS read and sent to GeKo (the token request inputs):
Code:
F190 VIN            WAUGGAFC7DN120188
F17C J518 FAZIT     HLH-W41 / 21.02.13 / 1003 / 1126
F191 J518 HW        4H0907064CR
     J533 FAZIT     LAK-000 / 22.02.13 / 2009 / 7162
+ key-fob transponder challenge-response via J518 TrainICA  (MASKED ****** in log)
The one IKA key blob that logged UNMASKED (J136 seat, DID 0x00BE, 34 bytes):
Code:
E6 2B 41 D1 1C 44 AF 20 21 77 FB 1F 27 4B 0A C2
D1 5B D2 62 E4 FD 27 AB 61 D1 23 C2 F1 5A 2C 93 26 00
(J136 variant SVF6000, FAZIT CU5-SIB 21.03.11 0002 0968)
Every other module's IKA was masked ****** — they went through the masked TrainICA KWP service; J136's went through a direct WriteDataByIdentifier so it logged verbatim.
Gateway constellation write (J533, DID 0x04A3):
Code:
Before:  FD A1 E9 0C FE 62 64 8D 00 00
After:   FD A1 E8 0C FE 62 60 0D 00 00
Procedure flow (reconstructed):
Code:
1. Read J518 FAZIT + HW, read J533 FAZIT
2. GeKo <- VIN + J518_FAZIT + J533_FAZIT + transponder data
3. GeKo -> IKA blob per component   (THIS is the masked secret)
4. KWP modules: TrainICA(blob) -> TrainGVA(blob) -> confirm
5. UDS modules: WriteDataByIdentifier(0x00BE, blob)
6. J533 constellation (0x04A3) updated

═══ 2. HOW CP ACTUALLY WORKS — TWO LAYERS ═══
People conflate these, which is why "just write the IKA" or "just zero the constellation" alone never works.
Layer 1 — Gateway enrollment (J533, 4G0907468AC SW 0037, LEAR, Renesas uPD70F3433 V850)
The gateway keeps the constellation (0x04A3) and each module's IKA. Critically, the gateway does NOT enforce CP — I confirmed this on the live car:
Code:
0x04A3 Constellation:  FD A1 E8 0C FE 62 60 0D 00 00
0x2A26 Present bitmap: FD A1 E8 0C FE 62 60 0D 00 00   <- IDENTICAL
0x0439 Auth-incorrect: 00 00 00 00 00 00 00 00 00 00   <- ALL ZEROS
Constellation == present bitmap, and "auth incorrect" is all zeros even with J255 throwing U1101. So the gateway just tracks an install list; each module self-polices its own CP. Clearing the constellation will NOT fix it.
The gateway's own integrity self-check (firmware RE) turned out to be a fixed-key AES-128 known-answer test over a PUBLIC sentinel — no per-vehicle secret:
Code:
key      = "LEAR D4 Gateway."   (ASCII, 16 bytes, in flash)
sentinel = 01 02 03 04 05 06 07 08 08 07 06 05 04 03 02 01
valid record = AES-ENC(sentinel, key)
             = 6D 08 45 31 99 C6 FF A0 A0 56 FB 72 0C 02 9B 07
So the gateway side is forgeable 100% offline. That layer is solved.
Layer 2 — The per-module credential (the actual lock)
On every self-policing CP module I tore down (HVAC J255 V850, driver seat J136 V850, BCM1 J519), the IKA is verified by a LOCAL symmetric-AES known-answer test:
Code:
pass  <=>  stored_block0  ==  AES-128(challenge, K)
- K is on the module — module-fixed AES-128 keys baked in flash. Seat J136, verified in the binary:
Code:
K5 = 16F45463BB3DB44EEB35DF537F8DFD6B
K6 = C93E58A121F00277912580785E1AD506
K7 = 2D508AB80B42AEF16E2335A70811C67D
(a second AES path keys off the IKA's own block1)
- stored_block0 (the "answer") is per-vehicle, in owner-writable data-flash (seat record @0x03FF9000). On the seat the write path is wide open: UDS 0x3B LID 0xBE -> TrainICA -> stored unconditionally, no SecurityAccess, default session.
- challenge arrives over the bus in the 0x00BE/0x00BD exchange.
No RSA, no ECC, no online check in the verify itself — it's a symmetric KAT. Fail -> DTC (U1101 / 0xEA6x) -> limp (Climatronic drops to defrost-only). The J525 amp is a "dumb endpoint" — stores the IKA, self-reports a flag, no cipher at all.
« Last Edit: Yesterday at 08:50:53 AM by dspl1236 » Logged
dspl1236
Jr. Member
**

Karma: +5/-2
Offline Offline

Posts: 35


« Reply #1 on: Yesterday at 08:49:39 AM »

═══ 3. THE LIVE HVAC (J255) — WHAT ACTUALLY HAPPENS ═══
My installed 2-zone unit runs EV_AirCondiBasisUDS (basic variant). Probing it directly:
Code:
DID 0x00BE (IKA):  NRC 0x31 requestOutOfRange  <- NOT supported on basic variant
DID 0x00BD (GKA):  NRC 0x31                      <- NOT supported
DID 0xF18C serial: 25021300111130                <- works
So the basic 2-zone variant doesn't even implement the IKA DID (the comfort variant does). And the dealer-session writes from before were ACCEPTED but did NOT clear CP:
Code:
J533 VCDS:  Programming Attempts 2, Successful 2  (our two WriteDataByIdentifier writes)
            but U1101 Component Protection Active is UNCHANGED (freq 2, reset counter 183)
So on the HVAC specifically, the writable CP record appears to live in the V850 internal data-flash around offset 0x0400 (~512 bytes) — consistent with independent EEPROM-CP-tool RE (C6-era climate: 93C86, CP region 0x0400 len 0x0200, "clear" = fill 0xFF, pure byte-copy, no crypto). The HVAC is on the Convenience CAN (100kbps, OBD pins 3+11) via VW TP 2.0, not ISO-TP — standard J2534 can't reach it; you need direct comfort-bus access.
Full J533 DID dump (live):
Code:
0x04A3 Constellation     FD A1 E8 0C FE 62 60 0D 00 00
0x2A26 Present bitmap    FD A1 E8 0C FE 62 60 0D 00 00
0x2A2A Allocation (80B)  slot->VCDS-addr map (full decode in the docs)
0x2A2C TP-Idents (160B)  only 8 modules have direct ISO-TP CAN IDs
0x0438 Theft protection  05 81 48 08 22 40 00 0C 00 00
0x0439 Auth incorrect    00 00 00 00 00 00 00 00 00 00
0x043D Successful dnlds   00
0x043E Showroom mode      FF

═══ 4. THE FIRMWARE WALL (why I can't just patch it) ═══
J255 flashware (FL_4G0820043HI_0088_S.frf) decrypts fine (standard VW frf.key recursive-XOR), but both flash blocks are RSA-1024 signed:
Code:
SECURITY-METHOD: SIG_SHA1-RSA1024_S
DB_1 sig: 526cb08946bd...
DB_2 sig: 5d865afc0eef...
The V850 bootloader verifies the signature on flash and rejects modified firmware. No known bootloader bypass for this Continental/Hella V850 (unlike Bosch Simos). So an in-car reflash-patch is out — the offline lever has to be the data-flash CP record (UDS write or V850 chip programmer), NOT a firmware patch.

═══ 5. THE ONE PIECE I'M MISSING ═══
The verify is local and symmetric, the write path exists, the gateway is forgeable. The whole problem reduces to one function:
What is the IKA/Train* derivation GeKo computes — i.e. is challenge = f(VIN, FAZITs, transponder C-R), and is it deterministic?
Static RE says the challenge must be deterministic per-vehicle (the verify compares against a STORED answer, so a fresh server nonce is architecturally impossible). That means ONE captured live pairing handshake (unmasked) is a permanent fix-enabler. In my DPROT the TrainICA/TrainGVA payloads are masked ****** and there's zero SecurityAccess captured — I have the OUTPUT (the J136 blob) and the request INPUTS, but not the middle.

═══ 6. WHERE I NEED HELP ═══
  • Anyone sitting on an UNMASKED TrainICA / TrainGVA capture (full request bytes) from a LEAR-gateway C7/D4? Even one closes it.
  • Anyone who knows the IKA / Train* derivation itself (the GeKo-supplied algorithm/inputs), or has GeKo token request/response pairs?
  • Abrites VN017 does "Climatronic replacement by OBDII" on this exact gateway offline — has anyone bus-sniffed what it sends? That capture answers everything.
  • Anyone dumped a J255 V850 data-flash (basic vs comfort variant) and can confirm the CP record location/format around 0x0400?
  • Confirmation either way: challenge = f(CS) vs server nonce.
═══ 7. EVERYTHING IS DOCUMENTED + OPEN SOURCE ═══
Research docs (mechanism, captured session, firmware RE):
Tooling (GPL-3.0, Python; FRF/SGO decode+repack, CP probe, cipher models, bus tools):

TL;DR — Audi C7 CP is a per-module local AES known-answer test (no server in the verify), the gateway doesn't enforce it and is forgeable, the write path is open, the firmware is RSA-signed so no patch. The only missing piece is the GeKo-side IKA derivation, and it's deterministic — so one unmasked TrainICA capture (or an Abrites VN017 sniff) cracks the whole thing open. Who's got it?
« Last Edit: Yesterday at 08:58:04 AM by dspl1236 » Logged
Pages: [1]
  Print  
 
Jump to:  

Powered by SMF 1.1.21 | SMF © 2015, Simple Machines Page created in 0.008 seconds with 13 queries. (Pretty URLs adds 0s, 0q)