Jump to content


Photo

Encontrar los datos exportados por un módulo


  • Please log in to reply
6 replies to this topic

#1 escafandra

escafandra

    Advanced Member

  • Administrador
  • 4111 posts
  • LocationMadrid - España

Posted 20 November 2009 - 06:28 PM

Me vi en la necesidad de tener que localizar los datos que exporta un archivo ejecutable en tiempo de ejecución, así que el mejor método es caminar por el formato PE y este es un ejemplo válido para todos los Windows NT:


cpp
  1. //---------------------------------------------------------------------------
  2. PIMAGE_EXPORT_DIRECTORY ImageExportDirectory(HMODULE hModule)
  3. {
  4.   DWORD VirtualAddress_idata = ((DWORD)hModule + *(DWORD*)((DWORD)hModule + 0x3C) + 0x78);
  5.   return PIMAGE_EXPORT_DIRECTORY((DWORD)hModule + *(DWORD*)VirtualAddress_idata);
  6. }
  7.  
  8. //-----------------------------------------------------------------------------
  9. void __fastcall GetExportData(char* ModuleName, TMemo* Memo1)
  10. {
  11.   Memo1->Clear();
  12.   HMODULE hModule = LoadLibrary(ModuleName);
  13.   if(!hModule)
  14.     hModule = GetModuleHandle(ModuleName);
  15.   if(!hModule){
  16.     Memo1->Text = "Can't open module";
  17.     return;
  18.   }
  19.  
  20.   PIMAGE_EXPORT_DIRECTORY IED = ImageExportDirectory(hModule);
  21.   char* ModuleName = (char*)(IED->Name + (DWORD)hModule);
  22.   char** Names = (char**)(IED->AddressOfNames + (DWORD)hModule);
  23.   DWORD* EntryPoints = (DWORD*)(IED->AddressOfFunctions + (DWORD)hModule);
  24.   WORD*  Index = (WORD*)(IED->AddressOfNameOrdinals + (DWORD)hModule);
  25.  
  26.   // Listar las funciones exportadas:
  27.   for(int n=0; n<IED->NumberOfNames; n++){
  28.       if(Index[n]>=IED->NumberOfFunctions) continue;
  29.       char* Name = Names[n] + (DWORD)hModule;
  30.       Memo1->Lines->Add("0x" + IntToHex((int)(EntryPoints[Index[n]] + (DWORD)hModule), 8) + ": " + String(Name));
  31.       Application->ProcessMessages();
  32.   }
  33.  
  34.   FreeLibrary(hModule);
  35. }


Saludos.
  • 0

#2 egostar

egostar

    missing my father, I love my mother.

  • Administrador
  • 14460 posts
  • LocationMéxico

Posted 20 November 2009 - 07:21 PM

Hola amigo

Dejame entender la situación, quieres decir que este proceso es algo como un sniffer ?

Salud OS
  • 0

#3 escafandra

escafandra

    Advanced Member

  • Administrador
  • 4111 posts
  • LocationMadrid - España

Posted 20 November 2009 - 07:37 PM

Dejame entender la situación, quieres decir que este proceso es algo como un sniffer ?


Bueno, olfatear, olfatea pero se trata de averiguar los datos que exporta un archivo ejecutable. Tanto una dll como un archivo.exe tienen una cabecera con un formato perfectamente definido y estandarizado para varios S.O. Es el formato PE. En él, los programas pueden exponer a otros, las funciones y datos que exportan, el caso de las librerías dll es el ejemplo mas claro. También tiene la información de lo que se importa, de la sección de recursos, el punto de entrada del ejecutable y un montón de cosas que pueden resultar muy útiles y que generalmente nos son transparentes.

Es el S.O. el que interpreta el PE y es absolutamente necesario para la carga y ejecución del ejecutable y lo hace compatible para las diferentes versiones del S.O.

El ejemplo muestra una pequeña parte de lo que se puede extraer del análisis del PE de un ejecutable. Distintas herramientas pueden dar esa información. El ejemplo trata de conseguirlo en tiempo de ejecución.

Saludos.
  • 0

#4 egostar

egostar

    missing my father, I love my mother.

  • Administrador
  • 14460 posts
  • LocationMéxico

Posted 20 November 2009 - 07:59 PM

Ah vaya, pues si que es muy interesante el asunto, siempre me agrada ver tu code aunque no comprenda de inicio todo lo que haces. Algún día lo entenderé, lo prometo :D

Salud OS
  • 0

#5 seoane

seoane

    Advanced Member

  • Administrador
  • 1259 posts
  • LocationEspaña

Posted 21 November 2009 - 04:25 AM

Lo que es mas difícil de averiguar es que librerias importa el programa forma dinámica (usando las funciones LoadLibrary y GetModuleHandle).

Por ejemplo, cuando aquí intento interceptar las comunicaciones de un proceso, busco en la misma tabla que tu (o eso creo  :p ) las funciones para enviar y recibir. Sin embargo me funciona en programas como firefox, pero en el opera no, y me temo que es porque este carga las funciones de forma dinámica.
  • 0

#6 Wilson

Wilson

    Advanced Member

  • Moderadores
  • PipPipPip
  • 2137 posts

Posted 21 November 2009 - 05:49 AM

Ah vaya, pues si que es muy interesante el asunto, siempre me agrada ver tu code aunque no comprenda de inicio todo lo que haces. Algún día lo entenderé, lo prometo :D

Salud OS


Gracias a los maestros por sus valiosos aportes, Egostar me uno a tu promesa...

saludos
  • 0

#7 escafandra

escafandra

    Advanced Member

  • Administrador
  • 4111 posts
  • LocationMadrid - España

Posted 22 November 2009 - 02:00 PM

Lo que es mas difícil de averiguar es que librerias importa el programa forma dinámica (usando las funciones LoadLibrary y GetModuleHandle).

Por ejemplo, cuando aquí intento interceptar las comunicaciones de un proceso, busco en la misma tabla que tu (o eso creo  :p ) las funciones para enviar y recibir. Sin embargo me funciona en programas como firefox, pero en el opera no, y me temo que es porque este carga las funciones de forma dinámica.


Ciertamente del PE se pueden extraer los datos importados, pero esta vez es de la sección .idata del PE. En mi ejemplo se investigan los datos exportados (sección .edata del PE).

Tu ejemplo, seoane es una magnífica forma de realizar un Hook a una API en la IAT (tabla de importación de direcciones) donde se encuentran los punteros de las APIs importadas por el ejecutable. Con la API ImageDirectoryEntryToData alcanzamos el directorio de datos importados, uno por cada módulo importado. Esa API, en caso de necesitar un nivel mas bajo en la implementación, puede ser sustituida por:


cpp
  1. PIMAGE_IMPORT_DESCRIPTOR GetImageImportDescriptor(HMODULE hModule)
  2. {
  3.   // Encuentra y devuelve el directorio de sección .idata para un modulo dado.
  4.  
  5.   DWORD VirtualAddress_idata = ((DWORD)hModule + *(DWORD*)((DWORD)hModule + 0x3C) + 0x80);
  6.   return PIMAGE_IMPORT_DESCRIPTOR((DWORD)hModule + *(DWORD*)VirtualAddress_idata);
  7. }



Efectivamente, si un proceso importa una API en tiempo de ejecución, no puede ser hookeada con esta técnica. Ese es el efecto buscado en esta solución en modo kernel. Para poder hookear esas APIs importadas en tiempo de ejecución, se debe usar la técnica de sobreescribir sus primeros bytes para provocar un salto a nuestro código. Ese salto se podría también sobreescribir en un salto de la misma API. Esta segunda técnica es válida para cualquier API, importada en tiempo de compilación o se ejecución, así, no hace falta averiguar que librerías importa el programa forma dinámica, no nos importa :).

De cualquier forma, el PE esconde secretos muy valiosos para los curiosos.  ;)

Saludos.
  • 0




IP.Board spam blocked by CleanTalk.