En la anterior entrada vimos la necesidad de utilizar las funciones GetModuleHandle y GetProcAddress para invocar a otras funciones de Windows.
No hay que olvidar que el objetivo de todo esto es poder añadir código a un ejecutable ya compilado el que seguramente no use las funciones que nosotros necesitamos.
Lo primero a tener en cuenta es que la función GetModuleHandle en realidad devuelve la dirección de memoria donde está cargada una DLL. La dirección donde se carga Kernel32.dll no siempre es la misma así que necesitamos buscar donde ha cargado Windows la librería.
Una de las formas de hacer esto la encontré en los manuales de programación de Virus de ZeroPad que podéis encontrar en el grupo de google de SectorVirus.
;Obtiene la dirección base de Kernel32 ObtenerKernel32 proc mov eax, dword ptr [esp+0Ch];Nos quedamos con la dirección de retorno hacia la funcion createprocess and eax, 0FFFFF000h ;Paginas de 1000h searchMZ: sub eax, 1000h cmp word ptr[eax], "ZM" jnz searchMZ ret ObtenerKernel32 endp
El código lo que hace es tener en cuenta que el loader de Windows cuando carga un ejecutable con la función CreateProcess se deja en la cima de la pila el valor de retorno a la función CreateProcess. Y como esta función está en Kernel32.dll ya tenemos una dirección de memoria de kernel32, a continuación va restando de 1000h en 1000h hasta encontrar el inicio de la DLL, los caracteres “MZ”. Este método lo he probado en Windows XP e Windows 7. Desconozco si en versiones viejas funciona o no.
Otra opción para encontrar la dirección donde se ha cargado Kernel32.dll es recorrer ciertas estructuras del PEB, pero la cosa ya se complica. En otra entrada se vera un método mas genérico.
Una vez hallado el inicio de kernel32 lo siguiente es localizar la tabla de funciones exportadas, ExportTable, accediendo a la tabla de directorios, PE+78h. Sabiendo donde está la ExportTable, se accede al campo ExportNameTable, ET+20h, donde están los nombres de todas las funciones exportadas y vamos comparando los nombres con la función que buscamos. Una vez localizado recordamos la posición donde lo hemos encontrado y mediante la tabla Export Ordinal Table obtenemos el índice para ya por fin acceder a la tabla Export Address Table que contiene la dirección de la función que tanto a costado conseguir jeje.
Lo he explicado muy resumidamente, en el capítulo 7 de SectorVirus que cuelgo aquí está explicado con todo detalle la estructura de la ExportTable y como recorrerla para encontrar una determinada función.
A continuación dejo la función en ensamblador que hace esto. Necesita saber la dirección de kernel32 hallada anteriormente.
.data Kernel32Dir dd 0 PEHeader dd 0 ET dd 0 PosicionEAT dw 0 Contador dd -1 FuncionBuscada db "GetProcAddress",0 FuncionBuscadaLen dd 0Eh .code ObtenerGPA proc mov eax, [Kernel32Dir] add eax, [eax+3Ch] ;Obtenermos el inicio del PE mov [PEHeader], eax add eax, 78h ;RVA de la export table mov eax, [eax] add eax, [Kernel32Dir] ;Pasamos de dirección relativa virtual, RVA, a dirección virtual mov [ET], eax ;Guardamos el valor add eax, 20h ;Nos situamos en la ExportNameTable, ET+20h mov eax, [eax] add eax, [Kernel32Dir] ;RVA->VA bucle: ;Bucle para comprobar si es la función GetProcAddress inc [Contador] ;Para saber en que posicion está la funcion mov ebx, [eax] ;Direcion del nombre de la funcion buscada add ebx, [Kernel32Dir] ;RVA->VA mov esi, ebx add eax, 4 ;Siguiente nombre lea edi, [FuncionBuscada] mov ecx, [FuncionBuscadaLen] repe cmpsb ;Compara esi y edi, con una longitud de ecx jnz bucle ;Se mira en la tabla de ordinales para saber en que posición esta la funcion en la tabla de funciones mov ecx, [ET] mov ecx, [ecx+24h] ;EOT add ecx, [Kernel32Dir] mov eax, [Contador] add eax, eax ;eax=eax*2 add ecx, eax mov ax, word ptr [ecx] mov [PosicionEAT], ax ;Por ultimo se accede a la posicion de la EAT para hallar la direccion de la funcion mov eax, [ET] mov eax, [eax+1Ch] add eax, [Kernel32Dir] mov ebx, [Contador] rol ebx, 2 ;Contador*4 add eax, ebx mov eax, [eax] add eax, [Kernel32Dir] ;Retornamos en eax la dirección de la función ret ObtenerGPA endpEl código está mucho mejor documentado en el capítulo de SectorVirus que he mencionado antes. Con esto ya podríamos llamar a GetProcAddress y obtener las direcciones de las funciones que nos hagan falta. Un saludo!
No hay comentarios:
Publicar un comentario