好吧,今天我遇到了一个奇怪的问题。不久前,我编写了自己的 GetProcAddress 版本,以从远程进程获取函数地址。我显然花了很多时间阅读 PE 架构来找出解决这个问题的最佳方法。
从 PECOFF v8 规范(我认为它是最新的官方规范)中,有以下关于 的符号Export Name Pointer Table
:
导出名称指针表是导出名称表中的地址数组 (RVA)。每个指针都是 32 位,并且相对于图像库。指针按词法排序以允许二进制搜索。
所以我在编写我的 GetProcAddress 版本时考虑到了这一点。显然,使用二进制搜索而不是线性搜索,在 say...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);
}
编辑:我是个白痴。当然,“Z”在“o”之前,现在是凌晨 3 点,我的大脑无法正常工作。很抱歉。
编辑编辑:好的,我并不完全疯了。问题的一半显然是 C# 的 string.CompareTo 扩展不进行词法比较。
例如
"LoadLibraryW".CompareTo("LZRead");
返回“-1”。这是我困惑的根源。