+ Reply to Thread
Results 1 to 8 of 8

Thread: Решения Easy Crackme

  1. #1

    Default Решения Easy Crackme

    Доброго времени суток!

    Сегодня я расскажу, как я решал crackme, который находится тут: http://forum.reverse4you.org/showthr...=4665#post4665

    Приступим к решению.

    Запустим сам crackme и посмотрим, что он из себя представляет...



    Видим, что у нас есть 2 поля для ввода и 2 кнопки для выхода, и проверки введенных данных. Пробуем что-то ввести и нажать кнопку Check. Видим, что программа закрылась(или вы с первого раза угадали, какой там серийник и увидели сообщение внизу приложение, где со старта написано "Hi!"), что же не будем отчаиваться и пойдем дальше.

    Открываем crackme в Immunity Debugger. Посмотри какие функции импортированы в текущем приложении. Для этого делаем правый клик мышки -> Search for -> Name(label) in current module. Получим следующее окошко:

    Лично меня очень заинтересовала функция GetDlgItemTextA, т.к. именно она получает данные, которые мы вводили в текстовые поля. Поставим бряк на эту функцию и запустим приложение. Видим, что мы остановились на этой функции, нажимаем один раз F8 и видим, что получаем введенный мной серийник:


    Теперь рассмотрим код, который идет далее. Видим, что наша введенная строка передается далее какой-то функции, давайте выполним эту функцию и остановимся на инструкции сравнения. Эта функция вернула, число 0х20, что равняется длине введенной нами строки, т.е. имеем, что эта функция возвращает нам длину введенной строки ( кто не верит, может сделать F7 и проанализировать код ;) - задание 1). Соответственно, получаем, что длина нашего серийника должна быть 0х20. Кто ввел другую длину, либо делаем до этого шага все сначала, либо меняем значение регистра EAX на 0х20 ручками и идем дальше ;). Т.к. длина введенной строки у меня нужная, то я попадаю на адрес 0040132E, где видим, что запихивается наша введенный серийник и еще какая область памяти. Посмотрим, что передается и что происходит в функции по адресу 0040338:
    Code:
    00401417  /$ 55             PUSH EBP
    00401418  |. 8BEC           MOV EBP,ESP
    0040141A  |. 56             PUSH ESI
    0040141B  |. 57             PUSH EDI
    0040141C  |. 53             PUSH EBX
    0040141D  |. 8B75 08        MOV ESI,DWORD PTR SS:[EBP+8]
    00401420  |. 8B7D 0C        MOV EDI,DWORD PTR SS:[EBP+C]
    00401423  |. EB 08          JMP SHORT KeygenMe.0040142D
    00401425  |> 83E3 0F        /AND EBX,0F
    00401428  |. 03C3           |ADD EAX,EBX
    0040142A  |. 8807           |MOV BYTE PTR DS:[EDI],AL
    0040142C  |. 47             |INC EDI
    0040142D  |> 0FB616          MOVZX EDX,BYTE PTR DS:[ESI]
    00401430  |. 83FA 40        |CMP EDX,40
    00401433  |. 1BDB           |SBB EBX,EBX
    00401435  |. 83EA 37        |SUB EDX,37
    00401438  |. 83E3 07        |AND EBX,7
    0040143B  |. 46             |INC ESI
    0040143C  |. 03DA           |ADD EBX,EDX
    0040143E  |. 78 1A          |JS SHORT KeygenMe.0040145A
    00401440  |. 8BC3           |MOV EAX,EBX
    00401442  |. C1E0 04        |SHL EAX,4
    00401445  |. 8807           |MOV BYTE PTR DS:[EDI],AL
    00401447  |. 0FB616         |MOVZX EDX,BYTE PTR DS:[ESI]
    0040144A  |. 83FA 40        |CMP EDX,40
    0040144D  |. 1BDB           |SBB EBX,EBX
    0040144F  |. 83EA 37        |SUB EDX,37
    00401452  |. 83E3 07        |AND EBX,7
    00401455  |. 46             |INC ESI
    00401456  |. 03DA           |ADD EBX,EDX
    00401458  |.^79 CB          \JNS SHORT KeygenMe.00401425
    0040145A  |> 5B             POP EBX
    0040145B  |. 5F             POP EDI
    0040145C  |. 5E             POP ESI
    0040145D  |. C9             LEAVE
    0040145E  \. C2 0800        RETN 8
    Видим, что в ESI и EDI запихиваются адреса памяти, переданных в функцию и дальше происходит манипуляции с введенным нами серийником... Придется разбираться, что уж тут поделать=)... Проводим, анализ цикла, который начинается на адресе 00401425 и заканчивается по адресу 00401458, мы можем заключить:
    0. Из цикла мы выходим, тогда когда очередной рассчитанный, по вышеуказанному алгоритму, будет меньше нуля.
    1. Берется символ нашей введенной строки.
    2. Отнимается от этого символа 55 ( в десятичной системе ).
    3. Проверятся, что полученное значение больше или меньше 0х40, если меньше то надо еще прибавить к символу число 7.
    4. Записывается, то что получили по определенному адресу.
    5. Берется следующий введенный символ.
    6. Умножается на 16
    7. Далее повторение пунктов 2-3.
    8. Далее получаем старшие 4 бита полученного числа и записываем по определенному адресу
    9. Переходим опять на пункт 1.
    Из этого всего можно сделать один вывод, что результирующий символ после процедуры "шифрования" равен двум символам введенного серийника.

    Отлично, самую тяжелую часть я думаю мы сделали ;). Выходим из функции и смотрим, как то, что мы "нашифровали" используется:
    Code:
    0040133D  |. 8D35 A8324000  LEA ESI,DWORD PTR DS:[4032A8]
    00401343  |. 8D3D EA324000  LEA EDI,DWORD PTR DS:[4032EA]
    00401349  |. B9 10000000    MOV ECX,10
    0040134E  |. FC             CLD
    0040134F  |. F3:A6          REPE CMPS BYTE PTR ES:[EDI],BYTE PTR DS:>
    00401351  |. 75 5D          JNZ SHORT KeygenMe.004013B0
    Исходя из этого кода, мы получаем, что наш "зашифрованный" серийник сравнивается с серийником, к-ый правильный ;). Соответственно, если эти строки не равны, то наша приложение закроется, если равны, то мы вместо строки "Hi!", внизу приложению, получим сообщение, что мы нереально круты и справились с заданием.
    Исходя из вышеописанного алгоритма генерации серийного номера, мы можем сесть и спокойно написать генератор серийники, т.к. "зашифрованный" правильный серийник мы знаем где достать ( DWORD PTR DS:[4032A8] ). Исходя из всего выше описанного, получаем следующий код генератора серийника:
    Code:
    #include <stdio.h>
    
    #define SERIAL_SIZE 0x20
    #define ENCRYPTED_SERIAL_SIZE (SERIAL_SIZE / 2)
    
    int main() {
    	char serial[SERIAL_SIZE];
    	char encryptedSerial[ENCRYPTED_SERIAL_SIZE] = {0xE9, 0x7F, 0x65, 0x04, 0x42, 0x44, 0x0B, 0x14, 0x4E, 0x39, 0xC4, 0xD2, 0x30, 0x1C, 0xDF, 0x1D};
    
    	unsigned int i;
    
    	for (i = 0; i < ENCRYPTED_SERIAL_SIZE; i++) {
    		char currByte = encryptedSerial[i];
    		char tmp;
    
    		tmp = ((currByte & 0xF0) >> 4) + 55;
    		tmp -= (tmp < 0x40 ? 7 : 0);
    		serial[2 * i] = tmp;
    
    		tmp = (currByte & 0x0F) + 55;
    		tmp -= (tmp < 0x40 ? 7 : 0);
    		serial[2 * i + 1] = tmp;
    	}
    
    	// for (i = 0; i < SERIAL_SIZE; i++) {
    	// 	printf("%x ", serial[i]);
    	// }
    	// printf("\n");
    
    	for (i = 0; i < SERIAL_SIZE; i++) {
    		printf("%c", serial[i]);
    	}
    	printf("\n");
    
    	return 0;
    }
    Собственно все! Хотелось напоследок, только заметить следующие:
    1. Для генерации серийники мы вообще не используем никак логин, только введенный нами серийник.
    2. Создается какой-то непонятный файл keygen.dat и потом удаляется. Что это за файл и нафиг он нужен, кому сильно интересно разбирайтесь в качестве домашнего задания ;)

    Вот и все! Всем успехов.

    Надеюсь кому-то понравилось и вопросов нету ;)

    P.S.: я не нашел как загрузить на наш форум картинки, поэтому пока пусть будут на radikal.ru =(

  2. 5 пользователя(ей) сказали cпасибо:
    V3T (17-03-2013) aspidites (18-03-2013) root (16-03-2013) whiteshuk (16-03-2013) ximera (16-03-2013)
  3. #2
    ARCHANGEL's Avatar

    Default Re: Решения Easy Crackme

    Не в обиду будет сказано, но я не согласен с выводами. Логин используется, непонятный файл keygen.dat - это динамическая библиотека, из который вызывается экспорт calc, которому передаётся дважды шифрованный логин, на выходе имеется результат шифровки внутри calc, именно с ним сравнивается введенный серийник. А функция, которую так детально разбирали, преобразует строку в число побайтово. Т.е. каждые два символа преобразуются в байт. И код, который приведен выше, никак не может быть "генератором серийника", как им генерировать ключи под произвольные имена?
    Добрым быть просто - достаточно обратить свой гнев на негодяев...

  4. 4 пользователя(ей) сказали cпасибо:
    V3T (17-03-2013) aspidites (18-03-2013) coldfire (16-03-2013) root (16-03-2013)
  5. #3

    Default Re: Решения Easy Crackme

    Quote Originally Posted by ARCHANGEL View Post
    Не в обиду будет сказано, но я не согласен с выводами. Логин используется, непонятный файл keygen.dat - это динамическая библиотека, из который вызывается экспорт calc, которому передаётся дважды шифрованный логин, на выходе имеется результат шифровки внутри calc, именно с ним сравнивается введенный серийник. А функция, которую так детально разбирали, преобразует строку в число побайтово. Т.е. каждые два символа преобразуются в байт. И код, который приведен выше, никак не может быть "генератором серийника", как им генерировать ключи под произвольные имена?
    Я не обращал на этот файл внимание, видимо зря, но просто когда я пробывал менять логин, то шифрованная строка, с которй сравнивается введенный нами серийник, не меняется.

    Никак не может генерировать.

    Судя по всему зря я не обратил внимание на этот файл.

    Спасибо за замечание. Приду вечером, надо будет тогда еще раз посмотреть!
    Last edited by coldfire; 16-03-2013 at 13:41.

  6. 2 пользователя(ей) сказали cпасибо:
    V3T (17-03-2013) aspidites (18-03-2013)
  7. #4

    Default Re: Решения Easy Crackme

    Все разобрался я с ним до конца и да это оказался keygen, а не crackme... Надо было сразу обратить внимание на файл keygen.dat и ковырять его... Спасибо ARCHANGELу, что это заметил и сказал, что я был не прав. И также спасибо ему, что отвечал периодически на возникшее у меня вопросы.

    Перейдем теперь к тому, как я осилил написать keygen :D....
    Открываем еще раз данный KeygenMe.exe в отладчике и смотрим, а как используется наш файл keygen.dat... Пролистуем листинг программы и видим, что происходит вызов функции LoadLibraryA с параметром в виде имени нашего файла:
    Code:
    00401299  |> 68 2A304000    PUSH KeygenMe.0040302A                   ; /FileName = "keygenme.dat"
    0040129E  |. E8 15030000    CALL <JMP.&kernel32.LoadLibraryA>        ; \LoadLibraryA
    004012A3  |. 0BC0           OR EAX,EAX
    004012A5  |. 0F84 05010000  JE KeygenMe.004013B0
    004012AB  |. A3 9C314000    MOV DWORD PTR DS:[40319C],EAX
    004012B0  |. E8 D7080000    CALL KeygenMe.00401B8C
    004012B5  |. 5A             POP EDX
    004012B6  |. 52             PUSH EDX                                 ; /Arg2
    004012B7  |. 68 A8324000    PUSH KeygenMe.004032A8                   ; |Arg1 = 004032A8
    004012BC  |. E8 E7080000    CALL KeygenMe.00401BA8                   ; \KeygenMe.00401BA8
    004012C1  |. E8 2E090000    CALL KeygenMe.00401BF4
    004012C6  |. 8BF8           MOV EDI,EAX
    004012C8  |. 6A 20          PUSH 20                                  ; /Length = 20 (32.)
    004012CA  |. 68 A8324000    PUSH KeygenMe.004032A8                   ; |Destination = KeygenMe.004032A8
    004012CF  |. E8 F6020000    CALL <JMP.&kernel32.RtlZeroMemory>       ; \RtlZeroMemory
    004012D4  |. 68 37304000    PUSH KeygenMe.00403037                   ; /ProcNameOrOrdinal
    004012D9  |. FF35 9C314000  PUSH DWORD PTR DS:[40319C]               ; |hModule = 00AD0000 (keygen_1)
    004012DF  |. E8 CE020000    CALL <JMP.&kernel32.GetProcAddress>      ; \GetProcAddress
    004012E4  |. A3 A0314000    MOV DWORD PTR DS:[4031A0],EAX
    004012E9  |. 57             PUSH EDI                                 ;  KeygenMe.00403300
    004012EA  |. FF15 A0314000  CALL DWORD PTR DS:[4031A0]               ;  keygen_1.calc
    004012F0  |. 68 A8324000    PUSH KeygenMe.004032A8
    004012F5  |. 56             PUSH ESI
    004012F6  |. E8 25030000    CALL KeygenMe.00401620
    Отлично, исходя из вышеуказанного листинга видим, что вначале наша библиотека "keygen.dat" динамически подгружается и сразу можно заметить, что из этой библиотеки происходит вызов функции calc ( это мы можем видеть в конце листинга ). Давайте посмотрим, что передается этой функции.

    Первые две функции, которые мы встречаем на своем пути после LoadLibraryA - это высчитывание длины введенной строки и копирование ее в опрделенную область памяти(0х0043310). В них нет ничего интересного, далее идет вызов функции 00401BF4. Вот она, то нам и интересна:
    Code:
    00401BF4  /$ 56             PUSH ESI
    00401BF5  |. 57             PUSH EDI
    00401BF6  |. A1 44334000    MOV EAX,DWORD PTR DS:[403344]
    00401BFB  |. BA 10000000    MOV EDX,10
    00401C00  |. 2BD0           SUB EDX,EAX
    00401C02  |. 8DB8 10334000  LEA EDI,DWORD PTR DS:[EAX+403310]
    00401C08  |. 81E2 FF000000  AND EDX,0FF
    00401C0E  |. 8BC2           MOV EAX,EDX
    00401C10  |. 8BCA           MOV ECX,EDX
    00401C12  |. F3:AA          REP STOS BYTE PTR ES:[EDI]
    00401C14  |. E8 57FEFFFF    CALL KeygenMe.00401A70
    00401C19  |. BE 30334000    MOV ESI,KeygenMe.00403330
    00401C1E  |. BF 10334000    MOV EDI,KeygenMe.00403310                ;  ASCII "coldfire"
    00401C23  |. B9 10000000    MOV ECX,10
    00401C28  |. F3:A4          REP MOVS BYTE PTR ES:[EDI],BYTE PTR DS:[>
    00401C2A  |. E8 41FEFFFF    CALL KeygenMe.00401A70
    00401C2F  |. B8 00334000    MOV EAX,KeygenMe.00403300
    00401C34  |. 5F             POP EDI
    00401C35  |. 5E             POP ESI
    00401C36  \. C3             RETN
    Видим, что тут мы берем нашу строку, дополняем ее до 0х10 байт, если она меньше ( символ, к-ым дополняется высчитуется так - 0х10 - длина введеной строки). Дальше наша строка шифруется дважды ( саму функци шифроку я не буду детально описывать, во-первых - она в целом понятно, во-вторых - ее можно увидеть в коде генератора, который я предоставлю ниже).

    После этой функции мы видим, что происходит вызов функции calc из динамической библиотеки keygen.dat. Смотрим, что передается этой функции - АГА, туда передается указатель на наш дважды зашифрованный буфер!!! Т.е. наш буфер еще раз шифруется. УЖАС! Заглянем в эту функцию, и видим, что то что оно нашифровало будет находится по адресу, который находится в регистре esi... Более детально мы не будем рассматривать эту функции, т.к. мы ее просто заиспользуем при написании генератора =)

    Далее видим, что далее происходит ( в функции 00401620 ) копирование зашифрованной строки в область памяти, которая потом преобразовывается в строку ( Алгортим преобразование, я собственно описал в самом начале, в первом моем посте ).

    Собственно, вот и все. Прилагаю код генератора, изучаем, хвалим или наоборот ;)

    Code:
    #include <stdio.h>
    #include <string.h>
    
    #include <windows.h>
    
    char *enteredLogin = "coldfire";
    
    #define BUFF_SIZE 0x48
    
    #define SERIAL_SIZE 0x20
    #define ENCRYPTED_SERIAL_SIZE (SERIAL_SIZE / 2)
    
    unsigned char encryptedSerial[ENCRYPTED_SERIAL_SIZE];
    
    unsigned char buff[BUFF_SIZE];
    
    unsigned char buff403080[] = {
                                    0x29, 0x2E, 0x43, 0xC9, 0xA2, 0xD8, 0x7C, 0x01, 0x3D, 0x36, 0x54, 0xA1, 0xEC, 0xF0, 0x06, 0x13,
                                    0x62, 0xA7, 0x05, 0xF3, 0xC0, 0xC7, 0x73, 0x8C, 0x98, 0x93, 0x2B, 0xD9, 0xBC, 0x4C, 0x82, 0xCA,
                                    0x1E, 0x9B, 0x57, 0x3C, 0xFD, 0xD4, 0xE0, 0x16, 0x67, 0x42, 0x6F, 0x18, 0x8A, 0x17, 0xE5, 0x12,
                                    0xBE, 0x4E, 0xC4, 0xD6, 0xDA, 0x9E, 0xDE, 0x49, 0xA0, 0xFB, 0xF5, 0x8E, 0xBB, 0x2F, 0xEE, 0x7A,
                                    0xA9, 0x68, 0x79, 0x91, 0x15, 0xB2, 0x07, 0x3F, 0x94, 0xC2, 0x10, 0x89, 0x0B, 0x22, 0x5F, 0x21,
                                    0x80, 0x7F, 0x5D, 0x9A, 0x5A, 0x90, 0x32, 0x27, 0x35, 0x3E, 0xCC, 0xE7, 0xBF, 0xF7, 0x97, 0x03,
                                    0xFF, 0x19, 0x30, 0xB3, 0x48, 0xA5, 0xB5, 0xD1, 0xD7, 0x5E, 0x92, 0x2A, 0xAC, 0x56, 0xAA, 0xC6,
                                    0x4F, 0xB8, 0x38, 0xD2, 0x96, 0xA4, 0x7D, 0xB6, 0x76, 0xFC, 0x6B, 0xE2, 0x9C, 0x74, 0x04, 0xF1,
                                    0x45, 0x9D, 0x70, 0x59, 0x64, 0x71, 0x87, 0x20, 0x86, 0x5B, 0xCF, 0x65, 0xE6, 0x2D, 0xA8, 0x02,
                                    0x1B, 0x60, 0x25, 0xAD, 0xAE, 0xB0, 0xB9, 0xF6, 0x1C, 0x46, 0x61, 0x69, 0x34, 0x40, 0x7E, 0x0F,
                                    0x55, 0x47, 0xA3, 0x23, 0xDD, 0x51, 0xAF, 0x3A, 0xC3, 0x5C, 0xF9, 0xCE, 0xBA, 0xC5, 0xEA, 0x26,
                                    0x2C, 0x53, 0x0D, 0x6E, 0x85, 0x28, 0x84, 0x09, 0xD3, 0xDF, 0xCD, 0xF4, 0x41, 0x81, 0x4D, 0x52,
                                    0x6A, 0xDC, 0x37, 0xC8, 0x6C, 0xC1, 0xAB, 0xFA, 0x24, 0xE1, 0x7B, 0x08, 0x0C, 0xBD, 0xB1, 0x4A,
                                    0x78, 0x88, 0x95, 0x8B, 0xE3, 0x63, 0xE8, 0x6D, 0xE9, 0xCB, 0xD5, 0xFE, 0x3B, 0x00, 0x1D, 0x39,
                                    0xF2, 0xEF, 0xB7, 0x0E, 0x66, 0x58, 0xD0, 0xE4, 0xA6, 0x77, 0x72, 0xF8, 0xEB, 0x75, 0x4B, 0x0A,
                                    0x31, 0x44, 0x50, 0xB4, 0x8F, 0xED, 0x1F, 0x1A, 0xDB, 0x99, 0x8D, 0x33, 0x9F, 0x11, 0x83, 0x14
                                };
    
    void init() {    
        int enteredLoginLen = strlen(enteredLogin);
    
        memset(buff, 0, BUFF_SIZE);
    
        memset(buff + 0x44, enteredLoginLen, 1);
    
    	memcpy(buff + 0x10, enteredLogin, enteredLoginLen);
    	memset(buff + 0x10 + enteredLoginLen, (0x10 - enteredLoginLen) & 0xFF, (0x10 - enteredLoginLen) & 0xFF);
    }
    
    void f(unsigned int off1, unsigned int off2, unsigned res_off) {
        unsigned char tmp[4];
        unsigned char tmp1[4];
    
        memcpy(tmp, buff + off1, 4);
        memcpy(tmp1, buff + off2, 4);
    
        int i;
        for(i = 0; i < 4; i++){
            tmp[i] ^= tmp1[i];
        }
    
        memcpy(buff + res_off, tmp, 4);
    }
    
    // need to add to off's - i....
    void f1(unsigned int off1, unsigned int off2, unsigned char *byte) {
        // byte - edx; i - edi
    //    unsigned char debug_byte;
    
        unsigned char tmp_byte_1;               // ecx
        unsigned char tmp_byte_2;               // eax
    
        tmp_byte_1 = *(buff + off1);
        tmp_byte_2 = *(buff + off2);
    
        (*byte) ^= tmp_byte_1;
    
    //    debug_byte = *(buff403080 + *byte);
    
        tmp_byte_2 ^= *(buff403080 + *byte);
    
        *(buff + off2) = tmp_byte_2;
    
        *byte = tmp_byte_2;
    }
    
    // need to add to off's - i....
    void f2(unsigned int off, unsigned char *byte) {
        unsigned char tmp_byte_2 = *(buff + off); // ebx
        *byte = *(buff403080 + *byte);
        *byte ^= tmp_byte_2;
        *(buff + off) = *byte;
    }
    
    void cryptBuffer() {
        f(0x10, 0, 0x20);
        f(0x14, 0x4, 0x24);
        f(0x18, 0x8, 0x28);
        f(0x1c, 0xC, 0x2c);
    
        unsigned char byte = *(buff + 0x3f);    // edx
    
        int i = -24;                            // edi
        do {
            f1(i + 0x28, i + 0x48, &byte);
            f1(i + 0x29, i + 0x49, &byte);
            f1(i + 0x2a, i + 0x4a, &byte);
            f1(i + 0x2b, i + 0x4b, &byte);
    
            i += 4;
    
        } while(i);
    
        byte = 0;
        i = -48;
        unsigned char j = 0;
    
        do {
            do {
                f2(i + 0x30, &byte);
                f2(i + 0x31, &byte);
                f2(i + 0x32, &byte);
                f2(i + 0x33, &byte);
    
                i += 4;
            } while(i);
    
            byte += j;
            j++;
            byte &= 0xff; // there is no any sense...
            i = -48;
        } while(j != 18);
    }
    
    void f_00401bf4() {
        cryptBuffer();
    
        memcpy(buff + 0x10, buff + 0x30, 0x10);
    
        cryptBuffer();
    }
    
    void f_00401620(int addr) {
    	signed int i;
    	int byte;
    
    	i = -1;
    	do
    	{
    		++i;
    		byte = *(BYTE *)(i + addr);
    		*(BYTE *)(i + encryptedSerial) = byte;
    	} while ( byte );
    }
    
    int main(void)
    {
        init();
    
        f_00401bf4();
    
        typedef int (__stdcall *calcfunc)(DWORD);
            
        HMODULE lib = LoadLibraryA("keygenme.dat");
        if (!lib) {
           printf("lib not loaded\n");
           return 1;
        }
        
        calcfunc calc = (calcfunc) GetProcAddress(lib, "calc");
        if (!calc) {
           printf("func address bad...\n");
           return 1;
        }        
    
    	DWORD addr = (DWORD)(&buff[0]);
    
        calc(addr);
     	
    	__asm {
    		mov addr, esi
    	}
    	
    	f_00401620(addr);
                    
        FreeLibrary(lib);
    
    	// translate encrypted buffer to string...
    	char serial[SERIAL_SIZE];
    
    	unsigned int i;
    
    	for (i = 0; i < ENCRYPTED_SERIAL_SIZE; i++) {
    		char currByte = encryptedSerial[i];
    		char tmp;
    
    		tmp = ((currByte & 0xF0) >> 4) + 55;
    		tmp -= (tmp < 0x40 ? 7 : 0);
    		serial[2 * i] = tmp;
    
    		tmp = (currByte & 0x0F) + 55;
    		tmp -= (tmp < 0x40 ? 7 : 0);
    		serial[2 * i + 1] = tmp;
    	}
    
    	for (i = 0; i < SERIAL_SIZE; i++) {
    		printf("%c", serial[i]);
    	}
    	printf("\n");
    
    	system("PAUSE");
        return 0;
    }
    На этом все! Спасибо за внимание! Если у кого есть еще какие-то вопросы, то пишем сюда буду пробовать отвечать ;)

    И, да, root, наверно, надо все таки все, что касается этого keygen'a перенести в соотвесвующий раздел, а то я был уверен, что это crackme :D Но все мы ошибаемся, особенно, когда находимся вначале пути ;)

    Оффтоп

  8. #5
    ARCHANGEL's Avatar

    Default Re: Решения Easy Crackme

    Так а чего последний косяк не исправили? Или вы выбрали Release сборку, и ошибка исчезла?
    Добрым быть просто - достаточно обратить свой гнев на негодяев...

  9. #6

    Default Re: Решения Easy Crackme

    Выбрал Release сборку и она куда-то пропала.... и в Debug сборке тоже...

    При том, что раньше я делал в 2008 студии (на ноуте стоит), а на ПК - 2010. И вот на ПК все норм работало...
    Last edited by coldfire; 23-03-2013 at 21:35.

  10. #7
    ARCHANGEL's Avatar

    Default Re: Решения Easy Crackme

    Ну, компилятор чуток по-другому код пересобрал, и, видать, прокатило. Странно, что имя жёстко забито, и его задавать нельзя, а так - работает, и слава богу ))
    Добрым быть просто - достаточно обратить свой гнев на негодяев...

  11. #8

    Default Re: Решения Easy Crackme

    Quote Originally Posted by ARCHANGEL View Post
    Ну, компилятор чуток по-другому код пересобрал, и, видать, прокатило. Странно, что имя жёстко забито, и его задавать нельзя, а так - работает, и слава богу ))
    Почему же, можно задать другое имя только для этого надо будет пересобрать всё =)

+ Reply to Thread

Tags for this Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
All times are GMT. The time now is 01:33
vBulletin® Copyright ©2000 - 2018
www.reverse4you.org