Решение versus - keygenme

Сложность: 1 - Very easy, for newbies
Платформа: Windows
Язык: Borland Delphi
Дано: keygenme

a simpl crackme coded on delphi+asm

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

Инструменты: автор решения использовал OllyDBG, DeDe (лично я использовал IDR)

1) И снова здравствуйте. Вчера я увидел этот давнишний crackme (ему около 2 лет) и, что удивительно, никаких решений до сих пор для него нет. Хотя, как видно из комментариев, большинство людей уже справились с ним, и меня удивляет, почему никто не написал решение к нему? Таким образом, я пренебрег уровнем сложности (1 - очень легко) и решил написать свое решение, чтобы люди (особенно новички), могли научиться чему-то, поэтому я и здесь.

2) При первом запуске, мы видим навязчивый NAG-диалог. На нем стоит таймер на 4 секунды, по истечении которых включается по умолчанию неактивная кнопка "ОК". У нас не стоит задача отключать/патчить NAG-окно. Просто немного подумаем: "если бы мы зарегистрировались, то мы не увидели бы NAG после регистрации". Поэтому постараемся сделать кейген :)

image00.jpg

3) После NAG-экрана, работаем с основным диалогом ввода данных. Итак, мы видим два текстовых поля (одно для имени, одно – для ключа), неактивная кнопка "ОК" (Хм, странно, не правда ли?). Можно сказать, что проверка ключа происходит «на лету», т.е. когда мы вводим наш ключ посимвольно во второе текстовое поле. Значит, мы должны найти «событие изменения» текстового поля (элемент ввода TEdit) ключа.

image01.jpg

Его можно найти с помощью OllyDBG, но мы будем использовать DeDe от DaFixer для ускорения процесса. Зная, что мы имеем дело с приложением Delphi, так почему бы нам не использовать декомпиляторы DeDe или IDR? В отличие от автора решения я использовал IDR. Пример работы с IDR можно найти в этом решении (Bring_Crackme).
В скором времени мы узнаем, что это событие 00458164 Edit2Change.

image02.jpg

4) В OllyDBG жмем «Ctrl+G», пишим 00458164 и переходим на этот адрес. Ставим точку останова на этой строке, и запускаем crackme. Вводим имя и при попытке ввести любой ключ, срабатывает наша точка останова, мы в начале процедуры Edit2Change. Далее пошагово (кнопка F8) выполняем программу до адреса 004581BF:

004581BF XOR ESI,ESI

С этого адреса вычисляется наш ключ. Первый же цикл - сразу же со следующей строки 004581C1 – берет один байт от нашего имени, прибавляет его значение к значению суммы и сумму XOR’ит с номером позиции этого символа. После цикла результат-сумма умножается на 10 и преобразуется в десятичное число (в виде строки) по адресу:

004581EC CALL crackme.0040844C ;Sysutils::IntToStr(int)

Первая часть нашего ключа готова!

5) Далее мы сталкиваемся с нашей первой проверкой, начиная с адреса 004581F1. Допустим вычисленная первая часть ключа будет «XXXX». Тогда EAX = «XXXX», ESI указывает на вводимый в данный момент ключ (содержимое 2-го текстового поля). Строки в EAX и ESI сравниваются символ за символом, и на строке:

0045822C CMP EDX,DWORD PTR SS:[EBP-1C]

мы видим, что содержимое EDX сравнивается с константой 0x5F (она лежит в стеке DWORD PTR SS:[EBP-1C]), т.е. символ «_». Но мы должны найти оригинальное значение этой константы. Если реверсировать функцию:

00458223 XOR EDX,14
00458226 ADD EDX,43
00458229 SUB EDX,1D

мы найдем значение:

(0x5F+0x1D-0x43) XOR 0x14 = 0x2D (-)
Да, 1-я часть нашего ключа должна заканчиваться дефисом (-). Это означает, что наш формат ключа становится «XXXX-» Если проверка не удалась, кнопка «ОК» остается отключенной.

6) Далее идет следующая проверка:

0045823B MOVZX EAX,BYTE PTR DS:[ECX+ESI-1] ; EAX указывает на 1-й символ после "-"
00458240 ADD EAX,DWORD PTR SS:[EBP-C] ;сложим EAX со значением последнего символа имени
00458243 MOV EDI,0A ; EDI = 10 (0x0A)
00458248 DIV EDI ; EAX / 10
0045824A CMP EDX,6 ; остаток от деления должен быть равен 6
0045824D JNZ SHORT crackme.0045828E ; jump BADBOY

После дефиса должен быть еще один байт, перемещаем его в EAX. Теперь наш формат ключа становится «XXXX-Y». Что делает этот фрагмент кода? Берем Y и складываем со значением крайнего символа нашего имени. Затем окончательное значение делится на 10, и остаток от деления должен быть равен 6. Таким образом, мы должны получить что-то вроде (10* ? +6).

7) Последняя проверка самая простая. Она зашита прямо в код:

00458255 CMP EAX,2D ; '-'
..
00458260 CMP EAX,41 ; 'A'
..
0045826B CMP EDX,4C ; 'L'
..
00458276 CMP EAX,47 ; 'G'

Остаток ключа должен быть «-ALG». Окончательный формат ключа «XXXX-Y-ALG», или так: «%d-%с-ALG»

Кейген

# -*- coding: cp1251 -*-
# Ждем ввода имени пользователя
name = raw_input()
 
# Считаем 1-ю часть ключа
total = 0
for i in range(len(name)):
    total += ord(name[i])
    total ^= (i+1)
total *= 10
 
# Считаем 2-ю часть ключа
lastchar = name[::-1][0]
midValue = ord(lastchar)+0x30
while midValue % 10 != 6:
    midValue += 1
midValue -= ord(lastchar)
 
# Вывод результатов
print ("[*]Name = "+name)
print ("[+]Serial = "+str(total)+"-"+chr(midValue)+"-ALG")


Примеры:
[*]Name = DrAww AliEn
[+]Serial = 9880-8-ALG

[*]Name = draww @ crackmes.de
[+]Serial = 17630-7-ALG

[*]Name = solutionmes
[+]Serial = 12200-3-ALG

[*]Name = Hello, World!
[+]Serial = 11140-5-ALG

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