2009-07-14 15 views

risposta

41

dumpbin /exports è praticamente quello che vuoi, ma quello è uno strumento di sviluppo, non un'API Win32.

LoadLibraryEx con DONT_RESOLVE_DLL_REFERENCES è fortemente in guardia contro, ma sembra essere utile per questo caso particolare – lo fa il sollevamento di carichi pesanti di mappare la DLL in memoria (ma in realtà non c'è bisogno o si desidera utilizzare qualsiasi cosa dalla libreria) , che rende banale la lettura dell'intestazione: l'handle del modulo restituito da punti 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]); 

Totalmente non testato, ma penso che sia più o meno corretto. (Ultime parole famose)

+0

funzionato abbastanza bene che la mia rapida porta a Python (con ctypes) funziona bene. Grazie! –

+10

È essenziale notare che ** chiamare le funzioni ** dopo aver caricato con il flag 'DONT_RESOLVE_DLL_REFERENCES' ** potrebbe far saltare in aria **, perché non viene chiamato' DllMain' per il modulo caricato. –

+0

Perché non solo memoria-mappare il file da solo al posto di DONT_RESOLVE_DLL_REFERENCES? Potrebbe essere anche più veloce. – masterxilo

5

Passa alla ricerca Microsoft e recupera la libreria Deviazioni. Uno dei suoi esempi fa esattamente quello che stai chiedendo. In pratica, l'intera libreria rende estremamente semplice la deviazione/reindirizzamento delle chiamate alla funzione win32. È roba piuttosto interessante.

Detours

Edit: noti inoltre che se si desidera solo guardare la tabella di esportazione, è possibile (almeno negli studi visivi) impostare le proprietà del progetto per stampare le tabelle di esportazione/importazione. Non riesco a ricordare l'opzione esatta, ma dovrebbe essere facile da google.

** Edit2: ** L'opzione è Progetto Proprietà-> Linker-> Debugging-> Genera mapfile -> Sì (/ MAP)

0

Se siete solo in cerca di un modo per scoprire quali funzioni vengono esportati in una DLL, è possibile utilizzare Microsoft dependency walker (depends.exe). Questo non ti aiuterà se hai effettivamente bisogno di scoprire le esportazioni a livello di programmazione, però.

1

Se non si vuole risolvere il problema della scrittura del proprio codice e si preferisce utilizzare una DLL già esistente per questo scopo, è consigliabile PE File Format DLL. Viene fornito con il codice sorgente in modo che è possibile modificare se lo si desidera. Nessuna GPL di cui preoccuparsi.

Anche disponibile è un'applicazione GUI che mostra come utilizzare la DLL.

0

Potrei sbagliarmi, e non ho ricontrollato per essere onesto, ma credo che ci possano essere alcuni problemi di compatibilità con l'uso del codice di efemio su un modulo che è stato costruito con un'architettura diversa da quella del vostro processo. (Di nuovo, posso parlare completamente fuori dal mio culo adesso)

C'è un progetto su github, chiamato dll2def che utilizza la stessa tecnica (sebbene carichi il file in memoria da solo), ma sembra avere qualche controlla in atto per trovare le esportazioni a seconda dell'architettura del binario. Il codice a cui probabilmente ti interesserebbe è this file.

2

Mentre l'efetto è corretto che LoadLibraryEx con DONT_RESOLVE_DLL_REFERENCES può semplificare molto questa operazione, è possibile renderlo ancora più semplice di quello che mostra. Invece di trovare ed enumerare la directory di esportazione della DLL da soli, è possibile utilizzare SymEnumerateSymbols per elencare i simboli.

Anche se solo marginalmente più semplice del suo codice (senza le asserzioni, la sua è solo una mezza dozzina di righe di codice) questo almeno offre un po 'di flessibilità in più nel caso in cui un giorno Microsoft decida di cambiare un po' il formato dell'eseguibile, e/o cambia esattamente ciò a cui punta HMODULE, quindi non funziona più (poiché la maggior parte di questi dettagli non sono comunque documentati ufficialmente).

2

provare questo:

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

esempio:

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

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

uscita:

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 
Problemi correlati