Contenu
Un décompilateur natif multi-versions Python et un décompilateur de fragments. Le successeur de décompyle, décompyle et décompyle2.
uncompyle6 traduit le bytecode Python en code source Python équivalent. Il accepte les bytecodes de Python version 1.0 à version 3.8, couvrant plus de 24 ans de versions Python. Nous incluons le bytecode Python 2.5 de Dropbox et certains bytecodes PyPy.
Ok, je vais le dire : ce logiciel est incroyable. C'est plus que votre décompilateur hacky normal. À l'aide de la technologie du compilateur, le programme crée un arbre d'analyse du programme à partir des instructions ; des nœuds aux niveaux supérieurs qui ressemblent un peu à ce qui pourrait provenir d'un Python AST. Nous pouvons donc vraiment classer et comprendre ce qui se passe dans les sections du bytecode Python.
Sur cette base, une autre chose qui le différencie des autres décompilateurs de bytecode CPython est la possibilité d'analyser uniquement des fragments de code source et de fournir des informations sur le code source autour d'un décalage de bytecode donné.
J'utilise les fragments d'arborescence pour analyser des fragments de code au moment de l'exécution dans mes débogueurs Trepan. Pour cela, les décalages de bytecode sont enregistrés et associés à des fragments du code source. Cet objectif, bien que compatible avec l’intention initiale, est pourtant un peu différent. Voir ceci pour plus d'informations.
L'analyse de fragments Python étant donné un décalage d'instruction est utile pour afficher les traces de pile et peut être intégrée à tout programme souhaitant afficher un emplacement plus en détail qu'un simple numéro de ligne au moment de l'exécution. Ce code peut également être utilisé lorsque les informations sur le code source n'existent pas et qu'il n'y a que du bytecode. Encore une fois, mes débogueurs en profitent.
Il y avait (et il y a toujours) un certain nombre de forks decompyle, uncompyle, uncompyle2, uncompyle3. Beaucoup d’entre eux proviennent essentiellement de la même base de code et (presque ?) tous ne sont plus activement maintenus. L'un était vraiment bon pour décompiler Python 1.5-2.3, un autre très bon pour Python 2.7, mais cela seulement. Un autre gère uniquement Python 3.2 ; un autre a corrigé cela et n'a géré que la version 3.3. Vous voyez l’idée. Ce code rassemble toutes ces fourches et avance . Il y a une refactorisation et un nettoyage sérieux dans cette base de code par rapport à ces anciens forks. Une refactorisation encore plus expérimentale est en cours dans decompyle3.
Cela fait manifestement le meilleur pour décompiler Python dans toutes les versions de Python. Et même lorsqu'il existe un autre projet qui ne propose la décompilation que pour un sous-ensemble de versions de Python, nous faisons généralement mieux pour celles-ci également.
Comment pouvons-nous le savoir ? En prenant le bytecode Python fourni avec cette version de Python et en le décompilant. Parmi ceux qui réussissent à décompiler, nous pouvons alors nous assurer que les programmes résultants sont syntaxiquement corrects en exécutant l'interpréteur Python pour cette version de bytecode. Enfin, dans les cas où le programme dispose d'un test pour lui-même, nous pouvons exécuter la vérification sur le code décompilé.
Nous utilisons des processus automatisés pour trouver des bugs. Dans les outils de suivi des problèmes d'autres décompilateurs, vous trouverez un certain nombre de bogues que nous avons trouvés en cours de route. Très peu d'entre eux, voire aucun, ne sont corrigés dans les autres décompilateurs.
Le code du référentiel git peut être exécuté depuis Python 2.4 jusqu'à la dernière version de Python, à l'exception de Python 3.0 à 3.2. Les bénévoles sont invités à remédier à ces lacunes s'ils le souhaitent.
La façon dont il procède est de séparer les versions consécutives de Python en branches git :
PyPy 3-2.4 et versions ultérieures fonctionnent également.
Les fichiers de bytecode qu'il peut lire ont été testés sur les bytecodes Python des versions 1.4, 2.1-2.7 et 3.0-3.8 et versions ultérieures de PyPy.
Vous pouvez installer depuis PyPI en utilisant le nom uncompyle6
:
pip installer décompyle6
Pour installer à partir du code source, ce projet utilise setup.py, il suit donc la routine Python standard :
$ pip install -e . # configuré pour s'exécuter à partir de l'arborescence des sources
ou:
$ python setup.py install # peut avoir besoin de sudo
Un Makefile GNU est également fourni, donc make install
(éventuellement en tant que root ou sudo) effectuera les étapes ci-dessus.
faire un chèque
Un makefile GNU a été ajouté pour faciliter la configuration en exécutant la bonne commande et en exécutant les tests du plus rapide au plus lent.
Si Remake est installé, vous pouvez voir la liste de toutes les tâches, y compris les tests via remake --tasks
Courir
$ uncompyle6 *fichier-python-compilé-pyc-ou-pyo*
Pour obtenir de l'aide à l'utilisation :
$ décompyle6 -h
Dans les anciennes versions de Python, il était possible de vérifier le bytecode en décompilant le bytecode, puis en le compilant à l'aide de l'interpréteur Python pour cette version du bytecode. Cela fait, le bytecode produit a pu être comparé au bytecode original. Cependant, à mesure que la génération de code Python s'améliorait, cela n'était plus réalisable.
Si vous souhaitez vérifier la syntaxe Python de l'exactitude du processus de décompilation, ajoutez l'option --syntax-verify
. Cependant, étant donné que la syntaxe Python change, vous devez utiliser cette option si le bytecode est le bon bytecode pour l'interpréteur Python qui vérifiera la syntaxe.
Vous pouvez également comparer les résultats avec une autre version de uncompyle6 car il y a parfois des régressions dans la décompilation d'un bytecode spécifique à mesure que la qualité globale s'améliore.
Pour Python 3.7 et 3.8, le code de decompyle3 est généralement meilleur.
Ou essayez un autre décompilateur Python spécifique comme uncompyle2, unpyc37 ou pycdc. Étant donné que les deux derniers fonctionnent différemment, les bogues ici ne sont souvent pas présents, et vice versa.
Il existe une classe intéressante de ces programmes qui sont facilement disponibles et qui permettent une vérification plus forte : les programmes qui, lorsqu'ils sont exécutés, se testent eux-mêmes. Notre suite de tests les inclut.
Et Python est livré avec un autre ensemble de programmes comme celui-ci : sa suite de tests pour la bibliothèque standard. Nous avons également du code dans test/stdlib
pour faciliter ce type de vérification.
Le plus gros problème connu et éventuellement réparable (mais difficile) concerne la gestion du flux de contrôle. (Python possède probablement l'ensemble d'instructions composées le plus diversifié et le plus fou que j'ai jamais vu ; il y a des clauses "else" sur les boucles et des blocs d'essai que je soupçonne que de nombreux programmeurs ne connaissent pas.)
Tous les décompilateurs Python que j'ai consultés ont des problèmes pour décompiler le flux de contrôle de Python. Dans certains cas, nous pouvons détecter une décompilation erronée et la signaler.
Le support de Python est plutôt bon pour Python 2
Dans la partie inférieure des versions de Python, la décompilation semble plutôt bonne, même si nous n'avons mis en place aucun test automatisé pour les tests distribués de Python. De plus, nous n'avons pas d'interpréteur Python pour les versions 1.6 et 2.0.
Dans la série Python 3, la prise en charge de Python est la plus forte autour de 3.4 ou 3.3 et diminue à mesure que vous vous éloignez de ces versions. Python 3.0 est étrange dans la mesure où, à certains égards, il ressemble plus à 2.6 qu'à 3.1 ou 2.7. Python 3.6 change radicalement les choses en utilisant des codes de mots plutôt que des codes d'octets. En conséquence, le champ de décalage de saut dans un argument d'instruction de saut a été réduit. Cela fait que les instructions EXTENDED_ARG
sont désormais plus répandues dans les instructions de saut ; auparavant, ils étaient rares. Peut-être pour compenser les instructions EXTENDED_ARG
supplémentaires, une optimisation de saut supplémentaire a été ajoutée. Donc, en somme, gérer le flux de contrôle par des moyens ad hoc comme c'est le cas actuellement est pire.
Entre Python 3.5, 3.6 et 3.7, des changements majeurs ont été apportés aux instructions MAKE_FUNCTION
et CALL_FUNCTION
.
Python 3.8 supprime SETUP_LOOP
, SETUP_EXCEPT
, BREAK_LOOP
et CONTINUE_LOOP
, instructions qui peuvent rendre la détection du flux de contrôle plus difficile, faute de l'analyse de flux de contrôle plus sophistiquée prévue. Nous verrons.
Actuellement, tous les nombres magiques Python ne sont pas pris en charge. Plus précisément dans certaines versions de Python, notamment Python 3.6, le nombre magique change plusieurs fois au sein d'une version.
Nous prenons en charge uniquement les versions publiées, pas les versions candidates. Notez cependant que la magie d’une version publiée est généralement la même que celle de la dernière version candidate avant sa sortie.
Il existe également des interpréteurs Python personnalisés, notamment Dropbox, qui utilisent leur propre magie et chiffrent le bytecode. À l'exception de l'ancien interpréteur Python 2.5 de Dropbox, ce genre de chose n'est pas géré.
Nous ne gérons pas non plus PJOrion ou le code obscurci. Pour PJOrion, essayez : PJOrion Deobfuscator pour déchiffrer le bytecode afin d'obtenir un bytecode valide avant d'essayer cet outil ; pydecipher pourrait aider avec ça.
Ce programme ne peut pas décompiler les fichiers EXE Microsoft Windows créés par Py2EXE, bien que nous puissions probablement décompiler le code après avoir extrait correctement le bytecode. Pydeinstaller peut aider à décompresser les bundles Pyinstaller.
La gestion de listes pathologiquement longues d’expressions ou de déclarations est lente. Nous ne gérons pas Cython ou MicroPython qui n'utilisent pas de bytecode.
Il existe de nombreux bugs dans la décompilation. Et c'est vrai pour tous les autres décompilateurs CPython que j'ai rencontrés, même ceux qui prétendaient être "parfaits" sur une version particulière comme la 2.4.
À mesure que Python progresse, la décompilation devient également plus difficile car la compilation est plus sophistiquée et le langage lui-même est plus sophistiqué. Je soupçonne qu'il y aura moins de tentatives ad hoc comme unpyc37 (qui est basé sur un décompilateur 3.3) simplement parce que c'est plus difficile à faire. La bonne nouvelle, du moins de mon point de vue, est que je pense comprendre ce qui est nécessaire pour résoudre les problèmes de manière plus robuste. Mais pour l'instant, jusqu'à ce que le projet soit mieux financé, je n'ai pas l'intention de faire d'efforts sérieux pour prendre en charge les versions 3.8 ou 3.9 de Python, y compris les bogues qui pourraient survenir. J'imagine qu'à un moment donné, cela pourrait m'intéresser.
Vous pouvez facilement trouver des bogues en exécutant les tests sur la suite de tests standard que Python utilise pour se vérifier. À tout moment, il existe des dizaines de problèmes connus qui sont assez bien isolés et qui pourraient être résolus si l’on y consacrait le temps. Le problème est qu'il n'y a pas beaucoup de gens qui ont travaillé sur la correction de bugs.
Certains bugs des versions 3.7 et 3.8 sont simplement une question de rétroportage des correctifs dans decompyle3 . Des volontaires ?
Vous pouvez rencontrer un bug que vous souhaitez signaler. Veuillez le faire après avoir lu Comment signaler un bug et suivez les instructions lors de l'ouverture d'un problème.
Sachez que cela pourrait ne pas attirer mon attention pendant un certain temps. Si vous parrainez ou soutenez le projet d'une manière ou d'une autre, je donnerai la priorité à vos problèmes plutôt qu'à d'autres choses que je pourrais faire à la place. Dans de rares situations, je peux effectuer une décompilation manuelle du bytecode moyennant des frais. Cependant, cela coûte cher, généralement au-delà de ce que la plupart des gens sont prêts à dépenser.
uncompyle6
decompyle3
-- BlackHat 2024 Asia (vidéo). Un grand merci aux organisateurs et aux évaluateurs de m'avoir laissé parler. Ce genre de chose m'encourage à travailler sur des projets comme celui-ci.uncompyle6
sont incorrects alors que les résultats uncompyle2
ne le sont pas, mais le plus souvent, uncompyle6 est correct lorsque uncompyle2 ne l'est pas. Parce que uncompyle6
adhère à la précision par rapport à Python idiomatique, uncompyle2
peut produire un code d'apparence plus naturelle lorsqu'il est correct. Actuellement, uncompyle2
est légèrement entretenu. Consultez son outil de suivi des problèmes pour plus de détails.