# Глава 33

Перед тем, как начинать, как безумные, чинить IAT’ы, необходимо введение в то, что такое вообще IAT. Мы рассмотрим на примере оригинального крэкми CrueHead’а [\[ссылка\]](https://github.com/yutewiyof/intro-cracking-with-ollydbg/tree/3679d233f4d394747f712e9b6b09bc9c2a3cad80/.gitbook/assets/files/1/ollydbg01-Crackme.7z) и упакованного варианта *(самостоятельно упаковывали его в 31 главе)*, где располагается IAT и что делает с ним упаковщик.

Ок, сначала общая идея, для чего нужен IAT.

Дело в том, что у каждой API-функции есть свой адрес, например, откроем оригинальный крэкми CrueHead’а в OllyDbg и напечатаем:

![](https://416819976-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LjyqT34OedPJiOdIrDw%2F-LmvTfhKwMHzvDz9duQT%2F-LmvTvk7RsdzEOx8uKY4%2F1.png?generation=1566513609345058\&alt=media)

Видим, что на моей машине адрес этой функции 77D50EA, если вы пойдёте по соответствующему адресу на вашей машине, то у одних это может быть тот же адрес, у других нет, зависит от вашей версии Windows, от установленных обновлений, которых, как мы знаем множество, и каждая новая версия DLL, содержащая API-функцию (в данном случае это User32.dll) обычно меняет адрес.

![](https://416819976-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LjyqT34OedPJiOdIrDw%2F-LmvTfhKwMHzvDz9duQT%2F-LmvTvkOcsSxI0-kCbu0%2F2.png?generation=1566513668819036\&alt=media)

Почти каждый раз, когда Microsoft выпускает новую версию этой DLL, меняются адреса API-функций, входящих в неё, поэтому если я запрограммирую в крэкми CrueHead’а, чтобы при совершении перехода на API-функцию MessageBoxA, это был переход на 77D504EA, то на моей машине это будет прекрасно работать, а также у тех, у кого та же версия User32.dll, но у остальных, у кого не Windows XP или стоит другая версия User32.dll, нужной функции по этому адресу не будет, и произойдёт ошибка.

Тогда вопрос заключается в том, что операционная система должна предоставлять какой-то способ, чтобы мой крэкми работал на других Windows и с другими версиями DLL.

Для этого были созданы знаменитые таблицы под названием IT (import table – таблица импорта) и IAT (Import Address Table – таблица импортированных адресов).

Не надо бояться этих страшных названий – в этой главе мы подробно рассмотрим, где они находятся в распакованной программе и для чего служат.

![](https://416819976-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LjyqT34OedPJiOdIrDw%2F-LmvTfhKwMHzvDz9duQT%2F-LmvTvkdzbBeS4yzpHyH%2F3.png?generation=1566513606527799\&alt=media)

Теперь делаем SEARCH FOR-ALL INTERMODULAR CALLS и видим вызовы, которые идут в другие модули или DLL, то есть могут быть вызовами API-функций.

![](https://416819976-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LjyqT34OedPJiOdIrDw%2F-LmvTfhKwMHzvDz9duQT%2F-LmvTvktdtutCKprz97e%2F4.png?generation=1566513632967093\&alt=media)

Здесь видим различные вызовы, например функции MessageBoxA, если сделаем двойной щелчок по первой из них:

![](https://416819976-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LjyqT34OedPJiOdIrDw%2F-LmvTfhKwMHzvDz9duQT%2F-LmvTvl28OvuhSXaq3pb%2F5.png?generation=1566513606574791\&alt=media)

Видим, что на самом деле это вызов CALL 40143A, и OllyDbg нам поясняет, что произойдёт переход на API-функцию MessageBoxA. Она заключает MessageBoxA в угловые скобки, чтобы показать, что вызов прямой, а не косвенный.

`CALL 40143A`

![](https://416819976-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LjyqT34OedPJiOdIrDw%2F-LmvTfhKwMHzvDz9duQT%2F-LmvTvlGuxG6w4YJibk8%2F6.png?generation=1566513609249919\&alt=media)

Видим, что среди опций OllyDbg во вкладке DISASM есть SHOW SIMBOLIC ADDRESSES. Если уберём её, то всё становится более ясным.

![](https://416819976-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LjyqT34OedPJiOdIrDw%2F-LmvTfhKwMHzvDz9duQT%2F-LmvTvlZWnNHUxuNH2lX%2F7.png?generation=1566513649378545\&alt=media)

Видим, что справа также остаются пояснения с параметрами и названием API-функции, куда будет совершён переход, но теперь CALL действительно похож на прямой переход.

`CALL 40143A`

В SEARCH FOR INTERMODULARS CALLS

![](https://416819976-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LjyqT34OedPJiOdIrDw%2F-LmvTfhKwMHzvDz9duQT%2F-LmvTvlnKm7c_ZMxhrQf%2F8.png?generation=1566513637199226\&alt=media)

Видим, что в реальности три вызова MessageBoxA – это вызовы 40143A, посмотрим, что там находится.

![](https://416819976-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LjyqT34OedPJiOdIrDw%2F-LmvTfhKwMHzvDz9duQT%2F-LmvTvm7O7rV9KeIbYFE%2F9.png?generation=1566513604162086\&alt=media)

Здесь видим, что вся загвоздка тут, чтобы добраться до API-функции, делает косвенный JMP, который таким образом получает значение, куда надо на самом деле перейти, из 4031AC.

`JMP [4031AC]`

![](https://416819976-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LjyqT34OedPJiOdIrDw%2F-LmvTfhKwMHzvDz9duQT%2F-LmvTvmNyvf_ofKyeoiy%2F10.png?generation=1566513616323860\&alt=media)

Также видим, что если включить эту опцию, то понять, что это косвенный переход сложнее, поэтому её лучше выключать, когда работаем с IAT.

И вот этот трюк: программа переходит на API-функцию с помощью косвенного JMP, который получает адрес API-функции из 4031AC, и видим, что для остальных функций есть похожие косвенные переходы.

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

![](https://416819976-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LjyqT34OedPJiOdIrDw%2F-LmvTfhKwMHzvDz9duQT%2F-LmvTvma7A7PDYDbrza1%2F11.png?generation=1566513641928329\&alt=media)

Здесь, и правда, видим, что 4031AC – это часть хранилища, которое содержит все адреса API-функций, по которым располагаются последние на моей машине. Это хранилище и есть знаменитая IAT или IMPORT ADRESS TABLE, которая является ключом к переносимости, и это означает, что все программы имеют одни и те же косвенные переходы на API-функции, а меняются только значения, находящиеся в хранилище. На разных машинах эти значения могут отличаться.

Но постой, скажет мне кто-то, 4031AC – это адрес в программе, поэтому если на каждой машине такие адреса могут отличаться, то и он может отличаться в разных случаях?

Хе-хе, хороший вопрос *(маэстро сам себе плохих вопросов не задаст ? - прим. пер)*, сейчас мы рассмотрим, как вся эта система работает. Главная её цель заключается в том, чтобы наполнить IAT правильными адресами.

![](https://416819976-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LjyqT34OedPJiOdIrDw%2F-LmvTfhKwMHzvDz9duQT%2F-LmvTvmouYGWuuvhVztS%2F12.png?generation=1566513606356259\&alt=media)

Мы знаем, что если сделать VIEW-EXECUTABLE FILE, то можно увидеть, что находится по адресу 4031AC в самом исполняемом файле, находящемся на нашем жёстком диске.

![](https://416819976-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LjyqT34OedPJiOdIrDw%2F-LmvTfhKwMHzvDz9duQT%2F-LmvTvn2b4-B6hc5SgNz%2F13.png?generation=1566513601243780\&alt=media)

Видим, что в exe-файле по этому адресу находится значение 60 33, а когда мы находимся на точке входа, то в памяти в этом месте находится адрес API-функции EA 04 D5 77, и это означает, что операционная система, загружая программу, берёт значение 33600, находящееся по СМЕЩЕНИЮ 0FAC, которое соответствует адресу 4031AC, и замещает его реальным адресом API-функции на моей машине.

Магия?

Нет-нет, так работает Windows, для каждого запускающегося исполняемого файла операционная система заполняет IAT правильными для моей машины адресами API-функций, в данном случае в 4031AC помещается адрес API-функции MessageBoxA, а соседние элементы IAT заполняются адресами других функций, пока вся IAT не будет заполнена.

Конечно, система не настолько магическая, как можно подумать, видим, что в 0FAC находится значение 3360, которое указывает на что-то, может быть на то, какую API-функцию надо вызывать?

Если прибавим 3360 к базе образа, то получим 403360, и что мы найдём по этому адресу?

![](https://416819976-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LjyqT34OedPJiOdIrDw%2F-LmvTfhKwMHzvDz9duQT%2F-LmvTvnI6a74xEIwPwzd%2F14.png?generation=1566513673338312\&alt=media)

Вот в чём дело, это указатель на строку MessageBoxA, то есть система смотрит на этот указатель, ищет нужную функцию по имени и, с помощью GetProcAddress, получает её адрес на нашей машине, а затем заносит его в IAT, перезаписывая им 3360. Таким образом, гарантируется, что программа будет работать с любой версией DLL, так как адрес будет найден ещё до того, как выполнение перейдёт к точке входа в программу, а как только оно там окажется, IAT уже будет заполнен адресами API-функций. Если посмотрим IAT на другой машине, то увидим, что содержимое 4031AC отличается, так как адрес функции другой.

`JMP [4031AC]`

Переход на MessageBoxA, и программисту не нужно думать о тонкостях, так как значение в IAT всегда будет правильным, будучи заполненным правильными адресами при старте программы.

То есть, чтобы система корректно заполнила IAT адресами API-функций, в файле должны находится следующие указатели:

1\)В элементе IAT в самом exe-файле должен находится указатель на строку с текстом, который говорит системе, адрес какой API-функции нужно поместить в этот элемент.

2\)Конечно, строка с текстом должна быть именем API-функции.

Если эти два пункта выполнены, то можем заключить, что программа запустится, и система заполнит IAT правильными значениями (позже рассмотрим полностью, как всё это работает).

Ок, мы оказываемся на OEP распакованной программы, вопрос заключается в том, когда мы туда добрались и делаем дамп программы, зачем нам нужно реконструировать IAT, упаковщики её, что, ломают? Да, одни больше, другие меньше, смысл в том, что упаковщику не нужен IAT программы, потому что загрузка начинается с процедуры распаковки, которая может прочитать какие API-функции нужны в IAT, узнать их адреса и заполнить ими IAT, строки же, которые задают имена функций, стираются, так как они программе не нужны – когда она будет загружена, IAT уже содержит правильные адреса.

Большинство упаковщиков хранят эти строки в зашифрованном виде или в таком месте, где найти их нам, крэкерам, не так уж просто.

Посмотрим на примере крэкми, запакованного UPX’ом, отличие от нормального исполняемого файла.

![](https://416819976-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LjyqT34OedPJiOdIrDw%2F-LmvTfhKwMHzvDz9duQT%2F-LmvTvnVc8Q_BPZFj4dX%2F15.png?generation=1566513632651195\&alt=media)

Вот у нас крэкми CrueHead’а, упакованный UPX’ом, который мы уже использовали в прошлых главах.

Смотрим, что находится по адресу 4031AC (в оригинальном крэкми там находится хранилище).

![](https://416819976-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LjyqT34OedPJiOdIrDw%2F-LmvTfhKwMHzvDz9duQT%2F-LmvTvnfJiid_ucb3Mtz%2F16.png?generation=1566513632268993\&alt=media)

Ничего, всё стёрто, а строки с именами API-функций, располагавшиеся в 403360, где они?

![](https://416819976-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LjyqT34OedPJiOdIrDw%2F-LmvTfhKwMHzvDz9duQT%2F-LmvTvnq-1HAwgzx5acP%2F17.png?generation=1566513599154200\&alt=media)

Ничего, совсем ничего, доходим до OEP и смотрим, что находится по тем же адресам, так как чтобы программа работала, в IAT должно быть что-то, чтобы был совершён переход на API-функцию.

`JMP [4031ac]`

Если IAT пуста, то это вызовет ошибку, то есть упаковщик должен сделать работу, которую обычно делает операционная система. Идём в OEP.

![](https://416819976-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LjyqT34OedPJiOdIrDw%2F-LmvTfhKwMHzvDz9duQT%2F-LmvTvo10WscMyvE0E_h%2F18.png?generation=1566513637324847\&alt=media)

Устанавливаем BP на переход на OEP, делаем RUN и доходим досюда.

Смотрим, что находится в том месте, где располагается IAT.

![](https://416819976-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LjyqT34OedPJiOdIrDw%2F-LmvTfhKwMHzvDz9duQT%2F-LmvTvoCevI28Dbynr81%2F19.png?generation=1566513629802080\&alt=media)

Видим, что для обеспечения нормальной работы программы распаковщик заполняет IAT правильными адресами API-функций на моей машине. Если мы сдампим программу в этот момент, то возникнет проблема, так как у получившейся программы не будет достаточно данных, чтобы запуститься.

Строки, которые идентифицировали каждую из API-функций и находились в 403360, сейчас там отсутствуют.

![](https://416819976-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LjyqT34OedPJiOdIrDw%2F-LmvTfhKwMHzvDz9duQT%2F-LmvTvoQJLfXe3U5FcKk%2F20.png?generation=1566513581335039\&alt=media)

Сделаем дамп, чтобы посмотреть, что останется, но как мы уже отметили, хотя код программы будет правильный, но запуститься сдампленная программа не запустится, так как система не сможет заполнить IAT из-за отсутствия данных.

Для того, чтобы сделать дамп, будем использовать внешнюю программу, которая называется LORDPE DELUXE [\[ссылка\]](https://github.com/yutewiyof/intro-cracking-with-ollydbg/tree/3679d233f4d394747f712e9b6b09bc9c2a3cad80/.gitbook/assets/files/33/LordPE-DLX%201.4actualizado.7z).

![](https://416819976-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LjyqT34OedPJiOdIrDw%2F-LmvTfhKwMHzvDz9duQT%2F-LmvTvoeA39bLe7Fdk-E%2F21.png?generation=1566513581390913\&alt=media)

Запускаем LORD PE DELUXE, ищем процесс, который нужно сдампить, в нашем случае это crackmeUPX.

![](https://416819976-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LjyqT34OedPJiOdIrDw%2F-LmvTfhKwMHzvDz9duQT%2F-LmvTvovNe2818pe9nyg%2F22.png?generation=1566513578274264\&alt=media)

Находим, отмечаем.

![](https://416819976-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LjyqT34OedPJiOdIrDw%2F-LmvTfhKwMHzvDz9duQT%2F-LmvTvp89E8P4R2ThSe7%2F23.png?generation=1566513613389464\&alt=media)

Нажимаем правую кнопку мыши, выбираем INTELLIDUMP, а затем – DUMP FULL.

![](https://416819976-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LjyqT34OedPJiOdIrDw%2F-LmvTfhKwMHzvDz9duQT%2F-LmvTvpNzTnHXbGLbRMm%2F24.png?generation=1566513599358832\&alt=media)

Дамп сохраняется под именем DUMPED.exe.

![](https://416819976-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LjyqT34OedPJiOdIrDw%2F-LmvTfhKwMHzvDz9duQT%2F-LmvTvpas2YGvdezBOvD%2F25.png?generation=1566513624717134\&alt=media)

Если попробуем запустить его, то увидим, что происходит ошибка. Открываем дамп в OllyDbg.

Посмотрим, какие ошибки показываются в LOG’е OllyDbg.

![](https://416819976-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LjyqT34OedPJiOdIrDw%2F-LmvTfhKwMHzvDz9duQT%2F-LmvTvpmJAmccuYvL1TY%2F26.png?generation=1566513587268532\&alt=media)

Ошибка происходит в 7c929913 на моей машине. Идём по этому адресу (у вас он может быть другим, поэтому надо смотреть в LOG’е).

![](https://416819976-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LjyqT34OedPJiOdIrDw%2F-LmvTfhKwMHzvDz9duQT%2F-LmvTvpvYoCeEv1idbkt%2F27.png?generation=1566513656256947\&alt=media)

Устанавливаем здесь HARDWARE BREAKPINT ON EXECUTION и BP, что увидеть, что происходит до возникновения ошибки.

Ок, видим, что останова не произошло, но зато случается другая ошибка из-за исключения. Рестартуем:

![](https://416819976-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LjyqT34OedPJiOdIrDw%2F-LmvTfhKwMHzvDz9duQT%2F-LmvTvq4MZmZGwhRHLKW%2F28.png?generation=1566513627585648\&alt=media)

Видим, что останавливаемся до прибытия в точку входа из за ошибки.

Раз уж мы оказались здесь, смотрим, что находится в IAT.

![](https://416819976-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LjyqT34OedPJiOdIrDw%2F-LmvTfhKwMHzvDz9duQT%2F-LmvTvqByIcrh51A_Atj%2F29.png?generation=1566513627298411\&alt=media)

Видим, что дампер сохранил значения, которые были в IAT на момент прибытия в OEP, и они являются правильными на моей машине, но для того, чтобы exe-файл запускался на любой машине, там должен быть сохранён указатель на строки с именами API-функций, а так как система не может их найти, то и происходит ошибка.

Не нужно быть гением, чтобы понять, что для того, чтобы программа запустилась, нужно восстановить имена API-функций, и указатели на них. Если делать это вручную, то это адская прорва работы: нужно было бы заменить содержимое 4031AC на указатель на строку MessageBoxA, и так со всеми.

Итак, нам брошен вызов: кроме того, что нам нужно было получить правильный дамп, нам ещё нужно починить его, чтобы он запускался.

Так как у нас правильный код, то без всяких сомнений идём в 401000, и смотрим, что там находится.

![](https://416819976-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LjyqT34OedPJiOdIrDw%2F-LmvTfhKwMHzvDz9duQT%2F-LmvTvqMXA7ggbnMHW3h%2F30.png?generation=1566513599190804\&alt=media)

Если переместимся в зону переходов на API-функции:

Здесь находится вызов MessageBoxA, уже виденный нами ранее.

![](https://416819976-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LjyqT34OedPJiOdIrDw%2F-LmvTfhKwMHzvDz9duQT%2F-LmvTvqZY1QYDKXTl3jb%2F31.png?generation=1566513653046140\&alt=media)

В вызове стоит правильный адрес, переходим на тот же JUMP, что и раньше.

![](https://416819976-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LjyqT34OedPJiOdIrDw%2F-LmvTfhKwMHzvDz9duQT%2F-LmvTvqih-lJVQp0ezoS%2F32.png?generation=1566513599038579\&alt=media)

JUMP’ы являются тем, что может не работать, так как в нормальных условиях система должна заполнить IAT правильными значениями, основываясь на указателях на строки с названиями функций, которые должны быть здесь до старта программы.

Прежде, чем заняться данной областью, посмотрим правильные определения и их расположение в исходной программе с не упаковонными IAT и IT.

Откроем оригинальный CC в OllyDbg.

![](https://416819976-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LjyqT34OedPJiOdIrDw%2F-LmvTfhKwMHzvDz9duQT%2F-LmvTvqu26EBOVLG2JKN%2F33.png?generation=1566513609321613\&alt=media)

Ок, находим нужные нам части, которые должны нормально работать в исходном файле.

В заголовке находим несколько важных указателей.

Идём туда же.

![](https://416819976-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LjyqT34OedPJiOdIrDw%2F-LmvTfhKwMHzvDz9duQT%2F-LmvTvr5Nu9la2gcmKwC%2F34.png?generation=1566513637946656\&alt=media)

![](https://416819976-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LjyqT34OedPJiOdIrDw%2F-LmvTfhKwMHzvDz9duQT%2F-LmvTvrFX3gEVY9p54Eh%2F35.png?generation=1566513658446781\&alt=media)

Меняем режим SPECIAL-PE HEADER.

![](https://416819976-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LjyqT34OedPJiOdIrDw%2F-LmvTfhKwMHzvDz9duQT%2F-LmvTvrTtwo2HkWyuFRp%2F36.png?generation=1566513604220974\&alt=media)

Спускаемся.

![](https://416819976-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LjyqT34OedPJiOdIrDw%2F-LmvTfhKwMHzvDz9duQT%2F-LmvTvreBNs7LVTw0T06%2F37.png?generation=1566513580345431\&alt=media)

Реальные данные идут с 100, где начинается PE SIGNATURE.

![](https://416819976-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LjyqT34OedPJiOdIrDw%2F-LmvTfhKwMHzvDz9duQT%2F-LmvTvrqNw0X7_yM6BMZ%2F38.png?generation=1566513581666766\&alt=media)

"Начинается со 100" - это значит, что начинается в 400100.

![](https://416819976-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LjyqT34OedPJiOdIrDw%2F-LmvTfhKwMHzvDz9duQT%2F-LmvTvs0_XwLM1kfWuYJ%2F39.png?generation=1566513637444908\&alt=media)

Здесь находится указатель на IT, то есть таблицу импорта, которую не надо путать с IAT

* IT = IMPORT TABLE
* IAT = IMPORT ADDRESS TABLE

Как видим, IAT – это хранилище, где система сохраняет после запуска правильные для моей машины адреса. А что такое IT? Идём туда. Как видим, она начинается с 3000 (403000), и её размер 670, то есть заканчивается в 403670. Смотрим, что там.

Поскольку мы ушли из заголовка, выходим из MODE SPECIAL-PE HEADER.

![](https://416819976-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LjyqT34OedPJiOdIrDw%2F-LmvTfhKwMHzvDz9duQT%2F-LmvTvsEH4fZvq4UkXjh%2F40.png?generation=1566513581591697\&alt=media)

Это знаменитая IT, она у нас в руках, если мы поймём её, и хотя мы не знаем номер каждого из указателей, мы знаем, чем является каждый из элементов и куда указывает. Тогда мы спасены.

Плохо то, что приходится объяснять это в OllyDbg, так как гораздо удобнее и нагляднее делать это, представив IT в виде 5 колонок.

Знаменитая IT состоит из так называемых IMAGE IMPORT DESCRIPTOR’ов, являющиеся строками из 5 dword-значений, по одному дескриптору на каждую из загружающихся с программой DLL-библиотек.

Смотрим IT, помним, что каждый элемент (IID) занимает 5 колонок.

Рассмотрим пример.

![](https://416819976-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LjyqT34OedPJiOdIrDw%2F-LmvTfhKwMHzvDz9duQT%2F-LmvTvsRl9JemRqC6npu%2F41.png?generation=1566513601318322\&alt=media)

Это первый IID нашей IT, в котором 5 DWORD’ов, означающих следующее:

* OriginalFirtsThunks
* TimeDateStamp
* ForwarderChain
* Указатель на имя DLL
* FirtsThunk (Указывает туда, где должен производиться в IAT поиск первого вхождения данной DLL)

Три первых обычно не слишком важны для крэкинга, нас интересуют указатели 4 и 5.

![](https://416819976-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LjyqT34OedPJiOdIrDw%2F-LmvTfhKwMHzvDz9duQT%2F-LmvTvsdBBZhYaNks9FE%2F42.png?generation=1566513581094629\&alt=media)

Как видим, 4-ый указывает на имя DLL, которой соответствует данный IID, по адресу 403290 смотрим, что это за DLL.

![](https://416819976-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LjyqT34OedPJiOdIrDw%2F-LmvTfhKwMHzvDz9duQT%2F-LmvTvsqzT0Eqw1vAJ7t%2F43.png?generation=1566513613751560\&alt=media)

Здесь у нас первая DLL, которую будет искать система – это USER32.DLL. 5 dword – это указатель, на вхождения этой DLL в IAT, в данном случае это 403184.

![](https://416819976-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LjyqT34OedPJiOdIrDw%2F-LmvTfhKwMHzvDz9duQT%2F-LmvTvt3oq0u9wVvlto8%2F44.png?generation=1566513581532227\&alt=media)

Вот IAT и её первый элемент, всё внутри IT, которая заканчивается в 403670. Таким образом, каждой DLL в IT соответствует один элемент, называющийся IID или IMAGE IMPORT DESCRIPTOR, а внутри IT находится IAT, то есть хранилище адресов API-функций, всё в компактном виде, готовое для использования системой.

Многие крэкеры, экспериментировавшие с IAT, говорят, что IAT не всегда находится внутри IT, так как указатель на IID может указывать куда угодно, поэтому тот может располагаться в любом месте программа, куда есть разрешение на запись, чтобы при запуске exe-файла, программа могла сохранить правильные адреса API-функций, но тем не менее, общая последовательность того, что система делает для заполнения IAT, является следующий:

1. Ищет IT
2. Ищет первый IID и устанавливает, к какой DLL относится 4-ый указатель.
3. Затем смотрит пятый указатель, чтобы выяснить, где располагается первый элемент IAT
4. Там находится указатель на строку с именем API-функции.
5. С помощью GetProcAddress ищется адрес и сохраняется в том же элементе.
6. Когда в IAT встречается элемент с нулям, это означает, что первая DLL закончилась, и теперь нужно смотреть второй IID, чтобы найти, где располагается информация о второй, и повторить процесс.

Таким образом, важно хорошо понимать, что делает система, и что произойдёт, если она встретит неправильные указатели.

Ищем адрес в IT

![](https://416819976-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LjyqT34OedPJiOdIrDw%2F-LmvTfhKwMHzvDz9duQT%2F-LmvTvtIHbMPHwkRHPig%2F45.png?generation=1566513579208213\&alt=media)

Идём по этом адресу

![](https://416819976-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LjyqT34OedPJiOdIrDw%2F-LmvTfhKwMHzvDz9duQT%2F-LmvTvtWRD_BgqsiL9hy%2F46.png?generation=1566513639937636\&alt=media)

В первой IID ищем 4-ый DWORD, который указывает на имя DLL, в данном случае это USER32.DLL.

![](https://416819976-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LjyqT34OedPJiOdIrDw%2F-LmvTfhKwMHzvDz9duQT%2F-LmvTvtjAdpk2iW0nN7v%2F47.png?generation=1566513609266496\&alt=media)

Затем смотрим содержимое 5-ого указателя, чтобы найти первый элемент IAT. Он равен 403184. Идём туда.

![](https://416819976-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LjyqT34OedPJiOdIrDw%2F-LmvTfhKwMHzvDz9duQT%2F-LmvTvtu0pYU-g09RyPS%2F48.png?generation=1566513632634993\&alt=media)

![](https://416819976-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LjyqT34OedPJiOdIrDw%2F-LmvTfhKwMHzvDz9duQT%2F-LmvTvu37GV_Z-Xbz9BW%2F49.png?generation=1566513636605694\&alt=media)

Здесь читаем значение и смотрим, на что оно указывает.

![](https://416819976-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LjyqT34OedPJiOdIrDw%2F-LmvTfhKwMHzvDz9duQT%2F-LmvTvuGYfVfY0BVw95X%2F50.png?generation=1566513629810499\&alt=media)

Это имя первой API-функции, оно располагается в 4032CC, идём туда.

![](https://416819976-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LjyqT34OedPJiOdIrDw%2F-LmvTfhKwMHzvDz9duQT%2F-LmvTvuTa5ky1lDgFeLr%2F51.png?generation=1566513581349059\&alt=media)

Видим, что первая API-функция – это KillTimer, её адрес находится с помощью GetProcAddress, мы можем сделать это с помощью OllyDbg.

![](https://416819976-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LjyqT34OedPJiOdIrDw%2F-LmvTfhKwMHzvDz9duQT%2F-LmvTvugTLM4yCDqmVd_%2F52.png?generation=1566513581403236\&alt=media)

И это значение, которое на моей машине равно 77d18c42, сохраняется в тот же элемент IAT, перезаписывая его предыдущее значение.

![](https://416819976-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LjyqT34OedPJiOdIrDw%2F-LmvTfhKwMHzvDz9duQT%2F-LmvTvutx5v2_26wr35I%2F53.png?generation=1566513580097990\&alt=media)

То, что мы здесь видим – это первый элемент IAT, и значение, которое оно содержит на моей машине.

Затем переходим к следующему элементу IAT, который легко найти, прибавив 4 к адресу предыдущего, и находим указатель на имя следующей API-функции.

![](https://416819976-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LjyqT34OedPJiOdIrDw%2F-LmvTfhKwMHzvDz9duQT%2F-LmvTvv5n19fetWzPRYE%2F54.png?generation=1566513581172913\&alt=media)

Конечно, смотрим исполняемый файл и вот оно:

![](https://416819976-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LjyqT34OedPJiOdIrDw%2F-LmvTfhKwMHzvDz9duQT%2F-LmvTvvKZfQZarh9DhNo%2F55.png?generation=1566513601350765\&alt=media)

32d8, то есть 4032d8, смотрим имя следующей API-функции по этому адресу, и так как в этом элементе нет ноля, это означает, что продолжается список функций user32.dll.

![](https://416819976-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LjyqT34OedPJiOdIrDw%2F-LmvTfhKwMHzvDz9duQT%2F-LmvTvvYXI1CNRgLLO0K%2F56.png?generation=1566513635758073\&alt=media)

Вторая API-функция – это GetSystemMetrics, её адрес будет найдён и сохранён во второй элемент IAT, и так будут находиться все API-функции библиотеки user32.dll, пока не будет обнаружен элемент, в котором содержатся все нули. Посмотрим, где он находится в исполняемом файле.

![](https://416819976-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LjyqT34OedPJiOdIrDw%2F-LmvTfhKwMHzvDz9duQT%2F-LmvTvvk9u-bG208PYdX%2F57.png?generation=1566513601334276\&alt=media)

Видим, что поиск в IT user32.dll будет продолжаться, пока не найдётся вот этот элемент с нулями, после чего произойдёт переход к следующему IID.

![](https://416819976-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LjyqT34OedPJiOdIrDw%2F-LmvTfhKwMHzvDz9duQT%2F-LmvTvvynVbjzNVVW1sq%2F58.png?generation=1566513601264295\&alt=media)

Вот 4-ый и 5-ый указатели, 4-ый говорит нам, что в 40329b находится имя 2-ой dll, где будет происходить поиск функций.

![](https://416819976-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LjyqT34OedPJiOdIrDw%2F-LmvTfhKwMHzvDz9duQT%2F-LmvTvw7UZ1WZPJrXKR3%2F59.png?generation=1566513609658920\&alt=media)

Это kernel32.dll, и первый элемент её IAT находится после элемента с нулями, т.е. начиная с адреса 40321c.

![](https://416819976-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LjyqT34OedPJiOdIrDw%2F-LmvTfhKwMHzvDz9duQT%2F-LmvTvwKkDrHVf_ub81K%2F60.png?generation=1566513578304817\&alt=media)

Здесь видим ноль, который задаёт конец API-функций из user32.dll, и в 40321c начинается IAT Kernel32.dll, где будут искаться указатели на имена функций и которая будет заполнена их реальными адресами.

Думаю, что очень важно понимать этот процесс, я попытался объяснить его и повторить это несколько раза, чтобы вы хорошо поняли его, так как это основа всей темы реконструкции IAT, и хотя мы рассмотрим в следующей части соответствующие инструменты, которые могут нам помочь сделать рутинную работу за нас, очень важно знать, как они работаю, чтобы в случае каких-либо проблем мы не сошли с дистанции и всегда могли понять, почему это произошло.

Ок, на этот раз достаточно, в следующей главе мы приведём IAT в порядок.

\[C] Рикардо Нарваха, пер. Aquila
