EVM en profundidad: los riesgos detrás del asunto trivial de la clasificación de contratos

En el campo de los contratos inteligentes, la "Ethereum Virtual Machine EVM" y sus algoritmos y estructuras de datos son los primeros principios.

Este artículo parte de por qué se deben clasificar los contratos, y combina qué tipo de ataques maliciosos puede enfrentar cada escenario, y finalmente brinda un conjunto de algoritmos de análisis de clasificación de contratos relativamente seguros.

**Aunque el contenido técnico es alto, también se puede utilizar como material de lectura para charlas misceláneas **Mira el bosque oscuro de los juegos entre sistemas descentralizados.

1. ¿Por qué se deben clasificar los contratos?

¡Debido a que es tan importante, se puede decir que es la piedra angular de Dapps, como intercambios, billeteras, navegadores de cadena de bloques, plataformas de análisis de datos, etc.!

La razón por la que una transacción es una transferencia ERC20 es porque su comportamiento se ajusta al estándar ERC20, al menos:

  1. El estado de la transacción es exitoso
  2. La dirección Para es un contrato que cumple con el estándar ERC20
  3. Se llama a la función Transfer, y la característica es que los primeros 4 dígitos del CallData de la transacción son 0xa9059cbb
  4. Después de la ejecución, se envía un evento de transferencia a la dirección Para

Si la clasificación es incorrecta, se juzgará mal el comportamiento de la transacción

Con el comportamiento de la transacción como piedra angular, si la dirección To se puede clasificar con precisión conducirá a una conclusión completamente diferente en el juicio de CallData. Para Dapp, la comunicación de información dentro y fuera de la cadena depende en gran medida del monitoreo de los eventos de transacción, y solo se puede confiar en el mismo código de evento si se envía en un contrato que cumple con los estándares.

Si la clasificación es incorrecta, la transacción irá al agujero negro por error

Si el usuario transfiere un Token a un determinado contrato, si el contrato no tiene un método de función preestablecido para la transferencia de Token, los fondos se bloquearán de la misma manera que Grabar y no se podrán controlar.

Y ahora que una gran cantidad de proyectos han comenzado a agregar soporte de billetera incorporado, es inevitable administrar billeteras para los usuarios.Es necesario clasificar los últimos contratos implementados de la cadena en tiempo real en todo momento, ya sea que puedan cumplir los estándares de activos.

Profundizando en el riesgo detrás del asunto trivial de la clasificación de contratos EVM

2. ¿Cuáles son los riesgos de la clasificación?

**La cadena es un lugar donde no hay identidad ni estado de derecho, no se puede detener una transacción normal, aunque sea maliciosa. **

Puede ser un lobo haciéndose pasar por una abuela, haciendo la mayoría de los comportamientos que esperas que haga una abuela, pero con el propósito de irrumpir en la casa y robar.

Estándar de reclamos, pero es posible que en realidad no cumpla

Un método de clasificación común es adoptar directamente el estándar EIP-165 para leer si la dirección es compatible con ERC20, etc. Por supuesto, este es un método eficiente, pero después de todo, el contrato está controlado por la otra parte, por lo que se puede hacer una declaración. forjado después de todo.

La consulta estándar 165 es solo un método para evitar que los fondos se transfieran a agujeros negros con el costo más bajo entre los códigos de operación limitados en la cadena.

Es por eso que cuando analizamos NFT anteriormente, mencionamos específicamente que habrá un método SafeTransferFrom en el estándar, donde Safe se refiere al uso del estándar 165 para determinar que la otra parte tiene la capacidad de transferir NFT.

Solo comenzando desde el código de bytes del contrato, haciendo un análisis estático en el nivel del código fuente y comenzando desde el comportamiento esperado del contrato, puede ser más preciso.

3. Diseño del esquema de clasificación de contratos

A continuación, analizaremos sistemáticamente el plan general y notaremos que nuestro objetivo final son los dos indicadores básicos de "precisión" y "eficiencia". **

Debe saber que incluso si la dirección es correcta, la forma de llegar al otro lado del océano no está clara. La primera parada para hacer un análisis de bytecode es obtener el código.

3.1 ¿Cómo obtener el código?

Desde el punto de vista de ir a la cadena, existe getCode, un método RPC, que puede obtener el bytecode de la dirección especificada en la cadena.Es muy rápido en términos de lectura, porque el codeHash se coloca en la estructura de la cuenta. de la EVM en la parte superior.

Profundizando en el riesgo detrás del asunto trivial de la clasificación de contratos EVM

Pero este método equivale a obtener una determinada dirección por sí sola. ¿Quiere mejorar aún más la precisión y la eficiencia?

Si se trata de una transacción de implementación de contrato, ¿cómo obtener el código implementado justo después de ejecutarlo o incluso cuando todavía está en el grupo de memoria?

Si la transacción está en el modo de fábrica por contrato, ¿hay algún código fuente en los datos de llamada de la transacción?

Al final, mi manera es clasificar en un modo similar a un tamiz.

  1. Para transacciones implementadas sin contrato, use directamente getCode para obtener las direcciones involucradas para la clasificación.
  2. Para las últimas transacciones del grupo de memoria, filtre las transacciones cuya dirección está vacía y cuyo CallData es el código fuente con el constructor
  3. Para la transacción del modo contract factory, dado que el contrato desplegado por el contrato puede reciclarse para llamar a otros contratos para ejecutar el despliegue, analizará recursivamente las subtransacciones de la transacción, y registrará cada llamada cuyo tipo sea CREAR o CREAR2.

Cuando hice una implementación de demostración, descubrí que la versión de rpc es relativamente alta ahora, porque la parte más difícil de todo el proceso es cómo encontrar recursivamente la llamada del tipo especificado al ejecutar 3. El método de nivel inferior es restaurar el contexto a través del código de operación. ¡Me sorprendió!

Afortunadamente, hay un método debug_traceTransaction en la versión actual de geth, que puede ayudar a ordenar la información de contexto de cada llamada a través del código de operación del código de operación y ordenar los campos principales.

Al final, se pueden obtener los bytecodes originales de varios modos de implementación (implementación directa, implementación única en modo de fábrica, implementación por lotes en modo de fábrica).

3.2 ¿Cómo clasificar a partir del código?

La forma más simple pero insegura es hacer directamente la coincidencia de cadenas con el código.Tomando ERC20 como ejemplo, la función que cumple con el estándar tiene

Profundizando en el riesgo detrás del asunto trivial de la clasificación de contratos EVM

Después del nombre de la función está la firma de la función. Como se mencionó en el análisis anterior, la transacción depende de hacer coincidir los primeros 4 dígitos de callData para encontrar la función de destino. Lectura adicional:

Por lo tanto, las firmas de estas 6 funciones deben almacenarse en el código de bytes del contrato.

Por supuesto, este método es muy rápido y puedes encontrar los 6, pero el factor inseguro es que si uso el contrato de solidez y diseño una variable con un valor de almacenamiento de 0x18160ddd, pensará que tengo esta función.

3.3 Mejora de la tasa de precisión 1- descompilación

¡El método más preciso es descompilar Opcode! La descompilación es el proceso de convertir los bytecodes obtenidos en códigos de operación, y una descompilación más avanzada consiste en convertirlos en pseudocódigos, lo que es más propicio para la lectura humana. No lo necesitamos esta vez. El método de descompilación se enumera en el apéndice en el final del artículo.

solidez (lenguaje de alto nivel) -> código de bytes (código de bytes) -> código de operación (código de operación)

Podemos encontrar claramente una característica, la firma de la función será ejecutada por el código de operación PUSH4, por lo que el método adicional es extraer el contenido después de PUSH4 del texto completo y hacerlo coincidir con el estándar de la función.

Profundizando en los riesgos detrás del asunto trivial de la clasificación de contratos EVM

También hice un experimento de rendimiento simple, y debo decir que el lenguaje Go es muy eficiente y solo toma 220ms para 10,000 veces de descompilación.

Lo que sigue será difícil

3.4 Mejora de la tasa de precisión Bloque de código de 2 búsquedas

La tasa de precisión anterior se ha mejorado pero no lo suficiente, porque es una búsqueda de texto completo PUSH4, porque todavía podemos construir una variable, que es del tipo byte4, que también activará el comando PUSH4.

Cuando estaba angustiado, pensé en la implementación de algunos proyectos de código abierto. ETL es una herramienta para leer datos en la cadena para su análisis. Analizará la transferencia de ERC20 y 721 en tablas separadas, por lo que debe tener la capacidad de clasificar contratos

Profundizando en el riesgo detrás del asunto trivial de la clasificación de contratos EVM

Después del análisis, se puede encontrar que se basa en la clasificación de bloques de código y solo procesa los primeros_bloques básicos [0] La instrucción push4 en

Surge la pregunta, cómo juzgar con precisión el bloque de código

El concepto del bloque de código proviene de los dos códigos de operación consecutivos de REVERT + JUMPDEST. Debe haber dos códigos de operación consecutivos aquí, porque en el intervalo de código de operación de todo el selector de funciones, si hay demasiadas funciones, aparecerá la lógica de cambio de página. Luego aparecerá también el comando JUMPDEST.

Profundizando en los riesgos detrás del asunto trivial de la clasificación de contratos EVM

3.5 Mejora de la tasa de precisión Selector de función 3-Find

La función del selector de función es leer los primeros 4 bytes de los datos de llamada de la transacción, y compararlos con la firma de la función de contrato preestablecida en el código, y ayudar a la instrucción a saltar a la ubicación de memoria especificada por el método de función.

Probemos una ejecución simulada mínima

Esta parte es el almacén selector (uint 256) y la recuperación () de las dos funciones, y la firma se puede calcular como 2e64cec1, 6057361d

Profundizando en el riesgo detrás del asunto trivial de la clasificación de contratos EVM

Después de descompilar, obtendrá la siguiente cadena de código de operación, que se puede decir que se divide en dos partes

primera parte:

En el compilador, solo la parte del selector de función del contrato obtendrá el contenido de callData, lo que significa obtener la firma de llamada de función de su CallData, como se muestra en la figura a continuación.

Profundizando en el riesgo detrás del asunto trivial de la clasificación de contratos EVM

Podemos ver el efecto simulando el cambio del grupo de memoria de EVM

Profundizando en el riesgo detrás del asunto trivial de la clasificación de contratos EVM

la segunda parte:

El proceso de juzgar si coincide con el valor del selector

  1. Pase la firma de la función de 4 bytes (0x2e64cec1) de retrieve() a la pila,

  2. El código de operación EQ extrae 2 variables del área de la pila, a saber, 0x2e64cec1 y 0x6057361d, y verifica si son iguales

  3. PUSH2 transfiere 2 bytes de datos (0x003b aquí, 59 en decimal) a la pila.Hay un contador de programa en el área de la pila, que especifica la posición del siguiente comando de ejecución en el código de bytes. Aquí establecemos 59 porque ahí es donde comienza el código de bytes de recuperación()

  4. JUMPI significa "Saltar a si...", extrae 2 valores de la pila como entrada y, si la condición es verdadera, el contador del programa se actualizará a 59.

Así es como EVM determina la ubicación del código de bytes de función que necesita ejecutar en función de la llamada de función en el contrato.

En realidad, esto es solo un conjunto simple de "declaraciones if" para cada función en el contrato y hacia dónde saltan.

Profundizando en el riesgo detrás del asunto trivial de la clasificación de contratos EVM

4. Resumen del esquema

El resumen general es el siguiente

  1. Cada dirección de contrato puede obtener el código de bytes después de la implementación a través de rpcgetcode o debug_traceTransaction, usando las bibliotecas VM y ASM en GO, y obtener el código de operación después de la descompilación
  2. En el principio de funcionamiento de EVM, el contrato tendrá las siguientes características
  • Use REVERT+JUMPDEST como distinción de bloque de código
  • El contrato debe tener la función de un selector de función, y esta función también debe estar en el primer bloque de código
  • En el selector de funciones, todos sus métodos de función usan PUSH4 como código de operación,
  • En el código de operación contenido en este selector, habrá PUSH1 00; CALLDATALOAD; PUSH1 e0; SHR; DUP1 consecutivos. La función principal es cargar los datos de callDate y realizar operaciones de desplazamiento. Desde la función de contrato, otra sintaxis no generará
  1. La firma de función correspondiente se define en eip, y hay instrucciones claras obligatorias y opcionales

4.1 Prueba de unicidad

En este punto, podemos decir que básicamente se ha realizado un método de análisis de contratos de alta eficiencia y alta precisión. Por supuesto, dado que ha sido riguroso durante tanto tiempo, también podríamos ser más rigurosos. En el esquema anterior, use REVER+JUMPDEST para hacer que los bloques de código se distingan, y combine la carga y el desplazamiento inevitables de CallDate para hacer un juicio único.¿Existe que pueda usar un contrato de solidez para implementar una secuencia de código de operación similar?

Hice un experimento de control Aunque existen métodos para obtener CallData como msg.sig desde el nivel de gramática de solidez, los métodos de implementación del código de operación después de la compilación son diferentes.

Profundizando en el riesgo detrás del asunto trivial de la clasificación de contratos EVM

Ver originales
El contenido es solo de referencia, no una solicitud u oferta. No se proporciona asesoramiento fiscal, legal ni de inversión. Consulte el Descargo de responsabilidad para obtener más información sobre los riesgos.
  • Recompensa
  • Comentar
  • Compartir
Comentar
0/400
Sin comentarios
  • Anclado
Comercie con criptomonedas en cualquier lugar y en cualquier momento
qrCode
Escanee para descargar la aplicación Gate.io
Comunidad
Español
  • 简体中文
  • English
  • Tiếng Việt
  • 繁體中文
  • Español
  • Русский
  • Français (Afrique)
  • Português (Portugal)
  • Indonesia
  • 日本語
  • بالعربية
  • Українська
  • Português (Brasil)