MFT(主文件表(Master File Table))鎖定 MFT,即主文件表(Master File Table)的簡稱,它是NTFS文件系統(tǒng)的核心。MFT由一個個MFT項(也稱為文件記錄)組成,每個MFT項占用1024字節(jié)的空間。每個MFT項的前部幾十個字節(jié)有著固定的頭結(jié)構(gòu),用來描述本MFT項的相關(guān)信息。后面的字節(jié)存放著“屬性”。每個文件和目錄的信息都包含在MFT中,每個文件和目錄至少有一個MFT項。除了引導(dǎo)扇區(qū)外,訪問其他任何一個文件前都需要先訪問MFT,在MFT中找到該文件的MFT項,根據(jù)MFT項中記錄的信息找到文件內(nèi)容并對其進(jìn)行訪問。NTFS(New Technology File System),是一種新型文件系統(tǒng)。 軟件名稱:Master File Table 軟件平臺:Windows NT 英文縮寫:MFT 地位:NTFS文件系統(tǒng)的核心 MFT簡介 (1)NTFS是Windows NT引入的新型文件系統(tǒng),它具有許多新特性。NTFS中,卷中所有存放的數(shù)據(jù)均在一個叫$MFT的文件中,叫主文件表(Master File Table)。而$MFT則由文件記錄(File Record)數(shù)組構(gòu)成。File Record的大小一般是固定的,通常情況下均為1KB,這個概念相當(dāng)于Linux中的inode。File Record在$MFT文件中物理上是連續(xù)的,且從0開始編號。$MFT僅供File System本身組織、架構(gòu)文件系統(tǒng)使用,這在NTFS中稱為元數(shù)據(jù)(Metadata)。 在NTFS文件系統(tǒng)里面,磁盤上的所有東西都以文件的形式出現(xiàn)。即使是元數(shù)據(jù)也是以一組文件的形式存儲的。 主文件表( MFT )是這個卷上每一個文件的索引。 MFT 為每一個文件保存著一組稱為“屬性”的記錄,每個屬性存儲了不同類型的信息。為主文件表(MFT)保留適當(dāng)?shù)目臻g。MFT在NTFS卷中扮演著重要的角色,對其性能的影響很大,系統(tǒng)空間分配、讀寫磁盤時會頻繁地訪問MFT,因此 MFT對NTFS的卷的性能有著至關(guān)重要的影響。NTFS文件系統(tǒng)的開發(fā)者在MFT附近預(yù)留著一個特定區(qū)域,用來減少MFT中的碎片,缺省狀態(tài)下,這一區(qū)域占整個卷大小的12.5%,盡管這個區(qū)域能使得MFT中的碎片最少,但它并非總是合適的。 MFT操作說明 要對MFT的空間進(jìn)行管理,可以在HKEY_LOCAL_MACHINE \ SYSTEM \ CurrentControlSet \ Control \FileSystem中增加一個類型為REG_DWORD的NtfsMftZoneReservation,它的缺省值是1,其范圍是1-4(1表示 MFT占整個卷的12.5%,2表示25%,3表示37.5%,4表示50%)。 NTFS 中包含一個稱為主文件表 (MFT) 的文件。MFT 是一個映射磁盤中儲存的所有對象的索引文件。在 MFT 中,NTFS 磁盤上的每個文件(包括 MFT 自身)至少有一映射項。MFT 中的各項包含如下數(shù)據(jù): 大小、時間及時間戳、安全屬性和數(shù)據(jù)位置。 一但 MFT 產(chǎn)生碎片,磁盤碎片整理程序無法對其進(jìn)行碎片整理。但是,由于可以持續(xù)使用 MFT 來存取磁盤上所有的其它文件,因此它也會逐漸形成碎片,從而導(dǎo)致磁盤存取時間加長,降低磁盤性能。NTFS 通過保留 1/8 的磁盤空間留作 MFT 專用而將此影響降至最低。磁盤的此區(qū)域(稱為 MFT 區(qū)域)盡可能在 MFT 增加時保持其連續(xù)性。 ———————————————— 版權(quán)聲明:本文為CSDN博主「千么漾漾」的原創(chuàng)文章,遵循 CC 4.0 BY-SA 版權(quán)協(xié)議,轉(zhuǎn)載請附上原文出處鏈接及本聲明。 原文鏈接:https://blog.csdn.net/qq_41786318/article/details/79791263 NTFS文件系統(tǒng)-MFT的屬性頭2016-07-07 12:51:02 海天數(shù)據(jù)恢復(fù) 閱讀數(shù) 4461 版權(quán)聲明:本文為博主原創(chuàng)文章,遵循CC 4.0 BY-SA版權(quán)協(xié)議,轉(zhuǎn)載請附上原文出處鏈接和本聲明。 本文鏈接:https://blog.csdn.net/a307871404/article/details/51850356 前面說過MFT是有一個個屬性組成,那么每個屬性的具體結(jié)構(gòu)又是如何呢?MFT屬性的類型很多,但它們都有個共同的特點,那就是每個屬性都有屬性頭和屬性體。屬性頭又分為常駐屬性和非常駐屬性。常駐屬性和非常駐數(shù)據(jù)最大的區(qū)別是常駐屬性的只是在MFT內(nèi)部記錄,非常駐數(shù)據(jù)由于MFT記錄不下(一個MFT項只有1024)所以需要在其它數(shù)據(jù)區(qū)記錄。不管是常駐屬性還是非常駐屬性,它的屬性頭的前面16個字節(jié)是一樣的。 MFT屬性結(jié)構(gòu)圖 從上圖可以看出MFT頭很小,只有幾行代碼 ,剩下都是MFT的屬性。圖中10屬性和30屬性都是常駐屬性,而80屬性是非常駐屬性 ,因為80屬性是記錄文件內(nèi)容的屬性,一般不是幾個字節(jié)就能記錄的。下面我們來看下非常駐屬性的屬性頭具體結(jié)構(gòu)
非常駐屬性頭的數(shù)據(jù)結(jié)構(gòu)
非常駐屬性頭的最后3個參數(shù)都表示屬性內(nèi)容的大小, 這里可以寫成一樣大的。 NTFS文件系統(tǒng)MFT的屬性列表原文鏈接:http://blog.51cto.com/shujvhuifu/1801556 MFT是由一個個屬性體組成,每個屬性體都有一個對應(yīng)的屬性名。如0x10類型的屬性表示標(biāo)準(zhǔn)屬性,這個屬性記錄著文件的基本信息。 NTFS文件系統(tǒng)的MFT屬性列表
紅色標(biāo)記:表示非常重要必須要記住 綠色標(biāo)記:表示比較重要最好記住 沒標(biāo)記的了解下即可 轉(zhuǎn)載于:https://blog.51cto.com/shujvhuifu/1801556 NTFS文件系統(tǒng)數(shù)據(jù)恢復(fù)----解析MFT表2015-05-11 21:50:12 weinierbian 閱讀數(shù) 10406 分類專欄: 數(shù)據(jù)恢復(fù) http://blog.csdn.net/jha334201553/article/details/9089119 開始先說下DBR, DBR是繼MBR 之后最先訪問的地方,MBR利用int 13h 讀取MBR并將之加載到物理地址0x7c00的地方. 然后將段地址:代碼地址入棧后retf跳過去運行. MBR利用BIOS中斷int 13h讀取數(shù)據(jù)加載到內(nèi)存指定位置..傳統(tǒng)的int 13h調(diào)用最多只能識別1024個磁頭: 前面MBR講解MBR的時候,有結(jié)構(gòu)如下 /*+0x01*/ uchar StartHead; // 分區(qū)起始磁頭號 (1磁頭 = 63 扇區(qū),取值 0~255 之間) /*+0x02*/ uint16 StartSector:10; // 啟始柱面號 10位 (1柱面 = 255 磁頭,取值 0~1023 之間) /*+0x02*/ uint16 StartCylinder:6; // 啟始扇區(qū)號 6位 (取值 1 到 63 之間) 此結(jié)構(gòu)可容納最大值為FF FF FF (現(xiàn)在這個值基本都寫成FE FF FF, 而廢棄不用), 即最大能尋址的就是255柱面, 1023磁頭, 63扇區(qū),計算扇區(qū)個數(shù)為: 1023*255*63+255*63+63 = 16450623 再按每扇區(qū) 512 字節(jié)算, 那么它容量為 8 GB ≈ 512*16450623 B = 7.84 GB 傳統(tǒng)的int 13h中斷就受限于8G的限制, Microsoft等多家公司制定了int 13h擴展標(biāo)準(zhǔn),讓int 13h讀寫磁盤中斷可以突破8G限制. 現(xiàn)在的計算機BIOS都是按擴展int 13h標(biāo)準(zhǔn)編寫的代碼.(具體詳細(xì)內(nèi)容可參考"擴展 int 13h規(guī)范"). 按MBR分區(qū)表里面的 SectionPrecedingPartition 邏輯扇區(qū)偏移(注意,這個邏輯扇區(qū)偏移是從0開始算的,讀取出來值為63,而物理扇區(qū)是從1開始計算的,邏輯扇區(qū)轉(zhuǎn)換物理扇區(qū)的時候必須+1才是正確的) 可以找到DBR的位置.可以看看winhex的顯示 以下就偷懶不從MBR尋址分區(qū)的DBR了,而是直接打開盤符讀取 (這樣打開的第一個扇區(qū)就是DBR),這樣做有個缺點,就是你用這個handle值將不能進(jìn)行內(nèi)存映射,只能一次多讀取幾個扇區(qū)來加快分析磁盤的速度(當(dāng)前用的是一次讀取20M數(shù)據(jù)然后分析)。 HANDLE handle = CreateFile ( TEXT("\\\\.\\C:") , GENERIC_READ,FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); DBR結(jié)構(gòu)定義為(對照winhex模板信息查看): //////////////////////////////////////////////////////////////////////////// // NTFS 的DBR 數(shù)據(jù)結(jié)構(gòu) //////////////////////////////////////////////////////////////////////////// typedef struct _BIOS_PARAMETER_BLOCK { /*+0x0B*/ uint16 BytesPerSector; //字節(jié)/扇區(qū)一般為0x0200 即512 /*+0x0D*/ uchar SectorsPerCluster; //扇區(qū)/簇 /*+0x0E*/ uint16 ReservedSectors; //保留扇區(qū) /*+0x0F*/ uchar Fats; // /*+0x11*/ uint16 RootEntries; // /*+0x13*/ uint16 Sectors; // /*+0x15*/ uchar Media; //媒介描述 /*+0x16*/ uint16 SectorsPerFat; // /*+0x18*/ uint16 SectorsPerTrack; //扇區(qū)/磁軌 /*+0x1A*/ uint16 Heads; //頭 /*+0x1C*/ uint32 HiddenSectors; //隱藏扇區(qū) /*+0x20*/ uint32 LargeSectors; //checked when volume is mounted }BIOS_PARAMETER_BLOCK, *pBIOS_PARAMETER_BLOCK; typedef struct _NTFS_Boot_Sector{ /*+0x00*/ uchar JmpCode[3]; //跳轉(zhuǎn)指令 /*+0x03*/char OemID[8]; //文件系統(tǒng)ID /*+0x0B*/ BIOS_PARAMETER_BLOCK PackedBpb; //BPB /*+0x24*/ uchar Unused[4]; //未使用,總是為 /*+0x28*/ uint64 NumberSectors; //扇區(qū)總數(shù) /*+0x30*/ lcn MftStartLcn; //開始C# $MFT (簇) 乘以 BIOS_PARAMETER_BLOCK.SectorsPerCluster 值得到扇區(qū)號 /*+0x38*/ lcn Mft2StartLcn; //開始C# $MFTMirr (簇) /*+0x40*/ uchar ClustersPerFileRecordSegment;//文件記錄大小指示器 /*+0x41*/ uchar Reserved0[3]; //未使用 /*+0x44*/ uchar DefaultClustersPerIndexAllocationBuffer; //簇/索引塊 /*+0x45*/ uchar Reserved1[3]; //未使用 /*+0x48*/ uint64 SerialNumber; //64位序列號 /*+0x50*/ uint32 Checksum; //校驗和 /*+0x54*/ uchar BootStrap[426]; //啟動代碼 /*+0x1FE*/ uint16 RecordEndSign; //0xAA55 結(jié)束標(biāo)記 }NTFS_Boot_Sector, *pNTFS_Boot_Sector; 在讀取DBR的時候,一些數(shù)據(jù)以后經(jīng)常會用到,那么需要根據(jù)DBR里面的信息保存以后會用到的信息,下面定義一個常用的保存信息結(jié)構(gòu): //保存 NTFS 的基本信息 typedef struct _NTFS_INFO uint32 BytesPerSector; //每扇區(qū)的字節(jié)數(shù) uint32 SectorsPerCluster; //每簇的扇區(qū)數(shù) uint32 BytesPerCluster; //每簇的字節(jié)數(shù) uint64 SectorCount; //扇區(qū)總數(shù) uint64 MftStart; //MFT表開始簇 uint64 MftMirrStart; //MFT備份表開始簇 uint32 BytesPerFileRecord; //每個文件記錄的字節(jié)數(shù)一般為512*2 uint16 VolumeLabelLength; // 卷名長度,卷名從MFT第4個項0x60屬性得到(與0x30屬性相似) wchar VolumeLabel[MAXIMUM_VOLUME_LABEL_LENGTH]; //卷名 uint16 vcnlen; uchar vcn[VCN_LENTH]; } NTFS_INFO, *PNTFS_INFO; 其中 MAXIMUM_VOLUE_LABEL_LENGTH定義為 #define MAXIMUM_VOLUME_LABEL_LENGTH (32*sizeof(wchar)) NTFS_Boot_Sector .MftStartLcn*NTFS_Boot_Sector. PackedBpb .SectorsPerCluster得到MFT所在扇區(qū)號,這里為 786432*8 = 6291456扇區(qū)(字節(jié)偏移為 6291456*512= 3221225472 ( 十六進(jìn)制0xC0000000))。然后MFT表里面的內(nèi)容是根據(jù)簇號來讀取數(shù)據(jù)的,那么可以定義一個根據(jù)簇號,讀取數(shù)據(jù)的函數(shù),如下形式: typedef struct _Partition_Stand_Post { HANDLE handle;//分區(qū)句柄 uint64 CluNnum; //簇號 uint32 BytesPerCluster; //每簇字節(jié) uint64 CluCount; //簇數(shù)量 PNTFS_INFO NtfsInfo; //指向NTFS_INFO 結(jié)構(gòu) }Partition_Stand_Post, *pPartition_Stand_Post; //按簇讀取數(shù)據(jù), //傳入 一個Partition_Stand_Post結(jié)構(gòu)體指針,并指定buf,讀取大小 //結(jié)果返回讀取的數(shù)據(jù)指針 PBYTE ReadClues(pPartition_Stand_Post post, PBYTE buf, DWORD lenth) { DWORD dwbytes = 0; LARGE_INTEGER li = {0}; li.QuadPart = post->CluNnum*post->BytesPerCluster; SetFilePointer(post->handle, li.LowPart, &li.HighPart, FILE_BEGIN); ReadFile(post->handle, buf, lenth, &dwbytes, NULL); if (lenth == dwbytes) { return buf; } return NULL; } 下面先說MFT表的結(jié)構(gòu): 首先,看到的是頭部,標(biāo)記為"FILE", 結(jié)構(gòu)體如下定義: //文件記錄頭 typedef struct _FILE_RECORD_HEADER { /*+0x00*/ uint32 Type; //固定值'FILE' /*+0x04*/ uint16 UsaOffset; //更新序列號偏移, 與操作系統(tǒng)有關(guān) /*+0x06*/ uint16 UsaCount; //固定列表大小Size in words of Update Sequence Number & Array (S) /*+0x08*/ uint64 Lsn; //日志文件序列號(LSN) } FILE_RECORD_HEADER, *PFILE_RECORD_HEADER; //文件記錄體 typedef struct _FILE_RECORD{ /*+0x00*/ FILE_RECORD_HEADER Ntfs;//MFT表頭 /*+0x10*/ uint16 SequenceNumber; //序列號(用于記錄文件被反復(fù)使用的次數(shù)) /*+0x12*/ uint16 LinkCount; //硬連接數(shù) /*+0x14*/ uint16 AttributeOffset;//第一個屬性偏移 /*+0x16*/ uint16 Flags; //falgs, 00表示刪除文件,01表示正常文件,02表示刪除目錄,03表示正常目錄 /*+0x18*/ uint32 BytesInUse; //文件記錄實時大小(字節(jié)) 當(dāng)前MFT表項長度,到FFFFFF的長度+4 /*+0x1C*/ uint32 BytesAllocated; //文件記錄分配大小(字節(jié)) /*+0x20*/ uint64 BaseFileRecord; //= 0 基礎(chǔ)文件記錄 File reference to the base FILE record /*+0x28*/ uint16 NextAttributeNumber; //下一個自由ID號 /*+0x2A*/ uint16 Pading; //邊界 /*+0x2C*/ uint32 MFTRecordNumber;//windows xp中使用,本MFT記錄號 /*+0x30*/ uint32 MFTUseFlags; //MFT的使用標(biāo)記 }FILE_RECORD, *pFILE_RECORD; 這里主要關(guān)注的就是文件頭大小(0x38)可以找到第一個屬性地址,緊跟在后面的是文件類型,00表示被刪除的文件,01表示正常文件,02表示刪除目錄,03表示正常目錄.再后面就是這個MFT記錄的數(shù)據(jù)大小(很奇怪,為什么數(shù)據(jù)大小是從頭到0xFFFFFFFF的大小+4,這個值為什么不是直接從頭到0xFFFFFFFF的大小呢?). 根據(jù)FILE頭部數(shù)據(jù)找到下面的一個個屬性,接下來分析的就是一個個屬性了. 屬性由屬性頭跟屬性體組成,屬性頭的結(jié)構(gòu)定義如下: //屬性頭 typedef struct { /*+0x00*/ ATTRIBUTE_TYPE AttributeType; //屬性類型 /*+0x04*/ uint16 RecordLength; //總長度(Header+body長度) /**0x06*/ uint16 unknow0; /*+0x08*/ uchar Nonresident; //非常駐標(biāo)志 /*+0x09*/ uchar NameLength; //操作屬性名長度 //0X0001為壓縮標(biāo)記 //0X4000為加密標(biāo)記 //0X8000為系數(shù)文件標(biāo)志 /*+0x0A*/ uint16 NameOffset; //屬性名偏移(從屬性起始位置的偏移) //NameLength 如果不為零,則用這個值去尋址數(shù)據(jù)偏移 /*+0x0C*/ uint16 Flags; //ATTRIBUTE_xxx flags. /*+0x0E*/ uint16 AttributeNumber; //The file-record-unique attribute instance number for this attribute. } ATTRIBUTE, *PATTRIBUTE; //屬性頭 typedef struct _RESIDENT_ATTRIBUTE { /*+0x00*/ ATTRIBUTE Attribute; //屬性 /*+0x10*/ uint32 ValueLength; //Data部分長度 /*+0x14*/ uint16 ValueOffset; //Data內(nèi)容起始偏移 /*+0x16*/ uchar Flags; //索引標(biāo)志 /*+0x17*/ uchar Padding0; //填充 } RESIDENT_ATTRIBUTE, *PRESIDENT_ATTRIBUTE; 其中ATTRIBUTE_TYPE是一個枚舉類型,里面定義了可能出現(xiàn)的所有類型。查看這個結(jié)構(gòu)主要是看AttributeType(上圖中,染上綠色的為屬性類型,跟在后面的的紅色框框內(nèi)數(shù)據(jù)為屬性頭+屬性體的大小(這個值必須是大于0x10,小于512的,程序中必須判斷),由這個值可以得到下一個屬性的地址),這個類型是什么,然后再跟去類型定義的Data部分去解析下面的屬性體。遍歷屬性的時候可以根據(jù)屬性類型來判斷是否已經(jīng)到達(dá)結(jié)尾,如果屬性類型為0xFFFFFFFF則表示已經(jīng)到達(dá)末尾(注意遍歷的時候還是要結(jié)合FILE頭部指定的大小來遍歷,這樣程序健壯性好很多,還有如果屬性頭后面跟著的大小值小于0x10也要結(jié)束遍歷,因為這時候這個MFT項已經(jīng)不可靠了,再繼續(xù)下去程序出錯可能性比較大(0x00值可能出現(xiàn)死循環(huán)))。 屬性類型定義,及各個類型屬性的結(jié)構(gòu)(缺少無關(guān)緊要的結(jié)構(gòu),其他結(jié)構(gòu)可參考nt4里面的源碼并對照winhex分析): //屬性類型定義 typedef enum _ATTRIBUTE_TYPE { AttributeStandardInformation = 0x10, AttributeAttributeList = 0x20, AttributeFileName = 0x30, AttributeObjectId = 0x40, AttributeSecurityDescriptor = 0x50, AttributeVolumeName = 0x60, AttributeVolumeInformation = 0x70, AttributeData = 0x80, AttributeIndexRoot = 0x90, AttributeIndexAllocation = 0xA0, AttributeBitmap = 0xB0, AttributeReparsePoint = 0xC0, AttributeEAInformation = 0xD0, AttributeEA = 0xE0, AttributePropertySet = 0xF0, AttributeLoggedUtilityStream = 0x100 } ATTRIBUTE_TYPE, *PATTRIBUTE_TYPE; //基礎(chǔ)信息ATTRIBUTE.AttributeType == 0x10 typedef struct _STANDARD_INFORMATION { uint64 CreationTime; //創(chuàng)建時間 uint64 ChangeTime; //修改時間 uint64 LastWriteTime; //最后寫入時間 uint64 LastAccessTime; //最后訪問時間 uint32 FileAttribute; //文件屬性 uint32 AlignmentOrReserved[3]; // #if 0 uint32 QuotaId; uint32 SecurityId; uint64 QuotaCharge; USN Usn; #endif } STANDARD_INFORMATION, *PSTANDARD_INFORMATION; //屬性列表ATTRIBUTE.AttributeType == 0x20 typedef struct _ATTRIBUTE_LIST { ATTRIBUTE_TYPE AttributeType; uint16 Length; uchar NameLength; uchar NameOffset; uint64 StartVcn; //LowVcn uint64 FileReferenceNumber; uint16 AttributeNumber; uint16 AlignmentOrReserved[3]; } ATTRIBUTE_LIST, *PATTRIBUTE_LIST; //文件屬性ATTRIBUTE.AttributeType == 0x30 typedef struct { /*+0x00*/ uint64 DirectoryFile:48; //父目錄記錄號(前個字節(jié)) /*+0x06*/ uint64 ReferenceNumber:16;//+序列號(與目錄相關(guān)) /*+0x08*/ uint64 CreationTime; //文件創(chuàng)建時間 /*+0x10*/ uint64 ChangeTime; //文件修改時間 /*+0x18*/ uint64 LastWriteTime; //MFT更新的時間 /*+0x20*/ uint64 LastAccessTime; //最后一次訪問時間 /*+0x28*/ uint64 AllocatedSize; //文件分配大小 /*+0x30*/ uint64 DataSize; //文件實際大小 /*+0x38*/ uint32 FileAttributes; //標(biāo)志,如目錄\壓縮\隱藏等 /*+0x3C*/ uint32 AlignmentOrReserved; //用于EAS和重解析 /*+0x40*/ uchar NameLength; //以字符計的文件名長度,沒字節(jié)占用字節(jié)數(shù)由下一字節(jié)命名空間確定 //文件名命名空間, 0 POSIX大小寫敏感,1 win32空間,2 DOS空間, 3 win32&DOS空間 /*+0x41*/ uchar NameType; /*+0x42*/ wchar Name[1]; //以Unicode方式標(biāo)識的文件名 } FILENAME_ATTRIBUTE, *PFILENAME_ATTRIBUTE; //數(shù)據(jù)流屬性 ATTRIBUTE.AttributeType == 0x80 typedef struct _NONRESIDENT_ATTRIBUTE { /*+0x00*/ ATTRIBUTE Attribute; /*+0x10*/ uint64 StartVcn; //LowVcn 起始VCN 起始簇號 /*+0x18*/ uint64 LastVcn; //HighVcn 結(jié)束VCN 結(jié)束簇號 /*+0x20*/ uint16 RunArrayOffset; //數(shù)據(jù)運行的偏移 /*+0x22*/ uint16 CompressionUnit; //壓縮引擎 /*+0x24*/ uint32 Padding0; //填充 /*+0x28*/ uint32 IndexedFlag; //為屬性值分配大小(按分配的簇的字節(jié)數(shù)計算) /*+0x30*/ uint64 AllocatedSize; //屬性值實際大小 /*+0x38*/ uint64 DataSize; //屬性值壓縮大小 /*+0x40*/ uint64 InitializedSize; //實際數(shù)據(jù)大小 /*+0x48*/ uint64 CompressedSize; //壓縮后大小 } NONRESIDENT_ATTRIBUTE, *PNONRESIDENT_ATTRIBUTE; 以下特別要說明就是數(shù)據(jù)恢復(fù)中要使用的一些結(jié)構(gòu) ;0x30 AttributeFileName屬性 (如果文件名很長,那么有多個0x30屬性,一個記錄短文件名,一個記錄長文件名),記錄了很多文件信息,可能使用到的有文件創(chuàng)建時間、文件修改時間、最后寫入時間、文件最后一次訪問時間。這里面的幾個值相當(dāng)于用GetFileTime 或者GetFileInformationByHandle得到的幾個FILETIME值,可以調(diào)用FileTimeToSystemTime轉(zhuǎn)換時間。其中DataSize為實際文件使用的大小,在0x80屬性中尋找簇恢復(fù)數(shù)據(jù)的時候會用到這個值。最后就是wchar的文件名,此名在cmd中顯示需用WideCharToMultiByte轉(zhuǎn)換后用printf顯示,如果用wprintf顯示中文會出現(xiàn)亂碼問題。數(shù)據(jù)恢復(fù)的時候如果需要目錄結(jié)構(gòu)可由此屬性中的DirectoryFile值得到,此值為父目錄的記錄號(相對于$MFT元所在扇區(qū)的偏移,即:$MFT + DirectoryFile*2)例如: 上圖,父目錄號為0x0000000002A4,從DBR中得到$MFT起始簇為786432(上面圖一簇為8扇區(qū)),則父目錄的MFT表項扇區(qū)為: 786432*8+0x0000000002A4*2 = 6292808,再查看6292808扇區(qū): 所以這個文件為 X:\windows\notepad.exe(其中X表示為根目錄,具體看前面CreateFile參數(shù)值是什么了). 0x80 AttributeData屬性( 注意:如果是目錄的話, 此結(jié)構(gòu)屬性是0xA0 ) 如果有多個0x80屬性,則應(yīng)該認(rèn)為這個文件里面存在數(shù)據(jù)流文件,數(shù)據(jù)流表示形式為"0x30記錄文件名:流文件名",并且在explorer瀏覽中查看不到這個文件,NTFS剛出來的時候,文件流屬性進(jìn)程被病毒作者使用,比如如果要將hack.exe數(shù)據(jù)加到 1.txt 數(shù)據(jù)流里面,那么可以如下方式: void CrateDataStream() HANDLE hfile = CreateFile( TEXT("1.txt:DataStream.exe"), //1.txt中數(shù)據(jù)流名字為DataStream.exe(隨意取的) GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (hfile == INVALID_HANDLE_VALUE) { return ; //打開文件錯誤 } HANDLE hExeFile = CreateFile( TEXT("hack.exe"), GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (hExeFile == INVALID_HANDLE_VALUE) { CloseHandle(hfile); return ; //打開文件錯誤 } DWORD dwsize = GetFileSize(hExeFile, NULL); BYTE* buf = new BYTE[dwsize]; DWORD wbytes; ReadFile(hExeFile, buf, dwsize, &wbytes, NULL); WriteFile(hfile, buf, wbytes, &wbytes, NULL); CloseHandle(hExeFile); CloseHandle(hfile); } 一般是病毒作者將這個 1.txt 添加到壓縮文件(高級里面選上保存文件流數(shù)據(jù)), 然后搞成自解壓包, 在解壓后命令中寫入1.txt: DataStream.exe, 在用戶雙擊解壓的時候就會運行里面的數(shù)據(jù)流程序。不過現(xiàn)在殺毒軟件對這種數(shù)據(jù)流病毒基本都能殺了。 再說數(shù)據(jù)恢復(fù)的關(guān)鍵點:數(shù)據(jù)內(nèi)容由NONRESIDENT_ATTRIBUTE. RunArrayOffset偏移指定DATA數(shù)據(jù)地址。如果屬性頭 ATTRIBUTE.Nonresident標(biāo)記為1表示非常駐,則下面會解析怎么需要解析DATA部分, 如果為0則表示DATA就是文件內(nèi)容, 比如一個txt文件里面記錄的數(shù)據(jù)很少, 則此標(biāo)記為0, 記事本里面數(shù)據(jù)就保存在DATA中。上圖因為查看的是MFT自身,$MFT比較特殊,非常駐屬性設(shè)置成0(即FALSE)但是卻要像非常駐屬性一樣去分析。 上圖藍(lán)色的部分,看不太清數(shù)據(jù),原始數(shù)據(jù)如下: 最開始的數(shù)據(jù)為32,其中高4bits表示數(shù)據(jù)起始簇地址占用字節(jié)數(shù),后4bits為數(shù)據(jù)大小(簇個數(shù))占用字節(jié)數(shù)..這里要特別注意,第一個起始簇信息是無符號的,后面第二個開始就是相對于前面一個簇的偏移,是有正負(fù)的,查了很多資料,這點基本上都沒提及,這也是數(shù)據(jù)恢復(fù)最容易出錯的地方,辛辛苦苦寫好了程序,一測試發(fā)現(xiàn)恢復(fù)出來的數(shù)據(jù)有問題。 上面第一個扇區(qū)地址為52604144(0x64559E*8,相對去當(dāng)前分區(qū)的扇區(qū)偏移),第二個扇區(qū)地址為(0x64559E - 0x 77)*8 = 6575399 扇區(qū)(這里值0x89為-119)。 恢復(fù)數(shù)據(jù)的時候可以根據(jù)簇大小讀取文件,然后保存,再根據(jù)前面的NONRESIDENT_ATTRIBUTE. DataSize值去SetFilePointer設(shè)置文件大小繼而調(diào)用SetEndOfFile。 定義一個結(jié)構(gòu)體表示這個結(jié)構(gòu): typedef struct _VCN_FLASH { uchar VcnLen:4; //簇流長度 *8*512 才是得到的文件字節(jié)數(shù) uchar StartVcnLen:4; //簇流起始位置--簇號 uchar Data[1]; //簇流長度&Data + 簇流起始位置&Data+VcnLen 數(shù)據(jù)部分 }VCN_FLASH, *PVCN_FLASH; 再定義2個函數(shù)計算有符號與無符號數(shù): uint64 make_uint64(uchar* buf, int lenth) { int64 ui=0; if (lenth > 8) { return (int64)0; } for (int i=0; i<lenth; i++) { ui = (buf[i]<<8*i)|ui; } return ui; } int64 make_int64(uchar* buf, int lenth) { int64 ui=0; if (lenth > 8) { return (int64)0; } for (int i=0; i<lenth; i++) { ui = (buf[i]<<8*i)|ui; } //判斷符號位,為負(fù)則需減取反 if (buf[lenth-1] >= 0x80) { int64 xorval = 0; for (i=0; i<lenth; i++) { xorval = xorval|(0xFF<<8*i); } ui = -((ui - 1)^xorval); } return ui; } 0x90 AttributeIndexRoot 屬性 ( 目錄索引B+樹結(jié)構(gòu) ) 這個屬性,我也不是很清楚,等弄清楚了,再接著完善................. NTFS文件系統(tǒng)中MFT項中主要字節(jié)的標(biāo)注(***)強調(diào): 1、標(biāo)注是結(jié)合其它資料和自己的理解完成的,有可能標(biāo)注不一定正確,所以僅供參考!! 2、如轉(zhuǎn)載,請保持圖片的完整性,這也是對原創(chuàng)人員的尊重,謝謝!! 原始 基本標(biāo)注 文件記錄頭標(biāo)注 文件記錄頭標(biāo)志字節(jié)的注解 屬性標(biāo)注 屬性頭 屬性值標(biāo)注 常駐、無屬性名的屬性頭標(biāo)注 常駐、有屬性名的屬性頭標(biāo)注 非常駐、無屬性名的屬性頭標(biāo)注 非常駐、有屬性名的屬性頭標(biāo)注 |
|