# Глава 33

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

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

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

![](https://2931627293-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnwCNY88kcGMCQxNdy6%2Fuploads%2Fgit-blob-492a993394d6290df08ca33ed2af89a8fac7a77f%2F1.png?alt=media)

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

![](https://2931627293-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnwCNY88kcGMCQxNdy6%2Fuploads%2Fgit-blob-6490e83a2fa577de973e9dc24f20d59a419c9208%2F2.png?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://2931627293-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnwCNY88kcGMCQxNdy6%2Fuploads%2Fgit-blob-bf7bb645c40a748a5a0f411e110e3b9479c41e4f%2F3.png?alt=media)

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

![](https://2931627293-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnwCNY88kcGMCQxNdy6%2Fuploads%2Fgit-blob-c9174f2cebd27e0f0358a5a2fa01302c0c036847%2F4.png?alt=media)

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

![](https://2931627293-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnwCNY88kcGMCQxNdy6%2Fuploads%2Fgit-blob-ec88a8d8f3ff42f6f0350086df33d08c4ea20e04%2F5.png?alt=media)

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

`CALL 40143A`

![](https://2931627293-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnwCNY88kcGMCQxNdy6%2Fuploads%2Fgit-blob-4e7797684ae574238a52eeeee4fb9c7aab6b074f%2F6.png?alt=media)

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

![](https://2931627293-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnwCNY88kcGMCQxNdy6%2Fuploads%2Fgit-blob-d856d25fdc677d3074af765069f89345fc73a7ce%2F7.png?alt=media)

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

`CALL 40143A`

В SEARCH FOR INTERMODULARS CALLS

![](https://2931627293-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnwCNY88kcGMCQxNdy6%2Fuploads%2Fgit-blob-9bd012296083fba663f62befe25e75c49eef74c1%2F8.png?alt=media)

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

![](https://2931627293-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnwCNY88kcGMCQxNdy6%2Fuploads%2Fgit-blob-4cc2235808bae7dd6eaa81e421beacff20a18076%2F9.png?alt=media)

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

`JMP [4031AC]`

![](https://2931627293-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnwCNY88kcGMCQxNdy6%2Fuploads%2Fgit-blob-c2869786a49405959d72638f1f5d7981f00e12af%2F10.png?alt=media)

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

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

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

![](https://2931627293-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnwCNY88kcGMCQxNdy6%2Fuploads%2Fgit-blob-5ab037d79754cd6e43d94a2142d785ce95af9018%2F11.png?alt=media)

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

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

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

![](https://2931627293-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnwCNY88kcGMCQxNdy6%2Fuploads%2Fgit-blob-e2f61f884ac8b31ba207494ab42e825b8133b699%2F12.png?alt=media)

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

![](https://2931627293-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnwCNY88kcGMCQxNdy6%2Fuploads%2Fgit-blob-0e0d6a89552d60510de66c3ea45e2984445c0ae1%2F13.png?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://2931627293-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnwCNY88kcGMCQxNdy6%2Fuploads%2Fgit-blob-28675eac58a060e12a7df8f9c9b5965fe6ef3b31%2F14.png?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://2931627293-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnwCNY88kcGMCQxNdy6%2Fuploads%2Fgit-blob-37b5e4e8d13112da3746993a559d1a241cbfabb8%2F15.png?alt=media)

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

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

![](https://2931627293-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnwCNY88kcGMCQxNdy6%2Fuploads%2Fgit-blob-ca760a3a3742e2fed8d00ee012ff9c09afef60fd%2F16.png?alt=media)

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

![](https://2931627293-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnwCNY88kcGMCQxNdy6%2Fuploads%2Fgit-blob-10355b3f5d7ee007f58881cb7f33d844e6fa316d%2F17.png?alt=media)

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

`JMP [4031ac]`

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

![](https://2931627293-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnwCNY88kcGMCQxNdy6%2Fuploads%2Fgit-blob-d1066a3886b141d19dc60b5dee62632612fdf8e7%2F18.png?alt=media)

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

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

![](https://2931627293-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnwCNY88kcGMCQxNdy6%2Fuploads%2Fgit-blob-319632b343cca990fa685b2d1dfd1a6768715325%2F19.png?alt=media)

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

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

![](https://2931627293-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnwCNY88kcGMCQxNdy6%2Fuploads%2Fgit-blob-6f535f585b137273fe183843dd652c30ad41be19%2F20.png?alt=media)

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

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

![](https://2931627293-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnwCNY88kcGMCQxNdy6%2Fuploads%2Fgit-blob-4236f727101eb08c77523d017b1d2ec29a34083d%2F21.png?alt=media)

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

![](https://2931627293-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnwCNY88kcGMCQxNdy6%2Fuploads%2Fgit-blob-034d8de7499affa91a40b4dd997bce57c710331d%2F22.png?alt=media)

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

![](https://2931627293-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnwCNY88kcGMCQxNdy6%2Fuploads%2Fgit-blob-f12032b7e6dc4d1012749951e6e968d221d8540a%2F23.png?alt=media)

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

![](https://2931627293-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnwCNY88kcGMCQxNdy6%2Fuploads%2Fgit-blob-3abf4329d6ae7f2c3c5186928d670c3547975745%2F24.png?alt=media)

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

![](https://2931627293-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnwCNY88kcGMCQxNdy6%2Fuploads%2Fgit-blob-02308fc0379720d8acedc796e2cabf4e9dffaa11%2F25.png?alt=media)

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

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

![](https://2931627293-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnwCNY88kcGMCQxNdy6%2Fuploads%2Fgit-blob-31da9b38779d0be273ff72d8c7b7837b3e07be65%2F26.png?alt=media)

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

![](https://2931627293-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnwCNY88kcGMCQxNdy6%2Fuploads%2Fgit-blob-ffdcb638b046bb9319658b94e4c2df2f9ba6845b%2F27.png?alt=media)

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

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

![](https://2931627293-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnwCNY88kcGMCQxNdy6%2Fuploads%2Fgit-blob-fca3c3f01464ea06ac4a3c8f531916e4af197c32%2F28.png?alt=media)

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

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

![](https://2931627293-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnwCNY88kcGMCQxNdy6%2Fuploads%2Fgit-blob-ff0130fea759acabeaf88dc7f5f7a1a8392c36ce%2F29.png?alt=media)

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

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

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

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

![](https://2931627293-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnwCNY88kcGMCQxNdy6%2Fuploads%2Fgit-blob-d27b4210e0245138d11f7f8f8289d598eba76d58%2F30.png?alt=media)

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

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

![](https://2931627293-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnwCNY88kcGMCQxNdy6%2Fuploads%2Fgit-blob-df5d269ab1cc0d5e6a8264a5f24b9b9f966f466c%2F31.png?alt=media)

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

![](https://2931627293-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnwCNY88kcGMCQxNdy6%2Fuploads%2Fgit-blob-76f76e1e77001d57fc71c423f845c0e1194fdb7d%2F32.png?alt=media)

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

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

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

![](https://2931627293-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnwCNY88kcGMCQxNdy6%2Fuploads%2Fgit-blob-1fb7a9153253a354b29ae030b6b2d8efb043a9fa%2F33.png?alt=media)

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

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

Идём туда же.

![](https://2931627293-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnwCNY88kcGMCQxNdy6%2Fuploads%2Fgit-blob-a0d9891b1fd6b853091a9cf42388d66ca52f83c3%2F34.png?alt=media)

![](https://2931627293-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnwCNY88kcGMCQxNdy6%2Fuploads%2Fgit-blob-b31bd4c168476887883846b5a0f860cb693ec856%2F35.png?alt=media)

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

![](https://2931627293-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnwCNY88kcGMCQxNdy6%2Fuploads%2Fgit-blob-6c18cebe821e4634d76e9f126107f25098a9010c%2F36.png?alt=media)

Спускаемся.

![](https://2931627293-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnwCNY88kcGMCQxNdy6%2Fuploads%2Fgit-blob-eb667e61256000008961c83997de21d103da545d%2F37.png?alt=media)

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

![](https://2931627293-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnwCNY88kcGMCQxNdy6%2Fuploads%2Fgit-blob-65df7bb46120c314938c2e4137d99c306df2ed26%2F38.png?alt=media)

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

![](https://2931627293-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnwCNY88kcGMCQxNdy6%2Fuploads%2Fgit-blob-0143c55ebc2dd053ccc0c0803478c1351ab505a2%2F39.png?alt=media)

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

* IT = IMPORT TABLE
* IAT = IMPORT ADDRESS TABLE

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

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

![](https://2931627293-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnwCNY88kcGMCQxNdy6%2Fuploads%2Fgit-blob-75a58b0ddc514cf6bd9698c109532f5d1a577e65%2F40.png?alt=media)

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

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

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

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

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

![](https://2931627293-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnwCNY88kcGMCQxNdy6%2Fuploads%2Fgit-blob-7a1f77d878e00aae9ffc2badf0ad228fbe69d283%2F41.png?alt=media)

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

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

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

![](https://2931627293-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnwCNY88kcGMCQxNdy6%2Fuploads%2Fgit-blob-683f440e6c5780453dd602f6563c193e397f24f6%2F42.png?alt=media)

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

![](https://2931627293-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnwCNY88kcGMCQxNdy6%2Fuploads%2Fgit-blob-76a314522b45bdf931e0e9bda4934b57a8c45418%2F43.png?alt=media)

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

![](https://2931627293-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnwCNY88kcGMCQxNdy6%2Fuploads%2Fgit-blob-791cc21d0540f7d5bce8f67a21cfe9064fddbf77%2F44.png?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://2931627293-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnwCNY88kcGMCQxNdy6%2Fuploads%2Fgit-blob-ecf3d3cd32bfa71140195e153dc431834acd61fd%2F45.png?alt=media)

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

![](https://2931627293-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnwCNY88kcGMCQxNdy6%2Fuploads%2Fgit-blob-b9f617ab1c4aae6f28e66b85fb87aafea7b99d63%2F46.png?alt=media)

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

![](https://2931627293-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnwCNY88kcGMCQxNdy6%2Fuploads%2Fgit-blob-737139aea9cb1a9b8a798cb69449c047428c5d53%2F47.png?alt=media)

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

![](https://2931627293-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnwCNY88kcGMCQxNdy6%2Fuploads%2Fgit-blob-5f388fe760d018add30958a710a61b24b18d7935%2F48.png?alt=media)

![](https://2931627293-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnwCNY88kcGMCQxNdy6%2Fuploads%2Fgit-blob-81644074fe5c0ed636da4d248c9ba65354104cee%2F49.png?alt=media)

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

![](https://2931627293-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnwCNY88kcGMCQxNdy6%2Fuploads%2Fgit-blob-7c39decc57f4c8765990f4966728ceaa57ff5378%2F50.png?alt=media)

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

![](https://2931627293-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnwCNY88kcGMCQxNdy6%2Fuploads%2Fgit-blob-98f744b72a0cc7789a93649e72a718f938e74f2d%2F51.png?alt=media)

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

![](https://2931627293-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnwCNY88kcGMCQxNdy6%2Fuploads%2Fgit-blob-beea2273e1edb5eff594914830c2cb308e956104%2F52.png?alt=media)

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

![](https://2931627293-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnwCNY88kcGMCQxNdy6%2Fuploads%2Fgit-blob-600721b1a2919bab260158df4c1bef9b4230b801%2F53.png?alt=media)

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

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

![](https://2931627293-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnwCNY88kcGMCQxNdy6%2Fuploads%2Fgit-blob-3eabb260ddc7033128e75f829211b1f81896eab7%2F54.png?alt=media)

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

![](https://2931627293-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnwCNY88kcGMCQxNdy6%2Fuploads%2Fgit-blob-9cacf23e7807f5bf07d2aa5f84c4b22484c583d6%2F55.png?alt=media)

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

![](https://2931627293-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnwCNY88kcGMCQxNdy6%2Fuploads%2Fgit-blob-cb9899120ad4dc148030b34acf36b89a4eae21f5%2F56.png?alt=media)

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

![](https://2931627293-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnwCNY88kcGMCQxNdy6%2Fuploads%2Fgit-blob-f294f85f5e4989e8184ab3c6e84fde1fa599cc72%2F57.png?alt=media)

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

![](https://2931627293-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnwCNY88kcGMCQxNdy6%2Fuploads%2Fgit-blob-8abbe6a34bad2dcb2e7127d6e4d0d874bf46b6c9%2F58.png?alt=media)

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

![](https://2931627293-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnwCNY88kcGMCQxNdy6%2Fuploads%2Fgit-blob-05998c7310a7ec0d59a58f150d1ea948c5df1c4a%2F59.png?alt=media)

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

![](https://2931627293-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnwCNY88kcGMCQxNdy6%2Fuploads%2Fgit-blob-ab6347b250d57b210a10f4413e04d8dc81cf8908%2F60.png?alt=media)

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

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

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

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