Импорт таблицы (IT) против импорта адресной таблицы (IAT)

#c #portable-executable

#c #переносимый-исполняемый

Вопрос:

Я пытался проанализировать / отобразить информацию в таблице адресов импорта (IAT) процесса после его загрузки и запуска. Я понимаю, что вызовы API в программах переходят к соответствующей точке в IAT, которая затем переходит к фактической функции в загруженных DLL.

Правильно ли, что IAT можно найти, прочитав заголовок PE и следуя OptionalHeader.DataDirectory[1] указатель на массив IMAGE_IMPORT_DESCRIPTORs. Затем следуем указателям FirstThunk. В то время как приведенные здесь указатели на OriginalFirstThunk дадут вам исходную таблицу импорта (IT)?

Я также попытался следовать OptionalHeader.Указатель DataDirectory[12] в заголовке PE, но это было еще менее успешным.

Я тестировал это, пытаясь проанализировать эту структуру для notepad.exe (32 бит), используя ReadProcessMemory из другого процесса.

Вот приблизительный C-псевдокод для того, что я делаю:

 char buf[128];

// get first import descriptor
readMemory(amp;import, procImgBase   DataDirectory[1].VirtualAddress, sizeof(IMAGE_IMPORT_DESCRIPTOR));

// get dll name 
readMemory(buf, import.Name   procImgBase, 127);
printf("libname: %sn", buf);

// get first function name
DWORD iltAddress = 0;
readMemory(amp;iltAddress, import.FirstThunk   procImgBase, 4);
readMemory(buf, iltAddress   procImgBase, 127);
printf("fname: %sn", libName   2); // <-- the  2 for the 2byte 'hint' of import lookup table entries
  

Если в строке с 3-й по последнюю я заменяю ее на import .OriginalFirstThunk вместо FirstThunk, он напечатает все, как ожидалось. Должно быть, я что-то упускаю концептуально, и поэтому мне было интересно, может ли кто-нибудь пояснить, что это такое, для меня?

Большое спасибо!

Ответ №1:

Похоже, вы движетесь в правильном направлении. Некоторые примечания:

  • DataDirectory выдает вам смещение к массиву IMAGE_IMPORT_DESCRIPTOR, который завершается вводом всех нулей. Для каждой импортируемой библиотеки DLL будет один IMAGE_IMPORT_DESCRIPTOR
  • IMAGE_IMPORT_DESCRIPTOR имеет смещения в 2 массива IMAGE_THUNK_DATA, один из которых поддерживает смещения в именах импортированных функций (OriginalFirstThunk), а другой, который теперь содержит фактические адреса функций (FirstThunk)

Поскольку ваш исполняемый файл запущен, IAT должен содержать фактический адрес функции, а не RVA для записи имени.

Вместо этого вы могли бы сделать что-то вроде этого:

 DWORD rva_to_name_of_function = 0;
DWORD address_of_function = 0;

// get the RVA of the IMAGE_IMPORT_BY_NAME entry
readMemory(amp;rva_to_name, import.OriginalFirstThunk   procImgBase, 4);

// copy the name of the import
readMemory(buf, rva_to_name   procImgBase   2, 127);

// get the actual address that was filled in by the loader
readMemory(amp;address_of_function, import.FirstThunk   procImgBase, 4);

printf("fname: %s address: %X", buf, address_of_function); 
  

Взгляните на эту статью для получения некоторых полезных деталей:
http://msdn.microsoft.com/en-us/magazine/cc301808.aspx

Комментарии:

1. Спасибо! теперь это имеет смысл. Я думаю, я должен был понять, когда значения, которые я получал обратно, выглядели как действительные адреса, а не RVA.

2. @Eric Rahm, ты уверен насчет своего первого пункта? В winnt.h необязательные структуры заголовка определяют IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; , не IMAGE_IMPORT_DESCRIPTOR DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];

3. Вот где я сейчас застрял… Я готов получить каталоги данных, но как загрузить их в правильные структуры, чтобы получить имена DLL из IAT, ILT или INT, в настоящее время блокирует меня.

Ответ №2:

Эрик дал хороший ответ, вот несколько дополнительных разъяснений:

Я понимаю, что вызовы API в программах переходят к соответствующей точке в IAT, которая затем переходит к фактической функции в загруженных DLL.

Программа использует ВЫЗОВ PTR DS:[IAT-ADDRESS], который считывает данные с адреса в IAT, чтобы определить, где находится программа во время выполнения.

Принимая во внимание, что указатели OriginalFirstThunk, приведенные здесь, дадут вам исходную таблицу импорта (IT)?

Указатели OriginalFirstThunk указывают на таблицу поиска импорта (ILT). Если вы откроете двоичный файл на диске, ILT и IAT будут идентичны; оба содержат строки RVA для имен функций. После загрузки программы записи IAT (в памяти) перезаписываются адресами импортированных функций.

По моему опыту, лучшим источником информации о таблице импорта и всех сопутствующих структурах данных является сама спецификация PE. Если вы терпеливо прочтете раздел об импорте, все станет ясно.

http://msdn.microsoft.com/en-us/windows/hardware/gg463125

Комментарии:

1. Спасибо за разъяснение этого. Я читал и перечитывал документацию MSDN, но мой мозг, похоже, устроен иначе, чем у авторов — я просто не мог понять эту ее часть. То, как вы формулируете вещи, понятнее 🙂

2. Этот pecoff docx меня действительно раздражает. В ней содержится тонна информации, но в ней есть некоторые действительно обидные пробелы… Тоже дезинформация. Их предложение о наличии «практически всех исполняемых файлов» .idata не так уж и всеобъемлюще…