CAN-Hacking

  • Ich möchte in diesem Thread meine Erkenntnisse und Erfahrungen bezüglich der Analyse von CAN-Bus Daten teilen und hoffe natürlich auch auf Ideen und Vorschläge von Euch! search


    Im Internet findet man unzählige Infos, Tools, viel kommerzielles und wirklich teures Zeug, aber auch einiges brauchbares. Für einfache Analysen braucht man eigentlich erstmal nur einen CAN-Adapter, Notepad++, Excel/Calc und viel Geduld.
    Über CAN-Adapter, dem CAN-Protokoll und den CAN-IDs ist an anderer Stelle genug beschrieben, hier möchte ich nur die Auswertung der Daten besprechen.


    Die Firmware des CAN-Adapters und natürlich auch die Software die diese Daten abspeichern kann, bestimmen das Log-Format. Hier mal die mit denen ich häufig arbeite:


    1.) Das ELM-Adapter CAN-Log (Dateiendung ".log")


    Hier ein Beispiel eines HS-CAN Trace:


    Vom Header abgesehen besteht jede Zeile aus einer Nachricht in folgendem Format (EBNF-Schreibweise):
    MESSAGE = HH ':' MM ':' SS '.' UUU ' ' CAN_ID [ ' ' DB0 ' ' DB1 ' ' DB2 ' ' DB3 ' ' DB4 ' ' DB5 ' ' DB6 ' ' DB7 ] ' ' CRLF ;

    • Beim Zeitstempel wird die Echtzeit, welche vom Computer stammt der das Log aufzeichnet, verwendet. Die letzten drei Ziffern sind die Millisekunden. Das schellste CAN-Intervall das ich bislang im Mondeo gefunden habe, lag bei 10 ms, also 100 Nachrichten pro Sekunde.
    • Die CAN_ID ist ebenfalls in hexadezimaler Schreibweise enthalten
    • Der Nachricht können per Protokoll 0 bis 8 Datenbytes anhängen (0 Bytes bei Remote-Frames, welche ich im Mondeo aber bislang noch nicht entdeckt habe), wobei das erste empfangene Datenbyte links als "DB0" bezeichnet wird und das achte als "DB7". Jedes Datenbyte wird in hexadezimaler Schreibweise mit zwei Zeichen repäsentiert.
    • Eine Angabe der Datenbytes pro Zeile (das "DLC" Attribut) fehlt bei diesem Format. Ist aber durch die Anzahl der nachfolgenden Datenbytes impliziert.
    • Am Ende jeder Zeile befindet sich ein zusätzliches Leerzeichen und eine PC-Kompatible Zeilenschaltung CRLF (CR=0x0D, LF = 0x0A).
    • Die Anzahl der Zeilen pro Logfile ist scheinbar unbegrenzt.


    2.) LAWICEL CAN-Log


    Hier, ebenfalls vom HS-CAN, ein Beispiel für ein Logfile im LAWICEL Format (weit verbreitet):


    Code
    1. Time ID DLC Data Comment
    2. 17,718 2ED 7 00 24 87 04 B1 B4 00
    3. 17,724 581 8 00 00 FF FF FF FF FF FF
    4. 17,728 128 8 0C 00 00 00 F0 00 87 FF
    5. 17,729 2A8 8 00 45 92 01 F4 D6 5F 00
    6. 17,734 160 8 00 01 80 27 99 44 00 C0
    7. 17,734 284 8 F1 4F 80 0B 91 80 00 00
    8. 17,734 4A3 8 30 72 10 00 00 49 00 00
    9. ...


    MESSAGE = SS ',' UUU ' ' CAN_ID ' ' DLC ' ' (DB0|' ') ' ' DB1|' ') ' ' (DB2|' ') ' ' (DB3|' ') ' ' (DB4|' ') ' ' (DB5|' ') ' ' (DB6|' ') ' ' (DB7|' ') ' ' [ COMMENT ] CRLF ;

    • Auffällig im Vergleich zum ELM-Log ist der Timecode. Hier sind nur die relativen Sekunden und Millisekunden (letztere durch Komma getrennt!) seit Aufzeichnungsstart und nicht die Echtzeit enthält. Die Firmware der LAWICEL Adapter senden nur Millisekunden pro Nachricht im Bereich 0-59.999. Danach wird wieder bei 0 begonnen. Will man also Aufzeichnungen länger als 60 Sekunden betrachten, muss man die fehlende Zeitbasis per Software hinzurechnen.
    • Im DLC ("Data-Length-Code") ist zusätzlich die Anzahl der Datenbytes (0-8) der Nachricht enthalten. Zwischen CAN_ID und DLC befinden sich 6 Leerzeichen.
    • Ebenfalls verwendet dieses Format PC-Returnzeichen (0x0D, 0x0A) und ein zusätzliches Leerzeichen davor.
    • Besonders ist hierbei noch zu erwähnen, das für jedes nicht vorhandene Datenbyte zwei Leerzeichen vorhanden sind.
    • Pro Zeile kann ein im Programm erfasster Kommentarstring enthalten sein. Eine Längenbegrenzung ist mir bislang nicht bekannt. Der Kommentar darf alle Zeichen, außer dem Newline enthalten.


    3.) Erweitertes LAWICEL CAN-Log


    Dieses entspricht im großen und ganzen dem obigen Format, mit dem Zusatz, das hinter den Datenbytes in Hex zusätzlich eine Darstellung als ASCII-Zeichen folgt. Nicht darstellbare ASCII-Zeichen werden durch einen Punkt "." repräsentiert:


    Code
    1. 33,126 23C 8 5F 80 47 80 57 00 00 00 |_.G.W...|
    2. 33,126 24E 8 01 00 00 00 50 00 57 FF |....P.W.|
    3. 33,127 260 8 7F 60 32 38 30 32 35 35 |.`280255|
    4. 33,127 296 8 1A CE 00 55 DD F3 00 00 |...U....|


    In seltenen Fällen kann man hierüber sowas wie Fahrgestellnummer, Kennungen von Radiosendern erkennen.



    4.) CANcool Logformat


    Code
    1. Timestamp;Frame;ID;DLC;D0;D1;D2;D3;D4;D5;D6;D7;
    2. 0;STD;581;8;00;00;FF;FF;FF;FF;FF;FF;
    3. 2;STD;511;8;11;01;00;00;00;00;00;00;
    4. 4;STD;35;8;00;02;00;00;00;00;00;00;
    5. ...
    6. 383402;STD;28;8;00;81;10;00;48;FF;FF;FF;
    7. 383404;STD;30;8;04;00;00;00;01;01;00;00;
    8. 383405;STD;50;8;40;27;2A;47;00;00;50;AC;


    MESSAGE = TIMESTAMP ';' FRAMETYPE ';' CAN_ID ';' DLC ';' D0 ';' D1 ';' D2 ';' D3 ';' D4 ';' D5 ';' D6 ';' D7 ';'

    • Es gibt eine Headerzeile
    • Die einzelnen Felder sind mit Semikolon ";" getrennt
    • Eine CAN-Nachricht pro Zeile. Die Zeile endet mit einem ";" und CRLF
    • Der TIMESTAMP ist die Integere Zahl der Millisekunden, von 0 beginnend aufsteigend, also immer relativ zum Aufzeichnungsstart.
    • Der FRAMETYPE ist "STD" für Standard-Frames (11 Bit Arbitration ID), "EXT" für Erweiterte-Frames (29 Bit) und "RTR" für Remoteframes
  • Als erstes interessiert mich immer eine Übersicht der in einem Log und damit einem CAN-Bus vorkommenden CAN-IDs, deren Intervall und Anzahl. Letzteres wird natürlich durch die Dauer der Aufzeichnung beeinflusst. Heraus kommt dann z.B. sowas hier:



    IDs die nur einmal oder wenige Male vorkommen sind besonders interessant, denn hier passiert was ausgewöhnliches. Im obigen Beispiel ist das die ID 736 und 73E, welche einen Restart des PAM-Moduls auslösen.
    Die Intervalle muss man etwas "runden" und sind der Übertragungsverzögerung geschuldet unscharf. Z.B. ist das Intervall "995 ms" als "1000 ms" zu sehen und "96 ms" als "253 ms" als "250 ms".

  • Wer sich schonmal die Datenbytes der CAN-Nachrichten angeschaut hat, wird wissen das hier ohne weiteres nicht erkennbar ist, wozu diese dienen. Hinzu kommt das manche IDs gemultiplexed werden, d.H. das die Bedeutung der Datenbytes von einem bestimmten Index-Datenbyte abhängig sind. Das werden wir später ermitteln, nur soviel sei verraten: Man erkennt Multiplex-IDs daran, das ein bestimmtes Datenbyte (meist DB0) hochzählt, also seinen Wert pro Nachricht um eins verändert und bei einer bestimmten Größe wieder bei einem Startwert beginnt. Grafisch sieht das dann aus wie eine Rampe (Sägezahn).


    Um einfache Schaltsignale zu finden sieht man sich eine ID nach der anderen an und vergleicht deren Datenbytes. Schaltsignale sind praktisch immer einzelne Bits eines Bytes, d.h. das Byte ändert sich nur zwischen zwei Werten hin und her. Hierzu macht man zunächst einen mit einer kontrollierbaren Anzahl von hin und herschaltungen, z.B. 5 mal Rückwärtsgang einlegen und wieder raus. Hintereinander, mit möglichst gleichem Zeitabstand. Die Dauer des Logs notiert man sich. Danach macht man wieder eines in gleicher Länge, jedoch ganz ohne Betätigung.


    Nun muss man den "Ruhe-Log" mit dem "Aktivitäts-Log" vergleichen. Eine Methode hierfür ist, aus beiden Logs die gleichen Datenbytes einer jeden ID zu entfernen. Übrig bleiben die Differenzen. Diese versucht man dann über die Anzahl der durchgeführten Statusänderungen zuzuordnen. Im Beispiel von oben würde ich also nach einer ID suchen, deren Wert sich gegenüber dem Ruhezustand ca. 5 mal ändert.


    Habe ich einen "Verdächtigen" gefunden, extrahiere ich nur diese ID aus dem Aktivitäts-Log und lasse mir die Zeitpunkte der Änderung darstellen. Kommt das Intervall hin, kann ich abschließend am Fahrzeug noch die Gegenprobe machen. Hierzu lasse ich mir Live, z.B. per "CANhacker" oder "CANcool" die Werte der gefundenen ID anzeigen. Aus dem Log weiss ich in welchem Byte welche Werte zu erwarten sind. Dann führe ich die Aktion erneut aus und erwarte eine prompte Wertänderung. Kann ich dies mehrfach reproduzieren habe ich die ID und die Statuswerte des Signals gefunden. Hierbei gehe ich nie auf den Wert als ganzes, sondern schaue mir die Werte in binärer Form an. Letztlich finde ich dann das einzelne Bit welches dem Signaleingang entspricht.


    Diese Methode lässt sich auch allein durch beobachtung der Live-Daten mit CANHacker machen ( "Value-Change-Scan" Methode). Für komplexere Daten und Zusammenhänge ist die Methode jedoch nicht nutzbar. Hier ist die beschriebene Analysemethode anzuwenden.

  • Als praktisches Beispiel mal die Auswertung eines 12 Sekunden langen MS-CAN Log, mit Zündung und ausgeschaltetem Radio, und 3maligem einlegen des Rückwärtsganges gemacht. Sowie über dieselbe Zeit ohne jegliche Betätigung, also "Idle". Beide Traces mit meinem Tool ausgewertet und in einem Spreadsheet gegenüber gestellt. Heraus kam dies:



    • Im Header gebe ich zunächst die Gesamtdauer der Aufzeichnung aus, in Millisekunden (Hinweis: Der "." entspricht dem deutschen ",")
    • ID: In der ersten Spalte einer jeden Zeile gebe ich zunächst die CAN-ID aus. Die Liste is nach IDs aufsteigend sortiert. IDs werden 3-stellig hexadezimal angegeben.
    • COUNT: Danach kommt die Anzahl der im Logfile gefundenen Nachrichten dieser ID. In der Praxis sind die meisten IDs gleichmäßig über das ganze Logfile verteilt. Die Länge der Aufzeichnung, geteilt durch die Anzahl der Nachrichten einer ID ist dann gleich der durchschnittlichen Wiederholzeit (AVG). Bei Abweichungen signalisiert das, sporadisch vorkommende IDs.
    • MIN/MAX/AVG: Die drei nachfolgenden Zeitwerte zeigen die kürzeste, längste und durchschnittliche Wiederholrate der Nachricht an. Hieran erkennt man ob es ein regelmässiges Signal ist, oder ob es nur zu bestimmten Ereignissen anliegt. Dann nämlich würden MIN und MAX erheblich voneinander und vom AVG (Durchschnitt) abweichen.
    • DCHG: Die Data-Change Spalte zeigt die Anzahl der verschiedenen Datensätze (DB0 - DB7) an. Ändern sich die Daten einer CAN-Nachricht während der gesamten Aufzeichnung nicht, steht hier ein "-". Ändert sich auch nur ein Bit der Datenbytes eines Datensatzes, wird der DCHG-Zähler um 1 erhöht. Enthält die Aufzeichnung die ID mit wieder einem anderen Datenmuster, wird wieder um 1 erhöht, usw. Wird z.B. über eine gemultiplexte ID die Fahrgestellnummer übertragen, dann werden hierfür 3 verschiedene Datensätze benötigt. Enthält die ID nichts anderes, wäre der DCHG-Zähler also 3.
      Die Zahl ansich verrät noch nicht so viel, aber die sich nicht ändernden Werte können oft ausgeschlossen werden, vor allem wenn man während der Aufzeichnung eine Änderung erwarten würde (Z.B. Rückwärtsgang einlegen). Damit fällt dann schon einiges an Datenmüll weg und man kann sich die verbleibenden näher ansehen.
    • DIFF: Hier zeige ich an, wieviele Muster mehr (+ Vorzeichen) oder weniger (- Vorzeichen) im Logfile mit Rückwärtsgang enthalten sind. Auch hier kann man alle IDs, welche ihren Wert in beiden Logs nicht ändern, einfach ignorieren.

    Reduziert man die obige Liste rein auf die Änderungen verbleiben dann nur noch eine Handvoll IDs:



    Hierin kann jetzt unser R-Signal stecken. Aber natürlich auch noch andere, damit verbundene Signale, wie Beispielsweise die Entfernungsmeldungen der PDC-Sensoren, welche sich beim Rückwärtsgang einlegen ja mit aktivieren. Es können aber auch zufällige andere CAN-Ereignisse enthalten sein, die zu dieser Zeit stattfanden.


    Das einlegen des Rückwärtsganges wird jedesmal dieselbe Werteänderung in den Bytes der ID zur Folge haben. Das heißt, das das Bytemuster zwischen "Nicht eingelegt" und "Eingelegt" wechselt, also in DCHG mind. eine "+1" stehen muss. Damit scheiden automatisch alle Zeilen aus, die im DCHG ein negatives Vorzeichen haben. Es verbleiben somit:


    Um jetzt weiter zu reduzieren muss man sich den Änderungsverlauf der Daten dieser IDs ansehen. Das geht dann ID für ID. Und auch hier interessieren wir uns nur für die Bytes deren Wert sich ändert.
    Mit Hilfe eines weiteren Tools filtere ich dann jeweils eine CAN-ID aus dem Datenstrom heraus und lasse mir über die Zeitachse des Log nur die Bytes ausgeben, die ihren Wert ändern.

  • Hier nun die zuvor erwähnte Auswertung der Daten pro ID. Ich habe mir dazu ein Auswertungstool geschrieben, welches ein Logfile nach einer bestimmten ID filtert. Dann ermittelt es aus den Bytewerten pro Nachricht eine Liste der vorkommenden Werte pro Byte. Damit erhält man die Anzahl der Änderungen pro Byte dieser ID und zugleich den kleinsten, größten und überhaupt alle vorkommenden Werte eines jeden Bytes.
    Ändert sich ein Bytewert über die gesamte Zeit nicht, halte ich ihn für diesen Test für uninteressant (statisch) und stelle "--" anstatt des Wertes dar. So erkenne ich sofort welche Bytewerte sich ändern und welche nicht.


    Als Beispiel die ersten 5 Zeilen der Idle-Auswertung der ID 050:

    Code
    1. 050 C0 -- -- -- -- -- -- --
    2. 050 40 -- -- -- -- -- -- --
    3. 050 C0 -- -- -- -- -- -- --
    4. 050 C0 -- -- -- -- -- -- --
    5. 050 40 -- -- -- -- -- -- --
    6. ...


    Nun dieselbe ID während der Betätigung:


    Gut zu erkennen das sich während der Aufzeichnung im Idle-Modus nichts ändert (wohlgemerkt "--" heißt nicht 00 sondern das der Wert über die gesamte Zeit gleich bleibt).
    Das erste Byte (DB0) wechselt immer zwischen 0xC0 und 0x40 hin und her.
    Im betätigten Zustand kommt dann auch noch das letzte Byte (DB7) dazu, welche über viele Nachrichten einen gleichbleibenden Wert hat, diesen aber auch zwischen 0xAC und 0xBC wechselt.


    Binär gesehen ist das:
    0xC0 = 0b1100 0000
    0x40 = 0b0100 0000


    0xAC = 0b1010 1100
    0xBC = 0b1011 1100


    In beiden Fällen ändert sich also immer nur 1 Bit in diesem Byte. Sehr interessant, auch wenn ich noch keine Idee hab was das sein könnte. In DB0 kann der Rückwärtsgang nicht kodiert sein, weil das signal auch im Ruhezustand hin und her wechselt, außerdem viel zu schnell (alle 60ms!).
    Beim letzten Byte (DB7) sieht das schon anders aus. Hier gibt es über die Zeit genau 3 längere Phasen während der der Wert 0xBC anliegt. Dabei ist im Vergleich zum anderen Wert (0xAC) das Bit 4 gesetzt. Bits zählt man immer von rechts nach links, beginnend mit 0. Mal kurz nachrechnen: pro 0xBC-Phase kommt das Signal ca. 35mal. 35x0,06 Sekunden = 2,1 Sekunden. Das kommt hin! Rein optisch und von den Werten würde ich behaupten das R-Signal gefunden zu haben.


    Dennoch sollte man alle Werte durchgehen. Nicht selten sind Signal mehr als einmal kodiert. Hier könnte man dann noch etwas vom experimentellen Wissen profitieren. Z.B. habe ich den MS-CAN Bus meines Labor-BCM gescannt. Zu diesem Zeitpunkt gab es keine anderen Teilnehmer an dem Bus, außer dem BCM. Damit ist klar, das alle gescannten IDs nur vom BCM stammen können. Nun weiß ich aus den Schaltplänen und Aufstellungen der Sensoren, das der Schalter vom Rückwärtsgang am BCM angeschlossen ist.


    Folgende IDs der obigen Ausschlußliste stammen vom BCM:

    • 050
    • 120
    • 220
    • 405
    • 433
    • 501

    Die anderen kenne ich zufällig auch schon fast alle:

    • 131 ist das PAM (Einparkmodul)
    • 503 ist das EATC (Klimamodul)
    • 508 kenne ich noch nicht.

    In den zuletzt genannten IDs kann der gesuchte Wert also nicht drinstecken, da die Nachrichten davon von anderen Modulen erzeugt werden. Ich muss als nur die oberen analysieren. Wer sich die Mühe macht und die Dateien mit und ohne Rückwärtsgang mal in einem Notepad++ oder so gegenüberstellt, findet schnell interessante Signale. Dabei sollte man auch erkennen, das der Rückwärtsgang nochmals in der ID 433 kodiert ist. Beachten muss man hier aber das das Signal 433 mit 100ms wiederholt wird, über dieselbe Zeitdauer also nur halbsoviel Einträge sendet wie die 050. Aber der Zusammenhang ist ganz klar erkennbar.


    Alle Ergebnisse habe ich als Datei angehangen, einmal im "Ruhezustand" ("...-idle.txt") und einmal mit 3mal betätigtem Rückwärtsgang ("...-rev.txt").



    Als letztes bliebe dann noch die Gegenprobe, live am Fahrzeug. Hierzu schaltet man nicht den Logger, sondern den Live-Monitor an. Für den ELM-Adapter ist mir hier noch keine Software bekannt, weder CANHacker noch CANcool unterstützen den Chipsatz direkt. Hier benötigt man also einen "richtigen" CAN-Adapter. Zum experimentieren reicht aber auch der "Sniffer-Mode" vom ELMConfig. Dabei empfiehlt es sich den Filter auf die zu untersuchende ID zu stellen:



    Dann sieht man rechts im Live-Log nur diese ID vorbeirauschen. Über die "Mask" könnte man sogar noch das einzelne Bit ausmaskieren, welches man sehen will.
    Nun startet man den Log und macht die Zündung an. Man sollte dann den "Ruhewert" (0xAC) in DB0 lesen. Legt man den Rückwärtsgang ein, sollte der "Arbeitswert" (0xBC) erkennen, solange der Gang drin ist und umgekehrt.
    Das wäre dann der Beweis!


    SO in dieser Art habe ich es mit allen IDs gemacht die ich bislang finden konnte. Das ist schon eine Sau-Arbeit, macht aber irgendwie auch Spaß :-)
    In der nächsten Zeit will ich meine Analysetools verfeinert und noch mehr Automatismen einbauen, sodass einfache Signal besser und mit weniger Arbeitsschritten zu finden sind. Vor allem suche ich nach einer Möglichkeit sich vortlaufend ändernde Werte zweier Logs zu synchronisieren.

    Dateien

    • 050-idle.txt

      (5,77 kB, 94 Mal heruntergeladen, zuletzt: )
    • 050-rev.txt

      (5,8 kB, 85 Mal heruntergeladen, zuletzt: )
    • 120-idle.txt

      (3,68 kB, 78 Mal heruntergeladen, zuletzt: )
    • 120-rev.txt

      (3,51 kB, 151 Mal heruntergeladen, zuletzt: )
    • 131-idle.txt

      (3,59 kB, 199 Mal heruntergeladen, zuletzt: )
    • 131-rev.txt

      (3,51 kB, 885 Mal heruntergeladen, zuletzt: )
    • 220-idle.txt

      (1,02 kB, 81 Mal heruntergeladen, zuletzt: )
    • 220-rev.txt

      (986 Byte, 81 Mal heruntergeladen, zuletzt: )
    • 405-idle.txt

      (1,46 kB, 77 Mal heruntergeladen, zuletzt: )
    • 405-rev.txt

      (1,33 kB, 84 Mal heruntergeladen, zuletzt: )
    • 433-idle.txt

      (3,68 kB, 84 Mal heruntergeladen, zuletzt: )
    • 433-rev.txt

      (3,63 kB, 78 Mal heruntergeladen, zuletzt: )
    • 501-idle.txt

      (493 Byte, 80 Mal heruntergeladen, zuletzt: )
    • 501-rev.txt

      (464 Byte, 122 Mal heruntergeladen, zuletzt: )
    • 503-idle.txt

      (493 Byte, 72 Mal heruntergeladen, zuletzt: )
    • 503-rev.txt

      (464 Byte, 119 Mal heruntergeladen, zuletzt: )
    • 508-idle.txt

      (493 Byte, 66 Mal heruntergeladen, zuletzt: )
    • 508-rev.txt

      (464 Byte, 87 Mal heruntergeladen, zuletzt: )
  • Ich habe die Tage meine obige Theorie mit Live-Datenanzeige im Fahrzeug erfolgreich verifizieren können.
    Der Rückwärtsgang ist in der Tat in zwei unterschiedlichen CAN Botschaften vorhanden, nämlich ID 433 und ID 050.
    Warum das so ist, wissen die (Ford)Götter...

  • Als nächstes möchte ich das Rätsel der Modulkonfiguraton anhand des PAM-Moduls lösen. Dieses kann per CCC auf drei unterschiedliche Betriebsmodi gestellt werden:

    • Kein PDC vorhanden
    • PDC nur hinten
    • PDC vorn und hinten


    Die Theorie


    Bislang vertrete ich die Theorie das beim umprogrammieren der CCC nur das BCM angesprochen wird, es also keine Programmierung direkt ans PAM-Modul gibt. Damit das PAM weiß wie es sich verhalten soll, muss sich dieses beim Start, der Aktivierung oder permanent zur Laufzeit diese Information vom BCM beschaffen. Ich glaube das das BCM hierzu diese Info ständig ausstrahlt.


    Indizien für diese Theorie sind:


    • Das PAM ist nur mit dem MS-CAN verbunden. Eine direkte Programmierung wäre also nur den MS-CAN Bus möglich. Die CCC wird aber nur über den HS-CAN Bus in das BCM geschrieben.
    • Scans auf dem MS-CAN Bus während der CCC Programmierung haben keine Regelabweichenden CAN-IDs gezeigt. Somit wird dem PAM auch nicht über den MS-CAN Anschluß des BCM irgendwas übermittelt.
    • Um den PAM-Modus zu ändern, reicht es die CCC ins BCM zu schreiben. Die CCC (Kopie) im IPC spielt hier also keine Rolle.
    • Die geänderte Funktion des PAM ist sofort nach beenden der CCC-Programmierung aktiv. Das erklärt sich aber aus dem nach der Programmierung folgenden RESET Befehl für alle Module. Ich muss mir separat diese ersten Sekunden direkt nach dem Modulreset nochmal genauer ansehen. Hier könnte ggf. das PAM etwas vom BCM anfordern.


    Die Hack-Methode


    Wenn der PDC-Modus in den CAN-Botschaften auf dem MS-CAN gesendet wird, dann muss es nach der umprogrammierung des Modus einen Unterschied geben. Ich erwarte das sich der Wert eines Bytes einer ID in allen drei Modi unterscheidet. Zudem muss diese ID permanent und nicht nur einmalig ausgesendet werden.


    Erstellen der Logs


    Nun habe ich in jedem PAM-Modus den MS-CAN Bus je 30 Sekunden aufgezeichnet. Hierzu habe ich die CCC geändert, Zündung ausgemacht und wieder an, etwas gewartet das sich alles stabilisiert hat und aufgezeichnet.


    Ermitteln der relevanten IDs


    Meiner Theorie folgend muss ich nur die IDs betrachten die vom BCM gesendet werden. Durch mein "Labor BCM" konnte ich folgende ermitteln:
    010 040 048 050 068 06B 078 080 084 08B 110 120 12C 138 200 220 260 280 400 405 433 480 4E2 501 581


    Da ich davon drei IDs bereits vollständig entschlüsselt habe, kann ich diese von der Liste ausnehmen:
    080, 110 => enthalten Datum und die Uhrzeit
    480 => enthalten Gaspedalstellung, Kupplungsbetätigung und Lenkwinkel


    Ermitteln der relevanten Daten


    Mit Hilfe eines selbst erstellten Programms lese ich alle drei Logfiles ein, filtere auf die o.g. IDs und vergleiche deren Datenbytes über die Laufzeit. Das Programm gibt nachfolgen nur die Unterschiede aus und markiert die sich ändernden Bytes in eckigen Klammern.



    Auf relevante Daten reduzieren


    Nun geht es darum die IDs rauszufiltern, die die Funktion des PAM nicht enthalten können.


    ID 048
    Hier hat DB5 im Rear-Only sowie im No-PDC Modus den Wert 0x00 und nur bei Front+Rear einen Wert 0x02. Das kann es eigentlich nicht sein, da man nur zwei unterschiedliche Status hat.


    ID 050
    Hier wechselt der Wert in DB0 immer zwischen 0x40 und 0xC0. Die Bytes DB2 - DB7 sind bei allen drei logs statisch und gleich. Einzig DB1 ändert seinen Wert im No-PDC sowie Rear-Only Modus auf Wert 0x07 und im Front+Rear Modus auf 0x27 . Hier sind auch nur zwei unterschiedliche Zustände abzulesen.


    ID 120
    Sieht eher uninteressant aus.


    ID 12C
    Hier ist in allen drei logs das gleiche Pattern zu erkennen. DB0 ist bis auf eine Ausnahme in logfile(2) immer 0x8E, DB1 wechselt irgendwie aufsteigend und die restlichen Bytes sind statisch gleich. Halte ich für unrelevant.


    ID 200
    Das einzig sich ändernde Byte ist DB5. Bei Rear-Only und No-PDC hat es die Werte 0x80 und 0x90. Bei Front+Rear die Werte 0x81 und 0x91, also genau ein Bit Unterschied. Leider keine Differenzierung zwischen Rear-Only und No-PDC, also wohl uninteressant.


    ID 220
    Hier weiß ich, das die Außentemperatur in den DB6+DB7 steckt. Ebenso das in DB0 der Wert immer zwischen 0x40 und 0xC0 hin und herwechselt. Blendet man diese Bytes aus, ist der Rest statisch. Diese ID können wir also ignorieren.


    ID 260
    Die würde perfekt auf mein Suchmuster passen. Nur ein Byte (DB7), welches in allen drei Logs unterschiedliche Werte hat:
    Rear-Only => 0x7B => 0b01111011
    Front+Rear => 0x7D => 0b01111101
    No-PDC => 0x4E => 0b01001110
    Ein sehr guter Kandidat!


    ID 280
    Ändert sich in DB0 und DB6. Leider haben No-PDC und Rear-Only wieder denselben Wert. Vermutlich also nicht relevant.


    ID 400
    Ebenfalls eine perfekte Übereinstimmung zum Suchmuster. Hier ändert sich nur DB3, welches in allen drei Logs unterschiedliche Werte hat:
    Front+Rear => 0x03 => 0b00000011
    Rear-Only => 0x02 => 0b00000010
    No-PDC => 0x01 => 0b00000001
    Ein sehr guter Kandidat!


    ID 405
    Solange DB0 den Wert 0x01 hat, wechseln bei allen drei Logs DB6 und DB7 immer zwischen '06 45' und 'F9 BA'. Sind also uninteressant.
    Beim Rest meine ich einen Zähler zu erkennen. Zumindes zählt DB5 um je 0x0A (dezimal 10) bei jeder ID hoch. DB4 folgt dann beim Überlauf des Byteswertes mit einer Erhöhung von 1, was offenbar auf noch DB3 beim Überlauf von DB4 macht. Die ID wird einmal pro Sekunde gesendet.
    Einmal sieht man in DB0 den Wert 0x02. Da weiß ich, steckt der Kilometerstand drin, also auch uninteressant.
    Ich glaube in dieser ID ist nichts interessantes für uns drin.


    ID 4E2
    Es ändern sich hier viele Bytes, fast zuviel für einen kleinen Funktionsunterschied. Dennoch merken...


    ID 501
    Diese kommt nur im Log (2) im Read-Only Modus vor und kann daher ignoriert werden.


    Verbleibende Daten bewerten


    Als interessant verbleiben also nur noch die IDs 260 und 400, wobei ich die 400 für den besseren halte. Da ich im Fahrzeug PDC vorn+hinten habe konnte ich ermitteln, das die ID 400 in allen meinen sonstigen Logs auch diesen Wert hat.


    Ergebnis


    Ich bin ziehmlich sicher die richtige ID in der 400 gefunden zu haben, wobei DB3 den PDC-Modus enthält.


    Beweis


    Beweisen könnte ich das ganze nur so, das ich vor dem MS-CAN Anschluß am PAM mein CAN-Gateway einschleife und die ID 400 zum Modul hin durch eine selbst generierte ersetze und damit einen beliebigen PDC-Modus erreichen kann.

  • Wow, jetzt wirds richtig interessant! Beflügelt von meinen vorherigen, wenn auch nur theoretischen Ergebnissen, habe ich etwas Datamining betrieben. Mit erstaunlichen Resultaten! gamer


    Wenn meine Theorie stimmt, dann müsste es ja einen Zusammenhang zwischen der CCC und den Daten in den gefundenen IDs geben. Da ich das Format der CCC auch schon weitgehenst entschlüsselt habe weiss ich, wo die Menüeinstellung des Parkpiloten vom ELMConfig in der CCC steht und welche Werte diese annimmt. Und tatsächlich, das Byte der CCC folgt exakt dem Byte DB3 in der ID 400 !


    Eine CCC sieht inhaltlich z.B. so aus:

    Code
    1. 5700318273713030350D0A57463047585847424247415230343932300D0A0000000000000000000D0A0000000D0A0000000000000D0A00000D0A0000000000000D0A00000000000000000000000000000000000000000D0A000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000FC380602010131020101010101010005020501020201020302020201020102030201010101010100010101010701050001010101640100020103030203010102240701010300125704000301020101010000010001010201020202010202050101010101010203010100010201020201020702010100010001000100020001020101000102020202020100000000030002020200000003010001010100000A00010000000000000301010100000201000500010101010000010201020000000201010002030300000000000000000000000000030100000000000000000000010001000000000000000000000100000000000000000000000000000000000000


    Auf das Format möchte ich nicht näher eingehen, das ist ein anderes Thema, welches auch in meiner "Bastelstube" zu finden ist. Nur soviel, das der eigentliche CCC-Optionsbereich nach diesen vielen Nullen und dem "FC38" beginnt. Die 38 ist dabei eine Checksumme und sicher bei jedem etwas anders. Danach kommen byte für byte die CCC-Einstellungen.


    Wenn ich mit meiner Theorie recht habe, und die ID 400 trägt die CCC auf den CAN-Bus hinaus, dann ist diese mit Sicherheit gemultiplexed. Das bedeutet das ein Byte, in der Regel DB0, wie ein Indexzähler genutzt wird und die eigentlichen Daten nur in den Bytes DB1 bis DB7 stehen. Aber immerhin kann man so eine Menge Daten auf nur einer CAN-ID senden. Also habe ich das erste Byte als Index gesehen und aus den anderen eine zusammenhängende Bytefolge ohne Leerzeichen gemacht, so wie es in der CCC formatiert ist.


    Heraus kommt dann aus dem Datateil bei programmiertem Front+Rear PAM: 09 03 02 03 01 01 02 24 die kompakte Bytefolge 03020301010224. Diese habe ich dann einfach in der CCC gesucht und bin tatsächlich fündig geworden! Die komplette Folge steht auch so in der CCC. Nun habe ich im Logfile mal alle ID 400 Werte ausgefiltert und erkannt das Byte DB0 tatsächlich ein Indexzähler ist. Er beginnt bei 0x01 und endet bei 0x24. Das macht rechnerisch 36 * 7 Bytes = 252 Bytes. EXAKT die größe der CCC-Optionsdaten! Und tatsächlich, beginnend mit Index 0x01 startet auch die CCC mit gleichen Bytewerten ("06020101310201").


    Ein kurzer Check auf dem HS-CAN und MM-CAN ergab das gleiche Ergebnis. Auch hier wird die komplette CCC auf den Bus ausgeplaudert.


    Damit ist BEWIESEN, das die Module ihre Konfiguration über die Aussendung der kompletten CCC über ID 400 vom BCM erhalten


    Yeah! Gotcha, little b***ch! misslelauncher

  • Diese Erkenntnis führt zu allerlei interessanten Anwendungsmöglichkeiten...


    Würde man z.B. ein CAN-Gateway direkt hinter den MS-CAN Anschluß des BCM einbauen, könnte man das Verhalten der anderen Module (natürlich nicht das das BCM selbst) beliebig, auch ohne anpassen der CCC ändern.
    Ich muss noch experimentell herausfinden ob die Module die für sie relevanten CCC-Daten permanent vom Bus lesen, oder nur nach einem Modul-Reset. Aber auch diesen könnte man problemlos vom Gateway erzeugen lassen.


    Eine mögliche Anwendung hierbei wäre z.B. das elektrische anklappen der Spiegel mittels einer gewünschten Funktion zu deaktiveren/aktivieren. Das könnte ein Kippschalter im Handschuhfach sein, oder eine besondere Form der Betätigung von Blinker/Kupplung oder was auch immer.


    Bin mal gespannt auf Eure Ideen und wende mich derweil schonmal dem nächsten CAN-Bus Hacking zu... denn da wartet noch eine Menge "unendecktes Land" :-)

  • Joa, das mit den Spiegeln wäre schon fein. Auch Nebelscheinwerfer als Standlicht müssten doch damit möglich werden? Oder sind die am BCM hardwired?

  • Aber es geht doch darum die Nebler zu schalten, richtig? Grundsätzlich ist dafür ja der Lichtschalter zuständig, welcher per LIN am BCM angeschlossen ist. Das wäre also eher ein Job für ein LIN-Gateway. Hat mit CAN also nix zu tun.


    Viel cooler finde ich, das man die CCC ja praktisch ohne auslesen, mitlesen kann :-)

  • Mich interessiert, wie CAN-Nachrichten von einem Bus zum anderen kommen. Wenn ich mir die CAN-IDs welche auf HS-CAN, MS-CAN und MM-CAN vorkommen ansehe, dann fällt auf, das viele IDs eindeutig nur in einem der Busse vorhanden sind. Manche IDs gibt es aber auch auf zwei oder allen drei Bussen. Fast alle Module im Mondeo sind mit nur einer CAN-Bus Schnittstelle ausgestattet, können also ihre IDs nur dort aussenden.


    Es gibt jedoch zwei Module, das IPC (Kombiinstrument) und das BCM (Zentralelektrikbox) welche über zwei Interfaces verfügen (siehe auch "Übersicht der CAN-Busse und Module im Mondeo"). Diese können zum einen ihre eigenen Nachrichten gleichzeitig auf beide Busse verteilen, aber auch von einem zum anderen übertragen. Man spricht dann von einem CAN-Gateway. Welche IDs übertragen werden und wie, entscheidet die Software im Modul. Es ist also nicht zwingend gesagt, das eine ID welche auf zwei Bussen auftaucht, die gleichen Datenbytes beinhaltet. Auch müssen nicht alle Datenformationen einer ID übertragen werden. Bei gemultiplexten IDs könnte es sein, das nur bestimmte den Weg von einem Bus zum anderen finden.


    Um das heraus zu bekommen starte ich einen neuen Hack. Zum einen analysiere ich Aufzeichnungen aller drei CAN-Busse (möglichst parallel, in echtzeit) zum anderen stelle ich mir eine Data-Injection-Penetration vor, mit der ein eigenes Modul IDs und Daten im Brute-Force Modus auf einem Bus erzeugt und auf dem anderen deren Ankunft erwartet. Als Ergebnis erhält man den Filter, der ggf. im Modul enthalten ist. Zum anderen die Latenzzeit zur Weiterleitung.


    Vorab noch ein paar logische Zusammenhänge hierzu:

    • Für den Brute-Force Test können nur IDs verwendet werden, welche nicht vom zu testenden Modul selbst erzeugt werden. Nehme ich mir also das BCM vor, muss ich alle mir bekannten BCM-CAN-IDs ausnehmen. Das würde sonst nur Kollisionen verursachen.
    • Das Intervall einer Nachricht wird wohl auf beiden Busseiten gleich sein. Andernfalls bestünde die Gefahr von Datenverlust. Wenn also das BCM Nachrichten vom HS-CAN mit Intervall 60ms auf den MS-CAN weiterleitet, werden diese vermutlich auch mit 60 ms ausgesandt. Ist dem nicht so, muss das BCM die Daten filtern oder anhand des Inhaltes entscheiden ob es auf dem MS-CAN erneut zu senden ist und wann.
    • Ein Gateway wird wohl nicht blind alles durchlassen, sondern nur die Daten die bestimmte Module der "anderen Seite" benötigen.
    • Momentan weiß ich noch garnicht ob überhaupt etwas von A nach B geleitet wird, oder doppelt vorkommende CAN-IDs nicht ausschließlich von IPC und BCM selbst erzeugt werden.
    • Es wäre logisch eine weitergeleitete Nachricht unverändert durchzuschleusen. Also müssten beliebige Datenbytes von A nach B gehen können. Ob das immer so ist, muss sich zeigen.

    Was kann man mit diesen Ergebnissen anfangen?
    Wenn der Inhalt einer Nachricht bekannt ist, könnte man spekulieren wozu diese den anderen Modulen dient. Auch könnte man bei freien, nicht verwendeten CAN-IDs diese für eigene Zwecke verwenden.

  • Da ist ja grundsätzlich immer das Problem mit dem verfälschen von Nachrichten. Wenn ich z.B. weiss das in einer Nachricht die Motordrezahl versendet wird, dann ist schon klar das diese vom Motorsteuergerät (PCM) stammen muss. Genutzt wird sie dann an ganz unterschiedlichen Stellen, u.a. auch für die Anzeige im Kombiinstrument (IPC). Jetzt wird die Nachricht aber permanent gesendet, also nicht erst wenn der Motor läuft. Dann ist der Drehzalwert eben 0 RPM. Dieses Prinzip findet man bei den allermeisten CAN-Nachrichten, nur ganz wenige werden "on-demand" gesendet.


    Möchte ich also einen eigenen Drehzahlwert versenden, bleibt mir fast nichts anderes übrig als die Originalnachricht vom PCM abzufangen und durch eine eigene zu ersetzen. Dieses "abfangen" kann man nur elektronisch durch einen CAN-Filter machen, der zwischen Steuergerät und CAN-Bus Leitung hängt. Solch einen zu entwickeln (muss ja stabil laufen, sonst wär das blöd) und dann auch noch einzubauen ist schon mächtig Arbeit. Eine andere Möglichkeit wäre, das Steuergerät dazu zu bringen, die entsprechende Nachricht unter einer anderen ID oder vielleicht sogar garnicht mehr zu versenden. Bei letzterem hat man aber dann das Problem das man auch die anderen Werte irgendwie erraten/simulieren muss. Senden unter einer anderen ID wäre perfekt, denn dann könnte man über ein eigenes Modul die originaldaten empfangen, nach belieben manipulieren und mit der richtigen ID wieder in den Bus einspeisen. Die Steuergeräte die das empfangen würden keinen Unterschied feststellen.


    Die CAN-ID einer Nachricht zu ändern bedürfte aber wieder einer speziellen Elektronik zwischen Modul und Bus oder einem Patch der Firmware des Steuergerätes. Letzteres wäre in der Tat die beste Variante. Leider ist das alles andere als einfach. Um eine firmware zu patchen, muss man diese erstmal als Datei haben. Kennt man die Mikroprozessorarchitektur des Moduls kann man diese sogar in Assembler (evtl. sogar C) zurückübersetzen und sich auf die Suche nach der ID machen. Diese dann ändern, neues Binary compilieren und Prüfsumme berechnen und das ganze mit einem Programmiertool wieder ins Steuergerät schreiben. Der wirklich schwere Teil daran ist, wie man an die Firmware rankommt. Die lässt sich nicht einfach auslesen. Selbst bei so trivialen System(chen) wie einem Lichtschalter ist der Chip gegen auslesen geschützt. Man müsste also richtig cracken, was sehr viel Spezialwissen und Werkzeug erfordert. Oder man hat eine andere "Quelle" für die Firmware ;-) Da muss man aber erstmal rankommen.


    Schon früh hatte ich versucht eine bekannte CAN-Nachricht durch senden durch meine eigene zu "ersetzen". Dabei wird diese aber noch nichtmal überlagert, denn dazu müssten beide Sendungen wirklich zeitgleich erfolgen. Das ist praktisch nie der Fall. So "mischen" sich diese Nachrichten nicht, sondern werden einfach nur hintereinander gesendet. Das habe ich natürlich im gleichen Intervall wie die Originalnachricht gemacht. Dennoch hatte das schon eine Wirkung. Beim senden der Drehzahl hat das IPC versucht die jeweils hintereinander eintreffenden Werte mit dem Zeiger anzufahren. Da das Intervall 60ms beträgt war ein "zitternder" Zeiger das Ergebnis, weil er versuchte zwischen 0 RPM (Wert vom PCM) und 1500 RPM (Wert von mir) hin und her zu wechseln.


    Jetzt habe ich diesen Versuch etwas erweitert, denn dem IPC ist es scheinbar egal wie oft eine Nachricht eintrifft. Wenn der CAN-Stack das hergibt wird jede Nachricht nach ihrem eintreffen bearbeitet und umgesetzt. Also hab ich einfach das Sendeintervall meiner gefälschten Nachricht erhöht. Und tatsächlich, je öfter ich meine falsche Nachricht sende, desto weniger kommt die richtige zur Wirkung. Sende ich mit 10ms, also 6mal so oft, habe ich einen ruhigen, stehenden Zeigerausschlag! Gleiches bei der Fahrgeschwindigkeit. Lustig hierbei fand ich, das ich in der Garage mit angezeigten 260 km/h unterwegs war und mich der Gurtwarner alsbald zum anschnallen ermahnte ;-) Interessant war aber, das das Radio lauter wurde. Hier konnte man also gut die automatische Lautstärkeanpassung prüfen.


    Ich kann mir Module vorstellen die bei (stark) widersprüchlichen Werten oder Sendeintervallen hier in eine Sicherheitsabschaltung gehen. Das Verfahren ist also sicher nicht bei allen Nachrichten anwendbar. Aber es ist ein Anfang.


    Nun habe ich mich daran erinnert, das es im CAN-Protokoll auch Fehlerzustände gibt. Erkennt also ein Sender das seine Nachricht beim senden verstümmelt wurde, so erhöht er einen internen Sendefehlerzähler um den Wert 8. Erreicht dieser Zähler einen Wert von 128 stellt der Sender seine Arbeit zunächst ein. Es müsste also möglich sein durch eine DoS-Attacke ein Modul zum "schweigen" zu bringen. Grad so als hätte man die Sicherung rausgezogen (was auch eine Alternative wäre). Leider geht das nur mit einem ganzen Modul/CAN-Schnittstelle und nicht mit einzelnen IDs. Um einen Fehler zu produzieren muss man exakt(!) zur selben Zeit wie der Sender versuchen Bits auf dem Bus zu verstümmeln. Da der CAN-Bus nur die 0-Werte dominant sendet (für eine 1 lässt er die Busleitung einfach auf 12V), müsste man also irgendwo im Datenstrom eine 0 senden, wenn der Sender eigentlich eine 1 senden würde. Vermutlich reicht es, nach der erkannten CAN-ID einfach etliche 0 zu senden um einen solchen Fehler zu produzieren. Etwas aufpassen muss man aufs Bit-Stuffing. Um 0er von einem Masseschluß zu unterscheiden muss nach sechs 0en immer erst eine 1 gesendet werden. Diese gehört nicht zu den Daten sondern dient der Übertragungssicherheit. Ich muss daran nochmal feilen und das mit meinem "BCM im Glas" mal ausprobieren.


    Beide Verfahren sind sicher nicht für einen praxistauglichen Alltag nutzbar, auch wenn jetzt vielleicht nahe liegt auf dem MM-CAN zur Anzeige eines Videos ständig das R-Signal zu senden. Könnte zwar sein das man damit eine stabile Bildanzeige erzeugen kann, aber man flutet damit natürlich auch ganz schön den Bus und erschwert oder verhindert gar so die Übertragung anderer Nachrichten.


    Es ist vielleicht mehr eine Methode um CAN-Sender und Nutzer zu finden. Bringe ich mit der o.g. DoS-Methode einen Sender zum schweigen, erkenne ich ja sofort welche IDs nicht mehr übertragen werden. Somit ist schonmal klar welche IDs zusammengehören, also von derselben Quelle/Modul kommen! Mit ziehmlicher Sicherheit wird dann im betreffenden Modul ein DTC ("U....") abgelegt. Lese ich also anschließend die Fehlerspeicher aus, weiss ich welches Modul ich gekillt habe. Über das Modul und die Schaltpläne weiss ich dann, welche Sensoren am Modul hängen und kann geziehlter die Daten der Nachricht nach den Sensorwerten untersuchen.


    Mit der "Message Overload" Methode kann ich eigene, krass unterschiedliche Werte simulieren und an der Reaktion der anderen Geräte erkennen was die Inhalte bedeuten. Blöd nur, wenn man das ODO-Meter dabei triggert, denn das wäre irreversiebel ("Oh, für 14.304.229 km sieht der Wagen aber noch echt gut in Schuß aus!" ;-)

  • Zum KM Zähler kann ich dir ne Lösung anbieten. Für einen Reset ginge das so, für einen bestimmten KM Stand brauchst du aber ein UCDS. Ersatzweise kann ich dir auch eine DIY Lösung besorgen, die einen bestimmten KM Stand einpflegt.