API Win32 для перечисления функций экспорта dll?

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

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

Ответ 1

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

LoadLibraryEx с DONT_RESOLVE_DLL_REFERENCES с большой осторожностью против, но, оказывается, полезно для этого конкретного случая – он тяжело поднимает отображение 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]);

Полностью непроверенный, но я считаю его более-менее правильным. (Знаменитые последние слова.)

Ответ 2

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

Detours

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

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

Ответ 3

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

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

Ответ 4

попробуйте следующее:

#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

Ответ 5

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

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

Ответ 6

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

Ответ 7

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

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