jueves, 20 de septiembre de 2012

Dumpear un módulo en memoria a disco[Parte 1]

Había estado buscando esta información hace mucho tiempo, pero por desgracia no la encontré o no supe como buscarla. A continuación hablaremos de como obtener un volcado (dump) de un módulo en memoria a un archivo en disco.

[+]Volcado de módulo.
[-]Conocimiento Previo.
[-]Conversión disco-memoria.
[-]Estructura de proceso y los módulos.
[-]Comenzando con el volcado.
[-]Archivo en disco.
[-]Referencias y agradecimientos.

[+]Volcado de módulo.
[-]Conocimiento previo.

Para el entendimiento de este documento se necesita estudiar la cabecera PE, para ello les recomiendo el texto de The Swash "Formato de ficheros ejecutables", existen mas requerimientos pero tratare de ser explicativo en ese ámbito, les recuerdo que no soy un experto en este campo y lo que escribo son investigaciones que he hecho.

[-]Conversión disco-memoria.

Como el título lo dice para entender el volcado de un módulo, cualquier archivo que contenga una cabecera PE como es el caso de un Ejecutable o una DLL (Dynamic Link Library) con la única diferencia de que la DLL contiene una tabla de exportaciones válida y ciertas flags activadas en la cabecera PE, primero es necesario entender como un archivo en disco es cargado por el Loader de Windows en memoria ya sea en un proceso nuevo o dentro de un proceso.
Dentro de IMAGE_OPTIONAL_HEADER se encuentran muchos de los datos que nos interesan como es el caso de ImageAddress, SizeOfImage, SectionAlignment, FileAlignment y los DataDirectory's; como es sabido la cabecera y las secciones están alineadas siempre en múltiplos de FileAlignment y esto se repite en memoria pero tomando como unidad SectionAlignment que normalmente tiene el valor de 0x1000, el tamaño de una página de la memoria RAM.
Dentro del proceso de conversión lo que a nosotros nos importa es cuando se copian las secciones del disco a la memoria, ese proceso comienza tomando el valor de ImageBase (normalmente 0x400000) y a partir de ese valor se comienza a copiar la cabecera PE posterior a eso se copian las secciones; antes de que el proceso comience a correr el Loader carga los módulos o librerías que se necesitan leyendo la tabla de importaciones (IT) y llenando la tabla de direcciones de importaciones (IAT) para que el proceso completo pueda hacer uso de APIs.
¿Donde podemos encontrar la IAT?
Bueno la Import Table (IT) es un array de IMAGE_IMPORT_DESCRIPTOR, el cual contiene el nombre de la DLL, existe un elemento del array por DLL. El array tiene su fin en un espacio vacío, les dejo su estructura en C.
typedef struct _IMAGE_IMPORT_DESCRIPTOR {
union {
ULONG Characteristics; //Valor en 0 para terminar el array
ULONG OriginalFirstThunk; // Un RVA a el primer IMAGE_THUNK_DATA de la DLL
} DUMMYUNIONNAME;

ULONG TimeDateStamp; //No sirve de mucho, muestra la fecha de la DLL
ULONG ForwarderChain; // -1 if no forwarders
ULONG Name; //Un RVA a el nombre de la DLL
ULONG FirstThunk; //Este valor en memoria contiene un puntero a la IAT de la DLL
} IMAGE_IMPORT_DESCRIPTOR;
Como ven FirstThunk contiene un puntero a el primer IMAGE_THUNK_DATA, ¿cuál es la diferencia entre FirstThunk y OriginalFirstThunk?, la diferencia es que FirstThunk es actualizado por el Loader de Windows por las direcciones a lasAPIs actuales y OriginalFisrtThunk contiene la lista virgen.
Les dejo la estructura en C de IMAGE_THUNK_DATA :
typedef struct IMAGE_THUNK_DATA {
union {
LPBYTE    ForwarderString;
FARPROC Function;
DWORD     Ordinal;
PIMAGE_IMPORT_BY_NAME   AddressOfData;
} u1;
} IMAGE_THUNK_DATA,*PIMAGE_THUNK_DATA;
Esta estructura solo tiene un valor... Pero podemos utilizarla a gusto en la IAT se usa el valor Function el cual contiene un puntero a un procedimiento, en otras palabras a una API.
El caso de AddressOfData tiene un RVA a una estructura tipo IMAGE_IMPORT_BY_NAME. Su estructura es la siguiente:
typedef struct IMAGE_IMPORT_BY_NAME {
WORD    Hint;
BYTE    Name[1];
} IMAGE_IMPORT_BY_NAME,*PIMAGE_IMPORT_BY_NAME;
La variable Hint contiene el index de la función en la DLL (Si también se pueden cargar APIs por index)
La variable Name es el comienzo del nombre de la DLL.

En otra entrega continuare con el tema.
Saludos!

No hay comentarios:

Publicar un comentario