Skip to content

Старый друг

Mikhail Gnedashev edited this page May 19, 2018 · 1 revision
  • Категория: Reverse
  • Стоимость: 450
  • Автор: Михаил Гнедашев
  • Репозиторий

Описание

Только что увиделись с моим давним другом. Он не богат, да и не красавец. Но говорит, что всегда носит с собой автомат. Как ни странно, оружия я у него не увидел. Удивился, переспросил. Он лишь усмехнулся и дал мне флешку с этим файлом.

Что даётся?

  • бинарник

Решение

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

Рассмотрим функцию _start, с которой и начинается исполнение программы.

_start

Всё, что происходит до iter - проверка аргументов. Действительно, запустив бинарник, он попросит передать ему вторым аргументом флаг.

Так же перед iter есть инструкция mov r8 [rsp+10h], т.е мы кладём в регистр r8 ссылку на первый символ флага.

Внутри iter сначала выполняем слкдующие инструкции:

mov     al, [r8]
test    al, al
jz      short final

Здесь мы каждый раз кладём в регистр al символ, находящийся по адресу, лежащему в r8. Если в al лежит 0, то прыгаем на функцию final. (проверяем, не закончилась ли строка)

Далее кусок кода:

mov     rbx, offset alpha
xlat

интерпретируем как al = alpha[al]. Т.е. в al после этого будет лежать элемент массива alpha, находящийся по индексу введённого символа.

mov     bx, 0Fh
mul     bx
add     al, state
mov     rbx, offset dfa
xlat

Интерпретируется как al = dfa[al*0x0f + state]

После этого кладём в state значение al и переходим к следующему символу, инкрементируя r8.

Т.е. iter двигается по введённому аргументу и меняет state по описанным выше правилам.

Стартовое значение state и массивы dfa и alpha можно найти в сегменте data (идущем после сегмента кода)

В функции final следующий код:

final

Он проверяет, что текущее значение state должно быть равно 4. Это будет означать, что мы всё сделали верно.

Т.е весь код можно переписать следующим образом:

state = 0x0d
dfa = [...]
alpha = [...]

for x in FLAG:
    x = alpha[x]
    x = dfa[x*0x0f + state]
    state = x

if state == 4:
    print('Right!')
else:
    print('Wrong!')

Т.е. весь код представляет из себя проверку флага по ДКА (Детерминированному конечному автомату).

Для решения можно либо нарисовать этот автомат на бумаге и прочитать флаг (так как он получается довольно маленький и простой), либо отлаживая (например, в gdb) ввод, подбирать используемые символы из alpha (это все индексы, которые не дают 0), которые будут менять текущее состояние в нужном направлении.

Останется лишь обернуть полученный флаг в QCTF{flag} и сдать.