Angr
Ein Teil dieses Spickzettels basiert auf der angr-Dokumentation.
Installation
Grundlegende Aktionen
Load Binary
Binärdatei laden
To start using angr, you need to load a binary file. You can do this by using the angr.Project
class and passing the path to the binary as a parameter. Angr will automatically analyze the binary and create a project object that you can use to perform various actions.
Um angr zu verwenden, müssen Sie eine Binärdatei laden. Dies können Sie tun, indem Sie die Klasse angr.Project
verwenden und den Pfad zur Binärdatei als Parameter übergeben. Angr analysiert automatisch die Binärdatei und erstellt ein Projektobjekt, das Sie für verschiedene Aktionen verwenden können.
Symbolically Execute Code
Code symbolisch ausführen
One of the main features of angr is its ability to symbolically execute code. Symbolic execution allows you to explore all possible paths through a program, even if you don't have concrete input values. This can be useful for analyzing and understanding the behavior of a program.
Eine der Hauptfunktionen von angr ist die symbolische Ausführung von Code. Die symbolische Ausführung ermöglicht es Ihnen, alle möglichen Pfade durch ein Programm zu erkunden, auch wenn Sie keine konkreten Eingabewerte haben. Dies kann nützlich sein, um das Verhalten eines Programms zu analysieren und zu verstehen.
Find Functions
Funktionen finden
Angr provides a convenient way to find functions within a binary. You can use the project.kb.functions
attribute to access a dictionary of all the functions in the binary. Each function is represented by an angr.knowledge_plugins.Function
object, which contains information such as the function's address, name, and arguments.
Angr bietet eine bequeme Möglichkeit, Funktionen in einer Binärdatei zu finden. Sie können das Attribut project.kb.functions
verwenden, um auf ein Wörterbuch aller Funktionen in der Binärdatei zuzugreifen. Jede Funktion wird durch ein angr.knowledge_plugins.Function
-Objekt repräsentiert, das Informationen wie die Adresse, den Namen und die Argumente der Funktion enthält.
Find Basic Blocks
Grundblöcke finden
In addition to functions, angr can also help you find basic blocks within a binary. A basic block is a sequence of instructions with a single entry point and a single exit point. You can use the project.factory.block
method to retrieve a basic block at a specific address.
Neben Funktionen kann angr Ihnen auch dabei helfen, Grundblöcke in einer Binärdatei zu finden. Ein Grundblock ist eine Sequenz von Anweisungen mit einem einzigen Einstiegspunkt und einem einzigen Ausgangspunkt. Sie können die Methode project.factory.block
verwenden, um einen Grundblock an einer bestimmten Adresse abzurufen.
Find Memory References
Speicherreferenzen finden
Angr can also help you find memory references within a binary. You can use the project.factory.memory
attribute to access a representation of the binary's memory. This representation allows you to query the memory for specific addresses and retrieve the values stored at those addresses.
Angr kann Ihnen auch dabei helfen, Speicherreferenzen in einer Binärdatei zu finden. Sie können das Attribut project.factory.memory
verwenden, um auf eine Darstellung des Speichers der Binärdatei zuzugreifen. Diese Darstellung ermöglicht es Ihnen, den Speicher nach bestimmten Adressen abzufragen und die Werte abzurufen, die an diesen Adressen gespeichert sind.
Manipulate Memory
Speicher manipulieren
In addition to reading values from memory, angr also allows you to manipulate the memory of a binary. You can use the project.factory.memory.store
method to store a value at a specific address in the binary's memory.
Neben dem Lesen von Werten aus dem Speicher ermöglicht es angr Ihnen auch, den Speicher einer Binärdatei zu manipulieren. Sie können die Methode project.factory.memory.store
verwenden, um einen Wert an einer bestimmten Adresse im Speicher der Binärdatei zu speichern.
Solve Constraints
Bedingungen lösen
Angr can also help you solve constraints within a binary. Constraints are conditions that must be satisfied for a specific path through the program to be taken. You can use the project.factory.path_group
method to create a group of paths and then use the group.satisfiable
method to check if the constraints are satisfiable.
Angr kann Ihnen auch dabei helfen, Bedingungen in einer Binärdatei zu lösen. Bedingungen sind Bedingungen, die erfüllt sein müssen, damit ein bestimmter Pfad durch das Programm eingenommen wird. Sie können die Methode project.factory.path_group
verwenden, um eine Gruppe von Pfaden zu erstellen, und dann die Methode group.satisfiable
verwenden, um zu überprüfen, ob die Bedingungen erfüllbar sind.
Geladene Daten
The loaded data refers to the information that is loaded into the memory when a program is executed. This includes the program's code, libraries, and any other resources that are required for its execution.
Die geladenen Daten beziehen sich auf die Informationen, die in den Speicher geladen werden, wenn ein Programm ausgeführt wird. Dies umfasst den Programmcode, Bibliotheken und alle anderen Ressourcen, die für die Ausführung erforderlich sind.
Main Object
The main object is the entry point of a program. It is the first object that is executed when the program starts running. The main object typically contains the main function, which is responsible for initiating the program's execution.
Das Hauptobjekt ist der Einstiegspunkt eines Programms. Es ist das erste Objekt, das ausgeführt wird, wenn das Programm gestartet wird. Das Hauptobjekt enthält in der Regel die Hauptfunktion, die für die Initiierung der Programmausführung verantwortlich ist.
Hauptziel
The main objective of this document is to provide an introduction to the basic usage of angr, a powerful binary analysis framework. This guide will cover the installation process, basic concepts, and common use cases of angr. By the end of this document, you should have a good understanding of how to use angr to analyze and manipulate binary files.
Hauptziel
Das Hauptziel dieses Dokuments ist es, eine Einführung in die grundlegende Verwendung von angr zu bieten, einem leistungsstarken Framework zur Analyse von Binärdateien. Diese Anleitung behandelt den Installationsprozess, grundlegende Konzepte und häufige Anwendungsfälle von angr. Am Ende dieses Dokuments sollten Sie ein gutes Verständnis dafür haben, wie Sie angr verwenden können, um Binärdateien zu analysieren und zu manipulieren.
Symbole und Relokationen
Symbole und Relokationen sind wichtige Konzepte in der Reverse Engineering-Welt. Sie helfen dabei, den Code zu verstehen und zu analysieren.
Symbole
Symbole sind Namen, die bestimmten Speicheradressen zugeordnet sind. Sie dienen dazu, Funktionen, Variablen und andere Codeelemente zu identifizieren. Symbole können in verschiedenen Formen auftreten, wie zum Beispiel Funktionssymbole, Variablensymbole oder Konstantensymbole.
Die Verwendung von Symbolen erleichtert die Lesbarkeit und Analyse des Codes erheblich. Anstatt sich mit reinen Speicheradressen auseinandersetzen zu müssen, können wir uns auf die Namen der Symbole beziehen, um den Code besser zu verstehen.
Relokationen
Relokationen sind Anweisungen im Code, die es dem Betriebssystem ermöglichen, den Code an unterschiedliche Speicheradressen zu verschieben. Dies ist besonders wichtig, wenn der Code in eine andere Umgebung geladen wird, wie zum Beispiel bei der Ausführung einer ausführbaren Datei.
Relokationen werden verwendet, um die Adressen von Symbolen anzupassen, wenn der Code an eine neue Speicheradresse verschoben wird. Dadurch bleibt der Code funktionsfähig, unabhängig von der tatsächlichen Speicheradresse.
Beim Reverse Engineering ist es wichtig, Relokationen zu verstehen, um den Code korrekt zu analysieren. Durch die Analyse der Relokationen können wir die ursprünglichen Speicheradressen der Symbole ermitteln und den Code besser verstehen.
Zusammenfassung
Symbole und Relokationen sind grundlegende Konzepte im Reverse Engineering. Symbole helfen dabei, den Code lesbarer zu machen, indem sie Namen für Speicheradressen bereitstellen. Relokationen ermöglichen es dem Code, an unterschiedliche Speicheradressen angepasst zu werden, um seine Funktionalität beizubehalten. Das Verständnis von Symbole und Relokationen ist entscheidend, um den Code erfolgreich zu analysieren.
Blöcke
Blocks sind die grundlegenden Bausteine in der angr-Bibliothek. Ein Block repräsentiert einen Abschnitt des Programms, der von einer bestimmten Adresse aus ausgeführt wird. Jeder Block enthält eine Anweisung, die an dieser Adresse ausgeführt wird, und einen Satz von Nachfolgerblöcken, die die möglichen nächsten Anweisungen darstellen.
Ein Block kann verschiedene Arten von Anweisungen enthalten, wie z.B. bedingte Sprünge, unbedingte Sprünge oder Rückkehrbefehle. Die Nachfolgerblöcke eines Blocks werden durch die möglichen Pfade bestimmt, die das Programm von diesem Block aus nehmen kann.
Die angr-Bibliothek ermöglicht es Ihnen, Blöcke zu erstellen, zu manipulieren und zu analysieren. Sie können Blöcke verwenden, um den Programmfluss zu modellieren und verschiedene Analysetechniken anzuwenden, um Informationen über das Programm zu gewinnen.
Die angr-Bibliothek bietet auch Funktionen zum Durchlaufen von Blöcken und zum Sammeln von Informationen über die Anweisungen in jedem Block. Sie können diese Informationen verwenden, um den Programmfluss zu verfolgen, Bedingungen zu analysieren und andere Reverse-Engineering-Aufgaben durchzuführen.
Insgesamt sind Blöcke ein wichtiges Konzept in der angr-Bibliothek und spielen eine zentrale Rolle bei der Analyse und Manipulation von Programmen.
Simulation Manager, Zustände
Der Simulation Manager ist ein zentrales Konzept in der Angr-Bibliothek. Er ist verantwortlich für die Verwaltung der Zustände während der Ausführung einer binären Datei. Ein Zustand repräsentiert den aktuellen Zustand der Ausführung, einschließlich des Programmzählers, der Registerwerte und des Speicherinhalts.
Der Simulation Manager ermöglicht es uns, verschiedene Aktionen auf den Zuständen auszuführen, wie z.B. das Setzen von Eingabewerten, das Auslösen von Ereignissen und das Überwachen von Speicherzugriffen. Darüber hinaus kann der Simulation Manager mehrere Zustände gleichzeitig verwalten und zwischen ihnen wechseln, um verschiedene Pfade der Ausführung zu erkunden.
Execution Enginges
Die Angr-Bibliothek unterstützt verschiedene Ausführungsmotoren, die die Ausführung der binären Datei steuern. Jeder Ausführungsmotor implementiert eine bestimmte Methode zur Ausführung der Anweisungen und zur Verwaltung der Zustände.
Einige der unterstützten Ausführungsmotoren sind:
VEX: Ein leistungsstarker und flexibler Ausführungsmotor, der auf der VEX-IR (Intermediate Representation) basiert.
Unicorn: Ein CPU-Emulator, der die Ausführung von Maschinencode ermöglicht.
SimuVEX: Eine Kombination aus VEX und Unicorn, die die Vorteile beider Ausführungsmotoren vereint.
Jeder Ausführungsmotor hat seine eigenen Vor- und Nachteile, und die Wahl des richtigen Motors hängt von den spezifischen Anforderungen des Reverse Engineering-Projekts ab.
Symbolic Execution
Symbolische Ausführung ist eine Technik, die es uns ermöglicht, den Programmfluss zu analysieren, indem wir symbolische Werte anstelle konkreter Werte verwenden. Anstatt tatsächliche Eingabewerte zu verwenden, verwenden wir symbolische Symbole, um den Wertebereich der Eingabe zu repräsentieren.
Die Angr-Bibliothek unterstützt symbolische Ausführung durch die Verwendung von Symbolic Expressions. Eine Symbolic Expression ist eine abstrakte Darstellung einer Berechnung, die symbolische Symbole enthält. Durch die Manipulation von Symbolic Expressions können wir Bedingungen und Einschränkungen auf die Eingabe definieren und den Programmfluss analysieren, um bestimmte Pfade zu erreichen oder zu vermeiden.
Symbolische Ausführung ist besonders nützlich für die Suche nach Schwachstellen in einer binären Datei, da sie es uns ermöglicht, verschiedene Eingabewerte zu testen und potenzielle Sicherheitslücken zu identifizieren.
Concolic Execution
Concolic Execution ist eine Kombination aus konkreter und symbolischer Ausführung. Bei der konkreten Ausführung werden tatsächliche Eingabewerte verwendet, um den Programmfluss zu steuern. Bei der symbolischen Ausführung werden symbolische Symbole verwendet, um den Wertebereich der Eingabe zu repräsentieren.
Die Angr-Bibliothek unterstützt Concolic Execution durch die Verwendung von Concolic Tracers. Ein Concolic Tracer zeichnet den Programmfluss auf und speichert Informationen über die konkreten und symbolischen Werte, die während der Ausführung verwendet werden.
Concolic Execution ist besonders nützlich für die automatische Generierung von Testfällen und die Suche nach Sicherheitslücken, da sie es uns ermöglicht, den Programmfluss zu analysieren und potenzielle Schwachstellen zu identifizieren, indem wir verschiedene Eingabewerte testen.
Aufrufen von Funktionen
Sie können eine Liste von Argumenten über
args
und ein Wörterbuch von Umgebungsvariablen überenv
anentry_state
undfull_init_state
übergeben. Die Werte in diesen Strukturen können Zeichenketten oder Bitvektoren sein und werden als Argumente und Umgebung in den Zustand serialisiert, um die simulierte Ausführung durchzuführen. Das Standard-args
ist eine leere Liste, daher sollten Sie immer mindestens einargv[0]
bereitstellen, wenn das von Ihnen analysierte Programm erwartet, dass es vorhanden ist!Wenn Sie möchten, dass
argc
symbolisch ist, können Sie einen symbolischen Bitvektor alsargc
an die Konstruktorenentry_state
undfull_init_state
übergeben. Seien Sie jedoch vorsichtig: Wenn Sie dies tun, sollten Sie auch eine Einschränkung für den resultierenden Zustand hinzufügen, dass Ihr Wert fürargc
nicht größer sein darf als die Anzahl der Argumente, die Sie inargs
übergeben haben.Um den Aufrufzustand zu verwenden, sollten Sie ihn mit
.call_state(addr, arg1, arg2, ...)
aufrufen, wobeiaddr
die Adresse der Funktion ist, die Sie aufrufen möchten, undargN
das N-te Argument für diese Funktion ist, entweder als Python-Integer, Zeichenkette oder Array oder als Bitvektor. Wenn Sie Speicher zuweisen und tatsächlich einen Zeiger auf ein Objekt übergeben möchten, sollten Sie ihn in einen PointerWrapper einwickeln, d.h.angr.PointerWrapper("zeige auf mich!")
. Die Ergebnisse dieser API können etwas unvorhersehbar sein, aber wir arbeiten daran.
Bitvektoren
Symbolische Bitvektoren & Einschränkungen
Symbolische Bitvektoren sind ein wichtiges Konzept in der Angr-Toolbox. Sie ermöglichen es uns, den Zustand eines Programms symbolisch zu repräsentieren, anstatt konkrete Werte anzunehmen. Dies ermöglicht es uns, komplexe Bedingungen und Einschränkungen zu modellieren und zu analysieren.
Ein symbolischer Bitvektor besteht aus einer Sequenz von Bits, die entweder konkrete Werte oder symbolische Variablen repräsentieren können. Konkrete Werte sind bekannte Werte, während symbolische Variablen unbekannte Werte darstellen. Durch die Verwendung von symbolischen Bitvektoren können wir Bedingungen wie "x > 5" oder "y == z" darstellen, ohne die genauen Werte von x, y und z zu kennen.
Einschränkungen sind Bedingungen, die auf symbolische Bitvektoren angewendet werden. Sie können verwendet werden, um bestimmte Pfade im Programmfluss zu erzwingen oder um Bedingungen zu modellieren, die erfüllt sein müssen, damit ein bestimmtes Verhalten auftritt. Einschränkungen können mit logischen Operatoren wie AND, OR und NOT kombiniert werden, um komplexe Bedingungen zu erstellen.
Die Angr-Toolbox ermöglicht es uns, symbolische Bitvektoren zu erstellen, Einschränkungen zu definieren und sie auf verschiedene Weisen zu manipulieren. Wir können Einschränkungen lösen, um konkrete Werte für symbolische Variablen zu finden, oder wir können Einschränkungen kombinieren, um neue Einschränkungen zu erstellen. Dies ermöglicht es uns, verschiedene Szenarien zu modellieren und zu analysieren, um Schwachstellen in einem Programm zu finden.
Die Verwendung von symbolischen Bitvektoren und Einschränkungen ist ein leistungsstarkes Werkzeug in der Reverse-Engineering- und Sicherheitsforschung. Es ermöglicht uns, komplexe Programme zu analysieren und zu verstehen, indem wir den Programmfluss und die Bedingungen, die zu bestimmten Verhaltensweisen führen, modellieren. Durch die Kombination von symbolischen Bitvektoren und Einschränkungen können wir Schwachstellen und Sicherheitslücken identifizieren, die sonst schwer zu finden wären.
Hooking
Hooking ist eine Technik, bei der der normale Ablauf einer Anwendung geändert wird, um bestimmte Funktionen zu überwachen oder zu modifizieren. Dies wird oft von Hackern verwendet, um den Code einer Anwendung zu manipulieren und unerwünschte Aktionen auszuführen.
Es gibt verschiedene Arten von Hooks, darunter:
Function Hooking: Hierbei wird der Code einer bestimmten Funktion geändert, um zusätzlichen Code einzufügen oder den ursprünglichen Code zu ersetzen. Dies ermöglicht es Hackern, den Fluss der Anwendung zu kontrollieren und bestimmte Aktionen auszuführen.
System Call Hooking: Bei dieser Methode werden Systemaufrufe abgefangen und modifiziert, um den Zugriff auf bestimmte Ressourcen oder Funktionen zu steuern. Dies kann verwendet werden, um Sicherheitsmechanismen zu umgehen oder unerwünschte Aktionen auszuführen.
Inline Hooking: Hierbei wird der Code einer Anwendung direkt im Speicher geändert, um den Fluss der Anwendung zu beeinflussen. Dies ermöglicht es Hackern, bestimmte Funktionen zu überwachen oder zu modifizieren, ohne den ursprünglichen Code zu ändern.
Message Hooking: Diese Methode wird verwendet, um Nachrichten zwischen Anwendungen abzufangen und zu modifizieren. Dies kann verwendet werden, um die Kommunikation zwischen Anwendungen zu überwachen oder zu manipulieren.
Das Hooking kann sowohl für legitime Zwecke als auch für bösartige Aktivitäten eingesetzt werden. Es ist wichtig, sich der potenziellen Risiken bewusst zu sein und geeignete Sicherheitsmaßnahmen zu ergreifen, um unerwünschte Manipulationen zu verhindern.
Darüber hinaus können Sie proj.hook_symbol(name, hook)
verwenden, wobei Sie den Namen eines Symbols als ersten Argument angeben, um die Adresse zu haken, an der das Symbol vorhanden ist.
Beispiele
Last updated