Резидентные программы



1

Содержание

Введение              .              2

1   РЕЗИДЕНТНЫЕ ПРОГРАММЫ              4

2   ЗАЩИТА РЕЗИДЕНТНЫХ ПРОГРАММ ОТ ПОВТОРНОЙ УСТАНОВКИ              .....8

3   ВЫГРУЗКА РЕЗИДЕНТНЫХ ПРОГРАММ ИЗ ПАМЯТИ              12

4   ОПИСАНИЕ ПРОГРАММЫ              13

Заключение              21

Литература              22

Приложение-листинг              23

Приложение-рисунок              35

Введение

 

 

В данной работе рассмотрено явление, которое в операционной системе 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:

 

mov si,80h lodsb cmp al,3 jl bue inc si lodsw cmp ax,'u/' jne bue



 

mov ax,3528h int21h push ds

 

Ids dx,dword ptr es:old_09

mov ax,2509h

int21h

 

Ids dx,dword ptr es:old_l С

mov ax,251Ch

int21h

Ids dx,dword ptr es:old_28 mov ax,2528h int 21h

Ids dx,dword ptr es:old_2F

mov ax,252Fh

int 21h

pop ds

mov ah,49h

int 21h

mov es,word ptr es:[0()2ch] mov ah,49h int 21h

bue:

mov ax,4c00h

int 21h TSRprog   endp code_seg ends end begin

 

Во-первых, сразу запросим прерывание 2F - нет ли нашей программы в памяти. Для этого занесем в АХ запланированный нами код функции (см. выше процедуру New_2F - мы там решили занять для своих нужд функцию 80 и подфункцию 00 . Проверим поступивший из прерывания «отзыв». Наша программа должна отозваться кодом 0ABCD (см.выше процедуру New_2F).

Если это так, то мы пытаемся второй раз установить программу - это не нужно, а может быть мы хоти выгрузить ее из памяти? Надо проверить ключ в строке параметров запуска программы, поэтому перейдем к метке analiz.

В противном случае начинаем установку программы резидентом в памяти. Для этого сначала сохраним адреса старых векторов прерываний, которые мы планируем заместить своими процедурами. Начнем с вектора 28h. Используя стандартную функцию 35h прерывания 21h получим этот вектор в ES:BX и сохраним его в специально подготовленной ячейке old_28 (см.выше).

С помощью стандартной функции 25п прерывания 21h на место старого вектора установим адрес нашей процедуры, и затем то же самое проделаем с вектором 2Fh и с вектором 1 Ch.

Разместим в регистре dx адрес начала не резидентной части программы с помощью прерывания 27h завершим нашу программу, оставив ее в памяти резидентной:

 

lea dx,start int 27h

Теперь удем анализировать содержимое строки параметров нашей программы. После запуска программы, содержимое командной строки операционная система размещает по смещению 80h в PSP программы. Точнее по самому смещению 80h находится байт, в котором размещается число, равное количеству символов в строке параметров. Получим его из PSP, для чего смещение интересующего нас байта занесем в SI. Потом загрузим этот байт в AL:

 

lodsb

и проверим, не меньше ли длина строки параметров 3-х символов. Если меньше, то выйти из программы , иначе перейдем на адрес следующего байта командной строки и возьмем из нее в АХ два байта. Проверим, это наш ключ /и:

 

cmp ах,'и/'

если не равно, то это не наш ключ и программу завершаем. В противном случае начинаем модуль выгрузки программы из памяти. Для начала загрузим регистры ES:BX адресом нашей программы в памяти для чего возьмем вектор любого из контролируемых ею прерываний, например, 28h:

 

mov ax,3528h int 21h

Теперь сохраним регистр ds.

Загрузим регистры DS:DX адресом старого вектора прерывания 1С взятого из памяти нашей программы, которая сейчас стоит резидентом:

 

Ids dx,dword ptr es:old_09

mov ax,2509h

int21h

Ids dx,dword ptr es:old_lC

 

To же сделаем с прерыванием 28h и прерыванием 2F. Восстановим регистр DS. Используя стандартную функцию 49h прерывания 21h, освободим память, занимаемую нашей резидентной программой. Функция освобождает память, сегмент которой стоит в ES. А там как раз адрес начала нашей резидентной программы:

 

mov ah,49h int 21h

 

Теперь надо освободить память, занятую блоком окружения программы. Возьмем оттуда этот адрес и поместим его в ES:

mov es,word ptr es:[002ch] после чего дадим команду освободить этот блок:

mov ah,49h

int 21h

Когда блок окружения программы свободен,   завершить программу и возвратиться в операционную систему: bue:

mov ax,4c00h

int 21h TSRprog   endp code_seg ends end begin

Заключение

 

Многие программы, обеспечивающие функционирование вычислительной системы (драйверы устройств, программы сжатия или шифрования данных, русификаторы, интерактивные справочники и др.), должны постоянно находиться в памяти и быстро реагировать на запросы пользователя или на какие-то события, происходящие в вычислительной системе. Такие программы носят название программ, резидентных в памяти (Terminate and Stay Resident, TSR), или просто резидентных. Сделать резидентной можно любую программу, однако ввиду того, что резидентная программа должна быть максимально компактной, чаще всего в качестве резидентных используют программы типа .СОМ.



 

Литература

1.      Пирогов В.Ю. ASSEMBLER Учебный курс Москва Издатель Молгачева СВ., 2001

2.      Зубков С. В. ASSEMBLER -язык неограниченных возможностей Издательство «ДМК Пресс», 1999

3.      АССЕМБЛЕР И ПРОГРАММИРОВАНИЕ ДЛЯ IBM PC Под редакцией Ершова В.Г.

4.      В. И. Юров ASSEMBLER Учебник для вузов. 2-е изд. / В. И. Юров — СПб.: Питер, 2003. —637 с: ил.

5.      Рудаков П. И., Финогенов К. Г. Язык ассемблера: уроки программирования. - М.: ДИАЛОГ-МИФИ, 2001. - 640 с.

6.      Интернет.

Приложение-листинг

 

 

code_seg segment TSRprog proc far

assume cs:code_seg

org lOOh begin:

jmp start

 

 

old_09      dw ? dw?

 

 

New_09 Proc pushf

call cs:dword ptr old_09 cli

mov ah, 0lh int 16h jz exit_int

cmp al,'q'; clear Cnt, key combination 'q'

jne exit_int

mov cs:cnt,0

exit_int:q sti iret

New_09 endp

 

 

New_2F Proc

;обработка мультиплексного прерывания



24

 



24

 

 

 

 

 

 

 

 

 

 

 

 

exit:


cli

cmp ax,08000h

jne exit

mov ax, OABCDh

sti

iret

 

 

sti

jmp cs:[O1d_2F] Old 2F DD 0


;запретим на время все прерывания в ОС ; проверим, а нашу ли программу вызывают? ;если нет, то выйти из процедуры. ;иначе - отправить пароль «я здесь» разрешить опять все прерывания в ОС. ; выйти из прерывания

 

 

разрешить опять все прерывания в ОС. ;и перейти по адресу старого обработчика прерывания 2F.

 

 

;это место под адрес старого обработчика прерывания 2F.



21

New_2F endp

 

 

 

 

 

 

 

New 1С Proc

 



21

 

 

 

 

 

 

 

 

 

 


cmpcs:Cnt,9      1              ;проверяем прошло ли 5 сек.?

jb М2              ;если нет, то переход на увеличение счетчика jb

mov cs:flg_timer,l              

 

 

M2:

 

 

 

 

 

 

 

;проверяем, прошло ли 5 секунд?

;если нет, то переход на увеличение счетчика jb

;сообщение можно выводить, поэтому установим

;в ячейке флага истечения

контрольного времени 1

 

 

 

 

inc byte ptr cs:Cnt              увеличить счетчик времени на 1

jmp cs:[O1d_lC]              ;перейти по адресу обработчика прерывания 2F.

01d_lC DD 0              ;адрес обработчика прерывания 2F.

Cnt DB 0              ;ячейка для счетчика тиков



21

 

flg_timer DB 0              ;ячейка для флага истечения заданного времени

New_lC endp

 

 

 

 

New_28 proc

;сохраним регистр флагов процессора

 

 

pushf

; проверим - в ячейке флага контроля истечения заданного времени установлена ли единица?

cmp cs:flg_timer,l

;если нет, то время до вывода сообщения на экран ;еще не истекло и мы переходим на старый ;обработчик прерывания 28h

jne Ml

;в противном случае активизируем модуль вывода

;сообщения на экран. Для чего

;сначала сохраним в стеке регистры, которые

;сейчас начнем использовать. Иначе

;мы испортим в них данные прерванной нами

программы.

push ах push bx push bp push es push cx

;3апретим прерывания нашей программы другими программами

        mov ah, OFh                                         ;Читаем текущий видео режим

int 1 Oh                                         ;bh <- номер активной страницы дисплея

 

 

mov ax,cs

mov es,ax              ;Выводимая строка

   ;Количество строк

  ;Вызов random

;Строка начала вывода

mov bp,offset curtime

 

mov cl,25

call random

mov dh,al

 

 

mov cl,73              ;Количество колонок - количество символов

;(80-7)

call random              ;Вызов random

mov dl,al              ;Колонка начала вывода

 

 

mov bl,2Eh              ;Атрибуты строки: желтые буквы на

;зеленом фоне

mov сх,7              ;Длина строки

mov ax,1300h              ;Вывод

int 10h

 

 

jmpql

 

 

random:

;Сохраняем в стек регистры

push es



 

 

push bx push dx push cx

 

 

mov ah,0              ;Читаем часы

int lAh              ;cx - старшая часть значения

;dx - младшая часть значения

mov es,cx mov bx,dx

mov al,byte ptr es:[bx]           ;Возвращаемое значение



 

 

 

11:

 

 

 

 

 

 

 

 

 

12:


pop cx

 

 

cmp al,cl jb 12

sub al,cl jmp 11


;Восстанавливаем

 

 

; Сравнение

;Если ниже

;Иначе CL - AL ;Повторная проверка

 

 

;Восстанавливаем сохраненные регистры



 

pop              dx

pop              bx

pop              es
ret

 

 

 

 

 

 

mov cs:flg_timer,0 mov cs:cnt,0


 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

;разрешим внешние прерывания



 

 



 

 

 

 

 

 

 

 

 

 

 

 

 

 

Ml:


sti

 

 

pop cx pop es pop bp pop bx pop ax

 

 

popf


 

восстановим все сохраненные регистры



 

 

 

 

 

 

jmp cs:[old_28]


;В заключение процедуры передадим управление старому обработчику

 

 

;А это область данных нашей процедуры New_28. ; Здесь хранится текстовая строка выводимая на ;экран ПЭВМ



 

curtime db "Message'

old_28 dd 0

New_28 endp

 

 

start:



 

 

 

 

 

 

 

 

 

 

 

 

 

mov ax,08000h


;Во-первых, сразу запросим прерывание 2F - нет

ли нашей программы в памяти?

;Для этого занесем в АХ запланированный нами

;код функции (см. выше процедуру

;New_2F - мы там решили занять для своих нужд

функцию 80 и подфункцию 00

 

 

; Обратимся к функции 2F



 

int 2Fh



 

 

;Проверим поступивший из прерывания «отзыв». ;Наша программа должна отозваться кодом

;0ABCD (см.выше процедуру New_2F)

cmp ax,0ABCDh

;Если это так, то мы пытаемся второй раз

установить программу - это не нужно,

;а может быть мы хоти выгрузить ее из памяти?

;Надо проверить ключ в строке

параметров запуска программы, поэтому

перейдем к метке ANALIZ

je analiz

;В противном случае начинаем установку программы резидентом в памяти ;Для этого сначала сохраним адреса старых ; векторов прерываний, которые мы ;планируем заместить своими процедурами. ;Начнем с вектора 28h. Используя стандартную функцию 35h прерывания 21h ;получим этот вектор в ES:BX

mov ax,3528h

int 21h

;и сохраним его в специально подготовленной ;ячейке old_28 (см.выше)

mov word ptr old_28,bx

mov word ptr old_28+2,es

;C помощью стандартной функции 25h прерывания 21h на место старого вектора установим адрес нашей процедуры

mov ax,2528h

lea dx,new_28

int21h

; Теперь то же самое проделаем с вектором 2Fh

mov ax,352Fh

int 21h

mov word ptr old_2F,bx

mov word ptr old_2F+2,es

mov ax,252Fh

lea dx,New_2F

int21h

;и с вектором lCh

mov ax,351Ch

int21h

mov word ptr old_lC,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



27

 



27

 

 

 

 

lea dx, start

 

 

 

 

int 27h analiz:


;Разместим в регистре dx адрес начала НЕ РЕЗИДЕНТНОЙ части программы

 

;с помощью прерывания 27h завершим нашу

программу, оставив

;ее в памяти резидентной



27

занесем в SI

mov si,80h

 

 

lodsb

 

 

cmp al,3

jl bue

;Будем анализировать содержимое строки

щараметров нашей программы.