导出的DLL函数没有词法排序?

Jas*_*rke 4 c++ windows portable-executable

好吧,今天我遇到了一个奇怪的问题.我刚才写了自己的GetProcAddress版本来获取远程进程的函数地址.我显然花了很多时间阅读PE架构,找出解决这个问题的最佳方法.

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

导出名称指针表是导出名称表中的地址数组(RVAs).指针各32位,并且相对于图像库.指针是词法排序的,以允许二进制搜索.

所以我在编写GetProcAddress版本时考虑到了这一点.显然,使用线性搜索的二进制搜索,在导出表格中可以有很好的效率提升... 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
Run Code Online (Sandbox Code Playgroud)

有人发现这个问题吗?尽管文档声称导出表是按词法排序的,但LZRead在LeaveCriticalSection之前列出.

在处理字符串时,我总是把词法排序当作字母顺序的同义词,我在这里错了还是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);
}
Run Code Online (Sandbox Code Playgroud)

编辑:我是个白痴.当然'Z'在'o'之前,它是凌晨3点,我的大脑没有运作.很抱歉.

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

例如

"LoadLibraryW".CompareTo("LZRead");
Run Code Online (Sandbox Code Playgroud)

返回"-1".这是我困惑的根源.

wal*_*lyk 5

LZReadLeaveCriticalSection使用ascii 之前按字典顺序排列.不要使用不区分大小写,看起来它会起作用.


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

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

很难理解为什么人们会对指针进行二进制搜索(而不是符号名称),但这就是所说的.