Введение в крэкинг с нуля, используя OllyDbg - Глава 33

  • На форуме работает ручное одобрение пользователей. Это значит, что, если Ваша причина регистрации не соответствует тематике форума, а также Вы используете временную почту, Ваша учётная запись будет отклонена без возможности повторной регистрации. В дальнейшем - пожизненная блокировка обоих аккаунтов за создание мультиаккаунта.
  • Мы обновили Tor зеркало до v3!
    Для входа используйте следующий url: darkv3nw2...bzad.onion/
  • Мы вновь вернули telegram чат форуму, вступайте, общайтесь, задавайте любые вопросы как администрации, так и пользователям!
    Ссылка: https://t.me/chat_dark_time

AnGel

Администратор
Команда форума

AnGel

Администратор
Команда форума
27 Авг 2015
3,411
2,025
Что такое IAT, и как её починить

Перед тем, как начинать, как безумные, чинить IAT’ы, необходимо введение в то, что такое вообще IAT. Мы рассмотрим на примере оригинального крэкми CrueHead’а и упакованного варианта, где располагается IAT и что делает с ним упаковщик.

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

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

48a4167a44f22d3d906f67b3db922e4d.png

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

268b20cdca4a0e87bc67db37c092ba17.png

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

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

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

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

5741a17b4ddf5fb9574297406c7edbf1.png

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

812f5799d0b58fd90b28d687bd85f063.png

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

58be575b9ce36461705a76f209beaf4d.png

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

CALL 40143A

153d44c5a0877b387489a73a44592463.png

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

d2f697ca6b197bdb352aea98c1e4fb9c.png

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

CALL 40143A

В SEARCH FOR INTERMODULARS CALLS

4cf80d09797212ce247f109c8b992101.png

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

ea436cb9e8c2fec659b9f68512c675b5.png

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

JMP [4031AC]

f23cd75f2086570528e09aa6fac9a2cb.png

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

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

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

3b13a2546ceed93004a8447bece815cf.png

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

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

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

f8a1f34a3bf4a2b9aa3aa2b95eaf93cc.png

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

0deebab1250d165c946996ffabc7af8e.png

Видим, что в 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, и что мы найдём по этому адресу?

37324874dc98ce0f5a70c22956115c6e.png

Вот в чём дело, это указатель на строку 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’ом, отличие от нормального исполняемого файла.

7036f94bdcdc890d247f9c43cfd60b8d.png

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

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

3c11489bf79616af4a7f36bdfb2099d1.png

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

304e01053560b09e3fe63688e1e8b456.png

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

JMP [4031ac]

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

e19333629fe4b014f98a6490f232922a.png

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

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

4162a5e6da86175f465c2f74691e8bf8.png

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

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

9c982bd18d7eae1158098f1f78582274.png

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

Для того, чтобы сделать дамп, будем использовать внешнюю программу, которая называется LORDPE DELUXE. Её можно скачать
Пожалуйста, Вход или Регистрация для просмотра содержимого URL-адресов!
.

6d855dd28a1910a40509b37aef32b4fc.png

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

10777645dc7718adf93af139177c5ec8.png

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

157b1b38c551605618aa39e483bba5e8.png

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

9d77884c52915a9557941f06af01ae4b.png

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

233cf78fe37a7c0426e4a010e3e1a6b0.png

Si corremos el dumpeado vemos que no arranca tratemos de abrirlo en OLLYDBG

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

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

6040684c68146309e4ea1da2a5a18edc.png

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

d6dd84d815e762184c47bfec74eeba91.png

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

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

92c08e8587ca118e1e563b64cbd397ae.png

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

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

cd66ed52278210b1ffcdebb4c4ec97b5.png

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

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

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

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

39bcd2d05880c05647eb0dfa0ae7ec98.png

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

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

11379088f23def64c18c80a2a740f99f.png

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

1fea35b467d6f0fff13ad82f7bdb9897.png

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

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

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

f5422da0b0ab7a4833a0d0906002fbf5.png

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

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

Идём туда же.

4ec85df0409638133cf31bfc926f8643.png

d01887105324d9b8dbb10c70a0d2448d.png

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

3d93876271e3ee304e65b8656516cf0c.png

Спускаемся.

78d30ba8702182723063a0b3806c2e2a.png

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

18ea3f5e37fef6376f567bba4eebc921.png

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

cbcef62d189b1b26c6cf5da0dbe9884f.png

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

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

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

05a8a95269025fcf4d9205e8a468b43e.png

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

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

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

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

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

07b22ef0440871122b77f64d51ebaaf1.png

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

  • OriginalFirtsThunks
  • TimeDateStamp
  • ForwarderChain
  • Указатель на имя DLL
  • FirtsThunk (Указывает туда, где должен производиться в IAT поиск первого вхождения данной DLL)
Три первых обычно не слишком важны для крэкинга, нас интересуют указатели 4 и 5.
09e4285e0dd50ca02de8d989bf6112f6.png

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

52d5673b1ca72cf564d5ca29dcd03061.png

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

ff72b5175ab3dbf0085700f6489d7276.png

Вот 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, чтобы найти, где располагается информация о второй, и повторить процесс.
Таким образом, важно хорошо понимать, что делает система, и что произойдёт, если она встретит неправильные указатели.

1) Ищем адрес в IT

308bbc33cc63abe5f645e50199f61f35.png

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

72e21b3c2c768806cb278ad89004bf33.png

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

6a4e8ad36f64fcdb505e4e130ddb5f69.png

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

ce1e7f422dcc1aca1a17d0b22c6cbc24.png

7ea2ca23d2c45eb517c1baaab0327a5a.png

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

50d612999bf3b986f52c17fc8e125e42.png

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

521db8a55ea807b728af595d7aa9f5ca.png

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

3fe44f800cb01e870fea96b8a55faa47.png

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

2bac5c01091f4a7e83d76f166f591a6d.png

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

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

a3b2c48563007936b5730fca6081d14e.png

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

2022429d4d1e9477b8e466b7d7b773d9.png

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

a34e2522b931658c578c05005f41a219.png

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

49026301e8826015f8df200856bd58f5.png

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

71a370666473ed47d8198e538f01c369.png

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

71f63b384932e3f8001b664354163cd8.png

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

91a851b4263a7579f924c460b2db70f3.png

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

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

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

О нас

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

    Dark-Time 2015 - 2022

    При поддержке: XenForo.Info

Быстрая навигация

Меню пользователя