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

时间:2012-06-19 18:28:24

标签: 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

有人在这里发现了这个问题吗?尽管文档声称导出表是按词汇顺序排序的,但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);
}
编辑:我是个白痴。当然&#39; Z&#39;在凌晨3点之前,凌晨3点,我的大脑无法正常运转。很抱歉。

编辑编辑:好的,我并非完全疯了。问题的一半是显然是C#的字符串。比较扩展并不能用词汇进行比较。

例如

"LoadLibraryW".CompareTo("LZRead");

返回&#34; -1&#34;。这是我混乱的根源。

2 个答案:

答案 0 :(得分:5)

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


关于文档的有趣观察。

  

指针各为32位......以词汇方式排序以允许二进制搜索

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

答案 1 :(得分:3)

大写的字符序号出现在小写的序号之前。