Ну, сегодня я столкнулся с странностью. Я написал свою собственную версию GetProcAddress некоторое время назад, чтобы получить адреса функций из удаленных процессов. Я, очевидно, потратил немало времени на чтение в архитектуре PE, чтобы выяснить, как лучше подойти к этому.Экспортированные DLL-функции не упорядочены лексически?
Из спецификации 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);
}
EDIT: Я идиот. Конечно, «Z» до «o», это 3 часа ночи, и мой мозг не функционирует. Очень жаль.
EDIT EDIT: Хорошо, я не совсем безумный. Половина проблемы заключалась в том, что, по-видимому, расширение C# string.CompareTo не сравнивается лексически.
Например
"LoadLibraryW".CompareTo("LZRead");
Возвращает "-1". Это стало причиной моей путаницы.
Um, 'Z' является U + 005A, тогда как 'e' является U + 0065 и 5A <65. –
'CompareTo' использует лингвистическое сравнение. Вы хотите сравнить по порядку: 'CompareOrdinal'. –
Да, я знаю об этом сейчас, я просто предположил, когда записываю мой бинарный поиск, который string.Compare будет сравнивать лексически. Все отсортированные сейчас, все еще не могут заставить его работать должным образом, хотя ха-ха. –