Автор работы: Пользователь скрыл имя, 14 Мая 2012 в 16:48, курсовая работа
В данной работе рассмотрено явление, которое в операционной системе MSDOS играет роль многозадачности. С истинной многозадачностью можно столкнуться, рассматривая программирование в операционной системе Windows. Многозадачность же, рассматриваемая в этой курсовой работе, может быть названа нелегальной. Термин TSR происходит от английской фразы Terminate State Resident, т.е. "завершить и остаться резидентным". Резидентная программа, находясь в памяти, выполняет свои функции через перехваченные прерывания. Связь с резидентной программой также осуществляется посредством прерываний.
1 РЕЗИДЕНТНЫЕ ПРОГРАММЫ 4
2 ЗАЩИТА РЕЗИДЕНТНЫХ ПРОГРАММ ОТ ПОВТОРНОЙ УСТАНОВКИ .....8
3 ВЫГРУЗКА РЕЗИДЕНТНЫХ ПРОГРАММ ИЗ ПАМЯТИ 12
4 ОПИСАНИЕ ПРОГРАММЫ 13
Заключение 21
Литература 22
Приложение-листинг 23
Приложение-рисунок 35
1
Содержание
Введение . 2
1 РЕЗИДЕНТНЫЕ ПРОГРАММЫ 4
2 ЗАЩИТА РЕЗИДЕНТНЫХ ПРОГРАММ ОТ ПОВТОРНОЙ УСТАНОВКИ .....8
3 ВЫГРУЗКА РЕЗИДЕНТНЫХ ПРОГРАММ ИЗ ПАМЯТИ 12
4 ОПИСАНИЕ ПРОГРАММЫ 13
Заключение 21
Литература 22
Приложение-листинг
Приложение-рисунок
Введение
В данной работе рассмотрено явление, которое в операционной системе MSDOS играет роль многозадачности. С истинной многозадачностью можно столкнуться, рассматривая программирование в операционной системе Windows. Многозадачность же, рассматриваемая в этой курсовой работе, может быть названа нелегальной. Термин TSR происходит от английской фразы Terminate State Resident, т.е. "завершить и остаться резидентным". Резидентная программа, находясь в памяти, выполняет свои функции через перехваченные прерывания. Связь с резидентной программой также осуществляется посредством прерываний. Часто такие программы играют роль драйверов -программ поддержки, каких-либо внешних устройств. Наиболее часто употребляемые резидентные драйверы обеспечивают русифицированную работу экрана и клавиатуры или поддерживают работу мыши. Популярны резидентные переводчики и различные резидентные детекторы, позволяющие на ранней стадии обнаруживать появление вируса. Наличие в памяти резидентных программ предполагает как бы некое подобие многозадачного режима, в котором, однако, есть главная задача, выполняющаяся в данный момент. Остальные же задачи получают управление время от времени через перехваченные ими прерывания либо "по милости" главной задачи. Таким образом, операционная система фактически не "знает" об их существовании. Многие авторы говорят в этой связи об изначальной порочности TSR-программ. Однако, надо заметить, что:
1. На TSR-программах держится значительная часть как чисто системной, так и прикладной программной поддержки в операционной системе MS DOS.
2. При написании любой программы нужно придерживаться определенных правил, а ошибка в программе приводит к полной и частичной ее неработоспособности.
3. Многие проблемы, рассмотренные в настоящей главе, носят общий характер для любых многозадачных сред.
1 РЕЗИДЕНТНЫЕ ПРОГРАММЫ
Структура типичной резидентной программы выглядит следующим образом:
text segment
assume CS:text,DS:text
org lOOh main proc
jmp init ;Переход на секцию инициализации
;Данные резидентной секции программы
entry: ;Текст резидентной секции программы
main endp
init proc ;Секция инициализации
mov DX,(init-main+10Fh)/16
mov АН,3100h ;Функция "Завершить и оставить в
int 21 h ; памяти"
init endp
text ends end main
Программа пишется в формате .СОМ, поэтому в ней предусматривается только один сегмент, с которым связываются сегментные регистры CS и DS; в начале сегмента резервируется lOOh байт для PSP. При запуске программы с клавиатуры управление передается (в соответствии с параметром директивы end) на начало процедуры main. Командой jmp сразу же осуществляется переход на секцию инициализации, которая может быть оформлена в виде отдельной процедуры или входить в состав процедуры main. В секции инициализации выполняются некоторые начальные действия, о которых мы поговорим позже. Последними строками секции инициализации вызывается функция DOS 3 lh, которая выполняет завершение программы с оставлением в памяти указанной ее части. Размер резидентной части программы (в параграфах) передается DOS в регистре DX. Определить этот размер можно, например, следующим образом. К разности смещений init-main, которая равна длине резидентной части программы в байтах, прибавляется размер PSP (lOOh) и еще число 15 (Fh), чтобы после целочисленного деления на 16 (для получения размера программы в параграфах) результат был округлен в большую сторону. С целью экономии памяти секция инициализации располагается в конце программы и отбрасывается при ее завершении. Функция 3lh, закрепив за резидентной программой необходимую для ее функционирования память, передает управление командному процессору (как и обычная функция завершения программы 4Ch), и вычислительная система переходит в исходное состояние. Наличие программы, резидентной в памяти, никак не отражается на ходе вычислительного процесса, за исключением того, что уменьшается объем свободной памяти. Одновременно в память может быть загружено любое число резидентных программ. Процесс первичного запуска резидентной программы, приводящего к ее загрузке в память, обычно называют установкой программы. На рисунке 1 показаны элементы резидентной программы и их взаимодействие.
PSP
Точка входа при
загрузке
Точка входа при актквнзадни —
Резидентные данные
entry:
> Резидентная часть программы
main endp
Резидентные шманды
init proc
: c*xw« инициализации mov AH, 31h
tot 21h init endp end main
Часть программы» > отбрасываемая после установки в памяти
Рис. 1. Взаимодействие элементов резидентной программы
Любая резидентная программа имеет по крайней мере две точки входа. При запуске с клавиатуры программы типа .СОМ управление всегда передается на первый байт после PSP (IP=100h). Поэтому практически всегда первой командой резидентной программы является команда jmp, передающая управление на начало секции инициализации. После отработки функции DOS 3 lh программа остается в памяти в пассивном состоянии. Для того чтобы активизировать резидентную программу, ей надо как-то передать управление. Вызвать к жизни резидентную программу можно разными способами, но наиболее употребительным является механизм аппаратных или программных прерываний. В этом случае в процессе инициализации необходимо заполнить соответствующий вектор адресом точки входа в программу (entry на рис.1). Адрес entry образует вторую точку входа в программу, через которую осуществляется ее активизация. Очевидно, что резидентная секция программы должна заканчиваться командой выхода из прерывания iret.
2 ЗАЩИТА РЕЗИДЕНТНЫХ ПРОГРАММ ОТ ПОВТОРНОЙ УСТАНОВКИ
Некоторые резидентные программы имеют серьезный недостаток: они не защищены от повторной загрузки. Вспомним, что для работы с резидентной программой ее следует прежде всего установить, запустив с клавиатуры как обычную программу. В этом случае управление передается на секцию инициализации, в которой подготавливаются условия для дальнейшей работы программы в резидентном состоянии. Как правило, в секции инициализации загружаются векторы прерываний, через которые программа будет активизироваться. Может получиться, что пользователь, установив программу, забудет об этом и запустит ту же программу повторно. В этом случае в память будет загружена и останется резидентной вторая копия той же программы. Это плохо не только потому, что понапрасну расходуется память; более неприятным является вторичный перехват тех же векторов. Если резидентная программа после ее активизации не обращается к старому содержимому перехваченных ею векторов, то вторая копия полностью лишит первую работоспособности и тогда повторная загрузка приведет только к расходованию памяти. Если, однако, как это обычно и имеет место, резидентная программа в процессе своей работы передает управление старому обработчику перехваченного ею прерывания, то новая копия резидентной программы, сохранившая в процессе инициализации адрес первой копии в качестве содержимого перехватываемого вектора, будет при каждой активизации вызывать и первую копию. В результате резидентная программа будет фактически выполняться при каждом вызове дважды. Во многих случаях такое повторное выполнение нарушит правильную работу программы. Поэтому обязательным элементом любой резидентной программы является процедура защиты ее от повторной загрузки (установки). Наиболее распространенным методом защиты резидентной программы от повторной установки является использование прерывания 2Fh, называемого мультиплексным и специально предназначенного для связи с резидентными программами. При вызове этого прерывания в регистре АН задается номер функции (от 00h до FFh), а в регистре AL - номер подфункции (в том же диапазоне). Функции с 00h по BFh зарезервированы для использования системой (например, функции 00h и Olh закреплены за резидентной программой DOS PRTNT.COM, а 1 Oh - за программой SHARE.EXE), а функции с COh по FFh могут использоваться прикладными программами. Для того чтобы резидентная программа могла отозваться на вызов прерывания int 2Fh, в ней должен иметься обработчик этого прерывания (рис. 1). Фактически все резидентные программы, как системные, так и прикладные, имеют такие обработчики, через которые осуществляется не только проверка на повторную установку, но и вообще вся связь с резидентной программой: смена режима ее работы или получение от нее требуемой информации. Задание действия, которое надлежит выполнить обработчику прерывания 2Fh конкретной резидентной программы, осуществляется с помощью номера подфункции, помещаемого перед вызовом прерывания в регистр AL. Обычно для проверки на наличие в памяти используется подфункция OOh.
9
DOS
entry: TSR (1)
■ Содержательная часть
• резидентной программы
jret
uew_2fti;
'. Обработчик прерывания 2Fh
Резидентная теть программы
Первый экземпляр TSE.COM, загруже ими й * память командой TSR,СОМ
Второй экземшяр TSR.COM, запущенны й повторной командой TSR.COM и приступивший к своей инициализаций
11
Признак наличия к памяти первого экземпляра программы
рис. 2. Проверка, осуществляемая запущенной с клавиатуры резидентной программой, на наличие в памяти ранее установленного экземпляра той же программы.
Резидентная программа на этапе инициализации должна выяснить, нет ли уже в памяти ранее установленного экземпляра той же программы. Для этого в секции инициализации выполняется команда int 2Fh (см. рис. 1). Предварительно в регистр АН помещается номер функции, присвоенный данной программе (из диапазона COh...FFh), а в регистр AL - номер подфункции, соответствующей запросу на наличие в памяти, например,ООп. Обработчик прерывания 2Fh резидентной программы должен прежде всего проверить номер функции в регистре АН; при обнаружении своей функции обработчик анализирует содержимое регистра AL и выполняет затребованные действия, после чего командой iret передает управление вызвавшей его программе. Если, однако, обработчик обнаружил в регистре АН чужую функцию, он должен командой jmp CS:old_2fh передать управление по цепочке тому обработчику, адрес которого был ранее в векторе 2Fh. В результате вызов int 2Fh из любой программы будет проходить по цепочке через все загруженные резидентные программы, пока не достигнет "своей" программы или йе вернет управление в вызвавшую программу через обработчик DOS (который, очевидно, всегда будет самым последним в цепочке).
4 ОПИСАНИЕ ПРОГРАММЫ
Данный резидентный обработчик должен выполнять следующее. После запуска программы на экране должны выводиться сообщения с текстом "Message" желтыми символами на зеленом фоне и прекращаться при нажатии клавиши "q" с клавиатуры.
Для того, чтобы останавливать вывод сообщений клавиатурой,
прописываем его для клавиши "q".
old_09 dw ?
dw? New_09 Proc pushf
call cs:dword ptr old_09 cli
mov ah, Olh int 16h jz exit_int
cmp al,'q'; clear Cnt, key combination 'q' jne exit_int mov cs:cnt,0 exit_int: sti iret
New_09 endp
Затем идет часть мультиплексной обработки прерывания:
New_2F Proc cli
cmp ax,08000h jne exit
mov ax, OABCDh
sti
iret
exit:
sti
jmp cs:[01d_2F]. 01d_2F DD 0 New_2F endp
Здесь сначала запрещаем на время все прерывания в операционной системе. Затем проверяем, нашу ли программу вызывают. Если же нет, то выйти из процедуры, а иначе отправить пароль «я здесь». После этого обратно разрешаем все прерывания в операционной системе и выходим из прерывания. А после того, как вышли из прерывания, разрешаем опять все прерывания в операционной системе и переходим по адресу старого обработчика прерывания F2.
После мультиплексного прерывания следует блок программы, который отсчитывает время 5 секунд до появления очередного сообщения на экране. New_lC Proc
cmp cs:Cnt,91 jb M2
mov cs:flg_timer,l
M2:
inc byte ptr cs:Cnt jmpcs:[01d_lC] OldJCDDO Cnt DB 0 flgjimer DB 0 New_lC endp
Проверяем, прошло ли 5 секунд. Если нет, то переход на увеличение счетчика jb. Сообщение можно выводить, поэтому установим в ячейке флага истечения контрольного времени 1. Увеличиваем счетчик времени на 1 и переходим по адресу обработчика прерывания F2.
New_28 proc pushf
cmp cs:flg_timer,l
jne Ml
push ax
push bx
push bp
push es
push cx
cli
В этой части программы сохраняем регистр флагов процессора. Проверяем, установлена ли 1 в ячейке флага контроля истечения заданного времени. Если не установлена, то время до вывода сообщения на экран еще не истекло и мы
переходим на старый обработчик прерывания 28h. В противном случае активизируем модуль вывода сообщения на экран. Для чего сначала сохраним в стеке регистры, которые сейчас начнем использовать. Иначе мы испортим в них данные прерванной нами программы. Запретим прерывания нашей программы другими программами.
Теперь идет блок, в котором прописывается вывод сообщений на экран.
mov ah, 01 ?h int lOh
mov ax,cs mov es,ax
mov bp,offset curtime
mov cl,25 call random mov dh,al mov cl,73 call random mov dl,al mov bl,2Eh mov cx,7 mov ax,1300h int lOh jmpql random:
push es push bx push dx push cx
mov ah,0 int lAh
mov es,cx mov bx,dx
mov al,byte ptr es:[bx] pop cx
cmp al,cl jb 12 sub al,cl jmp 11
pop dx pop bx pop es ret
Читаем текущий видеорежим и вызываем random, чтобы сообщения появлялись на экране в произвольных местах. Количество колонок - количество символов (80-7). Указываем атрибуты строки: желтые буквы на зеленом фоне mov bl,2Eh. После чего сохраняем в стек все регистры, и читаем часы.
3
ql:
mov cs:flg_timer,0 mov cs:cnt,0
sti
pop cx pop es pop bp pop bx pop ax
Ml:
popf
jmp cs:[old_28]
curtime db "Message" old_28 dd 0 New_28 endp
Здесь разрешаем все прерывания, восстанавливаем все сохраненные регистры и в заключение процедуры передаем управление старому обработчику.
И последний блок данного резидентного обработчика:
start:
mov ax,08000h int 2Fh
cmp ax,0ABCDh je analiz
mov ax,3528h int21h
mov word ptr old_28,bx mov word ptr old_28+2,es mov ax,2528h lea dx,new_28 int21h
mov ax,352Fh int21h
mov word ptr old_2F,bx mov word ptr old_2F+2,es mov ax,252Fh lea dx,New_2F int21h
mov ax,351Ch int21h
mov word ptr old_l C,bx mov word ptr old_lC+2,es mov ax,251Ch lea dx,New_lC int21h
mov ax,3509h" int21h
mov word ptr old_09,bx mov word ptr old_09+2,es mov ax,2509h lea dx,New_09 int21h
lea dx,start int 27h
analiz: