суббота, 5 декабря 2015 г.

Fun with crackme

Захотелось поломать какой-нибудь сложный крякми, выбор пал на https://exelab.ru/f/index.php?action=vthread&forum=2&topic=22109&page=0
Смысл в том, чтобы извлечь картинку из памяти.

== Цель ==

Максимально быстро решить crackme, сведя к минимуму анализ и отладку.

== Первичный анализ ==

Статический анализ: код написан на asm, в импорте только ZwRaiseHardError, среди строк интересна лишь строка Db.dll.
Статикой информацию получить можно, но это долго, а значит не соответствует цели.
Динамический анализ: отладчик пока отложим в сторону, соберем полную картину действий crackme:

Собираем лог сисколов либо тулзой PIN, либо иным инструментом ( я использовал свой ).
В логе видны манипуляции с mapping'ом и unmapping'ом секций, а также пара интересных сисколов: NtResetWriteWatch и NtGetWriteWatch.
Кроме этого есть 3 вызова NtAllocateVirtualMemory с MEM_WRITE_WATCH, и один с MEM_COMMIT.
Далее, в логе видим 1868207 вызовов NtProtectVirtualMemory, скорее всего цикл связан с расшифровкой изображения.

Где может скрываться изображение? В выделенной приватной памяти, в промаппированной памяти или в стеке(экзотика, но почему нет?).

Проверим вариант с секцией, тем более, что в crackme есть строка "Db.dll" намекающая на маппинг dll с картинкой в ресурсах.
В логе есть 8 вызовов NtMapViewOfSection, собираем адреса, куда замаплена секция. Причем два из них находятся среди 1.8 миллионов вызовов NtProtectVirtualMemory:

Первый вызов завершается unmapping'ом:

...
NtProtectVirtualMemory
NtCreateSection
NtMapViewOfSection
NtQuerySystemInformation
NtUnmapViewOfSection
NtProtectVirtualMemory
...

А второй нет:

...
NtProtectVirtualMemory
NtMapViewOfSection
NtProtectVirtualMemory
...

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

Далее, перематываем 1.8 миллиона NtProtectVirtualMemory в логе, из стектрейса берем адрес, из которого был вызван сискол: 0x412B6E.

Дальше нам понадобится отладчик, но не OllyDbg, т.к. бряк на адресе 0x412B6E не работает из-за защиты от модификации секции.
Тем не менее, все работает в windbg(хотя я использовал оба отладчика). Брякаемся, ищем в отладчике конец цикла с NtProtectVirtualMemory.

Конец цикла тут:

001b:00412ee6 6681390f31      cmp     word ptr [ecx],310Fh
001b:00412eeb 7517            jne     00412f04                           [br=1]
001b:00412eed 8b4a18          mov     ecx,dword ptr [edx+18h]

Ставим бряк на 0x00412eed. Ждем пока сработает бряк, смотрим ecx:

kd> r ecx
ecx=1000101a

И видим адрес нашей промапленной секции.
Если цикл с NtProtectVirtualMemory был завязан на расшифровку картинки в ресурсах промапленной dll, то сигнатуру картинки можно будет визуально найти в памяти.
Смотрим память по адресу 0x10000000, видим сигнатуру PE файла, листаем, ничего похожего на сигнатуру картинки не видно.
Либо она где-нибудь в другом месте, либо предположение с расшифровкой неверно и она лежит тут, но зашифрована.

Отпускаем выполнение, отладчик опять брякается на 0x00412eed, и содержимое секции изменяется, после нескольких бряков по адресу 0x10002000 видна сигнатура PNG формата.

DR регистры используются при расшифровке, поэтому бряк на запись последнего байта зашифрованных данных не сработает.
Тем не менее, при срабатывании бряка в edi находится адрес, по которому будет записан dword с расшифрованными данными. Поэтому просто пишем условный бряк:

bp 412eed "j @edi = 0x1001539c '';'gc'"

Ждем срабатывание брекпойнта и дампим картинку:

.writemem f:\result.png 0x10002000 L014000

Результат:



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