Решение Fego - Eazy Peazy CrackME

Сложность: 2 - Needs a little brain (or luck)
Платформа: Windows
Язык: Assembler
Дано: Eazy Peazy CrackME

Your Goal is to find the correct serial for the CrackME.
Honestly i dont know how hard it can be so try it out your self and let me know.
Written in pure Assembly using MASM.

For anything (really anything) contact me at
federicogorla at hotmail dot com
I'll see ya!

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

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

Наша задача - найти правильный ключ для crackme. Программа содержит диалоговое окно с одним полем ввода (ключ), которое проверяется по кнопке «CHECK». Контроля ввода символов – нет, можно забить любой печатаемый символ.

image00.jpg

Загружаем программу в OllyDBG и наблюдаем чистый (в смысле без обфускации, не оптимизированный, среда разработки – MASM) ассемблерный код. Вся логика crackme лежит по адресам с 0040113C по 0040123E и находится без труда. Отлично, но как программа работает?

1) Читаем строку (ключ) из поля ввода, есть проверка – длина строки должна быть 8 символов. Для примера возьмем строку «12345678» = 0x3132333435363738 (в hex-виде).



2) Вычисляем хэш первых 4-х символов ключа. Длина хэша 4 байта. Вычисляем хэш для «1234». Причем, эти четыре символа рассматриваются как 16-тиричное число, т.е. «1234» = 0x34333231 (где первый символ «1», это самый младший байт в числе - 0х31)



3) Вычисляем хэш последних 4-х символов ключа. Длина хэша 4 байта. Вычисляем хэш для «5678». Причем, эти четыре символа рассматриваются как 16-тиричное число, т.е. «5678» = 0x38373635 (где первый символ «5», это самый младший байт в числе - 0х35)



4) Далее полученный хэш (в сумме 8 байт) нормализуем в ASCII символы из дипазона [0x30…0x7A]: код с адреса 004011D5 по 004011F1. Приведу адаптированный вариант этого кода на Python. В результате получим хэш в виде строки.

def norm(x):
    # x - 16-тиричное число размером в байт
    res = x
    # если x лежит в диапазоне [0x30…0x7A], то ничего делать не надо
    if (res >= 48) & (res <= 122):
        return res
    # иначе x нормализуем к [0x30…0x7A] 
    while 1:
        res &= 0xFF
        if (res < 48):
            # пока x < 0х30, то x += 10 (0x0A) 
            res += 10
        else:
            if (res >> 7) & (res > 122):
               # пока x от 0x80 до 0xFF, то x += 10 (0x0A) 
                res += 10
            else:
               # пока x от 0x7B до 0x7F, то x -= 10 (0x0A) 
                res -= 10
        if (res >= 48) & (res <= 122):
            break
    return res


5) И, наконец, сравниваем хэш с «8x@rtr25»
И что мы можем сделать? Очевидный вариант: brute force, подобрать хэш методом тупого перебора входящих строк ключа. Благо, хэш четырехбайтный (хотя, их и два). Я адаптировал переборщик паролей на Python (откровенно, тормозное решение – тот же код на С/С++ выполняется за секунды, а на интерпретируемом языке – за минуты и часы). Оба хэша на моей машине подобрались минут за 20. Но мы же никуда не торопимся :)
# циклический сдвиг вправо
def ror(num, count, type):
    cnt = count % type
    a = type - cnt
    numcur = num
    if numcur < 0:
        numcur &= 0x7FFFFFFF
        ror_low = numcur >> cnt
        ror_low = ror_low | (1<<(a-1))
    else:
        ror_low = numcur >> cnt
    numcur = num
    ror_hi = numcur << a
    ror = ror_hi | ror_low
    if type == 8:
        ror = ror & 0x000000FF
    if type == 16:
        ror = ror & 0x0000FFFF
    if type == 32:
        ror = ror & 0xFFFFFFFF
    return ror 
 
# ОСНОВНОЙ КОД
check = "8x@rtr25"
 
#brute force первого 4-хбайтового хэша
print (Start one brute force:”)
for a in range(48,123):
    for b in range(48,123):
        for c in range(48,123):
            for d in range(48,123):
                z = a | (b << 8) | (c << 16) | (d << 24)
                hash1 = ((z * 0x310890) ^ 0x96547) & 0xFFFFFFFF
                ch_1 = norm((((hash1 & 0xFF) ^ a) << 2) & 0xFF)
                ch_2 = norm(((((hash1 >> 8) & 0xFF) ^ b) << 2) & 0xFF)
                ch_3 = norm(((((hash1 >> 16) & 0xFF) ^ c) << 2) & 0xFF)
                ch_4 = norm(((((hash1 >> 24) & 0xFF) ^ d) << 2) & 0xFF)
                #сверяем с хэшем «8x@r»
                if (ch_1 == ord(check[0])) & (ch_2 == ord(check[1])) & \
                    (ch_3 == ord(check[2])) & (ch_4 == ord(check[3])):
                        print (chr(a)+chr(b)+chr(c)+chr(d))
 
#brute force второго 4-хбайтового хэша
print (Start two brute force:”)
for a in range(48,123):
    for b in range(48,123):
        for c in range(48,123):
            for d in range(48,123):
                z = a | (b << 8) | (c << 16) | (d << 24)
                hash1 = ((z * 0x666666) ^ 0x365799) & 0xFFFFFFFF
                hash1 = ror(hash1, 0x31, 32)
                ch_1 = norm(ror((((hash1 & 0xFF) ^ a) ^ 0x31) & 0xFF, 0x12, 8))
                ch_2 = norm(ror(((((hash1 >> 8) & 0xFF) ^ b) ^ 0x31) & 0xFF, 0x12, 8))
                ch_3 = norm(ror(((((hash1 >> 16) & 0xFF) ^ c) ^ 0x31) & 0xFF, 0x12, 8))
                ch_4 = norm(ror(((((hash1 >> 24) & 0xFF) ^ d)  ^ 0x31) & 0xFF, 0x12, 8))
                #сверяем с хэшем «tr25»
                if (ch_1 == ord(check[4])) & (ch_2 == ord(check[5])) & \
                    (ch_3 == ord(check[6])) & (ch_4 == ord(check[7])):
                        print (chr(a)+chr(b)+chr(c)+chr(d))


Результаты оформим в виде таблички: строки, удовлетворяющие первому хэшу - слева, а строки для второго хэша - справа.
1-я половинка ключа (найдено 24):
1X=a
3_;J
8d[B
Fl\_
Gdh0
Gdhp
R534
R53t
R5sP
RuW^
Y1V[
Yqj>
l7oL
lwCb
m>Ja
n6i0
n6ip
nvMM
q<O7
q<Ow
s3BP
ssfI
x8bH
xxFe
2-я половинка ключа (найдено 31):
:m9U
;7<d
;A<2
;IvA
;s<8
M1qM;qz
McqB
Mmqh
PNn?
PbnK
Pgn2
U>`Uz`H
WAjO
[AWS
_E@C
_Y@7
_w@I
fBtX
fLt^
f`tj
fetQ
foto
gVxu
goxx
iW\z
iz\[
uE9A
uJ9@
ur9x


Любое сочетание двух половинок ключа даст нам полноценный ключ. Если использовать нашу табличку, то получим различных комбинаций: 24 * 31 = 744 ключа. Вводим любой полученный ключ и наблюдаем:

image01.jpg

Примеры:
[+]Serial = xxFegoxx
[+]Serial = GdhpfetQ
[+]Serial = R53tgoxx
[+]Serial = xxFePbnK
[+]Serial = l7oLfoto
[+]Serial = m>JafetQ
[+]Serial = x8bHgoxx

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