Reverse-Engineering von IR-Prüfbits/CRC

Ich versuche, eine einfache Arduino-basierte IR-Fernbedienung für einen billigen IR-gesteuerten Spielzeughubschrauber zu bauen (wie dieser - er heißt "Diamond Gyro" oder "Diamond Force"). Ich habe das IR-Protokoll bis auf die letzten Bits entschlüsselt. Diese letzten Bits scheinen ein Check oder CRC zu sein, aber ich konnte es nicht "knacken".

Es ist einfach genug, ein aufgezeichnetes Paket einfach zu wiederholen, aber ich möchte den Hubschrauber vollständig steuern. Das bedeutet Reverse-Engineering der Prüfbits.

(Ich sollte hinzufügen, dass ich tagsüber Software mache, aber Elektronik ist manchmal ein Hobby, also vermisse ich vielleicht nur etwas sehr Grundlegendes.)

Die Details des Protokolls sind in der Frage und Antwort enthalten, aber hier sind die Grundlagen:

  • 32-Bit-Paket, das mehrere einzelne Werte/Befehle unterschiedlicher Länge umfasst (plus 1 Startbit/Präambel, das nicht als Daten zählt)
  • Die Werte sind Little Endian (MSB zuerst)
  • Ich bin mir sicher, dass ich die ersten 22 Bits gemappt habe ...
  • ... aber die folgenden 4 Bits sind ein wenig mysteriös, obwohl ich den Zweck von mindestens 2 davon kenne.
  • Die letzten 6 Bits scheinen eine Art Überprüfung oder CRC zu sein

Hier ist ein Diagramm

 0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2
--+---------------------------+-----------+---+---+-+-+-----------
 P|    Yaw    |   Throttle    |   Pitch   | T | C |X|X|  CRC?

P: Preamble (always 1), T: Trim, C: Channel,
X: Either part of the channel data or the checksum.

Zunächst einmal bin ich mir nicht sicher, ob die XBits Teil des Kanalwerts, Teil der Prüfung oder etwas anderes sind. Sie folgen jedoch immer dem Kanalwert, daher ist es wahrscheinlich, dass der Kanalwert 3-4 Bit breit ist, obwohl 2 Bit für die 3 möglichen Kanalwerte ausreichen würden.

Zweitens gibt es die letzten 6 Bits ( CRC?oben markiert), die eindeutig eine Art Überprüfung darstellen (und tatsächlich reagiert der Hubschrauber nicht, wenn ich eines dieser Bits ändere).

Im Grunde gibt es also ein Paket mit 24–26 Datenbits, gefolgt von 6–8 Prüfbits. Und ich würde wirklich gerne diese Prüfbits herausfinden, damit ich selbst Pakete zusammenstellen kann.

Unten sind einige Beispiele der binären Daten, die ich bekomme. Die Präambel "1" ist immer vorhanden, und ich glaube nicht, dass sie zu den Daten zählt, aber ich habe sie trotzdem eingefügt, nur für den Fall, dass sie der Schlüssel zu allem ist.

Auch hier weiß ich nicht, ob die XBits Teil der Daten oder der Prüfung sind. Je nach Berechnungsweise des Checks kann es sein, dass die ersten 1-2 Bits des Checks zufällig auf den Kanalwert folgen. Es ist aber auch durchaus möglich, dass der Kanalwert 4 Bit lang ist, inklusive der XBits. Oder es liegt dazwischen, wobei ein XBit Teil des Kanals und das andere Teil der Prüfung ist. Ich weiß nicht.

Wenn jemand weiß, was das ist, oder wie ich das herausfinden könnte, würde ich es gerne wissen. Ich kann mir vorstellen, dass ich es brutal erzwingen kann, aber selbst wenn dies die einzige Option ist, würde ich gerne einige Hinweise hören, wie man das am besten macht.

Der Helikopter ist spottbillig, also bezweifle ich, dass irgendetwas wirklich Besonderes los ist.

Channel A                                                       
P  Yaw     Throttle  Pitch   Tr  Ch  XX  Check     Description
--------------------------------------------------------------
1  000100  10000100  000000  00  01  01  000101    Left Mid + throttle 
1  000000  10000110  010001  00  01  01  010010    Left Max + throttle 
1  100001  10000110  000000  00  01  01  100010    Right Mid + throttle 
1  100100  10000100  010001  00  01  01  110100    Right Max + throttle
1  010001  00000000  001011  00  01  01  011111    Forward Min 
1  010001  00000000  000000  00  01  01  010100    Forward Max 
1  010001  00000000  011000  00  01  01  001100    Back Min 
1  010001  00000000  100101  00  01  01  110001    Back Max
1  010001  00000000  010001  01  01  01  010101    Left Trim 
1  010001  00000000  010001  10  01  01  100101    Right Trim 
1  010001  00000011  010001  00  01  01  000110    Throttle 01 (min)
1  010001  00010110  010001  00  01  01  010011    Throttle 02
1  010001  00011111  010001  00  01  01  011010    Throttle 03
1  010001  00101111  010001  00  01  01  101010    Throttle 04
1  010001  00111110  010001  00  01  01  111011    Throttle 05
1  010001  01010101  010001  00  01  01  010000    Throttle 06
1  010001  01011111  010001  00  01  01  011010    Throttle 07
1  010001  01101100  010001  00  01  01  101001    Throttle 08
1  010001  01111010  010001  00  01  01  111111    Throttle 09
1  010001  10000101  010001  00  01  01  000000    Throttle 10 (max)

Channel B
P  Yaw     Throttle  Pitch   Tr  Ch  XX  Check     Description
--------------------------------------------------------------
1  000000  10000110  010001  00  00  10  010101    Left Max + throttle 
1  100100  10000110  010001  00  00  10  110001    Right Max + throttle 
1  010001  00000000  001001  00  00  10  011010    Forward Min 
1  010001  00000000  000000  00  00  10  010011    Forward Max 
1  010001  00000000  010111  00  00  10  000100    Back Min 
1  010001  00000000  100110  00  00  10  110101    Back Max
1  010001  00000000  010001  01  00  10  010010    Left Trim 
1  010001  00000000  010001  10  00  10  100010    Right Trim 
1  010001  00000001  010001  00  00  10  000011    Throttle Min 
1  010001  00110100  010001  00  00  10  110110    Throttle Mid 
1  010001  01100111  010001  00  00  10  100101    Throttle High 
1  010001  10001111  010001  00  00  10  001101    Throttle Max 

Channel C
P  Yaw     Throttle  Pitch   Tr  Ch  XX  Check     Description
--------------------------------------------------------------
1  000000  10000101  010001  00  10  00  011100    Left Max + throttle
1  100100  10000101  010001  00  10  00  111000    Right Max + throttle 
1  010001  00000000  001010  00  10  00  010011    Forward Min 
1  010001  00000000  000000  00  10  00  011001    Forward Max 
1  010001  00000000  010111  00  10  00  001110    Back Min 
1  010001  00000000  100110  00  10  00  111111    Back Max
1  010001  00000000  010001  01  10  00  011000    Left Trim 
1  010001  00000000  010001  10  10  00  101000    Right Trim 
1  010001  00000001  010001  00  10  00  001001    Throttle Min 
1  010001  00110100  010001  00  10  00  111100    Throttle Mid 
1  010001  01100110  010001  00  10  00  101110    Throttle High 
1  010001  10000101  010001  00  10  00  001101    Throttle Max

Antworten (3)

Zunächst einmal ist es ziemlich klar, dass die „XX“-Bits Teil der Kanalbezeichnung sind , da sie nur davon abhängen. Die "XX"-Bits können einfach eine Überprüfung der "Ch"-Bits sein.

Die Prüfbits sind ein einfaches bitweises XOR von 24 der 26 Datenbits: Wenn Sie die 6 Yaw-Bits, die 6 LSBs des Throttle, die 6 Pitch-Bits und die nächsten 6 Bits nehmen und diese Mengen XOR zusammenfügen, erhalten Sie die 6 Prüfbits. Es scheint, dass die oberen 2 Bits des Throttle die Prüfbits überhaupt nicht beeinflussen.

Das folgende Perl-Skript überprüft dies.

#!/usr/bin/perl

# crc.pl - verify decoding of check bits

# On the lines starting with '1', just keep the '0's and '1's in an array. 
while (<>) {
    my @letters = split '', $_;
    next unless $letters[0] eq '1';
    @letters = grep /[01]/, @letters;
    @letters = @letters[1..32];
    $a = string2bin (@letters[0..5]);
    $b = string2bin (@letters[8..13]);
    $c = string2bin (@letters[14..19]);
    $d = string2bin (@letters[20..25]);
    $e = string2bin (@letters[26..31]);
    $f = $a ^ $b ^ $c ^ $d;
    printf "%02X %02X %02X %02X %02X %02X %s\n", $a, $b, $c, $d, $e, $f,
        $e == $f ? '-' : '###';
}

sub string2bin {
    my $temp = 0;
    for (@_) {
        $temp = ($temp << 1) + ($_ eq '1' ? 1 : 0);
    }
    $temp;
}
Perfekt! Und: Der Helikopter stimmt zu! Ich nehme an, ich hätte das XOR-Schema selbst sehen sollen, aber wie bei der Protokolldecodierung glaube ich, dass ich mich selbst dazu gebracht habe, zu glauben, es sei komplizierter, als es tatsächlich war. Danke schön! Das war das letzte Puzzleteil, glaube ich
Nur um den Kommentaren von @Olin nachzugehen – Skriptsprachen wie Perl machen es einfach, die Daten zu manipulieren und Hypothesen auf die von ihm vorgeschlagene algorithmische Weise zu testen. Deshalb habe ich mein Skript hier als Demonstration eingefügt. Ich benutze Perl seit den späten 1980er Jahren, also wende ich mich dem zu, aber alle modernen Skriptsprachen sind für solche Dinge ungefähr gleich gut geeignet. Es war einfach so, dass das erste, was ich versuchte, richtig war. Ich hatte die Daten zuvor mit dem Auge durchsucht und einige Zeilen gefunden, die sich nur in wenigen Bits unterschieden.
Persönlich wende ich mich an Ruby (ich habe mich nie viel mit Perl beschäftigt, aber ich habe keine Probleme, Ihr Skript zu verstehen). Ich habe Ruby verwendet, um die Software-Demodulation/Hüllkurvenerkennung des IR-Signals aus rohen Timing-Daten durchzuführen (da ich direkt vom IC des Controllers gelesen habe, nicht von einem Empfänger), die Protokollspezifikationen ausgearbeitet und sogar einige Grafiken für meine frühere Frage erstellt . Ich habe auch einige Dinge versucht, um die Prüfbits selbst zu knacken, aber ich ging von den falschen Annahmen aus (zB CRC). Benötigte einen frischen Blick – in diesem Fall Ihren – auf die Daten selbst.

Ich sehe kein sofort offensichtliches Muster, also würde ich dies eher algorithmisch angreifen. Sie haben anscheinend die Fähigkeit, eine große Anzahl von Paketen zu erfassen und sie dann auf automatisierte Weise in einen Computer zu bringen. Ich würde eine große Anzahl erfassen, während ich die Steuerung langsam variiere.

Nachdem Sie einen Haufen Pakete in einer Datei haben, schreiben Sie etwas Code, um den Code zu knacken. Betrachten Sie es als ein Kryptografieproblem. Eines der ersten Dinge, die ich tun würde, ist, nach Paketpaaren zu suchen, die sich nur in einem Bit unterscheiden. Das sollte Ihnen sofort sagen, ob Sie eine einfache Prüfsumme oder etwas Komplizierteres wie einen CRC haben. Wenn es sich um eine einfache Prüfsumme handelt, dann sollte die Prüfsumme solcher Paketpaare nur variieren, indem ihr eine Potenz von 2 hinzugefügt wird. Wenn eine ganze Reihe von Bits auf unvorhersehbare Weise variieren, haben Sie wahrscheinlich einen CRC.

Wenn es sich um eine Grundsumme handelt, sollten Sie nach einigen Einzelbitänderungen herausfinden können, wie jedes Feld zur Prüfsumme hinzugefügt wird. Wenn es wie ein CRC aussieht, würde ich wahrscheinlich als nächstes eine umfassende Suche durchführen. Es ist nur eine 6-Bit-Prüfsumme, also gibt es nur 64 mögliche Polynome. Es kann bis zu 64 verschiedene Startwerte geben, aber normalerweise beginnt man einen CRC mit dem hohen Bit gesetzt und den anderen Bits auf 0. Neue Bits können von beiden Enden verschoben werden. Wahrscheinlich, zumindest wenn derjenige, der den CRC entworfen hat, wüsste, was er tut, dann sollte das Ergebnis 0 sein, wenn Sie das gesamte Paket durch den CRC laufen lassen. Die Anzahl der Kombinationen ist klein genug, dass eine erschöpfende maschinelle Suche die Antwort sofort finden sollte Menschenzeit, ob es sich wirklich um einen gewöhnlichen CRC handelt.

Hinzugefügt:

Ich habe gerade Dave Tweeds Antwort gesehen, wo er gezeigt hat, dass dies sogar noch einfacher ist als eine Summe, nur XOR der Felder. Es gibt viele faule Ingenieure da draußen. Ich hätte dies mit einem CRC gemacht, der wirklich sehr einfach zu berechnen ist.

Ich hinterlasse meine Antwort hier als Beschreibung, wie man so etwas angreift, wenn man bei der Inspektion kein Muster sieht. Wenn Sie diese Methode verwendet hätten, hätten Sie gesehen, dass einzelne Bitänderungen in den Daten zu einzelnen Bitänderungen in der Prüfsumme geführt hätten, was sofort auf ein XOR-Schema hingewiesen hätte.

Danke noch einmal! Bevor Dave Tweed die einfachere Antwort fand, war dies die Art von Antwort, auf die ich gehofft hatte. Ich hatte mich mit Brute-Forcing-CRC-Prüfungen befasst, aber nur wenige praktische Anleitungen gefunden (stattdessen fand ich meistens Komplikationen, wie zum Beispiel, ob die Eingabe / Ausgabe umgekehrt werden sollte, und natürlich war ich mir zu diesem Zeitpunkt über diese Teile nicht sicher) X. Was das Ändern eines einzelnen Bits und das Betrachten des Schecks betrifft, hätte ich das gerne versucht, aber es hätte einige Arbeit mit diesem billigen Controller erfordert. Hätte es ein wenig modifizieren müssen, um diese Art von Auflösung zu erhalten.
Was faule Ingenieure betrifft: Das ist der Grund, warum ich dachte, es wäre ein CRC. Einfach umzusetzen, wie Sie sagen. Nun ja

Über die XX: Wie Dave betont, scheinen sie Teil der Kanalinformationen zu sein, da sie für einen bestimmten Kanal immer gleich sind. Sie sind nicht wirklich erforderlich; wie Sie sagten, Sie können 3 Kanäle mit nur 2 Bit codieren, aber die gegebenen 4 Bit erlauben eine Hamming-Distanz von 2. Dies bedeutet, dass die Codes für die Kanäle immer mindestens 2 Bit-Änderungen voneinander entfernt sind. Das Ändern eines einzelnen Bits führt nicht zu einem gültigen Kanalcode. Zusammen mit der Prüfsumme erhöht dies die Zuverlässigkeit.