Cuando hablamos sobre el análisis estático de códigos maliciosos hacemos referencia el estudio de una amenaza sin tener que ejecutarla. De esta manera, es como si estuviéramos que realizar una autopsia para conocer qué es lo que hace o cuáles son las consecuencias que generará si llegase a infectar un sistema. Un primer acercamiento nos va a permitir conocer si el malware está empaquetado, en qué lenguaje de alto nivel fue desarrollado y otras tantas características más; Por ejemplo, podríamos ver qué librerías (DLLs) importa, las funciones que va a utilizar, el tamaño de sus secciones y otros datos de color.
Si quisiéramos ver cómo es que realiza tales acciones tendremos que adentrarnos aún más en lo que conocemos como Ingeniería Inversa y para ello, debemos entender sobre assembler y su utilidad en el desensamblado de los códigos maliciosos. En otras palabras, tendremos que aprender a hacerle una autopsia a un malware:
Introducción al desensamblado
Como mencionamos anteriormente, las técnicas básicas de análisis estático nos permiten conocer desde afuera, información acerca de un código malicioso. Dicho conjunto de técnicas es muy útil para darnos una idea inicial sobre la amenaza, pero para conocer todas sus funcionalidades debemos adentrarnos aún más. Listando las funciones que importa un malware, tomamos conocimiento de que la va a utilizar, pero no sabemos dónde ni cómo.
Por otro lado, al realizar un análisis dinámico de la amenaza, conocemos más información sobre su comportamiento, que información envía y recibe a través de la red, pero no como la utiliza internamente. Nuevamente, desensamblar la muestra nos permite conocer el detalle de dicha acción y responder a todas nuestras preguntas.
Aprender a desensamblar códigos maliciosos a través del uso de técnicas de Ingeniería Inversa es una habilidad que lleva tiempo desarrollar y puede resultar complicada. Sin embargo, no deja de ser una de las herramientas más útiles para combatir a los códigos y lograr proteger a los usuarios garantizando la seguridad y privacidad de su información.
Veamos los conceptos básicos para adentrarnos en el desensamblado y análisis de los códigos maliciosos.
Niveles de abstracción
Entender el funcionamiento de un sistema es un requerimiento necesario para saber cómo funcionan los códigos maliciosos. Además de ello también debemos darnos una idea de en qué nivel de abstracción o en qué capa vamos a estar trabajando.
A grandes rasgos existes tres niveles de abstracción en los cuáles nos vamos a manejar y son necesarios interpretar, según el caso que corresponda. El primero de ellos hace referencia al lenguaje de alto nivel que utilizó el creador de la amenaza al desarrollarla. El segundo involucra al código que se ejecuta directamente sobre el CPU de la máquina y que fue generado por el compilador y por último el lenguaje de bajo nivel con el cuál se trabaja durante el proceso de Ingeniería Inversa. En la siguiente imagen vemos la relación entre ellos:
Esta imagen nos da una idea simplificada de los diferentes niveles que existen dentro de todos los sistemas. Si arrancamos desde el hardware, microcódigo, código de máquina, los lenguajes de bajo nivel (Assembler), los lenguajes de alto nivel (C, C++, Delphi, etc) y los lenguajes interpretados (Java, Python, .NET, etc)
Según el caso en particular, las muestras de códigos maliciosos aparecen más frecuentemente en los últimos dos niveles, y partiendo desde esa base es el porqué de entender acerca de cómo desensamblar los códigos maliciosos para conocer sus actividades a través del uso de la Ingeniería Inversa.
Ingeniería Inversa
Cuando nos encontramos frente a una variante de algún código malicioso en un sistema y nos disponemos a analizarlo tenemos el archivo binario y debemos utilizar un desensamblador para generar el código en assembler con el objetivo de analizarlo. Ensamblador (assembler) es en realidad una clase de lenguaje de programación. Cada variante de ensamblador corresponde a una familia particular de microprocesadores tales como x86, x64, SPARC, PowerPC, MIPS o ARM. Dentro de todas estas familias la más habitual dentro las arquitecturas de procesadores es la x86, aunque con el pasar de los años vemos más y más procesadores x64.
Es a partir del desensamblado que debemos adentrarnos en el código de la amenaza para entender todas las acciones que realiza y cómo es que logra infectar un sistema para robar información, realizar ataques a otros sistemas o propagarse por la red. Para lograr una mejor comprensión de las acciones que queremos investigar debemos entender cómo se ejecuta la amenaza en el sistema, comprender qué son los registros del CPU, para qué se utilizan, cómo funciona la pila (stack), las instrucciones del CPU y muchas otras partes del sistema.
A partir de este post y en las próximas semanas iremos compartiendo con ustedes toda la información necesaria para comenzar a desensamblar las amenazas y entender las acciones maliciosas que realizan cuando logran engañar a los usuarios e infectar sus sistemas.