Уроки Iczelion'а




Урок 7. Таблица экспорта


Мы изучили одну часть динамической линковки под названием таблицы импорта в предыдущем туториале. Теперь мы узнаем о другой стороне медали, таблице экспорта.

Скачайте пример.

Теория:

Когда PE-загрузчик запускает программу, он загружает соответствующие DLL в адресное пространство процесса. Затем он извлекает информацию об импортированных функциях из основной программы. Он использует информацию, чтобы найти в DLL адреса функций, которые будут вызываться из основного процесса. Место в DLL, где PE-загрузчик ищет адреса функций - таблица экспорта.

Когда DLL/EXE экспортирует функцию, чтобы та была использована другой DLL/EXE, она может сделать это двумя путями: она может экспортировать функцию по имени или только по ординалу. Скажем, если в DLL есть функция под названием "GetSysConfig", она может указать други DLL или EXE, что если они хотят вызвать функцию, они должны указать ее имя, то есть, GetSysConfig. Другой путь - экспортировать функцию по ординалу. Что такое ординал? Ординал - это 16-битный номер, который уникальным образом идентифицирует функцию в определенном DLL. Этот номер уникален только для той DLL, на которую он ссылается. Hапример, в вышеприведенном примере, DLL может решить экспортировать функцию через ординал, скажем, 16. Тогда другая DLL/EXE, которая хочет вызвать эту функцию должна указать этот номер в GetProcAddress. Это называется экспортом только через ординал.

Экспорт только через ординал не очень рекомендуется, так как это может вызвать проблемы при распространении DLL. Если DLL апгрейдится или апдейтится, человек, занимающийся ее программированием не может изменять ординалы функции, иначе программы, использующие эту DLL, перестанут pаботать.

Теперь мы можем анализировать структуру экспорта. Как и в случае с таблицей импорта, вы можете узнать, где находится таблица экспорта, из директории данных. В этом случае таблица экспорта - это первый член директории данных. Структура экспорта называется IMAGE_EXPORT_DIRECTORY. В структуре 11 параметров, но только несколько из них по настоящему нужны.

ПолеЗначение

nName

Hастоящее имя модуля. Это поле необходимо, потому что имя файла может измениться. Если подобное произойдет, PE-загрузчик будет использовать это внутреннее имя.

nBase

Число, которое вы должны сопоставить с ординалами, чтобы получить соответствующие индексы в массиве адресов функций.

NumberOfFunctions

Общее количество функций/символов, которые экспортируются из модуля.

NumberOfNames

Количество функций/символов, которые экспортируются по имени. Это значение не является числом ВСЕХ функций/символов в модуле. Это значение может быть pавно нулю. В этому случае, модуль может экспортировать только по имени. Если нет функции/символа, который бы экспортировались, RVA таблицы экспорта в директории данных будет pавен нулю.

AddressOfFunctions

RVA, который указывает на массив RVA функций/символов в модуле. Вкратце, RVA на все функции в модуле находятся в массиве и это поле указывает на начало массива.

AddressOfNames

RVA, которое указывает на массив RVA имен функций в модуле.

AddressOfNameOrdinals

RVA, которое указывает на 16-битный массив, который содержит ординалы, ассоциированные с именами функций в массиве AddresOfNames.

<


Содержание  Назад  Вперед