终于决心开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