Задача #3: Взломай Keygenme

_MBK_

Ветеран
Новичок
Сообщения
157
Реакции
30
Алгоритм генерации ключа откровенно дурацкий.
На первый взгляд, от строки зависят только два байта хэша, которые подбираются мгновенно.
Это что, реально бугай накодил, дабы впарить доверчивым школьнегам?
 
Последнее редактирование:

DX0

Постоянный
Новичок
Сообщения
62
Реакции
4
Вот мой код кейгена на С:
Код:
#include <stdio.h>
#include <math.h>
#include <time.h>

// Author: Vlados(DX0)

unsigned int rol(unsigned int a, unsigned int n) {
    return (a << (n % 32)) | (a >> (32 - (n % 32)));
}
unsigned int ror(unsigned int a, unsigned int n) {
    return (a >> (n % 32)) | (a << (32 - (n % 32)));
}

void main() {
    char buf_ser[32] = { 0 };
    unsigned int res, len, *sum_ptr, hash;
    unsigned char sum[4] = { 0 };
    unsigned char tmp_res[4] = { 0 };
    float f_res;
    char* alphabet = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";

    srand(time(0));

    do {
        f_res = 0.f;
        sum_ptr = (unsigned int*)sum;
        *sum_ptr = 0;


        len = 1 + (rand() % (sizeof(buf_ser) - 1));
        for (int i = 0; i < len; i++) {
            buf_ser[i] = alphabet[rand() % strlen(alphabet)];
            buf_ser[i + 1] = 0;
        }

        for (int i = 0; i < len; i++)
            sum[0] += (buf_ser[i] % 0x0B);
    
        for (int i = 0; i < len; i++) {
            res = (i + 1) & 0x80000001;
            if (res < 0)
                res = ((res - 1) | 0xFFFFFFFE) + (res + 1);
            if (!res)
                sum[2] += (buf_ser[i] % 0x21);
            else
                sum[2] += ((buf_ser[i] % 0x17) << 2);
        }
        res = (((len * len) & 0x0000FFFF) + 0x60) - 0x4B;
        res = (res & 0x000000FF) << 2;
        res += (res * 2);
        f_res = res;
        f_res = f_res / 11.0;
        f_res = round(f_res);
        res = f_res;
        sum[1] = res;
        res = sum[0] * sum[1] * sum[2];

        sum[3] = res;

        sum_ptr = (unsigned int*)sum;
        *sum_ptr = rol(*sum_ptr, 3);

        for (int i = 0; i < 5; i++) {
            tmp_res[0] = (((sum[0] + sum[3]) % 0xFE) + 1);
            tmp_res[1] = (((sum[0] + sum[1]) % 0xFC) + 3);
            tmp_res[2] = (((sum[1] + sum[2]) % 0xF0) + 0x0E);
            tmp_res[3] = (((sum[2] + sum[3]) % 0xE9) + 0x14);

            sum[0] = tmp_res[3];
            sum[1] = tmp_res[0];
            sum[2] = tmp_res[1];
            sum[3] = tmp_res[2];
        }
        sum[0] += 0x13;
        sum[1] += 0x0B;

        tmp_res[0] = sum[0] - sum[3];
        tmp_res[1] = tmp_res[0] + (sum[1] - sum[2]);
        tmp_res[2] = sum[3] - sum[2];
        tmp_res[3] = sum[3] - tmp_res[1];

        sum[0] = tmp_res[0];
        sum[1] = tmp_res[3];
        sum[2] = tmp_res[1];
        sum[3] = tmp_res[2];

        sum_ptr = (unsigned int*)sum;
        res = *sum_ptr * *sum_ptr;
        hash = res % 0xFCFDFEFA;

    } while (hash != 0xD46E1384);

    printf("Serial code: %s",buf_ser);

    getchar();

    return;
}
 

Прикрепленные файлы:

Последнее редактирование:

_MBK_

Ветеран
Новичок
Сообщения
157
Реакции
30
А в чем разница???
У вас тоже брут, как я погляжу, причем, каждый раз случайная длина строки, полнейший фейспалм по оптимизации.
 

DX0

Постоянный
Новичок
Сообщения
62
Реакции
4
А в чем разница???
У вас тоже брут, как я погляжу, причем, каждый раз случайная длина строки, полнейший фейспалм по оптимизации.
Дк, правильно, это как брут. Дело в том, что я показал способ как быстро найти длину серийника, когда не знаешь длину серийника.
А так это кейген! ;)
 

DX0

Постоянный
Новичок
Сообщения
62
Реакции
4
Писал на скорую руку, так что тут извиняйте! :cool:
 

_MBK_

Ветеран
Новичок
Сообщения
157
Реакции
30
Дк, правильно, это как брут. Дело в том, что я показал способ как быстро найти длину серийника, когда не знаешь длину серийника.
А так это кейген! ;)
Почему не знаешь? По закону сохранения информации 32битный хэш вполне себе исчерпывается пятисимвольными наборами из 7битных символов. Фиксируем 5 символов и подбираем 16битный хэш, потом по готовому 16битному хэшу и саму пятисимвольную строку. Конечно есть вероятность невозможной комбинации, но она исчезающе мала.
 

OKOB

Постоянный
Победители турниров
Финалисты турниров
Мудрец
Сообщения
66
Реакции
518
Почему не знаешь?
Потому что накрутил преобразований на коленке и какая там теория про битность хэшей. Особенно радует наличие не только целочисленной математики. :eek: Что такое употреблять нужно чтобы так колбасило.
 

_MBK_

Ветеран
Новичок
Сообщения
157
Реакции
30
Я тоже удивился какая сакральная необходимость была делать нецелочисленное деление с округлением?
 

DX0

Постоянный
Новичок
Сообщения
62
Реакции
4
Я тоже удивился какая сакральная необходимость была делать нецелочисленное деление с округлением?
Дело в том, что когда целое число делится на 0x11, то получается дробная часть и это дробная часть и есть хитрый трюк при округлении.
Можете, если кому интересно, загрузить крекми в отладчик и там будет все понятно на этом участке кода.
На счет защиты я ее не придумывал, я лишь написал кейген, который работает и выдает правильные серийники.

Например, если мы разделим 0x39(57) / 0x0B(11) = 5.18 и функция round выполняет округление до ближайшего целого, то есть будет 5. Если 0x1F(31) / 0x0B(11) = 2.81 , то при round мы получим 3.
 
Последнее редактирование:

_MBK_

Ветеран
Новичок
Сообщения
157
Реакции
30
Там, вообще, то не 0х11 а 11.0, ну да не суть важно. Функция round зависит от реализации и результат может получиться весьма неожиданным
 

Mystery

Зарегистрированный
Сообщения
6
Реакции
1
Дк, правильно, это как брут. Дело в том, что я показал способ как быстро найти длину серийника, когда не знаешь длину серийника.
А так это кейген! ;)
Ест..но рандомизация быстрее)
Всё, видяхи не будет?
 

DX0

Постоянный
Новичок
Сообщения
62
Реакции
4

_MBK_

Ветеран
Новичок
Сообщения
157
Реакции
30
Ест..но рандомизация быстрее)
С какого перепугу? Длинные строки обрабатываются дольше коротких, вдобавок, какой смысл каждый раз считать полный 32битный хэш от всей строки, когда можно считать короткий 16битный?
 

Mystery

Зарегистрированный
Сообщения
6
Реакции
1
С какого перепугу? Длинные строки обрабатываются дольше коротких, вдобавок, какой смысл каждый раз считать полный 32битный хэш от всей строки, когда можно считать короткий 16битный?
Да.
Всё зависит от длины пароля и результата который тебе нужен. Если серийник не длинный можно сбрутить - получим список не повторяющихся кодов. Если же длинный на это уйдёт много времени.
В других кейгенах всё таки буду использовать метод рандома (A..Z,a..z,0..9). т.к. цель у меня найти 2-3 серийника с неизвестной длиной пароля? Считаю такой вариант быстрее.
По части проверки 16 битного хэш может DX0 прокомментирует. У меня привычка использовать полную проверку.
 

_MBK_

Ветеран
Новичок
Сообщения
157
Реакции
30
Вы, похоже, не поняли то, что я вам третий день обьясняю.
Давайте повторим еще раз и помедленнее.
1. Количество информации в 32битном хэше примерно такое же, как и во всем множестве пятисимвольных строк младшей части кодовой таблицы, а значит, достаточно перебирать их
2. В алгоритме присутствует бутылочное горлышко - собственно от строки зависит только 16 бит хэша, то есть все множество паролей, описываемое хэшем еще меньше, но есть байт, зависящий только от длины пароля.
3. Исходя из всего этого алгоритм (даже если не заморачиваться на полный реверс, хотя он настолько тупорыл, что, скорее всего, и прямой реверс возможен) оптимизируется до поиска 16битного хэша, что на несколько порядков быстрее чем дуболомный перебор строк с рандомной длиной.
Я понятно излагаю или чтото обьяснить еще подробнее?
 

Mystery

Зарегистрированный
Сообщения
6
Реакции
1
1. Любой хэш получаем из каких-либо вычислений, что не доказывает строку(серийник) длиной в 5 символов. Ограничиваете себя в длине искомого серийника.
2.3. - Оптимизация. Конечно нужная вещь.:geek:(y)

Задача так или иначе решена.
 

_MBK_

Ветеран
Новичок
Сообщения
157
Реакции
30
Любой хэш получаем из каких-либо вычислений, что не доказывает строку(серийник) длиной в 5 символов. Ограничиваете себя в длине искомого серийника.
Не совсем понимаю семантики вашей мысли, но попытаюсь еще раз обьяснить свою.
Количество неповторяющихся строк с разными хэшами равно два в тридцать второй степени - тут возражений нет, надеюсь? Разумеется, из этого не следует, что все неповторяющиеся хэши будут сидеть компактно в самом начале множества перебираемых строк. Однако, при равномерном распределении хэшей по данному множеству любая выборка из два в тридцать второй степени строк будет содержать практически все хэши, во всяком случае, бОльшую их часть. Количество же вариантов байта, зависящего просто от длины совсем небольшое (мы даже не 255символьные строки подбираем) Отсюда, стратегия оптимизации следующая - фиксируем значение длины равным пяти (как наиболее вероятное в смысле количественного охвата) и подбираем 16битный хэш исходя из контрольной суммы. Как только 16битный хэш найдется, уже по нему подбираем пятисимвольные строки. Вероятность непопадания в данном случае ничтожна, ибо количество неповторяющихся пятисимвольных строк очень сильно больше, чем два в шестнадцатой степени.
Теперь все понятно или какой то момент обьяснить дополнительно?
 
Верх Низ