[ Путеводитель по написанию вирусов: 6. Шифрование ]

 Техники шифрования весьма стары, но они еще эффективны и часто используются. Вероятно, это одна из тех концепций, 
которые могут жить годами, хотя бы и с постоянными усовершенствованиями, такими как полиморфизм, метаморфизм и тому 
подобное. Hашей целью является скрыть все текстовые строки, подозрительные опкоды и все остальное в этом роде от 
глаз пользователя. Мы можем сделать это с помощью простой математической операции, которую применим ко всем байтам 
тела вируса. Например мы можем увеличить все байты нашего вируса на один, после чего не сможем найти ни одной 
читабельной текстовой строки в нашем вирусе :).

Структура зашифрованного вируса следующая:

         +-----------------------------------+      Это очень просто. Сначала
       +-¦         Вызов декриптора          ¦      идет   вызов  декриптора,
       ¦ +-----------------------------------¦<---+ после   того,   как   тот

       ¦ ¦                                   ¦    ¦ заканчивает  свою работу,

       ¦ ¦                                   ¦    ¦ он   передает    контроль
       ¦ ¦         Зараженный файл           ¦    ¦ вирусу,  а  тот  в  конце
       ¦ ¦                                   ¦    ¦ концов передает программе
       ¦ ¦                                   ¦    ¦ контроль.
       ¦ +-----------------------------------¦<-+ ¦

       ¦ ¦                                   ¦  ¦ ¦

       ¦ ¦           Тело вируса             ¦  ¦ ¦
       ¦ ¦                                   ¦  ¦ ¦

       +>+-----------------------------------¦----+

         ¦            Декриптор              ¦  ¦
         +-----------------------------------+--+

Есть математическая операция, которая даст нам одно преимущество. Мы можем использовать одну процедуру для шифрования и 
расшифровки нашего кода. Конечно, мы говорим о XOR, наиболее используемой инструкции для дескрипторов. Есть еще две 
инструкции, которые могут быть использоваться как для шифрования, так и для расшифровки: NOT и NEG. Наиболее часто 
используемая из этих двух - это первая. Разумеется, мы можем использовать для шифрования гораздо больше инструкций. 
Я покажу вам небольшой список инструкций, которые мы можем использовать:

 INC/DEC, ADD/SUB, ROL/ROR, XOR, NOT, MUL/DIV, ADC/SBB, etc...

Самый простой путь зашифровать наш вирус - это использовать следующую процедуру:

 encryption:

        mov     cx,encrypt_size         ; encrypt_end-encrypt_start

        mov     di,[bp+encrypt_begin]   ; Откуда

        mov     si,di                   ; Для lodsb/stosb

        mov     ah,key                  ; Значение для XOR. key может быть

                                        ; таким, каким вам угодно.



 encryption_loop:

        lodsb                           ; Двигаем байт из DS:SI в AL

        xor     al,ah

        stosb                           ; Двигаем байт из AL в ES:DI

        loop    encryption_loop

        ret

Это не очень хорошая процедура. Она дает всего лишь 255 вариантов, так как мы работаем с 8-ми байтным регистром в 
качестве ключа (AH).

Конечно, это самый простой путь. Мы должны обратить внимание на следующее:

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

- Мы должны позаботиться о состоянии вируса в его первом поколении: когда он не зашифрован. Если мы используем xor, 
то для этой целью можем воспользоваться значением 00 в первом поколении, а затем специальная процедура поменяет 
это значение в коде, или просто избежать запуска шифрующей процедуры в первом поколении.

А теперь мы посмотрим, как можно адаптировать вышеприведенную процедуру, если использовать в качестве ключа 16-ти 
битный ключ.

 encryption:

        mov     cx,(encrypt_size+1)/2   ; encrypt_end-encrypt_start/2

        mov     di,[bp+encrypt_begin]   ; Откуда

        mov     si,di                   ; Для lodsb/stosb

        mov     dx,key                  ; Значение для XOR. key может быть

                                        ; таким, каким вам угодно.

 encryption_loop:

        lodsw                           ;

        xor     ax,dx                     Двигаем байт из DS:SI в AL

        stosw                           ;

        loop    encryption_loop           Двигаем байт из AL в ES:DI

        ret

Проблема следующая: если мы оставим процедуру копирования и криптор незашифрованными... то что сделают AVеры? У них 
есть наш вирусы, на который было затрачено столько усилий (да, да, у нас ушло столько времени и труда, чтобы сделать 
его антиэвристичным, невидимым, со множество крутых примочек...), сканстроку, достаточно длинную, чтобы добавить ее в 
свои антивирусы. За пять минут они реализуют алгоритм для обнаружения нашего вируса. Аррх! VXер потратил несколько дней, 
чтобы создать достойный вирус, а из-за того, что он использовал простой криптор вроде этого, за 5 минут наши враги нашли 
путь свести все его усилия на нет! Этот мир дерьмово устроен! :(

Hо VXеры никогда не сдаются, поэтому... Hам нужно сделать декриптор настолько малым, насколько это возможно. В следующей 
главе вы найдете лучших из возможных ответов :).

Как у нас может быть вторая копия нашего вируса в памяти? Это очень просто. После метки, которая указывает на последний 
байт, который скопирует наш вирус, у нас должно быть что-то вроде следующего:

 virus_end      label   byte            ; Метка, указывающая на последний байт



 enc_buffer     db      (offset virus_end-offset virus_start) dup (090h)

В переменной enc_buffer будет код только в первом поколении. Когда мы распространяем вирус, эта переменная не будет 
копироваться вместе с ней. Hо мы можем использовать ее смещение, чтобы бы мы могли поместить туда вторую копию вируса. 
Мы делаем следующее:

- Когда мы копируем наш вирус в память (если он резидентный), делаем это в другой раз, а также когда мы помещаем код в 
заголовок EXE или первые байты COM'а, мы помещаем их по тому же смещению, где должны находиться эти переменные, 
сдвинутые на размер вируса. Ок, я объясню это лучше. Представьте, что у нас есть что-то вроде следующего:

        mov     ah,3Fh

        mov     cx,4

        lea     dx,old3bytes

        int     21h

Хорошо. Теперь, если у нас есть вторая копия вируса в памяти, мы должны заменить третью линию на примерно следующее:

        lea     dx,virus_size+old3bytes

Лучший путь - это поэкспериментировать с этим...

- Или мы можем скопировать тело вируса непосредственно перед добавлением вируса: у нас есть весь набор переменных. 
Перемещение будет выглядеть примерно так:

        mov     cx,virus_size

        xor     si,si

        mov     di,offset virus_begin

        rep     movsb

Мы зашифровали ее, добавили эту вторую копию и... вот и все, ребята!


(c) Billy Belcebu, пер. Aquila