Assembler - язык неограниченных возможностей

         

Пассивная резидентная программа


В качестве первой резидентной программы рассмотрим именно пассивный резидент, который будет активироваться при попытке программ вызывать INT 21h и запрещать удаление файлов с указанного диска.

; tsr.asm ; Пример пассивной резидентной программы. ; Запрещает удаление файлов на диске, указанном в командной строке, всем ; программам, использующим средства DOS .model tiny .code org 2Ch envseg dw ? ; сегментный адрес копии окружения DOS

org 80h cmd_len db ? ; длина командной строки cmd_line db ? ; начало командной строки

org 100h ; СОМ-программа start: old_int21h: jmp short initialize ; эта команда занимает 2 байта, так что dw 0 ; вместе с этими двумя байтами получим ; old_int21h dd ? int21h_handler proc far ; обработчик прерывания 21h pushf ; сохранить флаги cmp ah,41h ; Если вызвали функцию 41h (удалить je fn41h ; файл) cmp ax,7141h ; или 7141h (удалить файл с длинным именем), je fn41h ; начать наш обработчик, jmp short not_fn41h ; иначе - передать управление ; предыдущему обработчику fn41h: push ax ; сохранить модифицируемые push bx ; регистры mov bx,dx cmp byte ptr ds:[bx+1],':' ; если второй символ ASCIZ-строки, ; переданной INT 21h, ; двоеточие - первый символ ; должен быть именем диска, je full_spec mov ah,19h ; иначе: int 21h ; функция DOS 19h - определить текущий диск, add al,'А' ; преобразовать номер диска к заглавной букве, jmp short compare ; перейти к сравнению full_spec: mov al,byte ptr [bx] ; AL = имя диска из ASCIZ-строки and al,11011111b ; преобразовать к заглавной букве compare: cmp al,byte ptr cs:cmd_line[1] ; если диски je access_denied ; совпадают - запретить доступ, pop bx ; иначе: восстановить pop ax ; регистры not_fn41h: popf ; и флаги jmp dword ptr cs:old_int21h ; и передать управление ; предыдущему обработчику INT 21h access_denied: pop bx ; восстановить регистры pop ax popf push bp mov bp,sp or word ptr [bp+6],1 ; установить флаг переноса ; (бит 0) в регистре флагов, ; который поместила команда INT в стек ; перед адресом возврата pop bp mov ax,5 ; возвратить код ошибки "доступ запрещен" iret ; вернуться в программу int21h_handler endp


initialize proc near cmp byte ptr cmd_len,3 ; проверить размер командной строки jne not_install ; (должно быть 3 - пробел, диск, двоеточие), cmp byte ptr cmd_line[2],':' ; проверить третий символ jne not_install ; командной строки (должно быть двоеточие), mov al,byte ptr cmd_line[1] and al,11011111b ; преобразовать второй ; символ к заглавной букве, cmp al,'А' ; проверить, что это не jb not_install ; меньше "А" и не больше cmp al,'Z' ; "Z", ja not_install ; если хоть одно из этих условий ; не выполняется - выдать информацию ; о программе и выйти, иначе - начать ; процедуру инициализации mov ax,3521h ; АН = 35h, AL = номер прерывания int 21h ; получить адрес обработчика INT 21h mov word ptr old_int21h,bx ; и поместить его в old_int21h mov word ptr old_int21h+2,es

mov ax,2521h ; AH = 25h, AL = номер прерывания mov dx,offset int21h_handler ; DS:DX - адрес нашего обработчика int 21h ; установить обработчик INT 21h mov ah,49h ; AH = 49h mov es,word ptr envseg ; ES = сегментный адрес блока с нашей ; копией окружения DOS int 21h ; освободить память из-под окружения mov dx,offset initialize ; DX - адрес первого байта за концом ; резидентной части программы int 27h ; завершить выполнение, оставшись ; резидентом

not_install: mov ah,9 ; АН = 09h mov dx,offset usage ; DS:DX = адрес строки с информацией об ; использовании программы int 21h ; вывод строки на экран ret ; нормальное завершение программы

; текст, который выдает программа при запуске с неправильной командной строкой: usage db "Использование: tsr.com D:",0Dh,0Ah db "Запрещает удаление на диске D:",ODh,OAh db "$" initialize endp end start

Если запустить эту программу с командной строкой D:, никакой файл на диске D нельзя будет удалить командой Del, средствами оболочек типа Norton Commander и большинством программ для DOS. Действие этого запрета, однако, не будет распространяться на оболочку Far, которая использует системные функции Windows API, и на программы типа Disk Editor, обращающиеся с дисками при помощи функций BIOS (INT 13h). Несмотря на то что мы освободили память, занимаемую окружением DOS (а это могло быть лишних 512 или даже 1024 байта), наша программа все равно занимает в памяти 352 байта из-за того, что первые 256 байт отводятся для блока PSP. Существует возможность оставить программу резидентной без PSP — для этого инсталляционная часть программы должна скопировать резидентную часть с помощью, например, movs в начало PSP. Но при этом возникает сразу несколько проблем: во-первых, команда INT 27h, так же как и функция DOS 31h, использует данные из PSP для своей работы, во-вторых, код резидентной части должен быть написан для работы с нулевого смещения, а не со 100h, как обычно, и, в-третьих, некоторые программы, исследующие выделенные блоки памяти, определяют конец блока по адресу, находящемуся в PSP программы — владельца блока со смещением 2. С первой проблемой можно справиться вручную, создав отдельные блоки памяти для резидентной и инсталляционной частей программы, новый PSP для инсталляционной части и завершив программу обычной функцией 4Ch или INT 20h. Реальные программы, делающие это, существуют (например, программа поддержки нестандартных форматов дискет PU_1700), но мы не будем чрезмерно усложнять наш первый пример и скопируем резидентную часть не в позицию 0, а в позицию 80h, то есть, начиная с середины PSP, оставив в нем все значения, необходимые для нормальной работы функций DOS.



Прежде чем это сделать, заметим, что и номер диска, и адрес предыдущего обработчика INT 21h изменяются только при установке резидента и являются константами во время всей его работы. Более того, каждое из этих чисел используется только по одному разу. В этих условиях оказывается, что можно вписать номер диска и адрес перехода на старый обработчик прямо в код программы. Более того, после этого наш резидент не будет больше ссылаться ни на какие переменные с конкретными адресами, а значит, его код становится перемещаемым, то есть его можно выполнять, скопировав в любую область памяти.

; tsrpsp.asm ; Пример пассивной резидентной программы с переносом кода в PSP. ; Запрещает удаление файлов на диске, указанном в командной строке, ; всем программам, использующим средства DOS

.model tiny .code org 2Ch envseg dw ? ; сегментный адрес копии окружения DOS

org 80h cmd_len db ? ; длина командной строки cmd_line db ? ; начало командной строки

org 100h ; СОМ-программа start: old_int21h: jmp short initialize ; переход на инициализирующую часть

int21h_handler proc far ; обработчик прерывания 21h pushf ; сохранить флаги cmp ah,41h ; Если вызвали функцию 41h ; (удалить файл) je fn41h cmp ax,7141h ; или 7141h (удалить файл ; с длинным именем), je fn41h ; начать наш обработчик, jmp short not_fn41h ; иначе - передать ; управление предыдущему обработчику fn41h: push ax ; сохранить модифицируемые push bx ; регистры mov bx,dx ; можно было бы использовать ; адресацию [edx+1], но в старшем ; слове EDX совсем не обязательно 0, cmp byte ptr [bx+1],':' ; если второй символ ; ASCIZ-строки, переданной INT 21h, ; двоеточие, первый символ должен ; быть именем диска, je full_spec mov ah,19h ; иначе: int 21h ; функция DOS 19h - определить ; текущий диск add al,'А' ; преобразовать номер диска ; к заглавной букве jmp short compare ; перейти к сравнению full_spec: mov al,byte ptr [bx] ; AL = имя диска из ASCIZ-строки and al,11011111b ; преобразовать к заглавной букве compare: db 3Ch ; начало кода команды CMP AL,число drive_letter: db 'Z' ; сюда процедура инициализации ; впишет нужную букву pop bx ; эти регистры больше не pop ax ; понадобятся, если диски совпадают - je access_denied ; запретить доступ not_fn41h: popf ; восстановить флаги и передать ; управление предыдущему ; обработчику INT 21h: db 0EAh ; начало кода команды ; JMP, FAR-число old_int21h dd 0 ; сюда процедура инициализации ; запишет адрес предыдущего ; обработчика INT 21h access_denied: popf push bp mov bp,sp ; чтобы адресоваться в стек ; в реальном режиме, or word ptr [bp+6],1 ; установить флаг ; переноса (бит 0) в регистре ; флагов, который поместила команда ; INT в стек перед адресом возврата pop bp mov ax,5 ; возвратить код ошибки ; "доступ запрещен" iret ; вернуться в программу int21h_handler endp



tsr_length equ $-int21h_handler

initialize proc near cmp byte ptr cmd_len,3 ; проверить размер ; командной строки jne not_install ; (должно быть 3 - ; пробел, диск, двоеточие) cmp byte ptr cmd_line[2],':' ; проверить ; третий символ командной jne not_install ; строки (должно быть двоеточие) mov al,byte ptr cmd_line[1] and al,11011111b ; преобразовать второй ; символ к заглавной букве cmp al,'A' ; проверить, что это не меньше "А" jb not_install ; и не больше cmp al,'Z' ; "Z", ja not_install ; если хоть одно из ; этих условий ; не выполняется - выдать информацию о программе и выйти, ; иначе - начать процедуру инициализации mov byte ptr drive_letter,al ; вписать имя ; диска в код резидента push es mov ax,3521h ; АН = 35h, ; AL = номер прерывания int 21h ; получить адрес обработчика INT 21h mov word ptr old_int21h,bx ; и вписать его ; в код резидента mov word ptr old_int21h+2,es pop es

cld ; перенос кода резидента, mov si,offset int21h_handler ; начиная ; с этого адреса, mov di,80h ; в PSP:0080h rep movsb mov ax,2521h ; AH = 25h, ; AL = номер прерывания mov dx,0080h ; DS:DX - адрес нашего обработчика int 21h ; установить обработчик INT 21h mov ah,49h ; AH = 49h mov es,word ptr envseg ; ES = сегментный адрес блока ; с нашей копией окружения DOS int 21h ; освободить память из-под ; окружения mov dx,80h+tsr_length ; DX - адрес первого ; байта за концом резидентной части ; программы int 27h ; завершить выполнение, ; оставшись резидентом not_install: mov ah,9 ; АН = 09h mov dx,offset usage ; DS:DX = адрес строки ; с информацией об ; использовании программы int 21h ; вывод строки на экран ret ; нормальное завершение ; программы

; текст, который выдает программа при запуске ; с неправильной командной строкой: usage db "Usage: tsr.com D:",0Dh,0Ah db "Denies delete on drive D:",0Dh,0Ah db "$" initialize endp end start

Теперь эта резидентная программа занимает в памяти только 208 байт.


Содержание раздела