Введение в реверсинг с нуля используя IDA PRO. Часть 9

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

AnGel

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

AnGel

Администратор
Команда форума
27 Авг 2015
3,411
2,025
Мы разбираемся понемногу как нужно работать с ЗАГРУЗЧИКОМ, мы оставили некоторые вещи на потом, чтобы наблюдать за ними позже в ОТЛАДЧИКЕ, например, как меняются флаги в зависимости от используемых инструкций.

Мы будем практиковаться на очень простых примерах, в нашем случае это очень простые крэкми, которые скомпилированы в VISUAL STUDIO 2015для нашей практики. Очевидно, для того, чтобы крэкми заработал, у Вас должны быть установлены последние версия библиотек VISUAL STUDIO 2015 C++.

Пожалуйста, Вход или Регистрация для просмотра содержимого URL-адресов!


Пакеты Visual C++ Redistributable устанавливают компоненты среды выполнения, которые необходимы для запуска приложений написанных на языке C++ и скомпилированные в Visual Studio 2015.

Выберите нужный для своей операционной системы пакет, согласно вашему языку, загрузите и установите библиотеки.

Присоединенный файл - это исполняемый файл, который называется HOLA_REVERSER.EXE и который запускается под WINDOWS 7.

6f4e4381fe913bb829b8ee50bd2980ed._.png

При вводе номера крэкми будет говорить, насколько я хороший или плохой реверсер.

c0144845f4e63cce84fac57c60f74b79._.png

Мы видим, что это очень простой крэкми, если я открою его в IDA и только в ЗАГРУЗЧИКЕ без отладчика, увидим следующее.

В моём случае (не в Вашем) функция MAIN появляется среди других функций, поэтому я могу найти её с помощью комбинации CTRL + F здесь на этой вкладке или там, где у меня открыта вкладка с функциями, но это происходит, потому что я скомпилировал программу с помощью VISUAL STUDIO и создал PDB файл с символами, который обнаруживает IDA и загружает оттуда имена функций и имена переменных, мы видим, что в моём листинге равно как и в моём исходном коде, появляется функция MAIN, а ниже функция PRINTF, мы будем смотреть, что будет происходить в Вашем случае.

658c427cb251fa6c656b1da595dfff9b._.png

В Вашем случае, IDA не скажет, что это за функция, потому что у IDA'Ы нет символов.

Вероятно, это потому, что никто не распространяет программу с символами.

255bf31051053218ccfedf6bfcccb337._.png

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

Мы видим, что здесь у нас нет символов.

9f860d976d17472fbc759edc6e6a54e0._.png

Мы имеем очень мало информации, но хорошо то, что мы можем видеть строки.

961e1cc904775f2980e5c3157a3ec59d._.png

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

Мы можем сделать двойной щелчок на строке “Pone un numerito\n”.

b3c0b5317f2cee08bd7815ae3135ee21._.png

Здесь мы видим, что 0x402108 это адрес строки, а рядом с адресом мы видим ТЭГ, который помещен рядом и всегда начинается с буквы “a” если это строка ASCII, а оставшиеся символы принадлежат к той же строки, поэтому её очень легко распознать, в нашем случае тэг называется aPoneUnNumerito, а затем идут символы DB, потому что строка - это последовательность байт.

Строку можно рассыпать на байты с помощью клавиши D, теперь мы видим те же самые символы только по вертикали и по одному.

49902aa076b9f129efc1e23ffb9fc1cc._.png

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

9cdd6b9383f47420d0674f2addfe8a00._.png

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

a2353deb796260bd6f7050d9023a89e2._.png

Хорошо, мы находимся в главной функции, здесь она не называется главной, хотя имя буфера, который является общим помечен как BUF.

efd95d0cdf6b9c862c77749ca18639f8._.png

Предполагается, что мы не знаем исходный код программы, но я Вам его покажу.

74290feb0e6e1285326da9fb94d85c5c._.png

Я понимаю, что переменные, которые Вы создаете, становятся оптимизированными, например такие как COOKIE и MAX, которые заменены константами и остаётся только мой буфер, который в моём коде составлял 120 байт в десятичной системе.

Буфер - это пространство памяти зарезервированное, чтобы хранить данные, в нашем случае резервируется 120 байтов.

Как мы можем узнать в IDA размер буфера в стеке, если у нас нет исходного кода?

9abeadb4e3e1980a4aabb11eecb6238f._.png

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

5d768371e67765f0fd5fb9470dfb00b5._.png

Здесь мы видим буфер BUF, но он определен как последовательность байт DB (IDA если нет символов не может обнаружить буфер). Чтобы собрать его в массив символов или пустой массив, щелкните правой кнопкой мыши на слове BUF и выберите параметр ARRAY.

-= Примечание от Яши — Можно также нажать символ * на цифровой клавиатуре=-

62de2902bd2d0178ea2afd0a426f3a10._.png

Здесь мы видим, что до следующей переменной или того, что находится ниже в стеке, IDA обнаружила 120 десятичных DB, а элемент массива равен длине каждого поля, так как размер поля равен 1 байту, то это массив символов или байтов и его сумма рассчитывается так 120*1 байт или просто 120 байт.

Если согласимся с этим, то получится так.

e6ad64f3261676b3bf1a617ebbfbda57._.png

Я вижу, что буфер состоит из 120 байт, что соответствует моему исходному коду, хотя компилятор может сделать его больше, пока он минимум равен 120 байт, то всё хорошо, в этом случае они равны. DUP - означает дубликат (на самом деле он должен быть умножен) 120 раз на символ “?”, потому что значение ещё не определено и это соответствует пустому статическому буферу.

b97a54a1d13b3a1c819ce1f06177d0bf._.png

Я буду прояснять представление статического стека позже, но ниже BUF есть переменная DWORD (DW) называемая VAR_4

S
и R - это сохраненный EBP родительской функции, которая вызвала эту функцию и АДРЕС ВОЗВРАТА, как мы видели при входе в первую функцию - сначала кладутся аргументы с помощью PUSH, а затем делается CALL, чтобы войти в функцию, которая сохранит АДРЕС ВОЗВРАТА в стек, и локальные переменные будут выше S.

ПЕРЕМЕННЫЕ


S (Сохраненный EBP - как правило, происходит от PUSH EBP, которая является первой инструкцией функции)
R (Адрес возврата)
АРГУМЕНТЫ

Поскольку аргументы помещаются в стек перед CALL, который помещает адрес возврата в стек, они будут ниже него, затем будет идти адрес возврата, а выше него СОХРАНЕННЙ EBP порожденный инструкцией PUSH EBP, которая как правило первая инструкция в функции, а затем выше идет пространство локальных переменных, мы увидим их более подробно позже.

Если я нажму X, чтобы увидеть откуда вызывается эта функция, то увижу:

024cc483ec63df8047e25092a62846b7._.png

e882fc3d0bf7efdada954a82e4fa5112._.png

И я иду туда и вижу, что у нас есть инструкции PUSH, которые передают аргументы функции, имя которой я видел, когда работал с СИМВОЛАМИ, а сейчас её здесь нет, 3 аргумента ниже пропущены, ниже есть изображение с символами.

5a9032d21ac2b89354a006ec0f5f4c96._.png

IDA обнаружила, что никогда не используются такие аргументы как ARGC, ARGV и ENVP, они присутствуют по умолчанию в функции MAIN, но так как там не было никаких ссылок на них или их использование в функции, IDAизбавилась от них.

62234c4b0a7ca0f19b95d59d7bbe7508._.png

Кроме того, в моём коде даже не передаются переменные как аргументы к функции MAIN, так что все хорошо - функция без аргументов.

Когда мы хотим увидеть из какого место получается доступ к переменной, мы отмечаем её и нажимаем X.

94c0ac89af69857a25eb4b06b55ed1cb._.png

Мы видим, что VAR_4 используется в двух местах, для тех кто не знает, это переменная COOKIE, которую я не программировал, это защита от переполнения стека, программа сохраняет их в начале при запуске функции, проверяет их на целостность при выходе из функции, теперь мы можем переименовать их в COOKIE_DE_SEGURIDAD или CANARY.

67a4d6f0b5f06f578a598e4e9ff2bb95._.png

Мы видим, что когда функция хочет напечатать строки она вызывает CALL в которой в конечном итоге будет вызвана функция PRINTF для печати строк.

003cb5f62c781ceaabb68711c32d0a56._.png

Мы видим, что в версии с символами IDA обнаружила её непосредственно как функцию PRINTF.

3d9c2cdc484e5de578ef9f0d54be2f4c._.png

Но только если мы посмотрим внутрь CALL то узнаем, что аргументы, это строки, которые печатаются в консоли и мы делаем вывод, что это функция PRINTF.

3f8ac4efae5eb3e38dafad92e82a1c78._.png

Мы видим, что внутри эта функция заканчивается вызовом VFPRINTF, так что, это то, что нам нужно переименовать.

60773b1bf37016e5892d470735452522._.png

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

Мы видим, что буфер идет как аргумент к функции GETS_S - эта функция, которая получает то, что мы вводим в консоли.

4cc8f30b8e85fb22e1b9aa93889db47a._.png

Мы видим, что есть два аргумента - указатель на буфер и его максимальный размер, в который позволено нам печатать, давайте посмотрим, что будет в нашем случае.

3dec77a73e3903a9d93b212578baa01e._.png

Ранее мы сказали, что LEA вычисляет адрес переменной, в этом случае LEAявляется указателем на буфер BUF, который передаётся с помощью инструкции PUSH EAX, а затем идёт PUSH 0x14, который указывает максимальное количество символов, которое можно ввести в консоли.

d1e56e1d72ba3053e8ad0ac5ee4586c8._.png

В моём исходном, мы видим тот же самый вызов GET_S с двумя аргументами - БУФЕР и его максимальное значение, который я обозвал как переменную MAX из 20 элементов, но компилятор, чтобы сохранить пространство поместил именно 20 в десятичной или 0x14 в HEX в этот аргумент, так как не нужно использовать больше.

Следовательно, не выполняя этот вызов, я знаю, что в буфере у меня есть символы, которые я набираю в консоли.

Позже, тот же указатель на буфер помещается как аргумент к функции ATOI.

841af53adaf08fa56eee1058cf78ac1f._.png

Она делает то же самое.

d34366f8d8306fbdd56f1b1f1f0020c8._.png

Эта функция конвертирует строку в целое число и если она не может это сделать, потому что происходит переполнение (выход за максимально возможное значение), нам будет показываться ошибка и вернётся ноль, тоже самое происходит и с отрицательным числом, но идея состоит в том, что всё что я буду вводить будет конвертироваться в число, если я введу значение 41424344 оно будет конвертироваться в десятичное значение 41424344, а так как в ассемблере мы работаем с HEX значениями, оно будет возвращено в HEX через регистр EAX.

Каждая функция возвращает генерируемое значение INT, она интерпретирует входные символы как число. Функция возвращает значение 0 для ATOI и _WTOI, если ввод не может быть преобразован в значение этого типа.

4783a1f5be79c2278495fa00bd50025f._.png

Мы видим, что значение возращенное из EAX переносится в ESI и после печати первоначальной строки, которая была введена, сравнивает ESI с числом 0x124578.

Так что, то, что набрано интерпретируется как строка в десятичном формате, которая возвращается в HEX виде и это число сравнивается с этой константой, передавая десятичное значение этой константы.

c576c9d9d327df516f93e44b60f9ada9._.png

Мы видим, что если сравнение не равно (JNZ) оно переносит меня к BAD REVERSER, а если равно, то переносит к GOOD REVERSER, давайте попробуем в консоли PYTHON увидеть десятичное значение числа 0x124578.

498921d8db82706040dd3a945fabdd74._.png

Мы вводим это значение в наш CRACKME.

2ca36bfd9399198bc50dfaf1ee218ae0._.png

c106ba531c7739d69fc02245e5a8173b._.png

Хорошо, это простой пример статического реверсинга, далее также продолжим работу с ЗАГРУЗЧИКОМ

До встрече в 10-той части.

Рикардо Нарваха.
 

О нас

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

    Dark-Time 2015 - 2022

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

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

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