Tenemos el placer de presentaros un nuevo servicio on-line para el análisis de packers, resultado del trabajo conjunto de S3Lab y S3 Eurecom. PackerInspector surge como consecuencia del trabajo de investigación presentado en la conferencia IEEE Security & Privacy en 2015: SoK: Deep Packer Inspection: A Longitudinal Study of the Complexity of Run-Time Packers. Tras más de un año de desarrollo, ponemos nuestra investigación al servicio de la comunidad.
Las sandbox ejecutan cada muestra en un entorno controlado para observar su comportamiento malicioso, pero normalmente estos sistemas carecen de información acerca de cómo está empaquetada la muestra. Si recordamos entradas previas de este blog, los autores de malware generalmente empaquetan sus programas para evitar su detección y dificultar la ingeniería inversa. A grandes rasgos, un programa empaquetado contiene una rutina encargada de descomprimir o descifrar una sección de código protegida, que más tarde será ejecutada. A menudo, los autores de malware utilizan varias capas de empaquetado, fuertes métodos de ofuscación de código para cada una de las capas, así como métodos para evadir herramientas como sandbox, debuggers, frameworks de instrumentación, etc.
En muchas ocasiones, el analista de malware necesita analizar en profundidad de forma estática la totalidad del código de la muestra. Si la muestra está empaquetada, es necesario desempaquetarla para obtener un volcado del código original. Para ello, existen diversas alternativas. Por un lado existen unpackers específicos, que son capaces de lidiar con un número limitado de packers conocidos. Por otro lado, existen algunas herramientas de desempaquetado generico basadas en heurísticas. Desafortunadamente, estas heurísticas en ocasiones no presentan una gran efectividad. Como último recurso, el analista debe desempaquetar manualmente la muestra, lo que requiere analizar el empaquetador y averiguar cómo protege el código original.
Si bien existen multitud de sandboxes que permiten analizar malware para extraer indicadores de su comportamiento, no hay apenas herramientas que permitan entender el funcionamiento de un packer. PackerInspector pretende llenar este hueco, de tal modo que se especializa en este tipo de análisis y ofrece un informe detallado sobre diferentes características del packer, obtenidas de forma estática y dinámica. Estas caracteristicas (número de capas, interacción entre las mismas, número de procesos e interacción entre ellos, estructura de las diferentes capas…), nos permiten categorizar la estructura del packer en 6 niveles de complejidad estructural. Por ejemplo, UPX, uno de los packers más sencillos tiene una complejidad de tipo 1 (Type-I), mientras que Armadillo con la protección CopyMem activada, presenta una estructura de complejidad 6 (Type-VI).
El grafo que mostramos corresponde a un packer con un único proceso (P0), y 4 layers (0 a 3). Cada layer contiene una serie de regiones (áreas de memoria escritas y ejecutadas). Por ejemplo, si una determinada región Ra es escrita por otra región situada en la layer 1 (Rb), y Ra es después ejecutada, entonces Ra formará parte de la layer 2. Cada región contiene una primera línea que nos indica el tipo de memoria (M (módulo), S (stack), H (heap)) y su comienzo mientras que la segunda línea indica su tamaño. La tercera línea muestra 3 valores separados por “#”, que indican: el número total de llamadas a la API realizadas desde la región, el número de funciones de la API diferentes utilizadas, así como la presencia de llamadas a ciertas funciones relacionadas con el código bootstrap insertado por compiladores. Finalmente, la última línea muestra el número de frames (cuando una región ha sido escrita y ejecutada en varios turnos). Además, los colores diferencian las regiones, siendo la región roja la última en ejecutarse en nuestra sandbox.
Estamos ante un packer que descifra una primera capa, y tras ello pasa a ejecutarla (la región situada en 0x401000). A continuación, la rutina situada en la región 0x4079b1 (layer 1), descifra una segunda capa y la ejecuta, que a su vez descifra el código original (layer 3), y lo ejecuta. Los conectores grises nos indican que solamente ha habido una transición del flujo de ejecución entre cada par de capas, mientras que los conectores verdes y rojos nos indican el número de bytes escritos por cada región a regiones en la siguiente capa (de color verde, excepto cuando existe una transición de ejecución además de la escritura, en cuyo caso se muestra en rojo). Finalmente, vemos que la región roja de la última capa contiene un número muy superior de llamadas a la API, además de llamadas a la API relacionadas con el código inicial insertado por el compilador. Todo ello nos indica que el binario original se encuentra en esta capa.
Si quieres aprender más sobre cómo funciona PackerInspector, puedes visitar la página de referencia. En nuestro estudio original, medimos la evolución de la complejidad del empaquetado de muestras enviadas a la sandbox Anubis a lo largo de varios años. Hoy, al publicar este servicio, damos continuidad a este estudio recogiendo estadísticas globales de la complejidad de las muestras que compartáis con nosotros.
PackerInspector permite el envío de muestras de forma pública y privada. Para poder hacer uso del envío privado, deberás iniciar sesión con una cuenta de Google (OpenID). Con este registro, no almacenamos información más allá de un identificador único por cuenta y aplicación. Para las muestras enviadas de forma pública, el resultado del análisis será accesible por cualquiera en posesión de la url correspondiente. Sin embargo, si envías la muestra de forma privada, solamente tú podrás acceder al informe generado. Además, si estás registrado, podrás realizar un seguimiento de las muestras enviadas para su análisis, así como localizar informes de muestras enviadas anteriormente y utilizar la API pública para automatizar el envío de muestras y recopilación de resultados.
Happy reversing!