OOK Sniffer PIC16/18F CC1101

Ich hoffe es ist okay, wenn ich hier ein neues Thema eröffne. Ich dachte es passt nicht zum URH und verdient ein eigenes.

Hier möchte ich euch mein OOK Sniffer Projekt vorstellen. Da ich in letzter Zeit ein paar defekte Garagenöffner hatte, wollte ich mir das mal genauer anschauen. Bei den meisten Funksendern sind die Typenbezeichnungen der IC’s entfernt oder mit eigenen Bezeichnungen wie ‚FAAC SL…‘ versehen, deshalb wollte ich ein Universal Gerät bauen.

Und, es ist einfacher als gedacht…

Als Funkmodule kommen die beliebten und bekannten CC1101 zum Einsatz, es gibt sie in fast allen Frequenz-Variationen und kosten rund 6 $, also wirklich billig. (Das soll keine Werbung für Waveshare sein)

Die Konfiguration wird mit RFStudo von TI und über die SPI Schnittstelle gemacht. RFStudio erlaubt es, die Konfig zu exportieren.

Zum Sniffer selbst:

CC1101 unterstützt sehr viele Modi wie ASK/OOK, FSK, MSK etc. Dazu Preamble, Sync-Word, Manchester etc. Wenn wir einen Sniffer bauen für OOK, wissen wir nur, dass es ein ON/OFF Keying ist, aber keine Baudrate, keine Preamble, kein Sync Wort.

Wir nutzen diese Funktionen also nicht und schalten den CC in den asynchronen seriellen Modus und ASK/OOK. Das bedeutet, die RX und TX Bits liegen nicht im FIFO welcher über die SPI Schnittstelle zugänglich ist, sondern werden an den GDOx Pins eingelesen oder ausgegeben.

Wir müssen also die Decodierung am Controller selbst machen. Die meisten Fernbedienungen im OOK Mode hatten ca. 1200 Baud. Wir stellen den CC also auf 4800 ein, dann können wir bis 2400 Baud problemlos lesen, natürlich geht auch mehr…

Mein Prototyp hat zwei Funktionen, sniffen und senden. Die ge-snifften Daten werden im Eeprom des PIC’s abgelegt und sind nach einem Neustart auch noch da.

Das Einfache an der Sache: Uns interessiert es eigentlich nicht, wie der Aufbau ist, sprich Preamble, Sync Word Daten. Wir messen die Länge der High und die der Low und legen diese im Eeprom ab.

Momentan läuft das ganze auf einem 18F45k22 PIC, werde heute das noch auf einem 16F873 anpassen.

Genauere Erklärung inkl. Schatlplan und Sourcecode folgt.

Nachtrag:

Hab schnell ein Layout erstellt, nicht schön aber es sollte funktionieren.

Ich bin noch einen Schritt weiter. Da die Module wirklich nicht teuer sind, dachte ich warum nicht zwei aufs Board :wink:
So wird ein Modul auf RX Konfiguriert, während das andere im TX Modus ein Störsignal auf einer leicht versetzten Frequenz sendet.

Stichwort: Rolling Code
Ich konnte bereits einen erfolgreichen Test machen, muss aber die Konfig von den CC1101 noch etwas anpassen.

1 „Gefällt mir“

Ich habe nun mal ein neues Layout erstellt und den PIC18F442 gewählt, da er in PLC44 Form verfügbar ist.

Am Board sind zwei CC1101 Module, ein Pin Header für ein LCD Display (3.3V), ein LM317 für die 3.3V Spannungsversorgung und ein Header für die UART und eine LED.

Die PINS in der Mitte des PLC44 Sockels habe ich vorsorglich gelegt um eventuell eine zweite Platine darunter zu verbinden.

Der 18F442 erhält einen seriellen Bootloader um ihn in der Schaltung bespielen zu können. Sollte dieser mal einen defekt ausweisen, ist es auch kein Drama den PIC aus dem Sockel zu nehmen.

Daher habe ich auf eine ICSP Schnittstelle verzichtet.

Hier das Layout:

bauteilseite.pdf (68,4 KB)

lotseite.pdf (68,1 KB)

Wer Interesse hat, kann sich gerne melden, werde in den nächsten zwei Wochen die Platinen in Auftrag geben. Sind sehr günstig und kosten meist nicht einmal 20 CHF. Gerne könnt ihr auch fertig bestückte Platinen mit dem Bootloader vorinstalliert haben zum Selbstkostenpreis natürlich.

Mit einem kleinen Windows Programm und einem RS232 Wandler könnt ihr dann ganz einfach Software einspielen.

Ganz kurz zum Thema Rolling Code:

Wer im Netz sucht, wird einige Beiträge in Englisch finden. Dabei geht es grundsätzlich darum, dass Handsender von z.B. Autos hohen Temperaturunterschieden unterliegen. Aus diesem Grund sind die Empfänger der Fahrzeuge/Tore sehr hellhörig, haben somit einen breiten Empfangsbereich um den Drift des Senders „auszugleichen“.

Sendet man nun ein Signal neben der Frequenz des eigentlichen Handsenders und noch im Empfangsbereich des Empfängers, so wird die Übermittlung des Handsender als inkorrekt eingestuft, obwohl es die richtige Kodierung hat.

Drückt der Proband nun ein zweites mal auf die Taste, so wird der nächste Code gesendet, welcher wiederum gültig ist aber durch das neben liegende Störsignal als nicht gültig erscheint.

Nun sendet der Sniffer das erste Signal ohne Störsignal und das Fahrzeug wird verschlossen, da dieser ja noch gültig ist. Im Speicher des Sniffers befindet sich aber noch der zweite Code, welcher gültig ist und zum entsperren verwendet werden kann.

Da ich niemanden unterstützen möchte um illegale Dinge zu machen, bitte ich um Nachsicht, dass ich den Code dafür nicht veröffentlichen werde. Für mich ist das ein rein wissenschaftliches Projekt welches ich nur ein meinen eigenen Fahrzeugen teste.

Mitglieder von Coredump können sich diesbezüglich bei mir melden.

Nachtrag: Hab jetzt noch einen Mikrosd Slot eingefügt. Kann nicht schaden die Daten auf die SD zu schreiben um sie später am Rechner zu analysieren.

roema

Klingt spannend :slight_smile: Ich habe momentan leider keine Verwendung dafür (besitze weder ein Auto noch eine Garage… :wink:)

Wo bestellst du deine Boards? Für Einzelstücke lohnt sich http://platinenshop.ch/, für Prototypen-Serien bestelle ich meistens bei Seeed oder EasyEDA.

Ich lasse meine Platinen immer im platinenshop.ch machen.
Sind sehr günstig und schnell geliefert.

Achte aber auch immer darauf nur einseitige Platinen zu entwerfen, sofern es möglich ist.

Werd mir mal seed anschauen. Bin an einer Nixie Clock dran und es lasst sich nicht vermeiden eine mehrschichtige Platine zu machen.

HEY!!! Seed ist ja komplett genial!!!

Endlich nimmt jemand meine Gerber Files! Danke für den Tip!!!

Hello roema,
after i finish my new topic i see one sugested topic with CC1101.
from your topic i know you have used the cc1101 in ask mode.
Could you please send me your config for it - it would help me much.
Also i did’nt know which RX bandwidth i should use in settings.
Could you help me to find the rigth setting?

Best regards,
Frank

Hey Manuel :slight_smile:
Ich versuche dein Projekt (inoffiziell, aus gleichen Gründen wie genannt von dir) auf den ESP32 (esp-idf) zu übertragen und habe folgende Fragen:
Könntest du deine Config hochladen, damit ich sie beim bepowern vom Board automatisch anwenden kann?
Wie kann ich nun genau die GPOs auslesen und in binäres Format umwandeln?
Und wie kann ich mit dem CC1101 diese abgefangenen Daten senden?

Vielen Dank!

Hi Sinan! Gerne!

void Write_CC_Config(char addr, char daten, char cc) 
{
    set_cc(cc);
    addr = addr;
    SPI1_write(addr);
    SPI1_write(daten);
    unset_cc(cc);
    delay_us(10);
    return;
    }

void setup_CC_TX(unsigned short cc){
        Write_CC_Config(0x0000,0x0B,cc);                   //IOCFG2
        Write_CC_Config(0x0002,0x0C,cc);                   //IOCFG0
        Write_CC_Config(0x0003,0x47,cc);                   //FIFOTHR
        Write_CC_Config(0x0006,0x3E,cc);                   //PKTLEN
        Write_CC_Config(0x0008,0x32,cc);                   //PKTCTRL0
        Write_CC_Config(0x0009,0xFF,cc);                   //ADDR
        Write_CC_Config(0x000B,0x06,cc);                   //FSCTRL1
        Write_CC_Config(0x000D,0x10,cc);                   //FREQ2
        Write_CC_Config(0x000E,0xB0,cc);                   //FREQ1
        Write_CC_Config(0x000F,0x71,cc);                   //FREQ0
        Write_CC_Config(0x0010,0xF5,cc);                   //MDMCFG4
        Write_CC_Config(0x0011,0x93,cc);                   //MDMCFG3
        Write_CC_Config(0x0012,0x30,cc);                   //MDMCFG2
        Write_CC_Config(0x0013,0x40,cc);                   //MDMCFG1
        Write_CC_Config(0x0014,0xF7,cc);                   //MDMCFG0
        Write_CC_Config(0x0015,0x14,cc);                   //DEVIATN
        Write_CC_Config(0x0018,0x18,cc);                   //MCSM0
        Write_CC_Config(0x0019,0x16,cc);                   //FOCCFG
        Write_CC_Config(0x0020,0xFB,cc);                   //WORCTRL
        Write_CC_Config(0x0022,0x11,cc);                   //FREND0
        Write_CC_Config(0x0023,0xE9,cc);                   //FSCAL3
        Write_CC_Config(0x0024,0x2A,cc);                   //FSCAL2
        Write_CC_Config(0x0025,0x00,cc);                   //FSCAL1
        Write_CC_Config(0x0026,0x1F,cc);                   //FSCAL0
        Write_CC_Config(0x002C,0x81,cc);                   //TEST2
        Write_CC_Config(0x002D,0x35,cc);                   //TEST1
        Write_CC_Config(0x002E,0x09,cc);                   //TEST0
        }

void setup_CC_RX(unsigned short cc){
        Write_CC_Config(0x0000,0x0D,cc);                   //IOCFG2
        Write_CC_Config(0x0002,0x0D,cc);                   //IOCFG0
        Write_CC_Config(0x0003,0x47,cc);                   //FIFOTHR
        Write_CC_Config(0x0006,0x3E,cc);                   //PKTLEN
        Write_CC_Config(0x0008,0x32,cc);                   //PKTCTRL0
        Write_CC_Config(0x0009,0xFF,cc);                   //ADDR
        Write_CC_Config(0x000B,0x06,cc);                   //FSCTRL1

        // AGC Adjust for OKK
        Write_CC_Config(0x001B,0x04,cc);                   //AGCCTRL2                              eventuell Anpassen
        Write_CC_Config(0x001C,0x00,cc);                   //AGCCTRL1
        Write_CC_Config(0x001D,0x90,cc);                   //AGCCTRL0
        Write_CC_Config(0x0021,0x56,cc);                   //FREND1
        ////////////////////////////////////////////////////////////////////////
        Write_CC_Config(0x000D,0x10,cc);                   //FREQ2
        Write_CC_Config(0x000E,0xB0,cc);                   //FREQ1
        Write_CC_Config(0x000F,0x71,cc);                   //FREQ0
        Write_CC_Config(0x0010,0xF7,cc);                   //MDMCFG4
        Write_CC_Config(0x0011,0x83,cc);                   //MDMCFG3
        Write_CC_Config(0x0012,0x30,cc);                   //MDMCFG2
        Write_CC_Config(0x0013,0x40,cc);                   //MDMCFG1
        Write_CC_Config(0x0014,0xF7,cc);                   //MDMCFG0
        Write_CC_Config(0x0015,0x14,cc);                   //DEVIATN
        Write_CC_Config(0x0018,0x18,cc);                   //MCSM0
        Write_CC_Config(0x0019,0x16,cc);                   //FOCCFG
        Write_CC_Config(0x0020,0xFB,cc);                   //WORCTRL
        Write_CC_Config(0x0022,0x11,cc);                   //FREND0
        Write_CC_Config(0x0023,0xE9,cc);                   //FSCAL3
        Write_CC_Config(0x0024,0x2A,cc);                   //FSCAL2
        Write_CC_Config(0x0025,0x00,cc);                   //FSCAL1
        Write_CC_Config(0x0026,0x1F,cc);                   //FSCAL0
        Write_CC_Config(0x002C,0x81,cc);                   //TEST2
        Write_CC_Config(0x002D,0x35,cc);                   //TEST1
        Write_CC_Config(0x002E,0x09,cc);                   //TEST0

        }

Hier die Konfig des CC1101, je nach dem ob du ihn im RX oder TX Mode benötigst. Wenn du nun am PIN DG01 ein Oszilloskop anschliesst und auf 433 MHZ gesendet wird, solltest du ein schönes Rechteck Signal sehen. Nun kannst du die Baudrate ermitteln. Vergiss nicht die Werte für FREQ0-1 anzupassen, am besten mit dem TI Studio, das berechnet alles für dich.

Wenn das mal funktioniert, kommt die schöne Arbeit, das decodieren. Mach ein paar Aufzeichnungen und sie dir das Rechteck Signal an. Du wirst ein zu Beginn ein Schema erkennen, ein Preamble das zur Synchronisierung des Empfängers dient, genau gesagt ist es 0x55 oder 0xAA… (high-low-high-low-high)…

Vielen Dank, ich bin dabei alles umzusetzen! :slight_smile:

Hallo nochmal!
Das Decodieren ist ja nicht notwendig für ein einfaches Weiterleiten des empfangenen Signales, richtig? Man müsse sozusagen exakt das, was am GPO0 seriell empfangen wurde wieder abspielen, um einen Replay auszuführen, oder liege ich da falsch?
Nichtsdestotrotz werde ich es manuell decodieren, denn das ist ja der Spaß dahinter :wink:
Danke für deine tollen Tutorials und Posts, echt genial!!!

Hallo Sinan!

Danke für das Lob!

Du hast recht, du müsstest eigentlich nichts decodieren, für eine einfache Replay-Attacke. Vielleicht möchtest du ja mal ein Datenpaket auf einem Display ausgeben oder das ganze über die serielle Schnittstelle senden, dann musst du decodieren.

Ist ganz einfach. Stell dir vor, der Empfänger hat keine Ahnung wann ein Datenpaket kommt, wenn das erste eintrifft braucht er etwas Zeit zum synchronisieren. Sagen wir er bekommt 10 Bytes mit 0x55 oder 0xAA, das sehe binär so aus

10101010 - 0xAA
01010101 - 0x55

Du siehst, es ist fast das gleiche… :wink:

Das ist das so genannte Preamble, danach kommt z.B ein START Byte, danach z.B. ein Byte mit der Länge der Nachricht, dann das eigentliche PAYLOAD, also der Code der zu übertragen ist und zum Schluss ein STOP Byte.

Dies wiederholt sich ein paar mal. Kennst du also das START und STOP Byte, kannst du einen ganz einfachen Decoder programmieren.

Das kannst du mit einem Schieberegister machen. Du schiebst jedes empfangene BIT in die Variable und prüfst nach jedem BIT den Wert der Variable. Irgendwann entspricht die Variable dem START Byte und jetzt bist du praktisch synchron zum Sender.

Du darfst dabei den PIN nicht einfach pollen, sonst liest du ein Bit öfters ein. Erstelle einen Interrupt der bei einem Flankenwechsel am GD0 Pin eine Funktion aufruft. Diese Funktion schiebt den Wert des PINs in die Variable und prüft die Variable…

Ist die Variable das START Byte, dann wissen wir, das die nächsten 8 Bit die Länge des Payloads darstellen. Wir erstellen einen Counter und lesen von 0-7, danach prüfen wir wieder die Variable und wissen wie lange lange unser Payload sein wird…

Das kann je nach Hersteller etwas abweichen, deshalb solltest du mit einem Oszi mal die Baudrate ermitteln, und danach das START Byte…