domingo, 1 de mayo de 2011

Usando GetProcAddress y LoadLibrary para localizar APIs 1/2

En las dos entradas que escribí sobre añadir código portable a un ejecutable:
http://el-blog-de-thor.blogspot.com/2011/02/anadir-codigo-portable-un-ejecutable-12.html
http://el-blog-de-thor.blogspot.com/2011/03/anadir-codigo-portable-un-ejecutable-22.html

Hice trampas o mas bien me facilite mucho la situación. Ya que me servía de que la API que iba a usar el código ya la importaba el ejecutable (MessageBoxW). Pero no siempre podemos confiar en tener esa suerte.

Así que lo suyo es primero encontrar la dirección de la API que necesitamos y después usarla. Para tal tarea se utiliza la API GetProcAddress, que pasándole el handle de una dll (la dirección de memoria donde empieza la dll) y el nombre de la función buscada nos devuelve la dirección de la misma. Para obtener el handle de una DLL que ya tiene cargada el ejecutable se usa la funcion GetModuleHandle. Hay que tener en cuenta que el cargador de Windows cuando arranca un programa siempre carga las dlls Kernel32.dll y NtDll.dll aunque el programa no necesite ninguna API de las mismas.

Esto se puede ver compilando un simple programa en ensamblador que solo tiene una instrucción nop y abriendolo con OllyDbg:

.386
.model flat, stdcall
option casemap:none

.code
codigo:
nop
end codigo

image

Así que si la API que necesitamos está en las DLLs Kernel32.dll o NtDll.dll nos vale con usar la función GetModuleHandle y pasarle ese valor a GetProcAddress junto al nombre de la API buscada:

HMODULE h = GetModuleHandle("kernel32.dll");
GetProcAddress(h, "ExitProcess");

Si no deberemos usar la API LoadLibrary para cargar una DLL en la memoria del proceso. Por ejemplo para los anteriores entradas necesitábamos usar la API MessageBoxA. Mirando en MSDN sabemos que se encuentra en la DLL User32.dll.

HMODULE h = LoadLibrary("User32.dll");
GetProcAddress(h, "MessageBoxA");

La función LoadLibrary a su vez la podemos localizar mediante el uso de GetProcAddress:

HMODULE h = GetModuleHandle("kernel32.dll");
LoadLibraryF = (void*)GetProcAddress(h, "LoadLibrary");
h = LoadLibraryF("User32.dll");
GetProcAddress(h, "MessageBoxA");

Vemos que las 2 funciones imprescindibles para cargar el resto son GetModuleHandle y GetProcAddress.

Pero fijaos en un problema, si un programa no importa las funciones GetModuleHandle y GetProcAddress no sabemos en que dirección están y por lo tanto no podemos encontrar otras APIs. Nos encontramos en un bucle, para saber la dirección de GetProcAddress necesitamos utilizar GetProcAddress y es lo que no sabemos.

En la siguiente entrada veremos como se soluciona esto.

No hay comentarios:

Publicar un comentario