; WINDOWS XP FAT32 BOOT SECTOR SOURCE CODE (sector 12, 2nd half of VBR)
; by Erdogan Tan - 12/12/2017
; Disassembler: IDA Pro Free by Hex-Rays SA

; Last Modification: 16/12/2017

; ---------------------------------------------------------------------------
; º	This file is generated by The Interactive Disassembler (IDA)	    º
; º	Copyright (c) 2010 by Hex-Rays SA, <support@hex-rays.com>	    º
; º			 Licensed to: Freeware version			    º
; ---------------------------------------------------------------------------
; File Name   :	xp_fat32_bs.bin

		.386
		.model flat

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

; Segment type:	Regular
seg000		segment	byte public '' use16
		assume cs:seg000
		assume es:nothing, ss:nothing, ds:nothing, fs:nothing, gs:nothing
; ---------------------------------------------------------------------------
		;org	8000h
; jump from boot sector 0 (the 1st half)
		; cs, ds, es, ss is 0
		; bp = 7C00h
loc_0:
		movzx	eax, byte ptr [bp+10h] ; [BPB_NumFATs]
		mov	ecx, [bp+24h]	       ; [BPB_FATSz32]
		mul	ecx
		add	eax, [bp+1Ch]	       ; [BPB_HiddSec]
		movzx	edx, word ptr [bp+0Eh] ; [BPB_RsvdSecCnt]
		add	eax, edx
		mov	[bp-4],	eax  ; [7BFCh] ; Beginning of data area 	
		mov	dword ptr [bp-0Ch], 0FFFFFFFFh ; fat sec in 7BF4h
		mov	eax, [bp+2Ch]	       ; [BPB_RootClus] 	

		cmp	eax, 2		       ; cluster number >= 2 ?
		jb	near ptr 0FCD6h	       ; no, error, go to 7CD6h
					       ; 8000h+0FCD6h = 7CD6h	
		cmp	eax, 0FFFFFF8h	       ; max. valid cluster number	
		jnb	near ptr 0FCD6h	       ; error, go to 7CD6h
					       ; (NTLDR is missing' msg)	
loc_3A:	
		; calculate sector address of the cluster	
		push	eax
		sub	eax, 2		       ; zero based cluster number  
		movzx	ebx, byte ptr [bp+0Dh] ; [BPB_SecPerClus]
		mov	si, bx
		mul	ebx
		add	eax, [bp-4]	       ; sector addr of root dir's
					       ; 1st cluster 	 	
loc_4E:
		; load root directory sector
		; EAX = sector address (sector x)		
		mov	bx, 8200h	       ; ES:BX = root dir buff addr
		mov	di, bx	
		mov	cx, 1		       ; sector count 	 		
		call	near ptr 0FCE0h	       ; 7CE0h, read disk sector
		; EAX = next sector (sector x+1) 
		; BX = 8400h	
loc_59:	
		; search root dir entries for 'NTLDR      '
		cmp	[di], ch ; 0
		jz	short loc_7B ; end of directory entries, error	
		mov	cl, 0Bh ; 11 (file name field length of dir entry) 
		push	si
		mov	si, 7D70h	       ; 'NTLDR      ' address	
		repe	cmpsb
		pop	si
		jz	short loc_83	       ; 'NTLDR' found	
		add	di, cx
		add	di, 15h
		cmp	di, bx		       ; DX < 8400h ? 	
		jb	short loc_59	       ; yes, search next entry	
		dec	si		       ; is next sec in same clust ? 		
		jnz	short loc_4E	       ; yes, read next sector		       	
		pop	eax
		call	get_next_cluster  ; call sub_DE
		jb	short loc_3A	       ; not EOCC, load clus sectors
		; End Of Cluster Chain ('NTLDR' not found) 	
ntldr_not_found:
loc_7B:		add	sp, 4
		jmp	near ptr 0FCD6h	; 7CD6h ; (NTLDR is missing' msg)
; ---------------------------------------------------------------------------
loc_81:	 				      ; Offset 8081h
		dw	2000h
; ---------------------------------------------------------------------------

startup_file_found:
loc_83:		
		add	sp, 4
		mov	si, [di+9]	      ; [DIR_FstClusHI] (offset 20)         	
		mov	di, [di+0Fh]	      ; [DIR_FstClusLO] (offset 26)	
		mov	ax, si			
		shl	eax, 10h
		mov	ax, di
		; EAX = 1st cluster of 'NTLDR' file
		cmp	eax, 2
		jb	near ptr 0FCD6h	      ; Not a valid cluster (<2)	
		cmp	eax, 0FFFFFF8h	
		jnb	near ptr 0FCD6h	      ; Not a valid cluster (>max.) 	
loc_A6:	
		push	eax
		sub	eax, 2
		movzx	ecx, byte ptr [bp+0Dh] ; [BPB_SecPerClus]
		mul	ecx
		add	eax, [bp-4]	      ; Start sector of data area	 
		mov	bx, 0		      ; Buffer offset 0	
		push	es  ; ES = 0		     	
		mov	es, word ptr ds:8081h ; [loc_81] = 2000h
		; EAX = 1st sector address of the cluster
		; ECX = sector count = sectors per cluster
		; ES:BX = read buffer (sector loading addr: 2000h:BX) 
		call	near ptr 0FCE0h ; 7CE0h ; Read disk sectors 	
		pop	es  ; ES = 0
		pop	eax
		shr	bx, 4  ; convert byte offset to paragraphs
		add	ds:8081h, bx  ; next (read buff) segment in loc_81
		call	get_next_cluster ; call	sub_DE
		jnb	loc_D6
		jb	short loc_A6
		; End Of Cluster Chain (All of 'NTLDR' has been loaded) 
loc_D6:	
		mov	dl, [bp+40h]	     ; [BS_DrvNum]
		jmp	far ptr	2000h:0	     ; Jump to NTLDR (at Offset 0)
					     ; (FAT32 BS entry offset = 0)
					     ; (FAT16 BS entry offset = 3)		

; --------------- S U B	R O U T	I N E ---------------------------------------

sub_DE		proc near
get_next_cluster:
		; EAX = zero based cluster number	
		shl	eax, 2	; convert to dword offset
		call	get_cluster_offset ; call sub_F6
		mov	eax, es:[bx+di]	; BX = byte offset ES:DI = FAT buff
		and	eax, 0FFFFFFFh  ; 28 bit cluster number
		cmp	eax, 0FFFFFF8h  ; must be < max. cluster num + 1 
		retn
sub_DE		endp


; --------------- S U B	R O U T	I N E ---------------------------------------

sub_F6		proc near
get_cluster_offset: Get cluster offset from start of FAT buffer	
		; EAX = cluster (dword) number offset 
		mov	di, 7E00h ; FAT32 sector buffer at 0:7E000h
		movzx	ecx, word ptr [bp+0Bh] ; [BPB_BytesPerSec]
		xor	edx, edx
		div	ecx
		; DX = cluster (dword) offset in FAT buffer
		cmp	eax, [bp-0Ch]	; FAT sector number in the buffer
		jz	short loc_144	; same FAT sector (with sec in buff)
		mov	[bp-0Ch], eax	; update FAT buff's sector pointer
		; calculate absolute (LBA) disk address of FAT sector
		add	eax, [bp+1Ch]	; [BPB_HiddSec]
		movzx	ecx, word ptr [bp+0Eh] ; [BPB_RsvdSecCnt]
		add	eax, ecx
		movzx	ebx, word ptr [bp+28h] ; [BPB_ExtFlags]
		and	bx, 0Fh		; check for active FAT number
		jz	short loc_13A	; FAT copy 0 is active
		cmp	bl, [bp+10h]	; active FAT num < [BPB_NumFATs] ?
		jnb	near ptr 0FCD6h ; no, error!, go to 7CD6h
		push	dx
		mov	ecx, eax
		mov	eax, [bp+24h]	; [BPB_FATSz32]
		mul	ebx
		add	eax, ecx	; add (inactive) FAT space to LBA
		pop	dx
loc_13A:	
		push	dx
		mov	bx, di		; FAT sector buffer is at 0:7E00h
		mov	cx, 1		; sector count = 1 
		call	near ptr 0FCE0h ; 7CE0h, read disk sector(s)
		pop	dx
loc_144:	
		mov	bx, dx ; move (buffer) cluster number offset to BX
		retn
sub_F6		endp

; ---------------------------------------------------------------------------
		db	81FEh-$ dup(0)
		;org	81FEh
boot_sector_sign:
		db  55h, 0AAh

seg000		ends

		end