Решение wt0vremr - DBP 1.0 keygenme

Сложность: 2 - Needs a little brain (or luck)
Платформа: Windows
Язык: Unspecified/other
Дано: DBP 1.0 keygenme


[stupid stuff]
Dear customer! Allow me to itroduce the most genial benchmark in the world - Dummy Benchmark Pro 1.0 Super Mega Enterprise XP! Main features:
- Multithread Pi counting with Monte Carlo algorythm.
- Uuuhh…. That's all.
[stupid stuff]

If talking serious, you have to write a keygen for this crackme. If you have a valid serial, you are able to start benchmark.

All this should work good on XP, and se7en, not sure about other OS.

Rules:
- No patching
- Code a keygen
- Self-keygening is NOT allowed
- Submit solution to crackmes.de

Feel free to mail me: wt0vremr[commercial at]gmail[littlenicedot]com

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

Открываем crackme в OllyDbg, жмем F8(выполнение по шагам) до тех пор, пока не достигнем адреса 00401145, где происходит вызов функции антиотладки 00401С98..



Это по сути реализация функции IsDebuggerPresent. Основана на флажке BeingDebugged, который расположен внутри структуры PEB (Process Environment Block), указатель на которую расположен в структуре TEB (Thread Environment Block).

struct _TEB {
/*0*/ struct _EXCEPTION_REGISTRATION_RECORD *ExceptionList - доступ через FS:[0]

/*18h*/ указатель на начало структуры _TEB - доступ через FS:[18h]

/*30h*/ PPEB _PEB /*указатель на структуру _PEB - см. ниже*/

}

struct _PEB
{

/*02*/ BOOLEAN BeingDebugged;

}

Чтобы обойти антиотладку, достаточно пропатчить условие по адресу 40114С с JE на JMP или JNE.

Далее, ставим точку останова по адресу 004011D4 - обработчик кнопки “Run DBP” и жмем F9, указываем свое имя и serial. Я обычно использую “abcde” в качестве имени пользователя! :)

image00.jpg

Замечание: в crackme стоит проверка на длину имени пользователя. Оно должно быть от 4-х до 10 символов.

Жмем “Run DBP”. Точка останова сработала. "Пошагово" выполняем программу, пока не достигнем адреса 00401260, здесь происходит вызов функции создания серийного номера (ключа), между адресами 00401B7A и 00401C12 создается часть ключа:
- берем первый символ нашего имени пользователя, а затем в цикле (количество итераций равно длине имени пользователя) перемножаем его (64-битное умножение), складывая с текущим индексом итерации.
Часть ключа сохраняется адресу 0040B378. Код его создания на Python:

username = "abcde"
 
serial = 0
for i in range(0,len(username)):
    serial += (i+1)
    serial *= ord(username[0])


Например, для имени “abcde” часть ключа - 0x20a90792F.

Начиная с адреса 00401C18, идет вторая часть алгоритма, где есть команды FPU (Floating Point Unit) - самое интересное то, что они не имеют никакого значения, только для отвода глаз и команды MMX, задействующие в нашем crackme только два 64-битных регистра mm0 и mm1.



Красным цветом выделены строки, влияющие на создание нашего ключа. Проанализируем алгоритм.

Псевдокод:
шаг 1. Как я говорил выше, часть ключа мы записали в 0040B378 (в вышеприведенном коде этот адрес пишется как serial) и сейчас копируем его в регистры mm0 (по адресу 00401С29) и mm1 (по адресу 00401С3С). Если имя пользователя у нас “abcde”, то полученную часть ключа “0х000000020A90792F” записываем в mm0 и mm1.

шаг 2. Выполнение по адресу 00401С4F команды “PSRLW mm0, 8” (“Packed Shift Right Logical”; на конце символ “W” означает “слово” - “word”). Эта команда выполняет логический сдвиг вправо упакованных слов в регистре mm0 на 8 бит:
0x000000020A90792F (mm0) → 0x0000 0002 0A90 792F (состоит из 4-х слов) → 0x0000 0000 000A 0079 (сдвиг на 8 бит каждого слова)

шаг 3. Выполнение по адресу 00401С5F команды “PSLLQ mm0, 0Ch” (“Packed Shift Left Logical”; на конце символ “Q” означает 64-битное слово - “Quadword”). Эта команда выполняет логический сдвиг влево учетверенного слова в регистре mm0 на 12 бит.
0x00000000000A0079 → 0x00000000A0079000 : сдвиг на 12 бит

шаг 4. Финальный аккорд по адресу 00401С75 - из mm0 вычитаем mm1 (“PSUBB”)…
mm0: 0х000000020A90792F
-
mm1: 0х00000000A0079000
=
mm0: 0x000000FE967717D1

Ключ сформировали (в нашем случае получили 0хFE967717D1). Но это еще не все. Мы возвращаемся в главную процедуру и по адресу 00401278 идет вызов функции преобразования числа в строку. Результат записываем по адресу 0040B3A0.
0хFE967717D1 → “FE967717D1”

Далее, выполняем по шагам и по адресу 004012C2 идет вызов хэш-функции SHA1, где наш ключ “FE967717D1” хэшируется в “8da6de5b07bb575332e4dd3c33423f380c2e9d0b”.

И наконец по адресу 004012D4, crackme берет последние 9 символов от нашего хэша.
“8da6de5b07bb575332e4dd3c33423f380c2e9d0b” → “80c2e9d0b”

Вот и все!

image01.jpg
image02.jpg

Keygen у автора был реализован на Python'е. Я взял за основу его keygen, только все операции с MMX-регистрами вынес в отдельный модуль mmx.py (будем наращивать его функционал по мере возможности)

import hashlib
import mmx
 
print "Keygen - DBP 1.0 Keygenme by wt0vremr"
 
username = raw_input("Username: ")
if (len(username) < 4) | (len(username) > 10):
    print "Too long username. Must be 4-10 chars"
    exit()
 
print "[*] Username: ",username
 
serial = 0
for i in range(0,len(username)):
    serial += (i+1)
    serial *= ord(username[0])
 
mm0 = mmx.mmx(serial)
mm1 = mmx.mmx(serial)
# Логический сдвиг вправо упакованных слов
mm0 = mmx.commands.psrl(mm0, 8, 'w')
# Логический сдвиг влево упакованных слов
mm0 = mmx.commands.psll(mm0, 12, 'q')
# Вычитание упакованных байтов
mm2 = mmx.commands.psub(mm0, mm1, 'b')
 
szserial = "%X" % (mm2.get())
print "[+] Serial:", hashlib.sha1(szserial).hexdigest()[31:]


Примеры:
[*] Username: crackmes
[+] Serial: add6ff41b

[*] Username: wt0vremr
[+] Serial: 40532e957

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