Вход на хостинг
IT-новости
20.04.2016 iPhone 2017 года поместят в водонепроницаемый корпус из стекла
Линейка iPhone в новом году серьезно поменяется. В этом уверен аналитический исследователь Мин Чи Ку......
30.07.2015 Ищем уникальный контент для сайта
Ищем уникальный контент для сайта Без уникального контента Ваш сайт обречен на то, что его страницы......
pNextSection+=40; // следующий элемент Section Table
}
Экспорт
Таблица экспорта представляет собой сложную иерархическую структуру, каждый из компонентов которой может быть расположен в любом месте страничного имиджа, хотя по спецификации она должна быть сосредоточена в одной области. Когда-то таблице экспорта выделялась своя персональная секция .edata, но теперь этого правила практически никто не придерживается, поэтому говорить о секции импорта не совсем корректно (впрочем, если вы назовете директорию секцией, большой беды не будет и все вас поймут).
На вершине иерархии находится структура IMAGE_ EXPORT_DIRECTORY, также известная под именем export directory table, содержащая указатели на три подчиненные структуры: таблицу экспортируемых имен (Name Pointer), таблицу экспортируемых ординалов (Ordinal Table) и таблицу экспортируемых адресов (Export Address Table). Поле Name RVA указывает на строку с именем динамической библиотеки, которое, судя по всему, игнорируется и может принимать любые значения.
Экспорт функций/данных может производиться как по их имени, так и по ординалу. Таблицы имен и адресов представляют собой массивы из RVA-указателей, ссылающихся на ASCIIZ-строки с именами функций и адреса экспортируемых функций/данных соответственно. Таблица ординалов представляет собой массив 16-битных индексов (ординалов) и служит своеобразным связующим звеном между таблицей имен и таблицей адресов. Пусть i-элемент таблицы имен указывает ASCIIZ-строку с именем интересующей нас функции «my_func», тогда i-элемент таблицы ординалов содержит индекс элемента таблицы адресов с RVA-адресом функции my_func или, говоря другими словами, ее ordinal.
В переводе на язык Си это выглядит так:
Листинг 8. Экспорт по именам
i = Search_ExportNamePointerTable (ExportName);
ordinal = ExportOrdinalTable [i];
SymbolRVA = ExportAddressTable [ordinal - OrdinalBase];
Если нам известен ординал функции, то обращаться к таблицам имен/ординалов необязательно. Определенная путаница связана с тем, что ординал задает отнюдь не индекс в таблице оридиналов, а индекс в таблице адресов. Таблица ординалов представляет собой вспомогательную подструктуру, не имеющую самостоятельной ценности и всегда использующуюся только в паре с таблицей имен. Поэтому таблицы имен и ординалов всегда содержат одинаковое количество элементов, задаваемое полем Number of Name Pointers, которое может и не совпадать с количеством элементов таблицы адресов, задаваемое полем Export Address Table RVA.
Теперь о тонкостях. Таблица адресов может содержать «разрывы», т.е. элементы, обращенные в нуль и указывающие в никуда. К счастью, их легко отсеять. Хуже, что далеко не всякий элемент таблицы адресов представляет собой действительный адрес экспортируемой функции, ведь динамические библиотеки поддерживают форвардинг (forwarding), т.е. сквозное перенаправление экспорта в другую DLL, и тогда соответствующий элемент таблицы адресов содержит RVA-адрес ASCIIZ-строки типа «NTDLL.RtlDeleteCriticalSection», описывающей переназначение. Как отличить forward-строки от действительных адресов экспортируемых функций? Да очень просто, forward-строки всегда расположены внутри таблицы экспорта (именно поэтому спецификация настоятельно рекомендует делать ее непрерывной, никаких других причин для этого у системного загрузчика нет). Размер таблицы экспорта содержится в DATA_DIRECTORY там же, где находится адрес export directory table, и разоблачение forward-строк осуществляется тривиально.