我发现类似的问题,但没有答案,我在找什么。 所以在这里:
对于本机Win32 DLL,是否有Win32 API来枚举其导出函数名称?
dumpbin /exports
几乎是你想要的,但是这是一个开发工具,而不是Win32 API。
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]);
完全没有经过testing,但我认为这或多或less是正确的。 (著名遗言。)
去微软的研究,抓住Detours图书馆。 其中一个例子就是你所要求的。 整个库基本上使绕过/重新路由win32函数调用非常容易。 它非常酷的东西。
less走弯路
编辑:另外请注意,如果你只是想看看导出表,你可以(至less在视觉工作室)设置你的项目属性打印输出/导入表。 我不记得确切的选项,但应该很容易谷歌。
**编辑2:**选项是项目属性 – >连接器 – >debugging – >生成MapFile – >是(/ MAP)
虽然ephemient是正确的, LoadLibraryEx
与DONT_RESOLVE_DLL_REFERENCES
可以简化这个任务很多,你可以使它甚至比他显示更简单。 您不必自己查找并枚举DLL的导出目录,而是使用SymEnumerateSymbols
为您列出符号。
虽然只比他的代码稍微简单一些(没有断言,他只有六行代码),但至less在理论上这给了一点额外的灵活性,以便微软有一天应该决定改变可执行格式和/或改变HMODULE指出什么,所以他不再工作(因为大多数这些细节没有正式logging)。
尝试这个:
#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); } }
例:
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
如果你不想去编写自己的代码,而宁愿使用一个已经存在的DLL来实现这个目的,我推荐PE文件格式DLL 。 附带源代码,以便您可以随意修改。 没有GPL担心。
另外还有一个显示如何使用DLL的GUI应用程序。
如果您只是在寻找一种方法来找出在DLL中导出的函数,则可以使用Microsoft的依赖关系walker (depend.exe)。 但是,如果你实际上需要以编程方式发现导出,这不会帮助你。
我可能是错的,而且我还没有仔细检查是否诚实,但是我相信在模块上使用ephemient代码可能会有一些兼容性问题,这些模块是在与您的进程不同的体系结构下构build的。 (再说一遍,我现在可能已经完全脱离了我的屁股)
在github上有一个项目叫做dll2def ,它使用了相同的技术(尽pipe它自己把文件加载到内存中),但是根据二进制的体系结构,似乎有一些检查来find导出。 你最有可能感兴趣的代码是在这个文件中 。