2012-06-19 1 views
4

Ну, сегодня я столкнулся с странностью. Я написал свою собственную версию 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". Это стало причиной моей путаницы.

+1

Um, 'Z' является U + 005A, тогда как 'e' является U + 0065 и 5A <65. –

+0

'CompareTo' использует лингвистическое сравнение. Вы хотите сравнить по порядку: 'CompareOrdinal'. –

+0

Да, я знаю об этом сейчас, я просто предположил, когда записываю мой бинарный поиск, который string.Compare будет сравнивать лексически. Все отсортированные сейчас, все еще не могут заставить его работать должным образом, хотя ха-ха. –

ответ

5

LZRead лексикографически до LeaveCriticalSection с использованием ascii. Не используйте чувствительность к регистру, и похоже, что это сработает.


Интересное наблюдение за документацией.

указатели являются 32-битными каждый ... упорядочены лексически, чтобы двоичный поиск.

Трудно понять, почему можно было бы выполнить двоичный поиск указателя (а не имени символа), но это то, что сказано.

+0

Да, я подумал, что после того, как я перечитаю свой вопрос. Сейчас я чувствую себя невероятно глупо. –

+0

Странно, ТАК не позволяет мне выбрать ответ на 10 минут. –

+0

о вашем редактировании, это не указательная таблица EntryPoint, это таблица указателей имен, по существу указатели просто указывают на строки с нулевым завершением и упорядочены так, что они образуют лексически упорядоченный массив. –

3

Символьные ординалы для верхнего регистра перед ординалами для нижнего регистра.