Таблица импорта (IT) и таблица адресов импорта (IAT)
Я пытаюсь разобрать/отобразить информацию в таблице адресов импорта (IAT) процесса после ее загрузки и запуска. Я понимаю, что вызовы API в программах переходят в соответствующую точку IAT, которая затем переходит к фактической функции в загружаемых DLL.
Правильно ли, что IAT можно найти, прочитав заголовок PE и следуя указателю OptionalHeader.DataDirectory [1], в массив IMAGE_IMPORT_DESCRIPTOR. Затем следуйте указателям FirstThunk. Если указатели OriginalFirstThunk здесь, вы получите исходную таблицу импорта (IT)?
Я также пробовал следовать указателю OptionalHeader.DataDirectory [12] в заголовке PE, но это было еще менее успешным.
Я тестировал это, пытаясь разобрать эту структуру для notepad.exe(32 бит), используя ReadProcessMemory из другого процесса.
Вот грубый C-psuedocode для того, что я делаю:
char buf[128];
// get first import descriptor
readMemory(&import, procImgBase + DataDirectory[1].VirtualAddress, sizeof(IMAGE_IMPORT_DESCRIPTOR));
// get dll name
readMemory(buf, import.Name + procImgBase, 127);
printf("libname: %s\n", buf);
// get first function name
DWORD iltAddress = 0;
readMemory(&iltAddress, import.FirstThunk + procImgBase, 4);
readMemory(buf, iltAddress + procImgBase, 127);
printf("fname: %s\n", libName + 2); // <-- the +2 for the 2byte 'hint' of import lookup table entries
Если на третьей-последней строке я заменю его import.OriginalFirstThunk вместо FirstThunk, он напечатает все, как ожидалось. Мне нужно что-то пропустить концептуально, и поэтому мне было интересно, может ли кто-нибудь прояснить, что это для меня?
Большое спасибо!
Ответы
Ответ 1
Похоже, ты направляешься в правильном направлении. Некоторые примечания:
- DataDirectory дает вам смещение
к массиву
IMAGE_IMPORT_DESCRIPTOR, который
завершается записью всех нулей.
Будет один
IMAGE_IMPORT_DESCRIPTOR для каждой DLL
который импортируется
-
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(&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(&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
Ответ 2
Эрик дал хороший ответ, вот некоторые дополнительные пояснения:
Я понимаю, что вызовы API в программах переходят в соответствующую точку IAT, которая затем переходит к фактической функции в загружаемых DLL.
В программе используется CALL PTR DS: [IAT-ADDRESS], который считывает с адреса в IAT, чтобы определить, где находится программа во время выполнения.
В то время как указатели OriginalFirstThunk здесь, вы получите исходную таблицу импорта (IT)?
Указатели OriginalFirstThunk указывают на таблицу Import Lookup (ILT). Если вы открываете двоичный диск на диске, ILT и IAT идентичны; оба содержат RVA для ввода имен имен. После загрузки программы записи IAT (в памяти) перезаписываются адресами импортированных функций.
По моему опыту, лучшим источником информации о таблице импорта и всех связанных с ней структурах данных является сама спецификация PE. Если вы будете терпеливо читать раздел об импорте, все будет ясно.
http://msdn.microsoft.com/en-us/windows/hardware/gg463125