Una advertencia antes de comenzar. El código de este tutorial es funcional y está diseñado para ser compilado y trabajar en un entorno de 32 bits.
EL HOOK A LA API EN DELPHI
Existen dos formas básicas de realizar un Hook a la API y múltiples variantes. Ninguna técnica es perfecta, todas tienen sus ventajas y sus inconvenientes. Todas requieren inyectar código en el proceso anfitrión.
- EL Hook en la IAT:
Quizás la forma mas sencilla sea el Hook en la IAT. La IAT es una Tabla en la cabecera PE de todo ejecutable y DLL que contiene las direcciones de las API y funciones que importa de forma estática (en tiempo de compilación). Cambiando el valor de esas direcciones a una función Gancho tenemos realizado el Hook. Es un método muy estable pero requiere cambiar el valor de la dirección en todos los módulos del proceso que importen dicha API. No funciona para API importada de forma dinámica, es decir con GetProcAddress.
- El Hook Trampolín:
Con esta técnica modificamos instrucciones asm de la API para provocar un salto a nuestro código. Nuestro código debe ser capaz de llamar, después a la API original sin provocar errores. Esta técnica es algo mas compleja que la anterior, funciona para APIs importadas tanto de forma estática como dinámica pero se pueden cometer errores al medir mal el número de bytes sobrescritos, partiendo una instrucción asm y alterando, con ello, el sentido del código.
Hace un tiempo, seoane publicó en su web un código para realizar un Hook a la IAT escrito en delphi. Yo me voy a centrar en la técnica del trampolín.
La filosofía de un Hook de tipo trampolín:
Como expliqué antes tenemos que buscar una fracción de código de la API original que podamos sobrescribir con cierta tranquilidad. Lo ideal es encontrar una zona de longitud 5 bytes, en una o varias instrucciones completas asm. Si nos fijamos como comienza el código asm de una API, casi siempre se repite la misma secuencia:
8BFF mov edi, edi 55 push ebp 8BEC mov ebp, esp
Lo ideal sería que esto fuera una constante, pero me he encontrado APIs con codificación distinta en distintos PCs, posiblemente debido a las distintas actualizaciones del S.O.
Otro buen punto, puede ser buscar una instrucción de salto (jmp) o llamada a subrutina (call) pero lógicamente no la encontraremos en sitios fijos, entorpeciendo un sistema automático de Hook. Esto nos obliga, en cierta forma, a proceder a un desensamblado de parte del código, bien manual para cada API, bien automático. Nosotros vamos a usar un desensamblador de longitud que nos informa de la longitud de las instrucciones asm. Esta herramienta es justo lo que nos hace falta para controlar que no partimos instrucciones al realizar la preparación del hook.
El código que muestro en este tutorial se centra en los 5 primeros bytes de la API. La filosofía será establecer un puntero especial, del mismo tipo que la API que vamos a enganchar. En el código para automatizar Hooks llamaré a este puntero, ToAPI. Vamos a reservar memoria para él de al menos mas de 10 bytes(los 5 o mas copiados desde la API original, más otros 5 para un salto). También escribiremos la función HOOK o suplantadora, que será declarada exactamente como la API original, yo la suelo denominar como la API víctima con el prefijo New. Los primeros 5 o mas Bytes de la API original serán copiados al Buffer apuntado por ToAPI, de forma que se copien instrucciones completas y si hubiese algún salto habría que recalcularlo. Detrás de los 5 o mas bytes copiados, escribiremos una instrucción de salto ($E9) que apunta al resto de código no copiado de la API original. Esto es para poder devolver el flujo del programa al punto donde lo interrumpiremos. En la API original rescribiremos los 5 bytes con otro salto ($E9) que apunta a nuestra función Hook (NewAPI). Cuando nuestro Hook necesite llamar a la API original, usaremos el puntero ToAPI como si fuese una función, que de hecho lo es.
El código de este tutorial es operativo y permite automatizar un Hook a cualquier API a nivel usuario de forma automatizada.
Un ejemplo vale mas que mil palabras, vamos a realizar un Hook a la API MessageBox en nuestro propio proceso. Comenzamos por un esquema de cómo queda el código asm que vamos a alterar: