Título: [Artículo] Parcheo de memoria en Drivers Externos Publicado por: Hendrix en 29 Octubre 2009, 20:21 pm Hacia ya mucho tiempo que no publicaba nada por este foro, es hora de quitarse la oxidación que provoca esto, así que me e decidido a publicar este post.
Antes de nada, quiero decir que este post esta orientado a personas que sepan programar drivers, si eres de los que todavía no saben que es un driver, o no saben programarlo, por favor, lean este post (http://foro.elhacker.net/analisis_y_diseno_de_malware/introduccion_a_la_programacion_de_drivers_en_windows-t231193.0.html). Las respuestas a este mensaje de tipo técnico (problemas con la DDK, con las herramientas usadas, etc.) por favor, háganlos en otros posts y en los subforos correspondientes. Cabe decir que este artículo es similar a uno que publiqué hace tiempo, lo tenia en PDF solamente y el host donde estaba alojado actualmente esta caído. Al no tener ninguna copia (y al tener un rato libre :P) e decidido reescribirlo (y reprogramarlo) de nuevo. Una vez explicado esto, comencemos :) Parcheo de memoria en Drivers Externos ¿Que se pretende conseguir? Lo que pretendo conseguir es la modificación de memoria en drivers externos, es decir, conseguir modificar el comportamiento de un driver externo sin que este se entere de que está siendo modificado. Herramientas a usar: Yo e usado las siguientes:
Por si a alguien le interesa, que sepa que puede desensamblar el driver con un programa llamado Syser, el cual permite debuggear drivers ;) Driver Objetivo: El driver que vamos a "destripar" es un driver que programé yo mismo, el cual nos bloquea la eliminación del fichero C:\prueba.txt. El código del mismo será publicado al final. Manos a la obra: Bien, ya que es un entorno emulado, controlamos la ejecución del driver y conocemos la API que va a hookear, podemos sacar la dirección real de dicha API con el WinDbg. Para ello lo abrimos, Kernel Debug --> Local. Una vez echo esto, escribimos u nt!NtOpenFile y nos da lo siguiente: Citar lkd> u nt!NtOpenFile nt!NtOpenFile: 8056f41a 8bff mov edi,edi 8056f41c 55 push ebp 8056f41d 8bec mov ebp,esp 8056f41f 33c0 xor eax,eax 8056f421 50 push eax 8056f422 50 push eax 8056f423 50 push eax 8056f424 50 push eax La dirección que está en negrita es la dirección en la SSDT de dicha API Nota: Aunque nosotros hookeemos la API ZwOpenFile, en el WinDbg tenemos que escribir NtOpenFile, para obtener la dirección real. Bien, nos anotamos en el notepad dicha dirección. (En el programa "parcheador", e harcodeado las direcciones para una mayor comodidad y para no complicar la cosa, aunque todas se pueden obtener automáticamente programando dichos módulos (por ejemplo, para sacar la dirección real de la API, etc.)). Una vez tenemos esto, ya podemos cargar nuestro driver, y como vemos, hookea perfectamente y nos impide la eliminación del archivo antes mencionado: (http://i.elhacker.net/i?i=vI54IR1oNPu5RidicIJbX2Vo) Bien, ahora lo que tenemos que hacer es empezar a desensamblar la función que nos bloquea el acceso al fichero. Si buscamos su dirección en el IceSword la encontraremos rápidamente, aunque no hace falta, ya que lo e incluido yo mismo en el output del driver (lo veos con DebugView), para mayor comodidad. La dirección de la función es: Citar Dirección después del Hook: 0xf7bcc4ce Esto es en mi maquina virtual, en la suya puede ser diferente ;) Una vez tenemos la dirección, vamos a desensamblarla con el WinDbg, para ello escribimos: u 0xf7bcc4ce l40 nos da esto: Citar lkd> u 0xf7bcc4ce l40 f7bcc4ce 6a10 push 0x10 f7bcc4d0 6860c8bcf7 push 0xf7bcc860 f7bcc4d5 e88e020000 call f7bcc768 f7bcc4da ff751c push dword ptr [ebp+0x1c] f7bcc4dd ff7518 push dword ptr [ebp+0x18] f7bcc4e0 ff7514 push dword ptr [ebp+0x14] f7bcc4e3 8b7510 mov esi,[ebp+0x10] f7bcc4e6 56 push esi f7bcc4e7 ff750c push dword ptr [ebp+0xc] f7bcc4ea 8b7d08 mov edi,[ebp+0x8] f7bcc4ed 57 push edi f7bcc4ee ff15a0c9bcf7 call dword ptr [f7bcc9a0] f7bcc4f4 85c0 test eax,eax f7bcc4f6 0f8583000000 jne f7bcc57f f7bcc4fc 2145fc and [ebp-0x4],eax f7bcc4ff 6a01 push 0x1 f7bcc501 ff7608 push dword ptr [esi+0x8] f7bcc504 8d45e0 lea eax,[ebp-0x20] f7bcc507 50 push eax f7bcc508 ff1508c8bcf7 call dword ptr [f7bcc808] f7bcc50e 8b45e4 mov eax,[ebp-0x1c] f7bcc511 be80c9bcf7 mov esi,0xf7bcc980 f7bcc516 8a16 mov dl,[esi] f7bcc518 8aca mov cl,dl f7bcc51a 3a10 cmp dl,[eax] f7bcc51c 751a jnz f7bcc538 f7bcc51e 84c9 test cl,cl f7bcc520 7412 jz f7bcc534 f7bcc522 8a5601 mov dl,[esi+0x1] f7bcc525 8aca mov cl,dl f7bcc527 3a5001 cmp dl,[eax+0x1] f7bcc52a 750c jnz f7bcc538 f7bcc52c 46 inc esi f7bcc52d 46 inc esi f7bcc52e 40 inc eax f7bcc52f 40 inc eax f7bcc530 84c9 test cl,cl f7bcc532 75e2 jnz f7bcc516 f7bcc534 33c0 xor eax,eax f7bcc536 eb05 jmp f7bcc53d f7bcc538 1bc0 sbb eax,eax f7bcc53a 83d8ff sbb eax,0xffffffff f7bcc53d 85c0 test eax,eax f7bcc53f 7538 jnz f7bcc579 f7bcc541 f6450e01 test byte ptr [ebp+0xe],0x1 f7bcc545 7432 jz f7bcc579 f7bcc547 6880c4bcf7 push 0xf7bcc480 f7bcc54c e809020000 call f7bcc75a f7bcc551 59 pop ecx f7bcc552 57 push edi f7bcc553 ff1500c8bcf7 call dword ptr [f7bcc800] f7bcc559 832700 and dword ptr [edi],0x0 f7bcc55c 834dfcff or dword ptr [ebp-0x4],0xffffffff f7bcc560 b8080000c0 mov eax,0xc0000008 f7bcc565 eb18 jmp f7bcc57f f7bcc567 33c0 xor eax,eax f7bcc569 40 inc eax f7bcc56a c3 ret f7bcc56b 8b65e8 mov esp,[ebp-0x18] f7bcc56e 68a4c4bcf7 push 0xf7bcc4a4 f7bcc573 e8e2010000 call f7bcc75a f7bcc578 59 pop ecx f7bcc579 834dfcff or dword ptr [ebp-0x4],0xffffffff f7bcc57d 33c0 xor eax,eax Como vemos nos muestra un montón de información, aunque, rápidamente, vemos lo que nos interesa, concretamente esto: Citar f7bcc4da ff751c push dword ptr [ebp+0x1c] f7bcc4dd ff7518 push dword ptr [ebp+0x18] f7bcc4e0 ff7514 push dword ptr [ebp+0x14] f7bcc4e3 8b7510 mov esi,[ebp+0x10] f7bcc4e6 56 push esi f7bcc4e7 ff750c push dword ptr [ebp+0xc] f7bcc4ea 8b7d08 mov edi,[ebp+0x8] f7bcc4ed 57 push edi f7bcc4ee ff15a0c9bcf7 call dword ptr [f7bcc9a0] Como vemos, hay unos cuantos push, y luego un call a la dirección almacenada en 0xf7c5caa0. Humm, esto suena a variable!!, vamos a ver que hay dentro, para ello: dd 0xf7bcc9a0: Citar dd f7bcc9a0 f7bcc9a0 8056f41a f7abbb9c 00000000 00000000 f7bcc9b0 00000000 00000000 00000000 00000000 f7bcc9c0 00000000 00000000 00000000 00000000 f7bcc9d0 00000000 00000000 00000000 00000000 f7bcc9e0 00000000 00000000 00000000 00000000 f7bcc9f0 00000000 00000000 00000000 00000000 f7bcca00 00000000 55ff8b00 98a1ec8b 85f7bcc9 f7bcca10 bb40b9c0 04740000 2375c13b c82c158b Bingo!! les suena de algo la dirección subrayada? Exacto, es la dirección real de la api ZwOpenFile (Si no están seguros, escriban u 0x8056f41a y automáticamente el WinDbg les va a resolver el nombre ;)) Bien, ya sabemos que en la dirección 0xf7c5caa0 se encuentra almacenada la dirección real a la API. Por lo que podemos interpretar el siguiente código en ensamblador: Código
Que, efectivamente, es la llamada a la API, bien, lo que tenemos que hacer, es que en lugar de saltar a la API real, nos salte a una función nuestra, la cual estará formada por los argumentos correspondientes a ZwOpenFile, así que no quedará la siguiente función: Código: NTSTATUS ZwOpenFileRep(OUT PHANDLE FileHandle,IN ACCESS_MASK DesiredAccess,IN POBJECT_ATTRIBUTES ObjectAttributes,OUT PIO_STATUS_BLOCK IoStatusBlock,IN ULONG ShareAccess,IN ULONG OpenOptions) Bien, pensemos la jugada, lo que vamos a hacer es escribir la dirección de nuestra función dentro de la variable del otro driver, el cual se cree que dicha variable contiene la variable real y, sin verificar nada, salta directamente hacia la función, en la cual nosotros tomaremos el control y lo que vamos a hacer será, llamar a la API real, le pasaremos los parámetros adecuados y ejecutará la acción pertinente, una vez ejecutado, lo que vamos a hacer será limpiar los datos de un argumento (el que contiene la ruta del archivo a eliminar), lo que lograremos así será saltarnos el filtro del driver, ya que como no tiene ningún dato, no puede aplicar su filtro. Bien, si leíste el post que publiqué sobre la introducción a la programación de drivers, te acordarás que no podemos modificar la memoria "al tun tun", ya que esta protegida y lo único que conseguiríamos seria un bonito BSOD. Para ello, me e servido del siguiente código: Antes de modificar la memoria: Código
Después de modificar la memoria: Código
Bien, antes de seguir trabajando definiremos las variables que usaremos, yo e usado las siguiente: Código
En la variable det está la dirección de la variable del driver en la cual está guardada la variable (Se puede obtener esta dirección con un código en ensamblador en el que, con un bucle, recorramos la memoria del driver en busca de datos que empiecen por 8056 (los primeros dígitos de la dirección real de la API), yo no me e querido complicar tanto y lo e harcodeado). En dir esta la dirección real de la API y en MyDir la dirección de mi función, donde recibiré la llamada del driver "victima". El código que e usado para sobrescribir la memoria del driver no es muy "elegante", pero bueno, aquí esta: Código
Escribo el Try & Catch porque sirve de mucho para evitar alguna que otra BSOD, así que recomiendo su uso. Dicho esto, el DriverEntry de nuestro driver nos quedaría así: Código
En el evento UnLoad del driver tenemos que acordarnos a restaurar la variable del driver "victima", ya que de lo contrario, va a llamar a una dirección de memoria invalida y provocará BSOD ;) Así que dejamos el evento UnLoad de la siguiente manera: Código
Como vemos, es exactamente el mismo código que el del DriverEntry, pero esta vez escribimos la dirección real en lugar de la dirección de nuestra función. Vamos al siguiente paso, la función que recibirá la llamada. Esta función es la misma que utilizaríamos si quisiéramos hookear a ZwOpenFile (de echo, yo e reciclado la función del driver "victima" y la e pegado tal cual en el "envenenador"). Pego la función aquí y explicare el único punto importante que hay: Código
Como ven en los comentarios, el punto importante es el uso de la función InitializeObjectAttributes para resetear la estructura ObjectAttributes, ya que en esta estructura, entre otras cosas, se almacena la ruta del archivo con el que se va a tratar. Si lo reseteamos, el driver "victima" nunca podrá saber el nombre del archivo, y como no esta en su filtro, dejará ejecutar la acción. Una vez tenemos esto, podemos probar nuestro código. Ejecutamos primero el driver victima y miramos lo que contiene su variable en la que tiene que haber la dirección real de la API ZwOpenFile, esto es lo que nos muestra: Citar lkd> dd f7bcc9a0 f7bcc9a0 8056f41a f7abbb9c 00000000 00000000 f7bcc9b0 00000000 00000000 00000000 00000000 f7bcc9c0 00000000 00000000 00000000 00000000 f7bcc9d0 00000000 00000000 00000000 00000000 f7bcc9e0 00000000 00000000 00000000 00000000 f7bcc9f0 00000000 00000000 00000000 00000000 f7bcca00 00000000 55ff8b00 98a1ec8b 85f7bcc9 f7bcca10 bb40b9c0 04740000 2375c13b c82c158b Como ven, esta la dirección correcta de la API, vamos a ejecutar nuestro "envenenador", a ver que pasa: Citar lkd> dd f7bcc9a0 f7bcc9a0 f7c944aa f7abbb9c 00000000 00000000 f7bcc9b0 00000000 00000000 00000000 00000000 f7bcc9c0 00000000 00000000 00000000 00000000 f7bcc9d0 00000000 00000000 00000000 00000000 f7bcc9e0 00000000 00000000 00000000 00000000 f7bcc9f0 00000000 00000000 00000000 00000000 f7bcca00 00000000 55ff8b00 98a1ec8b 85f7bcc9 f7bcca10 bb40b9c0 04740000 2375c13b c82c158b Juas Juas, se lo a tragado (y si han podido ver esto, es porque no les ha dado BSOD :xD) Si todo a funcionado bien, nuestra función debe de recibir ya la llamada del driver victima (lo hace, para ello pueden poner un simple DbgPrint("Me llaman"); en la función del driver de "envenenamiento"). Si echamos un ojo en el DbgView, vamos a ver que sale un montón de mensajes de "Error en el procesamiento del driver", esto sale desde el driver victima, ya que al no verificar que el ObjectAttributes esta vació, provoca error (esto lo e echo a propósito para que aprendas que, aparte de validar las variables que llamamos, siempre se tienen que validar este tipo de cosas, un error en modo Kernel puede ser muy grave ;)). Ahora si intentamos eliminar el archivo prueba.txt situado en C:\ veremos como no nos da ninun tipo de problema, ya que el driver de filtrado no puede saber que archivo queremos eliminar. Si cerramos el driver "envenenador" se restablecerá la dirección real de la API en dentro de la variable del driver de filtrado, y si cerramos este, eliminara en hook que había puesto en la SSDT, y va a creer que ha echo bien su trabajo, pero nosotros sabemos que no :D Creo que no me e dejado nada en el tintero, espero que este texto sirva para animaros a programar algo en modo kernel, os aseguro que si estos temas (de modo Kernel) se trataran más en este subforo la gente participaría un 300% más de lo que se participa en este foro, estoy seguro ;) Yo e dado el primer paso, ahora os toca a vosotros dar el vuestro, para poder charlar de un tema que personalmente me apasiona, no creen que lo de los troyanos y joiners ya esta muy visto? demos un paso al frente y progresemos ;) Por último, quiero dar las gracias a Mek, ya que parte de este concepto lo desarrollamos el y yo en el driver con el que "combatíamos" al sXe :D Un Saludo :) Código completo del Driver de filtrado: Código
Código completo del Envenenador: Código
(http://i.creativecommons.org/l/by-nc-sa/3.0/es/88x31.png) Título: Re: [Artículo] Parcheo de memoria en Drivers Externos Publicado por: Jaixon Jax en 29 Octubre 2009, 22:02 pm :D
Tremenda aportacion voy ha desempolvar el DDK y el manual para ver si ahora si tengo suerte con La programacion de Drivers :silbar: . La modestia de Hendrix es de admirar no quiso autocolocarce chincheta :xD me inmagino que Karckrack mañana lo colocara en la cartelera ... :) Saludos ... Título: Re: [Artículo] Parcheo de memoria en Drivers Externos Publicado por: Hendrix en 29 Octubre 2009, 22:07 pm :D Tremenda aportacion voy ha desempolvar el DDK y el manual para ver si ahora si tengo suerte con La programacion de Drivers :silbar: . Te animo a eso :D a tu y todos los que lean este post :) La modestia de Hendrix es de admirar no quiso autocolocarce chincheta :xD me inmagino que Karckrack mañana lo colocara en la cartelera ... :) jejejeje Muchas veces se ve primero el primer post sin chincheta que no las chinchetas :) Título: Re: [Artículo] Parcheo de memoria en Drivers Externos Publicado por: [Zero] en 29 Octubre 2009, 22:21 pm Aún nunca me propuse en serio programar nada en Kernel Mode, pero parece que seguir pasandose por aquí sin hacerlo va a ser un suplicio :xD. Mañana me releeré lo de Introducción a la programación de Drivers en Windows y luego leo ésto a ver si saco algo en limpio, gracias por éstas aportaciones, la verdad no se de muchas personas que escriban sobre éstos temas en español, y siempre es de agradecer :P.
jejejeje Muchas veces se ve primero el primer post sin chincheta que no las chinchetas :) Sobre todo si ves que el autor es Hendrix :xD. Saludos Título: Re: [Artículo] Parcheo de memoria en Drivers Externos Publicado por: Karcrack en 30 Octubre 2009, 15:57 pm Muy bueno :D
Pufff... viendo esto me doy cuenta de lo lejos que estoy de hacer un driver de verdad con VB :xD jejejeje Muchas veces se ve primero el primer post sin chincheta que no las chinchetas :) Sobre todo si ves que el autor es Hendrix :xD. Ya se pondrá la chincheta cuando quiera :P Por mi parte ya la tiene :laugh: Título: Re: [Artículo] Parcheo de memoria en Drivers Externos Publicado por: Hendrix en 30 Octubre 2009, 19:20 pm Ya se pondrá la chincheta cuando quiera :P Por mi parte ya la tiene :laugh: No soy de los de autocolocarse chinchetas, si algun otro mod/Mod global opina que merece estar pegado, que se la ponga, no soy de los que porque el texto es mio se merece una chincheta :) Animense a probar el codigo y a segguir avanzando, sujieran mejoras (que las hay), descubran fallos (que los hay), etc. :) Título: Re: [Artículo] Parcheo de memoria en Drivers Externos Publicado por: Karcrack en 30 Octubre 2009, 19:26 pm Mira que eres modesto :P
Ya tienes lo que te mereces!(http://foro.elhacker.net/Themes/newgeneration/images/icons/quick_sticky.gif) Título: Re: [Artículo] Parcheo de memoria en Drivers Externos Publicado por: Arkangel_0x7C5 en 30 Octubre 2009, 22:54 pm Sólo he visto a 2 personas usar este método je je
la primera vez me ánimo a programar un driver y aprendí muchas cosas por el camino. Os animo a que lo intenteis. ;D Título: Re: [Artículo] Parcheo de memoria en Drivers Externos Publicado por: n3fisto en 21 Julio 2010, 05:36 am No se si me das permiso para poder subir a mi blogger tus tutos y articulos son muy buenos...
Título: Re: [Artículo] Parcheo de memoria en Drivers Externos Publicado por: Hendrix en 21 Julio 2010, 13:54 pm Claro, siempre que pongas la fuente de donde lo sacaste ;)
Un Saludo :) Título: Re: [Artículo] Parcheo de memoria en Drivers Externos Publicado por: TheHck en 28 Julio 2010, 20:05 pm INTERESANTE EL ARTICULO COMO MUESTRA DE PARCHAR EN MEMORIA DE UN DRIVER, PERO ME PARECE POBRE DE COMO ATACAR EL PROBLEMA.
THE HCK Título: Re: [Artículo] Parcheo de memoria en Drivers Externos Publicado por: [L]ord [R]NA en 28 Julio 2010, 20:35 pm Para atacar el problema todo ya es cuestion de imaginacion.
|