Contenido
Un descompilador nativo de versiones cruzadas de Python y un descompilador de fragmentos. El sucesor de descompyle, uncompyle y uncompyle2.
uncompyle6 traduce el código de bytes de Python nuevamente al código fuente de Python equivalente. Acepta códigos de bytes desde la versión 1.0 de Python hasta la versión 3.8, que abarca más de 24 años de lanzamientos de Python. Incluimos el código de bytes Python 2.5 de Dropbox y algunos códigos de bytes de PyPy.
Ok, lo diré: este software es increíble. Es más que un descompilador hacky normal. Utilizando tecnología de compilación, el programa crea un árbol de análisis del programa a partir de las instrucciones; nodos en los niveles superiores que se parecen un poco a lo que podría provenir de un AST de Python. Entonces realmente podemos clasificar y comprender lo que sucede en las secciones del código de bytes de Python.
Sobre la base de esto, otra cosa que lo diferencia de otros descompiladores de código de bytes de CPython es la capacidad de analizar solo fragmentos de código fuente y proporcionar información del código fuente en torno a un desplazamiento de código de bytes determinado.
Utilizo los fragmentos de árbol para analizar fragmentos de código en tiempo de ejecución dentro de mis depuradores trepan. Para ello, las compensaciones de código de bytes se registran y asocian con fragmentos del código fuente. Este propósito, aunque compatible con la intención original, es un poco diferente. Vea esto para más información.
El análisis de fragmentos de Python dado un desplazamiento de instrucción es útil para mostrar seguimientos de pila y se puede incorporar a cualquier programa que quiera mostrar una ubicación con más detalle que solo un número de línea en tiempo de ejecución. Este código también se puede utilizar cuando no existe información del código fuente y solo hay código de bytes. Nuevamente, mis depuradores hacen uso de esto.
Había (y todavía hay) una serie de bifurcaciones decompyle, uncompyle, uncompyle2, uncompyle3. Muchos de ellos provienen básicamente de la misma base de código y (¿casi?) Todos ellos ya no reciben mantenimiento activo. Uno era realmente bueno descompilando Python 1.5-2.3, otro realmente bueno en Python 2.7, pero solo eso. Otro maneja Python 3.2 únicamente; otro parchó eso y manejó solo 3.3. Entiendes la idea. Este código reúne todas estas bifurcaciones y avanza . Hay una refactorización y limpieza serias en esta base de código sobre esas bifurcaciones antiguas. En decompyle3 se están llevando a cabo aún más refactorizaciones experimentales.
Es evidente que esto hace lo mejor al descompilar Python en todas las versiones de Python. E incluso cuando hay otro proyecto que solo proporciona descompilación para un subconjunto de versiones de Python, generalmente también lo hacemos mejor.
¿Cómo podemos saberlo? Tomando el código de bytes de Python que viene distribuido con esa versión de Python y descompilándolos. Entre aquellos que se descompilan exitosamente, podemos asegurarnos de que los programas resultantes sean sintácticamente correctos ejecutando el intérprete de Python para esa versión de código de bytes. Finalmente, en los casos en que el programa tenga una prueba para sí mismo, podemos ejecutar la verificación en el código descompilado.
Utilizamos procesos automatizados para encontrar errores. En los rastreadores de problemas de otros descompiladores, encontrará una serie de errores que hemos encontrado en el camino. Muy pocos o ninguno de ellos están corregidos en los otros descompiladores.
El código en el repositorio de git se puede ejecutar desde Python 2.4 hasta la última versión de Python, con la excepción de Python 3.0 a 3.2. Los voluntarios son bienvenidos para abordar estas deficiencias si así lo desean.
La forma en que lo hace es segregando versiones consecutivas de Python en ramas de git:
PyPy 3-2.4 y posteriores también funcionan.
Los archivos de código de bytes que puede leer se han probado en códigos de bytes de Python de las versiones 1.4, 2.1-2.7 y 3.0-3.8 y versiones posteriores de PyPy.
Puede instalar desde PyPI usando el nombre uncompyle6
:
pip instala uncompyle6
Para instalar desde el código fuente, este proyecto utiliza setup.py, por lo que sigue la rutina estándar de Python:
$ pip instalar -e . # configurado para ejecutar desde el árbol de fuentes
o:
$ python setup.py install # puede que necesite sudo
También se proporciona un GNU Makefile para que make install
(posiblemente como root o sudo) realice los pasos anteriores.
hacer cheque
Se ha agregado un archivo MAKE de GNU para suavizar la configuración, ejecutar el comando correcto y ejecutar pruebas de más rápido a más lento.
Si tiene remake instalado, puede ver la lista de todas las tareas, incluidas las pruebas, mediante remake --tasks
Correr
$ uncompyle6 *archivo-python-compilado-pyc-o-pyo*
Para ayuda sobre el uso:
$ uncompyle6 -h
En versiones anteriores de Python era posible verificar el código de bytes descompilando el código de bytes y luego compilando usando el intérprete de Python para esa versión de código de bytes. Una vez hecho esto, el código de bytes producido podría compararse con el código de bytes original. Sin embargo, a medida que la generación de código de Python mejoró, esto ya no era factible.
Si desea verificar la sintaxis de Python sobre la corrección del proceso de descompilación, agregue la opción --syntax-verify
. Sin embargo, dado que la sintaxis de Python cambia, debe usar esta opción si el código de bytes es el código de bytes correcto para el intérprete de Python que verificará la sintaxis.
También puede comparar los resultados con otra versión de uncompyle6 , ya que a veces hay regresiones al descompilar un código de bytes específico a medida que mejora la calidad general.
Para Python 3.7 y 3.8, el código en decompyle3 es generalmente mejor.
O intente especificar otro descompilador de Python como uncompyle2, unpyc37 o pycdc. Dado que los dos últimos funcionan de manera diferente, los errores aquí a menudo no se encuentran en eso, y viceversa.
Hay una clase interesante de estos programas que está disponible y ofrece una verificación más sólida: aquellos programas que, cuando se ejecutan, se prueban a sí mismos. Nuestro conjunto de pruebas los incluye.
Y Python viene con otro conjunto de programas como este: su conjunto de pruebas para la biblioteca estándar. También tenemos algo de código en test/stdlib
para facilitar este tipo de verificación.
El mayor problema conocido y posiblemente solucionable (pero difícil) tiene que ver con el manejo del flujo de control. (Python tiene probablemente el conjunto de declaraciones compuestas más diverso y retorcido que he visto jamás; hay cláusulas "else" en bucles y bloques try que sospecho que muchos programadores no conocen).
Todos los descompiladores de Python que he analizado tienen problemas para descompilar el flujo de control de Python. En algunos casos podemos detectar una descompilación errónea y reportarlo.
El soporte de Python es bastante bueno para Python 2
En el extremo inferior de las versiones de Python, la descompilación parece bastante buena, aunque no contamos con ninguna prueba automatizada para las pruebas distribuidas de Python. Además, no tenemos un intérprete de Python para las versiones 1.6 y 2.0.
En la serie Python 3, el soporte de Python es más fuerte alrededor de 3.4 o 3.3 y disminuye a medida que te alejas de esas versiones. Python 3.0 es extraño porque en algunos aspectos se parece más a 2.6 que a 3.1 o 2.7. Python 3.6 cambia las cosas drásticamente al usar códigos de palabras en lugar de códigos de bytes. Como resultado, se ha reducido el campo de compensación de salto en un argumento de instrucción de salto. Esto hace que las instrucciones EXTENDED_ARG
sean ahora más frecuentes en las instrucciones de salto; anteriormente habían sido raros. Quizás para compensar las instrucciones EXTENDED_ARG
adicionales, se agregó optimización de salto adicional. Entonces, en resumen, manejar el flujo de control por medios ad hoc como se hace actualmente es peor.
Entre Python 3.5, 3.6, 3.7 ha habido cambios importantes en las instrucciones MAKE_FUNCTION
y CALL_FUNCTION
.
Python 3.8 elimina SETUP_LOOP
, SETUP_EXCEPT
, BREAK_LOOP
y CONTINUE_LOOP
, instrucciones que pueden dificultar la detección del flujo de control, al carecer del análisis de flujo de control más sofisticado que se planea. Ya veremos.
Actualmente no se admiten todos los números mágicos de Python. Específicamente en algunas versiones de Python, en particular Python 3.6, el número mágico cambia varias veces dentro de una versión.
Solo admitimos versiones publicadas, no versiones candidatas. Sin embargo, tenga en cuenta que la magia de una versión lanzada suele ser la misma que la de la última versión candidata antes del lanzamiento.
También hay intérpretes de Python personalizados, en particular Dropbox, que utilizan su propia magia y cifran el código de bytes. Con la excepción del antiguo intérprete Python 2.5 de Dropbox, este tipo de cosas no se manejan.
Tampoco manejamos PJOrion ni ningún otro código ofuscado. Para PJOrion, intente: PJOrion Deobfuscator para descifrar el código de bytes para obtener un código de bytes válido antes de probar esta herramienta; Pydecipher podría ayudar con eso.
Este programa no puede descompilar archivos EXE de Microsoft Windows creados por Py2EXE, aunque probablemente podamos descompilar el código después de extraer el código de bytes correctamente. Pydeinstaller puede ayudar a descomprimir paquetes de Pyinstaller.
Manejar listas patológicamente largas de expresiones o afirmaciones es lento. No manejamos Cython o MicroPython que no usan código de bytes.
Existen numerosos errores en la descompilación. Y eso es cierto para todos los demás descompiladores de CPython que he encontrado, incluso aquellos que afirmaban ser "perfectos" en alguna versión particular como 2.4.
A medida que Python avanza, la descompilación también se vuelve más difícil porque la compilación es más sofisticada y el lenguaje en sí es más sofisticado. Sospecho que habrá menos intentos ad hoc como unpyc37 (que se basa en un descompilador 3.3) simplemente porque es más difícil hacerlo. La buena noticia, al menos desde mi punto de vista, es que creo que entiendo lo que se necesita para abordar los problemas de una manera más sólida. Pero ahora mismo, hasta que el proyecto esté mejor financiado, no tengo la intención de hacer ningún esfuerzo serio para soportar las versiones 3.8 o 3.9 de Python, incluidos los errores que puedan surgir. Me imagino que en algún momento podría estar interesado en ello.
Puede encontrar errores fácilmente ejecutando las pruebas en el conjunto de pruebas estándar que Python utiliza para comprobarse a sí mismo. En un momento dado, hay docenas de problemas conocidos que están bastante bien aislados y que podrían resolverse si uno dedicara el tiempo necesario para hacerlo. El problema es que no hay mucha gente que haya estado trabajando en la corrección de errores.
Algunos de los errores en 3.7 y 3.8 son simplemente una cuestión de trasladar las correcciones en decompyle3 . ¿Algún voluntario?
Es posible que te encuentres con un error que quieras informar. Hágalo después de leer Cómo informar un error y siga las instrucciones al abrir un problema.
Tenga en cuenta que es posible que no me llame la atención por un tiempo. Si patrocina o apoya el proyecto de alguna manera, priorizaré sus problemas por encima de otras cosas que podría estar haciendo. En situaciones excepcionales, puedo realizar una descompilación manual del código de bytes por una tarifa. Sin embargo, esto es expansivo, generalmente más allá de lo que la mayoría de la gente está dispuesta a gastar.
uncompyle6
decompyle3
- BlackHat 2024 Asia (vídeo). Muchas gracias a los organizadores y revisores por dejarme hablar. Este tipo de cosas me animan a trabajar en proyectos como este.uncompyle6
son incorrectos mientras que los resultados uncompyle2
no lo son, pero con mayor frecuencia uncompyle6 es correcto cuando uncompyle2 no lo es. Debido a que uncompyle6
se adhiere a la precisión sobre Python idiomático, uncompyle2
puede producir código de apariencia más natural cuando es correcto. Actualmente, uncompyle2
tiene un mantenimiento ligero. Consulte su rastreador de problemas para obtener más detalles.