На этот раз я берусь за этот прекрасный крэкми, третью серию. Чтобы решить эту проблему, мы будем использовать макросы radare2 и эмуляцию единорога. Давайте прямо сейчас!

Некоторый вводный анализ

Crackme запрашивает 4-значный пароль, который пользователь должен вводить по одной цифре за раз. Похож на ПИН-код.

Глядя на main, мы видим, что функция check_code_int вызывается ближе к концу самого большого блока.

Быстрый взгляд на функцию «check_code_int» показывает цепочку блоков «если», заканчивающихся проверками между eax и ebx, по одной на каждую цифру.

Блоки почти идентичны, все они производят некоторые вычисления, а затем сравнивают значение ebx с ожидаемым значением, хранящимся в eax. Если условие выполнено, происходит переход к следующему блоку, в противном случае возвращается код ошибки.

Решение 1. Использование макроса radare2

Чтобы получить правильный пароль, мы можем проверить значение eax во время сравнения, чтобы получить каждую цифру. Вот команды для извлечения кода с помощью radare2:

# set up relative breakpoints. one per cmp instruction
db sym.check_code_int+0x00001289-0x00001265
db sym.check_code_int+0x000012b7-0x00001265
db sym.check_code_int+0x000012e2-0x00001265
db sym.check_code_int+0x0000130d-0x00001265
# execute program
dc
# input four digits (doesn't matter which ones)
1
1
1
1
# define a macro that replaces the value 
# of ebx with the content of eax and stores it into a file
!rm ./crack_code
(eax_replace, dr ebx=`dr eax` | tee -a crack_code, dc)
# use the macro
.(eax_replace )@@=0 1 2 3
# show the results
!cat ./crack_code

Вот красивый макрос в действии

Теперь мы можем открыть сундук!

Решение 2: Bruteforce на базе GEF и движка единорога

Другой способ решить эту проблему - подобрать пароль. Поскольку существует разумное количество действительных PIN-кодов (точнее, 10000), это не займет много времени.

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

Это можно легко сделать, используя функцию GEF для эмуляции, которая генерирует скрипт python единорога, который мы затем можем модифицировать и адаптировать для наших целей.

# 1 - step through the code in gdb
# 2 - reach the start of the check function
# in my case the function starts at 0x555555555269 
# and ends at 0x555555555328
# 3 - use the GEF emu command:
emu -t 0x0000555555555328 -s -o emu.py

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

Мы можем использовать itertools Python для создания контактов и повторять процесс, пока не получим rax = 1 в конце запуска эмуляции.

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

Вы можете получить полный сценарий эмуляции из моего Github и попробовать его сами:



Последние мысли

  • Макросы Radare2 потрясающие! Мы могли бы пойти дальше и сгенерировать r2script для автоматизации задачи, используя макросы, которые мы написали ранее.
  • Эмуляция очень полезна для работы с запутанным кодом и перебора. Unicorn-engine - отличный инструмент, а команда GEF значительно упрощает нашу жизнь.
  • Другой альтернативой эмуляции может быть использование динамических инструментов. Но я оставлю это на будущее.

Надеюсь, вам понравилось это. До скорого!