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