¿Cómo se puede descompilar un contrato inteligente?

En la cadena de bloques puedo inspeccionar el código de un contrato y ver los códigos de operación de EVM. ¿Hay alguna manera de descompilar esto y volver a convertirlo en código fuente (Solidity)?

¿Cómo puedes ver los códigos de operación EVM?

Respuestas (7)

La compilación al código fuente original es imposible porque se eliminan todos los nombres de variables, nombres de tipos e incluso nombres de funciones. Puede ser técnicamente posible llegar a un código fuente que sea similar al código fuente original pero que sea muy complicado, especialmente cuando se usó el optimizador durante la compilación. No conozco ninguna herramienta que haga más que convertir código de bytes en códigos de operación.

Dado que los contratos pueden acceder a su propio código y, por lo tanto, (ab)utilizar el código para almacenar datos, no siempre está claro si una parte del código se usa realmente como código o solo como meros datos y si tiene sentido intentar descompilarlo. . Es computacionalmente indecidible si alguna parte del código es accesible o no.

Tenga en cuenta que no hay un área dedicada para almacenar datos fijos en el momento de la creación (como tablas de búsqueda, etc.). Además del código del contrato, también sería posible almacenar los datos en el almacenamiento, pero eso sería mucho más costoso, por lo que poner dichos datos en el código es algo común.

Entonces , si miro, por ejemplo, este contrato etherchain.org/account/... que dice ser un lanzamiento de moneda 50/50 aquí ( medium.com/@kpcb_edge /... ): ¿hay alguna manera de estar seguro de que hace efectivamente lo que dice ? lo hace ? ¿Cómo pueden las personas enviar dinero a los contratos si no pueden 'leer' el código?
Los creadores de @euri10 pueden proporcionar el código fuente y, al compilarlo con la misma versión del compilador, puede verificar que compila en el mismo código de bytes. Algunos exploradores de blockchain, como ether.camp, brindan esta funcionalidad incorporada.
Gran información. Solo para aclarar, la accesibilidad general es indecidible, pero muchos, si no la mayoría de los problemas prácticos de accesibilidad específicos, son decidibles. Tenga en cuenta que los linters señalarán funciones no utilizadas.

Hay un proyecto Porosity ahora https://github.com/comaeio/porosity También está integrado en la cadena de herramientas Quorum https://www.coindesk.com/first-ethereum-decompiler-launches-jp-morgan-quorum-integration/

He probado esta herramienta. No es estable hasta el momento. github.com/comaeio/porosidad/problemas/30
JEB Decompiler proporciona buenos resultados, es una herramienta profesional (no gratuita) pero tienen una demostración descargable aquí pnfsoftware.com/blog/ethereum-smart-contract-decompiler
@MarcelFalliere Esa es una herramienta interesante. Gracias.

es imposible volver al código de solidez. simplemente podría decodificar el código de bytes en códigos de operación.

mira este ejemplo: https://etherscan.io/opcode-tool?a=0x9e1b57fc92eba6434251a8458811c32690f32c45

pero el problema no debe considerarse resuelto cuando haya terminado con los códigos de operación. lo que el autor de la publicación quería es el código fuente.

En general, como comentaron otros usuarios, no es posible recuperar el código fuente original en la práctica. Sin embargo, en teoría, tanto las aplicaciones compiladas como las fuente deberían producir exactamente la misma salida (es decir, tener la misma semántica), por lo que debería ser posible obtener un programa en representación de código fuente que haga exactamente lo mismo que el código de bytes. La gente ha mencionado otros descompiladores como Porosity. También existen descompiladores (a una representación intermedia) llamados Mythril, EthIR y Vandal. Como usuario en 2018, el descompilador más completo disponible es https://www.contract-library.com . No es una herramienta independiente, pero puede descompilar la mayoría de los contratos que se encuentran actualmente en la red principal de Ethereum y otras redes de prueba.

Y este es el contrato que sugirió Badr Bellaj: https://contract-library.com/contracts/Ethereum/0x9e1b57fc92eba6434251a8458811c32690f32c45

Como puede ver, incluso algunos de los nombres de las funciones se infieren automáticamente, según el conocimiento que adquirió al intentar comprender los contratos anteriores. En general, los descompiladores para Ethereum actualmente no están diseñados para optimizar su salida para el consumo humano; sin embargo, están optimizados para el consumo de otras máquinas (algoritmos) que pueden encontrar vulnerabilidades de seguridad.

No creo que Mythil haga ninguna descompilación. Puede desensamblar el código y mostrar un gráfico de flujo de control similar a un árbol (no detecta bucles en este gráfico), pero creo que eso está lejos de lo que hace un descompilador.
Eso es correcto. Estaba incluyendo cualquier herramienta que eleve el nivel de abstracción. En este caso, tanto Mythril como Vandal lo hacen en diversos grados, pero no presentan una vista del código a nivel de fuente.

Lista de herramientas modernas (2022 y más allá)

  1. Desensamblador de código de bytes a código de operación de Etherscan .
  2. Descompilador de solidez en línea de EtherVM .

Esta no es una respuesta completa, pero describe un enfoque para el cual uno podría escribir un descompilador para Solidity que puede ser mejor que muchos de los descompiladores existentes.

Se basa en la experiencia en un descompilador de Python que desarrollé y mantengo .

la excelente respuesta aceptada de chriseth describe el caso general y supone que desea que la descompilación funcione en todas las situaciones en todo el código.

Pero muchas veces esta podría no ser la situación. Aquí hay algunos escenarios en los que puede hacerlo mejor que en el caso general:

  1. Supongamos que el código que quiero descompilar es una variante del código para el cual tengo disponible el código fuente. (Esto también se menciona en la respuesta de Neville Grech). Tal vez el bytecode/ewasm se generó a partir de una versión anterior o más nueva de la fuente que tengo. Aquí, puedo basarme en el hecho de que muchos de los nombres de las variables y sus tipos ya los conozco, es solo que puede haber algunas pequeñas diferencias en el código. Incluso si una variable "err" en el código fuente que tengo se cambia a "error" en el código fuente perdido que se usó en la compilación, siempre que los tipos sean los mismos, no es tan malo usar el nombre de variable "err" a pesar de que era "error". Es probable que proporcione un nombre más útil que un nombre inventado arbitrariamente.

  2. solc antes de la optimización basada en yul realiza optimización de pila y alguna optimización local, pero no los tipos más disruptivos de optimización "global". Incluso con la optimización, puede ser posible combinar patrones de secuencias de operación para obtener estructuras más grandes como asserty require. En Python utilizo un analizador J. Earley que es genial porque permite que las gramáticas se den de forma ambigua . Es decir, una secuencia de códigos de operación podría coincidir con una gramática, varias construcciones diferentes de alto nivel. Pero está bien, porque esa es, de hecho, la naturaleza del juego. En la descompilación, no debe esperar obtener algo que sea exactamente la fuente (aunque eso puede suceder). En su lugar, debe obtener algo que sea equivalente.

Si además conoce la versión de solc que se usó en la compilación y/o el nivel de optimización, eso puede ayudar aún más a reducir los patrones que posiblemente podrían emitirse y, por lo tanto, acortar la gramática y hacerla menos ambigua. Si la versión de solc es anterior a 0.5 o más, sabrá que la optimización de yul no es importante.

Estoy seguro de que en solc hay un código repetitivo por todas partes. Por ejemplo, al inicio de los contratos. Ese código puede coincidir. Hay un código repetitivo que solc usa para ver si el índice en una matriz dinámica es aceptable. Si este patrón de código es único, entonces podríamos inferir que hay una matriz dinámica en uso. De manera similar, el código que emite un "nuevo" podría caer en el reconocimiento de coincidencia de patrones.

Nota: ¿por qué escribo que coincide con los códigos de operación y no con las instrucciones (es decir, el código de operación y el par de operandos)? Esto se debe a que si está haciendo coincidencia de patrones, desea abstraerse un poco; usar el código de operación para la instrucción hace eso. En aquellos casos en los que se debe incluir información del operando, lo que se hace en el descompilador de Python es que el código de operación cambia para reflejar esta pieza adicional de abstracción. No hay nada que dicte que tenga que coincidir con los códigos de operación EVM existentes. Puede crear nuevos códigos de operación, insertar códigos de operación que podrían indicar el límite de la estructura de control o cambiar algunos nombres de códigos de operación para ayudar en la coincidencia de patrones.

  1. A veces, no está interesado en descompilar todo el código, solo una parte.

Encontré el descompilador Solidity aquí https://www.ethervm.io/decompile