15 abril 2013

WHF Windows Hooking Framework I

Hace algún tiempo, Yago me "incitó" a que redactara un artículo sobre WHF. Los que no lo conozcais es un Framework que comienza como proyecto final del Master en Auditoría y Seguridad Informática que cursé en la UPM y que expuse en la RootedCON de 2012. (video y slides)

Antes de entrar con el Framework creo necesario explicar qué es un hook. La definición que más me gusta la encontré en la Wikipedia y dice lo siguiente:

En informática, el termino hooking conjunto de tecnicas utilizadas para alterar el comportamiento de un sistema operativo, aplicaciones u otro componente software mediante la interceptación de llamadas a funcionmensajes o eventos intercambiados entre componentes software. El código que trata las llamadas a función, eventos o mensajes interceptados se llama hook

Como se puede ver en la definición hay varios tipos de hooks. Personalmente me gusta clasificarlos en Windows hooks (mensajes), Driver hooks (eventos), y API hooks (llamadas a funcion).

Hooks de Windows. Son los más sencillos para empezar. Se instalan utilizando el API de programación de Windows y permiten interceptar los mensajes enviados a los procesos. En documentación de Microsoft, se define un hook como un punto en el mecanismo de paso de mensajes del sistema operativo, en el cual una aplicación puede instalar una subrutina para monitorizar el tráfico de mensajes entre el operativo y una aplicación. En algunos casos además se puede actuar sobre los mismos antes de que éstos lleguen a la ventana destino.

Driver Hook. Los drivers tienen una característica interesante para instalar hooks sobre eventos. Los drivers permiten definir callbacks que se ejecutarán cuando ocurran ciertos eventos en el sistema operativo, como puede ser el inicio o el fin de un proceso, de un thread o el mapeo de ficheros binarios a memoria entre muchos otros.

API hook. Son hooks que interceptan las llamadas a funciones que realizan los programas. Ejemplos clásicos pueden ser interceptar llamadas a funciones del sistema de ficheros como son OpenFile, WriteFile o ReadFile, llamadas relacionadas con el registro de Windows como RegOpenKeyEx, RegEnumValue o RegCloseKey y funciones para comunicarse por red como connect, send o recv.

Cuando se utilizan API hooks, se consigue modificar el comportamiento de un programa realizando alguna de las siguientes acciones:
  1. Filtrado de llamadas: Según las condiciones que establezcamos se llamará o no a la función
  2. Modificación de los parámetros de entrada de la función, alterando así el resultado de la función
  3. Modificación del valor de retorno de la función, si es que devuelve algún valor, 
Dónde descargar WHF

En sourceforge están disponibles los binarios compilados para Windows XP y Windows 7, comprimidos en un 7z. También esta disponible el código fuente

Cómo instalar WHF

En la wiki del proyecto tengo una guía de instalación con los pasos a dar para instalarlo dependiendo del sistema operativo en el que se vaya a ejecutar.

Cómo utilizar WHF

Hay dos formas de utilizar, la primera es descargarse los binarios compilados para la versión de Windows en la que vayamos a utilizar WHF y la segunda es descargarse los fuentes y compilarlos.

La primera forma de utilizarlo, esta disponible sólo para Windows XP y Windows 7 de 32 bits. Vista no esta contemplado ya que no permite instalar drivers sin firmar y de momento no se estan firmando los drivers que se utilizan. Esta forma es la recomendada para iniciarse rápidamente sin tener que instalar compiladores.

La segunda forma de usarlo es descargarse los fuentes. Esta forma se la que recomiendo a todo aquel que tenga un poco de ganas de trastear con estas cosas de los hooks. Para ello se debe haber instalado  como mínimo Visual Studio 2008 y si se quiere enredar a nivel de kernel WDK. En el WHF hay ejemplos de los diferentes hooks que vamos a hablar en este artículo y os animo a que los modifiquéis y creéis nuevas DLLs y drivers para adaptarlos a vuestras necesidades y/o curiosidades, para mi fue la mejor forma de entender un poco mejor como funciona por dentro Windows.

Componentes de WHF

Tiene 3 componentes principales:

Una GUI (WHF-GUI.exe) desarrollada en C#, que permite configurar los hooks que se van a instalar y bajo que  condiciones instalarlos.

Un instalador de hooks (hooklauncher.exe) desarrollado en C, que es el encargado de leer la configuracion e instalar los hooks.

Los hooks que se implementan en DLLs y drivers que es donde estan los payloads a ejecutar

En la versión actual la configuración de los hooks que utiliza el hooklauncher se guarda en el registro de Windows. En la lista de mejoras esta apuntado tener algún tipo de repositorio central donde guardar esta configuración o ver la posibilidad de integrarlo con ActiveDirectory. Además de convertir el hooklauncher en un servicio de Windows en lugar de un programa de consola.

Configuración

A la hora de configurar los hooks a aplicar se utiliza WHF-GUI que es una interfaz gráfica para definir las reglas y acciones a aplicar.

En la imagen inferior se puede ver WHF-GUI, herramienta con la que se establece la configuración que posteriormente utilizará el instalador de hooks (hooklauncher.exe). Como se puede ver la ventana se divide en dos áreas diferenciadas. En la zona de la derecha se encuentran las políticas o reglas que definen los hooks a aplicar y sobre que procesos o ventanas se aplicarán. En la zona de la izquierda existen dos ayudas para definir estas reglas, que permiten seleccionar una o varias de las ventanas y aplicaciones que estén ejecutándose en ese momento. Además se pueden restringir los resultados a los procesos y ventanas que sean visibles en ese momento.

Mediante las ayudas de la izquierda de la GUI, el administrador de la máquina puede definir a que ventanas y procesos quiere aplicar un hook, como podría ser restringir la ejecución de aplicaciones basándose ademas de en el nombre de proceso en el título de la ventana.


En la imagen inferior se muestran cuatro reglas. Las reglas definen que acción se va a aplicar y sobre que procesos o ventanas se va a aplicar. Las tres primeras columnas permiten discriminar a que procesos o ventanas se aplicarán los hooks definidos en la columna Action. Se puede discriminar por nombre del proceso, título de la ventana y por WindowClass. Si una columna no tiene valor, ese campo no se tendrá en cuenta a la hora de discriminar sobre quien aplicar la acción definida. La última columna tiene un valor numérico que representa el identificador de la acción a aplicar. Este valor se asigna automáticamente y no es editable y permite saber si varias reglas aplican la misma acción. En el ejemplo superior cada regla tiene una acción diferente. Así cuando se detecte un navegador Chrome (proceso chrome.exe) con el título de ventana "Barcelona en AS.com - Google Chrome" y WindowClass "Chrome_Widget" se le aplicará la acción 2. A los navegadores Chrome con título de ventana "As.com: noticias..." se les aplicará la accion 3. Sin embargo a todos los navegadores Firefox se les aplicará la acción 4 y a todos los demás procesos y ventanas la acción 1


El orden de las reglas es importante ya que marca la prioridad a la hora de aplicar acciones. Con los botones Up / Down se puede subir o bajar una regla.

Las acciones se definen haciendo click con el raton en la columna acción. También se pueden seleccionar varias reglas y aplicarles la misma acción mediante el boton "Group edit".

Como se puede ver en la imagen inferior, la ventana de selección de acciones permite definir los hooks a aplicar y el horario en el que se aplica. Si no se define horario se aplicará siempre. No voy a entrar mucho en detalle ahora por que en el próximo punto con ejemplos prácticos se explica mas en profundidad su funcionamiento. Sólo destacar que por defecto se dispone de dos DLLs llamadas testDll.dll e testIAT.dll, pero se pueden añadir más DLLs para poder aplicar hooks definidos en otras DLLs mediante el botón LoadDll. Una vez seleccionada se añadirá al combo de DLLs y las funciones que exporte dicha DLL estarán disponibles para definir la acción.


Practica

Como siempre al final esta lo divertido. En las siguientes lineas voy a mostrar configuraciones que podéis establecer para usar WHF en vuestros ordenadores.

Al iniciar WHF-GUI os aparecerá una ventana como la que se muestra en la imagen inferior. Esta pantalla sirve para seleccionar para que usuario se quiere crear una configuración  Si se selecciona un usuario la pantalla inicial cargará la configuración del usuario seleccionado. Si se pulsa cancelar la pantalla inicial estará vacía.


A la hora de guardar una configuración pulsando el boton Save aparecerá la siguiente ventana, que permite tres opciones a la hora de almacenar una configuración:
  • Guardar la configuración para todos los usuarios de la máquina
  • Para el usuario en el que estamos conectados. Esta es la que utilizaremos en los ejemplos
  • Para los usuarios que le indiquemos 


hooklauncher a la hora de seleccionar la configuración a aplicar, intentará localizar primero la configuración del usuario con el que se esta logado en el sistema y si no la encuentra intentará aplicar la configuración general de todos los usuarios.

Unos diez segundos después de que se haya lanzado el hooklauncher aparece la ventana que se muestra en la imagen inferior. Para detener el hooklauncher debéis pulsar en Cancelar y hooklauncher se encargará de desinstalar los hooks que se hayan instalado. Si cerráis el hooklauncher sin pulsar Cancelar algunos hooks pueden permanecer instalados y no retirarse hasta que se reinicie el equipo.


Ejemplo 1, Registrando el uso de aplicaciones a través de pulsaciones de teclado y clicks de ratón

En el siguiente ejemplo vamos a mostrar como se puede crear un fichero de log con las horas a las que se ha interactuado con una ventana (teclado o ratón  y sus características (PID, titulo de la ventana y clase de la ventana). 

En primer lugar seleccionamos las aplicaciones que queremos monitorizar. En el ejemplo he seleccionado el notepad y los navegadores, en mi caso chorme, firefox y iexplore

A continuación seleccionamos todas las filas y pulsamos el botón "Group Edit" para asignarles a todos la misma acción.


Una vez en la ventana de selección de acciones pulsamos en check box WinHook. El primer combo a la derecha de este check nos permite seleccionar el tipo de mensaje a hookear. El segundo nos permite seleccionar la DLL donde se encuentra la función a aplicar para este hook. En el tercer combo se muestran los símbolos que exporta la DLL del segundo combo. Entre ellos estará la función que se quiere aplicar.

Para este ejemplo seleccionamos en el primer combo WH_KEYBOARD, indica que es un hook sobre el teclado, en el segundo combo seleccionamos la DLL testDll.dll y en el tercero la función KeyboardRegister. Por último pulsamos el check global para indicar que queremos que el hook se instale en todas las ventanas del escritorio (la función KeyboardRegister se encargará de aplicarlo sólo a las ventanas que hemos indicado en la configuración). Por último pulsamos Add

Posteriormente repetimos el proceso para hookear el raton, seleccionamos WH_MOUSE, testDll.dll y la función MouseRegister. volvemos a marcar el check global y pulsamos Add.

La pantalla de acciones debe quedar como la de la figura inferior.



Una vez terminado, pulsamos Ok y en la pantalla principal pulsamos Save. En las opciones de Guadar seleccionamos Current User.

Ahora ejecutamos hooklauncher y debeis utilizar el notepad y los navegadores que se hayan configurado durante un rato. Cuando terminéis pulsad Cancelar en la ventana de hooklauncher para desinstalar los hook. En el directorio C:\WHF\TestingPath\ se habrá creado una carpeta para cada proceso como muestra la imagen inferior.


Y dentro de cada carpeta hay un fichero con la fecha del día.


Si abrís el fichero, tendrá un log como el que se muestra en la imagen inferior con las horas a las que se estuvo utilizando esa aplicación junto con la información del ProcessId, título de la ventana y clase de la ventana


Ejemplo 2,  Ocultando ventanas.

Imaginemos que en una determinada situación, no queremos que el usuario utilice un determinado programa a la hora de editar documentos, pero no queremos ser tan agresivos como para terminar el proceso en cuestión. Una opción puede ser ocultar la ventana al usuario.

En el ejemplo siguiente no queremos que edite el fichero noMirar.txt con el notepad.exe. Para ello aprovecharemos que notepad establece como titulo de la ventana el nombre del fichero. La imagen inferior muestra la configuración a utilizar.



En la pantalla de acciones seleccionamos WH_MOUSE, la DLL testDll.dll y la función MouseProcHideWindow. Por último marcamos la opcion global, tal y como se puede ver en la imagen inferior.


Una vez salvada esta configuración y lanzado el hooklauncher, cuando el usuario abra con el notepad el fichero noMirar.txt y trate de posicionarse con el ratón en el fichero, la ventana desaparecerá, pero el proceso notepad.exe seguirá vivo en el sistema.

Si se quiere modificar el comportamiento de este hook, se debe localizar la función MouseProcHideWindow dentro del proyecto TestDll. En la imagen inferior podemos ver ante que eventos de ratón llamamos a la función HideWindow

La función HideWindow utiliza una serie de estructuras que se deben utilizar si queremos que el hook utilice la configuración establecida con WHF-GUI para discriminar a quien se le aplica el mismo. La parte resaltada es donde debemos introducir nuestro código. En este ejemplo llamamos a la función ShowWindow, en ese punto es donde se debe introducir el código que queremos que ejecute nuestro  hook.


Ejemplo 3, Linux Copy&Paste.

Para aquellos que seáis Windows 100%, hay una funcionalidad en Linux que igual desconocéis y que me parece especialmente útil. Es la opción de seleccionar un texto con el ratón y posteriormente pulsando el botón intermedio del ratón pegarlo. En mi trabajo tengo dos ordenadores un Windows y un Linux que comparten teclado y raton mediante Synergy. Synergy además comparte el Clipboard lo cual te permite llevarte un texto de un ordenador a otro. Normalmente para hacer esta operación seleccionaba un texto en el equipo Windows y para copiarlo tenia que pulsar Ctrl+C. Posteriormente en el Linux pulsaba el botón intermedio del ratón para pegarlo. Cuando quería hacer la operación inversa marcaba el texto en la Linux y para pegarlo tenía que hacer Ctrl+V. Para evitar utilizar el teclado y seguir utilizando el comportamiento de la maquina Linux en la maquina Windows, implementé este hook que simula este comportamiento.

En este ejemplo vamos a aplicar el hook a todas las ventanas del sistema, para ello establecemos una regla sin Process Name, Window Title o Window Class.



A esta regla le definimos la siguiente acción. Seleccionamos WinHook y en el primer combo seleccionamos WH_MOUSE, en el segundo seleccionamos testDll.dll y en el tercero la función LinuxCopyAndPaste. Por último marcamos la opción global. En la imagen inferior se muestra esta acción.

Ejecutando hooklauncher, podréis observar que ahora tenéis el comportamiento descrito funcionando en Windows. Si  se quiere restringir este comportamiento a editores de texto y/o navegadores, bastaría con definir una regla con el nombre de cada proceso, editarlas todas en grupo y configurar la acción anteriormente descrita.

En la segunda parte abordaré los API hooks y los hooks con drivers.

Un saludo
@psaneme

2 comments :

Capi dijo...

Muy chulo el articulo ;)

Alexander Aguirre dijo...

Excelente articulo