Программы поиска "вирусов"
Реальна ли разработка программы, которая обнаруживает "вирус" до его
распространения и может сообщить об этом или обезопасить этот "вирус"?
Коэн отвечает отрицательно на этот вопрос c обоснованием, котoрое вряд ли
можно использовать в научной работе. Это обоснование выглядит следующим обра-
зом [ср. с 9]:
Если функция F(x) может различить, является ли "x" "вирусом", то
такая функция может быть встроена в программу, которая при F(x)=Тrue
не инициирует активность "вируса", а при F(x)=False - инициирует.
Таким образом можно доказать все и ничего. Для примера, присвоим
переменной "х" значение 5:
Если функция F(x) может отличить, имеет ли "х" значение 5, то эта
функция может быть встроена в программу, которая при F(x)=True присваи-
вает "х" значение 6, а при F(X)=False оставляет значение =5.
Хотя этот способ доказательства очевидно невыполним, все же
необходимо согласиться с основным высказыванием Коэна: Программа поиска
"вируса" может и не существовать. Конечно, по другим причинам.
Как было показано, к основным функциям "вируса" принадлежит его
право на запись, чтение и способность распознавать
состояние программы. Теперь можно попытаться сказать, что все
программы, которые обладают этими функциями, являются потенциальными "виру-
сами". Однако несколько задумавшись над программными функциями, быстро приходят
к заключению, что эти функции присутствуют почти во всех программах.
Кроме того, обращает на себя внимание связь этих функций друг с другом.
Если сделать еще один шаг и попытаться определить эти связи, то
программы, которые читают, изменяют или пишут командные коды - это
потенциальные вирусы. Теперь круг несколько сужается, поскольку число программ,
изменяющих другие программы, относительно невелико. Складывается впечатление,
что таким образом действительно можно выявить вирусы. Однако опять возникают
проблемы, которые вновь сводят на нет достигнутое. Распознавание
функций записи/чтения и их связей между собой в исследуемом программном
обеспечении является хотя и проблематичным, но на
первый взгляд разрешимым. Однако приведенный листинг на псевдоязыке
программирования позволяет выявить возможные трудности:
100 move "ITE"
110 move "WR"
120 jmp 130
130 END
Эта программа, например, при поверхностном контроле не вызвала бы никаких
нареканий. Она загружает две ячейки памяти и, после этого выполняет переход
к ячейке 130, в которой расположена команда END. Кажется безобидная
вещь ! Однако, если присмотреться внимательнее к программе, делается ясно,
что после отработки двух первых команд программа полностью изменяется.
100 move "ITE" ,132
110 move "WR" ,130
120 jmp 130
130 WRITE
Посредством автомодификации команда END в ячейке 130 превращается в
команду WRITE. Разумеется, подобная автомодификация может быть многократно
вложенной. Это означает, что автомодифицируемый код в свою очередь
генерирует новый автомодифицируемый код и т.д.
Таким образом анализ программных кодов не имеет смысла, поскольку
вирус уходит на более глубокие уровни, чем тот, на котором работает
тестирующая программа. Конечно, при необходимости можно осуществить
проверку с помощью интерпретирующей обработки программы, поскольку в этом
случае выполняются все шаги автомодификации. Большим недостатком интерпрети-
рующего метода тестирования является значительное время, необходимое для
того, чтобы выполнить, к примеру 40 Кб машинных кодов с помощью программы
DEBUG в режиме трассировки. Кроме того, может оказаться, что
вирулентная часть программы вообще не выполняется, поскольку она узнает
о тестировании или поскольку не выполняются условия внешней среды: дата,
время и т.д.
Известным примером является система защиты копирования Prolok. Программа,
защищенная с помощью этой системы, располагается на диске в
зашифрованном виде. Декодирование происходит поблочно после загрузки.
Для того, чтобы устранить нежелательные манипуляции, принимают всевозможные
меры, в том числе изменение вектора прерывания, призванное осложнить по-шаговый
режим.
Если первое препятствие удается обойти, декодируется следующая
программа и т.д.
Таким образом приходится отказаться от надежды распознать вирус до
его активации. Однако есть определенный шанс, что удастся определить
его идентификатор вируса. Если он состоит из простой
последовательности символов, то можно посредством такой, например,
программы, как TextSrch (поиск текста) просмотреть всю массовую память и
обнаружить в ней аналогичные последовательности. Все программы
содержащие такую же последовательность должны быть тщательно обследованы.
Сложнее, если идентификатор состоит из различных символов, например,
Х является вирусом, если сумма первых 10 байт равна 99. С помощью
обычной программы поиска этот идентификатор можно и не обнаружить. В
таком случае необходимо разработать специальную программу поиска,
которая из каждой программы читает первые 10 байт, образует сумму и, в
случае, если результат равен 99, выводит на экран имя исследуемой программы.
Вирус может быть обнаружен не только по идентификатору, но и по какой-либо
его характеристике. Конечно, разработчик вируса вряд ли отважится зафиксировать
в нем свое авторское право. Однако, если определенная комбинация команд
распространяется как центральная составляющая часть вируса, то она может
помочь обнаружению самого вируса. Подобный подход эффективен лишь для виру-
сов, которые при распространении не изменяют своего облика, т.е. не авто-
модифицируются.
Несмотря на указанные трудности ниже приводятся листинги двух возможных
решений тестирующих программ, которые в состоянии проверить все файлы в
каталоге на существование признака вируса 909090h в начале файла или
признака 31/30 минут в каталоге. Это позволяет обнаружить вирус,
рассмотренный в [10.], а также "венский" вирус.
Name VD1
;************************************************************
; VD1 проверяет стоит ли в начале файла признак 909090h
; Версия: 1.0 Copyright by R. Burger 1988
;************************************************************
Code Segment
Assume CS:Code
Assume DS:Nothing
Assume es:Nothing
ORG 100h
Start:
;*************************************
; Сообщение о старте
;*************************************
lea dx,mes_sta
mov ah,9
int 21h
;*************************************
; Считать имя
;*************************************
lea dx,charcount
mov bx,dx
mov ah,10
int 21h
;*************************************
; Окончить с нулем
;*************************************
mov ah,0
mov al,cs:[bx+1]
add bx,ax
add bx,2
mov byte ptr cs:[bx],0
;*************************************
; Открыть файл
;*************************************
mov ah,3dh
mov al,0
lea dx,kbdbuf
int 21h
jc err_ope
;*************************************
; Обеспечить манипуляцию
;*************************************
mov bx,ax
;**************************************
; Прочитать 3 символа
;**************************************
mov ah,3fh
mov cx,3
int 21h
jc err_red
;***************************************
; Длина файла достаточна ?
;***************************************
cmh ax,3
jb shj1 ;файл слишком мал
;***************************************
; Существует ли признак ?
;***************************************
mov si,dx
cmp word hnu cs:[si],9090h
jnz ok1
inc dx
cmp word hnu cs:[si],9090h
jnz ok1
;***************************************
; Признак обнаружен ?
;***************************************
vir: lea dx,mes_vir
mov ah,9
int 21h
jmp close
;***************************************
; Файл не читается
;***************************************
err_red:
lea dx,mes_red
mov ah,9
int 21h
jmp close
;**************************************
; Файл не открывается
;**************************************
err_ope:
lea dx,mes_ope
mov ah,9
int 21h
jmp ende
;*************************************
; Файл слишком короток
;*************************************
sho1: lea dx,mes_sho
mov ah,9
int 21h
jmp close
;*************************************
; Все нормально
;*************************************
ok1: lea dx,mes_ok1
mov ah,9
int 21h
;*************************************
; Файл закрыть
;*************************************
close:
mov ah,3eh
int 21h
jnc ende
mov ah,9
lea dx,mes_clo
int 21h
;************************************
; Конец программы
;************************************
ende: mov ah,00
int 21h
mes_ok1 db 10,13,"Признак вируса не обнаружен $"
mes_sho db 10,13,"Для признака вируса файл слишком короток $"
mes_red db 10,13,7,"Файл не может быть считан $"
mes_ope db 10,13,7,"Файл не может быть открыт $"
mes_vir db 10,13,7,"Признак вируса 909090h обнаружен $"
mes_clo db 10,13,7,"Файл не может быть закрыт $"
mes_sna db 10,13,"Программа обнаружения признака вируса 909090h Версия:1.0",
db 10,13,"Copyright by R.Burger"
db 10,13,"Имя файла: $"
;*************************************
; Буфер для имени
;*************************************
charcount db 65,0
kbdbuf db 65 dup (0)
code ends
end start
Name VD2
;*********************************************************
; VD2 проверяет, имеется ли признак 31/30 минут в DIR
; Версия: 1.0 Copyright by R. Burger 1988
;*********************************************************
Code Segment
Assume CS:Code
Assume DS:Nothing
Assume es:Nothing
ORG 100h
Start:
;*************************************
; Сообщение о старте
;*************************************
lea dx,mes_sta
mov ax,90
int 21h
;*************************************
; Считать имя
;*************************************
lea dx,charcount
mov bx,dx
mov ah,10
int 21h
;*************************************
; Окончить с нулем
;*************************************
mov ah,0
mov al,cs:[bx+1]
add bx,ax
add bx,2
mov byte ptr cs:[bx],0
;*************************************
; Открыть файл
;*************************************
mov ah,3dh
mov al,0
lea dx,kbdbuf
int 21h
jc err_ope
;*************************************
; Обеспечить манипуляцию
;*************************************
mov bx,ax
;**************************************
; Считать дату/время
;**************************************
mov ah,57h
mov al,0
int 21h
jc err_red
;***************************************
; Дата верна ?
;***************************************
and cx,1fh
cmp cx,1fh
jnz ok1
;***************************************
; Признак найден ?
;***************************************
vir: lea dx,mes_vir
mov ah,9
int 21h
jmp close
;**************************************
; Файл не открывается
;**************************************
err_ope:
lea dx,mes_ope
mov ah,9
int 21h
jmp ende
;***************************************
; Файл не читается
;***************************************
err_red:
lea dx,mes_red
mov ah,9
int 21h
jmp close
;*************************************
; Все нормально
;*************************************
ok1: lea dx,mes_ok1
mov ah,9
int 21h
;*************************************
; Файл закрыть
;*************************************
close:
mov ah,3eh
int 21h
jnc ende
mov ah,9
lea dx,mes_clo
int 21h
;************************************
; Конец программы
;************************************
ende: mov ah,00
int 21h
mes_ok1 db 10,13,"Признак вируса не обнаружен $"
mes_red db 10,13,7,"Файл не может быть считан $"
mes_ope db 10,13,7,"Файл не может быть открыт $"
mes_vir db 10,13,7,"Признак вируса 31/30 min. обнаружен $"
mes_clo db 10,13,7,"Файл не может быть закрыт $"
mes_sna db 10,13,"Программа обнаружения признака вируса 31/30 min. Версия:1.0",
db 10,13,"Copyright by R.Burger"
db 10,13,"Имя файла: $"
;*************************************
; Буфер для имени
;*************************************
charcount db 65,0
kbdbuf db 65 dup (0)
code ends
end start
Резюме:
Обнаружить программы-вирусы c помощью стагндартных программ поиска
чрезвычайно трудно, создать универсальную программу анти-вирус невозможно.
Программа обнаружения вируса должна быть настроена на его характеристику,
что в первую очередь предполагает знание структуры вируса. Поскольку
автомодификация вируса, также как и стратегия его распространения могут
оказаться вложенными друг в друга,то между разработчиками вирусов и
разработчиками программ их обнаружения можно ожидать такого же соревно-
вания, как между создателями "защиты при копировании" и ее "разрушителями".
Соревнования, в котором не может быть победителей.