Читаю Bernd Luevelsmeyer'a. Вижу следующее: Пишу код, который делает именно это. Экспериментирую над ntoskrnl.exe WIN XP SP 2. В моем случае i=1. Если все делать по мануалу Brend'a, то получаем следующие данные: FuncName: CcCanIWrite Ordinal: 003C RVA EP: 0x47В5 А если мы запустим LordPE или PE Tools, то увидим, что это значение RVA EP для функции с ординалом 1 и именем ExAcquireFastMutexUnsafe. Кто прав? Кому верить?
IceFire Вместо адреса публичного символа там может оказаться адрес цепочки форвардов (forwarder chain). Если адрес попадает в диапазон секции экспорта, то там должен быть форвард. Нельзя так делать, ведь по индексам совпадают только 2 последние таблицы (names и ordinals), а первую (EAT) нужно индексировать по ординалу из 3ей. Т.е. сначала читаем н-ный ординал из таблицы ординалов (и параллельно имя функции из таблицы имён), вычитаем базу ординалов и прибавляем 1 - получаем индекс для RVA адреса данной функции в таблице адресов (или форвард вместо адреса). PECOFF v8: Visual Studio, Microsoft Portable Executable and Common Object File Format Specification Хотя и в нём есть некоторые ошибки.
А поподробнее можно? Интересненько... //хотя даже в мануалах от интела последних несколько ошибок нашёл сам (fsincos - гон в хедере таблицы).
asmfan Формат библиотек импорта описан неправильно вообще (есть там 2-3 серьёзных ошибки) и про @compid'ы ни слова. Ординалы в импорте/экспорте не zero-based, а 1-based, т.е. с 1 начинаются. Поэтому в своём парсере после длительной отладки пришлось добавить +1 и всё заработало.
6.3.1. Export Directory Table об этом речь? [added] Всё-таки 0 то мы получим при вычитании. Да это и логично имхо, т.к. доступ до первой экспортируемой ф-ии - нулевой индекс.
Кстати, очень много примеров разбора таблицы экспорта написаны с учетом того, что ординалы, как вы тут выразились, zero-based. Я тоже в свое время разобрался в этом деле, но мне непонятны постоянные ошибки в статьях - они что там свои примеры не тестят чтоли?
asmfan Нет, Ordinal Base - это само собой. Я имел в виду, что к ординалу из таблицы ординалов, из которого нужно вычесть базу, необходимо ещё прибавить 1, чтобы проиндексировать таблицу адресов. Короче, так: function_RVA = RVA_table[ordinal - base + 1] Ну, вот простой пример из kernel32.dll: Address of name ordinals: 000043EC (RVA) -> 000037EC (file offset) Base: 1 В хексредакторе по адресу 000037EC имеем следующее: 0000 0100 0200 0300 0400 0500 0600 0700 ... Таким образом, первый ординал = 0. После вычитания базы получаю: 0 - 1 = -1, а вовсе не ноль! Поэтому нужно прибавить ещё 1.
мне кажется что у Ицзелиона этот момент вполне прозрачно описан, + исходники pedump, и не надо запутывать я вот так ищу указатели на RVA(в памяти) Код (Text): for ( unsigned int i = 0; i < pExportDir->NumberOfNames; i++ ) { if ( 0 == strcmp(lpProcName, (char*)(pszFuncNames[i] + (char*)ImageBase)) ) return (void*)(&pdwFunctions[(unsigned int)pwOrdinals[i]]); } и надеюсь что все правильно
Зря, что надеешься... Во-первых, не учитываешь OrdinalBase, во-вторых - забыл вычесть 1 из индекса при поиске адреса точки входа функции. Короче, смотри последний пост Quantum'а
у дядьки Ицзелиона написано: "Заметьте, что nBase не влияет на значения в массиве AddressOfNameOrdinals. Hесмотpя на имя "AddressOfNameOrdinals", этот массив содеpжит индесы в массиве, а не оpдиналы." оттуда же: Если у нас есть имя экспоpтиpуемой функции и нам тpебуется получить ее адpес в модуле, мы должны сделать следующее.
Смотри, тут получается интересная вещь - (кстати у меня ошибочка вышла в предыдущем посте: не отнять 1, а прибавить 1 к индексу )), извиняюсь за дизинформацию) если ты не будешь учитывать эти вещи о которых я написал, у тебя все БУДЕТ РАБОТАТЬ при OrdinalBase == 1 (в большинстве случаев линкер в такое значение его и выставляет). А вот если OrdilnalBase != 1, то тогда ты будешь получать адреса каких-то следующих функций.
чтоб показать что код работает корректно набросал примерчик, реализован поиск по имени в таблице экспорта указателя на RVA
А что именно чиать то? если вот это "у тебя все БУДЕТ РАБОТАТЬ при OrdinalBase == 1 (в большинстве случаев линкер в такое значение его и выставляет). А вот если OrdilnalBase != 1, то тогда ты будешь получать адреса каких-то следующих функций." то я спецом сделал две dll'ки разные для теста, как видишь все работает
Asterix Во-первых твой код показывает адрес, по которому хранится RVA функции MyProc2, а не сам RVA. Во-вторых, что гораздо интереснее, в обоих DLL таблицы ординалов идентичны - они содержат 0000 0100. Получается, что база вообще учитывается только лишь при импорте по ординалу. Получается, что дока по PE формату врёт ещё больше, чем я думал А в моей формуле нужно не 1 прибавлять, а просто не вычитать базу...
Quantum Почитай что Ицзелион пишет... что это не ординалы а индексы. А ординалы само собой, и при поиске по имени они как таковые не учитываются. Вот когда нужен поиск по ординалу, тогда и базу учитывать придется. а функции в имеют ординалы 1 и 2 в первой длл, и 200, 201 во второй, значит во втором случае база 200