APS Logo APS_TUNING [ ABOUT ] [ BLOG ]
[ VISSZA A LOGOKHOZ ]

Hogyan flasheltem tuned kalibrációt egy BMW DDE6-ra WinKFP-vel? Sehogy. 😂

TIMESTAMP: 2026.05.31 | TARGET: BOSCH DDE626 (DDE6) - BMW | AUTHOR: APS TUNING | v4

Volt egy egyszerűnek tűnő ötletem: fogom a módosított .0da cal-fájlt, feltolom WinKFP-vel, és kész. Hát, nem így lett. Egy kis nyomozás, négy zsákutca, és egy meglepő végkifejlet után most már pontosan tudom, miért nem megy ez WinKFP-vel, és hogy kell megoldani saját flasherrel.

Ez a poszt a sztoriról szól. Ha valaki maga akar flash toolt írni, a végén ott a recept és a logika, amiből össze tudja rakni. Fontos pontosítás: a flash-authhoz továbbra is kell az RSA512-es auth-kulcs, illetve hozzáférési ág; itt nem ezt kerülöm meg. A poén az, hogy a másik, cal-data RSA-aláírási ág érvényes privát kulcsa nem kell, mert nem ezen az úton viszem be az ECU-t.

A felállás

A DDE626 flash 256 KB-os cal-zónája (0xC0000..0xFFFFF) tele van olyan mezőkkel, amik első ránézésre nem árulják el, melyik mit csinál. Van benne pár terminator, egy pointer-tábla, a tényleges cal-adat (mapek, paraméterek), és pár fingerprint-szerű érték a végén. A klasszikus tuner-tudás szerint a recept egyszerű: módosítod a mapeket, újraszámolod a Bosch sum-checksumot (a cal-data BE 32-bit word-jeinek összege egy fix konstansra kell kijöjjön), és kész.

Csak hát ez itt nem volt elég.

A nyomozás

Első tipp: hiányzik egy marker (AF FE 08 15) a 0xC0290 területen. Összehasonlítottam egy .0da fájlt egy ECU-ról mentett kalibrációval, és hiányzott ez a marker. Na de beleírom a fájlba, és minden okés lesz.

AF FE 08 15 marker a 0xC0290 területen

Az AF FE 08 15 marker a 0xC0290 területen, egy ECU-ról mentett kalibrációban.

Beleírtam. WinKFP szépen leflashelte. Az ECU programozási státusza maradt 0x06, ami a Bosch nyelvén nagyjából annyit tesz: "data-sign verify nem ment át". Tehát nem ez volt a kulcs.

WinKFP flash fail

WinKFP flash, a folyamat lefut, de a programozási státusz a verify miatt nem áll normálba.

Második tipp: a cal végén lévő CVN érték (egy fingerprint a 0xFD774-en) eltér a gyáritól, biztos azt ellenőrzi.

Pcap-analízis. Kiderült: a WinKFP magából a fájlból olvassa ezt az értéket, és az ECU futás közben rá se néz. Nem ez a probléma.

Harmadik tipp: van egy iflash mirror a cal-régióról, az nem konzisztens a frissen flashelt területtel.

Tisztázódott: ugyanazon az ECU-n flasheltem vissza, a mirror konzisztens volt. Megint mellé.

Negyedik tipp: van egy 64 byte-os RSA-aláírás a 0xC0100 körül.

Diff a két fájl között: ott mindkettőben csak FF. Ilyen sig nem létezik DDE626-on. A régebbi generációs Ghidra-tudás itt félrevezetett, generációs változás történt.

A felfedezés

Végül a diff a gyári kalibrációk között, azonos szoftvereken, egy konkrét helyen mutatott eltérést: egy 128 byte-os blob a 0xC0314-en. Ez minden egyes cal-on más. És itt jött a meglepetés: sikeres gyári flash után az ECU magától beírta az AFFE0815 markert a 0xC0290-re.

Ez fordította meg az egész képet:

Tehát az első tippem fejjel lefelé volt: én okozatot próbáltam bemásolni ok helyett.

Mi történik az ECU-ban?

A $31 09 04 routine indítja a data-sign verify-t. Nagyvonalakban:

Itt a lényeg, hogy a privát kulcs az ECU-ban nincs benne (helyesen, csak a publikus van), tehát új, érvényes aláírást előállítani a tuned cal-hoz a klasszikus úton nem lehet. Ezért bukik 0x06 státuszban minden tuned cal, amit a fő verify-ágon küldenek be.

Hol él a státusz? A programozási státusz nem a flash-image-ben van, hanem az ECU EEPROM-jában. A 0xC0290-en lévő AFFE0815 tehát nem maga a státusz, hanem az a jelzés, amit az ECU a verify után a flashbe ír; a státuszt, a 0x01-et az ECU a saját EEPROM-jába írja. Ez lesz a lényeg lentebb: a DDE-n az EEPROM-státuszt nem tudom kívülről, OBD-n írni (ellentétben a VGSG-vel), csak rávenni az ECU-t, hogy ő maga írja be.
0x06 programozási státusz

A 0x06 programozási státusz: a data-sign verify nem ment át a fő ágon.

Mit jelentenek pontosan a programozási státuszok?

A BMW NCS Dummyban van egy tábla a 09DDE604.prg fájlhoz, ami megadja az összes lehetséges állapotot. Pár fontos kódolás:

PROGRAMMIERSTATUS tábla a 09DDE604.prg fájlból

A teljes PROGRAMMIERSTATUS tábla a Tool32-ből, kiolvasva a 09DDE604.prg fájlból. Itt látszik a Bosch tervezett állapotgépe a két különálló sign-verify ággal (PAF, DAF) és a köztes hibakezelési állapotokkal.

A két kulcs amivel itt találkozni, a 0x05 PAF és a 0x06 DAF. Ezek a két különálló sign-verify ág kimenete. Ha csak kalibrációs adatot módosítasz, akkor 0x06-on bukik az ECU. Ha kód is módosul, akkor lehet 0x05 is, vagy 0x06, attól függően melyik ág bukik először a verify sequence-ben.

A 0x06 szó szerint azt jelenti, hogy a Datensignaturprüfung nem futott le (nicht durchgeführt), nem azt hogy lefutott és elbukott. (Bár ha lefuttatod a rutint, és elbukik az aláírás ellenőrzés, akkor is ezt a státuszt írja be az EEPROM-ba) Ez a Bosch szövegezésben pontos: az ECU nem tud bizonyítani sikeres verify-t, ezért a marker nem íródik be, ezért a fallback ág is bukik (ha a marker eleve hiányzik), ezért az állapotgép ezen ragad.

Dokumentált megerősítés: a hivatalos SGBD

Eddig ez a kép megfigyelésből állt össze: CAN logolás flashelés közben, diff, Ghidra. De a BMW diagnosztikai leírás, a 10DDE626.prg SGBD (EDIABAS objektum, a stringjei XOR 0xF7-tel kódolva) feketén-fehéren alá is támasztja. Dekódolva a job-definíciók pontosan azt mondják, amit eddig láttam.

A FLASH_SIGNATUR_PRUEFEN job ugyanazt a routine-t hívja, amit a CAN logban, és megmutatja a két ág eredetét is:

10DDE626.prg - FLASH_SIGNATUR_PRUEFEN (dekódolva)
JOBNAME:    FLASH_SIGNATUR_PRUEFEN
JOBCOMMENT: KWP2000: $31 StartRoutineByLocalIdentifier
JOBCOMMENT: $09 CheckSignature
ARG:        BEREICH            ('Programm' | 'Daten')
ARG:        SIGNATURTESTZEIT   (Zeit in Sekunden)
RESULT:     JOB_STATUS         (OKAY, wenn fehlerfrei)

Vagyis a $31 09 CheckSignature egyetlen routine, és a BEREICH argumentum dönti el, hogy a Programm (kód, PAF-ág) vagy a Daten (cal, DAF-ág) aláírását ellenőrzi. A két külön státusz (0x05 PAF / 0x06 DAF), amit a flashelés CAN logjából következtettem ki, itt egyetlen job két bemenetén jön ki, a Bosch kétágú modellje dokumentálva, nem sejtésből.

És a marker hiánya a diagnosztikában is bizonyíték, nem hiányosság: a teljes DDE626 SGBD-ben nulla marker író vagy olvasó job van, és sehol egy AFFE konstans. Nincs olyan diagnosztikai parancs, amivel a 0xC0290 markert kívülről írni lehetne, mert az tisztán belső iflash-mechanizmus, amit az ECU maga ír. Pontosan ezért nem ír rá a WinKFP sem.

Végül a teljes PROGRAMMIERSTATUS tábla, közvetlenül a SGBD STATUS_TEXT táblájából, a gyártói szöveggel, nem parafrazálva:

KódSGBD-szöveg (10DDE626.prg)
0x00Anlieferzustand
0x01Normalbetrieb ★
0x02nicht benutzt
0x03Speicher gelöscht
0x04nicht benutzt
0x05Signaturprüfung PAF nicht durchgeführt
0x06Signaturprüfung DAF nicht durchgeführt
0x07Programmprogrammiersitzung aktiv
0x08Datenprogrammiersitzung aktiv
0x09Hardwarereferenzeintrag fehlerhaft
0x0AProgrammreferenzeintrag fehlerhaft
0x0BReferenzierungsfehler Hardware → Programm
0x0CProgramm nicht vorhanden oder nicht vollständig
0x0DDatenreferenzeintrag fehlerhaft
0x0EReferenzierungsfehler Programm → Daten
0x0FDaten nicht vorhanden oder nicht vollständig
0x10Reserviert für BMW
0x80Reserviert für Zulieferer

A 0x06 sora itt a legbeszédesebb: "Signaturprüfung DAF nicht durchgeführt" , a $31 09 CheckSignature, azaz a verify rutinnem futott le, (vagy lefutott és elbukott).

,

A kiskapu: egy fallback

A nyomozás közben viszont előkerült egy második kódág. Amikor a programozási státuszt kérdezed le, az ECU nem mindig fut bele a teljes RSA-verify-be. Van egy gyorsabb, fallback útvonal:

Ez a kulcs a DDE6-nál: a fallback nem közvetlenül a flashből "olvassa" a státuszt, hanem az ECU-t veszi rá, hogy ő maga írja be az EEPROM-státuszt 0x01-re. A flashbeli marker csak a trigger; a státusz kapcsoló az EEPROM-ban billen át. Ez lesz fontos, amikor lentebb a VGSG-vel és a 6HP-vel összevetem.

Miért nem megy ez WinKFP-vel?

Itt a csavar a WinKFP-ben van. A pcap szerint a gyári flash-folyamat a $34/$36/$37 write-keretekkel soha nem ír a 0xC0290 területre. Akkor sem, ha beleírod a .0da fájlba. Az erase ugyan letörli ezt a területet flash közben, de visszaírni csak az ECU írja vissza, sikeres $31 09 04 után.

Vagyis WinKFP-vel tuned cal esetén:

Ez tiszta separation-of-concerns a Bosch részéről: a tool szállítja a payloadot, az ECU dönt a verify-ról és a marker beírásáról. Logikus, csak épp nem hagy kiskaput a tunernek.

Hogyan oldja meg a saját flasherem?

A teljes flash-területet maga kontrollálja, beleértve a 0xC0290-et. Tehát:

Nincs szükség a cal-data RSA privát kulcsára, és firmware-patchre sem. Az RSA512-es flash-auth ettől még megmarad belépési feltételnek a programozáshoz; a trükk csak az, hogy a másik, fő data-sign verify ág tuned cal-on nem fut le érdemben, és helyette a szándékos service-fallback billenti át az EEPROM-státuszt. Vagyis a DDE6-on közvetve állítom be az EEPROM-státuszt: nem OBD-írással (arra itt nincs mód), hanem úgy, hogy az ECU-t a flashbeli marker + fallback ágon ráveszem, hogy ő maga írja be, szemben a VGSG-vel, ahol a $31 28 EEPROM-write-tal közvetlenül beírom.

A két flow egymás mellett: gyári vs tuned

A legtisztább bizonyíték a két flash-log $31 09 04 finalize lépése. Ugyanaz a tool, ugyanaz az ECU, csak a cal tartalma más. Először a gyári, érvényes aláírású cal (egy visszaolvasott WinKFP-frissítés):

$31 09 04 finalize, gyári cal
[4b] CVN Finalize ($31 $09 $04)...
  $31 $09 $04 OK (5.0s, 2 retries): 71 09 01
    r[2]=0x01, FRESH CVN VERIFY PERFORMED (correct path)
  $31 $09 $04 #2 OK: 71 09 01
    #2 r[2]=0x01 (fresh verify confirmed)

Itt az r[2]=0x01 azt jelenti, hogy a fő RSA-verify ténylegesen lefutott és átment. Ezután az ECU maga írja be az AFFE markert, és a státusz 0x01. Ez a "rendes" út, pont mint WinKFP-nél.

DDE Flasher, gyári cal CVN finalize, r[2]=0x01

A DDE Flasher gyári cal flashelése közben: a CVN finalize 71 09 01, r[2]=0x01, fresh verify lefutott (correct path).

Most ugyanaz a finalize lépés, de tuned cal-lal (a 0xC0290-en már bent van a kézzel beírt marker):

$31 09 04 finalize, tuned cal
[4b] CVN Finalize ($31 $09 $04)...
  $31 $09 $04 OK (5.0s, 2 retries): 71 09 00
    r[2]=0x00, ECU already in app mode, NO fresh verify ran
    Boot-time sig check may reject the flash.
  $31 $09 $04 #2 OK: 71 09 00

A tool itt figyelmeztet, hogy nem futott fresh verify, és hogy a boot-time sig check elvileg elutasíthatná a flasht. De a reset utáni identify-ban:

DDE Flasher, tuned cal CVN finalize, r[2]=0x00

Ugyanaz a tool tuned cal-lal: a CVN finalize 71 09 00, r[2]=0x00, a piros keret a "NO fresh verify ran" figyelmeztetést emeli ki. A flash mégis sikeres, és az ECU 0x01-be áll a fallback-ág miatt.

Reset utáni identify, tuned cal
[IDENTIFY] $31 0A OK, Status: 0x01 Normal operation

A státusz 0x01, normál működés, annak ellenére, hogy a fő verify nem futott le (r[2]=0x00). Ez a fallback memcmp-ág a gyakorlatban: az ECU nem talált friss aláírást, viszont a 0xC0290-en megvan az AFFE marker, és ennyi elég neki. Pontosan ezt az ágat írtuk le fentebb, csak most élő logon is látszik.

A lényeg dióhéjban: gyári cal-on r[2]=0x01 (fresh verify lefut, átmegy), tuned cal-on r[2]=0x00 (fresh verify nem fut), de a végeredmény mindkét esetben 0x01 Normal operation, mert a marker megléte a fallback-ágon elég.

A kód-oldali sztori ugyanaz

A sztori nem áll meg a .0da-nál. Az ext-flash-ben négy AFFE0815 marker-blokk van, két RSA-1024 aláírással, a másik két blokk pedig benne van a 0pa fájlban is, így az nem releváns.

Ugyanaz az architektúra: 64 byte marker (AF FE 08 15 plusz 60 byte zero), majd a tábla folytatása, majd a típuscímke (00 00 00 20), majd a 128 byte RSA-1024 aláírás. Két különálló védelmi ág, ugyanazzal a Bosch receptúrával.

A WinKFP a .0pa (Programm-Anwendung) fájlt is ugyanúgy kezeli mint a .0da-t. A $34/$36/$37 write-keretek soha nem írnak a 0x010290 területre sem. Ha módosítod a kódot, a Programm-sign-verify ugyanúgy elbukik mint a Daten-sign-verify, és az ECU 0x06 (vagy 0x05) státuszba ragad. Ugyanaz a fallback ág van itt is, csak más címen.

Ha csak a cal-t módosítod (kód érintetlen), a kód-AFFE-t a gyári dump-ból úgyis tudod átemelni, egy bytewise copy a működő ECU 0x010290 területéről. Az ECU magától nem írja vissza ezt a területet flash közben (a separation-of-concerns ott is érvényes), de a fájlban benne kell legyen.

Variációk a témára, a 6HP TCU

Mellékág, ami közben felbukkant: a ZF 6HP TCU .0da fájlokban is megtaláltam ugyanezt a mintázatot. Egy RSA-1024-es aláírási blokk, utána egy second-tier marker-mező, közvetlenül az aláírás után. Első ránézésre kézenfekvő volt a következtetés: ugyanaz, mint a DDE6, csak más címen.

Egy különbség rögtön szembeötlött: a 6HP-nél a Bosch fordított konvenciót használ. A .0da fájl üres területeit nem FF-fel tölti, hanem 0x00-val, beleértve a marker-mezőt is. Ami DDE6-on FF FF plusz az AFFE0815 marker, az 6HP-n fordított byte-mintaként jelenik meg. Egy 0x01-státuszú TCU-ból kiolvasott érték és a .0da csere-fájlbeli érték is épp fordítva viszonyul egymáshoz, mint a DDE6-on.

6HP TCU RSA-1024 aláírás és marker-mező

Egy 6HP TCU flash-fájl hexdumpja, a 128 byte RSA-1024 aláírás után közvetlenül a marker-mezőnek gondolt rész.

Csakhogy időközben visszafejtettem a Siemens VDO alapú xDrive transfer-case modult (a fentebb már emlegetett VGSG-t), és ott állt össze a teljes kép. A VGSG-nél a programozási státusz ugyanúgy a modul EEPROM-jában él, mint a DDE6-nál, de ott van rá közvetlen OBD-út egy diagnosztikai EEPROM-write szolgáltatással a 0x01 Normalbetrieb-et közvetlenül, kívülről beírható az EEPROM-ba. Nincs flash-fájlbeli marker.

Ez is bizonyítja: ott is az EEPROM-státusz a valódi kapcsoló, csak nincs hozzá OBD-írási út. A DDE626 SGBD-jében nincs olyan job, amivel az EEPROM-státuszt kívülről billenteni lehetne. Ezért kell a DDE6-nál a kerülőút: a flashbeli AFFE0815 markerrel + a fallback memcmp-ággal az ECU-t veszem rá, hogy ő maga írja be a 0x01-et az EEPROM-jába. A cél mindkét modulnál ugyanaz (EEPROM-státusz 0x01), csak a DDE6-on közvetve, a VGSG-n közvetlenül érem el.

Ez a 6HP-re vonatkozó hipotézisemet is a helyére teszi.Szinte biztos, hogy a 6HP is EEPROM-státuszú, mint a másik kettő, és az összes BMW modul, a fájlban talált aláírás-blokk és marker-mező inkább a struktúra maradványa, a tényleges kapcsoló a TCU EEPROM-jában lévő programozási státusz. A nyitott kérdés ott már csak az, hogy melyik írási úton lehet a 0x01-et beállítani: közvetlen OBD EEPROM-write-tal (mint a VGSG), vagy az ECU-t rávéve (mint a DDE6).

Fontos, hogy ez a 6HP-nél egyelőre hipotézis: a fájlstruktúra megvan, az xDrive-analógia erős, de éles 6HP-flasht ezen az úton még nem futtattam, és a pontos EEPROM-mechanizmust szándékosan nem részletezem itt. Architektúrálisan viszont letisztult a kép: mindhárom modulnál az EEPROM-ban él a programozási státusz ugyanaz a Bosch/ZF/Siemens állapotgép-gondolat. A különbség nem "flash-image vs EEPROM", hanem hogy hogyan jut be a 0x01 az EEPROM-ba: a VGSG-n közvetlen OBD-írással, a DDE6-on az ECU-t rávéve (marker + fallback), a 6HP pedig egyelőre nyitott, de az egyik útra fog illeszkedni.

A recept (ha magad akarsz toolt írni)

Egy gyári, működő cal-dumpból kiindulva így állítható elő egy 0x01-státuszú, tuned flash:

A cal-aláírás privát kulcsa sehol nem kell. Az RSA512-es auth-kulcs, illetve hozzáférés viszont kell a flashelési session megnyitásához, csak a második RSA, vagyis a cal-data signature privát kulcsa nem szükséges. A "védelem" itt a tuned oldalon nem új aláírás gyártásával dől el, hanem azon, hogy tudni kell, melyik ellenőrzési ágon megy be az ECU.

A "ne fuss bele, mint én" rész

Pár buktató, amibe én belefutottam, hogy te ne kelljen:

< VISSZA A LOGOKHOZ