¿Nadie piensa en las DLL? II
¿Nadie piensa en las DLL? I
¿Nadie piensa en las DLL? II
[…]
Continuamos con esta segunda parte, profundizando un poco más en las librerías.
Inicialización de las DLL
Tal y como había comentado en la parte 1, todas las librerías sea cual sea la forma en la que se cargan van a ser inicializadas por el sistema operativo. Esto quiere decir, que una pequeña parte de código será ejecutada. Es importante tener esto muy en cuenta ya que es el vector de ataque.
¿Para qué se inicializan las librerías?
Según Microsoft:
Sirve para realizar gestiones de memoria. En caso de ser necesario hacer una reserva de la misma. También se admiten otras gestiones previas a la utilización de la librería. Con la única salvedad, “no se permite ejecutar (iniciar) hilos.”
En este punto, podemos comenzar a desarrollar nuestro código, teniendo en cuenta que será lo primero en ser ejecutado y tendremos control total sobre la aplicación que ha cargado la librería.
Rompiendo un ejecutable
He creado un programa que muestra por consola un mensaje diciendo que es capaz de dividir 0 entre 0. Obviamente la aplicación no es capaz de realizar la división y es en ese momento en el que fallará estrepitosamente. Mostrando una ventana de error.
El código del programa es más o menos así:
- Muestra un mensaje
- Intenta cargar una librería <- Nuestro vector
- Muestra la dirección de memoria en la que ha cargado la DLL.
- Intenta divir 0/0 <- En este punto falla y finaliza la ejecución.
- Muestra un mensaje diciendo que el programa ha sido reparado y funciona normalmente.
Este último mensaje nunca lo podríamos ver, ya que falla justo antes. Es aquí donde la DLL tendrá que hacer una modificación del código para que se pueda ejecutar normalmente.
¿Qué tiene que hacer la librería?
Si miramos el código en ensamblador vemos lo siguiente:
Vamos a intentar poner un nop (No Operation) en la zona señalada. De esta manera la aplicación nunca intentará dividir entre 0, y por lo tanto al no dar un error, podrá continuar la ejecución de forma normal, permitiéndonos ver el mensaje y finalizando normalmente.
De todo esto se tiene que encargar la librería que el programa ha intentado cargar. La carga se está realizando de forma dinámica, por lo que se puede ejecutar el programa de forma normal sin que muestre un error en caso de no existir la DLL. En caso de existir intentará colocarla en una sección de la memoria.
Para comprobar que es lo que ocurre te recomiendo ejecutar el programa sin la librería y luego con la librería en la misma carpeta. En caso de no estar la librería el programa fallará, pero será debido a la división y no a la falta de la DLL.
El pseudocódigo de la librería es el siguiente:
- Inicialización de la librería
- Detecta si ha sido incluida en un programa (Con cualquier tipo de carga)
- Busca la posición de memoría: 0040141Ch (La que queremos noopear)
- Cambia los permisos a lectura, ejecución y escritura
- Pone los bytes “909090” (NOP) en esa posición de memoria
- Restaura los permisos anteriores de esa posición.
- Devuelve el control a la aplicación
Con estos cambios ya tendremos la aplicación reparada y funcionando. De esta manera vamos a poder ver el mensaje final.
Ha quedado demostrado que con una librería podemos modificar todo el código del programa y no sólo eso, si no que podemos acceder a zonas criticas de la memoria con el riesgo que esto implica.
WiNSoCk