domingo, marzo 23, 2014

Uso de API Hooking en Windows para analizar binarios

Una de tantas técnicas que usan algunas muestras de malware es la conocida como API Hooking aunque en este artículo lo que me interesa es darle una función buena a esta técnica para poder facilitarnos un análisis a alguna muestra de software malicioso. Vamos a repasar un poco antes para entender el proceso.

Introducción

Los procesadores X86 de Intel y compatibles tienen 4 niveles de privilegios que son conocidos como "anillos" o Ring 0 a Ring 3. En los sistemas operativos Win32, tal y como se explica en el libro de Máxima Seguridad en Windows, solamente se hace uso de los niveles de Ring 0 y de Ring 3 y donde nosotros trabajaremos con las aplicaciones será en nivel de usuario que es el conocido como Ring 3.
Ring 0: Mayor privilegio (nivel kernel del Sistema Operativo)
Ring 1
Ring 2
Ring 3: menor privilegio (nivel usuario)
Cuando trabajamos con Ring 3 estaremos invocando a las APIs del sistema Microsoft Windows de nivel de usuario que proveen la funcionalidad del sistema que permite a un programador hacer que un programa funcione sobre este sistema operativo. Estas funciones de la API de Ring 3 cuando necesitan un acceso privilegiado lo que hace es entrar a nivel kernel Ring 0 a ejecutarse, y después retornar a nivel usuario para de esta forma aislar el programa del nivel de Ring 0.

Ahora bien, crear un gancho o Hook para alguna función de la API es simple y existen diversos métodos. Uno de esos métodos que es muy sencillo pero a la vez muy útil es el conocido como Método del Columpio, que se basa en inyectar una librería DLL al proceso. Se le llama así porque la primera instrucción que se coloca al iniciar la función de la API que es una redirección a nuestro código inyectado.

La idea con API Hooking es que si podemos enganchar no una, sino todas las APIs del sistema, por ejemplo las de manipulación de archivos o las de conexiones de red, entonces se podría crear un registro en un fichero LOG con todo lo que va modificando el binario cuando se ejecuta, tal y como hacen herramientas de análisis profesional de malware. Esto tiene algunos pros y contras ya que me he encontrado algunos bichos que detectan y eliminan algunos ganchos ya que es una de las técnicas para poder evadir algunas sandbox de análisis de malware, por ejemplo la famosa Cucko Sandbox.

Un ejemplo de API Hooking

En este ejemplo vamos a hacer una pequeña prueba para monitorizar un supuesto fichero malicioso para guardar en un fichero todo lo que haga en nuestro sistema relativo a ficheros y claves de registro. Comenzaremos con el código de este proyecto que se encarga de incluir nuestra DLL dentro del proceso del malware. cargando el proceso suspendido con la función de la API CreateProcess.

En este caso el proceso será nuestro supuesto malware al que he llamado virulo.exe. Posteriormente hacemos espacio en el proceso e incluimos nuestra DLL con VirtualAllocEx y WriteProcessMemory. Para terminar se crea un hilo en la DLL que inyectamos y con ResumeThread conseguimos que siga ejecutándose el proceso suspendido ya con la DLL que se encargará del resto:

Figura 1: Inyectando la DLL

Ahora pasemos al código de la DLL encargada de hacer el gancho donde lo que está remarcado en rojo es quizá lo mas importante para entender cómo funciona. Lo primero que hacemos es obtener la ruta donde está ubicada la librería que contiene la API que nos interesa y así obtener con GetProcAddress el offset de la API. Posteriormente hacemos una llamada a “inyector” que es una rutina que he añadido a la DLL para poder enganchar varias y no solo una API, aunque en este artículo no entraré en tantos detalles. Los parámetro que pide y su contenido son:

Figura 2: DLL que hace el hook de la API
Direcciones: El offset de la API.
Bytesoriginales: Dirección del buffer donde guardaremos los bytes reales.
Bandera: Contiene la dirección a donde queremos redirigir nuestro gancho.
Como verán, el código esta comentado y básicamente lo que hace es guardar en uno de los parámetros que coloqué los bytes originales para mantenerlos y si queremos después volver a colocarlos en su lugar.

Figura 3: Parámetros para volver a reparar el estado

Ya guardado todo, pasa a cambiar los permisos a escritura a la zona donde se inicia la API que queremos enganchar, pues para poder escribir los primeros bytes debemos cambiar el permiso si no saltaría una excepción y no pasaría nada. Después escribe algunos bytes, como son 0x68 que es el offset de mi redirección y 0xc3 que corresponden a un “Push + dirección” y un “RET”. Esto podríamos verlo dentro del debugger, por ejemplo en la API MessageBox.

Figura 4:  Cambiando los permisos y hookeando la API

Esto es básicamente el gancho y ya tenemos hookeada nuestra API lo cual es un columpio hacia nuestro código. En este momento podríamos hacer algunas cosas como registrar todos los movimientos que hace. Apoyándonos con el stack o pila en una API que de acceso al registro como "RegQueryValueExA" podríamos ver en la pila:

Figura 5: Valores en la Pila del proceso

Recuerden que ya estamos en el mismo proceso por lo tanto manipular los parámetros que tiene el stack es simple pues el registro ESP contiene siempre el inicio de la pila. Sumando un ESP+4,  ESP+8, etcétera podríamos obtener los datos de qué es lo que lee, crea, etcétera la API o las APIs hookeadas y hacer un registro de acciones realizadas por el proceso, que era la idea principal de la herramienta, pero también podríamos jugar creando filtros para saber exactamente en qué parte del registro hace los cambios, por ejemplo:

Figura 6: Filtrando los cambios en el registro de Windows

Si queremos restaurar lo que hemos hecho para que todo actúe otra vez normal sin ganchos o redirecciones, podemos hacerlo entrando a otra rutina que nombré como “repairbytes” cuyos parámetros son:
DireccionesAPI: Dirección de la API a restaurar.
Bytesoriginalesencurso: buffer que contiene los bytes originales que guardamos.
Esta rutina es similar a la anterior que escribía al inicio de la API, solo que en lugar de guardar los bytes originales, los saca del buffer y los ubica donde estaban originalmente:

Figura 7: Para dejar el sistema como estaba

Las últimas pruebas que hice fueron monitorizar las actividades del registro y manipulación de archivos, guardando en un fichero de LOG con extensión .ini toda esa información:

Figura 8: El fichero de LOG con los datos de actividad

Conclusiones

Con este ejemplo se puede ver cómo funciona el API Hooking en Ring 3 con el Método del Columpio, utilizado para analizar malware o para hacer proyectos de ingeniería inversa en cualquier otro índole, como por ejemplo las técnicas de cracking, exploiting o fuzzing para hacer  auditoría de seguridad de binarios. Mi idea es seguir desarrollando estas técnicas y hacer una herramienta de monitorización que funcione con solo hacer drag and drop de un binario a una sandbox y genere un informe de actividad, así que si alguien se anima a colaborar que contacte conmigo.

Autor: Alejandro Torres (TorresCrack)
Twitter: @TorresCrack248

5 comentarios:

  1. Hasta ahora la mejor herramienta que yo he usado en reversing para analizar las API calls es API Monitor (en http://www.rohitab.com/apimonitor). Tiene la capacidad de seleccionar por clases aquellas que se quieren detectar así como cambiar los parámetros con que son llamadas en tiempo de ejecución. Una maravilla.

    ResponderEliminar
  2. Nunca he usado API monitor, pero por lo que comentas suena interesante y me da ideas a agregar en futura herramienta, saludos!

    ResponderEliminar
  3. Cuckoo hace algo parecido, inyecta una dll en el proceso analizado que monitoriza toda la actividad del exe, puedes ver el code por aqui:
    https://github.com/cuckoobox/cuckoomon

    Lo mas interesante que tiene es que detecta cuando un proceso lanza otro o cuando está inyectando código en otro para pasar a monitorizar estos procesos tmb.

    Un saludo!

    ResponderEliminar
  4. Si Francisco, cucko usa una técnica similar, para monitorizar como dices se me ocurre, sólo deberia aplicarlo a las diferentes o la mayoría de formas en que pudieras levantar otro proceso o inyectarlo por decir un ejemplo común, con la API 'CreateProcessA' y aplicar un filtro en el hook para tomar datos del siguiente proceso y atachearle la dll, quisiera terminar pronto para mostrar en video (POC)

    Saludos.

    ResponderEliminar
  5. Ese código en que está escrito?
    Lo pregunto porque no parece escrito en C ó C++.

    ResponderEliminar