1. Вы находитесь в архивной версии форума xaker.name. Здесь собраны темы с 2007 по 2012 год, большинство инструкций и мануалов уже неактуальны.
    Скрыть объявление

Самомодификация как средство защиты своих программ - часть 2

Тема в разделе "Исследование софта на уязвимости, crackme", создана пользователем Dr. MefistO, 1 фев 2012.

  1. Dr. MefistO

    Dr. MefistO Крывіч Глобальный модератор

    Регистрация:
    3 авг 2008
    Сообщения:
    152
    Симпатии:
    254
    Баллы:
    0
    [​IMG]

    Привет всем!

    Надеюсь, вы успешно прочитали и осилили предыдущую статью о самомодификации?!) Если да, пойдем дальше, и займемся простеньким шифрованием кода какой-нибудь процедуры. Ну а если нет - не бойтесь задавать вопросы - постараюсь ответить)

    Инструментарий:
    • Delphi 7 Lite (для написания приложений) + KOL;
    • Olly Debugger v2 (для анализа кода);
    • Hex Workshop - для модификации процедуры на побайтовом уровне.

    Часть II: защита исполняемого кода от декомпиляторов

    Итак, приступим.
    Допустим, нам надо защитить код процедуры WriteValues из предыдущей статьи, чтобы реверсер не мог увидеть ее исходного кода (а вдруг у нас там процедура проверки ключа).
    Код:
    [COLOR="Navy"]procedure[/COLOR] WriteValues;
    [COLOR="Navy"]var[/COLOR]
      i: Byte;
    [COLOR="Red"]begin[/COLOR]
      [COLOR="DarkOrange"]for[/COLOR] i:=[COLOR="Blue"]1[/COLOR] to [COLOR="Blue"]10[/COLOR] [COLOR="DarkOrange"]do[/COLOR]
      Writeln(i);
    [COLOR="Red"]end;[/COLOR]
    Для начала, выберем алгоритм шифрования. Пускай это будет обычный XOR с любым байтом (я выбрал $AB). Предположим, что мы уже зашифровали процедуру. Как мы будем ее расшифровывать?

    Приблизительный алгоритм:
    1. Получить зашифрованный байт процедуры;
    2. Поксорить его с $AB (т.к. операция обратимая, т.е. как шифруем, так и расшифровываем);
    3. Записать на место прежнего байта.

    Напишем код расшифровки. Для этого нам нужно определить - сколько байт мы будем расшифровывать. Для этого глянем на картинку из предыдущей статьи, и посчитаем количество байт в дампе памяти (от первого до последнего байта процедуры):
    [​IMG]

    Получилось 53 байта, или $35 в хексе. Изменим соответствующим образом VirtualProtect:
    Код:
      [COLOR="Navy"]VirtualProtect[/COLOR](
      Pointer(base), [COLOR="DarkGreen"]//передаем указатель на модифицируемый байт[/COLOR]
      53,             [COLOR="DarkGreen"]//количество изменяемых байт исправлено на 53[/COLOR]
      PAGE_EXECUTE_READWRITE,  [COLOR="DarkGreen"]//режим чтения-записи в память[/COLOR]
      OldPageProtection        [COLOR="DarkGreen"]//в эту переменную мы сохраняем старый режим[/COLOR]
      );
    Расшифровывать мы будем с первого байта, поэтому offset будет равен нулю:
    Код:
    offset:=[COLOR="Blue"]0[/COLOR];
    Действия будут выполняться в цикле от первого до последнего байта, поэтому объявим переменную для счетчика:
    Код:
    i: Byte;
    Теперь вместо:
    Код:
    base^:=[COLOR="Blue"]101[/COLOR];
    нам нужно написать сам цикл. Он будет выглядеть следующим образом:
    Код:
      [COLOR="Red"]for[/COLOR] i:=[COLOR="Blue"]1[/COLOR] to [COLOR="Blue"]53[/COLOR] [COLOR="Red"]do[/COLOR]
      [COLOR="Red"]begin[/COLOR]
      base^:=base^ [COLOR="Navy"]xor[/COLOR] [COLOR="Blue"]$AB[/COLOR]; [COLOR="DarkGreen"]//считываем байт процедуры и ксорим его с $AB[/COLOR]
      inc(base);           [COLOR="DarkGreen"]//переходим к следующему байту[/COLOR]
      [COLOR="Red"]end[/COLOR];
    Вот и вся процедура расшифровки. Скомпилируем ехешник и засунем в Olly Debugger, перейдем к адресу нашей процедуры, который мы получаем всегда из сообщения:
    Код:
    MsgOK(Int2Hex(Cardinal(@WriteValues),[COLOR="Blue"]8[/COLOR]));
    На первой строчке процедуры щелкните правой кнопкой мыши, и выберите Follow in Dump->Selection. Мы окажемся на том байте дампа памяти, с которого начинается процедура. Необходимо посчитать длину процедуры. Я выделил прямоугольниками байты процедуры:
    [​IMG]

    Выделите их, и нажмите правой кнопкой мыши, а затем: Edit->Binary Copy.
    Запустим хекс-редактор, и вставим туда эти байты. Теперь шифрование.

    Вставьте из буфера обмена в новый файл эти байты (File->New). Жмем меню Tools->Operations->XOR...

    Выставляем настройки так, как на скрине:
    [​IMG]

    И жмем ОК. Копируем новые байты, и вставляем их вместо предыдущих в Oly Debugger: Edit->Binary Paste. Опять жмем правой кнопкой мыши на измененных байтах в дампе, и выбираем меню: Edit->Copy to Executable, а в новом окошке жмем правой кнопкой и пункт меню Save File. Жмем Yes, заменяем исходный файл.

    Анализ выполненного

    Переоткрываем наш измененный файл в Olly Debugger, переходим на адрес процедуры. Видим, что там непонятный набор байт. Попробуем запустить файл на исполнение, и... О ЧУДО! Эта штука работает)

    Привожу исходный код всего проекта:
    Код:
    [COLOR="Navy"]program[/COLOR] test1;
    
    [COLOR="MediumTurquoise"]{$APPTYPE CONSOLE}[/COLOR]
    
    [COLOR="Navy"]uses[/COLOR]
      KOL, windows;
    
    [COLOR="Navy"]procedure[/COLOR] WriteValues;
    [COLOR="Navy"]var[/COLOR]
      i: Byte;
    [COLOR="DarkRed"]begin[/COLOR]
      [COLOR="DarkOrange"]for[/COLOR] i:=1 [COLOR="Navy"]to[/COLOR] 10 [COLOR="DarkOrange"]do[/COLOR]
      Writeln(i);
    [COLOR="DarkRed"]end;[/COLOR]
    
    [COLOR="Navy"]var[/COLOR]
      OldPageProtection: Cardinal;
      base: PByte;
      offset: byte;
      i: byte;
    [COLOR="DarkRed"]begin[/COLOR]
      MsgOK(Int2Hex(Cardinal(@WriteValues),8));
      WriteValues;     [COLOR="DarkGreen"]//первый раз выводим для просмотра результата[/COLOR]
    
      offset:=[COLOR="Blue"]0[/COLOR]; [COLOR="DarkGreen"]//Смещение изменяемого байта относительно начала процедуры[/COLOR]
    
      base := PByte(Cardinal(@WriteValues) + offset); [COLOR="DarkGreen"]//Позиция изменяемого байта[/COLOR]
      VirtualProtect(
      Pointer(base), [COLOR="DarkGreen"]//передаем указатель на модифицируемый байт[/COLOR]
      53,             [COLOR="DarkGreen"]//количество изменяемых байт[/COLOR]
      PAGE_EXECUTE_READWRITE,  [COLOR="DarkGreen"]//режим чтения-записи в память[/COLOR]
      OldPageProtection        [COLOR="DarkGreen"]//в эту переменную мы сохраняем старый режим[/COLOR]
      );
    
      [COLOR="Red"]for[/COLOR] i:=[COLOR="Blue"]1[/COLOR] to [COLOR="Blue"]53[/COLOR] [COLOR="Red"]do[/COLOR]
      [COLOR="Red"]begin[/COLOR]
      base^:=base^ [COLOR="Navy"]xor[/COLOR] [COLOR="Blue"]$AB[/COLOR]; [COLOR="DarkGreen"]//считываем байт процедуры и ксорим его с $AB[/COLOR]
      inc(base);           [COLOR="DarkGreen"]//переходим к следующему байту[/COLOR]
      [COLOR="Red"]end[/COLOR];
    
      VirtualProtect(Pointer(base),[COLOR="Blue"]53[/COLOR],OldPageProtection,OldPageProtection);
    
      WriteValues;    [COLOR="DarkGreen"]//смотрим изменения[/COLOR]
    
      Readln;
    [COLOR="DarkRed"]end.[/COLOR]
    Исходник проекта из статьи

    ----------------------------------------------------------------​

    Автор: Владимир Мефисто
     
    3 пользователям это понравилось.

Поделиться этой страницей