2009-07-14 129 views

回答

41

dumpbin /exports幾乎是你想要的,但這是一個開發工具,而不是Win32 API。

LoadLibraryExDONT_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的)工作正常。謝謝! – 2010-03-24 19:27:39

+10

需要注意的是,在使用'DONT_RESOLVE_DLL_REFERENCES'標誌加載**之後調用函數**可能會引起混亂**,因爲沒有爲加載的模塊調用DllMain。 – 2013-01-14 16:56:23

+0

爲什麼不自己記憶映射文件而不是DONT_RESOLVE_DLL_REFERENCES?甚至可能會更快。 – masterxilo 2016-01-19 18:34:45

5

轉到Microsoft研究部門,抓住Detours圖書館。其中一個例子就是你正在問的問題。整個庫基本上使繞過/重新路由win32函數調用非常容易。它非常酷的東西。

Detours

編輯:另外請注意,如果你只是想看看導出表,你可以(至少在視覺工作室)設置你的項目屬性,打印出的導出/導入表。我不記得確切的選項,但應該很容易谷歌。

** EDIT2:**的選擇是項目屬性 - >連接器 - > Debugging->生成映射文件 - >是(/ MAP)

0

如果你只是尋找一種方法來找出哪些功能導出在一個DLL中,你可以使用微軟的dependency walker(depends.exe)。儘管如此,如果你真的需要以編程方式發現導出,這不會對你有所幫助。

1

如果你不想去編寫你自己的代碼的麻煩,而寧願使用一個已經存在的DLL爲此目的,我推薦PE File Format DLL。附帶源代碼,以便您可以根據需要進行修改。沒有GPL擔心。

另外還有一個顯示如何使用DLL的GUI應用程序。

0

我可能錯了,而且我沒有仔細檢查過,但我相信在模塊上使用ephemient代碼可能會有一些兼容性問題,這些模塊是在與您的進程不同的體系結構下構建的。 (同樣,我現在可能完全說不出我的屁股)

在github上有一個項目,名爲dll2def,它使用相同的技術(儘管它自己將文件加載到內存中),但似乎有一些根據二進制文件的體系結構進行檢查以查找輸出。您最有可能感興趣的代碼是this file

2

雖然ephemient是正確的,LoadLibraryExDONT_RESOLVE_DLL_REFERENCES可以簡化這項任務很多,你可以使它甚至比他顯示更簡單。您可以使用SymEnumerateSymbols來爲您列出符號,而不是自己查找並枚舉DLL的導出目錄。

雖然只比他的代碼稍微簡單一些(沒有斷言,他只有六行代碼),但至少在理論上這給了一點額外的靈活性,以防微軟應該有一天決定改變可執行格式, /或者改變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