domingo, 29 de mayo de 2011

Obtener la dirección base de kernel32.dll consultando el PEB

En la entrada de Usando GetProcAddress y LoadLibrary para localizar APIs vimos que una de las primeras cosas que hay que hacer es localizar la dirección de memoria donde se carga la dll kernel32.dll. Para ello se utilizaba un código que suponía que en la pila se encontraba una dirección de retorno a una función de dicha dll:

;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

Esta forma no parece muy correcta, puede que en alguna versión de Windows pasada o futura no funcione bien. Además se supone que se conoce en que posición de la pila estará el valor de retorno que comentaba, esto por ejemplo puede no saberse exactamente si el código se usa para explotar una vulnerabilidad mediante una shellcode que use ese método.

Por suerte existe otra forma de obtener la dirección base de kernel32.dll.

Citando a la wikipedia:

En computación, el Win32 Thread Information Block (TIB) es una estructura de datos en los sistemas Win32 específicamente en la arquitectura x86 que almacena información a cerca del thread que se esta ejecutando.

El TIB esta indocumentado oficialmente para Windows 9x.La serie Windows NT incluye una estructura NT TIB en winnt.h que lo documenta .Wine incluye declaraciones para extender (una parte especifica del subsistema) TIB

El TIB puede ser usado para obtener buena cantidad de información en el proceso sin llamar ninguna API de Win32.Por ejemplo la emulación de GetLastError() , GetVersion(). A través del puntero en el PEB se puede obtener acceso a la tabla de importación (IAT) , los argumentos pasados al proceso etc …

La dirección de esta estructura esta apuntada por el registro FS y en la misma página de wikipedia que he comentado antes pueden verse los campos que tiene. Uno de ellos es el Process Enviroment Block, PEB. Una estructura que contiene información sobre el proceso que ejecuta el hilo:

FS:[0x30] –> Linear address of Process Environment Block (PEB)

En MSDN podemos ver de que se compone la estructura PEB:

typedef struct _PEB {
  BYTE                          Reserved1[2];
  BYTE                          BeingDebugged;
  BYTE                          Reserved2[1];
  PVOID                         Reserved3[2];
  PPEB_LDR_DATA                 Ldr;  //+0x0C
  PRTL_USER_PROCESS_PARAMETERS  ProcessParameters;
  BYTE                          Reserved4[104];
  PVOID                         Reserved5[52];
  PPS_POST_PROCESS_INIT_ROUTINE PostProcessInitRoutine;
  BYTE                          Reserved6[128];
  PVOID                         Reserved7[1];
  ULONG                         SessionId;
} PEB, *PPEB;

Mediante esta estructura podemos saber si un proceso está siendo depurado, los parámetros del proceso y lo que mas nos interesa los módulos que ha cargado el Loader de Windows. En estos módulos se encuentra el propio ejecutable y todas las DLLs que ha cargado Windows para poder ejecutarlo, entre ellas estará kernel32.dll. El campo que nos da esta información es el siguiente:

PPEB_LDR_DATA  Ldr;

Que se encuentra a un desplazamiento de 0x0C desde el principio de la estructura PEB.

La estructura PEB_LDR_DATA a su vez también está documentada en MSDN:

typedef struct _PEB_LDR_DATA {
  BYTE       Reserved1[8];
  PVOID      Reserved2[3];
  LIST_ENTRY InMemoryOrderModuleList; // +0x14
} PEB_LDR_DATA, *PPEB_LDR_DATA;

En MSDN describen esa lista cómo:

InMemoryOrderModuleList The head of a doubly-linked list that contains the loaded modules for the process. Each item in the list is a pointer to an LDR_DATA_TABLE_ENTRY structure. For more information, see Remarks.

Con la siguiente estructura:

typedef struct _LIST_ENTRY {
   struct _LIST_ENTRY *Flink;
   struct _LIST_ENTRY *Blink;
} LIST_ENTRY, *PLIST_ENTRY, *RESTRICTED_POINTER PRLIST_ENTRY;

Y por último la tabla donde apuntan Flink y Blink:

typedef struct _LDR_DATA_TABLE_ENTRY {
  PVOID Reserved1[2];
->LIST_ENTRY InMemoryOrderLinks;
  PVOID Reserved2[2];
  PVOID DllBase; //+0x10 desde –>
  PVOID EntryPoint;
  PVOID Reserved3;
  UNICODE_STRING FullDllName; //+0x1C desde –>
  BYTE Reserved4[8];
  PVOID Reserved5[3];
  union {
    ULONG CheckSum;
    PVOID Reserved6;
  };
  ULONG TimeDateStamp;
} LDR_DATA_TABLE_ENTRY, *PLDR_DATA_TABLE_ENTRY;

Hay que fijarse que los punteros Flink y Blink de la lista doblemente enlazada no apuntan al comienzo de la estructura LDR_DATA_TABLE_ENTRY sino al campo InMemoryOrderLinks, como he marcado con la flecha –>. Los desplazamientos los he puestos relativos a este punto.

De esta última estructura nos interesan los campos:

PVOID DllBase; 

Que contiene la dirección base donde se ha cargado el módulo y:

UNICODE_STRING FullDllName;

Que es la ruta y nombre del módulo. El tipo UNICODE_STRING está definido también en MSDN:

typedef struct _LSA_UNICODE_STRING {
  USHORT Length;
  USHORT MaximumLength;
  PWSTR  Buffer;
} LSA_UNICODE_STRING, *PLSA_UNICODE_STRING, UNICODE_STRING, *PUNICODE_STRING;

Perfecto! Ya tenemos todo lo necesario para lograr nuestro objetivo. La idea es primero acceder al TIB, desde este localizar la estructura PEB, después acceder al valor Ldr a la estructura PPEB_LDR_DATA, utilizar el valor InMemoryOrderModuleList para recorrer la lista mediante el puntero Flink(Follow link) y en cada tabla LDR_DATA_TABLE ver si corresponde al módulo kernel32.dll comparando con el campo FullDllName, si no es así ir a la siguiente tabla, si sí que corresponde con kernel32.dll quedarnos con la dirección base DllBase que es lo que buscamos.

A continuación dejo el código en ensamblador que realiza todas estas tareas. Para hacerlo lo mas genérico he comparado el nombre del módulo con kernel32.dll de forma que no sea sensible a minúsculas o mayúsculas lo que hace un poco mas largo el código:

.386
.model flat, stdcall
option casemap:none
assume fs:nothing

.data
 Kernel32Name db 'K',0,'E',0,'R',0,'N',0,'E',0,'L',0,'3',0,'2',0,'.',0,'D',0,'L',0,'L',0
 Kernel32NameLength dw 24
.code
codigo:
 call ObtenerKernel32PEB
 ret

;Obtiene la dirección de memoria donde se encuentra cargada kernel32.dll y la guarda en eax
ObtenerKernel32PEB proc
 mov eax, [fs:30h]    ;PEB
 mov eax, [eax+0Ch]    ;PEB.Ldr, Loader data
 add eax, 14h     ;PEB.Ldr.InMemoryOrderModuleList.Flink, Puntero al primer modulo
NextTable:
 mov eax, [eax]      ;Nos movemos a la siguiente tabla LDR_DATA_TABLE_ENTRY
 mov ecx, 0
 mov esi, offset [Kernel32Name] ;En esi guardamos la dirección del nombre kernel32.dll en unicode
 mov cx, word ptr [eax+1Ch]  ;LDR_DATA_TABLE_ENTRY.FullDllName.Length, longitud de la cadena unicode
 mov edi, [eax+20h]    ;LDR_DATA_TABLE_ENTRY.FullDllName.Buffer, puntero a la cadena unicode con el nombre del módulo
 ;No nos interesa la ruta entera solo los últimos caracteres, el nombre del fichero
 add di, cx      ;Nos situamos al final de la cadena
 sub di, Kernel32NameLength  ;Y restamos el tamaño de la cadena a comparar
 mov cx, Kernel32NameLength
ComparaCadenas:
 mov bl, byte ptr [edi]
 cmp bl, 'a'      ;Si bl >= 'a' convertir a mayusculas
 jb Mayuscula
 sub bl, 20h      ;Pasa de minusculas a mayusculas
Mayuscula:
 cmp bl, byte ptr[esi]
 jnz NextTable     ;Si no es kernel32.dll mirar en la siguiente tabla
 inc edi
 inc esi
 dec cx
 jnz ComparaCadenas
 ;Si llega aquí es que la cadena era kernel32.dll, cogemos el dato que nos interesa del modulo
 mov eax, [eax+10h]    ;eax = LDR_DATA_TABLE_ENTRY.DllBase
 ret
 
ObtenerKernel32PEB endp

end codigo

Es bastante lioso manejar tantas estructuras y entender el código en ensamblador, lo mejor para entenderlo es seguirlo poco a poco con un depurador, ver las estructuras en memoria y muuucha paciencia.

Y así obtendríamos la dirección de memoria donde está cargada la librería kernel32.dll, ahora ya podríamos seguir con el proceso que realizábamos en la otra entrada de buscar las funciones GetProcAddress y LoadLibrary.

Aquí dejo una entrada de LordRNA donde hace lo mismo de forma muy similar Gracias a @The_Swash también por su solución al mismo problema.

Un saludo!

domingo, 22 de mayo de 2011

Cargando funciones importadas manualmente

@The_Swash no para quieto. Acaba de terminar este documento donde explica como rellenar la IAT desde código ensamblador. Muy útil para hacer que un protector de ejecutables que cifre la Import Table y después en ejecución se descifre y rellene la IAT para que el programa funcione correctamente. Dejo a continuación la introducción que ha escrito @The_Swash:
Hola, aquí estoy escribiendo otro artículo que he estado preparando desde el día en el que publiqué el anterior o por lo menos la base.
En este artículo intentaré mostrarles como cargar las funciones que importamos manualmente, es decir no participará ni dependeremos del sistema operativo.
¿Con que fin cargamos las funciones manualmente?
Bueno, en realidad tengo 2 objetivos y son:
  1. Mostrar como Windows carga las direcciones de las funciones (API) que importamos.
  2. Una vez conociendo como funciona, podremos relacionarlo con Empaquetadores y
    cifradores de archivos.
Como todo necesitaremos conocer un poco de lo que trataremos claro teniendo algunas nociones sobre el formato portable executable (PE) y posteriormente dejaré un código que se
encarga de hacer esta tarea, en realidad la base de todo esto es el código porque a mano sería
muy complejo.
Muchas gracias por estos documentos!

domingo, 15 de mayo de 2011

Ejemplo de uso de TLS Callbacks Funtions

@The_Swash me ha enviado este documento que ha redactado él explicado el uso de Thread Local Storage Callbacks Functions para ejecutar código antes de la propia ejecución del programa en el Entry Point.

Con esto se puede conseguir que por ejemplo cuando se abra un exe con OllyDbg antes de que pare en el EP se ejecute código que detecte que el ejecutable esta siendo depurado y modifique parte del código del ejecutable para engañar a quien intente realizarle ingeniería inversa. Esto es usado desde hace tiempo en el malware, protectores de ejecutables, packers, etc…

Es posible configurar OllyDbg para que se detenga antes del EntryPoint y evitar que se ejecute este código. Para ello hay que ir a Options>Debugging Options>Make first pause at y seleccionar System breakPoint.

Gracias por el documento @The_Swash!

sábado, 7 de mayo de 2011

Usando GetProcAddress y LoadLibrary para localizar APIs 2/2

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 endp
El 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!

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.