Reverse Engineering der Gerätefirmware am Beispiel eines blinkenden „Nashorns“. Teil 2


Wir stellen Ihnen den zweiten Teil des Artikels über das Reverse Engineering der Flashing Rhino-Gerätefirmware vor, der auf einem Workshop auf der SMARTRHINO-2018- Konferenz basiert.

Im ersten Teil des Artikels wurde die Gerätefirmware in den IDA-Disassembler geladen und eine erste Analyse der Geräteprotokollbefehle durchgeführt. Einzelne Befehle wurden auf einem Arbeitsgerät getestet.

Im zweiten Teil wird eine Analyse der verbleibenden Firmware-Aufgaben durchgeführt.

Ich möchte Sie daran erinnern, dass nach der Analyse der Bluetooth-Aufgabe im Hinblick auf die Steuerung von LEDs beschlossen wurde, zur LED-Aufgabe zu wechseln, da die erste Aufgabe darin besteht, eine Anwendung zur Steuerung von LEDs zu erstellen. Dazu ist ein detailliertes Verständnis des Firmware-Betriebs erforderlich.

Die Firmware-Datei steht für unabhängige Studien zur Verfügung.

Alle Informationen werden nur zu Bildungszwecken bereitgestellt.

Unter der Katze gibt es viele blinkende Nashörner.

LED Aufgabe


Kurz gesagt: eine vollständige Analyse der Aufgabe, die für das Schalten von LEDs verantwortlich ist. Analyse von Datentypen und globalen Variablen.

Die LED-Aufgabe wird durch die Funktion x_leds_task dargestellt , die sich unter 0x08005A08 .

Zusätzlich zu den seltsamen Zeilen "Ich habe eine Superleistung ..." in der Hauptfunktion der LED-Aufgabe können Sie auf die Zeile "Farbton> max: Glanz ändern \ r \ n" achten.



Gleichzeitig sehen wir eine vertraute Situation - (WORD *) (v26 + 4). Wählen Sie im Kontextmenü der Variablen v26 das Element "In Struktur konvertieren *" aus und geben Sie die zuvor erstellte Struktur an:



Da v5 = v26 , wiederholen wir die Operation "In Struktur konvertieren *" für die Variable v5.

Wir strukturieren weiterhin den Code und die Daten. Stellen Sie die Hex-Darstellung überall ein. Umbenennen:

  • v5 - geführt ;
  • v6 - idx ;
  • v8 - hue_1 ;
  • v9 - hue_2 ;
  • v26 - _led ;

Der Code verbessert sich. Einige Variablen verletzen jedoch immer noch das Auge, z. B. die Variable v23:





Anscheinend ist v23 ein Array von 4 Bytes.
idx ist der Index der LED; Dieser Index wird der Basisadresse hinzugefügt. Auf diese Weise wird auf Elemente mit denselben Verschiebungen zugegriffen - so verhalten sich Arrays.

Wir weisen den Typ char v23[4] und benennen ihn in leds_smth um . Der Code wird schöner:



Sie können auch feststellen, dass das Ergebnis der Funktion x_queue_recv an die Variable v25 zurückgegeben wird:

 x_queue_recv(&v25, leds_queue, 1000); 

Möglicherweise ist jedoch nicht klar, wie sich die benötigten Daten in der _led- Struktur befinden. Tatsache ist, dass sich die Variablen v25 und _led in der Nähe des Stapels befinden - dies kann durch die Tatsache verstanden werden, dass sie beim Dekompilieren in benachbarte Zeilen geschrieben werden. Die Position der Variablen auf dem Stapel wird in einem separaten Fenster angezeigt, wenn Sie auf die Variable doppelklicken:



Es handelt sich wahrscheinlich um eine Struktur, oder der Compiler hat einige Optimierungen vorgenommen. Somit kann argumentiert werden, dass Daten von der Bluetooth-Aufgabe an die LED-Aufgabe übertragen werden. Um dies genauer herauszufinden, überprüfe ich das Gerät - für die Null-LED über Bluetooth sende ich die Werte 0x208 , 0x2D0 , 0x398 , 0x3E9 , die im Code erkennbar sind:



Die Ergebnisse der Überprüfung des Farbtonwerts auf dem Gerät:

  • 0x208 - Die LEDs schalteten nicht mehr reibungslos und wurden in den Farben Rot, Grün, Blau, Lila eingestellt.
  • 0x2D0 - die LEDs begannen wieder zu schalten;
  • 0x398 - nichts hat sich geändert;
  • 0x3E9 - nichts hat sich geändert.

Wenn Sie sich den Code noch einmal ansehen, sehen Sie, dass der Wert 0x398 logisch einem Wert kleiner als 0x167 zugeordnet werden kann (für das Array-Element leds_smth werden unterschiedliche Werte festgelegt ). Daher werde ich diese Prüfung durchführen: Zuerst setze ich die erste LED auf Grün (Farbton = 0x78, LED 010078FF20 ), während die anderen drei LEDs weiterhin ihre Farben wechseln.


Jetzt werde ich LED 010398FFFF Bluetooth-Protokollbefehl LED 010398FFFF - danach hat die erste LED in den allgemeinen Farbumschaltmodus geschaltet.

Somit setzt der Farbtonwert von 0x398 den statischen Farbwert zurück, was bedeutet, dass das Array leds_smth Flags (0 oder 1) für die zu besetzenden LEDs enthält:

  • 0 - die LED ist nicht besetzt, nimmt an einer reibungslosen Farbumschaltung teil ( Farbton = 0x398 );
  • 1 - Die LED ist besetzt, der Benutzer hat eine statische Farbe eingestellt ( Farbton <= 0x167 ).

Benennen Sie leds_smth in leds_busy um .

Nun sollte der Zweck des folgenden Codeblocks klar werden:



Der Zyklus in den Zeilen 83-101 führt ein glattes Farbmosaik mit einem Farbwechselschritt von 5 aus: v12 += 5 . Wenn die LED eine statische Farbe hat, nimmt diese LED nicht am Mosaik teil. Nach dem Zyklus gibt es Linien der kurzfristigen Einbeziehung aller LEDs.

Umbenennen:

  • sub_800678A - x_led_set_hsv ;
  • v12 - hue_step ;
  • v13, v17, v18, v19 - led0_busy , led1_busy , led2_busy , led3_busy ;
  • v11, v20, v21, v22 - Farbton0 , Farbton1 , Farbton2 , Farbton3 ;
  • dword_200004C4 - led_control .

Die Funktion sub_80039FE führt vermutlich ein Timeout durch (andernfalls haben die LEDs nicht reibungslos, sondern sofort geschaltet). Nennen wir es x_sleep , und die Variable v16 lautet led_timeout .

Der Zweck der Funktion sub_8006934 ist noch nicht klar, wird jedoch überall verwendet, nachdem die Farbe auf den LEDs eingestellt wurde - Sie können sie x_led_fix_color nennen .

Nach dieser Umbenennung ist die Funktion sub_8006944 (im Zweig hue <= 0x167 aufgerufen) leicht zu verstehen:



Es wird lediglich eine zusätzliche Überprüfung durchgeführt, um die Farbe der LED zu bestimmen. Benennen Sie die Funktion sub_8006944 in x_led_set_hsv_wrap um (Suffix _wrap - eine Erklärung, dass dies ein "Wrapper" über eine andere Funktion ist) und legen Sie den folgenden Prototyp dafür fest:

 signed int __fastcall x_led_set_hsv_wrap(int led_control, signed int idx, int hue, char sat, char val) 

Kehren wir eine Ebene zurück zur Funktion x_leds_task. Wenn Sie sich den Code noch einmal ansehen, können Sie feststellen, dass der Zweig "Farbton> 0x3E8" folgendermaßen aussah:



Das heißt, ein Farbtonwert größer als 0x3E8 sollte das Zeitlimit des farbigen Mosaiks ändern. Ich überprüfe dies, indem ich einige Werte an das Gerät sende:

  • Farbton = 0x3E9 - Die LEDs begannen schnell zu schalten:


  • hue = 0xFFFF - die LEDs begannen sehr langsam zu schalten:



Beim Verlassen des Hauptzyklus der LED-Task wird die Funktion sub_8003C44 verwendet , die auch in der Funktion sub_8005070 verwendet wird:



Umbenennen:

  • sub_8005070 - x_freeMsg ;
  • sub_8003C44 - x_free_queue .

Weiter in der LED-Aufgabe kann der folgende Zweig nur Aufmerksamkeit erregen:



Sie können versuchen, den LED B816D8D90000FFFF Befehl LED B816D8D90000FFFF . Wenn Sie sich jedoch daran erinnern, dass nur 2 Zeichen als LED-Index verwendet werden, ist ein Versuch, diesen Code zu erreichen, offensichtlich erfolglos. Lassen Sie diesen Thread für später. Benennen Sie die Funktion sub_8004AE8 in x_mad_blinking um und es ist Zeit, die Signatur der x_printf- Funktion zu korrigieren (das letzte Mal, als ich die falsche Signatur geschrieben habe):

 void x_printf(const char *format, ...) 

Der Hauptzyklus der LED-Aufgabe wird zerlegt, aber am Anfang der Aufgabe befindet sich noch ein Code.

Schauen wir uns den Code an:



In Zeile 49 werden die LEDs höchstwahrscheinlich auf Verfügbarkeit überprüft, und im Fehlerfall wird die Funktion sub_8004BBC aufgerufen, die Interrupts ausschaltet und eine Endlosschleife startet, in der die Zeile "../Drivers/STM32F0xx_HAL_Driver/Src/stm32f0xx_hal_gpio.c" verwendet wird. Höchstwahrscheinlich handelt es sich um eine Assert- oder ähnliche Funktion.

Umbenennen:

  • sub_8004BBC - x_gpio_assert ;
  • sub_800698C - x_check_gpio .

Der Zweck der Funktion sub_8006968 wird deutlich, wenn Sie sich das Gerät beim Einschalten genau ansehen:


Alle vier LEDs zusammen leuchten zuerst rot, dann grün und dann blau. Danach werden sie nach Farbe eingestellt: 0-rot, 1-grün, 2-blau, 3-violett. Und erst dann beginnen sie, Mosaike zu wechseln.

Da das Mosaik im Hauptaufgabenzyklus beginnt, ist es logisch, dass die Zeilen 58 bis 61 vor dem Hauptzyklus für die kurzfristige Aufnahme verschiedener Farben in die LEDs verantwortlich sind und die Zeilen 52 bis 56 für die gleichzeitige Einstellung von Rot-Grün-Blau auf allen LEDs verantwortlich sind. Benennen Sie die Funktion sub_8006968 in x_led_all_set_rgb um (RGB - nach den übergebenen Argumenten rein ahnungslos ).

Seltsamkeiten in der LED-Aufgabe


Kurz gesagt: Definieren der Funktionalität von Code mit seltsamen Zeilen. Generieren eines Passworts für das Gerät.

Fahren wir nun mit dem Anfang der Funktion x_leds_task fort:



"Eraze" , "gen" , "flash" , "reset" - warum ist das alles ???

Versuchen wir es herauszufinden.

Sei sub_80066BC x_leds_task_init .

Schauen wir uns sub_8006B38 an:



Reines Wasser memset, stimme zu?



Zurück zu x_leds_task. Mit dem Variablentyp v24 stimmt etwas nicht:



Die IDA hat einen kleinen Fehler mit dem Typ gemacht, aber ein Kommentar mit einer Stapelmarkierung hilft uns. Zwischen den Variablen v24 und v25 bis zu 12 Byte (0x44 - 0x38). Daher benennen wir v24 in buf um und weisen den Typ unsigned __int8 buf[12] (Ida warnt, dass der neue Datentyp größer als der alte ist - wir sind uns einig).

Weiter. Funktion sub_8004CE4:



Benennen Sie a1 in buf , v1 in _buf um .

Funktion sub_8006B26:



Hast du sie erkannt?

Und wenn ohne Make-up?

Natürlich memcpy . Umbenennen.

Der Zweck der Funktion sub_8004CE4 besteht dann darin, einige Daten an der Adresse 0x08007C00 zu erhalten . Diese Adresse liegt übrigens im Adressbereich des Flash-Speichers des Mikrocontrollers (und insbesondere der Firmware). Benennen Sie sub_8004CE4 in x_read_data_0x08007C00 um .

X_leds_task Funktionszeile 36:

 if ( (unsigned int)buf[0] - 65 > 0x19 ) 

Ändern Sie die Datenanzeige (R-Taste auf der Nummer 65, H-Taste auf der Nummer 0x19):

 if ( (unsigned int)buf[0] - 'A' > 25 ) 

Nach einigem Nachdenken können Sie verstehen, dass dies ein solcher Test für den Bereich des lateinischen Alphabets AZ ist.

Benennen Sie als Nächstes mithilfe der Eingabeaufforderungen in Form von Formatzeichenfolgen Folgendes um:

  • sub_8004C10 - x_erase ;
  • sub_80059C8 - x_gen ;
  • sub_8004C84 - x_flash .

Die Funktion sub_8003C66 macht nichts Bemerkenswertes - sie erhöht nur einige globale Variablen - benennt sub_8003C66 in x_smth_inc um .

Die Funktion x_erase akzeptiert tatsächlich keine Argumente - dies kann im Disassembler überprüft werden:



In x_erase wird die bekannte Adresse 0x08007C00 verwendet und auf drei unbekannte Funktionen zugegriffen:



Ein kurzer Blick auf diese drei Funktionen zeigt, dass sie auf Adressen im Bereich von 0x40022000 - 0x400223FF zugreifen . In der Dokumentation zum Mikrocontroller ist eindeutig angegeben, dass dies der Bereich „FLASH Interface“ ist. Das heißt, die x_erase-Funktion löscht einen Teil des Flash-Speichers - großartig!

Anscheinend schreibt die Funktion x_flash in den Flash-Speicher, nachdem die Länge der Zeile zum Schreiben überprüft wurde (die Argumente a2 und a3 sind hier übrigens überflüssig - wir helfen Idea):



Und das alles passiert im "Beleuchtungsgerät" ???

Was ist mit der Funktion x_gen ? Nach einem kurzen Blick und dem Umbenennen von Variablen sieht es folgendermaßen aus:



Die Funktion sub_8006CB4 sieht folgendermaßen aus:



Und sub_8006D10 - so:



Halten Sie den Wunsch nicht zurück, im Internet nach diesen unanständig schönen Konstanten zu suchen: 0xABCD , 0x1234 , 0xE66D , 0xDEEC , 0x4C957F2D und 0x5851F42D . Wenn das Internet noch nicht vollständig gesperrt ist, finden Sie diese Konstanten wahrscheinlich in der Quelle für zufällige Funktionen . Kein Wunder, dass die übergeordnete Funktion x_gen heißt.

Dies ist auch eine sehr typische Situation: Rufen Sie srand () vor der Schleife auf und rufen Sie random () in der Schleife auf. Benennen Sie es also um:

  • sub_8006D10 - x_rand;
  • sub_8006CB4 - x_srand.

Ein neugieriger Leser kann anhand der Funktion sub_8005098 herausfinden, woher der Startwert für die srand-Funktion stammt.

Somit generiert die Funktion x_gen eine zufällige Zeichenfolge mit der angegebenen Größe .

Nachdem die generierte Zeile in den Flash-Speicher geschrieben wurde, wird das Gerät neu gestartet:



Es scheint ein seltsamer Neustart zu sein. Wenn wir uns jedoch die Liste der Aufgaben dieses Geräts ansehen, finden wir unter ihnen "watchdogTask". Wenn es eine "feststeckende Aufgabe" gibt, wird der Watchdog offensichtlich neu gestartet.

Eine LED-Aufgabe mit Ausnahme des MadBlinking-Modus kann als analysiert betrachtet werden.

Lassen Sie uns durch die Zeilen schauen, welche anderen Aufgaben im System sind:



Nachdem Sie die Links zu Zeichenfolgen im Code wiederhergestellt haben, sehen Sie dieses Bild:



Zuerst gibt es eine Verknüpfung zu einer Zeichenfolge mit der Namensaufgabe, dann eine Verknüpfung zur Hauptaufgabenfunktion. Und sie werden in der Hauptfunktion verwendet, in der diese Aufgaben gestartet werden:



Lassen Sie uns die fehlenden Umbenennungen ausführen:

  • sub_80050FC - x_sensor_task ;
  • sub_8004AAC - x_watchdogTask ;
  • sub_8005440 - x_uartRxTask .

Watchdog-Aufgabe


Task Watchdog macht nichts besonders Interessantes:



Umbenennen:

  • dword_200003F8 - wd_variable ;
  • sub_8001050 - x_update_wd_var .

UART-Aufgabe


Kurz gesagt: Suchen Sie nach Daten und Funktionen, die Links von verschiedenen Funktionen enthalten. Bestimmung ihres Zwecks.

Ein kurzer Blick auf die UART-Task ermöglicht es Ihnen, das Senden von Daten an eine unbekannte Warteschlange zu erkennen, die durch die Variable unk_200003EC definiert ist :



Nachdem die Links zu dieser Variablen über die binäre Suche wiederhergestellt wurden, werden wir sehen, dass sie zusätzlich zu x_uartRxTask in der Hauptfunktion (dort wird anscheinend die Warteschlange erstellt) und in der bisher unbekannten Funktion sub_80051EC verwendet wird :



Umbenennen:

  • sub_80051EC - x_recvMsg_uart_queue ;
  • unk_200003EC - uart_queue .

Siehe Querverweise zu x_recvMsg_uart_queue:

  • sub_8005250;
  • x_bluetooth_task.

Siehe zuerst die Funktion sub_8005250 :



Benennen Sie nach dem Nachdenken um:

  • unk_2000034C - cmd_count ;
  • a1 - cmd ;
  • v4 - _cmd ;
  • v6 ist rsp ;
  • sub_8005250 - x_bluetooth_cmd .

Mal sehen, wo x_bluetooth_cmd noch verwendet wird. Alle zusätzlichen Links nur von der Bluetooth-Aufgabe, es ist Zeit, zu ihr zurückzukehren.

Zurück zur Bluetooth-Aufgabe


Kurz: die endgültige Analyse der Bluetooth-Aufgabe. Suchen Sie nach einer Autorisierung ohne Passwort.



Wenn Sie sich die Stellen ansehen, an denen die Funktion sub_8006A84 verwendet wird , und Sie nicht zu faul sind und in den Darm schauen, besteht kein Zweifel - dies ist calloc . Es ist logisch - um Daten in den Puffer zu empfangen, müssen Sie zuerst diesen Puffer erstellen.

Jetzt sub_8006DBC . Schauen wir es uns an (Variablen wurden bereits umbenannt):



Wenn wir uns an die Funktionen der Standard-C-Bibliothek für die Arbeit mit Zeichenfolgen erinnern , sehen wir hier strstr (Suche nach einem Teilstring) und benennen ihn mutig um.

Lassen Sie uns den Code der Funktion x_bluetooth_task durchgehen - vielleicht hat sich hier seit dem letzten Besuch etwas geändert . Dabei benennen wir die Variablen:

  • v2 - _state ;
  • v3 - data_len .

Direkt daneben befindet sich eine Funktion sub_80052E2 . In Analogie zu Funktionen, die Zahlen aus einem Bluetooth-Befehl abrufen, wird eine Zeichenfolge mit einer bestimmten Länge abgerufen - nennen wir sie x_get_str .

Wir fahren fort:

  • v26 - isEcho ;
  • v6 - meow_str ;
  • v10 - uart_cmd_byte ;
  • v11 - uart_cmd_str ;
  • v12 - str_0 ;
  • v13 - str_1 ;
  • v14 - format_str ;
  • sub_8000F5C - x_blink_small_led .

Beenden Sie mit einer schnellen Umbenennung:

  • v19 - Passwort ; (da daneben Zeilen über Autorisierung und Passwort stehen)
  • sub_8004CC0 - x_check_password ;
  • sub_8006AF4 - x_free (da password, cmd und bt_args Zeiger auf dynamische Objekte sind (überprüfen Sie dies!), sollte der Speicher nach deren Verwendung freigegeben werden);
  • sub_8006DAC - x_strcpy (check it out!).

Erkunden Sie nun die Zweige READ , WRIT , AUTP , SETP .

Wie ein Test auf einem laufenden Gerät gezeigt hat, ist eine Autorisierung für die Befehle READ, WRIT, SETP erforderlich. Ein Autorisierungsversuch mit dem Befehl AUTP bringt uns zur Funktion x_check_password , um das Kennwort zu überprüfen:



Es stellt sich heraus, dass die Kennwortlänge 8 Zeichen betragen muss und das Kennwort (in der Funktion sub_8006B08) mit Bytes an der Adresse 0x08007C00 verglichen wird - wo die generierte Folge von Zufallszeichen AZ gespeichert wird.

Es stellt sich heraus, dass wir uns ohne Kenntnis des Passworts nicht am Gerät anmelden können. Naja oder fast nicht ...

Achten Sie darauf, wo die Variable auth_flag verwendet wird :



Es stellt sich heraus, dass es nicht nur in Bluetooth-Aufgaben verwendet wird. Und hier haben wir einfach noch nicht in Sensor Aufgabe geschaut. Wir gehen dorthin.

Sensoraufgabe


Kurz gesagt: Was macht die Touch-Taste?

Gemäß den besten Programmierpraktiken passt die gesamte Sensoraufgabe in einen IDA-Bildschirm. Und das kann sich nur freuen:



Zeile zu Zeile ...

  • "TSC% d \ r \ n" - Diese Zeile sollte Sie über den Touch Sensing Controller für STM32-Mikrocontroller nachdenken lassen.
  • "AUTH BTN \ r \ n" - Autorisierungsknopf ???
  • "SET AUTH% d \ r \ n" - Berechtigungsflag setzen?

Mal sehen, wie sich das Gerät verhält, wenn Sie die Touch-Taste drücken (haben Sie festgestellt, dass das Nashorn am Bein eine Touch-Taste hat?):



Bei kurzem Drücken leuchtet die rote kleine LED auf. Bei langem Drücken leuchtet diese LED lange auf.

Wenn wir dies mit dem Code korrelieren, können wir annehmen, dass die Funktion sub_8000708 eine Funktion zum Abrufen der aktuellen Zeit ist. Wenn die Differenz zwischen der aktuellen Zeit und dem Beginn des Berührens des Sensors mehr als 1000 (1 Sekunde) beträgt, leuchtet die LED für 0xEA60 Millisekunden (1 Minute). Von großem Interesse ist jedoch die Variable auth_flag, die durch langes Drücken der Touch-Taste auf 1 gesetzt wird und dem Angreifer den Zugriff auf den Administrator des "Beleuchtungskörpers" auf privilegierte Funktionen ermöglicht.

So können Sie nach der Autorisierung „per Taste“ das im Gerät gespeicherte Passwort lesen (Befehl READ), in den RAM schreiben (WRIT-Funktion) oder ein neues Passwort festlegen (SETP).

Mad blinkt


Kurz gesagt: Kann ein seltsamer Mad Blinking-Code-Zweig ausgeführt werden?

Kehren wir zur Bluetooth-Aufgabe zurück und führen eine weitere Umbenennung durch.

  • v21 - vip_smth (es ist noch nicht klar, was da ist);
  • v22 - vip_str (Zeichenfolge unbekannter Größe, extrahiert aus den Argumenten);
  • v23 - mad_led - weise "In Struktur konvertieren *" zu und gebe struct_LED an .

Und hier sehen wir die Nummer 0xB816D8D9 (sie wurde im ersten Teil des Artikels in der Bluetooth-Aufgabe gefunden) als Index der LED. Dieser Code wird ausgeführt, wenn eine Überprüfung durchgeführt wird:

 if ( sub_8005520(vip_str, vip_smth) == 0x46F70674 ) 

Benennen Sie sub_8005520 in x_vip_check um und sehen Sie es sich an:



Da das erste Argument eine Zeichenfolge ist (zumindest die Zeichenfolge wird an diese Funktion übergeben), zeigt dieser Code, dass das zweite Argument die Länge dieser Zeichenfolge (oder die Länge, die verarbeitet werden muss) ist. Umbenennen:

  • a1 - str ;
  • a2 - len .

Schauen wir uns die Funktion sub_8000254 an :



Schauen Sie sich nun sub_8000148 an . Hier ist der Anfang:



Dies ist nur ein Drittel der Funktion ... Mmmm ... Lecker! Ein erfahrener Bagger wird hier leicht sehen ...

Was?
Ganzzahldivisionsoperation.

Wie kann es ausgegraben werden?
Wenn Sie sich anstrengen, können Sie über die Funktion sub_8000254 (über mehrere andere Funktionen) zu x_printf gelangen. Ein wichtiger Punkt an dieser Stelle ist, dass normalerweise alle Standardfunktionen ziemlich Standard sind . Dies bedeutet, dass Sie versuchen können, mindestens einen Quellcode der untersuchten Funktion öffentlich zu finden, damit die Studie produktiver ist.

Also nehmen wir die Quelle von printf, dann schauen wir uns vfprintf an und vergleichen es mit dem Code der untersuchten Firmware. Unter Verwendung des Quellcodes verlassen wir die itoa- Funktion und schließen daraus, dass die sub_8000254- Funktion der Operatoroperator % ist (der Rest der Division nimmt), und diese schrecklich lange Funktion ist nichts anderes als der ganzzahlige Teil der Division (div-Operation).

Es kann sich eine berechtigte Frage stellen - warum? Tatsache ist, dass es in einem bestimmten Mikrocontroller keine DIV-, MOD-Operationen geben kann. Daher ersetzt der Compiler den Aufruf einzelner Funktionen anstelle dieser Operatoren. Übrigens, hier sind einige andere mathematische Funktionen .

Vergessen Sie nicht, beim Graben umzubenennen.

So berechnet die Funktion x_vip_check ... Und das sind Ihre Hausaufgaben .

Übrigens, wenn Sie den richtigen VIP- Befehl ausführen, erhalten wir ein "Nashorn in der Disco":



Kurzbericht zur Firmware


Die Firmware des Geräts basiert auf dem Echtzeit-Betriebssystem FreeRTOS. Das System hat folgende Aufgaben:

  1. Bluetooth-Aufgabe . Verarbeitet Befehle, die in Textform über Bluetooth eingehen.
  2. LED Aufgabe . Steuert Farb-LEDs gemäß Bluetooth-Befehlen.
  3. Sensoraufgabe . Schaltet die rote LED ein und ermöglicht eine kurzfristige Autorisierung ohne Kennwort auf dem Gerät.
  4. UART-Aufgabe . Ermöglicht die Interaktion mit dem Bluetooth-Modul über den internen UART-Port (zur Initialisierung von Bluetooth).
  5. Watchdog-Aufgabe . Verfolgt das Einfrieren.

Die Studie berücksichtigte nicht die Fähigkeit, Daten vom UART-Port (Tx / GND-Kontakte) zu lesen.

Zusammenfassung


Während der Meisterklasse auf der Konferenz wurde nur die Hauptfunktion der LED-Steuerung zerlegt. Den aktivsten Teilnehmern wurden ihre experimentellen „Nashörner“ vorgestellt.

Meiner Meinung nach hat das „Nashorn“ ein anständiges Layout für einen Schulungskurs über Reverse Engineering und Schwachstellensuche erstellt. Ein Merkmal des Layouts kann die Möglichkeit sein, die Firmware so oft zu ändern, wie Sie möchten. Jeder Kurs hat seine eigene Firmware. Im Gegensatz zum Parsen einer ausführbaren Datei können Sie mit der Reverse-Firmware Folgendes besser verstehen:

  • wie man mit IDA arbeitet;
  • Prinzipien der Interaktion zwischen Firmware und Gerät;
  • RTOS-Funktionsprinzipien.

Vielen Dank an alle, die bis zum Ende gelesen haben!

Source: https://habr.com/ru/post/de412561/


All Articles