导出的 DLL 函数未按词法排序? [英] Exported DLL functions not ordered lexically?

查看:33
本文介绍了导出的 DLL 函数未按词法排序?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

Well, today I ran into an oddity. I wrote my own version of GetProcAddress a while ago to get function addresses from remote processes. I obviously spent quite a lot of time reading up on the PE architecture to figure out the best way to approach this.

根据 PECOFF v8 规范(我认为这是最新的官方规范),关于 Export Name Pointer Table 有以下表示法:

From the PECOFF v8 specification (which, as I take it is the most up-to-date official specification), there is the following notation about the Export Name Pointer Table:

导出名称指针表是一个地址数组 (RVA) 到导出名称表.每个指针都是 32 位,并且相对于形象基地.指针按词法排序以允许二进制搜索.

The export name pointer table is an array of addresses (RVAs) into the export name table. The pointers are 32 bits each and are relative to the image base. The pointers are ordered lexically to allow binary searches.

所以我在编写我的 GetProcAddress 版本时考虑到了这一点.显然,在说...KERNEL32.dll(1300 多个导出函数)中,使用二进制搜索而不是线性搜索来遍历导出表会大大提高效率.

So I took this into account when writing my version of GetProcAddress. Obviously there would be a nice efficiency improvement in walking the export table in say...KERNEL32.dll (1300+ exported functions) using a binary search over a linear search.

直到今天我遇到了一个奇怪的问题,这才奏效了一段时间.似乎 Kernel32 中的某些导出函数实际上并未按词法排序,这使我无法进行二分查找.以下是使用我将在下面发布的函数的导出 Dll 转储的摘录:

This worked for a while until today when I ran into a weird issue. It appears that some of the exported functions in Kernel32 aren't actually ordered lexically and this was throwing off my binary search. The following is an excerpt from a Exported Dll dump using the function I'll post below:

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 之前.

Anyone spot the issue here? Despite the documentation claiming that the export table is ordered lexically, LZRead is listed before LeaveCriticalSection.

在处理字符串时,我一直认为词法排序与字母排序是同义词,是我在这里弄错了还是 Kernel32 的导出表有一些奇怪的问题?

I've always taken lexical ordering to be synonymous with alphabetical ordering when dealing with strings, am I wrong here or is there some weird issue with Kernel32's export table?

用于转储导出的函数:

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 点,我的大脑不工作了.非常抱歉.

I'm an idiot. Of course 'Z' is before 'o', It's 3am and my brain isn't functioning. Very sorry.

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

EDIT Okay, I'm not totally insane. Half of the problem was that apparently C#'s string.CompareTo extension doesn't compare lexically.

例如

"LoadLibraryW".CompareTo("LZRead");

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

Returns "-1". This was the source of my confusion.

推荐答案

LZRead 按字典顺序在 LeaveCriticalSection 之前使用 ascii.不要使用不区分大小写的方式,它看起来会起作用.

LZRead is lexicographically before LeaveCriticalSection using ascii. Don't use case insensitivity and it looks like it will work.

关于文档的有趣观察.

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

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

It is hard to understand why one would do a binary search for a pointer (rather than a symbol name) but that is what is says.

这篇关于导出的 DLL 函数未按词法排序?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆