Драйверы, резидентные программы и WINDOWS
В этом разделе, как и в следующем, мы не будем ничего говорить о защищённом режиме работы процессора. Мы рассмотрим здесь некоторые особенности, которые необходимо учитывать при разработке резидентных программ и драйверов, работающих совместно с WINDOWS.
Очень часто резидентные программы или драйверы перехватывают аппаратное прерывание клавиатуры и отслеживают коды нажимаемых клавиш, выполняя те или иные действия при нажатии заданных комбинаций. Например, драйвер "секретного" диска Norton DISKREET может при нажатии заданной комбинации клавиш блокировать доступ к "секретному" диску, экрану и клавиатуре.
Так как WINDOWS в расширенном режиме использует собственную систему клавиатурного ввода/вывода, основанную на очередях сообщений, а также реализует концепцию виртуальных машин, нажатие активизирующих резидентную программу комбинаций клавиш в неподходящий момент может не привести к желаемому результату и даже стать причиной "зависания" системы.
Есть два возможных решения этой проблемы. Во-первых, можно запретить запуск WINDOWS, если активна резидентная программа или драйвер, не способные работать совместно с WINDOWS. Во-вторых, на время работы WINDOWS можно запретить выполнение резидентной программой или драйвером специфических функций, несовместимых с WINDOWS (например, запретить активизацию резидентной программы при нажатии комбинации клавиш).
Перед запуском WINDOWS и перед её завершением вызываются функции прерывания INT2Fh 1605h и 1606h соответственно. Ваша резидентная программа или драйвер могут подготовить собственные обработчики для этих прерываний и отслеживать моменты запуска WINDOWS и завершения её работы.
Функция 1605h вызывается при запуске WINDOWS:
Регистры при вызове прерывания:
AX 1605h ES:BX 0000h:0000h DS:SI 0000h:0000h CX 0000h DX Флаги: Бит 0 = 0, если выполняется инициализация WINDOWS в расширенном режиме; Бит 0 = 1, если выполняется инициализация DOS-экстендера "Microsoft 286 DOS extender" (используется в стандартном режиме работы WINDOWS); Биты 1-15 зарезервированы, их содержимое неопределено.Регистры перед возвратом из прерывания:
CX 0000h, если WINDOWS может продолжать инициализацию; CX <> 0, если запуск WINDOWS недопустим. Функция 1606h вызывается при завершении WINDOWS расширенном или стандартном режиме:
Регистры при вызове прерывания:
AX 1606h DX Флаги: Бит 0 = 0, если выполняется завершение WINDOWS, работавшей в расширенном режиме; Бит 0 = 1, если выполняется завершение DOS-экстендера "Microsoft 286 DOS extender"; Биты 1-15 зарезервированы, их содержимое не определено. Обработчик функции 1605h может выполнить необходимые действия, связанные с модификацией алгоритма работы резидентной программы или драйвера, а также при помощи соответствующей установки регистра CX может разрешить или запретить запуск WINDOWS.
Обработчик функции 1606h получает управление при завершении работы WINDOWS и может восстановить прежний алгоритм работы критичной к WINDOWS резидентной программы или драйвера.
Приведённая ниже резидентная программа перехватывает прерывание INT 2Fh и отслеживает фунции 1605h и 1606h, вызавая сообщение и ожидая нажатия на любую клавишу при запуске и завершении работы WINDOWS:
Листинг 22. Контроль запуска WINDOWS Файл wintsr.asm ----------------------------------------------------------- .MODEL tiny .CODE .STARTUP jmp begin old_int2Fh_off dw 0 ; Адрес старого обработчика old_int2Fh_seg dw 0 ; прерывания 2Fh ; Сообщение, которое будет выдано на экран ; при запуске WINDOWS msg_win db 'WINDOWS Started. Press any key...$' msg_win_off dw offset msg_win ; Сообщение, которое будет выдано на экран ; при завершении WINDOWS msg_win1 db 'WINDOWS Ended. Press any key...$' msg_winend_off dw offset msg_win1 ; Новый обработчик прерывания 2Fh нужен ; для проверки наличия программы в памяти ; при ее запуске для предохранения ; от повторного запуска new_int2Fh proc far cmp ax,0FF00h jz installed cmp ax,1605h jz winstart cmp ax,1606h jz winend jmp dword ptr cs:old_int2Fh_off winstart: ; запуск WINDOWS push ax push bx push cx push dx push ds mov dx,cs:msg_win_off mov ah,9 push cs pop ds int 21h mov ax,0 int 16h pop ds pop dx pop cx pop bx pop ax jmp dword ptr cs:old_int2Fh_off winend: ; завершение WINDOWS push ax push bx push cx push dx push ds mov dx,cs:msg_winend_off mov ah,9 push cs pop ds int 21h mov ax,0 int 16h pop ds pop dx pop cx pop bx pop ax jmp dword ptr cs:old_int2Fh_off ; Если код функции 0FF00h, то возвращаем ; в регистре AX значение 00FFh.
Это признак ; того, что программа уже загружена в память installed: mov ax,00FFh iret new_int2Fh endp ;============================== ; Точка входа в программу ; В этом месте начинается выполнение программы begin proc ; Проверяем, не загружена ли уже программа ; в память mov ax,0FF00h int 2Fh cmp ax,00FFh jne first_start mov dx,offset msg_load1 mov ah,9 int 21h .EXIT ; Первоначальный запуск программы first_start: ; Запоминаем адрес старого обработчика прерывания 2Fh mov ax,352Fh int 21h mov cs:old_int2Fh_off,bx mov cs:old_int2Fh_seg,es push cs pop ds ; Выводим сообщение mov dx,offset msg_load mov ah,9 int 21h mov dx,OFFSET new_int2Fh mov ax,252Fh int 21h ; Завершаем программу и оставляем резидентно ; в памяти часть программы, содержащую новые ; обработчики прерываний mov dx,OFFSET begin int 27h begin endp msg_load db 'Резидентная программа WINTSR загружена$' msg_load1 db 'Резидентная программа WINTSR уже загружена$' end Следующая резидентная программа работает аналогично, но она запрещает запуск WINDOWS. Попробуйте, запустив предварительно программу NOWINTSR, запустить WINDOWS и посмотрите, что из этого получится.
Листинг 23. Запрет запуска WINDOWS Файл nowintsr.asm ----------------------------------------------------------- .MODEL tiny .CODE .STARTUP jmp begin old_int2Fh_off dw 0 ; Адрес старого обработчика old_int2Fh_seg dw 0 ; прерывания 2Fh ; Сообщение, которое выдаётся при запуске WINDOWS msg_win db 'NOWINTSR несовместима с WINDOWS. Нажмите любую клавишу...$' msg_win_off dw offset msg_win ; Сообщение, которое выдаётся при завершении WINDOWS msg_win1 db 10,13,'WINDOWS Ended. Press any key...$' msg_winend_off dw offset msg_win1 ; Новый обработчик прерывания 2Fh нужен ; для проверки наличия программы в памяти ; при ее запуске для предохранения ; от повторного запуска new_int2Fh proc far cmp ax,0FF00h jz installed cmp ax,1605h jz winstart cmp ax,1606h jz winend jmp dword ptr cs:old_int2Fh_off winstart: push ax push bx push cx push dx push ds mov dx,cs:msg_win_off mov ah,9 push cs pop ds int 21h mov ax,0 int 16h pop ds pop dx pop cx pop bx pop ax mov cx,0ffh jmp dword ptr cs:old_int2Fh_off winend: push ax push bx push cx push dx push ds mov dx,cs:msg_winend_off mov ah,9 push cs pop ds int 21h mov ax,0 int 16h pop ds pop dx pop cx pop bx pop ax jmp dword ptr cs:old_int2Fh_off ; Если код функции 0FF00h, то возвращаем ; в регистре AX значение 00FFh.
Это признак ; того, что программа уже загружена в память installed: mov ax,00FFh iret new_int2Fh endp ;============================== ; Точка входа в программу begin proc ; Проверяем, не загружена ли уже программа ; в память mov ax,0FF00h int 2Fh cmp ax,00FFh jne first_start mov dx,offset msg_load1 mov ah,9 int 21h .EXIT ; Первоначальный запуск программы first_start: ; Запоминаем адрес старого обработчика прерывания 2Fh mov ax,352Fh int 21h mov cs:old_int2Fh_off,bx mov cs:old_int2Fh_seg,es push cs pop ds ; Выводим сообщение mov dx,offset msg_load mov ah,9 int 21h mov dx,OFFSET new_int2Fh mov ax,252Fh int 21h ; Завершаем программу и оставляем резидентно ; в памяти часть программы, содержащую новые ; обработчики прерываний mov dx,OFFSET begin int 27h begin endp msg_load db 'Резидентная программа NOWINTSR загружена$' msg_load1 db 'Резидентная программа NOWINTSR уже загружена$' end