Мы подходим к самому интересному разделу данного файла и любого PE исполнимого файла. По сравнению со старыми 16 битными приложениями все значительно упростилось - мы говорим системе о том, что мы хотим вызвать и откуда, а система в нужное место нашей программы предоставляет адрес перехода (внутри нашей FLAT памяти виртуальной машины). Все. Далее адрес уже используют по разному. Borland строит самостоятельно в секции кода (точнее линкер) переходники вида
SomeThunkGate: Jmp D,[0XXXXXXXXh]
и все ссылки в программе оформляются:
Call SomeThunkGate
При этом задача организации импорта возлагается на линковщик (напомним, Borland использует старый OMF формат). Прародители метода пошли другим путем. Переходники содержатся в библиотеке импорта и являются частью библиотеки. Линкер просто компонует ее в программу, причем с помощью одной хитрой особенности: имена секций содержащие в себе знак '$' могут объединяться с отсечением оставшейся части имени (секции упорядочиваются перед слиянием по оставшейся части имени). Линкеру остается лишь из чего-то вроде .idata$1 .idata$2 .idata$3 составить одну удобоваримую секцию .idata Следует еще добавить, Microsoft в своих программах часто организует вызовы внешних функций несколько иным образом: вместо Near вызова переходников используется непосредственно требуемый адрес, примерно так
Call DWord Ptr [SomeServiceAddressVariable]
или так
Mov ESi,SomeServiceAddressValue
Call ESi
Call ESi
создавшие формат да создадут удобный компилятор ;-)
Каталог импорта (Import Directory Table)
Информация импорта начинается с Import Directory Table, которая описывает остальную информацию об импорте. Import Directory Table содержит адресную информацию используемую для разрешения ссылок на точки входа внутри образа библиотеки. Таблица импорта состоит из отдельных входов, как минимум по одному на каждую импортируемую библиотеку. Последний вход, указывающий на конец таблицы является пустым (заполнен нулями).
В "нормальных" файлах вся информация об импорте предворяется записью Import Directory Table (но физически вы можете разместить эту таблицу где угодно). Дело обстоит примерно так:
Typical Import Layout
это приблизительная последовательность расположения в файле различных частей секции импорта, создаваемой существующими компоновщиками. В реальных файлах нет никаких ограничений на порядок следования участков секции импорта, а у загрузчика Windows'95 и на расположение последних. Формат одного входа каталога импорта приведен в таблице чуть ниже.
Import Directory Entry
00h |
DWord |
Import LookUp |
Содержит ссылку на табличку RVA указывающих на соответствующие Hint-Name's или непосредственно ординал ипортируемого входа |
04h |
DWord |
Time/Date Stamp |
Отметка о времени создания, часто содержит 0 (У-уф) |
08h |
DWord |
Forward Chain |
? связано с возможностью передачи экспорта в другие библиотеки. Обычно равно 0FFFFFFFFh |
0Ch |
DWord |
Name RVA |
Ссылка на библиотеку с которой нам необходимо поиметь вызовы представлена в виде ASCIZ. |
10h |
DWord |
Addres Table RVA |
Ссылка на табличку адресов импорта, заполняется системой при связывании |
Total Structure size |
14h |
Общий размер таблички импорта |
Таблица просмотра импорта (Import LookUp Table)
Имена сервисов библиотеки содержатся в Hint-Name's Table. Ее формат довольно прост:
Hint-Name Entry
Word Hint |
Размер произвольный ASCIZ Service Name |
Byte PAD |
Строка закрывается нулевым байтом, и при необходимости ее длина выравнивается до четной границы еще одним 0 |
На имена сервисов и ссылаются RVA из таблицы Import LookUp. В случае импорта по ординалам старший бит значения из таблицы Import LookUp установлен в единицу. Конец таблицы находится по нулевому элементу. При попытке связывания по имени системный загрузчик использует вначале значение Hint (укороченный идентификатор точки входа) и только при неудачной попытке его использования производит в своих системных таблицах поиск требуемой точки входа. Имя сервиса чувствительно к регистру. Имя библиотеки - нет.
Таблица адресов импорта (Import Address Table)
Данная таблица принимает в себя информацию после связывания загрузчиком импорта из внешних библиотек, она завершается нулевым элементом. Очень интересным фактом является то, что во многих программах она уже заполнена. Это справедливо, по меньшей мере, для программ самой Windows'95. Подобный факт заставляет предполагать, что загрузчик может не выполнять утомительной процедуры настройки во многих случаях. Ему будет необходимо лишь загрузить файл в ОЗУ и передать туда управление... Да здравствует вечно живой COM формат!
Да, еще, для перехвата функции из библиотеки можно поменять адрес в этой таблице - довольно простой и общий метод перехвата управления внутри отдельного процесса. И еще пара плюшек на заметку, данная таблица (как и многие другие таблицы импорта) может находиться на своем старом месте, а вот Import Directory Table имеет смысл изменить, перенести в требуемое место и там оставить. Файл корректируется минимально, а проблемы возникающие при этом весьма незначительны и я их описывал.
[Оглавление]