22.10.2009, 10:39
общий
это ответ
Здравствуйте, dr213.
Исправлены все Ваши ошибки:
1) Строки, выводимые из резидента, должны быть доступны из резидента.
Не забывайте, что после
mov dx,offset Init
int 27h
все последующее за Init отсекается
2) Подпрограмма Out_mess должна быть доступна из резидента
3) Для вывода сообщения из прерывания лучше использовать int 10h
4) 9 вектор вообще построен неправильно. После того, как Вы отработаете старым вектором, in al,60h Вам уже не даст скан-код
5) Освобождение сегмента окружения надо делать после того, как Вы возьмете оттуда параметр командной строки
Приложение:
;TASM.EXE resid27.asm
;TLINK.EXE resid27.obj /t/x
;-------------------------------------------------------------------------
;=== Начало программы: ===
cseg segment
.286
assume cs:cseg, ds:cseg, ss:cseg, es:cseg
org 100h
Begin:
jmp Init ; На метку инициализации
Any_key db 0dh,0Ah,'Для продолжения нажмите любую клавишу...$'
Prog_work db 0dh,0Ah,'Программа работает!',0Ah,0Dh,'$'
;--------------------------------------------------------------------------
; === Обработчик 21h-ого прерывания ===
Int_21h_proc proc
; ---
cmp ax,9988h ;Проверка на повторную загрузку?
jne No_test
xchg ah,al ;Даем наш "отклик".
iret ;И моментально выходим из прерывания...
; ---
No_test:
cmp ax,9999h ;Получаем информацию о нашем резиденте?
jne No_remove
mov ax,9998h ;Даем отклик и...
push cs ;...передаем в ES сегмент резидента...
pop es
mov dx,offset Int_21h_proc ;...в DX смещение...
;...BX - смещение оригинального обработчика...
mov bx,word ptr cs:[Int_21h_vect]
;...CX - сегмент оригинального обработчика...
mov cx,word ptr cs:[Int_21h_vect+2]
iret ;...и выходим из резидента.
; ---
No_remove:
;Передаем управление предыдущему (оригинальному) обработчику
;21h-ого прерывания без условия того, что потом опять вернемся сюда.
jmp dword ptr cs:[Int_21h_vect]
Int_21h_vect dd ?
Int_21h_proc endp
;---------------------------------------------------------------------------
; === Вывод строки на экран ===
Out_mess proc
push si
mov si,dx
lll:
lods byte ptr cs:[si]
cmp al,'$'
je om_ret
mov ah,0eh
int 10h
jmp lll
om_ret:
; mov ah,9 ;Выводим строку. DX уже должен содержать ее адрес!
; int 21h
pop si
ret
Out_mess endp
;-----------------------------------------------------------------------------------
; === Обработчик 09h-ого прерывания ===
Int_09h_proc proc
cli ;Запрещаем все прерывания
push ax
in al,60h ;Получим СКАН-КОД нажатой клавиши.
cmp al,58h ;Нажали F12?
jnz to_old_09h ;Если да - выводим сообщение
pushf
call dword ptr cs:[Int_09h_vect] ;оригинальный обработчик
push dx
mov dx,offset Prog_work
call Out_mess
pop dx
pop ax
iret
to_old_09h:
pop ax
jmp dword ptr cs:[Int_09h_vect] ;на оригинальный обработчик
Int_09h_vect dd ?
Int_09h_proc endp
;-------------------------------------------------------------------------------
; === Инициализация (подготовка и настройка резидента) ===
Init:
call Get_cmd ;Проверим командную строку
;Итак,
;Если ничего в командной строке не введено, тогда пробуем установить резидент.
or al,al
jz Ok_cmd
;Если в командной строке введено '/u', то пробуем удалить программу из памяти.
cmp al,1
je Remove
;В противном случае выведем сообщение о неверной командной строке
;и завершимся...
Bad_cmd:
mov dx,offset Mess_badcmd
call Out_mess
ret
;На процедуру удаления программы из памяти...
Remove:
jmp Remove_prog
;Устанавливаем резидент.
Ok_cmd:
mov ax,9988h ;Проверка на повторную загрузку.
int 21h
cmp ax,8899h ;Получили наш отклик?
jne Next_step2 ;Нет. Тогда
;Мы уже в памяти! Выведем соответствующую строку.
mov dx,offset Mess_memory
call Out_mess ;Универсальная процедура вывода строки.
ret ;Выйдем в DOS...
Next_step2:
; === 21h ===
;Все готово для перехвата прерывания и установки резидента.
mov ax,3521h
int 21h ;Получим и сохраним адрес (вектор) 21h прерывания
mov word ptr cs:[Int_21h_vect],bx ;Смещение...
mov word ptr cs:[Int_21h_vect+2],es ;Сегмент...
mov ax,2521h
mov dx,offset Int_21h_proc
int 21h ;"Повесим" нашу процедуру на 21h прерывание
; === 09h ===
mov ax,3509h
int 21h ;Получим и сохраним адрес (вектор) 09h прерывания
mov word ptr cs:[Int_09h_vect],bx ;Смещение...
mov word ptr cs:[Int_09h_vect+2],es ;Сегмент...
mov ax,2509h
lea dx,Int_09h_proc
int 21h ;"Повесим" нашу процедуру на 09h прерывание
;Выведем сообщение, что, мол, все в порядке!!! Программа загружена в память!
mov dx,offset Mess_hello
call Out_mess
mov es,word ptr cs:[2Ch] ;Получим сегмент окружения DOS.
mov ah,49h ;Функция освобождения памяти.
int 21h ;Освобождаем память...
;Оставляем резидентную часть в памяти и выходим в DOS.
mov dx,offset Init
int 27h
;------------------------------------------------------------------------------------------------------
; ======= Пошли подпрограммы =======
; --- Получим параметры в командной строке ---
Get_cmd proc
mov si,80h ;SI=смещение командной строки.
lodsb ;Получим кол-во символов.
or al,al ;Если 0 символов введено,
jz Got_cmd ;то все в порядке.
cmp al,3 ;Иначе ввели не 3 символа? (пробел + /u)
jne No_string ;Да - на метку No_string
inc si ;Теперь SI указывает на первый символ строки.
Next_char:
lodsw ;Получаем два символа
cmp ax,'u/' ;Это /u? Помним, что данные будут наоборот!!!
jne No_string ;Да - на выход...
mov al,1 ;Сигнал того, что пора удалять программу из памяти
ret
Got_cmd:
xor al,al ;Сигнал того, что ничего не ввели в командной строке
ret ;Выходим из процедуры
No_string:
mov al,3 ;Сигнал неверного ввода командной строки
ret ;Выходим из процедуры
Get_cmd endp
; === Удаляем программу из памяти ===
Remove_prog:
;Прежде посылаем сигнал 21h-ому прерыванию, т.е. 9999h.
mov ax,9999h
int 21h
;Если в ответ получаем 9998h, то наш резидент "сидит" в памяти.
cmp ax,9998h
je In_mem ;Перейдем на соответствующую метку.
;Если мы не получили отклик (9998h), то наш резидент не загружен.
;Сообщим об этом пользователю и выйдем в DOS.
mov dx,offset Mess_badmem
call Out_mess
ret
;-------------------------------------------------------------------------------
;Итак, наш резидент сидит в памяти.
;Помимо отклика от нашего резидента мы также получаем (см. процедуру
;обрабоки прерывания 21h выше):
;* ES = сегмент, в который загрузился резидент;
;* DX = смещение резидента в данном сегменте;
;* CX = сегмент оринигального (прежнего) обработчика прерывания 21h;
;* BX = смещение оринигального (прежнего) обработчика прерывания 21h.
In_mem:
push es ;Сохраним некоторые регистры в стеке,..
push bx
mov Seg_21h,es ;...а также в переменных.
mov Off_21h,dx
push bx
push cx
mov ax,3521h
int 21h ;Получим адрес обработчика 21h-прерывания.
;Равен ли он тому, куда загружен наш обработчик?
;Если так, то никто не "повис" над нами. Т.е. можно смело удалять нашу
;программу из памяти.
mov ax,es
cmp ax,Seg_21h
jne Cannot_remove
cmp bx,Off_21h
jne Cannot_remove
;Вот и удаляем. Внимательно проследите, что мы загружаем в регистры!
cli
mov ax,2521h
pop ds
pop dx
int 21h
push cs
pop ds
mov ah,49h
int 21h
sti
;Программа удалена! Выведем сообщение об успешном удалении и вернемся в DOS.
mov dx,offset Remove_okmess
Exit_prog:
call Out_mess
int 20h
;Невозможно удалить программу, т.к. кто-то "повис" над нами.
Cannot_remove:
;Сообщим о случившейся беде пользователю и выйдем в DOS...
mov dx,offset Mess_cantremove
jmp short Exit_prog
Seg_21h dw ?
Off_21h dw ?
;----------------------------------------------------------------------------------------------
; === Сообщения ===
Mess_hello db 0Ah,0Dh,'Резидентная программа.',0Ah,0Dh
db 'Программа загружена в память',0Ah,0Dh,'$'
Mess_memory db 0Ah,0Dh,' Программа уже загружена в память ',0Ah,0Dh
db 'Для ее удаления из памяти укажите /u в командной строке.',0Ah,0Dh,'$'
Mess_badcmd db 0Ah,0Dh,'Неверно указан параметр в командной строке.',0Ah,0Dh
db 'Укажите /u, если хотите удалить программу из памяти.',0Ah,0Dh,'$'
Mess_badmem db 0Ah,0Dh,'Программы ведь нет в памяти. Удаление невозможно.',0Ah,0Dh,'$'
Remove_okmess db 0Ah,0Dh,'Программа успешно удалена из памяти.',0Ah,0Dh,'$'
Mess_cantremove db 0Ah,0Dh,'Не могу удалить резидент из памяти.',0Ah,0Dh,0Ah
db 'Какая-то программа перехватила 21h-ое прерывание после того,',0Ah,0Dh
db 'как загружен был RES.COM. Прежде необходимо удалить ее из памяти,',0Ah,0Dh
db 'а потом уже удалять RES.COM!',0Ah,0Dh,'$'
cseg ends
end Begin
Об авторе:
"Если вы заметили, что вы на стороне большинства, —
это верный признак того, что пора меняться." Марк Твен