2009-07-14 3 views

ответ

41

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

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

+0

работал достаточно хорошо, что мой быстрый порт Python (с ctypes) работает отлично. Благодаря! –

+10

Важно отметить, что ** вызов функций ** после загрузки флагом 'DONT_RESOLVE_DLL_REFERENCES' может привести к удару **, потому что для загруженного модуля вызывается' DllMain'. –

+0

Почему бы просто не сохранить карту памяти самим файлом, а не DONT_RESOLVE_DLL_REFERENCES? Возможно, даже быстрее. – masterxilo

5

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

Detours

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

** Edit2: ** Опция Project Properties-> Linker-> Debugging-> Создать файл проект -> Да (/ MAP)

0

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

1

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

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

0

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

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

2

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

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

2

попробовать это:

#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 
Смежные вопросы