导出的DLL函数不是按字面顺序排列的?

那么今天我遇到了一个怪事 前一段时间,我写了自己的GetProcAddress版本来获取远程进程的函数地址。 我显然花了很多时间阅读PE体系结构来找出解决这个问题的最好方法。

从PECOFF v8规范(我认为它是最新的官方规范)中,有关于Export Name Pointer Table的以下符号:

导出名称指针表是到导出名称表中的地址数组(RVA)。 指针每个都是32位,并且与图像库相关。 这些指针在词汇上sorting以允许二进制search。

所以在编写我的GetProcAddress版本的时候就考虑了这个问题。 很显然,在使用线性search的二进制search的情况下,在导出表中引用KERNEL32.dll(1300+个导出的函数)会有很好的效率提升。

这工作了一段时间,直到今天,当我遇到一个奇怪的问题。 看起来,Kernel32中的一些导出函数实际上并不是按照词汇顺序排列的,而这是抛弃了我的二分查找。 以下是使用我将在下面发布的函数导出的Dll转储的摘录:

 Ordinal: 810 Name: K32QueryWorkingSetEx Ordinal: 811 Name: LCIDToLocaleName Ordinal: 812 Name: LCMapStringA Ordinal: 813 Name: LCMapStringEx Ordinal: 814 Name: LCMapStringW Ordinal: 815 Name: LZClose Ordinal: 816 Name: LZCloseFile Ordinal: 817 Name: LZCopy Ordinal: 818 Name: LZCreateFileW Ordinal: 819 Name: LZDone Ordinal: 820 Name: LZInit Ordinal: 821 Name: LZOpenFileA Ordinal: 822 Name: LZOpenFileW Ordinal: 823 Name: LZRead Ordinal: 824 Name: LZSeek Ordinal: 825 Name: LZStart Ordinal: 826 Name: LeaveCriticalSection Ordinal: 827 Name: LeaveCriticalSectionWhenCallbackReturns Ordinal: 828 Name: LoadAppInitDlls Ordinal: 829 Name: LoadLibraryA Ordinal: 830 Name: LoadLibraryExA 

任何人在这里发现问题? 尽pipe文档声明导出表是按字面顺序排列的,但LZRead在LeaveCriticalSection之前列出。

在处理string时,我总是把词汇顺序作为字母顺序的同义词,在这里我错了,还是在Kernel32的导出表中存在一些奇怪的问题?

用于转储输出的函数:

 void DumpExports(PBYTE pBase) { freopen("B:\\PeDump.txt", "wb", stdout); IMAGE_DOS_HEADER *pDosHd = (IMAGE_DOS_HEADER*)pBase; IMAGE_NT_HEADERS *pNtHd = (IMAGE_NT_HEADERS*)(pBase + pDosHd->e_lfanew); IMAGE_DATA_DIRECTORY expDir = pNtHd->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT]; if (expDir.Size) { IMAGE_EXPORT_DIRECTORY *pExpDir = (IMAGE_EXPORT_DIRECTORY*)(pBase + expDir.VirtualAddress); WORD *pOrds = (WORD*)(pBase + pExpDir->AddressOfNameOrdinals); DWORD *pNames = (DWORD*)(pBase + pExpDir->AddressOfNames); for(unsigned long i = 0; i < pExpDir->NumberOfNames; i++, pOrds++, pNames++) printf("Ordinal: %d\tName: %s\n", *pOrds, (char*)(pBase + *pNames)); } else { printf("No functions are exported from this image.\n"); } fflush(stdout); freopen("CON", "w", stdout); } 

编辑:我是个白痴。 当然'Z'在'o'之前,凌晨3点,我的大脑不能正常工作。 很抱歉。

编辑编辑:好的,我不完全疯了。 一半的问题是显然是C#的string.CompareTo扩展不能词法比较。

例如

 "LoadLibraryW".CompareTo("LZRead"); 

返回“-1”。 这是我混乱的根源。

LZRead在使用ascii的LZRead之前LeaveCriticalSection字典顺序LeaveCriticalSection 。 不要使用大小写不敏感,它看起来会工作。


关于文档的一个有趣的观察。

指针是每个32位…是词法排序,以允许二进制搜索

很难理解为什么要做一个指针(而不是一个符号名)的二分法搜索,但这就是说。

大写的字符序列在小写字母之前。