Physical Address
304 North Cardinal St.
Dorchester Center, MA 02124
Physical Address
304 North Cardinal St.
Dorchester Center, MA 02124
Сегодня я покажу тебе несколько приемов обращения с Radare2 — мощным фреймворком для обратной разработки. Мы выведаем скрытый в программе пароль, для чего научимся извлекать из исполняемых файлов структурированную информацию и конвертировать получаемые значения. Затем изменим исполняемый файл и выполним недоступную при корректном поведении функцию.
Упражняться мы будем на crackme, которую я написал специально для демонстрации. Скачать файл ты можешь с моего GitHub. Все действия мы будем проводить в Debian Linux.
В статье «Radare2 с самого начала. Учимся использовать опенсорсный фреймворк для анализа приложений в Linux» мы уже начали исследовать этот исполняемый файл. При запуске он открывает сокет и начинает слушать порт 14884. Если подключиться к этому сокету при помощи netcat, то можно увидеть приглашение для ввода имени пользователя или пароля. Если ввести неверный пароль, сеанс завершится.
Используя основные возможности Radare2, мы выявили в программе функции main, authenticate, check_username, check_password, start_server и несколько других. В authenticate есть пять локальных переменных, а также вызов функции с говорящим названием check_username, которой в качестве единственного аргумента передается значение переменной fd.
Это краеугольная функция в защитном механизме, поскольку из нее вызываются некоторые другие весьма важные и не всегда относящиеся к процедуре логина функции. На очереди — извлечение пароля. Но даже когда мы раскусим защитный механизм, у нас будет возможность копать этот крякмис в глубину. Мы изменим его код, чтобы выполнение программы шло по той ветви, результаты выполнения которой нам нужны.

Дизассемблированная функция check_username
В функции check_username дескриптор сокета, переданный в аргументе, помещается в переменную fildes. Далее с помощью библиотечной функции memset готовится буфер памяти: src заполняется нулями, затем в него с помощью функции read читается пользовательский ввод из сокета, на который указывает fildes. То есть читается как бы с удаленного устройства.
Дальше в консоль на стороне сервера функция printf выводит строку [+] Reading username, потом в нее же с помощью fputs выливается содержимое буфера src, содержащего введенное имя пользователя. Далее возвращенный функцией fputs результат сравнивается с -1. Если равенство верно, выводится сообщение об ошибке, если же возвращенное значение не равно -1 (ноль или положительное значение), то выполняется переход на строку 0x1605. Здесь происходит вывод символа конца строки — n.
После этого готовятся параметры для вызова библиотечной функции strcpy. Она копирует имя пользователя src в новую область памяти — dest. Далее в строке со смещением 0x1628 в переменную var_420h копируется значение 0x6262616a. В комментарии рядом Radare2 оставил метку, заключенную в одинарные кавычки, — jabb:
mov dword [var_420h], 0x6262616a ; 'jabb'
По мнению Radare2, это шестнадцатеричное число — набор букв в кодировке UTF-8, используемой в большинстве дистрибутивов Linux. Доверяй, но проверяй! В командную строку под дизассемблированным листингом функции введи
? 0x6262616a
Ниже появится список, в котором указанное значение будет конвертировано в разные типы данных.

Приведение числа 0x6262616a к разным типам данных
Нас интересует тип string. Напротив него мы видим строку jabb, что и требовалось доказать.

Неверно введенное имя пользователя
Вернемся в функцию check_username. Строкой ниже (0x1632) мы видим, что в переменную var_21ch помещается символ a, пока непонятно для чего. Снова промотаем листинг к началу функции, где расположены комментарии о переменных:
... ; var int64_t var_41ch @ rbp-0x41c ; var int64_t var_420h @ rbp-0x420 ...
Нас интересуют эти две переменные. Теперь посмотрим на код присвоения им значений:
mov dword [var_420h], 0x6262616a ; 'jabb'mov word [var_41ch], 0x61 ; 'a'
Истина где‑то рядом. В UTF-8 символ может занимать от одного до четырех байтов, однако латинские символы, которые мы видим в листинге, никогда не превышают одного байта. Таким образом, значение 0x6262616a — это четыре байта, что подтверждает размер приемника — двойное слово, dword.
Источник: xakep.ru