

32. Перехват системных вызовов DOS
Существует множество практических задач, для решения которых требуется производить мониторинг (контроль событий) вычислительной системы.
Например, для того, чтобы запретить несанкционированное обращение к отдельным устройствам, накопителям, директориям или файлам, необходимо перехватывать такие обращения с целью аутентификации пользователя (проверки пароля), а для того, чтобы контролировать целевое использование вычислительной системы (защита от "игрушек"), необходимо перехватывать запуски программных файлов на выполнение и вести протокол запущенных программ.
В операционной системе MS-DOS задача контроля облегчается тем, что точки входа в системные функции операционной системы и базовой системы ввода/вывода BIOS известны. Адреса этих точек входа суть векторы программных прерываний с известными номерами, а обращения прикладных программ к системным функциям производятся путем вызова программного прерывания с соответствующим номером (команда процессора INT).
Таким образом, для организации контроля системных вызовов необходимо занести в качестве вектора соответствующего прерывания адрес программной процедуры, которая получает управление каждый раз при вызове прикладной программой интересующей нас системной функции, анализирует переданные ей параметры, а затем решает, что делать с перехваченным вызовом - пропустить его дальше, запретить или занести в протокол.
Все интересующие нас функции операционной системы MS-DOS вызываются через программное прерывание диспетчера функций ДОС с номером 0x21, причем номер функции передается в старшем байте AH регистра AX процессора. В остальных регистрах могут содержаться параметры, необходимые для работы системной функции. Результат работы функции передается также через регистры процессора, причем наиболее часто для передачи результата используются регистр AX и бит переноса CF регистра флагов FLAGS. В случае ошибки выполнения функции бит CF устанавливается в 1, а регистр AX содержит код ошибки. Бит CF является младшим (нулевым) битом регистра флагов.
В примере для изучения (control.c) производится перехват функции с номером 0x4B (запуск дочернего процесса) программного прерывания ДОС с номером 0x21, определяется имя файла запускаемой программы, и сообщение о факте запуска программы заносится в файл протокола. Указанные действия выполняет функция обработки прерывания void interrupt my_dos(). При этом без ведома прикладной программы в ее исполняемый код по сути встраивается часть кода нашей программы.
Поскольку прикладная программа, в общем случае, не рассчитана на такое вмешательство, то размер области памяти, отведенной в той программе под стек, как правило оказывается недостаточным для функционирования нашего встраиваемого кода. Нам же необходимо использовать стек для передачи параметров в функции языка СИ и для создания автоматических переменных, объявляемых внутри наших и библиотечных функций. Поэтому при перехвате прерывания стек той программы необходимо переключать на наш собственный стек достаточного размера. Если переключение не производится, то в таком случае говорят, что прерывающий процесс "паразитирует" на стеке прерванного процесса. Такое паразитирование может привести к переполнению стека, порче содержимого оперативной памяти и "зависанию" системы.
Переключение стека на фиксированную (статическую) область памяти приводит к нереентерабельности той части функции my_dos(), которая работает со своим стеком. Поэтому указанный участок функции необходимо защитить от повторного вхождения методом запрета аппаратных прерываний.
Приведем описание интересующих нас функций операционной системы MS-DOS. Точка входа в диспетчер функций ДОС - вектор прерывания 0x21. Регистр AH содержит код номера функции. Остальные параметры передаются и возвращаются в регистрах процессора.
Резидентный режим работы программы контроля обеспечивается путем запуска из нее в качестве дочернего процесса любой другой программы, обеспечивающей командный интерфейс пользователя и управление файловой системой, например, командных процессоров VOLKOV COMMANDER, NORTON COMMANDER или ДОС НАВИГАТОР.
Так как указанные программы обеспечивают полную свободу действий Оператора, то нам нужно принять меры защиты от повторного запуска нашей программы контроля, которая уже один раз была запущена и находится в памяти. В одном из методов такой защиты можно использовать идентификатор загруженной программы - некоторый уникальный код, записанный на место заведомо неиспользуемого системой вектора прерываний, например, с номером 0x85.
Еще один вектор с номером 0x86 мы будем использовать для переназначения вызова диспетчера функций операционной системы, то есть вектор с номером 0x86 будет содержать точку входа в системные функции ДОС, которую раньше адресовал вектор 0x21.
Отложенная запись сообщений в файл протокола производится аналогично лабораторной работе №3 - по прерыванию системного таймера или по инициативе функции ДОС ожидания ввода (прерывание 0x28). При этом также необходимо обеспечить переключение стека прерванного процесса на собственный стек и принять меры против повторного вхождения в нереентерабельный участок кода при помощи флага запрета повторной входимости.
Например, для того, чтобы запретить несанкционированное обращение к отдельным устройствам, накопителям, директориям или файлам, необходимо перехватывать такие обращения с целью аутентификации пользователя (проверки пароля), а для того, чтобы контролировать целевое использование вычислительной системы (защита от "игрушек"), необходимо перехватывать запуски программных файлов на выполнение и вести протокол запущенных программ.
В операционной системе MS-DOS задача контроля облегчается тем, что точки входа в системные функции операционной системы и базовой системы ввода/вывода BIOS известны. Адреса этих точек входа суть векторы программных прерываний с известными номерами, а обращения прикладных программ к системным функциям производятся путем вызова программного прерывания с соответствующим номером (команда процессора INT).
Таким образом, для организации контроля системных вызовов необходимо занести в качестве вектора соответствующего прерывания адрес программной процедуры, которая получает управление каждый раз при вызове прикладной программой интересующей нас системной функции, анализирует переданные ей параметры, а затем решает, что делать с перехваченным вызовом - пропустить его дальше, запретить или занести в протокол.
Все интересующие нас функции операционной системы MS-DOS вызываются через программное прерывание диспетчера функций ДОС с номером 0x21, причем номер функции передается в старшем байте AH регистра AX процессора. В остальных регистрах могут содержаться параметры, необходимые для работы системной функции. Результат работы функции передается также через регистры процессора, причем наиболее часто для передачи результата используются регистр AX и бит переноса CF регистра флагов FLAGS. В случае ошибки выполнения функции бит CF устанавливается в 1, а регистр AX содержит код ошибки. Бит CF является младшим (нулевым) битом регистра флагов.
В примере для изучения (control.c) производится перехват функции с номером 0x4B (запуск дочернего процесса) программного прерывания ДОС с номером 0x21, определяется имя файла запускаемой программы, и сообщение о факте запуска программы заносится в файл протокола. Указанные действия выполняет функция обработки прерывания void interrupt my_dos(). При этом без ведома прикладной программы в ее исполняемый код по сути встраивается часть кода нашей программы.
Поскольку прикладная программа, в общем случае, не рассчитана на такое вмешательство, то размер области памяти, отведенной в той программе под стек, как правило оказывается недостаточным для функционирования нашего встраиваемого кода. Нам же необходимо использовать стек для передачи параметров в функции языка СИ и для создания автоматических переменных, объявляемых внутри наших и библиотечных функций. Поэтому при перехвате прерывания стек той программы необходимо переключать на наш собственный стек достаточного размера. Если переключение не производится, то в таком случае говорят, что прерывающий процесс "паразитирует" на стеке прерванного процесса. Такое паразитирование может привести к переполнению стека, порче содержимого оперативной памяти и "зависанию" системы.
Переключение стека на фиксированную (статическую) область памяти приводит к нереентерабельности той части функции my_dos(), которая работает со своим стеком. Поэтому указанный участок функции необходимо защитить от повторного вхождения методом запрета аппаратных прерываний.
Приведем описание интересующих нас функций операционной системы MS-DOS. Точка входа в диспетчер функций ДОС - вектор прерывания 0x21. Регистр AH содержит код номера функции. Остальные параметры передаются и возвращаются в регистрах процессора.
Резидентный режим работы программы контроля обеспечивается путем запуска из нее в качестве дочернего процесса любой другой программы, обеспечивающей командный интерфейс пользователя и управление файловой системой, например, командных процессоров VOLKOV COMMANDER, NORTON COMMANDER или ДОС НАВИГАТОР.
Так как указанные программы обеспечивают полную свободу действий Оператора, то нам нужно принять меры защиты от повторного запуска нашей программы контроля, которая уже один раз была запущена и находится в памяти. В одном из методов такой защиты можно использовать идентификатор загруженной программы - некоторый уникальный код, записанный на место заведомо неиспользуемого системой вектора прерываний, например, с номером 0x85.
Еще один вектор с номером 0x86 мы будем использовать для переназначения вызова диспетчера функций операционной системы, то есть вектор с номером 0x86 будет содержать точку входа в системные функции ДОС, которую раньше адресовал вектор 0x21.
Отложенная запись сообщений в файл протокола производится аналогично лабораторной работе №3 - по прерыванию системного таймера или по инициативе функции ДОС ожидания ввода (прерывание 0x28). При этом также необходимо обеспечить переключение стека прерванного процесса на собственный стек и принять меры против повторного вхождения в нереентерабельный участок кода при помощи флага запрета повторной входимости.