Ответы:
------
Инициализирующая часть не остается в памяти резидентно, т.к. она не вхо-
дит в п/п-му обработки прерывания 05, она нужна лишь для посадки резидента в
память и перенаправления вектора прерывания на него. Здесь уместна аналогия с
запуском орбитального спутника: ракета-носитель <инициализирующая часть>, вы-
водит на орбиту спутник-шпион <резидентная часть>. При этом сама ракета-носи-
тель разрушается и на орбиту не попадает.
О порядке следования. Если бы сначала шла инициализирующая часть, а по-
том - резидентная, то мы были бы вынуждены сделать резидентным и инициализи-
рующий кусок, ибо резидентным становится все, начиная от PSP и до того адре-
са, который мы поместим в DX перед генерацией INT 27h. Оставление в резиден-
туре инициализационной части приведет к расходованию лишней памяти (очень
ценного ресурса).
ЗАМЕЧАНИЕ: вот в случае создания резидентного вируса инициализирующая
часть обязана быть резидентной, так как ВИРУСУ ДОЛЖЕН БЫТЬ ДОСТУПЕН ВЕСЬ СОБ-
СТВЕННЫЙ КОД. Лишь при этом условии вирус сможет себя куда-нибудь запихнуть.
Вот зачем появились операторы CLI и STI: в момент, когда мы вручную (при
помощи команд пересылки) заменяем адрес в таблице векторов, может произойти
вызов того самого прерывания, которое мы перехватываем. Если одно слово заме-
нено, а другое - еще нет -- будет маленький Чернобыль (семь бед - один
RESET). На время замены вектора надо временно запретить вызовы прерываний
(команда CLI), после окончания замены -- разрешить вновь (команда STI). Ко-
манда CLI запрещает все прерывания, кроме немаскируемого NMI.
Зачем в начале нашей п/п-мы обработки прерывания 05 торчит PUSH AX, а в
конце -- POP AX? Слушайте СУПЕРПРАВИЛО:
-СУПЕРПРАВИЛО---------------------------------------------------------------¬
¦ Если п/п-ма обработки прерыв-я в процессе работы портит какой-либо ре-¦
¦гистр, то перед окончанием своей работы она обязана вернуть ему прежнее¦
¦значение. Чаще всего это делается так: перед началом работы этот регистр¦
¦роняется в стек, а перед окончанием достается обратно. (Есть и другие спо-¦
¦собы). ¦
L----------------------------------------------------------------------------
В заключение главы сварганим еще один резидент, который будет гудеть,
стОит лишь нам запустить какую-либо программу. Сажать его мы будем на обра-
ботку прерывания 21h - "Прерывания DOS" (функция 4Bh) :
коментарии см. ниже
-----------------------------------------------------------¬
¦ пример 6 ¦:
L-----------------------------------------------------------
TITLE Это - COM. программа N6 для демонстрации посадки резидента
ASSUME CS:CodeSegment
;-----------------------------------------------------------------
CodeSegment SEGMENT PARA
ORG(100h)
Start:
MainProcedure PROC NEAR
;
;
JMP initial ; перепрыгнем через данные
; ; и наш обработчик прер-я 21
; ; на инициализирующую часть
;
;
saved_int21: DD 0 ; данные (хранилище для
; ; адреса стандартного обра-
; ; ботчика прерывания 21 --
; ; -- 2 слова)
;
;-----------наша п/п-а обработки прерывания 21------------------¬
;¦ (она останется резидентной в памяти) ¦
;¦ ;здесь мы можем приколоться как ¦
int21_treater:;¦ ; хотим.. ¦
PUSH AX ; ¦
CMP AH,4Bh ;вызвана ф-я 4Bh прерыв-я 21h ¦
JNE not_beep ; (запуск программы) -- если ¦
MOV AX,0E07h ; нет - гудеть не будем ¦
INT 10h ;давать гудок (печать - символа ¦
not_beep: POP AX ; с кодом 07) ¦
; ;PUSH и POP ОЧЕНЬ важны сами ¦
; ; знаете теперь почему ¦
; ; ¦
JMP dword ptr CS:[saved_int21] ; длин. JMP по адресу, котор. ¦
rezident_end: ;¦ ; находится теперь в хранилище ¦
;¦ ; saved_int21 (возвращаем управ-¦
;¦ ; ление стандартному обработчику¦
;¦ ; прерывания 21) ¦
;L---------------------------------------------------------------
; ;
;-----------инициализирующая часть------------------------------¬
;¦ (здесь мы сажаем резидент, переопределяя адреса) ¦
;¦ ; ¦
initial: XOR DX,DX ; ---¬ ¦
MOV DS,DX ; ---+--> DS = 0 ¦
; ; ¦
MOV AX,DS:[21h*4] ; сохраняем в хранилище saved_
MOV word ptr CS:[saved_int21 ],AX ; int21 адрес стандартного ¦
MOV AX,DS:[21h*4+2] ; обработчика прерывания 21 ¦
MOV word ptr CS:[saved_int21+2],AX ; ( OFFSET и SEGMENT ) ¦
; ; ¦
; ; ¦
CLI ;запрещаем прерывания ¦
MOV AX,OFFSET int21_treater ; ¦
MOV word ptr DS:[21h*4],AX ;кладем в таблицу векторов ¦
PUSH CS ; адрес нашего обработчика ¦
POP AX ; прерывания 21 ¦
MOV word ptr DS:[21h*4+2],AX ; ¦
STI ;разрешаем прерывания ¦
; ; ¦
; ; ¦
MOV DX,OFFSET rezident_end ;DX<--конец резид. части ¦
INT 27h ;закончить программу и ¦
;¦ ; вернуться в DOS, оставив ¦
;¦ ; резидентной п/п-му ¦
;¦ ; int21_treater ¦
;L---------------------------------------------------------------
MainProcedure ENDP
;
CodeSegment ENDS
END Start
коментарии:
-----------
Единственное, что здесь для Вас ново - характер обработки прерыв-я 21h.
Мы подробней изучим его дальше, а здесь отметим лишь, что это прерыв-е содер-
жит офигительное количество функций, т.е. в п/п-ме его обработки содержится
множество суб-подпрограмм, каждая из которых вызывается в определенных обсто-
ятельствах. Здесь резидент вешается на суб-подпрограмму которая вызывается в
момент запуска на выполнение исполняемой программы (функция 4Bh). Говоря
по-русски, -- как только Вы запустите на выполнение какую-либо программу
(например TETRIS.EXE), будет сгенерировано прерывание 21h, - управление будет
передано соответств. п/п-ме обработки. При этом в регистре AH будет находить-
ся число 4Bh (входной параметр), которое означает, что внутри п/п-мы обработ-
ки прерыв-я 21h, управление, в свою очередь, будет передано суб-подпрограмме,
которая и осуществит запуск файла TETRIS.EXE.
Сущность нашего перехвата прерывания 21h такова: как только возникло
прерывание, и управление перешло к нашему резиденту мы сравниваем значение AH
с 4Bh. Если AH=4Bh (запускается какая-то программа), то мы даем гудок и пере-
даем управление в руки хозяина (функции 4Bh) -- делаем длинный джамп. Если же
вызванная функция -- не 4Bh, то мы возвращаем управление, что называется, без
звука.
Экспериментируя с этим резидентом, мы обнаружим, что при запуске прог-
рамм может раздаваться несколько гудков. Дело в том, что запускаемые нами
программы могут, в свою очередь, запускать свои дочерние процессы. Крайне
часто запускаются Norton и COMMAND.COM.
гл.5 ЧУТЬ-ЧУТЬ О PSP (как и обещали)
=============================================================================
PSP расшифровывается так: префикс программного сегмента (Programm
Segment Prefix). Где, когда и как он возникает? Каждый раз, когда какая-либо
программа (ЕХЕ- или СОМ-файл) запускается на выполнение, для нее в памяти
создается PSP. Сама программа считывается в память сразу за PSP. Длина PSP
составляет 256 (100h) байт. В PSP содержится много всяких штучек. Мы покажем
Вам лишь те, которые, возможно, понадобятся нам в дальнейшем.
смещение ¦длина ¦
от нача- ¦(в бай-¦ содержимое
ла PSP ¦тах) ¦
---------+-------+---------------------------------------
00 ¦ 2 ¦ код команды INT 20h (CD20h)
¦ ¦
02 ¦ 2 ¦ размер доступной сейчас памяти
¦ ¦ (в параграфах по 10h)
¦ ¦
2Ch ¦ 2 ¦ сегментный адрес среды для хранения
¦ ¦ ASCIIZ-строк
¦ ¦
80h ¦ 20h ¦ область передачи данных DTA
Прерывание INT 20h. Что за фигня? Если в программе дать такое прерыва-
ние, то выполнение ее будет завершено и управление вернется DOS. Совсем как
после команды RET. А как Вы думаете, - как работает команда RET? Команда эта
выполняет действие . А в стеке, сразу после загрузки СОМ-программы на
выполнение, лежит 0. Таким образом после команды RET управление передается по
адресу CS:00, т.е. на начало PSP, т.е. на команду INT 20h.
Обо всех прочих объектах Вы подробнее узнаете позднее.
гл.6 ПЕРВАЯ ПАКОСТЬ (создание ублюдочного резидентного вируса, грохающего за-
ражаемую программу)
=============================================================================
КОМЕНТАРИЙ К ЗАГЛАВИЮ: этот бездарный вирус показан здесь как анти-при-
мер для подражания и лишь для повышения Вашей образованности на достаточно
простом и наглядном материале. Вообще -- вирусы, необратимо грохающие прог-
раммы, создаются, как правило, либо - человеконенавистниками, либо - програм-
мистами, пока что еще слабо владеющими мастерством, либо - в погоне за рекор-
дом (например - рекордно короткая длина), либо - чтобы реализовать конкретный
алгоритм в условиях сильных внешних ограничений (например вирус должен быть
не длиннее одного сектора - 512 байт). Наш случай (смеем надеяться) не подхо-
дит ни под одну из этих категорий.
Что касается нашего первого вируса, то он будет вот каким: Вирус будет
резидентным. Резидент будет обрабатывать по-своему операции чтения/записи на
HDD. Как только резидент обнаружит, что с HDD читается годный для заражения
файл, он тут же запишет в него свою копию. Причем запишет таким образом, что
при запуске пораженного файла тот создаст новую резидентную копию вируса.
Цикл функционирования вируса замкнется.
Чтобы выполнить задуманное, нам необходимо еще кое-что узнать. Кое-что о
жестком диске PC (HDD, он же - "винчестер") и о гибких дисках (FDD).
Информацию можно читать/писать на HDD только фиксированными порциями -
секторами. Как правило, для HDD длина сектора составляет 512 байт. За один
раз на HDD можно записать/прочитать несколько секторов. Т.о. за каждое обра-
щение к HDD на него можно записать/прочитать количество байт, СТРОГО КРАТНОЕ
512. Нельзя, например, записать/прочитать 1,65,513,1033 байт, но можно --
512,1024,1536,...
Как PC находит нужные ему сектора? Чтение и запись на HDD осуществляется
не совсем так, как на магнитофон. В магнитофоне чтобы найти и считать/запи-
сать информацию нужно задать ее координату от начала ленты -- система ОДНО-
МЕРНА. При этом Вы должны пролистать ВСЮ предшествующую информацию. Скорость
такого процесса весьма мала. Такую фигню называют устройством последователь-
ного доступа. В HDD реализован другой принцип. HDD - это - трехмерное инфор-
мационное пространство и информацию в него писать/читать можно как в ТРЕХМЕР-
НЫЙ массив. Это же круто! Скорость офигительная, износ - минимальный.
Итак, можно представить HDD как трехмерный массив, элементами которого
являются сектора. Индексы-измерения этого массива будут называться вот как, и
иметь вот какие диапазоны изменения:
индекс-измерение ¦ диапазон изменения
-----------------------------+-------------------
сторона (side) ¦ 0,...,N--¬
¦ +--для разных
цилиндр (cylinder) ¦ 0,...,M--+ HDD - разные
¦ ¦ значения
сектор (sector) ¦ 1,...,L---
Измерение "сектор" пока что не смешивайте с элементарной неделимой еде-
ницей читаемой/пишущейся информации, так же именуемой "сектор".
Вот как понял бы приведенное выше описание HDD PASCAL-ист:
Type
Sector = array [1..512] of byte;
Var
HDD : array [0..N, 0..M, 1..L] of Sector;
LT-- LT-- LT--
+-----+-----+--------- для разных HDD
side cylinder sector разный верх. предел
Когда операционная система MS-DOS работает с файлами, она на самом деле
имеет дело с отдельными секторами и группами секторов, в которых размещается
содержимое файла.
Если Вы желаете подробнее познакомиться со структурой HDD, - то прочи-
тайте нижеследующий кусок текста, - нет -- джампуйте через него - информации
у Вас для понимания дальнейшего материала в принципе достаточно.
Если не хотите о HDD подробнее -- следуйте за стрелкой: ==>==============>==¬
V
¦¬ структура дискаг¦ ¦
¦L==(подробнее)===-¦ На физическом уровне HDD состоит из нескольких плоских ¦
L==================- (наверное - жестких) дисков, намертво закрепленных на ¦
общей оси (своего рода - этажерка). Первое измерение этого трехмерного квази- ¦
массива называется "сторона"(side). Верхняя сторона верхнего диска "этажерки"- V
¦
-----------------------------------------------------------¬ ¦
¦ рис.5 ¦: ¦
L----------------------------------------------------------- ¦
¦
ось-¬ -----> side 0 Измерение "сторона" ¦
L---->¦¦ ¦ V
================х================ пределы изменений: 0..N, ¦
диски-T- ¦¦ L----> side 1 где N -- для разных HDD ¦
¦L¬ ¦¦ -----> side 2 -- различно ¦
======¦=========х================ ¦
¦ ¦¦ L----> side 3 ¦
¦ ¦¦ ... ¦
L-¬ ¦¦ -----> side N-1 ¦
================х================ V
¦¦ L----> side N ¦
¦
-- это side 0, а нижняя - side 1; верхняя сторона следующего диска -- side 2, ¦
а нижняя - side 3. И т.д. - см. рис. 5. ¦
Следующее измерение называется "цилиндр" (cylinder) . Надеемся искренне, ¦
что, гдядя на рис. 5, Вы все же сможете ухватить нашу мысль (поясним лишь, ¦
что здесь средствами уголковой графики мы попытались изобразить "двухэтажный" ¦
диск). Цилиндр - пространство на ВСЕХ дисках "этажерки", находящееся на опре- V
деленном расстоянии от мест закреплений дисков на оси. Т.е. это - совокуп- ¦
ность концентрических дорожек одного радиуса на ВСЕХ сторонах HDD. Цилиндры ¦
нумеруются так: 0..M, где M -- для разных HDD -- различно. ¦
¦
-----------------------------------------------------------¬ ¦
¦ рис.6 ¦: ¦
L----------------------------------------------------------- ¦
верхний V
диск --¬ ¦
"этажерки"¦ --------------T-------------¬ ¦
¦ ---------\ ¦ /L--------¬ ¦
¦ ----- \-----------+----------/---¬ L---¬ ¦
----- ---------- \ ¦ / L--------¬ L---¬ ¦
----- ----- --\-------+------/--¬ L---¬ L---¬ ¦
--- ----- ----------- \ ¦ / L---------¬ L--¬ L-¬ ¦
-- ---- ------ \--+¦¦-/-¬ L-----¬ L--¬ L¬ V
¦ --- ---- ------ \¦¦¦ L--¬ L---¬ L¬ ¦ ¦
+---+TTTTT+------------------+--------¦L------+---------------------+----+--+ ¦
¦ L¦+++++TT¬ L----¬ / ¦ \ ---- ----- -- ¦ ¦
L¬ L¦++++++TTTT¬ /---+---\- ------- ---- -- ¦
L-¬ ¦L¦¦¦¦¦¦¦¦+TTTTTTTTT¬ / ¦ \ ----------- ------LT---- ¦
L---¬¦ L++++¦¦¦¦¦¦¦¦¦¦¦-¬гTTTTTT+---------- LT- ----- --+-- ¦
L+--¬ L++++++++-¦/¦¦¦¦¦¦¦¦¦¦ \ ------+---- ----- ¦ ¦
¦ L---¬ ¦ /-¦¦¦¦¦¦+¦¦¦+-----------\ ¦ ----- ¦ V
¦ L-----+--/ ¦ ¦ \---+----- ¦ ¦
¦ ¦ L---------+--T+T------------- ¦ ¦ ¦
¦ ¦ ¦ ¦¦¦ ¦ ¦ ¦
сентор 3--- ¦ ¦ ¦¦¦ -------+----¬ -------+----¬ ¦
¦ ¦ ¦ ¦¦¦--¬ ¦ цилиндр 1 ¦ ¦ цилиндр 0 ¦ ¦
¦ ¦ ¦ ¦¦¦ ¦ ¦(стОроны ¦ ¦(стОроны ¦ ¦
¦ сентор 2 ------- ¦ ¦¦¦ ось ¦ 0,1,2,3)¦ ¦ 0,1,2,3)¦ V
¦ ¦ ¦ ¦¦¦ L------T----- L------T----- ¦
¦ ¦ сентор 1 ---------- ¦¦¦------------¬ ¦ ¦ ¦
¦ ¦ ¦ ¦¦¦ /L---+----¬ ¦ ¦
¦ ¦ ¦ ¦¦¦---------/---¬ ¦ L---¬ ¦ ¦
¦ ¦ ¦ ¦¦¦ / L--+-----¬ L---¬ ¦ ¦
на цилиндре с номером 1 ¦¦¦-----/--¬ -+¬ L---¬ L-+¬ ¦
(из рис. не просЕчь - на какой стороне)¦¦¦ / L---------¬ L--¬-+L-¬ ¦
¦¦¦-/-¬ L-----¬ L--¬ L-¬ V
¦¦¦ L--¬ L---¬ L¬ ¦ ¦
L¦L------+---------------------+----+--+ ¦
| \ ---- ----- --- ¦ ¦
возможно - сектора нумеруются против \---\- ------- ---- --- ¦
часовой стрелки - нам это как-то | \ ----------- ----- --- ¦
пО фигу /-------\-- ----- ---- ¦
| \ ----------- ----- V
\-----------\ ----- ¦
| \--------- ¦
/-------------- ¦
¦
Третье измерение HDD -- "сектор" -- угловое расстояние от определенной ¦
точки на каком-либо цилиндре какой-либо стороны HDD. Секторы нумеруются по ¦
возрастанию углового расстояния. Нумеруются они так: 1..L (НЕ С 0, КАК ЦИЛИН- V
ДРЫ И СТОРОНЫ!), где L -- для разных HDD -- различно. ¦
Отметим, что пересечение цилиндра со стороной образует дорожку (track) ¦
-- одну окружность на одной из сторон. Так вот, -- дорожка состоит из следу- ¦
ющих друг за другом секторов. ¦
Задав все три координаты, мы однозначно задаем определенное место на ¦
HDD. Вообще говоря, эта фигня сильно напоминает цилиндрические координаты. ¦
г==<===============<===================<=====================<===============<===-
V
Что же касается гибких дисков -- дискет (FDD), то все вышесказанное
справедливо и для них. У FDD всего 2 стороны -- 0 и 1. Больше, пока что, и
добавить нечего.
Теперь вопрос: На что же мы посадим наш резидент? Для этого здесь должно
быть какое-то прерывание. И оно имеется. Прерывание, по которому PC чита-
ет/пишет на HDD и FDD сектор (группу секторов). Прерывание 13h. Опишем его.
¦прерывание 13h¦-----очень-очень важная фенька
L---------------
PC читает и пишет файлы на HDD посекторно. А секторА он читает/пишет при
помощи специального прерывания 13h. Это программное прерывание, генерируемое
Вами (а не аппаратурой) при помощи команды INT 13h. Вот какие у него входные
и выходные параметры:
-- MOV AH, (признак операции: 2-читать,3-писать,и пр.)
¦ MOV AL, сколько секторов читать/писать
¦ MOV CH, цилиндр--¬
входные параметры---+ MOV CL, сектор +-координаты записи
(заполняем перед ¦ MOV DH, сторона---
вызовом INT 13h) ¦ MOV DL, дисковод (0 - A:, 1 - B:, 80h - HDD)
¦ MOV BX, офсет----¬
L- MOV ES, сегмент--+--адрес буфера ввода/вывода
-----------------------------------------------------------¬
¦ INT 13h -- вызов п/п-мы чтения/записи секторов ¦
L-----------------------------------------------------------
-- CF (флаг переноса) содержит индикацию ошибки
¦ 0 - ошибок не было, 1 - произошла ошибка
¦
¦ в AL - содержится кол-во действительно обработанных
¦ секторов,
выходные параметры-+
(имеем в PC после ¦ в AH - если CF=1 (произошла ошибка) -- код ошибки
вызова INT 13h) ¦
L- по адресу ES:BX -- прочитанный сектор (группа секторов)
-- в случае, если была операция чтения
Вот пример использования INT 13h; здесь мы хотим прочитать в ОЗУ
MBR-"винчестера" (что это такое - объясним позднее) предположим, для како-
го-то исследования:
Далее
|