Reverse Engineering
Python-basierte Executables entpacken: Von PE und ELF zurück zum Sourcecode
Ein praxisnaher Workflow zum Erkennen, Extrahieren und Dekompilieren von PyInstaller-Executables unter Windows und Linux – vom Binary bis zum möglichst ursprünglichen Python-Sourcecode.
Eine unbekannte .exe landet auf dem Tisch, Detect It Easy meldet Python oder PyInstaller und beim Öffnen in IDA oder Ghidra sieht man hauptsächlich Bootloader-Code.
Die gute Nachricht: Wenn es sich tatsächlich um eine mit PyInstaller erzeugte Anwendung handelt, müssen wir diesen nativen Stub meistens gar nicht vollständig reverse engineeren.
Der eigentliche Python-Code steckt in vielen Fällen weiterhin als CPython-Bytecode innerhalb der Executable.
Unser Ziel sieht vereinfacht so aus:
sample.exebeziehungsweise ein Linux-Binary untersuchen- PyInstaller erkennen
- Das interne Archiv extrahieren
- Den Entry Point wie
main.pycfinden - Den Python-Bytecode dekompilieren
- Den rekonstruierten Code als
main.pyanalysieren
Unter Windows handelt es sich normalerweise um ein PE – Portable Executable. Unter Linux steckt dasselbe Prinzip in einem ELF – Executable and Linkable Format.
Dieser Artikel zeigt beide Varianten und beginnt bewusst bei null.
Am Ende solltest du auch ohne vorherige Erfahrung verstehen, wie du aus einer Python-basierten Executable wieder möglichst nah an den ursprünglichen Python-Sourcecode kommst.
Erst einmal: Was steckt überhaupt in einer Python-EXE?
Python wird normalerweise nicht wie C oder C++ direkt zu nativem Maschinencode kompiliert.
Aus:
print("Hello from AetherSec")
entsteht zunächst CPython-Bytecode. Vereinfacht läuft das in drei Schritten ab:
script.py- CPython-Compiler
script.pyc
Eine .pyc enthält Bytecode für die Python Virtual Machine.
Tools wie PyInstaller nehmen anschließend unter anderem:
- den Python-Bytecode
- benötigte Python-Module
- Libraries
- Ressourcen
- Teile der Python-Runtime
- einen nativen Bootloader
und bauen daraus eine eigenständig startbare Anwendung.
In einer solchen Datei befinden sich typischerweise der PyInstaller-Bootloader, die Python-Runtime, Module und Abhängigkeiten sowie ein CArchive oder PYZ-Archiv mit Dateien wie main.pyc, requests.pyc und config.pyc.
PyInstaller verwendet dafür eigene CArchive- und PYZ/ZlibArchive-Strukturen, in denen Python-Module gespeichert werden. Die offiziellen PyInstaller-Tools können diese Archive ebenfalls anzeigen.
Das ist ein wichtiger Unterschied:
PyInstaller ist primär ein Packaging-System und kein Schutzmechanismus gegen Reverse Engineering.
Eine mit PyInstaller erzeugte .exe sieht von außen wie ein kompiliertes natives Programm aus – intern kann der ursprüngliche Python-Bytecode aber weiterhin vorhanden sein.
Wichtig: Nicht jede Python-Executable ist PyInstaller
Bevor wir irgendetwas extrahieren, müssen wir herausfinden, womit die Anwendung gebaut wurde.
Neben PyInstaller existieren beispielsweise:
- Nuitka
- cx_Freeze
- py2exe
- Cython
- Briefcase
Der Workflow aus diesem Artikel konzentriert sich auf PyInstaller.
Besonders Nuitka und Cython sind ein anderes Thema, da Python dort deutlich stärker in nativen Code übersetzt werden kann.
Wenn pyinstxtractor also meldet:
Not a PyInstaller archive
bedeutet das nicht automatisch, dass das Tool kaputt ist. Vielleicht ist die Datei schlicht kein PyInstaller-Binary.
Vorbereitung: Nicht einfach unbekannte Executables starten
Bei Reverse Engineering gilt dasselbe wie bei Malware-Analyse:
Eine unbekannte Binary gehört nicht auf das Host-System.
| Komponente | Empfehlung |
|---|---|
| Umgebung | isolierte VM |
| Snapshot | vor der Analyse |
| Netzwerk | deaktiviert oder kontrolliert |
| Shared Folders | möglichst deaktiviert |
| Hash | vor der Analyse dokumentieren |
| Ausführung | für diesen Workflow normalerweise nicht notwendig |
Unter Linux:
sha256sum sample.exe
Unter Windows PowerShell:
Get-FileHash .\sample.exe -Algorithm SHA256
Für das eigentliche Extrahieren müssen wir die Executable normalerweise nicht starten.
Phase 1: Herausfinden, womit wir es zu tun haben
Windows PE
Unter Linux, WSL oder REMnux:
file sample.exe
Eine typische Ausgabe könnte sein:
sample.exe: PE32+ executable (console) x86-64, for MS Windows
Zusätzlich lohnt sich Detect It Easy:
diec sample.exe
Je nach Sample kann DIE bereits Hinweise wie diese liefern:
Compiler: Microsoft Visual C/C++
Packer: PyInstaller
Language: Python
Alternativ können wir Strings durchsuchen:
strings -a sample.exe | grep -Ei 'pyinstaller|pyiboot|pyz|_MEI'
Unter Windows:
strings.exe sample.exe | findstr /i "pyinstaller pyiboot PYZ _MEI"
Interessante Strings sind beispielsweise:
PYZ-00.pyz
pyiboot01_bootstrap
pyimod01_archive
_MEIPASS
Ein einzelner String beweist noch nichts – mehrere typische PyInstaller-Artefakte sind aber ein ziemlich guter Hinweis.
Linux ELF
Unter Linux geht es genauso los:
file sample
Beispiel:
sample: ELF 64-bit LSB pie executable, x86-64, dynamically linked
Danach:
strings -a sample | grep -Ei 'pyinstaller|pyiboot|pyz|_MEI'
Optional:
readelf -S sample
readelf -d sample
Damit sehen wir zunächst nur die native ELF-Seite der Anwendung. Der Python-Code liegt normalerweise tiefer im eingebetteten PyInstaller-Archiv.
Phase 2: PyInstaller-Archiv untersuchen
Hier hat sich seit älteren Tutorials einiges verbessert.
Ein älterer Workflow bestand teilweise daraus, unter Linux zunächst eine eingebettete pydata-Section manuell aus dem ELF zu dumpen und erst anschließend den PyInstaller-Extractor darauf anzusetzen.
Das ist beim modernen Standardfall nicht mehr notwendig.
Die aktuelle Generation von pyinstxtractor-ng unterstützt sowohl Windows-PEs als auch Linux-ELFs direkt. Außerdem verwendet das Tool xdis, wodurch die Extraktion nicht mehr zwingend mit exakt derselben Python-Version ausgeführt werden muss, mit der das Zielprogramm erstellt wurde.
Variante A: pyinstxtractor-ng
Für einen modernen Workflow würde ich heute zuerst pyinstxtractor-ng verwenden.
Archiv zunächst nur untersuchen
Windows:
.\pyinstxtractor-ng.exe -i .\sample.exe
Linux:
./pyinstxtractor-ng -i ./sample
-i beziehungsweise --info zeigt Informationen über das gefundene PyInstaller-Archiv, ohne direkt alles zu extrahieren.
Eine Ausgabe kann sinngemäß so aussehen:
PyInstaller archive detected
Python version: 3.x
Package size: ...
Files: ...
Damit wissen wir bereits zwei wichtige Dinge:
- Ist es tatsächlich PyInstaller?
- Für welche Python-Version wurde der Bytecode erzeugt?
Archiv extrahieren
Windows:
.\pyinstxtractor-ng.exe .\sample.exe
Linux:
./pyinstxtractor-ng ./sample
Danach entsteht normalerweise ein Verzeichnis wie sample.exe_extracted oder sample_extracted.
Ein mögliches Ergebnis:
sample.exe_extracted/
main.pyc
pyiboot01_bootstrap.pyc
pyimod01_archive.pyc
python3.dll
base_library.zip
PYZ.pyz_extracted/
os.pyc
json.pyc
requests/
urllib/
Jetzt sind wir bereits aus der PE- beziehungsweise ELF-Ebene heraus. Ab diesem Punkt analysieren wir überwiegend Python-Bytecode.
Variante B: Klassisches pyinstxtractor
Der ursprüngliche pyinstxtractor.py funktioniert weiterhin und unterstützt moderne PyInstaller-Versionen sowie Linux-ELFs direkt. Beim klassischen Extractor sollte möglichst dieselbe Python-Version verwendet werden, mit der auch die Executable gebaut wurde.
Aufruf unter Windows:
python pyinstxtractor.py sample.exe
Oder unter Linux:
python3 pyinstxtractor.py sample
Typische Ausgabe:
[+] Processing sample.exe
[+] Pyinstaller version: ...
[+] Python version: ...
[+] Found ... files in CArchive
[+] Beginning extraction...
[+] Possible entry point: main.pyc
[+] Successfully extracted pyinstaller archive
Besonders interessant ist:
Possible entry point: main.pyc
Das ist häufig genau die Datei, die wir suchen.
Variante C: Offizielles PyInstaller-Tool
Wenn PyInstaller lokal installiert ist, existiert zusätzlich:
pyi-archive_viewer sample.exe
Beziehungsweise unter Linux:
pyi-archive_viewer sample
Der Viewer kann PyInstaller-Archive innerhalb von Windows-Executables und ELF-Binaries untersuchen.
Innerhalb des Viewers stehen unter anderem folgende Befehle zur Verfügung:
O <name> eingebettetes Archiv öffnen
X <name> Datei extrahieren
U eine Ebene zurück
Q beenden
Beispielsweise kann man PYZ-00.pyz öffnen und anschließend die enthaltenen Module untersuchen.
Für automatisierte Extraktion ist pyinstxtractor-ng meistens angenehmer. Für das manuelle Verständnis der Archivstruktur ist pyi-archive_viewer allerdings ziemlich praktisch.
Phase 3: Wo ist jetzt mein eigentliches Programm?
Nach der Extraktion liegen möglicherweise hunderte .pyc-Dateien vor.
Das sieht zunächst schlimmer aus, als es ist. Ein großer Teil davon gehört meistens zu:
- Python Standard Library
- Requests
- urllib
- PyQt oder Tkinter
- cryptography
- setuptools
- PyInstaller selbst
- anderen Dependencies
Wir suchen dagegen die Module, die der Entwickler selbst geschrieben hat.
Alle PYC-Dateien anzeigen
Linux:
find sample.exe_extracted -type f -name '*.pyc'
Windows PowerShell:
Get-ChildItem .\sample.exe_extracted -Recurse -Filter *.pyc
Ein Ergebnis könnte so aussehen:
main.pyc
config.pyc
crypto.pyc
network.pyc
pyiboot01_bootstrap.pyc
pyimod01_archive.pyc
PYZ.pyz_extracted/requests/api.pyc
PYZ.pyz_extracted/json/__init__.pyc
Hier wären main.pyc, config.pyc, crypto.pyc und network.pyc deutlich interessanter als die Standardbibliotheken.
Der Entry Point
pyinstxtractor beziehungsweise pyinstxtractor-ng kann häufig bereits mögliche Entry Points identifizieren.
Beispiel:
Possible entry point: pyiboot01_bootstrap.pyc
Possible entry point: main.pyc
pyiboot01_bootstrap.pyc gehört zu PyInstaller. main.pyc sieht dagegen nach unserem eigentlichen Programm aus.
Eine typische Importstruktur könnte so aussehen:
main.pyc- importiert
config - importiert
networking - importiert
crypto - importiert
gui
- importiert
Damit können wir uns vom Entry Point durch die Anwendung bewegen.
Phase 4: Aus .pyc wieder .py machen
Jetzt kommt der Teil, der bei älteren Tutorials oft unnötig kompliziert wird.
Das eigentliche Extrahieren von PyInstaller ist meistens relativ stabil. Das Dekompilieren des Python-Bytecodes ist schwieriger.
Der Grund: CPython-Bytecode verändert sich zwischen Python-Versionen teilweise erheblich. Besonders Python 3.10, 3.11, 3.12, 3.13 und 3.14 unterscheiden sich in verschiedenen Opcode- und Control-Flow-Details. CPython-Bytecode ist ein Implementierungsdetail und kann sich zwischen Releases verändern.
Deshalb:
Erst Python-Version bestimmen, dann passenden Decompiler auswählen.
Moderne Empfehlung: PyLingual
Für moderne Python-Versionen ist PyLingual eine der interessantesten Möglichkeiten.
PyLingual unterstützt nach Angaben des Projekts veröffentlichte CPython-Versionen ab Python 3.6 und kann sowohl über einen Webdienst als auch lokal verwendet werden.
Einfachster Weg: PyLingual im Browser
Wenn du eine extrahierte Datei wie main.pyc hast, kannst du sie auf pylingual.io hochladen.
Der Ablauf:
- PyInstaller-Binary mit
pyinstxtractor-ngextrahieren main.pycidentifizieren- Die Datei mit PyLingual dekompilieren
- Den rekonstruierten Inhalt als
main.pyanalysieren
Gerade bei neueren Python-Versionen ist das oft deutlich angenehmer, als viele ältere Decompiler nacheinander auszuprobieren. Der Dienst versucht außerdem, die verwendete Python-Version automatisch zu erkennen.
Achtung bei vertraulichem Code
Bei Malware-Samples, Firmen-Code oder anderen sensiblen Dateien sollte man grundsätzlich überlegen, ob man die .pyc auf einen externen Dienst hochladen möchte.
Für vertrauliche Samples ist die lokale Variante sauberer.
PyLingual lokal verwenden
Das Projekt kann auch lokal installiert werden.
git clone https://github.com/syssec-utd/pylingual.git
cd pylingual
uv tool install .
Eine Datei dekompilieren:
pylingual main.pyc
Ergebnisse in ein eigenes Verzeichnis schreiben:
pylingual -o recovered main.pyc
Das Ergebnis befindet sich anschließend beispielsweise unter recovered/main.py.
Mehrere Dateien können ebenfalls verarbeitet werden:
pylingual -o recovered main.pyc config.pyc networking.pyc
Damit lässt sich nach der PyInstaller-Extraktion Stück für Stück das ursprüngliche Projekt rekonstruieren.
Was ist mit uncompyle6?
Viele ältere Tutorials verwenden:
pip install uncompyle6
uncompyle6 main.pyc
Für ältere Python-Versionen ist das weiterhin interessant.
Das Problem: Neuere CPython-Versionen werden von uncompyle6 nicht vollständig unterstützt. Insbesondere bei Python 3.9 und neuer sollte man sich nicht auf dieses Tool allein verlassen.
Ein grober Entscheidungsweg:
| Bytecode | Erste Wahl |
|---|---|
| ältere Python-Versionen | uncompyle6 testen |
| Python 3.7 oder 3.8 | decompyle3 möglich |
| moderne Python-Versionen | PyLingual |
| unbekannte Version | PyLingual Auto Detection oder Extractor-Info |
| Decompiler scheitert | Bytecode manuell untersuchen |
decompyle3 ist insbesondere auf Python-3.7- und Python-3.8-Bytecode ausgerichtet.
Warum funktioniert mein .pyc nicht?
Das ist wahrscheinlich der häufigste Punkt, an dem Einsteiger hängen bleiben.
Du hast main.pyc, aber der Decompiler meldet beispielsweise:
Unsupported Python version
Invalid magic number
Marshal error
Oder er erzeugt nur unvollständigen Code. Dafür gibt es mehrere mögliche Ursachen.
Problem 1: Falsche Python-Version
PYC-Dateien besitzen eine versionsabhängige Kennung. Bytecode von Python 3.8 ist nicht dasselbe wie Bytecode von Python 3.12.
Wenn dein Extractor beispielsweise meldet:
Python version: 3.12
und dein Decompiler nur Python 3.8 versteht, wird das nicht funktionieren.
Die Lösung:
- Python-Version feststellen
- Decompiler mit passendem Support auswählen
- Bei modernen Versionen zunächst PyLingual testen
Problem 2: Falscher PYC-Header
Ein aus einem PyInstaller-Archiv extrahiertes Codeobjekt entspricht nicht immer exakt einer normalen .pyc, wie sie im __pycache__-Verzeichnis liegt.
Extractor wie pyinstxtractor reparieren beziehungsweise rekonstruieren die notwendigen Header bereits für viele Fälle.
Deshalb solltest du nicht einfach mit binwalk beliebige Bytebereiche herausschneiden und sie anschließend in something.pyc umbenennen. Benutze zuerst einen PyInstaller-spezifischen Extractor.
Problem 3: Es ist gar nicht dein Hauptprogramm
Wenn du versuchst, pyiboot01_bootstrap.pyc zu dekompilieren, bekommst du PyInstaller-internen Code. Das ist meistens nicht das, was du suchst.
Interessanter sind Namen wie:
main.pyc
app.pyc
client.pyc
server.pyc
bot.pyc
gui.pyc
config.pyc
Auch andere projektspezifische Modulnamen können relevant sein.
Problem 4: Der Decompiler rekonstruiert nur Teile
Auch ein korrekt extrahiertes .pyc garantiert keine perfekte Dekompilation.
Komplexe Konstruktionen können Probleme verursachen, zum Beispiel:
try:
process_data()
except ValueError:
handle_error()
finally:
cleanup()
Auch Generatoren, Pattern Matching, verschachtelte Closures oder stark veränderter Control Flow können die Rekonstruktion erschweren.
Dann kann das Ergebnis beispielsweise so aussehen:
def process_data(data):
...
# decompilation failed
Das bedeutet nicht, dass der Bytecode verloren ist. Nur die automatische Rückübersetzung ist gescheitert.
Dann lohnt es sich:
- einen zweiten Decompiler zu testen
- PyLingual zu testen
- das betreffende Codeobjekt als Bytecode zu disassemblieren
- die Funktion manuell zu rekonstruieren
Bytecode statt Sourcecode betrachten
Python besitzt selbst das Modul dis für die Darstellung von CPython-Bytecode.
Ein einfaches Beispiel:
def check_password(password):
return password == "AetherSec"
Der Bytecode kann sinngemäß Operationen wie diese enthalten:
LOAD_FAST
LOAD_CONST
COMPARE_OP
RETURN_VALUE
Selbst wenn kein Decompiler daraus wieder perfekten Python-Code baut, ist diese Repräsentation immer noch analysierbar.
Ein Python-Modul lässt sich beispielsweise so disassemblieren:
python -m dis recovered/main.py
Gerade bei Malware-Analyse reichen manchmal bereits Hinweise wie LOAD_GLOBAL requests, eine URL in LOAD_CONST und ein anschließender Aufruf, um zu verstehen, was eine Funktion macht.
Bekomme ich wirklich den originalen Sourcecode zurück?
Nicht exakt. Das ist wichtig.
Beim Erstellen des Bytecodes gehen Informationen verloren.
Beispielsweise:
# Diese Funktion prüft den Key
def check_key(key):
return key == SECRET_KEY
Der Kommentar existiert normalerweise nicht mehr im Bytecode. Auch die ursprüngliche Formatierung ist nicht rekonstruierbar.
Was wir zurückbekommen, ist ein rekonstruierter Python-Sourcecode, der funktional möglichst nah am ursprünglichen Programm liegt.
Typischerweise bleiben jedoch sehr viele wertvolle Informationen erhalten:
- Funktionsnamen
- Klassennamen
- Variablennamen
- Konstanten
- Strings
- Imports
- URLs
- Dateipfade
- Kontrollfluss
- Funktionsaufrufe
- große Teile der Programmlogik
Für Reverse Engineering ist das normalerweise mehr als ausreichend.
Windows: Komplettworkflow
Nehmen wir an, unsere Datei heißt sample.exe.
1. Hash erzeugen
Get-FileHash .\sample.exe -Algorithm SHA256
2. Strings prüfen
strings.exe .\sample.exe | findstr /i "pyinstaller pyiboot PYZ _MEI"
Optional mit Detect It Easy:
diec.exe .\sample.exe
3. PyInstaller-Archiv prüfen
.\pyinstxtractor-ng.exe -i .\sample.exe
4. Archiv extrahieren
.\pyinstxtractor-ng.exe .\sample.exe
5. PYC-Dateien suchen
Get-ChildItem .\sample.exe_extracted -Recurse -Filter *.pyc
6. Main-Modul identifizieren
Der Extractor nennt häufig einen möglichen Entry Point:
Possible entry point: main.pyc
Die relevante Datei wäre dann beispielsweise sample.exe_extracted\main.pyc.
7. Dekompilieren
Mit einer lokalen PyLingual-Installation:
pylingual -o .\recovered .\sample.exe_extracted\main.pyc
Alternativ kannst du nicht vertrauliche Dateien über pylingual.io dekompilieren.
8. Weitere eigene Module rekonstruieren
pylingual -o .\recovered .\sample.exe_extracted\config.pyc .\sample.exe_extracted\network.pyc
Linux: Komplettworkflow
Nehmen wir an, das ELF-Binary heißt sample.
1. Hash und Dateityp prüfen
sha256sum ./sample
file ./sample
2. Nach PyInstaller-Artefakten suchen
strings -a ./sample | grep -Ei 'pyinstaller|pyiboot|pyz|_MEI'
3. Archivinformationen anzeigen
./pyinstxtractor-ng -i ./sample
4. Archiv extrahieren
./pyinstxtractor-ng ./sample
5. PYC-Dateien suchen
find ./sample_extracted -type f -name '*.pyc'
6. Entry Point und eigene Module identifizieren
Achte in der Extractor-Ausgabe auf Possible entry point. Trenne anschließend projektspezifische Namen wie main.pyc, client.pyc oder config.pyc von PyInstaller- und Standardbibliotheksmodulen.
7. Dekompilieren
pylingual -o ./recovered ./sample_extracted/main.pyc
Mehrere Module lassen sich in einem Durchlauf verarbeiten:
pylingual -o ./recovered ./sample_extracted/main.pyc ./sample_extracted/config.pyc ./sample_extracted/network.pyc
Häufige Sonderfälle
One-file und One-folder
PyInstaller kann Anwendungen unter anderem im One-file- oder One-folder-Modus bauen.
Beim One-folder-Modus liegen viele Bestandteile bereits neben der Executable. Beim One-file-Modus stecken sie im Binary und werden beim Start normalerweise in ein temporäres Verzeichnis extrahiert.
Für die statische Analyse ist das kein Grund, das Sample zu starten: Ein PyInstaller-Extractor liest das eingebettete Archiv direkt.
Verschlüsselte oder obfuskierte Module
Einige Anwendungen verwenden zusätzliche Obfuskation, verschlüsselte PYZ-Inhalte oder Produkte wie PyArmor. Dann kann die Archivextraktion zwar funktionieren, der enthaltene Code ist aber nicht sofort sinnvoll dekompilierbar.
In diesem Fall sind weitere Schritte nötig, beispielsweise:
- Loader-Code untersuchen
- Schlüssel oder Entschlüsselungslogik identifizieren
- Module in einer isolierten Umgebung zur Laufzeit beobachten
- geladene Codeobjekte oder entschlüsselte Inhalte aus dem Speicher sichern
Das geht über den normalen PyInstaller-Workflow hinaus.
Kein PyInstaller gefunden
Wenn der Extractor kein Archiv erkennt, solltest du die ursprüngliche Annahme überprüfen:
- Erkennt Detect It Easy einen anderen Packager?
- Deuten Strings auf Nuitka, cx_Freeze, py2exe oder Cython hin?
- Wurde das Binary zusätzlich mit einem nativen Packer geschützt?
- Ist die Datei beschädigt oder unvollständig?
Bei Nuitka oder Cython ist eine klassische .pyc-Extraktion häufig nicht der richtige Ansatz.
Kompakte Checkliste
- Sample nicht auf dem Host-System starten.
- Hash dokumentieren und Dateityp bestimmen.
- Nach PyInstaller-Artefakten suchen.
- Archivinformationen mit
pyinstxtractor-nganzeigen. - Archiv statisch extrahieren.
- Entry Point und projektspezifische
.pyc-Dateien identifizieren. - Python-Version des Bytecodes beachten.
- Moderne Dateien zuerst mit PyLingual dekompilieren.
- Bei sensiblen Samples ausschließlich lokal arbeiten.
- Fehlgeschlagene Funktionen über Bytecode und
dismanuell untersuchen.
Fazit
Eine Python-basierte Windows- oder Linux-Executable ist häufig kein undurchsichtiger Block aus nativem Maschinencode. Wenn sie mit PyInstaller erstellt wurde, enthält sie in vielen Fällen weiterhin extrahierbaren CPython-Bytecode.
Der moderne Standardworkflow ist überschaubar:
- PE oder ELF identifizieren
- PyInstaller bestätigen
- Archiv mit
pyinstxtractor-ngextrahieren - Entry Point und eigene Module finden
.pycmit einem zur Python-Version passenden Tool dekompilieren- unvollständige Ergebnisse bei Bedarf über Bytecode analysieren
Dabei erhältst du nicht die ursprünglichen Kommentare oder exakt dieselbe Formatierung zurück. Funktionsnamen, Klassen, Strings, Imports, Konstanten und große Teile der Programmlogik bleiben aber oft erhalten.
Damit wird aus einer vermeintlich geschlossenen Executable wieder ein nachvollziehbares Python-Projekt – oder zumindest eine sehr gute Grundlage für die weitere Analyse.
Weiterführende Links
- Fortinet: Unpacking Python Executables on Windows and Linux
- pyinstxtractor-ng auf GitHub
- PyLingual
- PyLingual auf GitHub
- PyInstaller: pyi-archive_viewer
- Python-Dokumentation: dis
Nutze die beschriebenen Techniken ausschließlich für eigene Dateien, autorisierte Analysen, Forschung und legitime Incident-Response- oder Malware-Analyse-Szenarien.
Ich hoffe dir hat dieser Blog-Eintrag gefallen. Bis zum nächsten …