Inhalt
Ein nativer Python-Versionsübergreifender Dekompiler und Fragment-Dekompiler. Der Nachfolger von decompyle, uncompyle und uncompyle2.
uncompyle6 übersetzt Python-Bytecode zurück in äquivalenten Python-Quellcode. Es akzeptiert Bytecodes von Python Version 1.0 bis Version 3.8, die sich über 24 Jahre Python-Releases erstrecken. Wir schließen den Python 2.5-Bytecode von Dropbox und einige PyPy-Bytecodes ein.
Ok, ich sage es: Diese Software ist erstaunlich. Es ist mehr als Ihr normaler Hacky-Decompiler. Mithilfe der Compiler-Technologie erstellt das Programm aus den Anweisungen einen Parse-Baum des Programms. Knoten auf den oberen Ebenen, die ein wenig wie das aussehen, was von einem Python AST stammen könnte. So können wir wirklich klassifizieren und verstehen, was in Abschnitten des Python-Bytecodes vor sich geht.
Darauf aufbauend ist ein weiterer Unterschied zu anderen CPython-Bytecode-Decompilern die Fähigkeit, nur Fragmente des Quellcodes zu deparieren und Quellcodeinformationen um einen bestimmten Bytecode-Offset herum bereitzustellen.
Ich verwende die Baumfragmente, um Codefragmente zur Laufzeit in meinen Trepan-Debuggern zu zerlegen. Dazu werden Bytecode-Offsets aufgezeichnet und Fragmenten des Quellcodes zugeordnet. Dieser Zweck ist zwar mit der ursprünglichen Absicht vereinbar, unterscheidet sich jedoch ein wenig. Weitere Informationen finden Sie hier.
Das Parsen von Python-Fragmenten bei gegebenem Befehlsoffset ist nützlich bei der Anzeige von Stack-Traces und kann in jedes Programm integriert werden, das zur Laufzeit einen Speicherort detaillierter als nur eine Zeilennummer anzeigen möchte. Dieser Code kann auch verwendet werden, wenn keine Quellcodeinformationen vorhanden sind und nur Bytecode vorhanden ist. Auch dies machen sich meine Debugger zunutze.
Es gab (und gibt) eine Reihe von Decompyle-, Uncompyle-, Uncompyle2- und Uncompyle3-Forks. Viele von ihnen stammen im Wesentlichen aus derselben Codebasis und werden (fast?) alle nicht mehr aktiv gepflegt. Einer war wirklich gut darin, Python 1.5-2.3 zu dekompilieren, ein anderer wirklich gut in Python 2.7, aber nur das. Ein anderer beherrscht nur Python 3.2; ein anderer hat das gepatcht und nur 3.3 verarbeitet. Sie haben die Idee. Dieser Code zieht alle diese Zweige zusammen und bewegt sich vorwärts . Es gibt einige ernsthafte Umgestaltungen und Aufräumarbeiten in dieser Codebasis gegenüber diesen alten Forks. In decompyle3 wird noch mehr experimentelles Refactoring durchgeführt.
Dies ermöglicht nachweislich die beste Dekompilierung von Python in allen Python-Versionen. Und selbst wenn es ein anderes Projekt gibt, das nur die Dekompilierung für eine Teilmenge der Python-Versionen bereitstellt, schneiden wir im Allgemeinen auch bei diesen nachweislich besser ab.
Wie können wir das erkennen? Indem Sie den Python-Bytecode, der mit dieser Python-Version geliefert wird, nehmen und diesen dekompilieren. Unter den erfolgreich dekompilierten Programmen können wir dann sicherstellen, dass die resultierenden Programme syntaktisch korrekt sind, indem wir den Python-Interpreter für diese Bytecode-Version ausführen. Schließlich können wir in Fällen, in denen das Programm einen Test für sich selbst hat, die Prüfung am dekompilierten Code durchführen.
Wir verwenden automatisierte Prozesse, um Fehler zu finden. In den Issue-Trackern für andere Dekompilierer finden Sie eine Reihe von Fehlern, die wir unterwegs gefunden haben. Nur sehr wenige bis gar keine davon werden in den anderen Dekompilierern behoben.
Der Code im Git-Repository kann von Python 2.4 bis zur neuesten Python-Version ausgeführt werden, mit Ausnahme von Python 3.0 bis 3.2. Freiwillige sind herzlich willkommen, diese Defizite zu beheben, wenn sie den Wunsch dazu haben.
Dies geschieht jedoch durch die Aufteilung aufeinanderfolgender Python-Versionen in Git-Zweige:
PyPy 3-2.4 und höher funktioniert ebenfalls.
Die Bytecode-Dateien, die es lesen kann, wurden mit Python-Bytecodes der Versionen 1.4, 2.1-2.7 und 3.0-3.8 und späteren PyPy-Versionen getestet.
Sie können von PyPI aus unter dem Namen uncompyle6
installieren:
pip install uncompyle6
Zur Installation aus dem Quellcode verwendet dieses Projekt setup.py und folgt daher der Standard-Python-Routine:
$ pip install -e . # für die Ausführung vom Quellbaum aus eingerichtet
oder:
$ python setup.py install # benötigt möglicherweise Sudo
Ein GNU-Makefile wird ebenfalls bereitgestellt, sodass make install
(möglicherweise als Root oder Sudo) die oben genannten Schritte ausführt.
Scheck machen
Es wurde ein GNU-Makefile hinzugefügt, um die Einstellung des richtigen Befehls und die Ausführung von Tests vom schnellsten zum langsamsten zu vereinfachen.
Wenn Sie Remake installiert haben, können Sie über remake --tasks
die Liste aller Aufgaben einschließlich Tests anzeigen
Laufen
$ uncompyle6 *compiled-python-file-pyc-or-pyo*
Für Hilfe bei der Verwendung:
$ uncompyle6 -h
In älteren Versionen von Python war es möglich, Bytecode durch Dekompilieren und anschließendes Kompilieren mit dem Python-Interpreter für diese Bytecode-Version zu überprüfen. Anschließend konnte der erzeugte Bytecode mit dem ursprünglichen Bytecode verglichen werden. Da die Codegenerierung von Python jedoch besser wurde, war dies nicht mehr möglich.
Wenn Sie eine Python-Syntaxüberprüfung der Korrektheit des Dekompilierungsprozesses wünschen, fügen Sie die Option --syntax-verify
hinzu. Da sich die Python-Syntax jedoch ändert, sollten Sie diese Option verwenden, wenn der Bytecode der richtige Bytecode für den Python-Interpreter ist, der die Syntax überprüft.
Sie können die Ergebnisse auch mit einer anderen Version von uncompyle6 vergleichen, da es manchmal zu Rückschritten bei der Dekompilierung bestimmter Bytecodes kommt, wenn sich die Gesamtqualität verbessert.
Für Python 3.7 und 3.8 ist der Code in decompyle3 im Allgemeinen besser.
Oder versuchen Sie es mit einem anderen Python-Decompiler wie uncompyle2, unpyc37 oder pycdc. Da die beiden letztgenannten unterschiedlich funktionieren, liegen hier häufig keine Fehler vor und umgekehrt.
Es gibt eine interessante Klasse dieser Programme, die leicht verfügbar ist und eine stärkere Überprüfung liefert: Programme, die sich selbst testen, wenn sie ausgeführt werden. Unsere Testsuite umfasst diese.
Und Python bringt eine weitere Reihe solcher Programme mit: seine Testsuite für die Standardbibliothek. Wir haben Code in test/stdlib
um auch diese Art der Überprüfung zu erleichtern.
Das größte bekannte und möglicherweise behebbare (aber schwierige) Problem hat mit der Handhabung des Kontrollflusses zu tun. (Python verfügt wahrscheinlich über die vielfältigsten und verrücktesten zusammengesetzten Anweisungen, die ich je gesehen habe; es gibt „else“-Klauseln für Schleifen und Try-Blöcke, von denen ich vermute, dass viele Programmierer nichts davon wissen.)
Alle Python-Dekompiler, die ich mir angesehen habe, haben Probleme beim Dekompilieren des Kontrollflusses von Python. In einigen Fällen können wir eine fehlerhafte Dekompilierung erkennen und dies melden.
Die Python-Unterstützung für Python 2 ist ziemlich gut
Am unteren Ende der Python-Versionen scheint die Dekompilierung ziemlich gut zu sein, obwohl wir keine automatisierten Tests für die verteilten Tests von Python haben. Außerdem haben wir keinen Python-Interpreter für die Versionen 1.6 und 2.0.
In der Python 3-Serie ist die Python-Unterstützung um 3.4 oder 3.3 am stärksten und nimmt ab, je weiter man sich von diesen Versionen entfernt. Python 3.0 ist insofern seltsam, als es in gewisser Weise 2.6 mehr ähnelt als 3.1 oder 2.7. Python 3.6 ändert die Dinge drastisch, indem es Wortcodes anstelle von Bytecodes verwendet. Infolgedessen wurde das Sprungoffsetfeld in einem Sprunganweisungsargument reduziert. Dies führt dazu, dass die EXTENDED_ARG
-Anweisungen in Sprunganweisungen jetzt häufiger vorkommen; zuvor waren sie selten gewesen. Vielleicht um die zusätzlichen EXTENDED_ARG
-Anweisungen zu kompensieren, wurde eine zusätzliche Sprungoptimierung hinzugefügt. Alles in allem ist die Handhabung des Kontrollflusses durch Ad-hoc-Mittel, wie sie derzeit durchgeführt wird, schlechter.
Zwischen Python 3.5, 3.6 und 3.7 gab es wesentliche Änderungen an den Anweisungen MAKE_FUNCTION
und CALL_FUNCTION
.
Python 3.8 entfernt SETUP_LOOP
, SETUP_EXCEPT
, BREAK_LOOP
und CONTINUE_LOOP
, Anweisungen, die die Kontrollflusserkennung möglicherweise erschweren, da die geplante ausgefeiltere Kontrollflussanalyse fehlt. Wir werden sehen.
Derzeit werden nicht alle magischen Python-Zahlen unterstützt. Insbesondere in einigen Versionen von Python, insbesondere Python 3.6, ändert sich die magische Zahl innerhalb einer Version mehrmals.
Wir unterstützen nur veröffentlichte Versionen, keine Kandidatenversionen. Beachten Sie jedoch, dass die Magie einer veröffentlichten Version normalerweise die gleiche ist wie die der letzten Kandidatenversion vor der Veröffentlichung.
Es gibt auch angepasste Python-Interpreter, insbesondere Dropbox, die ihre eigene Magie verwenden und Bytecode verschlüsseln. Mit Ausnahme des alten Python 2.5-Interpreters von Dropbox wird so etwas nicht behandelt.
Wir verarbeiten auch keinen PJOrion oder anderweitig verschleierten Code. Versuchen Sie für PJOrion: PJOrion Deobfuscator, um den Bytecode zu entschlüsseln, um gültigen Bytecode zu erhalten, bevor Sie dieses Tool ausprobieren; Pydecipher könnte dabei helfen.
Dieses Programm kann von Py2EXE erstellte Microsoft Windows EXE-Dateien nicht dekompilieren, obwohl wir den Code wahrscheinlich dekompilieren können, nachdem Sie den Bytecode ordnungsgemäß extrahiert haben. Pydeinstaller kann beim Entpacken von Pyinstaller-Bundlern helfen.
Der Umgang mit pathologisch langen Listen von Ausdrücken oder Aussagen ist langsam. Wir verarbeiten weder Cython noch MicroPython, die keinen Bytecode verwenden.
Es gibt zahlreiche Fehler bei der Dekompilierung. Und das gilt für jeden anderen CPython-Decompiler, dem ich begegnet bin, sogar für diejenigen, die behaupteten, in einer bestimmten Version wie 2.4 „perfekt“ zu sein.
Mit fortschreitendem Python wird auch die Dekompilierung schwieriger, da die Kompilierung ausgefeilter und die Sprache selbst ausgefeilter wird. Ich vermute, dass es weniger Ad-hoc-Versuche wie unpyc37 (das auf einem 3.3-Decompiler basiert) geben wird, einfach weil es schwieriger ist. Die gute Nachricht ist, zumindest aus meiner Sicht, dass ich glaube zu verstehen, was nötig ist, um die Probleme entschiedener anzugehen. Aber im Moment, bis das Projekt besser finanziert ist, habe ich nicht vor, ernsthafte Anstrengungen zu unternehmen, um die Python-Versionen 3.8 oder 3.9 zu unterstützen, einschließlich der möglicherweise auftretenden Fehler. Ich kann mir vorstellen, dass ich irgendwann daran interessiert sein könnte.
Sie können Fehler leicht finden, indem Sie die Tests mit der Standardtestsuite ausführen, die Python zur Selbstprüfung verwendet. Zu jeder Zeit gibt es Dutzende bekannter Probleme, die ziemlich isoliert sind und die gelöst werden könnten, wenn man sich die Zeit dafür nehmen würde. Das Problem ist, dass es nicht so viele Leute gibt, die an der Fehlerbehebung arbeiten.
Einige der Fehler in 3.7 und 3.8 sind lediglich eine Frage der Rückportierung der Korrekturen in decompyle3 . Gibt es Freiwillige?
Möglicherweise stoßen Sie auf einen Fehler, den Sie melden möchten. Bitte tun Sie dies, nachdem Sie „So melden Sie einen Fehler“ gelesen haben, und befolgen Sie die Anweisungen, wenn Sie ein Problem eröffnen.
Seien Sie sich bewusst, dass es möglicherweise eine Zeit lang nicht meine Aufmerksamkeit erregt. Wenn Sie das Projekt sponsern oder auf irgendeine Weise unterstützen, werde ich Ihre Probleme über die Warteschlange anderer Dinge priorisieren, die ich stattdessen möglicherweise tun würde. In seltenen Fällen kann ich gegen eine Gebühr eine manuelle Dekompilierung des Bytecodes durchführen. Dies ist jedoch kostspielig und liegt in der Regel über dem, was die meisten Menschen auszugeben bereit sind.
uncompyle6
decompyle3
– BlackHat 2024 Asia (Video). Ein großes Dankeschön an die Organisatoren und Gutachter, die mich sprechen ließen. So etwas ermutigt mich, an Projekten wie diesem zu arbeiten.uncompyle6
falsch sind, die Ergebnisse uncompyle2
jedoch nicht, aber häufiger ist uncompyle6 korrekt, wenn dies bei uncompyle2 nicht der Fall ist. Da sich uncompyle6
gegenüber dem idiomatischen Python an die Genauigkeit hält, kann uncompyle2
natürlicher aussehenden Code erzeugen, wenn er korrekt ist. Derzeit wird uncompyle2
nur geringfügig gewartet. Weitere Informationen finden Sie im Issue-Tracker.