7 февраля 2013 г.

Пишем кейген для MaxXor's KeygenMe V4.

Итак, продолжим. В первой части мы нашли вилку и нашли места где создаются части ключа.
Теперь необходимо понять каким образом создается сам ключ и собственно написать кейген.
Итак, вернемся назад, к началу функции по адресу 009C27D0 и начнем разбираться.

Протрейсим ее еще раз, но теперь всем вызовам будем давать имя.
Тот вызов что вываливает в HexView циферки по адресу 009C2891 - будет называться create_numer
Вызов который на выходе показывает буковки по адресу 009C289C - будет называться Create_code
А вызов функции который делает буковки заглавными по адресу 009C28B3 - будет называться Upper_string
Если проскроллить вниз, то можно увидеть, что эти функции встречаются еще 3 раза. Это подтверждает, что серийник состоит из 4х частей. Только если приглядется, 1 часть, очень длинная и похоже там производится инициализация расчетов.
Возвращаемся снова к началу функции и начинаем ее выполнять по шагам.
Первым делом обращаем внимание на код типа
.text:009C2816 mov     eax, 2AAAAAABh
.text:009C281B imul    esi

Как я говорил в предыдущей части, если есть некие константы вшитые в код, то это не спроста.
В этом коде производится умножение eax на esi. Причем в esi находится значение 04D2h. Тут у меня в голове щелкнуло и я запустил калькулятор, если перевести десятичнку цифру 1234 в шеснадцетиричный, то получится как раз 04D2h. Вот и наше введеное iD. Позапускав несколько раз программу и повводя в нее разные циферки, я понял, что этой функции передается параметр через ecx следующим кодом.
.text:009C2517 mov     ecx, [esp+240h+var_22C] ; тут и передается число в HEX
.text:009C251B add     esp, 4
.text:009C251E call    Enter_String_SE ; а это вызов функции расчета серийника

Как я писал раньше, я забил на выяснение, где и как преобразуется эта строчка, сделав упор на разбор самого алгоритма вычисления серийника.
Делаем вывод, что надо внимательно смотреть какие операции делаются с ecx. В принципе дальше  все просто, надо тупо выписывать все операции связанные с ecx в отдельный файлик, или сразу как я копировать генерацию в код, по этому буду показывать уже на своем кейгене.
KeyGen    proc    num:DWORD
;######## init calc and part 1
    invoke    GetSystemTime, offset systime ; get system time
    xor        esi, esi ; clear esi
    mov        eax, num ; in eax put number in HEX
    mov        esi, eax ; copy eax in esi
    cdq ; clear edx
    and        edx, 0fh ; edx = edx AND 0Fh
    lea        ecx, [edx+eax] ; ecx = edx + eax
    mov        eax, 2AAAAAABh ; eax = 2AAAAAABh
    imul    esi ; eax = eax * esi
    sar        edx, 2 ; edx right shift on 2
    mov        eax, edx ; eax = edx
    shr        eax, 1Fh ; eax right shift on 1Fh
    add        eax, edx ; eax = eax + edx
    imul    eax, esi ; eax = eax * esi
    mov        serialtmp1, eax ; remember eax in serialtmp1
    mov        eax, esi ; eax = esi
    cdq ; clear edx
    and        edx, 1Fh ; edx = edx AND 1Fh
    lea        edi, [edx+eax] ; edi = edx + eax
    xor        ebx, ebx ; clear ebx
    mov        bx, WORD PTR [systime] ; in bx put current Year in HEX(DEC 2013 == HEX 07DD) 
    mov        eax, 66666667h ; eax = 66666667h
    imul    esi ; eax = eax * esi
    sar        edx, 4 ; edx right shift on 4
    mov        eax, edx ; eax = edx
    shr        eax, 1Fh ; eax right shift on 1Fh
    add        eax, edx ; eax = eax + edx
    imul    eax, esi ; eax = eax * esi
    sar        edi, 5 ; edi right shift on 5
    imul    edi, esi ; edi = edi * esi
    sar        ecx, 4 ; ecx right shift on 4
    imul    ecx, esi ; ecx = ecx * esi
    add        ebx, eax ; ebx = ebx + eax
    add        ebx, edi ; ebx = ebx + eedi
    add        ebx, serialtmp1 ; ebx = ebx + serialtmp1
    mov        serialtmp2, eax ; remember eax in serialtmp2
    add        ebx, ecx ; ebx = ebx + ecx
    mov        serialtmp3, ecx ; remember ecx in serialtmp3
    lea        ecx, [eax+17h] ; ecx = eax+17h
    mov        eax, ebx ; eax = ebx
    cdq ; clear edx
    idiv    ecx ; eax = eax / ecx
    mov        serialtmp4, edi ; remember edi in serialtmp4
    invoke    HEX2DEC, edx ; convert HEX in ASCII number 
    invoke    CreateSerial, eax, ecx, offset serial ; generate string for 1 part serial
    mov        BYTE PTR [edi], 2Dh ; add in serial string dymbol "-" 

;######## calc part 2    
    mov        ecx, serialtmp4 ; put in ecx serialtmp4
    mov        eax, ebx ; eax = ebx
    cdq ; clear edx
    add        ecx, 13h ; ecx = ecx + 13h
    idiv    ecx ; eax = eax / ecx
    invoke    HEX2DEC, edx ; convert HEX in ASCII number 
    inc        edi ; move position in serial on 1
    invoke    CreateSerial, eax, ecx, edi ; generate string for 2 part serial
    mov        BYTE PTR [edi], 2Dh ; add in serial string dymbol "-" 

;######## calc part 3
    mov        ecx, serialtmp1 ; put in ecx serialtmp1
    mov        eax, ebx ; eax = ebx
    cdq ; clear edx
    add        ecx, 0Fh ; ecx = ecx + 0Fh 
    idiv    ecx ; eax = eax / ecx
    invoke    HEX2DEC, edx ; convert HEX in ASCII number 
    inc        edi ; move position in serial on 1
    invoke    CreateSerial, eax, ecx, edi ; generate string for 3 part serial
    mov        BYTE PTR [edi], 2Dh ; add in serial string dymbol "-" 

;######## calc part 4
    mov        ecx, serialtmp3 ; put in ecx serialtmp3
    mov        eax, ebx ; eax = ebx
    cdq ; clear edx
    add        ecx, 25h  ; ecx = ecx + 25h 
    idiv    ecx ; eax = eax / ecx
    invoke    HEX2DEC, edx ; convert HEX in ASCII number 
    inc        edi ; move position in serial on 1
    invoke    CreateSerial, eax, ecx, edi ; generate string for 4 part serial
    ret
KeyGen endp
Мне честно говоря сложно перевести это все в псевдокод, но в принципе тут все достаточно понятно.

Теперь посмотрим на процедуру, которая переводит ключевое число в строку буков, которые и являются частью серийника.
CreateSerial    proc uses ebx    num:DWORD, count:DWORD, pPos:DWORD
    mov        esi, num ; in esi number
    mov        edi, pPos ; in edi position on serial
    xor        ecx, ecx ; clear ecx
    mov        ebx, count ; in ebx count digits
    shr        ebx, 1 ; right shift on 1
@@:
    .if ecx <= ebx ; if ecx <= ebx
        mov        al, BYTE PTR [esi] ; on al put digit on temp ASCII number
        add        al, 32h ; al = al + 32h
    .elseif
        mov        al, BYTE PTR [esi] ; on al put digit on temp ASCII number
        add        al, 3Ch ; al = al + 3Ch
    .endif
    sub        al, 20h ; upper symbol al = al - 20h
    mov        BYTE PTR [edi], al ; put cymbol in serial
    inc        ecx ; ecx = ecx + 1
    inc        esi ; esi = esi + 1
    inc        edi ; edi = edi + 1
    .if    ecx >= count ; if curent position bigger or eq count
        jmp        @f ; exit
    .endif
    
    jmp    @b ; next digit
@@:
    
    ret
CreateSerial endp
Тут проще, можно расписать алгоритм на русском.
Сначало берется общее количество цифр в ключевой номере и сдвигается в право на 1 и поместим получившееся в ebx.
После чего сравнивается с текущей позицией, если текущая позиция меньше или равна с ebx, то к 16ричному значению текущий цифры в номере прибавляется 32h. если же меньше, то прибавляется 3Ch. Ну и т.д. пока не кончатся цифры в текущем наборе.

На этом в принципе и все, кейгенми достаточно простой, хоть и стоит оценка сложности в 3.
Яб поставил не больше двойки за такое, так как все достаточно просто отыскивается. Целиком мой кодъ кейгена можно посмотреть на депозите.

Комментариев нет:

Отправить комментарий