;обработчик DOS достигнут, иначе – продолжаем трассировку
;и выходим из обработчика
cmp word ptr [bp+4],300h
jnc ExitFromInt
;Достигнут DOS – берем из стека адрес обработчика и сохраняем его
push bx
mov bx,[bp+2]
mov word ptr cs:O21,bx
mov bx,[bp+4]
mov word ptr cs:S21,bx
pop bx
;Заканчиваем обработку прерывания и дальнейшую трассировку
TraceOff:
;Устанавливаем в ноль бит, соответствующий TF,
;в копии регистра флагов в стеке
and word ptr [bp+6],0FEFFh
;Устанавливаем в ноль флаг продолжения
mov byte ptr cs:ContinueFlag,0
ExitFromInt:
pop bp
;Выходим из обработчика
iret
;Восстановление после трассировки
Next:
;Сбрасываем флаг продолжения
mov byte ptr ds:ContinueFlag,0
;Восстанавливаем прежнее значение вектора прерывания INT 01h
mov ax,2501h
mov dx,si
mov ds,di
int 21h
В настоящее время этот алгоритм можно считать несколько устаревшим. Дело в том, что современные версии DOS могут размещать свой обработчик в областях верхней памяти. Поэтому условие окончания трассировки должно выглядеть, например, так:
cmp word ptr [bp+4],300h
jb loc_65
cmp word ptr [bp+4],0F000h
ja loc_65
В качестве альтернативного варианта можно использовать такой прием. Сначала определяется исходный сегмент DOS при помощи недокументированной функции 52h прерывания INT 21h (возвращает адрес векторной таблицы связи DOS):
mov ah, 52h
int 21h
mov SegDOS, es
Тогда условие завершения трассировки можно оформить следующим образом:
push ax
mov ax, cs: SegDOS
cmp word ptr [bp+6], ax
pop ax
jz DOSIsGot
Разумеется, разные приемы могут дать разные результаты. Причем все результаты можно считать в той или иной мере корректными. Дело в том, что современные версии DOS, даже будучи загруженными в верхнюю память, всегда имеют точку входа в нижней памяти вида:
nop
nop
;Проверка состояния адресной линии A20
call Check_A20
;Переход в верхнюю память
jmp cs: dword ptr HI_DOS
С точки зрения обхода резидентных мониторов «правильным» следует признать адрес в обработчике DOS, имеющий максимальное значение. Мы еще вернемся к вопросу о нахождении «правильного» адреса далее. Авторы антивирусных мониторов знают о подобном приеме поиска оригинального адреса DOS. Достаточно легко испортит трассировку, например, вот такой вот фрагмент, встроенный в цепочку обработчиков:
;Вызываем обработчик прерывания INT 60h (до этого момента
;прерывание INT 60h должно быть перехвачено)
int 60h
;Сюда нужно вернуться из прерывания
nop
;Сюда реально вернемся, и флаг трассировки будет сброшен,
;то есть трассировка будет прекращена
nop