Win32 API para enumerar funciones de exportación dll?

Encontré preguntas similares pero ninguna respuesta a lo que estoy buscando. Así que aquí va:

Para un DLL nativo Win32, ¿hay una API de Win32 para enumerar sus nombres de funciones de exportación?

dumpbin /exports es prácticamente lo que quieres, pero es una herramienta de desarrollador, no una API de Win32.

LoadLibraryEx con DONT_RESOLVE_DLL_REFERENCES está muy DONT_RESOLVE_DLL_REFERENCES , pero resulta útil para este caso en particular: hace el trabajo pesado de mapear el archivo DLL en la memoria (pero en realidad no necesita ni quiere usar nada de la biblioteca), lo que lo hace trivial para que usted lea el encabezado: el identificador del módulo devuelto por LoadLibraryEx apunta justo a él.

 #include  HMODULE lib = LoadLibraryEx("library.dll", NULL, DONT_RESOLVE_DLL_REFERENCES); assert(((PIMAGE_DOS_HEADER)lib)->e_magic == IMAGE_DOS_SIGNATURE); PIMAGE_NT_HEADERS header = (PIMAGE_NT_HEADERS)((BYTE *)lib + ((PIMAGE_DOS_HEADER)lib)->e_lfanew); assert(header->Signature == IMAGE_NT_SIGNATURE); assert(header->OptionalHeader.NumberOfRvaAndSizes > 0); PIMAGE_EXPORT_DIRECTORY exports = (PIMAGE_EXPORT_DIRECTORY)((BYTE *)lib + header-> OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress); assert(exports->AddressOfNames != 0); BYTE** names = (BYTE**)((int)lib + exports->AddressOfNames); for (int i = 0; i < exports->NumberOfNames; i++) printf("Export: %s\n", (BYTE *)lib + (int)names[i]); 

Totalmente no probado, pero creo que es más o menos correcto. (Últimas palabras famosas.)

Vaya a la investigación de Microsoft y tome la Biblioteca Detours. Uno de sus ejemplos hace exactamente lo que estás preguntando. La biblioteca completa básicamente hace que las llamadas a funciones de desvío / reencaminamiento sean extremadamente sencillas. Es muy bueno.

Desvíos

Editar: También tenga en cuenta que si solo quiere mirar la tabla de exportación, puede (al menos en los estudios visuales) establecer las propiedades de su proyecto para imprimir las tablas de exportación / importación. No recuerdo la opción exacta, pero debería ser fácil de googlear.

** Edit2: ** La opción es Project Properties-> Linker-> Debugging-> Generate MapFile -> Yes (/ MAP)

Aunque ephemient es correcto, LoadLibraryEx with DONT_RESOLVE_DLL_REFERENCES puede simplificar mucho esta tarea, puede hacerlo aún más simple de lo que muestra. En lugar de buscar y enumerar el directorio de exportación de la DLL usted mismo, puede usar SymEnumerateSymbols para listar los símbolos por usted.

Aunque solo marginalmente más simple que su código (sin las afirmaciones, su es solo media docena de líneas de código) al menos teóricamente da un poco de flexibilidad extra en caso de que Microsoft algún día decida cambiar un poco el formato ejecutable, y / o cambiar exactamente lo que señala el HMODULE, por lo que ya no funciona (ya que la mayoría de estos detalles no están oficialmente documentados de todos modos).

prueba esto:

 #include  #include  #include  void EnumExportedFunctions (char *, void (*callback)(char*)); int Rva2Offset (unsigned int); typedef struct { unsigned char Name[8]; unsigned int VirtualSize; unsigned int VirtualAddress; unsigned int SizeOfRawData; unsigned int PointerToRawData; unsigned int PointerToRelocations; unsigned int PointerToLineNumbers; unsigned short NumberOfRelocations; unsigned short NumberOfLineNumbers; unsigned int Characteristics; } sectionHeader; sectionHeader *sections; unsigned int NumberOfSections = 0; int Rva2Offset (unsigned int rva) { int i = 0; for (i = 0; i < NumberOfSections; i++) { unsigned int x = sections[i].VirtualAddress + sections[i].SizeOfRawData; if (x >= rva) { return sections[i].PointerToRawData + (rva + sections[i].SizeOfRawData) - x; } } return -1; } void EnumExportedFunctions (char *szFilename, void (*callback)(char*)) { FILE *hFile = fopen (szFilename, "rb"); if (hFile != NULL) { if (fgetc (hFile) == 'M' && fgetc (hFile) == 'Z') { unsigned int e_lfanew = 0; unsigned int NumberOfRvaAndSizes = 0; unsigned int ExportVirtualAddress = 0; unsigned int ExportSize = 0; int i = 0; fseek (hFile, 0x3C, SEEK_SET); fread (&e_lfanew, 4, 1, hFile); fseek (hFile, e_lfanew + 6, SEEK_SET); fread (&NumberOfSections, 2, 1, hFile); fseek (hFile, 108, SEEK_CUR); fread (&NumberOfRvaAndSizes, 4, 1, hFile); if (NumberOfRvaAndSizes == 16) { fread (&ExportVirtualAddress, 4, 1, hFile); fread (&ExportSize, 4, 1, hFile); if (ExportVirtualAddress > 0 && ExportSize > 0) { fseek (hFile, 120, SEEK_CUR); if (NumberOfSections > 0) { sections = (sectionHeader *) malloc (NumberOfSections * sizeof (sectionHeader)); for (i = 0; i < NumberOfSections; i++) { fread (sections[i].Name, 8, 1, hFile); fread (&sections[i].VirtualSize, 4, 1, hFile); fread (&sections[i].VirtualAddress, 4, 1, hFile); fread (&sections[i].SizeOfRawData, 4, 1, hFile); fread (&sections[i].PointerToRawData, 4, 1, hFile); fread (&sections[i].PointerToRelocations, 4, 1, hFile); fread (&sections[i].PointerToLineNumbers, 4, 1, hFile); fread (&sections[i].NumberOfRelocations, 2, 1, hFile); fread (&sections[i].NumberOfLineNumbers, 2, 1, hFile); fread (&sections[i].Characteristics, 4, 1, hFile); } unsigned int NumberOfNames = 0; unsigned int AddressOfNames = 0; int offset = Rva2Offset (ExportVirtualAddress); fseek (hFile, offset + 24, SEEK_SET); fread (&NumberOfNames, 4, 1, hFile); fseek (hFile, 4, SEEK_CUR); fread (&AddressOfNames, 4, 1, hFile); unsigned int namesOffset = Rva2Offset (AddressOfNames), pos = 0; fseek (hFile, namesOffset, SEEK_SET); for (i = 0; i < NumberOfNames; i++) { unsigned int y = 0; fread (&y, 4, 1, hFile); pos = ftell (hFile); fseek (hFile, Rva2Offset (y), SEEK_SET); char c = fgetc (hFile); int szNameLen = 0; while (c != '\0') { c = fgetc (hFile); szNameLen++; } fseek (hFile, (-szNameLen)-1, SEEK_CUR); char* szName = calloc (szNameLen + 1, 1); fread (szName, szNameLen, 1, hFile); callback (szName); fseek (hFile, pos, SEEK_SET); } } } } } fclose (hFile); } } 

ejemplo:

 void mycallback (char* szName) { printf ("%s\n", szName); } int main () { EnumExportedFunctions ("C:\\Windows\\System32\\user32.dll", mycallback); return 0; } 

salida:

 ActivateKeyboardLayout AddClipboardFormatListener AdjustWindowRect AdjustWindowRectEx AlignRects AllowForegroundActivation AllowSetForegroundWindow AnimateWindow AnyPopup AppendMenuA AppendMenuW ArrangeIconicWindows AttachThreadInput BeginDeferWindowPos BeginPaint BlockInput BringWindowToTop BroadcastSystemMessage BroadcastSystemMessageA BroadcastSystemMessageExA BroadcastSystemMessageExW BroadcastSystemMessageW BuildReasonArray CalcMenuBar .....etc 

Si no quiere tomarse la molestia de escribir su propio código y prefiere usar una DLL que ya existe para este fin, recomiendo PE File Format DLL . Viene con el código fuente para que pueda modificarlo si lo desea. Sin GPL de qué preocuparse.

También está disponible una aplicación GUI que muestra cómo usar el DLL.

Si solo está buscando una forma de averiguar qué funciones se exportan en una DLL, puede usar la herramienta de dependencia de dependencias de Microsoft (depends.exe). Sin embargo, esto no te ayudará si realmente necesitas descubrir las exportaciones programáticamente.

Puedo estar equivocado, y no lo he comprobado dos veces para ser sincero, pero creo que puede haber algunos problemas de compatibilidad con el uso del código de ephemient en un módulo que está construido bajo una architecture diferente a la de su proceso. (De nuevo, puedo estar hablando completamente fuera de mi culo en este momento)

Hay un proyecto en github, llamado dll2def que usa la misma técnica (aunque carga el archivo en la memoria por sí mismo), pero parece tener algunas verificaciones para encontrar las exportaciones según la architecture del binario. El código que probablemente le interese está en este archivo .