+ Reply to Thread
Results 1 to 2 of 2

Thread: CrackMe by Fereter #2[разбор и написание KeyGen]

  1. #1
    theoretic's Avatar

    Default CrackMe by Fereter #2[разбор и написание KeyGen]

    В этой статье мы рассмотрим решение CrackMe by Fereter #2. Скачать его можно здесь.
    Не беря во внимание названия файла, фактически - это КейГенМи.
    Уровень: Для начинающих.
    Используемые инструменты:
    IDA Pro как дизассемблер и деббагер.
    х64dbg
    плагин Labeless(импортирует метки и имена с IDA Pro в х64dbg)
    Задача: найти и разобрать алгоритм валидации пары Name : Serial key и написать Генератор Ключей.

    Посмотрим на сам КрекМи:

    Базовый статистический анализ с помощью PEview и Peid ничего интересного не показал.
    Загружаем в IDA Pro и начнем углубленный статический анализ и динамический анализ.

    1. Анализируем строки
    В окне программы мы видим следующие строки:
    «CrackMe by Fereter #2», «Name», «Serial key», «Unregistered», «Check», «Exit»
    В IDA Pro в закладке String window(View>Open subviews>Strings) видим только:
    «Made in Russia»

    Можно сделать предположение, что программа содержит строки GUI-окна в зашифрованном виде - в процессе работы их расшифровывает.
    Если начать деббажить та увидим, что перед началом каждого WinApi вызова, который берет на вход строку как один из аргументов, вызывается sub_402590 , а после выполнения WinApi_вызова, вызывается sub_40257E, ниже на рисунке пример

    Проанализируем, что это за функции.

    Это функции XOR расшифровывания и зашифровывания строк, в который в качестве ключа используется байтовое значение C6h, а указатель на строку передается в функции через регистр EAX
    Переименовываем эти функции соответственно как XorDecode и XorEncode.
    Дальше-больше, локализуем и расшифруем строки которые использует XorDecode.
    Сначала смотрим адреса, где XorDecode вызывается (IDA Pro > переходим на листинг XorDecode > Правый клик мыши > List crossreferences to...)

    Смотрим адреса которые XorDecode использует в качестве аргумента передаваемого через регистр EAX - все они находятся в диапазоне 00401000 - 00401073

    Посмотрим на них в HEX-редакторе

    Можно наблюдать, что очень часто встречается байт C6h, который равен нашему ключу шифрования с функций XorDecode и XorEncode что говорит о том что перед нами зашифрованы массив ноль-терминированных(NULL-terminated) строк, так как C6h XOR 00h = C6h.

    Теперь расшифровываем, чтобы посмотреть содержимое этого массива и сформировать массивы и присвоить им имена в IDA Pro. Для этого используем XOR idc script отсюда:

    В итоге было:

    То что мы сделали после расшифровки:

    Теперь снова зашифруем (ведь наша цель была сформировать структуры данных(строки) и присвоить им имена отражающие их содержимое, а не изменять бинарный файл)

    В итоге видим полный набор строк которые использует программа.

    2. Анализируем функции
    В начале недалеко от start видим RegisterClassA вызов, который берет на вход структуру WNDCLASS

    Рассмотрим эту структуру:

    Видим offset sub_4021B7 - это WNDPROC lpfnWndProc (см.MSDN) обработчик сообщений посылаемых окну
    Благополучно переименовываем sub_4021B7 на fnWndProc.
    Из оставшихся функции с наскока можно понять, что делает sub_40254A

    Подсчитывает 8-битную контрольную суму строки, указатель на которую содержится в регистре EBX, и результат сохраняет в регистре DL. Переименовываем sub_40254A на ByteControlSumm.
    А также sub_4025A2

    Переименовываем sub_4025A2 на ClearEAX.

    В итоги имеем следующее окно функций


    3. Анализируем поток программы
    функция start как и в любой другой GUI-программе содержит Message Loop, в который вставлены некоторые средства анти-отладки:

    В 1-ом и 3-ем случае сканирование в цикле кода на наличие INT3(0xCC), во 2-ом на наличие NOP(0x90). Думаю элегантным решением будет заменить на NOP-ы инструкции условного переход jz (short)end_program
    В итоге получаем:

    Есть одно средство анти-деббагина, которое обходиться любым плагином типа IDAStealth, ScyllaHide


    Ура, товарищи!, мы обошли средства анти-деббагинга.

    4. Анализируем нашу функцию-обработчик сообщений(ивентов) fnWndProc

    Первая проверка сравнивает аргумент MSG с единицей(1==WM_CREATE). Далее ветвление направо на блок создания GUI окна программы. Все что нам нужно с этого блока - это идентификатор кнопки «CHECK». А вот и он


    Ветвление на лево ведет нас к блоку, где сравнивается аргумент MSG с 111h (111h==WM_COMMAND) - это то, куда мы двигаемся далее loc_4023F2

    Вот тут и начинается обработка нашего нажатия на кнопку «Check»


    5. Анализируем нашу обработку нажатия на кнопку «Check»
    анализируем sub_402557 видим, что фактически это обертка функции SendMessageA. Переименовываем ее как SendMessageAWrapper.

    Видим как извлекается ввод полей Name, Serial key.
    И, внимание, проверка № 1 сравнивается длина ввода поля Serial key с числом 11.
    Если не равно, то осуществляется прыжок на loc_40253А(это епилог(окончание) функции fnWndProc)

    Далее идут проверки на соответствие введенного имени и серийного ключа. Рассмотрим их.

    проверка № 2 - см. псевдокод на рисунке выше
    проверка № 3 - см. псевдокод на рисунке выше
    Следующий блок:

    проверка № 4 - см. псевдокод на рисунке выше
    проверка № 5 - см. псевдокод на рисунке выше

    Теперь рассмотрим sub_402541 что это за зверь такой?
    Это зверь в середине себя содержит две проверки.
    uint8_t serialKeyControlSumm = ByteControlSumm(serialKey); # см. предпоследний рисунок
    проверка № 6: # см. последний рисунок
    if ( serialKeyFieldInput[6] == serialKeyControlSumm/9%9 + 30h)
    проверка № 7: # см. последний рисунок
    if ( serialKeyFieldInput[5] == serialKeyControlSumm%9 + 30h)

    И вот финал.
    Алгоритм валидации пары Name : Serial key на псевдокоде выглядит так:

    var name;
    var serialKey;
    var nameControlSumm;
    var serialKeyControlSumm;

    GetInput(name);
    GetInput(serialKey);

    nameControlSumm = ByteControlSumm(Name);
    serialKeyControlSumm = ByteControlSumm(serialKey);

    if( serialKey.length == 11
    && serialKey[0] == NameControlSumm%9 + 30h
    && serialKey[1] == NameControlSumm/9%9 + 30h
    && serialKey[3] == '-'
    && serialKey[7] == '-'
    && serialKey[5] == serialKeyControlSumm%9 + 30h
    && serialKey[6] == serialKeyControlSumm/9%9 + 30h
    ) {
    Registered();
    } else {
    Unregistered();
    }


    P.S.: Исходники самого КейГен(уже готов) - приведу в красивый вид и выложу в ближайшее время

    P.P.S.: Комментарии, замечания, вопросы, предложения приветствуются,
    возможно, вы бы делали что-то иначе - в общем прошу комментировать
    Last edited by theoretic; 17-05-2017 at 21:29.

  2. 4 пользователя(ей) сказали cпасибо:
    Darwin (17-05-2017) Shizoid (17-05-2017) korsader (17-05-2017) ximera (19-05-2017)
  3. #2
    theoretic's Avatar

    Default

    исходный код Генератора Серийников
    Attached Files

+ Reply to 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 06:23
vBulletin® Copyright ©2000 - 2017
www.reverse4you.org