Сложность: 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 более чем достаточно. Приступим.
- Запускаем IDR (Interactive Delphi Reconstructor). Через меню: File -> Load File -> Autodetect Version (версию Delphi определяем автоматически) выбираем наш crackme. Стартует анализ файла. После окончания анализа будет выведено сообщение, предупреждающее о значительном времени, которое может понадобиться для построения полного дерева классов. Можно ответить и «Да», и «Нет» (на ваш выбор), на дальнейший разбор crackme это никак не скажется.
- Идем на вкладку «Forms (F5)». Переключатель выставляем с «Text» на «Form» (просмотр форм в режиме дизайнера). Чуть ниже в списке перечислены все существующие формы. Двойной клик по любой из них – открывает форму на просмотр. Как выяснилось, нас интересует только две формы: TForm1 {Form1} (здесь вводим данные) , TForm2 {Form2} (goodboy-сообщение «Parabens, voce conseguiu» с португальского «Поздравляю, вы сделали это»). Вариантов немного. TForm2 – это уже результат. Значит, вся логика программы спрятана в форме TForm1.
- Дальнейший шаг, узнать какие события отрабатывает форма. В IDR это сделать проще простого. В режиме просмотра щелкаем правой клавишей мышки на том элементе, который нас интересует. Всплывет меню с событиями, которые обрабатывает элемент-владелец. Событие можно выбрать, и в окне справа отобразится дизассемблированный код метода. Итак, в TForm1: FormCreate, Button1Click, Timer10Timer; в TForm2: FormShow, FormClose.
Предположим логику работы программы:
- Создается форма (TForm1.FormCreate) . Инициализация. Забегая вперед, скажу, что здесь заполняется поле «HD» (поле недоступно для редактирования).
- В поле «Serial» вводим свой ключ. Жмем «ОК». Вызывается метод TForm1.Button1Click.
- В случае если ключ правильный, Button1Click запускает таймер TForm1.Timer10. И уже таймер, когда сработает, выполнит метод TForm1.Timer10.Timer10Timer. И вот здесь покажем форму goodboy-сообщения TForm2.FormShow.
Более подробно. Смотрим код, который выполняет каждый метод. Работа с кодом организована так, как в IDA. Двойной клик по функции – «проваливаемся» к ее коду. По правой клавише мыши открывается меню, где, в частности, можно перейти к указанному адресу.
TForm1.FormCreate (0049EF4C) делает две вещи. Первое, поле «HD» заполняем значением серийного номера тома диска C:\ с помощью GetVolumeInformationA (естественно, что это значение привязано к «железу»). Интерактивно его можно получить через команду «vol» в командной строке (cmd.exe). Т.е. у меня HD = «F2A3D2F6»
Второе, TForm1.Timer10.SetEnabled(False) – отключаем таймер.
TForm1.Button1Click (0049EBFC)
- 0049EC41 Проверяем длину ключа. Длина должна быть не нуль.
- Проверка первого символа ключа. Он должен быть либо «A» (0x41) 0049EC5F, либо «S» (0x53) 0049ED20.
Далее для ключа формата «Axxxx»
- Цикл 0049EC84-0049ECA4. Считаем сумму байт (пусть будет totalHD), входящих в строку-значение «HD».
- Цикл 0049EC84-0049ECA4 Читаем цифровую часть ключа (со второго байта и до конца) в строку.
- 0049ECF8 Преобразуем строковое представление цифровой части ключа (десятичное значение) в число (пусть будет intSerial)
- 0049ED07 Основная фишка всего crackme: считаем адрес функции, куда надо передать управление – CALL (totalHD + intSerial)
Для ключа формата «Sxxxx»:
Действия аналогичные. Считаем totalHD, intSerial. Вот только адрес считаем немного по-другому - CALL (totalHD - intSerial)
Скорее всего, префикс ключа задает тип операции расчета адреса «A» = ADD (сложение), «S» = SUB (вычитание).
Остается выяснить: какой адрес вызывать в инструкции CALL (totalHD +/- intSerial). Ясно, что адрес должен лежать в пределах самой программы. В противном случае сработает исключение, и задача не будет решена. Не будем торопиться. Единственное событие, которое еще не рассмотрели - TForm1.Timer10.Timer10Timer.
TForm1. Timer10Timer (0049EE58)
- 0049EE62 TForm2.Show() – показать TForm2 (как помним, это goodboy-сообщение)
- 0049EE6F TForm1. Timer10.SetEnabled(False) – отключить таймер
Итак, надо вызвать код TForm1.Timer10Timer (0049EE58). Для этого, надо включить таймер. Всего лишь в коде программы надо найти функцию, отвечающую за TForm1.Timer10.SetEnabled(True). На вкладке «Units (F2)» находим модуль для методов TForm1. Он находится в конце списка – Unit1. И первая же процедура в нем по адресу 0049EB98 отлично нам подходит.
Функция 0049EB98
- 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