2009-07-14 9 views

Odpowiedz

41

dumpbin /exports jest praktycznie tym, czego potrzebujesz, ale to jest narzędzie programistyczne, a nie Win32 API.

LoadLibraryEx z DONT_RESOLVE_DLL_REFERENCES jest mocno wystrzegać, ale zdarza się być użyteczne dla tego konkretnego przypadku – robi podnoszenie ciężkich mapowania DLL do pamięci (ale w rzeczywistości nie potrzebują lub chcą używać niczego z biblioteki) , co sprawia, że ​​odczytanie nagłówka jest banalne: uchwyt modułu zwrócony przez punkty LoadLibraryEx tuż przy nim.

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

Całkowicie nietestowany, ale uważam, że jest mniej więcej poprawny. (Znane ostatnie słowa.)

+0

pracował na tyle dobrze, że mój szybki port Pythonie (z ctypes) działa poprawnie. Dzięki! –

+10

Należy zauważyć, że ** wywołanie funkcji ** po wczytaniu z flagą 'DONT_RESOLVE_DLL_REFERENCES' ** może wywołać gówno **, ponieważ nie ma wywołania' DllMain' dla załadowanego modułu. –

+0

Dlaczego nie po prostu pamięć-mapować samemu plik zamiast DONT_RESOLVE_DLL_REFERENCES? Może być nawet szybszy. – masterxilo

5

Przejdź do badań firmy Microsoft i pobierz bibliotekę Detours. Jeden z jego przykładów dokładnie to, o co prosisz. Cała biblioteka zasadniczo ułatwia obcinanie i przekierowywanie wywołań funkcji win32. To całkiem fajne rzeczy.

Detours

Edit: Należy również pamiętać, że jeśli po prostu zajrzeć do tabeli eksportu, można (przynajmniej w pracowniach plastycznych) ustawić właściwości projektu do wydrukowania tabel eksport/import. Nie pamiętam dokładnej opcji, ale powinno być łatwe do Google.

** Edit2: ** Opcja Projekt Ustawienia-> Linker-> Debugging-> Generowanie mapFile -> Yes (/ MAP)

0

Jeśli jesteś po prostu szukasz sposobu, aby dowiedzieć się, jakie funkcje są eksportowane do biblioteki DLL, możesz użyć Microsoft dependency walker (depends.exe). To jednak nie pomoże, jeśli rzeczywiście trzeba będzie programowo wykryć eksport.

1

Jeśli nie chcesz zadawać sobie trudu napisania własnego kodu i wolisz używać biblioteki DLL, która już istnieje w tym celu, polecam PE File Format DLL. Zawiera kod źródłowy, który możesz modyfikować, jeśli chcesz. Nie martw się GPL.

Dostępne jest również aplikacja GUI, która pokazuje, jak korzystać z biblioteki DLL.

0

Mogę się mylić i nie sprawdziłem jeszcze raz szczerze, ale sądzę, że mogą występować pewne problemy ze zgodnością przy korzystaniu z kodu ephemienta w module zbudowanym w innej architekturze niż w twoim procesie. (Ponownie, mogę teraz mówić całkowicie z mojego tyłka)

Jest projekt na github, zwany dll2def, który używa tej samej techniki (choć sam ładuje plik do pamięci), ale wydaje się, że ma trochę kontrole w celu znalezienia eksportu w zależności od architektury binarnej. Kod, który najprawdopodobniej byłby zainteresowany, to this file.

2

Podczas gdy ephemient ma rację, to LoadLibraryEx z DONT_RESOLVE_DLL_REFERENCES może znacznie uprościć to zadanie, możesz uczynić go jeszcze prostszym, niż pokazuje. Zamiast znaleźć i wyliczyć katalog eksportu DLL, możesz użyć listy SymEnumerateSymbols, aby wyświetlić listę symboli.

Chociaż tylko nieznacznie prostszy niż jego kod (bez asserts, jego jest tylko pół tuzina linii kodu) to przynajmniej teoretycznie daje trochę dodatkowej elastyczności w przypadku, gdy Microsoft powinien kiedyś zdecydować się nieco zmienić format pliku wykonywalnego, oraz/lub zmień dokładnie to, na co wskazuje HMODULE, więc jego już nie działa (ponieważ większość tych szczegółów i tak nie jest oficjalnie dokumentowana).

2

spróbuj tego:

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

przykład:

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

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

wyjściowa:

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 
Powiązane problemy