Читаем Создаем вирус и антивирус полностью

В настоящее время этот алгоритм можно считать несколько устаревшим. Дело в том, что современные версии 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

...

;Обработчик прерывания. При вызове прерывания флаг трассировки

;сбрасывается – при входе в обработчик трассировка будет

выключена

Int60:

;Разрешение прерываний, так как при выходе из обработчика не

;будет восстанавливаться оригинальное значение регистра флагов

sti

;Увеличиваем на единицу адрес возврата в стеке

push bp

mov bp, sp

add [bp+2],1

pop bp

;Выходим из прерывания, но не командой IRET, а командой RETF 2,

;чтобы не восстанавливать флаги (и, как следствие,

;флаг трассировки TF)

retf 2

Кроме того, факт трассировки можно достаточно просто обнаружить, применив хорошо известный разработчикам защит от несанкционированного копирования прием аппаратного конвейера, который использует процессор для ускорения работы. При выполнении очередной команды процессор считывает код следующей. Когда придет время выполнения следующей команды, она будет уже считана из памяти, и не нужно будет тратить время на ее чтение. Прием заключается в модификации команд, которые уже оказались в конвейере: если трассировка не ведется, то код команд модифицируется только в памяти, а выполняется та программа, которая находится в конвейере. Если трассировка ведется, то конвейер сбрасывается перед каждой командой трассируемой программы (конвейер сбрасывают такие команды, как JMP, CALL, RET) и выполняется модифицированный код.

;Модифицируем следующую команду. Команда JMP (безусловный

;переход) заменяется на две команды NOP (нет операции)

mov Metka, 9090h

;Переходим, если выполняется немодифицированный код (в случае,

;когда трассировка не ведется), и проходим дальше, если выполняется

;модифицированный код (в случае трассировки)

Metka: jmp NoTrace

Trace:

;Сюда попадем при выявленном факте трассировки

NoTrace:

;Трассировка не ведется – нормальное выполнение программы

Перейти на страницу:
Нет соединения с сервером, попробуйте зайти чуть позже