Ho trovato domande simili ma nessuna risposta a quello che sto cercando. Quindi ecco:API Win32 per enumerare le funzioni di esportazione dll?
Per una dll nativa Win32, esiste un'API Win32 per enumerarne i nomi delle funzioni di esportazione?
Ho trovato domande simili ma nessuna risposta a quello che sto cercando. Quindi ecco:API Win32 per enumerare le funzioni di esportazione dll?
Per una dll nativa Win32, esiste un'API Win32 per enumerarne i nomi delle funzioni di esportazione?
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)
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.
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)
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ò.
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.
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.
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).
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 (§ions[i].VirtualSize, 4, 1, hFile);
fread (§ions[i].VirtualAddress, 4, 1, hFile);
fread (§ions[i].SizeOfRawData, 4, 1, hFile);
fread (§ions[i].PointerToRawData, 4, 1, hFile);
fread (§ions[i].PointerToRelocations, 4, 1, hFile);
fread (§ions[i].PointerToLineNumbers, 4, 1, hFile);
fread (§ions[i].NumberOfRelocations, 2, 1, hFile);
fread (§ions[i].NumberOfLineNumbers, 2, 1, hFile);
fread (§ions[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
funzionato abbastanza bene che la mia rapida porta a Python (con ctypes) funziona bene. Grazie! –
È 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. –
Perché non solo memoria-mappare il file da solo al posto di DONT_RESOLVE_DLL_REFERENCES? Potrebbe essere anche più veloce. – masterxilo