Решение bringola - Bring_Crackme

Сложность: 3 - Getting harder
Платформа: Windows
Язык: Borland Delphi
Дано: Bring_Crackme

Fishing Serial only

Решение (автор draww)
опубликовано 26.06.2012

Примечание:
1. badboy-сообщение - это сообщение, которое отображается пользователю в случае неверной пары имя-ключ. Текст сообщения разный, содержание всегда одно: “Вы ввели неправильное имя или пароль (ключ)”. Либо другой вариант - пользователю ничего не сообщается, а программа ожидает ввода правильного ключа.
2. goodboy-сообщение - это ура-сообщение, которое показывается пользователю в случае корректной пары имя-ключ.

Инструменты: IDR

1. Анализ

Сам автор решения использовал связку: декомпилятор DeDe и OllyDBG. Я же предложу вариант решения с помощью IDR (Interactive Delphi Reconstructor) – качественного и удобного декомпилятора Delphi (о том, что программа написана на Delphi – известно заранее). К тому же, статического анализа для нашего crackme более чем достаточно. Приступим.

  1. Запускаем IDR (Interactive Delphi Reconstructor). Через меню: File -> Load File -> Autodetect Version (версию Delphi определяем автоматически) выбираем наш crackme. Стартует анализ файла. После окончания анализа будет выведено сообщение, предупреждающее о значительном времени, которое может понадобиться для построения полного дерева классов. Можно ответить и «Да», и «Нет» (на ваш выбор), на дальнейший разбор crackme это никак не скажется.
  2. Идем на вкладку «Forms (F5)». Переключатель выставляем с «Text» на «Form» (просмотр форм в режиме дизайнера). Чуть ниже в списке перечислены все существующие формы. Двойной клик по любой из них – открывает форму на просмотр. Как выяснилось, нас интересует только две формы: TForm1 {Form1} (здесь вводим данные) , TForm2 {Form2} (goodboy-сообщение «Parabens, voce conseguiu» с португальского «Поздравляю, вы сделали это»). Вариантов немного. TForm2 – это уже результат. Значит, вся логика программы спрятана в форме TForm1.
  3. Дальнейший шаг, узнать какие события отрабатывает форма. В IDR это сделать проще простого. В режиме просмотра щелкаем правой клавишей мышки на том элементе, который нас интересует. Всплывет меню с событиями, которые обрабатывает элемент-владелец. Событие можно выбрать, и в окне справа отобразится дизассемблированный код метода. Итак, в TForm1: FormCreate, Button1Click, Timer10Timer; в TForm2: FormShow, FormClose.


image00.jpg
image01.jpg
image02.jpg

Предположим логику работы программы:

  1. Создается форма (TForm1.FormCreate) . Инициализация. Забегая вперед, скажу, что здесь заполняется поле «HD» (поле недоступно для редактирования).
  2. В поле «Serial» вводим свой ключ. Жмем «ОК». Вызывается метод TForm1.Button1Click.
  3. В случае если ключ правильный, Button1Click запускает таймер TForm1.Timer10. И уже таймер, когда сработает, выполнит метод TForm1.Timer10.Timer10Timer. И вот здесь покажем форму goodboy-сообщения TForm2.FormShow.

Более подробно. Смотрим код, который выполняет каждый метод. Работа с кодом организована так, как в IDA. Двойной клик по функции – «проваливаемся» к ее коду. По правой клавише мыши открывается меню, где, в частности, можно перейти к указанному адресу.

TForm1.FormCreate (0049EF4C) делает две вещи. Первое, поле «HD» заполняем значением серийного номера тома диска C:\ с помощью GetVolumeInformationA (естественно, что это значение привязано к «железу»). Интерактивно его можно получить через команду «vol» в командной строке (cmd.exe). Т.е. у меня HD = «F2A3D2F6»

image03.jpg

Второе, TForm1.Timer10.SetEnabled(False) – отключаем таймер.

TForm1.Button1Click (0049EBFC)

  1. 0049EC41 Проверяем длину ключа. Длина должна быть не нуль.
  2. Проверка первого символа ключа. Он должен быть либо «A» (0x41) 0049EC5F, либо «S» (0x53) 0049ED20.

Далее для ключа формата «Axxxx»

  1. Цикл 0049EC84-0049ECA4. Считаем сумму байт (пусть будет totalHD), входящих в строку-значение «HD».
  2. Цикл 0049EC84-0049ECA4 Читаем цифровую часть ключа (со второго байта и до конца) в строку.
  3. 0049ECF8 Преобразуем строковое представление цифровой части ключа (десятичное значение) в число (пусть будет intSerial)
  4. 0049ED07 Основная фишка всего crackme: считаем адрес функции, куда надо передать управление – CALL (totalHD + intSerial)

Для ключа формата «Sxxxx»:
Действия аналогичные. Считаем totalHD, intSerial. Вот только адрес считаем немного по-другому - CALL (totalHD - intSerial)

Скорее всего, префикс ключа задает тип операции расчета адреса «A» = ADD (сложение), «S» = SUB (вычитание).

Остается выяснить: какой адрес вызывать в инструкции CALL (totalHD +/- intSerial). Ясно, что адрес должен лежать в пределах самой программы. В противном случае сработает исключение, и задача не будет решена. Не будем торопиться. Единственное событие, которое еще не рассмотрели - TForm1.Timer10.Timer10Timer.

TForm1. Timer10Timer (0049EE58)

  1. 0049EE62 TForm2.Show() – показать TForm2 (как помним, это goodboy-сообщение)
  2. 0049EE6F TForm1. Timer10.SetEnabled(False) – отключить таймер

Итак, надо вызвать код TForm1.Timer10Timer (0049EE58). Для этого, надо включить таймер. Всего лишь в коде программы надо найти функцию, отвечающую за TForm1.Timer10.SetEnabled(True). На вкладке «Units (F2)» находим модуль для методов TForm1. Он находится в конце списка – Unit1. И первая же процедура в нем по адресу 0049EB98 отлично нам подходит.

Функция 0049EB98

  1. 0049EBA5 TForm1.Timer10.SetEnabled(True) – включить таймер


2. Кейген

Итак, нам надо получить totalHD +/- intSerial = 0x49EB98.

  • Входные данные – значение «HD» (8 символов, алфавит «0..9A..F»). Считаем totalHD.
  • Считаем intSerial = 0x49EB98 - totalHD

Результат-ключ (два варианта на выбор): ключ «A» + строка(intSerial) или ключ «S» + строка(-intSerial)

# -*- coding: cp1251 -*-
call_address = 0x49EB98
 
# ввести HD - строка (8 символов, алфавит "0..9A..F")
HD = raw_input()
if len(HD) != 8:
    print ("[-]Error: invalid length. Only 8 chars for input")
    exit()
 
# считаем сумму байт строки HD
totalHD = 0
for i in range(len(HD)):
    totalHD += ord(HD[i])
 
# считаем числовую часть ключа
intSerial = call_address - totalHD
# ключ А
ASerial = "A"+str(intSerial)
# ключ S: числовая часть та же, только добавляем минус "-"
SSerial = "S-"+str(intSerial)
 
print ("[*]HD = "+HD)
print ("[+]A Serial = "+ASerial)
print ("[+]S Serial = "+SSerial)


Примеры:
[*]HD = F2A3D2F6
[+]A Serial = A4843962
[+]S Serial = S-4843962

[*]HD = 11111111
[+]A Serial = A4844048
[+]S Serial = S-4844048

[*]HD = 12345678
[+]A Serial = A4844020
[+]S Serial = S-4844020

Пока не указано иное, содержимое этой страницы распространяется по лицензии Creative Commons Attribution-ShareAlike 3.0 License