Stadeo: Desofuscar Stantinko y más


Presentamos Stadeo, un conjunto de scripts que pueden ayudar a otros investigadores de amenazas e ingenieros inversos a desofuscar el código de Stantinko y otro malware.

Stadeo es un conjunto de herramientas desarrollado principalmente para facilitar el análisis de Stantinko, que es una botnet que realiza fraude de clics, inyección de anuncios, fraude en redes sociales, ataques de robo de contraseñas y criptominería.

Stadeo se demostró por primera vez en Black Hat USA 2020 y posteriormente publicado para uso gratuito.

Los scripts, escritos íntegramente en Python, se ocupan de las técnicas únicas de control-flujo-aplanamiento (CFF) y ofuscación de cadenas de Stantinko descritas en nuestro informe de marzo de 2020 entrada en el blog. Además, se pueden utilizar para otros fines: por ejemplo, ya ampliamos nuestro enfoque para admitir la desofuscación del CFF presentado en Emotet, un troyano que roba credenciales bancarias y descarga cargas útiles adicionales como ransomware.

Nuestros métodos de desofuscación utilizan IDA, que es una herramienta estándar en la industria, y Miasma – un marco de código abierto que nos proporciona varios análisis de flujo de datos, un motor de ejecución simbólica, un motor de ejecución simbólica dinámica y los medios para reensamblar funciones modificadas.

Puedes encontrar a Stadeo en https://github.com/eset/stadeo.

Ejemplos de uso

Para trabajar con Stadeo, primero necesitamos configurar un servidor RPyC (Remote Python Call) dentro de IDA, que nos permite acceder a la API de IDA desde un intérprete de Python arbitrario. Puedes usar este guión para abrir un servidor RPyC en IDA.

En todos los ejemplos a continuación, configuramos un servidor RPyC que escucha en 10.1.40.164:4455 (4455 es el puerto predeterminado) y luego nos comunicamos con el servidor desde una consola Python.

Usaremos dos clases de Stadeo:

  • Estrategias CFFS para la desofuscación CFF
  • StringRevealer para la desofuscación de cuerdas

Ambas clases se pueden inicializar para arquitectura de 32 y 64 bits.

Desofuscar una sola función

SHA-1 de la muestra: 791ad58d9bb66ea08465aad4ea968656c81d0b8e

El siguiente código desofusca la función en 0x1800158B0 con el parámetro en el R9 registro establecido en 0x567C y escribe su versión desofuscada en el 0x18008D000 habla a.

los R9 El parámetro es una variable de control para la fusión de funciones del bucle CFF (variable de fusión) y debe especificarse mediante expresiones Miasm, que están documentadas. aquí; tenga en cuenta que uno tiene que usar RSP_init / ESP_init en vez de RSP / ESP para hacer referencia a los parámetros de la pila. Por ejemplo, usaríamos ExprMem (ExprId ("ESP_init", 32) + ExprInte (4, 32), 32) para apuntar al primer parámetro de pila en la arquitectura de 32 bits.

Figura 1. Llamada a la función ofuscada

Figura 2. CFG ofuscado (izquierda) y desofuscado (derecha)

Procesamiento de funciones accesibles

SHA-1 de la muestra: e0087a763929dee998deebbcfa707273380f05ca

El siguiente código reconoce solo funciones ofuscadas accesibles desde 0x1002DC50 y busca candidatos para fusionar variables. Las funciones reconocidas y desofuscadas con éxito comienzan en 0x10098000.

Salida parcial:

omitiendo 0x1002dc50 con val None: 0xbadf00d
mapeo: 0x1001ffc0 -> 0x10098000 con val @ 32 (ESP_init + 0x8): 0x6cef
omitiendo 0x100010f0 con val None: 0xbadf00d
mapeo: 0x1000f0c0 -> 0x100982b7 con val @ 32 (ESP_init + 0x8): 0x2012
mapeo: 0x1003f410 -> 0x10098c8a con val @ 32 (ESP_init + 0x4): 0x21a4
mapeo: 0x1003f410 -> 0x10098f3d con val @ 32 (ESP_init + 0x4): 0x772a
omitiendo 0x1004ee79 (función de biblioteca)

Las funciones asignadas se desofuscaron correctamente y las omitidas no se consideraron ofuscadas. El formato del cartografía líneas en la salida es:

mapeo:% obfuscated_function_address% ->% deobfuscated_function_address% con val% merging_variable%:% merging_variable_value%

El valor predeterminado para merging_variable_value es 0x0BADF00D. los salto a la comba las líneas siguen el mismo patrón, pero no hay dirección_función_deofuscada. Las funciones de biblioteca reconocidas por IDA simplemente se omiten sin más procesamiento.

Procesando todas las funciones

SHA-1 de la muestra: e575f01d3df0b38fc9dc7549e6e762936b9cc3c3

Usamos el siguiente código solo para tratar con CFF presentado en Emotet, cuya implementación de CFF se ajusta a la descripción del aplanamiento de flujo de control común aquí.

Preferimos este enfoque porque el método CFFStrategies.process_all () no intenta reconocer las variables de fusión que no están presentes en Emotet y busca solo un bucle CFF por función; por tanto, es más eficiente.

Las funciones reconocidas y desofuscadas con éxito se escriben secuencialmente desde 0x0040B000. El formato de la salida es el mismo que en el process_merging método utilizado en el Procesamiento de funciones accesibles ejemplo, pero naturalmente no habrá ninguna variable de combinación.

Salida parcial:

mapeo: 0x00401020 -> 0x0040b000 con val Ninguno: 0xbadf00d
omitiendo 0x00401670 con val None: 0xbadf00d
mapeo: 0x00401730 -> 0x0040b656 con val Ninguno: 0xbadf00d

Figura 3. Ejemplo de función ofuscada (izquierda) y desofuscada (derecha) en Emotet

Redirigir referencias a funciones desofuscadas

Stadeo no actualiza automáticamente las referencias a las funciones después de su desofuscación. En el siguiente ejemplo, demostramos cómo parchear una llamada de función en la Figura 1 desde el Desofuscar una sola función ejemplo. La referencia parcheada se muestra en la Figura 4.

Usamos el siguiente código para parchear llamadas, cuyo cuarto parámetro es 0x567C, a la función ofuscada en 0x1800158B0 con el desobstruido en 0x18008D000. Tenga en cuenta que hay que asegurarse de que IDA haya reconocido los parámetros de la función correctamente y posiblemente reparar ellos.

Figura 4. Referencia parcheada

Revelar cadenas ofuscadas en una función

La función StringRevealer.process_funcs () revela cadenas ofuscadas en la función especificada y devuelve un mapa de cadenas desofuscadas y sus direcciones.

Tenga en cuenta que el flujo de control de la función de destino ya debe haberse desofuscado.

En el siguiente ejemplo, desofuscamos las cadenas de la función en 0x100982B7, que se muestra en la Figura 5. La función en sí fue desofuscada en el anterior Procesamiento de funciones accesibles ejemplo.

Figura 5. Parte de la función en 0x100982B7 que claramente ensambla una cadena

El contenido de la variable de cadenas después de la ejecución es:

Esperamos que las herramientas Stadeo y esta explicación de su uso le resulten útiles. Si tiene alguna consulta, comuníquese con nosotros en Threatintel (at) eset.com o abra un problema en https://github.com/eset/stadeo.





Enlace a la noticia original