Screenshot der IDA Pro Disassembler-SchnittstelleIDA Pro ist ein berühmter Disassembler, der seit vielen Jahren von Informationssicherheitsforschern auf der ganzen Welt eingesetzt wird. Wir bei Positive Technologies verwenden dieses Tool ebenfalls. Darüber hinaus konnten wir ein eigenes
Disassembler-Prozessormodul für die NIOS II-Mikroprozessorarchitektur entwickeln , das die Geschwindigkeit und den Komfort der Codeanalyse erhöht.
Heute werde ich über die Geschichte dieses Projekts erzählen und zeigen, was am Ende passiert ist.
Hintergrund
Alles begann im Jahr 2016, als wir unser eigenes Prozessormodul entwickeln mussten, um die Firmware in einer Aufgabe zu analysieren. Die Entwicklung wurde von Grund auf anhand des Handbuchs
Nios II Classic Processor Reference Guide durchgeführt , das damals am relevantesten war. Insgesamt dauerte diese Arbeit etwa zwei Wochen.
Das Prozessormodul wurde für die Version IDA 6.9 entwickelt. Aus Gründen der Geschwindigkeit wurde IDA Python ausgewählt. An der Stelle, an der sich die Prozessormodule befinden - dem Unterverzeichnis procs im IDA Pro-Installationsverzeichnis - befinden sich drei Python-Module: msp430, ebc, spu. In ihnen können Sie sehen, wie das Modul angeordnet ist und wie die grundlegenden Demontagefunktionen implementiert werden können:
- Analyseanweisungen und Operanden,
- ihre Vereinfachung und Darstellung,
- Erstellen von Offsets, Querverweisen sowie des Codes und der Daten, auf die sie sich beziehen
- Verarbeitung von Schalterkonstruktionen,
- Umgang mit Manipulationen mit dem Stack und den Stack-Variablen.
Ungefähr diese Funktionalität wurde zu dieser Zeit implementiert. Glücklicherweise war das Tool nützlich, um an einer anderen Aufgabe zu arbeiten, bei der es ein Jahr später aktiv genutzt und verfeinert wurde.
Ich beschloss, die Erfahrungen mit der Erstellung des Prozessormoduls bei den PHDays 8 mit der Community zu teilen. Die Präsentation erregte Interesse (der Videobericht wurde auf der PHDays-Website veröffentlicht), sogar der Schöpfer von IDA Pro Ilfak Gilfanov war anwesend. Eine seiner Fragen war, ob die Unterstützung für IDA Pro Version 7 implementiert wurde. Zu diesem Zeitpunkt war sie nicht vorhanden, aber nach der Aufführung versprach ich, eine entsprechende Version des Moduls zu veröffentlichen. Hier begann der Spaß.
Jetzt das neueste
Handbuch von Intel , mit dem Fehler überprüft und überprüft wurden. Ich habe das Modul erheblich überarbeitet und eine Reihe neuer Funktionen hinzugefügt, darunter die Lösung der Probleme, die zuvor nicht behoben werden konnten. Natürlich habe ich Unterstützung für die 7. Version von IDA Pro hinzugefügt. Folgendes ist passiert.
NIOS II-Softwaremodell
NIOS II ist ein Softwareprozessor, der für Altera-FPGAs (jetzt Teil von Intel) entwickelt wurde. Aus Sicht der Programme weist es die folgenden Merkmale auf: Bytereihenfolge des Little Endian, 32-Bit-Adressraum, 32-Bit-Befehlssatz, dh 4 Bytes, 32 allgemeine und 32 Spezialregister werden zum Codieren jedes Befehls verwendet.
Demontage- und Code-Referenzen
Deshalb haben wir in IDA Pro eine neue Datei mit Firmware für den NIOS II-Prozessor geöffnet. Nach der Installation des Moduls wird es in der Liste der IDA Pro-Prozessoren angezeigt. Die Wahl des Prozessors ist in der Abbildung dargestellt.

Angenommen, das Modul hat noch nicht einmal eine grundlegende Analyse von Befehlen implementiert. Da jeder Befehl 4 Bytes benötigt, gruppieren wir die Bytes in vier, dann sieht alles ungefähr so aus.

Nachdem die Grundfunktionen zum Decodieren von Anweisungen und Operanden implementiert, auf dem Bildschirm angezeigt und Steuerübertragungsanweisungen analysiert wurden, wird der im obigen Beispiel festgelegte Bytesatz in den folgenden Code konvertiert.

Wie aus dem Beispiel ersichtlich ist, werden Querverweise auch aus Steuerübertragungsbefehlen generiert (in diesem Fall sehen Sie den bedingten Sprung und den Prozeduraufruf).
Eine der nützlichen Eigenschaften, die in Prozessormodulen implementiert werden können, sind Befehlskommentare. Wenn Sie die Ausgabe von Bytewerten deaktivieren und die Ausgabe von Kommentaren aktivieren, sieht derselbe Codeabschnitt bereits so aus.

Wenn Sie hier zum ersten Mal auf den Assembler-Code einer neuen Architektur gestoßen sind, können Sie anhand von Kommentaren verstehen, was passiert. Darüber hinaus haben die Codebeispiele dieselbe Form - mit Kommentaren, um nicht das NIOS II-Handbuch zu lesen, sondern sofort zu verstehen, was im Codeabschnitt geschieht, der als Beispiel angegeben ist.
Pseudoanweisungen und Vereinfachung von Befehlen
Einige NIOS II-Befehle sind Pseudobefehle. Für solche Teams gibt es keine separaten Opcodes, und sie selbst werden als Sonderfälle anderer Teams modelliert. Beim Zerlegen wird eine Vereinfachung der Anweisungen durchgeführt - das Ersetzen bestimmter Kombinationen durch Pseudobefehle. Pseudoanweisungen in NIOS II können allgemein in vier Typen unterteilt werden:
- wenn eine der Quellen Null ist (r0) und aus der Betrachtung entfernt werden kann,
- wenn das Team einen negativen Wert hat und das Team durch das Gegenteil ersetzt wird,
- wenn der Zustand umgekehrt ist,
- Wenn der 32-Bit-Offset in zwei Teams in Teilen (dem jüngsten und dem ältesten) eingegeben wird und dieser durch einen Befehl ersetzt wird.
Die ersten beiden Typen wurden implementiert, da das Ersetzen der Bedingung nichts Besonderes ergibt und 32-Bit-Offsets mehr Optionen bieten als im Handbuch dargestellt.
Betrachten Sie beispielsweise für die erste Ansicht den Code.

Es ist ersichtlich, dass hier häufig die Verwendung des Nullregisters in Berechnungen gefunden wird. Wenn Sie sich dieses Beispiel genau ansehen, werden Sie feststellen, dass alle Befehle außer der Übertragung der Steuerung Optionen zum einfachen Eingeben von Werten in bestimmte Register sind.
Nachdem wir die Verarbeitung von Pseudobefehlen implementiert haben, erhalten wir denselben Codeabschnitt, aber jetzt sieht er besser lesbar aus, und anstelle von Variationen der Befehle oder und add erhalten wir Variationen des Befehls mov.

Stapelvariablen
Die NIOS II-Architektur unterstützt den Stapel, und zusätzlich zum Stapelzeiger sp gibt es auch einen Zeiger auf den fp-Stapelrahmen. Betrachten Sie ein Beispiel für eine kleine Prozedur, die einen Stapel verwendet.

Offensichtlich ist Platz für lokale Variablen auf dem Stapel reserviert. Es kann davon ausgegangen werden, dass das Register ra in der Stapelvariablen gespeichert und daraus wiederhergestellt wird.
Nach dem Hinzufügen von Funktionen zum Modul, die Änderungen im Stapelzeiger verfolgen und Stapelvariablen erstellen, sieht dasselbe Beispiel folgendermaßen aus.

Jetzt sieht der Code etwas klarer aus, und Sie können die Stapelvariablen bereits benennen und ihren Zweck analysieren, indem Sie den Querverweisen folgen. Die Funktion im Beispiel ist vom Typ __fastcall und ihre Argumente in den Registern r4 und r5 werden auf den Stapel geschoben, um eine Unterprozedur vom Typ _stdcall aufzurufen.
32-Bit-Zahlen und Offsets
Die Besonderheit von NIOS II besteht darin, dass in einer Operation, dh wenn ein einzelner Befehl ausgeführt wird, höchstens ein direkter Wert von 2 Bytes (16 Bit) registriert werden kann. Andererseits sind die Prozessorregister und der Adressraum 32-Bit, dh zum Adressieren müssen 4 Bytes in das Register eingegeben werden.
Um dieses Problem zu lösen, werden zweiteilige Verschiebungen verwendet. Ein ähnlicher Mechanismus wird in Prozessoren in PowerPC verwendet: Der Offset besteht aus zwei Teilen, dem ältesten und dem jüngsten, und wird durch zwei Befehle in das Register eingegeben. In PowerPC ist dies wie folgt.

Bei diesem Ansatz werden aus beiden Teams Querverbindungen gebildet, obwohl die Adresse tatsächlich im zweiten Befehl konfiguriert wird. Dies kann manchmal störend sein, wenn die Anzahl der Querverweise gezählt wird.
Die Offset-Eigenschaften für das ältere Teil verwenden den nicht standardmäßigen Typ HIGHA16, manchmal wird der Typ HIGH16 für das jüngere Teil verwendet - LOW16.

Die Berechnung von zweiteiligen 32-Bit-Zahlen ist nicht kompliziert. Schwierigkeiten ergeben sich bei der Bildung von Operanden als Offsets für zwei separate Teams. All diese Verarbeitung fällt auf das Prozessormodul. Es gibt keine Beispiele dafür, wie dies (insbesondere in Python) im IDA SDK implementiert werden kann.
In dem Bericht über PHDays waren Vorurteile ein ungelöstes Problem. Um das Problem zu lösen, haben wir betrogen: 32-Bit-Offset nur vom jüngsten Teil - auf der Basis. Die Basis wird als ältester Teil berechnet und um 16 Bit nach links verschoben.

Bei diesem Ansatz wird ein Querverweis nur mit dem Befehl zum Eingeben des unteren Teils des 32-Bit-Offsets gebildet.
Die Basis ist in den Offset-Eigenschaften sichtbar und die Eigenschaft ist markiert, um sie als Zahl zu betrachten, so dass keine große Anzahl von Querverweisen auf die Adresse selbst gebildet wird, die wir als Basis nehmen.

Im Code für NIOS II wird der folgende Mechanismus zum Eingeben von 32-Bit-Zahlen in das Register gefunden. Zunächst wird der älteste Teil des Offsets mit dem Befehl movhi in das Register eingetragen. Dann schließt sich der jüngere Teil an. Dies kann auf drei Arten (durch Befehle) erfolgen: Hinzufügen von Addi, Subtrahieren von Subi, logisches ODER-Ori.
Beispielsweise werden im nächsten Codeabschnitt die Register auf 32-Bit-Zahlen gesetzt, die dann vor dem Aufruf der Funktion in Register - Argumente - eingegeben werden.

Nach dem Hinzufügen der Offsetberechnung erhalten wir die folgende Darstellung dieses Codeblocks.

Der resultierende 32-Bit-Offset wird neben dem Befehl zur Eingabe des unteren Teils angezeigt. Dieses Beispiel ist sehr anschaulich, und wir könnten sogar alle 32-Bit-Zahlen im Kopf leicht berechnen, indem wir einfach die kleinen und höchsten Teile hinzufügen. Nach den Werten zu urteilen, sind sie höchstwahrscheinlich keine Vorurteile.
Betrachten Sie den Fall, wenn beim Betreten des jüngeren Teils die Subtraktion verwendet wird. In diesem Beispiel ist es nicht möglich, die endgültigen 32-Bit-Zahlen (Offsets) unterwegs zu ermitteln.

Nach der Berechnung der 32-Bit-Zahlen erhalten wir das folgende Formular.

Hier sehen wir, dass jetzt, wenn sich die Adresse im Adressraum befindet, ein Versatz darauf gebildet wird und der Wert, der als Ergebnis der Verbindung der Neben- und Oberteile gebildet wurde, nicht mehr in der Nähe angezeigt wird. Hier erhielten sie einen Versatz durch die Zeile „22.10.08“. Damit der Rest der Offsets auf gültige Adressen verweist, erhöhen wir das Segment ein wenig.

Nach dem Erhöhen des Segments erhalten wir, dass jetzt alle berechneten 32-Bit-Zahlen Offsets sind und gültige Adressen angeben.
Es wurde oben erwähnt, dass es eine andere Option zum Berechnen von Offsets gibt, wenn ein logischer ODER-Befehl verwendet wird. Hier ist ein Beispielcode, in dem zwei Offsets auf diese Weise berechnet werden.

Derjenige, der im r8-Register ausgewertet wird, wird dann auf den Stapel geschoben.
Nach der Konvertierung ist ersichtlich, dass in diesem Fall die Register auf die Adressen des Beginns der Prozeduren konfiguriert sind, dh die Adresse der Prozedur wird auf den Stapel geschoben.

Lesen und Schreiben relativ zur Basis
Zuvor haben wir Fälle betrachtet, in denen eine 32-Bit-Zahl, die mit zwei Befehlen eingegeben wurde, nur eine Zahl und auch ein Versatz sein kann. Im folgenden Beispiel wird die Basis in den oberen Teil des Registers eingegeben, und das Lesen oder Schreiben erfolgt relativ dazu.

Nach der Verarbeitung solcher Situationen erhalten wir den Offset zu den Variablen aus den Lese- und Schreibbefehlen selbst. Darüber hinaus wird abhängig von der Dimension der Operation die Größe der Variablen selbst festgelegt.

Konstruktionen wechseln
Die in Binärdateien gefundenen Schalterkonstrukte können die Analyse erleichtern. Anhand der Anzahl der Auswahlfälle innerhalb des Switch-Konstrukts können Sie beispielsweise den Switch lokalisieren, der für die Verarbeitung eines bestimmten Protokolls oder Befehlssystems verantwortlich ist. Daher besteht die Aufgabe darin, den Schalter selbst und seine Parameter zu erkennen. Betrachten Sie den folgenden Codeabschnitt.

Der Ausführungsthread stoppt beim Übergang des Registers jmp r2. Ferner gibt es Codeblöcke, zu denen Links von den Daten bestehen, und am Ende jedes Blocks gibt es einen Sprung zu derselben Bezeichnung. Offensichtlich ist dies ein Schalterkonstrukt, und diese einzelnen Blöcke behandeln bestimmte Fälle daraus. Oben sehen Sie auch die Überprüfung der Anzahl der Fälle und den Standardsprung.
Nach dem Hinzufügen der Switch-Verarbeitung sieht dieser Code folgendermaßen aus.

Nun wird der Sprung selbst angezeigt, die Adresse der Tabelle mit Offsets, die Anzahl der Fälle sowie jeder Fall mit der entsprechenden Anzahl.
Die Tabelle selbst mit Offsets zu den Optionen lautet wie folgt. Um Platz zu sparen, werden die ersten fünf Elemente angegeben.

Tatsächlich besteht die Verarbeitung des Schalters darin, den Code erneut durchzugehen und nach allen seinen Komponenten zu suchen. Das heißt, ein Switch-Organisationsschema wird beschrieben. Manchmal kann es Ausnahmen in den Schemata geben. Dies kann der Grund für Fälle sein, in denen die scheinbar klaren Schalter in vorhandenen Prozessormodulen nicht erkannt werden. Es stellt sich heraus, dass der reale Switch einfach nicht unter das im Prozessormodul definierte Schema fällt. Es gibt immer noch mögliche Optionen, wenn die Rennstrecke vorhanden zu sein scheint, aber es gibt andere Teams in der Rennstrecke, die nicht an der Rennstrecke beteiligt sind, oder die Hauptteams werden neu angeordnet oder sie werden durch Übergänge unterbrochen.
Das NIOS II-Prozessormodul erkennt einen Schalter mit solchen "fremden" Anweisungen zwischen den Hauptbefehlen sowie mit den neu angeordneten Stellen der Hauptbefehle und mit Unterbrechungen, die die Schaltung unterbrechen. Entlang des Ausführungspfads wird ein Rückweg verwendet, der mögliche Übergänge berücksichtigt, die die Schaltung unterbrechen, und interne Variablen installiert, die unterschiedliche Zustände des Erkenners signalisieren. Infolgedessen werden ungefähr 10 verschiedene Switch-Organisationsoptionen in der Firmware erkannt.
Benutzerdefinierte Anweisung
In der NIOS II-Architektur gibt es eine interessante Funktion - die benutzerdefinierte Anweisung. Es bietet Zugriff auf 256 benutzerdefinierte Anweisungen, die in der NIOS II-Architektur möglich sind. In seiner Arbeit kann der benutzerdefinierte Befehl zusätzlich zu Allzweckregistern auf einen speziellen Satz von 32 benutzerdefinierten Registern zugreifen. Nach der Implementierung der Logik zum Parsen des benutzerdefinierten Befehls erhalten wir das folgende Formular.

Möglicherweise stellen Sie fest, dass die letzten beiden Anweisungen dieselbe Anweisungsnummer haben und dieselben Aktionen ausführen.
Gemäß den benutzerdefinierten Anweisungen gibt es ein
separates Handbuch . Ihm zufolge ist eine der umfassendsten und aktuellsten Optionen für den benutzerdefinierten Befehlssatz der Befehlssatz NIOS II Floating Point Hardware 2 Component (FPH2) für die Arbeit mit dem Gleitkomma. Nach der Implementierung des Parsens von FPH2-Befehlen sieht das Beispiel folgendermaßen aus.

Aus den Mnemoniken der letzten beiden Teams geht hervor, dass sie wirklich dieselbe Aktion ausführen - den Befehl fadds.
Übergänge nach Registerwert
In der untersuchten Firmware tritt häufig eine Situation auf, wenn ein Sprung gemäß dem Wert des Registers ausgeführt wird, in den zuvor ein 32-Bit-Offset eingegeben wird, der den Ort des Sprungs bestimmt.
Betrachten Sie einen Code.

In der letzten Zeile gibt es einen Sprung im Wert des Registers, während klar ist, dass die Prozeduradresse, die in der ersten Zeile des Beispiels beginnt, zuerst in das Register eingegeben wird. In diesem Fall ist es offensichtlich, dass der Sprung zu seinem Anfang gemacht wird.
Nach dem Hinzufügen der Erkennungsfunktionalität von Sprüngen wird die folgende Form erhalten.

Neben dem Befehl jmp r8 wird die Adresse angezeigt, an der der Sprung erfolgt, wenn eine Berechnung möglich war. Ein Querverweis wird auch zwischen dem Team und der Adresse gebildet, an der der Sprung stattfindet. In diesem Fall ist der Link in der ersten Zeile sichtbar, der Sprung selbst wird von der letzten Zeile ausgeführt.
GP-Registerwert (globaler Zeiger), speichern und laden
Es ist üblich, einen globalen Zeiger zu verwenden, der für eine bestimmte Adresse konfiguriert ist, und Variablen werden relativ dazu adressiert. NIOS II verwendet das Register gp (Global Pointer), um den globalen Zeiger zu speichern. Irgendwann wird in der Regel bei den Initialisierungsprozeduren der Firmware der Adresswert in das GP-Register eingetragen. Das Prozessormodul behandelt diese Situation. Um dies zu veranschaulichen, sind im Folgenden Codebeispiele und das IDA Pro-Ausgabefenster aufgeführt, wenn Debugging-Meldungen im Prozessormodul aktiviert sind.
In diesem Beispiel findet und berechnet das Prozessormodul den Wert des GP-Registers in der neuen Datenbank. Beim Schließen der IDB-Datenbank wird der GP-Wert in der Datenbank gespeichert.

Wenn eine vorhandene IDB-Datenbank geladen wird und der GP-Wert bereits gefunden wurde, wird er aus der Datenbank geladen, wie in der Debug-Meldung im folgenden Beispiel gezeigt.

Lesen und Schreiben zu gp
Übliche Operationen sind Lesen und Schreiben mit einem Versatz relativ zum GP-Register. Im folgenden Beispiel werden beispielsweise drei Lesevorgänge und ein Datensatz dieser Art ausgeführt.

Da wir bereits den Wert der Adresse erhalten haben, die im GP-Register gespeichert ist, können wir diese Art des Lesens und Schreibens adressieren.
Nachdem wir die Verarbeitung für Lese- und Schreibsituationen relativ zum GP-Register hinzugefügt haben, erhalten wir ein bequemeres Bild.

Hier können Sie sehen, auf welche Variablen zugegriffen wird, ihre Verwendung verfolgen und ihren Zweck identifizieren.
Adressierung relativ zu gp
Es gibt eine andere Verwendung des gp-Registers zum Adressieren von Variablen.

Hier sehen wir zum Beispiel, dass die Register relativ zum GP-Register für einige Variablen oder Datenbereiche konfiguriert sind.
Nach dem Hinzufügen von Funktionen, die solche Situationen erkennen, in Offsets konvertieren und Querverweise hinzufügen, erhalten wir das folgende Formular.

Hier können Sie bereits sehen, welche Bereiche in Bezug auf GP-Register konfiguriert sind, und es wird klarer, was passiert.
Adressierung relativ zu sp
In ähnlicher Weise werden im folgenden Beispiel die Register auf einige Speicherbereiche abgestimmt, diesmal relativ zum Register sp - Zeiger auf den Stapel.

Offensichtlich sind die Register auf einige lokale Variablen abgestimmt. Solche Situationen - das Setzen von Argumenten auf lokale Puffer vor Prozeduraufrufen - sind häufig genug.
Nach dem Hinzufügen der Verarbeitung (Konvertieren direkter Werte in Offsets) erhalten wir das folgende Formular.

Nun wird klar, dass nach dem Prozeduraufruf die Werte aus den Variablen geladen werden, deren Adressen vor dem Funktionsaufruf als Parameter übergeben wurden.
Querverweise von Code zu Strukturfeldern
Das Definieren und Verwenden von Strukturen in IDA Pro kann die Codeanalyse erleichtern.

Wenn wir uns diesen Teil des Codes ansehen, können wir verstehen, dass das Feld field_8 inkrementiert und möglicherweise ein Zähler für das Auftreten eines Ereignisses ist. Wenn Lese- und Schreibfelder im Code in großer Entfernung voneinander getrennt sind, kann ein Querverweis hilfreich sein.
Betrachten Sie die Struktur selbst.
Obwohl der Zugriff auf die Felder von Strukturen, wie wir sehen, keine Querverweise vom Code zu den Elementen von Strukturen gibt.Nachdem solche Situationen verarbeitet wurden, sieht in unserem Fall alles wie folgt aus.
Jetzt gibt es Querverweise auf Strukturfelder von bestimmten Teams, die mit diesen Feldern arbeiten. Vorwärts- und Rückwärtsquerverweise werden erstellt, und Sie können nach verschiedenen Verfahren verfolgen, wo die Werte der Strukturfelder gelesen und wo sie eingegeben werden.Diskrepanzen zwischen Handbuch und Realität
Im Handbuch müssen beim Decodieren einiger Befehle bestimmte Bits streng definierte Werte annehmen. Für einen Rückgabebefehl von einer eret-Ausnahme sollten die Bits 22–26 beispielsweise 0x1E sein.
Hier ist ein Beispiel für diesen Befehl aus einer Firmware.
Wenn wir eine andere Firmware an einem Ort mit einem ähnlichen Kontext öffnen, stoßen wir auf eine andere Situation.
Diese Bytes wurden nicht automatisch in einen Befehl konvertiert, obwohl alle Befehle verarbeitet werden. Gemessen an der Umgebung und sogar einer ähnlichen Adresse sollte dies dasselbe Team sein. Schauen wir uns die Bytes genau an. Dies ist der gleiche Befehl zum Löschen, mit der Ausnahme, dass die Bits 22–26 nicht gleich 0x1E, sondern gleich Null sind.Wir müssen die Analyse dieses Befehls etwas korrigieren. Jetzt entspricht es nicht ganz dem Handbuch, aber es entspricht der Realität.
IDA 7-Unterstützung
Ab IDA 7.0 hat sich die von Python IDA für reguläre Skripte bereitgestellte API erheblich geändert. Bei den Prozessormodulen sind die Änderungen enorm. Trotzdem konnte das NIOS II-Prozessormodul für Version 7 neu erstellt werden und funktionierte erfolgreich darin.
Der einzige unverständliche Moment: Beim Laden einer neuen Binärdatei unter NIOS II in IDA 7 findet die erste automatische Analyse in IDA 6.9 nicht statt.Fazit
Zusätzlich zu den grundlegenden Demontagefunktionen, von denen Beispiele im SDK enthalten sind, implementiert das Prozessormodul viele verschiedene Funktionen, die die Arbeit des Code-Explorers erleichtern. Es ist klar, dass dies alles manuell erfolgen kann, aber wenn zum Beispiel Tausende und Zehntausende von Offsets unterschiedlichen Typs in einer Binärdatei mit einer Firmware von einigen Megabyte vorhanden sind, warum sollte man Zeit damit verbringen? Lassen Sie das Prozessormodul dies für uns tun. Wie sind die angenehmen Eigenschaften einer schnellen Navigation durch den untersuchten Code unter Verwendung von Querverweisen? Dies macht IDA zu einem so bequemen und unterhaltsamen Tool, wie wir es kennen.Gepostet von Anton Dorfman, Positive Technologies