Как исследовать exe-файлы с Cutter. Практика обратной разработки

Простейший пример исследования и патчинга исполняемого файла с помощью Cutter

2 мин на чтение

В этой небольшой статье мы рассмотрим простейший пример исследования exe-файла методом обратной разработки с помощью Cutter. Мы научимся искать в exe-файлах нужные данные и соответствующие им участки кода, а также попробуем выполнить инъекцию своих инструкций в exe-файл (патчинг).

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

Исследование exe-файла

Cutter позволяет дизассемблировать содержимое exe-файла и предоставляет удобные инструменты для работы с ним. Разберем основные моменты на конкретном примере.

Пусть у нас есть программа cutter_example.exe, которая при запуске требует пароль доступа. Вводим пароль “123” и получаем ответ “Wrong password. Closing”. Попробуем найти правильный пароль внутри exe-файла.

Консоль cutter_example.exe с сообщением "Wrong password. Closing" после ввода неверного пароля 123

После неудачной попытки ввода пароля у нас появились зацепки: строки “Enter admin password:” и “Wrong password. Closing”. Дизассемблируем exe-файл и найдем их в его коде.

Запускаем Cutter и подаем ему на вход наш cutter_example.exe.

Диалог "Открыть файл" в Cutter с выбранным cutter_example.exe для анализа

В следующем окне выставляются настройки анализа. Можно ничего не менять и нажать ОК. Начнется анализ.

Диалог "Параметры загрузки" Cutter с настройками уровня авто-анализа exe-файла

Через некоторое время Cutter покажет окно с дизассемблированным кодом.

Окно Cutter с дизассемблированным кодом cutter_example.exe после анализа

Теперь можем искать строки. Переходим на вкладку Strings (1) и вводим в поле фильтра строку “password” (2). Результат (3) как раз содержит интересующие нас строки.

Вкладка Strings в Cutter с результатом поиска по фильтру "password"

Выделяем первую строку и ищем ее использование в коде через окно просмотра перекрёстных ссылок. Окно вызывается либо через контекстное меню выбранной строки, либо по нажатию клавиши “X”. В окне мы увидим, что строка используется только в одном месте кода в инструкции lea (получение адреса строки). То, что нужно. Двойным кликом по ссылке (1) переходим к этому месту в основном окне.

Окно перекрёстных ссылок Cutter с единственным использованием строки в инструкции lea

Здесь у нас самое интересное - работа с кодом. Мы видим, что это функция main. После строки “Enter admin password:” (1) есть вызов оператора std::cin (2), отвечающего за ввод пароля. Спускаемся еще ниже до первой инструкции сравнения cmp (3). По этой инструкции, если сравниваемые значения не равны, то выполняется условный прыжок jne к выводу строки “Wrong password. Closing” (4). А если равны, то идем прямиком к выводу сообщения “Hello admin!” (4). В инструкции сравнения (3) участвует регистр r9. Немного выше находим значение, которое ему присваивается - это строка [str.123456] (5). Вероятно “123456” как раз и есть тот самый пароль.

Дизассемблированный код функции main с инструкцией cmp и строкой пароля str.123456

Запускаем cutter_example.exe и пробуем ввести пароль “123456”. Как и ожидалось, все получилось!

Консоль cutter_example.exe с сообщением "Hello admin!" после ввода найденного пароля 123456

Патчинг exe-файла

Теперь изменим, то есть пропатчим, cutter_example.exe так, чтобы доступ предоставлялся при вводе любого пароля. Самый простой путь - это заменить условные инструкции на пустые nop-ы, которые при выполнении будут просто пропущены.

Выбираем инструкцию с первым условным прыжком jne, которая ведет нас к выводу строки “Wrong password. Closing”, и через контекстное меню заменяем ее на nop.

Контекстное меню замены инструкции jne на nop через пункт "Редактировать" в Cutter

При изменении может выскочить окно с подтверждением перехода в режим записи. Подтверждаем.

Диалог "Ошибка записи" с предложением переоткрыть файл в режиме записи в Cutter

После подтверждения инструкция jne была успешно заменена на два nop-а (1). Их два, потому что инструкция jne занимает два байта, а nop - один. То есть для выравнивания требуется заполнить все пространство изменяемой инструкции.

Немного ниже есть еще один условный прыжок jne (2). Его тоже уберем на всякий случай, чтобы нам ничего не мешало на пути к “Hello admin!”.

Дизассемблированный код с первой замененной инструкцией jne на два nop и вторым условным прыжком jne

Получаем такую картину.

Дизассемблированный код после замены обеих инструкций jne на nop-ы

Теперь закрываем окно Cutter и снова пробуем запустить cutter_example.exe. Вводим заведомо неправильный пароль “1234” и вуаля, доступ получен!

Консоль пропатченного cutter_example.exe с сообщением "Hello admin!" при вводе неверного пароля 1234

Выводы

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


Обсудить в Телеграм


Свежие записи

Чему учиться в эпоху ИИ?

Чему учиться в эпоху ИИ?

Заметка по книге Букреева и ДеУолта “Эверест. Смертельное восхождение”

1 мин на чтение

Doc As Code: диаграммы PlantUML в Doxygen

Doc As Code: диаграммы PlantUML в Doxygen

Включаем поддержку UML-диаграмм в Doxygen и размышляем о последствиях

3 мин на чтение

Какие файлы нельзя коммитить в Git

Какие файлы нельзя коммитить в Git

Разбираемся, как не превратить репозиторий Git в Google-диск

3 мин на чтение

Зачем нужны UML диаграммы?

Зачем нужны UML диаграммы?

Выясняем, когда и для чего разработчики используют UML

3 мин на чтение

Как разбить проект CMake на подпроекты

Как разбить проект CMake на подпроекты

Разделяем на подпроекты существующий проект C++ на CMake

1 мин на чтение