web-dev-qa-db-fra.com

Win32 API pour énumérer les fonctions d'exportation DLL?

J'ai trouvé des questions similaires mais pas de réponse à ce que je cherche. Alors, voici:

Pour une DLL Win32 native, existe-t-il une API Win32 pour énumérer ses noms de fonctions d'exportation?

36
user15071

dumpbin /exports est à peu près ce que vous voulez, mais c'est un outil de développement, pas une API Win32.

LoadLibraryEx with DONT_RESOLVE_DLL_REFERENCES est fortement recommandé, mais se révèle utile dans ce cas particulier - il est très difficile de mapper le DLL dans la mémoire (mais vous n'avez ni besoin ni voulu de utilisez quelque chose dans la bibliothèque), ce qui rend la lecture de l’en-tête plus simple: le descripteur de module renvoyé par LoadLibraryEx pointe sur lui.

#include <winnt.h>
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]);

Totalement non testé, mais je pense que c'est plus ou moins correct. (Derniers mots célèbres.)

45
ephemient

Passez à la recherche Microsoft et récupérez la bibliothèque Detours. Un de ses exemples fait exactement ce que vous demandez. La bibliothèque entière facilite le détournement/réacheminement des appels de fonctions win32. C'est assez cool. 

Détours

Edit: Notez également que si vous souhaitez uniquement consulter le tableau d'exportation, vous pouvez (au moins dans Visual Studios) définir les propriétés de votre projet pour imprimer les tableaux d'exportation/importation. Je ne me souviens pas de l'option exacte, mais il devrait être facile de google.

** Edit2: ** L'option est Propriétés du projet-> Éditeur de liens-> Débogage-> Générer un fichier MapFile -> Oui (/ MAP)

8
DeusAduro

Bien qu'éphemient ait raison, LoadLibraryEx avec DONT_RESOLVE_DLL_REFERENCES peut grandement simplifier cette tâche, mais vous pouvez le rendre encore plus simple qu'il ne le montre. Au lieu de rechercher et d’énumérer vous-même le répertoire d’exportation de la DLL, vous pouvez utiliser SymEnumerateSymbols pour répertorier les symboles à votre place.

Bien que légèrement plus simple que son code (sans les assertions, il ne représente qu'une demi-douzaine de lignes de code), cela donne au moins théoriquement un peu plus de flexibilité au cas où Microsoft déciderait un jour de modifier légèrement le format de l'exécutable et/ou de le modifier exactement ce que le HMODULE pointe vers, donc son ne fonctionne plus (puisque la plupart de ces détails ne sont de toute façon pas officiellement documentés).

3
Jerry Coffin

essaye ça:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

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);
    }
}

exemple:

void mycallback (char* szName) {
    printf ("%s\n", szName);
}

int main () {
    EnumExportedFunctions ("C:\\Windows\\System32\\user32.dll", mycallback);
    return 0;
}

sortie:

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
2
user5588894

Si vous ne souhaitez pas écrire votre propre code et que vous préférez utiliser un DLL qui existe déjà à cet effet, je vous recommande Format de fichier PE DLL . Livré avec le code source afin que vous puissiez modifier si vous le souhaitez. Pas de GPL à craindre.

Est également disponible une application graphique qui montre comment utiliser la DLL.

1
Stephen Kellett

Si vous cherchez simplement un moyen de savoir quelles fonctions sont exportées dans une DLL, vous pouvez utiliser le dependency walker de Microsoft (depend.exe). Cela ne vous aidera pas si vous avez réellement besoin de découvrir les exportations par programmation, cependant.

0
Ferruccio

Je me trompe peut-être et je n’ai pas vérifié deux fois pour être honnête, mais j’estime que l’utilisation du code de l’éphémient sur un module construit sous une architecture différente de celle de votre processus peut poser des problèmes de compatibilité. (Encore une fois, je parle peut-être complètement hors de mon cul en ce moment)

Il y a un projet sur github, appelé dll2def qui utilise la même technique (même s'il charge le fichier en mémoire), mais semble avoir quelques vérifications en place pour trouver les exportations en fonction de l'architecture du binaire. Le code qui vous intéresserait le plus probablement est dans ce fichier .

0
Charles Grunwald