Win32 API для перечисления функций экспорта DLL? - PullRequest
36 голосов
/ 15 июля 2009

Я нашел похожие вопросы, но не нашел ответа на то, что ищу. Итак, вот так:

Для нативных Win32 dll, существует ли Win32 API для перечисления имен его функций экспорта?

Ответы [ 7 ]

45 голосов
/ 15 июля 2009

dumpbin /exports - это почти то, что вам нужно, но это инструмент разработчика, а не Win32 API.

LoadLibraryEx с DONT_RESOLVE_DLL_REFERENCES строго предупреждается, но оказывается полезным для данного конкретного случая - ndash; он выполняет тяжелую работу по отображению DLL в память (но вам на самом деле не нужно или не нужно использовать что-либо из библиотеки), что упрощает чтение заголовка: дескриптор модуля, возвращаемый LoadLibraryEx указывает вправо на это.

#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]);

Совершенно не проверено, но я думаю, что это более или менее правильно. (Известные последние слова.)

8 голосов
/ 15 июля 2009

Перейдите к исследованиям Microsoft и возьмите библиотеку Detours. Один из примеров делает именно то, что вы просите. Вся библиотека в основном делает обход функций вызова win32 чрезвычайно простым. Это довольно крутые вещи.

Detours

Редактировать: Также обратите внимание, что если вы просто хотите взглянуть на таблицу экспорта, вы можете (по крайней мере в визуальных студиях) установить свойства своего проекта для распечатки таблиц экспорта / импорта. Я не могу вспомнить точный вариант, но это должно быть легко для Google.

** Edit2: ** Опция: Свойства проекта-> Компоновщик-> Отладка-> Создать MapFile -> Да (/ MAP)

3 голосов
/ 05 февраля 2013

Хотя ephemient верен, LoadLibraryEx с DONT_RESOLVE_DLL_REFERENCES может значительно упростить эту задачу, но вы можете сделать ее еще проще, чем он показывает. Вместо того, чтобы находить и перечислять каталог экспорта DLL самостоятельно, вы можете использовать SymEnumerateSymbols, чтобы вывести список символов для вас.

Хотя только немного проще, чем его код (без утверждений, он составляет всего полдюжины строк кода), это по крайней мере теоретически дает немного дополнительной гибкости в случае, если Microsoft когда-нибудь решит немного изменить формат исполняемого файла, и или точно измените то, на что указывает HMODULE, чтобы он больше не работал (так как большинство этих деталей так или иначе официально не задокументировано).

2 голосов
/ 01 января 2016

попробуйте это:

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

пример:

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

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

Выход:

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
1 голос
/ 04 апреля 2010

Если вы не хотите писать собственный код и предпочитаете использовать уже существующую для этой цели DLL, я рекомендую PE File Format DLL . Поставляется с исходным кодом, так что вы можете изменить, если хотите. Нет необходимости беспокоиться о GPL.

Также доступно приложение с графическим интерфейсом, которое показывает, как использовать DLL.

0 голосов
/ 11 августа 2012

Я могу ошибаться, и я не проверил дважды, если честно, но я полагаю, что могут быть некоторые проблемы с совместимостью при использовании кода ephemient в модуле, который построен под архитектурой, отличной от той, которая используется в вашем процессе. (Опять же, я могу говорить прямо из своей задницы прямо сейчас)

Есть проект на github, который называется dll2def , который использует ту же технику (хотя сам загружает файл в память), но, кажется, имеет некоторые проверки для поиска экспорта в зависимости от архитектура двоичного файла. Код, который вас, скорее всего, заинтересует, находится в этом файле .

0 голосов
/ 15 июля 2009

Если вы просто ищете способ выяснить, какие функции экспортируются в DLL, вы можете использовать обходчик зависимостей от Microsoft (зависимость.exe). Это не поможет вам, если вам действительно понадобится открыть экспорт программно.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...