Ю. Косивцов

Конструирование антивирусного "сторожа"

Пример 1

Пример процедуры, которая производит замену точки входа DOS. Начало
установки драйвера

Новая точка входа INT 21h
DOS_ENTRY_POINT PROC NEAR
        PUSHF
        CMP AH,4CH
        JE EXIT          ; Чтобы "сторож" не реагировал на Ctrl-break В PC DOS
        DB 80H           ;─┐ Инструкция CMP AH,0 (FFh),
        DB 0FCH          ; │ был ли проход цепочки прерывания
CHAIN   DB 0FFh          ;─┘
        JB EVASION       ;   Нет, цепочка обойдена
EXIT:   DB 2EH           ;─┐ Выход, если цепочка пройдена,
        DB 0C6H          ; │ инструкция MOV CS:CHAIN,0FFH -
        DB 06H           ; │ сброс переменной "проход цепочки"
OFS_1   DW OFFSET CHAIN  ; │
        DB 0FFH          ;─┘
        POPF
INST_1  DB 80H           ;─┐ Сохраненная точка входа в DOS
INST_2  DW 33FCH         ;─┘ инструкция CMP AH,... или JMP для DOS 5.00

INST_3  DB 0E9H          ;─┐ JMP NEAR в точку входа в DOS 3.XX И 4.XX
OFS_2   DW OFFSET EVASION;─┘
EVASION:
        DB 0EAH          ; Если был обход цепочки, то JMP FAR
        DW OFFSET EVASION_CHAIN   ; на процедуру обработки такой
SEG_1   DW ?              ; ситуации
DOS_ENTRY_POINT ENDP

; Процедура обработки "обхода цепочки INT 21H"
EVASION_CHAIN PROC
        ...


; Начало установки драйвера
INSTALL_DRIVER:
        XOR AX,AX        ; Установка ES
        MOV ES,AX        ; на таблицу векторов
        MOV AX,ES:[86H]  ; Сегмент точки входа INT 21H (MS-DOS)
        MOV BX,ES:[84H]  ; Смещение точки входа INT 21H (MS-DOS)
        MOV SEG_JMP,AX   ; Занесение сегмента DOS в переменную
        MOV SEG_2,AX     ; Настройка сегмента в JMP FAR
        MOV DX,CS
        MOV SEG_1,DX     ; Построение JMP FAR
        SUB DX,AX        ; В DX разность сегментов драйвера и DOS
        MOV CL,4
        SHL DX,CL        ; Перевод разности сегментов в смещение
	JC BREAK_INSTALL ;
        MOV SI,DX        ; Сохранение поправки на разность сегментов
        ADD DX,OFFSET EVASION_CHAIN ; Получение смещения относительно
                                    ; сегмента DOS
        JC BREAK_INSTALL ; Разность сегментов недопустимо велика
	SUB DX,BX
        CMP DX,8000H     ; Сравнение с максимально возможной разностью смещений
        JAE BREAK_INSTALL; Разность сегментов недопустимо велика
	PUSH DS
        MOV DS,AX        ; DS:BX на точку входа DOS
; Выяснение истинной версии DOS
        CLC              ; Сброс CARRY флага
        PUSH BX          ; Сохранение BX
        MOV AX,3306H     ; Функция 33Н, подфункция 6
        INT 21H
        JC INCORRECT_DOS_VERSION_2  ; Если взведен CARRY, то это DR DOS
        CMP AL,0FFH
        JE THREE_OR_FOUR ; Если AL=0FFH, то это версия DOS старше 5.00
        CMP BX,5
        POP BX
        JE VERSION_5     ; Если BX=5, то это MS-DOS 5.00
        ...
Пример 2

Пример установки своего обработчика завершения процесса

INSTALL_RETURN_ADRESS:
        INC STACK_EXEC     ; Увеличение указателя вложенности EXEC
; Далее расчет на основании указателя вложенности положения текущей
; структуры для сохранения адреса возврата и переменных
        MOV AL,STACK_EXEC  ; Загрузка в AL указателя уровня вложенности EXEC
        MOV CL,3           ; Подготовка к умножению на 8
        CBW                ; Конвертирование байта в слово
        SHL AX,CL          ; * 8 - получение поправки к смещению
        MOV SI,OFFSET STACK_EXEC_AREA  ; Загрузка адреса переменной
        ADD SI,AX          ; Корректирование адреса с учетом уровня вложенности

; Сканирование блоков памяти
        PUSH DS            ; Сохранение DS
        MOV AX,FIRST_MCB   ; Загрузка в AX переменной, заполняемой при
                           ; инициализации драйвера (начало цепочки MCB)

; Основной цикл сканирования блоков памяти
MCB_CYCL_1:
        MOV DS,AX               ; Загрузка DS сегментным адресом MCB
        MOV BX,AX               ; Сохранение сегментного адреса MCB в BX
        CMP BYTE PTR DS:[0],'Z' ; Это последний блок в цепочке?
        JE END_MCB_1            ; Да, выход из цикла сканирования блоков
        CMP WORD PTR DS:[1],0   ; Проверка пустоты блока
        JE FREE_BLOCK           ; Да, блок пустой
        XOR DI,DI          ; Обнуление DI - признак непустого блока памяти

; Расчет адреса следующего блока памяти
CONTINUE_MCB_CYCL_1:
        MOV AX,DS:[3]           ; Загрузка в AX размера блока памяти
        ADD AX,BX               ; Сложение с адресом текущего блока
        INC AX                  ; Поправка на MCB
        JMP SHORT MCB_CYCL_1    ; Возврат в основной цикл

; При обнаруженном пустом блоке памяти
FREE_BLOCK:
        OR DI,DI           ; Проверка DI=0, признак предыдущего пустого блока
        JNZ CONTINUE_MCB_CYCL_1 ; Предыдущий блок пустой, ничего не делать
        MOV DI,BX               ; Занесение адреса пустого блока в DI
        JMP SHORT CONTINUE_MCB_CYCL_1  ; Возврат в основной цикл

; Сканирование блоков закончено
END_MCB_1:
        POP DS                ; Восстановление DS
        OR DI,DI              ; Была ли обнаружена цепочка пустых блоков
        JZ NON_FREE_BLOCK     ; Нет
        MOV DS:[SI],DI        ; Иначе - занесение в переменную начала цепочки
        JMP SHORT CONTINUE_BLOCK_SET

; Цепочка пустых блоков не обнаружена
NON_FREE_BLOCK:
        MOV DS:[SI],AX        ; Занесение в переменную адреса последнего блока

; Завершение установок и выход в DOS
CONTINUE_BLOCK_SET:
; Сохранение оригинального адреса возврата для EXEC
        MOV AX,SS:[BP+2]       ; Смешение адреса возврата EXEC в AX
        MOV DS:[SI+2],AX       ; Сохранение в переменной
        MOV AX,SS:[BP+4]       ; Сегмент адреса возврата EXEC в AX
        MOV DS:[SI+4],AX       ; Сохранение в переменной
        MOV BYTE PTR DS:[SI+6],1 ; Разрешение сообщения о TSR

; Занесение в стек в качестве адреса возврата указателя на обработчик
        MOV WORD PTR SS:[BP+2],OFFSET END_EXEC
        MOV SS:[BP+4],CS

; Передача управления DOS
END_SETTING:
        JMP RETURN_FOR_DOS
;Пример 3
;
;Данная программа после завершения останется резидентной
 с помощью манипуляции блоками памяти
;
;  Любой ассемблер и компоновщик. Должна конвертироваться в COM-файл.

CODE SEGMENT WORD PUBLIC
ASSUME CS:CODE,DS:CODE

ORG 100H

; Точка входа COM-файла
START:

; Сжатие занимаемого блока памяти до 50 Кбайтов
        MOV BX,0C80H               ; BX - требуемый размер блока в параграфах
        MOV AH,4AH                 ; AX - номер функции сжатия блока памяти 
        INT 21H                    ; Вызов DOS (ES - PSP программы)
        JC _ERROR                  ; Переход, если была ошибка

; Удаление окружения процесса
        MOV AX,DS:[2CH]            ; Загрузка сегментного адреса окружения
        MOV ES,AX                  ; процесса в ES
        MOV AH,49H                 ; Освобождение блока памяти, занимаемого
        INT 21H                    ; окружением процесса
        JC _ERROR                  ; Переход, если была ошибка

; Корректировка поля владельца в MCB
        PUSH DS                    ; Загрузка в ES адреса MCB, равного
        POP AX                     ; значению адреса PSP программы - 1
        DEC AX                     ;
        PUSH AX                    ;
        POP ES                     ;
        MOV WORD PTR ES:[1],8      ; Корректировка поля владельца блока
        MOV DX,OFFSET OK_MESSAGE   ; Подготовка к хорошему сообщению
        JMP SHORT _QUIT

; При ошибке работы с блоками выдача сообщения
_ERROR:
        MOV DX,OFFSET ER_MESSAGE   ; Подготовка к плохому сообщению
_QUIT:
        MOV AH,9                   ; Вывод строки на экран
        INT 21H                    ;
        MOV AX,4C00H               ; Завершение с незаконным оставлением
        INT 21H                    ; в памяти блока размером 50 Кбайтов

OK_MESSAGE DB 'Нет ошибки',0DH,0AH,'$'
ER_MESSAGE DB 'Ошибка!',0DH,0AH,'$'

CODE ENDS
END START
