Haben Sie schon einmal den Wunsch verspürt, einen Mechanismus auseinanderzunehmen, um herauszufinden, wie er funktioniert? Nun, wer hat das nicht. Dieser Wunsch ist die treibende Kraft beim Reverse Engineering. Diese Fähigkeit ist nützlich, um die Produktsicherheit zu analysieren, den Zweck einer verdächtigen .exe-Datei herauszufinden, ohne sie auszuführen, verlorene Dokumentation wiederherzustellen, eine neue Lösung auf der Grundlage von Legacy-Software zu entwickeln usw.
In diesem Artikel werden die Wissensbasis, die für die Durchführung von Reverse Engineering erforderlich ist, die Grundprinzipien des Reverse Engineering einer Windows-Software, Disassembler und Tools behandelt. Außerdem wird ein schrittweises Beispiel für das Reverse Engineering einer Anwendung gegeben.
Geschrieben von
Sergii Bratus,
Entwicklungskoordinator,
Netzwerksicherheitsteam
und
Anton Kukoba,
Sicherheitsforschungsleiter
Inhalt
Was ist Software-Reversing?
Was brauchen wir für Reverse Engineering?
Theoretisches Wissen. Software Reverse Engineering Prozess
Nützliche Tools für Reverse Engineering von Windows Software
Disassembler
Windows Sysinternals
Netzwerküberwachungs-Tools
Debugger
Real-Beispiel für Software-Reverse-Engineering
Wie man einen Treiber zurückentwickelt
Abschluss
- Was ist Software-Reversing?
- Was brauchen wir für Reverse Engineering?
- Theoretisches Wissen. Software-Reverse-Engineering-Prozess
- Nützliche Tools für das Reverse-Engineering von Windows-Software
- Disassembler
- Windows Sysinternals
- Netzwerküberwachungs-Tools
- Debugger
- Beispiel für Software-Reverse-Engineering im echten Leben
- Wie man einen Treiber zurückentwickelt
- Fazit
Was ist Software-Reversing?
Reverse Engineering ist der Prozess der Aufdeckung von Prinzipien hinter einer Hardware oder Software, wie z.B. ihrer Architektur und internen Struktur. Die Frage, die das Reverse Engineering antreibt, lautet: Wie funktioniert es?
Wenn man eine Dokumentation hat, wird der ganze Prozess natürlich viel einfacher. Aber es kommt oft vor, dass es keine Dokumentation gibt und man einen anderen Weg finden muss, um zu erfahren, wie eine Software funktioniert.
Wann kann es notwendig sein, eine Software zurückzuentwickeln, und wie kann Ihnen das helfen?
Es gibt viele Verwendungszwecke für Reverse Engineering im Bereich der Informatik, darunter:
- Untersuchung von Netzwerkkommunikationsprotokollen
- Finden von Algorithmen, die in Malware wie Computerviren, Trojanern, Ransomware usw. verwendet werden
- Untersuchung des Dateiformats, das zum Speichern von Informationen jeglicher Art verwendet wird, z. B. E-Mail-Datenbanken und Festplattenabbilder
- Überprüfung der Fähigkeit der eigenen Software, Reverse Engineering zu widerstehen
- Verbesserung der Softwarekompatibilität mit Plattformen und Software von Drittanbietern
- Nutzung nicht dokumentierter Plattformfunktionen
Die Rechtmäßigkeit von Reverse Engineering hängt von seinem Zweck und der Art der Verwendung der Software ab. Alle oben genannten Zwecke sind völlig legitim, vorausgesetzt, Sie haben eine Kopie der Software legal erworben. Wenn Sie aber beispielsweise beabsichtigen, eine bestimmte Funktion einer geschlossenen Anwendung zurückzuentwickeln und sie dann in eine andere Anwendung zu implementieren, werden Sie wahrscheinlich Probleme bekommen.
Was die rechtliche Dokumentation betrifft, so wird Reverse Engineering häufig durch Endbenutzer-Lizenzvereinbarungen (EULAs) verboten. Der US Digital Millennium Copyright Act legt jedoch fest, dass das Reverse Engineering einer Software legal ist, wenn es dazu dient, die Kompatibilität mit anderen Produkten zu verbessern.
Die rechtlichen Anforderungen variieren von Land zu Land, also nehmen Sie sich die Zeit, sie zu recherchieren, bevor Sie beginnen.
Lassen Sie uns nun sehen, wie man Software zurückentwickelt.
Was brauchen wir für Reverse Engineering?
Um mit dem Reverse Engineering von Software zu beginnen, brauchst du:
- Kenntnisse in dem Bereich, in dem du Reverse Engineering anwenden willst
- Werkzeuge, die es dir ermöglichen, dein Wissen anzuwenden, während du versuchst, Software zu zerlegen.
Lassen Sie uns ein allgemeines Beispiel betrachten, das nichts mit Software zu tun hat. Nehmen wir an, du hast eine Uhr und willst herausfinden, ob sie mechanisch, quarzgesteuert oder automatisch ist.
Wenn du dich auf diesem Gebiet auskennst, solltest du wissen, dass es drei Arten von Uhren gibt. Außerdem solltest du wissen, dass sich die Batterie im Inneren der Uhr befindet und du sie sehen kannst, wenn du sie öffnest. Du solltest auch grundlegende Kenntnisse über den inneren Aufbau einer Uhr haben, wissen, wie die Batterie aussieht und welche Werkzeuge du brauchst, um ein Uhrengehäuse zu öffnen. Die Werkzeuge zu haben, um dein Wissen anzuwenden, bedeutet, dass du einen Schraubenzieher oder ein anderes spezielles Werkzeug haben musst, das dir die Möglichkeit gibt, die Uhr zu öffnen.
Genauso wie das Reverse Engineering einer Uhr spezielle Fähigkeiten und Werkzeuge erfordert, benötigt das Reverse Engineering von Software eigene feldspezifische Kenntnisse und Werkzeuge.
Theoretisches Wissen. Software-Reverse-Engineering-Prozess
Für verschiedene Software-Reverse-Engineering-Aufgaben benötigt man unterschiedliche Arten von Wissen. Natürlich gibt es allgemeines Wissen, das Ihnen bei den meisten Reverse-Engineering-Aufgaben helfen wird: Wissen über gängige Anwendungsstrukturen, Programmiersprachen, Compiler usw. Ohne spezielles theoretisches Wissen können Sie jedoch keine spezifischen Reverse-Engineering-Aufgaben lösen.
Wenn Sie… |
Sie brauchen Kenntnisse über… |
jede Art von Netzwerkanwendungen |
Grundsätze der Kommunikation zwischen Prozessen, die Struktur von Netzwerken, Verbindungen, Netzwerkpaketen, etc. |
Umkehrung kryptographischer Algorithmen |
Kryptographie und die gängigsten Algorithmen, die in diesem Bereich verwendet werden |
Forschung von Datei- und Strukturen |
Grundlegende Dateikonzepte und wie verschiedene Systeme oder Komponenten mit Dateien arbeiten |
Spezielle Techniken können beim Rückgängigmachen spezieller Arten von Software viel Zeit sparen. Im Falle von Datei-Zusammenhängen kann ein Test, der eindeutige Werte in eine Datei schreibt, während die Offsets und die Datengröße in der eigentlichen Speicherdatei protokolliert werden, dabei helfen, gemeinsame Muster in den Offsets zu finden. Dies gibt Ihnen einen Hinweis auf die internen Strukturen dieser Dateien.
Beim Beginn eines Reverse-Engineering-Prozesses verwenden Softwareentwickler in der Regel einen Disassembler, um Algorithmen und Programmlogik an Ort und Stelle zu finden. Es gibt viele verschiedene Formate für ausführbare Dateien, Compiler (die unterschiedliche Ausgaben liefern) und Betriebssysteme. Diese Vielfalt an Technologien schließt die Verwendung einer einzigen Technologie für die Umkehrung aller Arten von Software aus.
Um den dekompilierten Code zu verstehen, benötigt man einige Kenntnisse der Assemblersprache, der Konventionen für Funktionsaufrufe, der Stack-Struktur, des Konzepts der Stack-Frames usw.
Die Kenntnis der Assembler-Ausgabe für verschiedene Code-Beispiele kann Ihnen helfen, die ursprüngliche Funktionalität aufzudecken. Betrachten wir einige Beispiele für die Windows x86-Plattform.
Angenommen, wir haben den folgenden Code:
Wenn wir diesen Code zu einer ausführbaren Datei kompilieren, sehen wir dies im Disassembler:
Wie wir sehen können, wurde der reguläre Zyklus in Assemblercode mit Vergleichen und Sprüngen umgewandelt. Beachten Sie, dass der Assemblercode nicht die reguläre Assemblerschleife mit dem Zähler im ecx-Register verwendet. Außerdem werden die lokalen Variablen hier als und bezeichnet.
Schauen wir uns an, was passiert, wenn wir diesen Code mit dem Release-Build kompilieren:
Dieses Stück Code sieht ganz anders aus als das vorherige. Das liegt daran, wie der Code optimiert wurde. Technisch gesehen wurde die Schleife entfernt, da sie nichts anderes tut, als die Zählvariable auf 10 zu inkrementieren. Daher hat der Optimierer beschlossen, den Endwert der Zählvariablen beizubehalten und den Wert direkt als Argument für den Zählausgabeoperator zu verwenden.
Die Compiler, die wir heutzutage verwenden, sind sehr gut im Optimieren von Code. Deshalb ist es beim Reverse Engineering besser, die Idee hinter dem Code (die Prinzipien des Codes) zu verstehen, als zu versuchen, den Originalcode selbst zu bekommen. Wenn man die Idee hinter dem Code versteht, kann man einfach seinen eigenen Prototyp schreiben, der zur ursprünglichen Aufgabe passt.
Es ist sehr nützlich zu wissen, welchen Assemblercode man erhält, wenn man verschiedene Operatoren, Strukturen und andere Sprachkonstruktionen kompiliert. Das Verständnis des resultierenden Assembler-Codes ist eine gute Möglichkeit, den C++-Reverse-Engineering-Prozess zu beginnen, aber wir werden hier nicht auf technische Details eingehen.
Nützliche Tools für das Reverse-Engineering von Windows-Software
Wir haben bereits mehrere Reverse-Engineering-Tools, einschließlich ProcessMonitor und ProcessExplorer, in unserer Anwendungsarchitekturforschung beschrieben. Diese Tools sind für das Reverse Engineering absolut unverzichtbar.
In diesem Abschnitt stellen wir die beliebtesten Disassembler und einige weitere Tools vor, die wir für unsere Reverse-Engineering-Projekte verwenden.
Weitere Details und Anwendungsbeispiele finden Sie in unserem Artikel über die besten Software-Reverse-Engineering-Tools.
Disassembler
Ein Disassembler ist ein Programm, das eine ausführbare Datei in Assemblersprache übersetzt. Das populärste ist IDA Pro
IDA Pro
IDA Pro
IDA Pro ist ein bequemes und leistungsfähiges Werkzeug für die Disassemblierung. Es verfügt über eine große Anzahl von Instrumenten, die es Ihnen ermöglichen, ein Stück Software schnell zu disassemblieren. Es kann den Funktionsaufrufbaum anzeigen, Import und Export der ausführbaren Datei analysieren und Informationen dazu anzeigen. Es kann sogar den Code in C anzeigen. Außerdem unterstützt es mehrere CPU-Architekturen, so dass es möglich ist, IDA Pro zu verwenden, um Code für ARM, AVR, M68k und viele andere Architekturen zurückzuentwickeln.
Radare
Radare
Der Radare Disassembler ist eine Alternative zu IDA. Er hat im Grunde alle IDA-Funktionen, ohne so robust und stabil zu sein. Aber er ist frei und quelloffen. Radare selbst ist ein Konsolenwerkzeug, aber es hat ein Cutter-Frontend, was es zu einer echten Alternative zu IDA macht.
Windows Sysinternals
Windows Sysinternals Dienstprogramme werden im Allgemeinen für die Verwaltung, Diagnose, Fehlersuche und Überwachung der Microsoft Windows Umgebung verwendet. Sie eignen sich aber auch für das Reverse Engineering von Windows-Software.
TCPView ist ein Netzwerk-Sniffer, der alle Informationen über TCP/UDP-Pakete von allen Prozessen anzeigt. Dieses Tool ist nützlich für das Reverse Engineering von Netzwerkprotokollen.
PortMon ist ein physischer Systemportmonitor. Es überwacht serielle und parallele Ports und den gesamten Verkehr, der über sie läuft.
WinObj zeigt alle globalen Objekte im System in einer hierarchischen Struktur an. Dieses Tool kann nützlich sein, wenn man eine Anwendung, die mit Synchronisationsprimitiven wie Mutexen und Semaphoren arbeitet, rückgängig macht, und auch beim Reverse Engineering von Kernel-Mode-Treibern.
Netzwerküberwachungs-Tools
Wireshark
Wireshark
Wireshark ist einer der leistungsfähigsten Netzwerk-Sniffer. Es ermöglicht nicht nur die Erfassung des Netzwerkverkehrs, sondern enthält auch Parser für verschiedene Netzwerkprotokolle, angefangen von sehr einfachen wie Ethernet, TCP und IP bis hin zu anwendungsspezifischen Protokollen wie WebSockets und XMPP.
Fiddler
Fiddler
Fiddler ist ein Web-Proxy, der den Verkehr von Browsern aufzeichnet und die Analyse von HTTP/HTTPS-Anfragen ermöglicht. Im Gegensatz zu Wireshark zeigt er HTTP-Sitzungen anstelle von einzelnen Netzwerkpaketen an. Fiddler ermöglicht auch die Analyse von komprimierten Daten, die über HTTP gesendet werden, sowie die Analyse von JSON- und XML-Daten bei der Überwachung von SOAP-, REST- und AJAX-Anfragen.
API Monitor
API Monitor
API Monitor ist ein nützliches Tool, um herauszufinden, welche APIs von einer Anwendung aufgerufen werden und welches Verhalten die Anwendung von diesen APIs erwartet. Dieses Tool verfügt über eine leistungsfähige Datenbank und ermöglicht es Ihnen, die Aufrufe einer großen Anzahl von API-Funktionen nicht nur von kernel32 und ntdll, sondern auch von COM, Managed Environment und anderen zu sehen. Außerdem bietet API Monitor praktische Filtermechanismen.
Debugger
Ein Debugger ist für jeden Entwickler von unschätzbarem Wert, um zu sehen, was ein Programm gerade tut. Das Debuggen beim Rückgängigmachen von Anwendungen hat den gleichen Nutzen wie das Debuggen von laufenden Anwendungen.
Die beliebtesten Debugger sind OllyDbg, WinDbg und Windbg Preview.
OllyDbg
OllyDBG
OllyDbg (und sein Nachfolger x64dbg) ist wahrscheinlich der beste Debugger, wenn es um Software Reverse Engineering geht. Er wurde speziell für die Bedürfnisse des Reverse Engineering entwickelt und verfügt über alle Werkzeuge, die für diesen Zweck benötigt werden:
- ein eingebauter Disassembler mit der Fähigkeit, wichtige Datenstrukturen zu analysieren und zu identifizieren
- eine Import- und Export-Analysefunktion
- eine eingebaute Assemblierungs- und Patching-Engine
Die Fähigkeit, API-Funktionen und ihre Parameter zu analysieren, macht es einfach, Interaktionen mit einem System rückgängig zu machen. Die Stack-Ansicht liefert viele Informationen über den Aufrufstapel. Ein weiterer wichtiger Vorteil ist, dass man OllyDbg mit debuggeschützten Anwendungen verwenden kann, wenn die üblichen Debugger einfach nichts tun können.
WinDbg
Windbg
Trotz seiner einfachen Oberfläche hat WinDbg mächtige Werkzeuge zum Debuggen. Es hat einen eingebauten Disassembler, verschiedene Befehle, die es Ihnen erlauben, fast alles über den Prozess/das System zu wissen, das Sie debuggen, und die Fähigkeit, Kernel-Mode-Debugging zu betreiben, was wahrscheinlich die wertvollste Funktion ist. Es ist ein großer Vorteil für das Umkehren von Treibern, insbesondere von Kernel-Mode-Treibern.
Windbg Preview
Windbg Preview
Windbg Preview ist eine neue Version von Windbg, die von Microsoft entwickelt wurde. Sie wird nur über den Windows Store vertrieben. Es hat alle Funktionen des klassischen Windbg, gepaart mit einer neuen Benutzeroberfläche und mehreren neuen Funktionen. Eine dieser neuen Funktionen ist das Time Travel Debugging, mit dem Sie einen bestimmten Zeitraum der Programmausführung aufzeichnen und dann so oft wie nötig wiedergeben können. Auf diese Weise können Sie die interessanten Teile des Codes schrittweise ausführen, ohne Angst haben zu müssen, versehentlich Code auszuführen und den Kontext oder alle Daten zu verlieren.
Lesen Sie auch:
9 Beste Reverse-Engineering-Tools für 2018
Beispiel für Software-Reverse-Engineering im echten Leben
Nun sehen wir uns ein Beispiel dafür an, wie man ein Stück Software zurückentwickelt. Nehmen wir an, Sie haben eine verdächtige ausführbare Datei. Sie müssen herausfinden, was dieses Programm tut und ob es für die Benutzer sicher ist.
In Anbetracht des Szenarios ist es eine gute Idee, diese ausführbare Datei nicht auf Ihrem Arbeitscomputer auszuführen, sondern stattdessen eine virtuelle Maschine zu verwenden. Starten wir die Anwendung in unserer virtuellen Maschine.
Prozess erstellt einen Dienst
Wie wir sehen können, erstellt diese Datei einen Windows-Dienst namens TestDriver. Er hat den Typ Kernel, so dass wir wissen, dass es sich um einen Treiber handelt. Aber woher nimmt er die Treiberdatei, um ausgeführt werden zu können? Wir können ProcessMonitor aus der Sysinternals Suite verwenden, um das herauszufinden. Wenn wir ProcessMonitor öffnen, können wir Filter einrichten, die uns nur die Dateiaktivitäten des Prozesses anzeigen, der uns interessiert. Das Aktivitätsprotokoll sieht folgendermaßen aus:
FileMon information
Die Treiberdatei wird von dem Prozess erstellt, den wir rückgängig machen wollen, und dieser Prozess legt diese Datei im Temp-Verzeichnis des Benutzers ab. Es ist nicht nötig, im Temp-Ordner nach der Datei zu suchen, da der Prozess sie nach der Verwendung sofort löscht. Was macht der Prozess nun mit dieser Datei? Wenn er die Datei entpackt, können wir versuchen, sie im Ressourcenbereich des Prozesses zu finden, da dies ein üblicher Ort ist, um solche Daten zu speichern. Schauen wir dort nach. Wir werden ein anderes Tool – Resource Hacker – verwenden, um die Ressourcen zu untersuchen. Starten wir es:
Untersuche Ressourcen mit Resource Hacker
Bingo! Wie wir aus dem gefundenen Ressourceninhalt ersehen können, handelt es sich wahrscheinlich um die ausführbare Windows-Datei, da sie mit einer MZ-Signatur beginnt und die Zeichenfolge „Dieses Programm kann nicht im DOS-Modus ausgeführt werden“ enthält. Lassen Sie uns überprüfen, ob es sich um unsere Treiberdatei handelt. Zu diesem Zweck extrahieren wir die Ressource mit Resource Hacker und öffnen sie im Disassembler.
Disassembler-Bildschirm
Wie wir wissen, ist DriverEntry der Einstiegspunkt für Kernel-Mode-Treiber in Windows-Systemen. Wir können unsere Nachforschungen fortsetzen, denn es sieht so aus, als hätten wir den richtigen Treiber gefunden.
Wie man einen Treiber zurückentwickelt
Um mit dem Reverse Engineering des Treibers zu beginnen, untersuchen wir die Funktionen, die von DriverEntry aufgerufen werden, eine nach der anderen. Wenn wir zu sub_14005 gehen, finden wir nichts Interessantes, also fahren wir mit sub_110F0 fort und finden diesen Code:
Codestück 1
Codestück 2
Codestück 3
Codestück 4
Einige Zeilen werden hier der Einfachheit halber weggelassen.
Im ersten Listing wird ein Unicode-String erstellt, der auf den Pfad C:\hello.txt zeigt. Danach wird die Struktur OBJECT_ATTRIBUTES mit regulären Werten gefüllt; wir wissen, dass diese Struktur oft benötigt wird, wenn Funktionen wie ZwCreateFile aufgerufen werden.
Im zweiten Listing sehen wir, dass ZwCreateFile tatsächlich aufgerufen wird, was uns ziemlich sicher macht, dass der Treiber die Datei erstellt – und wir wissen, wo sich diese Datei nach dem Erstellen befindet.
Aus dem dritten und vierten Listing können wir ersehen, dass der Treiber die Unicode-Zeichenkette nimmt und in den Puffer schreibt (dies geschieht in der Funktion sub_11150), und der Puffer wird mit der Funktion ZwWriteFile in die Datei geschrieben. Am Ende schließt der Treiber die Datei mit der ZwClose API.
Fassen wir zusammen. Wir haben herausgefunden, dass das Originalprogramm die Treiberdatei aus seinen Ressourcen extrahiert, sie im Temp-Ordner des aktuellen Benutzers ablegt, den Windows-Dienst für diesen Treiber erstellt und ihn ausführt. Danach stoppt das Programm und löscht den Dienst und die ursprüngliche Treiberdatei aus dem temporären Verzeichnis. Aus diesem Verhalten und aus der Analyse der Disassemblierung geht hervor, dass der Treiber nichts anderes tut, als eine Datei auf dem Laufwerk C mit dem Namen hello.txt zu erstellen und die Zeichenfolge „Hello from driver“ zu schreiben.
Nun müssen wir überprüfen, ob wir richtig liegen. Starten wir das Programm und überprüfen wir das Laufwerk C:
Anwendungsbildschirm
Wunderbar! Wir haben dieses einfache Programm zurückentwickelt und wissen jetzt, dass es sicher zu benutzen ist.
Wir hätten dieses Ergebnis auf viele verschiedene Arten erreichen können – mit Debugging oder API Mon, durch das Schreiben von Tests, usw. Sie können Ihre eigenen Wege zum Reverse Engineering von Software finden, die für Sie funktionieren.
Fazit
Windows Software Reverse Engineering erfordert einen soliden Bildungshintergrund und Programmiererfahrung. Um Reverse Engineering durchführen zu können, müssen Sie Fähigkeiten in den Bereichen Disassemblierung, Netzwerküberwachung, Debugging, API-Integration, verschiedene Programmiersprachen, Compiler usw. kombinieren. Außerdem müssen Sie beim Reverse Engineering von Software sehr vorsichtig sein, um keine Urheberrechte zu verletzen oder Ihr System zu beschädigen.
Bei Apriorit verfügen wir über ein erfahrenes Team von Reverse Engineers. Wenn Sie Reverse-Engineering-Fähigkeiten auf Ihr Projekt anwenden möchten, können Sie sich gerne mit uns in Verbindung setzen!