开篇文:NTFS文件系统分析之序章:NTFS分区的引导记录源码

  终于决心开BLOG了,准备写个NTFS系列,这篇老文就作为序吧:)

  NTFS文件系统有着非常优秀的特性,其安全性、可靠性都远胜于我们常用的FAT文件系统,但是微软公司出于商业目的没有公布它的规范,使得这种优秀的文件系统只能在Windows NT架构的操作系统中使用。

  不过先辈们唱得好:“没有枪没有炮,敌人给我们造!”。不管微软再怎么保密,它自己总要使用NTFS文件系统。那我们就通过分析它的代码来研究NTFS文件系统的规范呐。下面就列出小弟在仔细分析之后制做的Windows 2000 build 2195版格式化的NTFS分区的引导记录的源代码,以此与各位同好共勉。

  本代码在MASM 6.11下编译通过。其中与分区结构相关的数据仅适用于在下自己分的分区,各位引用时请自行代入正确的值。

 

  本代码仅供参考,请使用者确定使用范围,如有引起任何问题,本人根不负责。

.486
	Title	NTFS $Boot of Windows 2000 build 2195

Code		SEGMENT	BYTE PUBLIC USE16	'CODE'
		ASSUME	CS:Code,DS:Code
NTFS		PROC	FAR
START:		JMP	SHORT Loader
		DB	90H

PartitionID		DB	'NTFS    '
BytePerSector		DW	512
SectorPerCluster		DB	1
SectorNumWanted		DW	0
SectorWanted		DD	0
SupportExtendInt13Flag	DB	0
StorageMedia		DB	0F8H
			DB	0,0
SectorPerTrack		DW	3FH
Heads			DW	0FFH
HiddenSector		DD	3FH
CHSMaxSectorNum		DD	0
CurrentDisk		DB	81H
			DB	0,8,0
SectorsInPartition		DD	3E81FFH
			DD	0
MFTPosition		DD	0C5A70H
			DD	0
MFTMirrPosition		DD	1FCD0AH
			DD	0
ClusterPerFRS		DD	2
			DB	08H,0,0,0,0F6H,79H
			DB	58H,5CH,0BBH,58H,5CH,0F4H
			DB	0,0,0,0

Loader:		CLI				; Disable interrupts
		XOR	AX,AX
		MOV	SS,AX
		MOV	SP,7C00H		; Initalize stack
		STI				; Enable interrupts
		MOV	AX,7C0H
		MOV	DS,AX
		CALL	GetCHSMaxSectorNum
		MOV	AX,0D00H
		MOV	ES,AX
		XOR	BX,BX
		MOV	BYTE PTR DS:[SectorNumWanted],10H
		CALL	ReadSector
		PUSH	0D00H
		PUSH	26AH
		RETF
NTFS		ENDP
;-----------------------------------------------------------------------------
GetCHSMaxSectorNum	PROC	NEAR
		MOV	DL,DS:[CurrentDisk]
		MOV	AH,8
		INT	13H
		JNC	Lost
		MOV	CX,0FFFFH
		MOV	DH,CL

Lost:		MOVZX	EAX,DH
		INC	AX
		MOVZX	EDX,CL
		AND	DL,3FH
		MUL	DX
		XCHG	CL,CH
		SHR	CH,6
		INC	CX
		MOVZX	ECX,CX
		MUL	ECX
		MOV	DS:CHSMaxSectorNum,EAX
		RET
GetCHSMaxSectorNum	ENDP
;-----------------------------------------------------------------------------
IsSupportExtendInt13	PROC	NEAR
		MOV	AH,41H
		MOV	BX,55AAH
		MOV	DL,DS:CurrentDisk
		INT	13H				; Is support extend int 13h
		JC	SHORT NotSupport		; Jump if carry Set
		CMP	BX,0AA55H
		JNE	SHORT NotSupport		; Jump if not equal
		TEST	CL,1
		JZ	SHORT NotSupport		; Jump if zero
		INC	BYTE PTR DS:SupportExtendInt13Flag

NotSupport:	RET
IsSupportExtendInt13	ENDP
;-----------------------------------------------------------------------------
;Function : read number indicated by [WantedSecotrNum] sectors at [WantedSector] to ES:BX
ReadSector	PROC	NEAR
		PUSHAD					; Save all regs
		PUSH	DS
		PUSH	ES

GetReadParam:	MOV	EAX,DS:[SectorWanted]
		ADD	EAX,DS:[HiddenSector]
		CMP	EAX,DS:[CHSMaxSectorNum]
		JB	NEAR PTR ReadByOldInt13		
		; Sector number is less than CHSMaxSectorNum , use origin int 13h
		PUSH	DS
;		PUSH	DWORD PTR 0
		DB	66H,6AH,0
		PUSH	EAX
		PUSH	ES
		PUSH	BX
		PUSH	DWORD PTR 10010H
		CMP	BYTE PTR DS:SupportExtendInt13Flag,0
		JNE	NEAR PTR Supported
		CALL	IsSupportExtendInt13
		CMP	BYTE PTR DS:SupportExtendInt13Flag,0
		JE	NEAR PTR FatalFault

Supported:	MOV	AH,42H
		MOV	DL,DS:[CurrentDisk]
		PUSH	SS
		POP	DS
		MOV	SI,SP
		INT	13H				; read sector
		POP	EAX
		POP	BX
		POP	ES
		POP	EAX
		POP	EAX
		POP	DS
		JMP	SHORT OneSectorRead

ReadByOldInt13:	XOR	EDX,EDX
		MOVZX	ECX,WORD PTR DS:[SectorPerTrack]
		DIV	ECX
		INC	DL
		MOV	CL,DL
		MOV	EDX,EAX
		SHR	EDX,10H
		DIV	WORD PTR DS:[Heads]
		XCHG	DL,DH
		MOV	DL,DS:[CurrentDisk]
		MOV	CH,AL
		SHL	AH,6
		OR	CL,AH				; Build read sector parameters
		MOV	AX,201H
		INT	13H				; Read sector
		
OneSectorRead:	JC	NEAR PTR FatalFault		; Read error,shut down
		MOV	AX,ES
		ADD	AX,20H
		MOV	ES,AX
		INC	DWORD PTR DS:[SectorWanted]
		DEC	WORD PTR DS:[SectorNumWanted]
		JNZ	GetReadParam			; Fixup parameters
		POP	ES
		POP	DS
		POPAD					; Restore all regs
		RET
		
FatalFault::	MOV	AL,ReadDiskErrorOffset
ReadSector	ENDP
;-----------------------------------------------------------------------------
DispFatalMsg::	CALL	PrintString
		MOV	AL,ShutDownMsgOffset
		CALL	PrintString			; Display shutdown message
		STI					; Enable interrupts

ShutDown:	JMP	SHORT ShutDown			; Crash
;-----------------------------------------------------------------------------
PrintString	PROC	NEAR
		MOV	AH,1
		MOV	SI,AX

LoadChar:	LODSB
		CMP	AL,0
		JZ	SHORT PrintStringEnd
		MOV	AH,0EH
		MOV	BX,7
		INT	10H
		JMP	SHORT LoadChar

PrintStringEnd:	RET
PrintString	ENDP
;-----------------------------------------------------------------------------
ReadDiskError	DB	0DH, 0AH, 'A disk read error occurred', 0
MissNTLDRError	DB	0DH, 0AH, 'NTLDR is missing', 0
NTLDRCompressed	DB	0DH, 0AH, 'NTLDR is compressed', 0
ShutDownMsg	DB	0DH, 0AH, 'Press Ctrl+Alt+Del to restart',0DH,0AH,0
		DB	13 DUP (0)
ReadDiskErrorOffset	DB	83H	;OFFSET ReadDiskError
MissNTLDRErrorMsg	DB	0A0H	;OFFSET MissNTLDRError
NTLDRComperssedOffset	DB	0B3H	;OFFSET NTLDRCompressed
ShutDownMsgOffset	DB	0C9H	;OFFSET ShutDownMsg
		DB	0, 0
BootValidFlag	DW	0AA55H

UnicodeNTLDR	DW	5
		DB	"N",0,"T",0,"L",0,"D",0,"R",0

UnicodeDirectory:
		DW	4
		DB	"S",0,"I",0,"3",0,"0",0
AttributePoint	DD	0E000H
MFTPoint	DD	3000H
MFTNumber	DD	0
TempRootBuffer	DD	0
TempDirBuffer	DD	0
TempBitmapBuf	DD	0
RootAttribute	DD	0
DirEntryList	DD	0
BitmapAttribute	DD	0
TempMFT		DD	0
		DD	0
TempDataBuf	DD	0
BitampPoint	DD	0
ParamTailPoint	DD	0
BytePerCluster	DD	0
MFTSize		DD	0
MFTSizeBySector	DD	909012EBH
MFTTail		DD	0
BytePerRecord	DD	0
DATA_46		DD	0
SectorPerRecord	DD	0

Booting:	MOV	AX,CS
		MOV	DS,AX
		SHL	AX,4
		CLI
		MOV	SP,AX				; Initalize stack
		STI					; Enable interrupts
		CALL	GetCHSMaxSectorNum
		MOVZX	EAX,WORD PTR [BytePerSector]
		MOVZX	EBX,BYTE PTR [SectorPerCluster]
		MUL	EBX
		MOV	[BytePerCluster],EAX
		MOV	ECX,[ClusterPerFRS]
		CMP	CL,0
		JG	NEAR PTR IsMFTSize

			NEG	CL
			MOV	EAX,1
			SHL	EAX,CL
			JMP	SHORT LOC_14
			DB	90H

	IsMFTSize:	MOV	EAX,BytePerCluster
			MUL	ECX

LOC_14:		MOV	[MFTSize],EAX
		MOVZX	EBX,WORD PTR [BytePerSector]
		XOR	EDX,EDX
		DIV	EBX
		MOV	[MFTSizeBySector],EAX		; Count sector number occurpied by MFT
		CALL	FindLastMFT
		MOV	ECX,[ParamTailPoint]
		MOV	[TempRootBuffer],ECX
		ADD	ECX,[MFTSize]
		MOV	[TempDirBuffer],ECX
		ADD	ECX,[MFTSize]
		MOV	[TempBitmapBuf],ECX
		ADD	ECX,[MFTSize]
		MOV	[TempMFT],ECX
		ADD	ECX,[MFTSize]
		MOV	[TempDataBuf],ECX
		MOV	EAX,90H
		MOV	ECX,[TempRootBuffer]
		CALL	GetAttributePos
		OR	EAX,EAX
		JZ	FatalFault
		MOV	[RootAttribute],EAX
		MOV	EAX,0A0H
		MOV	ECX,[TempDirBuffer]
		CALL	GetAttributePos
		MOV	[DirEntryList],EAX
		MOV	EAX,0B0H
		MOV	ECX,[TempBitmapBuf]
		CALL	GetAttributePos
		MOV	[BitmapAttribute],EAX
		MOV	EAX,[RootAttribute]
		OR	EAX,EAX
		JZ	FatalFault			; Check if root is exist
		CMP	BYTE PTR [EAX+8],0		; Nonresident, error record!
		JNE	FatalFault
		LEA	EDX,DWORD PTR [EAX+10H]
		ADD	AX,WORD PTR [EDX+4]
		MOVZX	ECX,BYTE PTR [EAX+0CH]
		MOV	[DATA_46],ECX
		MOV	ECX,DWORD PTR [EAX+8]
		MOV	[BytePerRecord],ECX
		MOV	EAX,[BytePerRecord]
		MOVZX	ECX,WORD PTR [BytePerSector]
		XOR	EDX,EDX
		DIV	ECX
		MOV	[SectorPerRecord],EAX
		MOV	EAX,[TempDataBuf]
		ADD	EAX,[BytePerRecord]
		MOV	[BitampPoint],EAX
		CMP	[DirEntryList],0
		JE	NEAR PTR LookForNTLDR
			CMP	[BitmapAttribute],0
			JE	FatalFault
			MOV	EBX,[BitmapAttribute]
			PUSH	DS
			POP	ES
			MOV	EDI,[BitampPoint]
			CALL	GetAttributeData

LookForNTLDR:	MOVZX	ECX,WORD PTR [UnicodeNTLDR]
		MOV	EAX,OFFSET [UnicodeNTLDR+2]
		CALL	SearchFileInRoot		; Look for NTLDR in root
		OR	EAX,EAX
		JZ	MissNTLDR			; Can't find NTLDR
		MOV	EAX,[EAX]
		PUSH	DS
		POP	ES
		MOV	EDI,[TempMFT]
		CALL	LoadMFTNode
		MOV	EAX,[TempMFT]
		MOV	EBX,80H
		MOV	ECX,0
		MOV	EDX,0
		CALL	SearchAttribute
		OR	EAX,EAX
		JNZ	NEAR PTR LoadNTLDR
		MOV	ECX,80H
		MOV	EAX,[TempMFT]
		CALL	SearchAttributeEx
		OR	EAX,EAX
		JZ	MissNTLDR			; Can't find NTLDR
		PUSH	DS
		POP	ES
		MOV	EDI,[TempMFT]
		CALL	LoadMFTNode
		MOV	EAX,[TempMFT]
		MOV	EBX,80H
		MOV	ECX,0
		MOV	EDX,0
		CALL	SearchAttribute
		OR	EAX,EAX
		JZ	MissNTLDR			; Can't Find NTLDR

LoadNTLDR:	MOVZX	EBX,WORD PTR [EAX+0CH]
		AND	EBX,0FFH
		JNZ	CompressedNTLDR
		MOV	EBX,EAX
		PUSH	2000H
		POP	ES
		SUB	EDI,EDI
		CALL	GetAttributeData		; Load NTLDR
		MOV	DL,CurrentDisk
		MOV	AX,3E8H
		MOV	ES,AX
		LEA	SI,CS:[0BH]
		SUB	AX,AX
		PUSH	2000H
		PUSH	AX
		RETF					; Jump to NTLDR to run
;-----------------------------------------------------------------------------
; Function : read some clusters indicated by EDX at the cluster indicated by EAX to buffer indicated by ES:EDI
; ArgIn : EAX cluster offset, EDX cluster number,ES:EDI point to buffer to store data
ReadCluster	PROC	NEAR
		PUSH	ES
		PUSH	DS
		PUSHAD
		MOV	EBX,EDX
		MOVZX	ECX,BYTE PTR [SectorPerCluster]
		MUL	ECX
		MOV	[SectorWanted],EAX
		MOV	EAX,EBX
		MUL	ECX
		MOV	WORD PTR DS:[SectorNumWanted],AX
		MOV	BX,DI
		AND	BX,0FH
		MOV	AX,ES
		SHR	EDI,4
		ADD	AX,DI
		PUSH	AX
		POP	ES				; Calculate buffer address
		CALL	ReadSector
		POPAD
		NOP
		POP	DS
		POP	ES
		RET
ReadCluster	ENDP
;-----------------------------------------------------------------------------
; Look for a attribute item at buffer indicated by DS:EAX
; Name of attribute indicated by ES:EDI size is indicated by ECX
SearchAttribute	PROC	NEAR
		ADD	AX,WORD PTR [EAX+14H]

	Searching:	CMP	DWORD PTR [EAX],0FFFFFFFFH	; Is chain tail?
			JE	NEAR PTR RecordIsNotExist	; Yes return
			CMP	[EAX],EBX
			JNE	NEAR PTR ToNextAttribute
			OR	ECX,ECX
			JNZ	NEAR PTR HaveName
			CMP	BYTE PTR [EAX+9],0		; Have name?
			JNE	NEAR PTR ToNextAttribute
			RET

		HaveName:	CMP	CL,BYTE PTR [EAX+9]
				JNE	NEAR PTR ToNextAttribute		; Jump if not equal
				MOV	ESI,EAX
				ADD	SI,WORD PTR [EAX+0AH]
				CALL	LowerCase2UpperCase
				PUSH	ECX
				PUSH	DS
				POP	ES
				MOV	EDI,EDX
				REPZ	CMPSW		; names of them is equal ?
				POP	ECX
				JNZ	NEAR PTR ToNextAttribute
				RET

	ToNextAttribute:
			CMP	DWORD PTR [EAX+4],0
			JE	NEAR PTR RecordIsNotExist
			ADD	EAX,DWORD PTR [EAX+4]
			JMP	SHORT Searching

RecordIsNotExist:
		SUB	EAX,EAX
		RET
SearchAttribute	ENDP
;-----------------------------------------------------------------------------
; Function : Look for a file in directory named as buffer indicated by EBX
; ArgOut : EAX The file record
SearchFile	PROC	NEAR
		MOV	ESI,EBX
		CALL	LowerCase2UpperCase
		ADD	EAX,[EAX]

	SearchingFile:	TEST	WORD PTR [EAX+0CH],2
			JNZ	NEAR PTR FileNotFound
			LEA	EDX,DWORD PTR [EAX+10H]
			CMP	CL,BYTE PTR [EDX+40H]
			JNE	NEAR PTR SearchNextFile
			LEA	ESI,DWORD PTR [EDX+42H]
			CALL	LowerCase2UpperCase
			PUSH	ECX
			PUSH	DS
			POP	ES
			MOV	EDI,EBX
			REPZ	CMPSW
			POP	ECX
			JNZ	NEAR PTR SearchNextFile
		RET

	SearchNextFile:	CMP	WORD PTR [EAX+8],0
			JE	NEAR PTR FileNotFound
			ADD	AX,WORD PTR [EAX+8]
			JMP	SHORT SearchingFile

FileNotFound:	XOR	EAX,EAX
		RET
SearchFile	ENDP
;-----------------------------------------------------------------------------
; Function : Copy attribute data to buffer indicated by ES:EDI
; ArgIn : EBX point to attribute item, ES:EDI buffer to store attribute data
; ArgOut :
GetAttributeData	PROC	NEAR
		CMP	BYTE PTR [EBX+8],0
		JNE	NEAR PTR DataForRun

		PUSH	ES
		PUSH	DS
		PUSHAD					; Save all regs
		LEA	EDX,DWORD PTR [EBX+10H]
		MOV	ECX,[EDX]			; Get resident data length
		MOV	ESI,EBX
		ADD	SI,WORD PTR [EDX+4]		; Get resident data offset
		REP	MOVSB				; Copying
		POPAD					; Restore all regs
		NOP
		POP	DS
		POP	ES
		RET

DataForRun:	LEA	EDX,DWORD PTR [EBX+10H]
		MOV	ECX,DWORD PTR [EDX+8]		; Get the last VCN Segment
		INC	ECX
		SUB	EAX,EAX
		CALL	ReadRunDataByClusterOffset	; Read data in runs
		RET
GetAttributeData	ENDP
;-----------------------------------------------------------------------------
; Function : Read noresident data in attribute item
; ArgIn : EAX cluster offset in file
; ArgIn : EBX point to noresident attribute item,ES:EDI buffer to store noresident data
; ArgOut : None
ReadRunDataByClusterOffset	PROC	NEAR
		PUSH	ES
		PUSH	DS
		PUSHAD					; Save all regs
		CMP	BYTE PTR [EBX+8],1
		JE	NEAR PTR IsDataForRun
		JMP	FatalFault			; Invalid description

	IsDataForRun:	CMP	ECX,0
			JNE	NEAR PTR ReadingRunningData
		POPAD					; Read complete
		NOP
		POP	DS
		POP	ES
		RET

	ReadingRunningData:
			PUSH	EBX
			PUSH	EAX
			PUSH	ECX
			PUSH	EDI
			PUSH	ES
			CALL	GetStreamPos
			MOV	EDX,ECX
			POP	ES
			POP	EDI
			POP	ECX
			CMP	ECX,EDX
			JGE	NEAR PTR ReadRunClusters
			MOV	EDX,ECX

	ReadRunClusters:
			CALL	ReadCluster
			SUB	ECX,EDX
			MOV	EBX,EDX
			MOV	EAX,EDX
			MOVZX	EDX,BYTE PTR [SectorPerCluster]
			MUL	EDX
			MOVZX	EDX,WORD PTR [BytePerSector]
			MUL	EDX
			ADD	EDI,EAX			; Fixup Buffer point
			POP	EAX
			ADD	EAX,EBX			; Fixup cluster
			POP	EBX
			JMP	SHORT IsDataForRun
ReadRunDataByClusterOffset	ENDP
;-----------------------------------------------------------------------------
; Function : Read some data to ES:EDI
; ArgIn : EBX point to a run data, ES:EDI point to the buffer, EAX file offset sector index
; AgrIn : ECX sector count
ReadRunDataBySectorOffset	PROC	NEAR
		PUSH	ES
		PUSH	DS
		PUSHAD					; Save all regs
		CMP	BYTE PTR [EBX+8],1
		JE	NEAR PTR PrepairReadData
		JMP	FatalFault

	PrepairReadData:
			CMP	ECX,0
			JNE	NEAR PTR ReadingRunningData
		POPAD					; Restore all regs
		NOP
		POP	DS
		POP	ES
		RET

	ReadingRunningData:
			PUSH	EBX
			PUSH	EAX
			PUSH	ECX
			PUSH	EDI
			PUSH	ES
			PUSH	ECX
			XOR	EDX,EDX
			MOVZX	ECX,BYTE PTR [SectorPerCluster]
			DIV	ECX			; Calculate cluster number
			PUSH	EDX
			CALL	GetStreamPos
			MOVZX	EBX,BYTE PTR [SectorPerCluster]
			MUL	EBX
			POP	EDX
			ADD	EAX,EDX
			PUSH	EAX
			MOVZX	EAX,BYTE PTR [SectorPerCluster]
			MUL	ECX			
			; Calculate the sector offset and sector number of the data wanted read
			MOV	EDX,EAX
			POP	EAX
			POP	ECX
			POP	ES
			POP	EDI
			POP	ECX
			CMP	ECX,EDX
			JGE	NEAR PTR ReadRunningClusters
				MOV	EDX,ECX		; Fixup the sector number will be read

	ReadRunningClusters:
			MOV	[SectorWanted],EAX
			MOV	WORD PTR DS:[SectorNumWanted],DX
			PUSH	ES
			PUSH	DS
			PUSHAD
			MOV	BX,DI
			AND	BX,0FH
			MOV	AX,ES
			SHR	EDI,4
			ADD	AX,DI
			PUSH	AX
			POP	ES
			CALL	ReadSector
			POPAD
			NOP
			POP	DS
			POP	ES
			SUB	ECX,EDX
			MOV	EBX,EDX
			MOV	EAX,EDX
			MOVZX	EDX,WORD PTR [BytePerSector]
			MUL	EDX
			ADD	EDI,EAX			; Fixup buffer point
			POP	EAX
			ADD	EAX,EBX
			POP	EBX
			JMP	PrepairReadData
ReadRunDataBySectorOffset	ENDP
;-----------------------------------------------------------------------------
; Function : Fixup record
; ArgIn : ES:EDI point to the record 
; ArgOut : None
FixupRecord	PROC	NEAR
		PUSH	ES
		PUSH	DS
		PUSHAD					; Save all regs

		MOVZX	EBX,WORD PTR ES:[EDI+4]
		MOVZX	ECX,WORD PTR ES:[EDI+6]
		OR	ECX,ECX
		JZ	FatalFault
		ADD	EBX,EDI
		ADD	EBX,2
		ADD	EDI,1FEH
		DEC	ECX

	FixupingRecord:	OR	ECX,ECX
			JZ	NEAR PTR FixupRecordComplete
			MOV	AX,ES:[EBX]
			MOV	ES:[EDI],AX
			ADD	EBX,2
			ADD	EDI,200H
			DEC	ECX
			JMP	SHORT FixupingRecord

FixupRecordComplete:
		POPAD					; Restore all regs
		NOP
		POP	DS
		POP	ES
		RET
FixupRecord	ENDP
;-----------------------------------------------------------------------------
; Function : Get MFT record number occupide by MFT description
; ArgIn : None
; ArgOut : None
FindLastMFT	PROC	NEAR
		PUSH	ES
		PUSH	DS
		PUSHAD					; Save all regs
		MOV	EAX,1
		MOV	[MFTNumber],EAX
		MOV	EAX,[MFTPoint]
		ADD	EAX,[MFTSize]
		MOV	[MFTTail],EAX
		ADD	EAX,[MFTSize]
		MOV	[ParamTailPoint],EAX
		MOV	EAX,[MFTPosition]
		MOVZX	EBX,BYTE PTR [SectorPerCluster]
		MUL	EBX			
		MOV	EBX,[ParamTailPoint]
		MOV	[BX],EAX
		MOV	[SectorWanted],EAX
;-------------------------------------------------
		ADD	BX,4
		MOV	EAX,[MFTSizeBySector]
		MOV	[BX],EAX
		MOV	WORD PTR DS:[SectorNumWanted],AX
		ADD	BX,4
		MOV	[ParamTailPoint],EBX
		MOV	EBX,[MFTPoint]
		PUSH	DS
		POP	ES
		CALL	ReadSector			; Read MFT
		MOV	EDI,EBX
		CALL	FixupRecord			; Fixup
		MOV	EAX,[MFTPoint]
		MOV	EBX,20H
		MOV	ECX,0
		MOV	EDX,0
		CALL	SearchAttribute			; Look for attribute list
		OR	EAX,EAX				; Find ?
		JZ	NoAttributeList			; Can't find attribute list
		MOV	EBX,EAX
		PUSH	DS
		POP	ES
		MOV	EDI,[AttributePoint]
		CALL	GetAttributeData		; Read attribute list
		MOV	EBX,[AttributePoint]

	SearchingAttribute:
			CMP	DWORD PTR [BX],80H
			JZ	FoundData		; Look for a data record in attribute list
			ADD	BX,[BX+4]
			JMP	SHORT SearchingAttribute

GetExtMFTPos:	PUSH	EBX
		MOV	EAX,[BX+10H]
		MUL	[MFTSizeBySector]
		PUSH	EAX
		XOR	EDX,EDX
		MOVZX	EBX,BYTE PTR [SectorPerCluster]
		DIV	EBX				; Get cluster number of record
		PUSH	EDX
		CALL	GetMFTDataPos
		OR	EAX,EAX
		JZ	FatalFault
		MOV	ECX,[MFTSizeBySector]
		MOVZX	EBX,BYTE PTR [SectorPerCluster]
		MUL	EBX
		POP	EDX
		ADD	EAX,EDX
;-------------------------------------------------
		MOV	EBX,[ParamTailPoint]
		MOV	[BX],EAX
		ADD	BX,4
		MOVZX	EAX,BYTE PTR [SectorPerCluster]
		SUB	EAX,EDX
		CMP	EAX,ECX
		JBE	NEAR PTR SaveMFTUnitSize
			MOV	EAX,ECX

SaveMFTUnitSize:
		MOV	[BX],EAX

	FixupMFTParam:	SUB	ECX,EAX
			POP	EDX
			JZ	NEAR PTR NextUnit
			ADD	EAX,EDX
			PUSH	EAX
			XOR	EDX,EDX
			MOVZX	EBX,BYTE PTR [SectorPerCluster]
			DIV	EBX
			PUSH	ECX
			CALL	GetMFTDataPos
			POP	ECX
			OR	EAX,EAX
			JZ	FatalFault
			MOVZX	EBX,BYTE PTR [SectorPerCluster]
			MUL	EBX
			MOV	EBX,[ParamTailPoint]
			MOV	EDX,[BX]
			ADD	BX,4
			ADD	EDX,[BX]
			CMP	EDX,EAX
			JNE	NEAR PTR GetReadParam8
			MOVZX	EAX,BYTE PTR [SectorPerCluster]
			CMP	EAX,ECX
			JBE	NEAR PTR SaveFixupSize
				MOV	EAX,ECX

	SaveFixupSize:	ADD	[BX],EAX
			JMP	SHORT FixupMFTParam

;-------------------------------------------------
GetReadParam8:	ADD	BX,4
		MOV	[ParamTailPoint],EBX
		MOV	[BX],EAX
		ADD	BX,4
		MOVZX	EAX,BYTE PTR [SectorPerCluster]
		CMP	EAX,ECX
		JBE	NEAR PTR GetReadParam9
			MOV	EAX,ECX

GetReadParam9:	MOV	[BX],EAX
		JMP	SHORT FixupMFTParam

NextUnit:	ADD	BX,4
		INC	[MFTNumber]
		MOV	[ParamTailPoint],EBX
		POP	EBX

FoundData:	ADD	BX,[BX+4]
		CMP	DWORD PTR [BX],80H
		JZ	GetExtMFTPos

NoAttributeList:
		POPAD					; Restore all regs
		NOP
		POP	DS
		POP	ES
		RET
FindLastMFT	ENDP
;-----------------------------------------------------------------------------
; Function : Calculate next cluster offset in MFT and cluster number in the stream
; ArgIn : EAX cluster index
; ArgOut : EAX cluster offset, ECX cluster number in the stream
GetMFTDataPos	PROC	NEAR
		MOV	EDX,EAX
		MOV	ECX,[MFTNumber]
		MOV	ESI,DWORD PTR [MFTTail]
		ADD	ESI,[MFTSize]

	GetMFTData:	PUSH	EDX
			PUSH	ECX
			PUSH	EDX
			MOV	EBX,DWORD PTR [MFTTail]
			MOV	EDI,[MFTSizeBySector]

		LoadingData:	MOV	EAX,[SI]
				MOV	[SectorWanted],EAX
				ADD	SI,4
				MOV	EAX,[SI]
				MOV	WORD PTR DS:[SectorNumWanted],AX
				ADD	SI,4
				PUSH	DS
				POP	ES
				CALL	ReadSector	; Read a cluster of MFT
				SUB	EDI,EAX
				JZ	NEAR PTR ReadComplete

				MUL	WORD PTR [BytePerSector]
				ADD	BX,AX		; Fixup parameter
				JMP	SHORT LoadingData

	ReadComplete:	MOV	EDI,DWORD PTR [MFTTail]
			PUSH	DS
			POP	ES
			CALL	FixupRecord
			MOV	EAX,DWORD PTR [MFTTail]
			MOV	EBX,80H
			MOV	ECX,0
			MOV	EDX,ECX
			CALL	SearchAttribute		; Look for a data attribute
			OR	EAX,EAX
			JZ	FatalFault
			MOV	EBX,EAX
			POP	EAX
			PUSH	ESI
			CALL	GetStreamPos
			POP	ESI
			OR	EAX,EAX
			JZ	NEAR PTR NoStreamData

		POP	EBX
		POP	EBX
		RET

	NoStreamData:	POP	ECX
			POP	EDX
			LOOP	GetMFTData

		XOR	EAX,EAX
		RET
GetMFTDataPos	ENDP
;-----------------------------------------------------------------------------
; Function : Read  some records of MFT
; ArgIn : EAX sector offset, ECX = count,ES:EDI
ReadMFTNode	PROC	NEAR
		PUSH	ES
		PUSH	DS
		PUSHAD					; Save all regs

	PrepairReadParam:
			PUSH	EAX
			PUSH	ECX
			XOR	EDX,EDX
			MOVZX	EBX,BYTE PTR [SectorPerCluster]
			DIV	EBX
			PUSH	EDX
			PUSH	EDI
			CALL	GetMFTDataPos		; Calculate next MFT cluster parameter
			POP	EDI
			OR	EAX,EAX
			JZ	FatalFault
			MOVZX	EBX,BYTE PTR [SectorPerCluster]
			MUL	EBX
			POP	EDX
			ADD	EAX,EDX
			MOV	[SectorWanted],EAX
			POP	ECX
			MOVZX	EBX,BYTE PTR [SectorPerCluster]
			CMP	ECX,EBX
			JLE	NEAR PTR ReachToLastCluster

				MOV	WORD PTR DS:[SectorNumWanted],BX
				SUB	ECX,EBX
				POP	EAX
				ADD	EAX,EBX
				PUSH	EAX
				PUSH	ECX
				JMP	SHORT CalculateBuffer
				DB	90H

		ReachToLastCluster:
				POP	EAX
				ADD	EAX,ECX
				PUSH	EAX
				MOV	WORD PTR DS:[SectorNumWanted],CX
				MOV	ECX,0
				PUSH	ECX

	CalculateBuffer:
			PUSH	ES
			PUSH	EDI
			MOV	BX,DI
			AND	BX,0FH
			MOV	AX,ES
			SHR	EDI,4
			ADD	AX,DI
			PUSH	AX
			POP	ES
			CALL	ReadSector
			POP	EDI
			POP	ES
			ADD	EDI,[BytePerCluster]	; Fixup buffer address
			POP	ECX
			POP	EAX
			CMP	ECX,0
			JG	PrepairReadParam	; Reading...

		POPAD					; Restore all regs
		NOP
		POP	DS
		POP	ES
		RET
ReadMFTNode	ENDP
;-----------------------------------------------------------------------------
; Function : Load some units of MFT and fixup
; ArgIn : EAX MFT record number, ES:EDI buffer to store data
LoadMFTNode	PROC	NEAR
		PUSH	ES
		PUSH	DS
		PUSHAD					; Save all regs
		MUL	[MFTSizeBySector]
		MOV	ECX,[MFTSizeBySector]
		CALL	ReadMFTNode
		CALL	FixupRecord
		POPAD					; Restore all regs
		NOP
		POP	DS
		POP	ES
		RET
LoadMFTNode	ENDP
;-----------------------------------------------------------------------------
; Function : Read Extend directory entrys list
; ArgIn : EAX record index
ReadExtDirNode	PROC	NEAR
		PUSH	ES
		PUSH	DS
		PUSHAD
		MUL	[SectorPerRecord]
		MOV	EBX,[DirEntryList]		; Resident data point (?)
		MOV	ECX,[SectorPerRecord]
		PUSH	DS
		POP	ES
		MOV	EDI,[TempDataBuf]
		CALL	ReadRunDataBySectorOffset
		CALL	FixupRecord
		POPAD					; Restore all regs
		NOP
		POP	DS
		POP	ES
		RET
ReadExtDirNode	ENDP
;-----------------------------------------------------------------------------
; Function : Check if a bit in directory bitamp is used
; ArgIn : EAX the index in bitmap
FindUsedUnit	PROC	NEAR
		PUSH	EAX
		PUSH	EBX
		PUSH	ECX
		MOV	EBX,[BitampPoint]
		MOV	ECX,EAX
		SHR	EAX,3
		AND	ECX,7
		ADD	EBX,EAX
		MOV	EAX,1
		SHL	EAX,CL			; Search in a bit data
		TEST	AL,[EBX]
		JZ	NEAR PTR FreedomUnit
			CLC
			JMP	SHORT UsedUnit
			DB	90H

	FreedomUnit:	STC

UsedUnit:	POP	ECX
		POP	EBX
		POP	EAX
		RET
FindUsedUnit	ENDP
;-----------------------------------------------------------------------------
; Function : return offset and size of a stream data in running data
; ArgIn : EBX point to the running data,EAX the offset of unit in file
; ArgOut : EAX the cluster offset of the wanted unit
; ArgOut : ECX the last unit number from the offset
GetStreamPos	PROC	NEAR
		CMP	BYTE PTR [EBX+8],1
		JE	NEAR PTR IsRunningData
		SUB	EAX,EAX
		RET

IsRunningData:	LEA	ESI,DWORD PTR [EBX+10H]
		MOV	EDX,DWORD PTR [ESI+8]
		CMP	EAX,EDX
		JA	NEAR PTR OutOfVCNSegment
		MOV	EDX,[ESI]
		CMP	EAX,EDX
		JAE	NEAR PTR StartHandle

OutOfVCNSegment:					; Out of range of VCN
		SUB	EAX,EAX
		RET

StartHandle:	ADD	BX,WORD PTR [ESI+10H]		; EBX point to data offset
		SUB	ESI,ESI

	ReadStreamInChain:
			CMP	BYTE PTR [EBX],0
			JE	NEAR PTR ReachEndOfData
			CALL	GetStreamOffset
			ADD	ESI,ECX
			CALL	GetStreamSize
			ADD	ECX,EDX
			CMP	EAX,ECX
			JL	NEAR PTR StreamFound
			MOV	EDX,ECX
			PUSH	EAX
			MOVZX	ECX,BYTE PTR [EBX]
			MOV	EAX,ECX
			AND	EAX,0FH
			SHR	ECX,4
			ADD	EBX,ECX
			ADD	EBX,EAX
			INC	EBX			; Fixup index point
			POP	EAX
			JMP	SHORT ReadStreamInChain

StreamFound:	SUB	ECX,EAX
		SUB	EAX,EDX
		ADD	EAX,ESI
		RET

ReachEndOfData:	SUB	EAX,EAX
		RET
GetStreamPos	ENDP
;-----------------------------------------------------------------------------
; Function : Get noresident data record size
; ArgIn : EBX Point to a noresident record index
; ArgOut : ECX Current record size
GetStreamSize	PROC	NEAR
		SUB	ECX,ECX
		MOV	CL,[EBX]
		AND	CL,0FH
		CMP	ECX,0
		JNE	NEAR PTR NeedBind	; There is data
		SUB	ECX,ECX
		RET

NeedBind:	PUSH	EBX
		PUSH	EDX
		ADD	EBX,ECX
		MOVSX	EDX,BYTE PTR [EBX]	; Get data size
		DEC	ECX
		DEC	EBX

	CombineDataSize:
			CMP	ECX,0
			JE	NEAR PTR BindComplete
			SHL	EDX,8
			MOV	DL,[EBX]
			DEC	EBX
			DEC	ECX
			JMP	SHORT CombineDataSize

BindComplete:	MOV	ECX,EDX
		POP	EDX
		POP	EBX
		RET
GetStreamSize	ENDP
;-----------------------------------------------------------------------------
; Function : Get noresident data record offset
; ArgIn : EBX Point to a noresident record index
; ArgOut : ECX Current record offset
GetStreamOffset	PROC	NEAR
		PUSH	EBX
		PUSH	EDX
		SUB	EDX,EDX
		MOV	DL,[EBX]
		AND	EDX,0FH
		SUB	ECX,ECX
		MOV	CL,[EBX]
		SHR	CL,4
		CMP	ECX,0
		JNE	NEAR PTR OffsetValid
		SUB	ECX,ECX
		POP	EDX
		POP	EBX
		RET

OffsetValid:	ADD	EBX,EDX
		ADD	EBX,ECX				; EBX point the offset of record
		MOVSX	EDX,BYTE PTR [EBX]
		DEC	ECX
		DEC	EBX

	CombineDataOffset:
			CMP	ECX,0
			JE	NEAR PTR HandleComplete
			SHL	EDX,8
			MOV	DL,[EBX]
			DEC	EBX
			DEC	ECX
			JMP	SHORT CombineDataOffset

HandleComplete:	MOV	ECX,EDX
		POP	EDX
		POP	EBX
		RET
GetStreamOffset	ENDP
;-----------------------------------------------------------------------------
LowerCase2UpperCase	PROC	NEAR
		OR	ECX,ECX
		JNZ	NEAR PTR StringValid
		RET

StringValid:	PUSH	ECX
		PUSH	ESI

CheckChar:	CMP	WORD PTR [ESI],61H
		JL	NEAR PTR NextChar
		CMP	WORD PTR [ESI],7AH
		JG	NEAR PTR NextChar
		SUB	WORD PTR [ESI],20H

NextChar:	ADD	ESI,2
		LOOP	CheckChar

		POP	ESI
		POP	ECX
		RET
LowerCase2UpperCase	ENDP
;-----------------------------------------------------------------------------
; Function : Read root and look for a file in it
; ArgIn : EAX point to the file name, ECX file name size(Unicode)
; ArgOut : point to file record 
SearchFileInRoot	PROC	NEAR
		PUSH	EAX
		PUSH	ECX
		MOV	EDX,EAX
		MOV	EAX,[RootAttribute]
		LEA	EBX,DWORD PTR [EAX+10H]
		ADD	AX,WORD PTR [EBX+4]
		LEA	EAX,DWORD PTR [EAX+10H]
		MOV	EBX,EDX
		CALL	SearchFile
		OR	EAX,EAX
		JZ	NEAR PTR NeedSearch

		POP	ECX
		POP	ECX
		RET

NeedSearch:	MOV	EAX,[DirEntryList]
		OR	EAX,EAX
		JNZ	NEAR PTR OneSectorRead8

		POP	ECX
		POP	ECX
		XOR	EAX,EAX
		RET

OneSectorRead8:	MOV	EDX,[DirEntryList]
		LEA	EDX,DWORD PTR [EDX+10H]
		MOV	EAX,DWORD PTR [EDX+8]
		INC	EAX
		MOV	EBX,[BytePerCluster]
		MUL	EBX
		XOR	EDX,EDX
		DIV	[BytePerRecord]
		PUSH	EAX

		TestPreviousUnit:
				POP	EAX
				OR	EAX,EAX
				JZ	NEAR PTR UnitNotFound
				DEC	EAX
				PUSH	EAX
				CALL	FindUsedUnit
				JC	TestPreviousUnit

			CALL	ReadExtDirNode
			POP	EDX
			POP	ECX
			POP	EBX
			PUSH	EBX
			PUSH	ECX
			PUSH	EDX
			MOV	EAX,[TempDataBuf]
			LEA	EAX,DWORD PTR [EAX+18H]
			CALL	SearchFile
			OR	EAX,EAX
			JZ	TestPreviousUnit

		POP	ECX
		POP	ECX
		POP	ECX
		RET

UnitNotFound:	POP	ECX
		POP	ECX
		XOR	EAX,EAX
		RET
SearchFileInRoot	ENDP
;-----------------------------------------------------------------------------
; Function : 
; ArgIn : EBX attribute of "$I30" record, ECX
; ArgOut : 
GetAttributePos	PROC	NEAR
		PUSH	ECX
		PUSH	EAX
		MOV	EAX,5
		PUSH	DS
		POP	ES
		MOV	EDI,ECX
		CALL	LoadMFTNode			; Read the 5th MFT record
		MOV	EAX,ECX
		POP	EBX
		PUSH	EBX
		MOVZX	ECX,WORD PTR [UnicodeDirectory]
		MOV	EDX,OFFSET [UnicodeDirectory+2]
		CALL	SearchAttribute
		POP	EBX
		POP	ECX
		OR	EAX,EAX
		JNZ	NEAR PTR FindRecord
		MOV	EAX,ECX
		MOV	ECX,EBX
		PUSH	EAX
		PUSH	EBX
		CALL	SearchAttributeEx		; Check if the attribute item exist in attribute list
		POP	EBX
		POP	EDI
		OR	EAX,EAX
		JZ	NEAR PTR FindRecord
		PUSH	DS
		POP	ES
		CALL	LoadMFTNode
		MOV	EAX,EDI
		MOVZX	ECX,WORD PTR [UnicodeDirectory]
		MOV	EDX,OFFSET [UnicodeDirectory+2]
		CALL	SearchAttribute

FindRecord:	RET
GetAttributePos	ENDP
;-----------------------------------------------------------------------------
; Function : Look for attribute item in attribute list
; ArgIn : ECX the attribute of wanted item
; ArgOut : EAX point to the wanted attribute item
SearchAttributeEx	PROC	NEAR
		PUSH	ECX
		MOV	EBX,20H
		MOV	ECX,0
		MOV	EDX,0
		CALL	SearchAttribute
		OR	EAX,EAX
		JZ	NEAR PTR SearchFailure
		MOV	EBX,EAX
		PUSH	DS
		POP	ES
		MOV	EDI,[AttributePoint]
		CALL	GetAttributeData
		PUSH	DS
		POP	ES
		MOV	EBX,[AttributePoint]
		POP	ECX

	_Searching:	CMP	ES:[BX],ECX
			JE	NEAR PTR FoundTheRecord
			CMP	DWORD PTR ES:[BX],0FFFFFFFFH
			JE	NEAR PTR SearchComplete
			CMP	WORD PTR ES:[BX+4],0
			JE	NEAR PTR SearchComplete
			MOVZX	EAX,WORD PTR ES:[BX+4]
			ADD	BX,AX
			MOV	AX,BX
			AND	AX,8000H
			JZ	_Searching

				MOV	AX,ES
				ADD	AX,800H
				MOV	ES,AX
				AND	BX,7FFFH
				JMP	SHORT _Searching	; Fixup segment

FoundTheRecord:	MOV	EAX,ES:[BX+10H]
		RET

SearchFailure:	POP	ECX

SearchComplete:	XOR	EAX,EAX			; Zero register
		RET
SearchAttributeEx	ENDP
;-----------------------------------------------------------------------------
MissNTLDR:	MOV	AL,MissNTLDRErrorMsg
		JMP	DispFatalMsg

CompressedNTLDR:
		MOV	AL,NTLDRComperssedOffset
		JMP	DispFatalMsg
		DB	4908 DUP (0)
Code		ENDS
		END	START

 

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值