Como Crear In Driver Con C++
Enviado por allan.aguilar2 • 20 de Octubre de 2013 • 1.586 Palabras (7 Páginas) • 979 Visitas
1. COMO SE DESARROLLAN LOS DRIVERS EN C++?
Para programar drivers no se usa el compilador del Dev ni del MVC++ ni de ningun otro, se usa la DDK (Driver Development Kit), aunque se pueden configurar tanto el MVC++ como el Dev para usar el compilador del DDK.
Una vez se tenga el DDK, hay que instalarlo, luego se va a Inicio / Todos los programas y buscamos el DDK que se instaló, luego hay que ir a Build Environments, desde ahi se puede seleccionar cualquiera, aunque muchos recomiendan usar Win XP Free Build Environment para compilar, lo que tienen que hacer es crear una carpeta y dentro meter el codigo (main.c, por ejemplo) y un archivo SOURCES y un MAKEFILE.
El SORCES tiene que se así:
TARGETNAME=prueba
TARGETPATH=.
TARGETTYPE=DRIVER
SOURCES=main.c
Donde prueba es el nombre del driver que se generará y main.c es el archivo con el código fuente, no se tiene que modificar nada más.
El MAKEFILE es siempre el mismo:
!INCLUDE $(NTMAKEENV)\makefile.def
Una vez tengamos esto, ejecutamos el Win XP Free Build Environment y se nos abrirá una consola, cambiamos el directorio actual con el comando CD, una vez situados dentro de la carpeta donde estan los 3 archivos (como mínimo), tenemos que escribir:
build -cZ
Esto se encarga de compilar y enlazar (linkear) el archivo, si ha habido errores nos lo va a marcar. Si no ha habido errores, nos va a generar el driver dentro de \i386 (se genera una carpeta dentro de la del proyecto). Una vez echo esto, el trabajo de la DDK se puede dar por concluido.
El tema de las herramientas no a terminado, ahora nos falta, como mínimo, una herramienta para cargar el driver y otra para ver los mensajes que el driver nos envía. Ya que un driver no se ejecuta con una consola como los archivos de C/C++ o con una ventana, para poder ver los mensajes que nos envía debemos tener una herramienta adicional.
DebugView: Como su nombre indica, esta herramienta sirve para ver los mensajes que se enviar a través de debug (con el comando DbgPrint). Aunque no solo esta orientada a modo kernel, también sirve para aplicaciones de modo usuario.
OSRLoader: Aunque hay otras, esta es la que uso para cargar los drivers, utiliza el método de cargar lo drivers como servicios, primero seleccionan el driver, registran el servicio y lo ejecutan, una vez terminado, lo pueden parar y para no dejar rastro en el registro pueden eliminar el servicio, aunque esto es opcional.
2. DE UN EJEMPLO DE COMO CONSTRUIR UN DRIVER DE CUALQUIER TIPO. FUNDAMENTE CON CÓDIGO FUENTE.
Hola mundo desde el driver
Como en todo programa, tiene que haber un punto de partida, un main. El de los drivers es así:
Código
1. NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath)
2. {
3. //Codigo
4. }
5.
Como vemos, al DriverEntry se le pasan 2 parámetros, el primero es un puntero a la estructura DRIVER_OBJECT, más adelante veremos como usar esto. El segundo es un puntero a una cadena Unicode donde esta guardada la ruta del registrot con el que se cargó el driver.
Una vez realizadas las tareas en el DriverEntry, tenemos que retornar un valor, si no ha habido ningún error retornaremos STATUS_SUCCESS, de lo contrario, el código de error pertinente.
Cabe decir que retornando el valor no se descarga el driver, ya que para poderse descargar se tiene que crear una rutina, pecisamente esta rutina se crea a partir del puntero al primer parametro. Veamos como se hace:
Código
1. void Salir(PDRIVER_OBJECT DriverObject)
2. {
3. //Codigo de salida
4. }
5.
6. NTSTATUS DriverEntry( PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath)
7. {
8. DriverObject->DriverUnload=Salir;
9. return STATUS_SUCCESS;
10. }
11.
Como vemos aquí, creamos una rutina para que al descargar el driver se llame a la rutina, dentro podemos escribir un mensaje de "Cerrando driver..." o algo asi, o en su caso, unhookear las apis, ya que si cerramos el driver si unhookear la SSDT nos va a mostrar una bonita pantalla azul, ya que se va a llamar una zona de memoria donde no hay nada.
El comando para poder escribir datos al DebugView es el comando DbgPrint y funciona exactamente igual que el printf de C/C++. Si nos miramos la información, vemos que esta dentro de Ntddk.h, asi que la tenemos que incluir. El programa que nos dirá hola mundo al iniciarse y Adiós al cerrarse nos quedaría así:
Código
1. #include <ntddk.h>
2.
3. void Salir(PDRIVER_OBJECT DriverObject)
4. {
5. DbgPrint("Adiós");
6. }
7.
8. NTSTATUS DriverEntry( PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath)
9. {
10. DriverObject->DriverUnload=Salir;
11. DbgPrint("Hola mundo!!!");
12. return STATUS_SUCCESS;
13. }
Una vez echo esto ya podemos abrir el DebugView, le habilitamos la opción para capturar mensajes del Kernel y lo podemos ejecutar. Este ejemplo lo e probado yo mismo y pueden ejecutarlo en el PC, aunque es recomendable siempre hacer pruebas en una maquina virtual, ya que un error en el driver provocaría un reinicio de sistema.
Comunicación entre Modo kernel y modo usuario
Este tema ya es algo mas lioso. Hay varias formas de pasar información desde modo usuario a modo kernel y viceversa, la que yo voy a utilizar es el metodo que utiliza la API DeviceIoControl.
Esto me permite enviar un mensaje desde modo usuario (MU desde ahora en adelante) hacia modo kernel (MK). Además, me retorna un puntero hacia un buffer de salida (de MK a MU) y la longitud de este, si la longitud es igual a 0 no hay datos, de lo contrario si.
La estructura donde se fundamenta la comunicación entre MU y MK es la estructura IRP. Para poder manejarla, en el driver tendremos que crear una funcion que maneje esta estructura. Esta función se declarará igual que declaramos la función de salida en el DriverEntry. Aqui un ejemplo:
Código
1. NTSTATUS Control(PDEVICE_OBJECT DeviceObject,PIRP Irp)
2. {
3. //Codigo
4. }
5.
6. NTSTATUS DriverEntry( PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath)
7. {
8. DriverObject->DriverUnload=Salir;
...