Add files via upload

This commit is contained in:
3gstudent
2021-04-22 13:53:57 -10:00
committed by GitHub
parent 060ca4373b
commit 87ecd5d75a
11 changed files with 3516 additions and 0 deletions
+28
View File
@@ -0,0 +1,28 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 14
VisualStudioVersion = 14.0.25420.1
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ntfsDump", "ntfsDump\ntfsDump.vcxproj", "{9622A76B-A2B2-4E45-B38B-1EBD2A0DDAEF}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{9622A76B-A2B2-4E45-B38B-1EBD2A0DDAEF}.Debug|x64.ActiveCfg = Debug|x64
{9622A76B-A2B2-4E45-B38B-1EBD2A0DDAEF}.Debug|x64.Build.0 = Debug|x64
{9622A76B-A2B2-4E45-B38B-1EBD2A0DDAEF}.Debug|x86.ActiveCfg = Debug|Win32
{9622A76B-A2B2-4E45-B38B-1EBD2A0DDAEF}.Debug|x86.Build.0 = Debug|Win32
{9622A76B-A2B2-4E45-B38B-1EBD2A0DDAEF}.Release|x64.ActiveCfg = Release|x64
{9622A76B-A2B2-4E45-B38B-1EBD2A0DDAEF}.Release|x64.Build.0 = Release|x64
{9622A76B-A2B2-4E45-B38B-1EBD2A0DDAEF}.Release|x86.ActiveCfg = Release|Win32
{9622A76B-A2B2-4E45-B38B-1EBD2A0DDAEF}.Release|x86.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal
+18
View File
@@ -0,0 +1,18 @@
/*
* NTFS include files
*
* Copyright(C) 2010 cyb70289 <cyb70289@gmail.com>
*/
#ifndef __NTFS_H_CYB70289
#define __NTFS_H_CYB70289
#pragma pack(8)
#include "NTFS_Common.h"
#include "NTFS_FileRecord.h"
#include "NTFS_Attribute.h"
#pragma pack()
#endif
File diff suppressed because it is too large Load Diff
+307
View File
@@ -0,0 +1,307 @@
/*
* NTFS Class common definitions
*
* Copyright(C) 2010 cyb70289 <cyb70289@gmail.com>
*/
#ifndef __NTFS_COMMON_H_CYB70289
#define __NTFS_COMMON_H_CYB70289
#include <windows.h>
#include <stdio.h>
#include <tchar.h>
#include <crtdbg.h>
#include "NTFS_DataType.h"
#define ATTR_NUMS 16 // Attribute Types count
#define ATTR_INDEX(at) (((at)>>4)-1) // Attribute Type to Index, eg. 0x10->0, 0x30->2
#define ATTR_MASK(at) (((DWORD)1)<<ATTR_INDEX(at)) // Attribute Bit Mask
// Bit masks of Attributes
#define MASK_STANDARD_INFORMATION ATTR_MASK(ATTR_TYPE_STANDARD_INFORMATION)
#define MASK_ATTRIBUTE_LIST ATTR_MASK(ATTR_TYPE_ATTRIBUTE_LIST)
#define MASK_FILE_NAME ATTR_MASK(ATTR_TYPE_FILE_NAME)
#define MASK_OBJECT_ID ATTR_MASK(ATTR_TYPE_OBJECT_ID)
#define MASK_SECURITY_DESCRIPTOR ATTR_MASK(ATTR_TYPE_SECURITY_DESCRIPTOR)
#define MASK_VOLUME_NAME ATTR_MASK(ATTR_TYPE_VOLUME_NAME)
#define MASK_VOLUME_INFORMATION ATTR_MASK(ATTR_TYPE_VOLUME_INFORMATION)
#define MASK_DATA ATTR_MASK(ATTR_TYPE_DATA)
#define MASK_INDEX_ROOT ATTR_MASK(ATTR_TYPE_INDEX_ROOT)
#define MASK_INDEX_ALLOCATION ATTR_MASK(ATTR_TYPE_INDEX_ALLOCATION)
#define MASK_BITMAP ATTR_MASK(ATTR_TYPE_BITMAP)
#define MASK_REPARSE_POINT ATTR_MASK(ATTR_TYPE_REPARSE_POINT)
#define MASK_EA_INFORMATION ATTR_MASK(ATTR_TYPE_EA_INFORMATION)
#define MASK_EA ATTR_MASK(ATTR_TYPE_EA)
#define MASK_LOGGED_UTILITY_STREAM ATTR_MASK(ATTR_TYPE_LOGGED_UTILITY_STREAM)
#define MASK_ALL ((DWORD)-1)
#define NTFS_TRACE(t1) _RPT0(_CRT_WARN, t1)
#define NTFS_TRACE1(t1, t2) _RPT1(_CRT_WARN, t1, t2)
#define NTFS_TRACE2(t1, t2, t3) _RPT2(_CRT_WARN, t1, t2, t3)
#define NTFS_TRACE3(t1, t2, t3, t4) _RPT3(_CRT_WARN, t1, t2, t3, t4)
#define NTFS_TRACE4(t1, t2, t3, t4, t5) _RPT4(_CRT_WARN, t1, t2, t3, t4, t5)
// User defined Callback routines to process raw attribute data
// Set bDiscard to TRUE if this Attribute is to be discarded
// Set bDiscard to FALSE to let CFileRecord process it
typedef void (*ATTR_RAW_CALLBACK)(const ATTR_HEADER_COMMON *attrHead, BOOL *bDiscard);
// User defined Callback routine to handle CFileRecord parsed attributes
// Will be called by CFileRecord::TraverseAttrs() for each attribute
// attrClass is the according attribute's wrapping class, CAttr_xxx
// Set bStop to TRUE if don't want to continue
// Set bStop to FALSE to continue processing
class CAttrBase;
typedef void (*ATTRS_CALLBACK)(const CAttrBase *attr, void *context, BOOL *bStop);
// User defined Callback routine to handle Directory traversing
// Will be called by CFileRecord::TraverseSubEntries for each sub entry
class CIndexEntry;
typedef void (*SUBENTRY_CALLBACK)(const CIndexEntry *ie);
// List Entry
template <class ENTRY_TYPE>
struct NTSLIST_ENTRY
{
NTSLIST_ENTRY *Next;
ENTRY_TYPE *Entry;
};
// List Entry Smart Pointer
template <class ENTRY_TYPE>
class CEntrySmartPtr
{
public:
CEntrySmartPtr(ENTRY_TYPE *ptr = NULL)
{
EntryPtr = ptr;
}
virtual ~CEntrySmartPtr()
{
if (EntryPtr)
delete EntryPtr;
}
private:
const ENTRY_TYPE *EntryPtr;
public:
__inline CEntrySmartPtr<ENTRY_TYPE> operator = (const ENTRY_TYPE* ptr)
{
// Delete previous pointer if allocated
if (EntryPtr)
delete EntryPtr;
EntryPtr = ptr;
return *this;
}
__inline const ENTRY_TYPE* operator->() const
{
_ASSERT(EntryPtr);
return EntryPtr;
}
__inline BOOL IsValid() const
{
return EntryPtr != NULL;
}
};
//////////////////////////////////////
// Single list implementation
//////////////////////////////////////
template <class ENTRY_TYPE>
class CSList
{
public:
CSList()
{
ListHead = ListTail = NULL;
ListCurrent = NULL;
EntryCount = 0;
}
virtual ~CSList()
{
RemoveAll();
}
private:
int EntryCount;
NTSLIST_ENTRY<ENTRY_TYPE> *ListHead;
NTSLIST_ENTRY<ENTRY_TYPE> *ListTail;
NTSLIST_ENTRY<ENTRY_TYPE> *ListCurrent;
public:
// Get entry count
__inline int GetCount() const
{
return EntryCount;
}
// Insert to tail
BOOL InsertEntry(ENTRY_TYPE *entry)
{
NTSLIST_ENTRY<ENTRY_TYPE> *le = new NTSLIST_ENTRY<ENTRY_TYPE>;
if (!le)
return FALSE;
le->Entry = entry;
le->Next = NULL;
if (ListTail == NULL)
ListHead = le; // Empty list
else
ListTail->Next = le;
ListTail = le;
EntryCount++;
return TRUE;
}
// Remove all entries
void RemoveAll()
{
while (ListHead)
{
ListCurrent = ListHead->Next;
delete ListHead->Entry;
delete ListHead;
ListHead = ListCurrent;
}
ListHead = ListTail = NULL;
ListCurrent = NULL;
EntryCount = 0;
}
// Find first entry
__inline ENTRY_TYPE *FindFirstEntry() const
{
((CSList<ENTRY_TYPE>*)this)->ListCurrent = ListHead;
if (ListCurrent)
return ListCurrent->Entry;
else
return NULL;
}
// Find next entry
__inline ENTRY_TYPE *FindNextEntry() const
{
if (ListCurrent)
((CSList<ENTRY_TYPE>*)this)->ListCurrent = ListCurrent->Next;
if (ListCurrent)
return ListCurrent->Entry;
else
return NULL;
}
// Throw all entries
// Caution! All entries are just thrown without free
__inline void ThrowAll()
{
ListHead = ListTail = NULL;
ListCurrent = NULL;
EntryCount = 0;
}
}; //CSList
//////////////////////////////////////
// Stack implementation
//////////////////////////////////////
template <class ENTRY_TYPE>
class CStack
{
public:
CStack()
{
ListHead = ListTail = NULL;
EntryCount = 0;
}
virtual ~CStack()
{
RemoveAll();
}
private:
int EntryCount;
NTSLIST_ENTRY<ENTRY_TYPE> *ListHead;
NTSLIST_ENTRY<ENTRY_TYPE> *ListTail;
public:
// Get entry count
__inline int GetCount() const
{
return EntryCount;
}
// Insert to head
BOOL Push(ENTRY_TYPE *entry)
{
NTSLIST_ENTRY<ENTRY_TYPE> *le = new NTSLIST_ENTRY<ENTRY_TYPE>;
if (!le)
return FALSE;
le->Entry = entry;
le->Next = ListHead;
ListHead = le;
if (ListTail == NULL)
ListTail = le; // Empty list
EntryCount ++;
return TRUE;
}
// Remove from head
ENTRY_TYPE* Pop()
{
if (ListHead == NULL)
return NULL;
NTSLIST_ENTRY<ENTRY_TYPE> *le = ListHead;
ENTRY_TYPE *e = le->Entry;
if (ListTail == ListHead)
ListTail = ListHead->Next;
ListHead = ListHead->Next;
delete le;
EntryCount --;
return e;
}
// Remove all entries
void RemoveAll()
{
NTSLIST_ENTRY<ENTRY_TYPE> *le;
while (ListHead)
{
le = ListHead->Next;
delete ListHead->Entry;
delete ListHead;
ListHead = le;
}
ListHead = ListTail = NULL;
EntryCount = 0;
}
}; //CStack
#endif
+370
View File
@@ -0,0 +1,370 @@
/*
* NTFS data structures and definitions
*
* Copyright(C) 2010 cyb70289 <cyb70289@gmail.com>
*/
#ifndef __NTFS_DATATYPE_H_CYB70289
#define __NTFS_DATATYPE_H_CYB70289
// NTFS Boot Sector BPB
#define NTFS_SIGNATURE "NTFS "
#pragma pack(1)
typedef struct tagNTFS_BPB
{
// jump instruction
BYTE Jmp[3];
// signature
BYTE Signature[8];
// BPB and extended BPB
WORD BytesPerSector;
BYTE SectorsPerCluster;
WORD ReservedSectors;
BYTE Zeros1[3];
WORD NotUsed1;
BYTE MediaDescriptor;
WORD Zeros2;
WORD SectorsPerTrack;
WORD NumberOfHeads;
DWORD HiddenSectors;
DWORD NotUsed2;
DWORD NotUsed3;
ULONGLONG TotalSectors;
ULONGLONG LCN_MFT;
ULONGLONG LCN_MFTMirr;
DWORD ClustersPerFileRecord;
DWORD ClustersPerIndexBlock;
BYTE VolumeSN[8];
// boot code
BYTE Code[430];
//0xAA55
BYTE _AA;
BYTE _55;
} NTFS_BPB;
#pragma pack()
// MFT Indexes
#define MFT_IDX_MFT 0
#define MFT_IDX_MFT_MIRR 1
#define MFT_IDX_LOG_FILE 2
#define MFT_IDX_VOLUME 3
#define MFT_IDX_ATTR_DEF 4
#define MFT_IDX_ROOT 5
#define MFT_IDX_BITMAP 6
#define MFT_IDX_BOOT 7
#define MFT_IDX_BAD_CLUSTER 8
#define MFT_IDX_SECURE 9
#define MFT_IDX_UPCASE 10
#define MFT_IDX_EXTEND 11
#define MFT_IDX_RESERVED12 12
#define MFT_IDX_RESERVED13 13
#define MFT_IDX_RESERVED14 14
#define MFT_IDX_RESERVED15 15
#define MFT_IDX_USER 16
/******************************
File Record
---------------------
| File Record Header|
---------------------
| Attribute 1 |
---------------------
| Attribute 2 |
---------------------
| ...... |
---------------------
| 0xFFFFFFFF |
---------------------
*******************************/
// File Record Header
#define FILE_RECORD_MAGIC 'ELIF'
#define FILE_RECORD_FLAG_INUSE 0x01 // File record is in use
#define FILE_RECORD_FLAG_DIR 0x02 // File record is a directory
typedef struct tagFILE_RECORD_HEADER
{
DWORD Magic; // "FILE"
WORD OffsetOfUS; // Offset of Update Sequence
WORD SizeOfUS; // Size in words of Update Sequence Number & Array
ULONGLONG LSN; // $LogFile Sequence Number
WORD SeqNo; // Sequence number
WORD Hardlinks; // Hard link count
WORD OffsetOfAttr; // Offset of the first Attribute
WORD Flags; // Flags
DWORD RealSize; // Real size of the FILE record
DWORD AllocSize; // Allocated size of the FILE record
ULONGLONG RefToBase; // File reference to the base FILE record
WORD NextAttrId; // Next Attribute Id
WORD Align; // Align to 4 byte boundary
DWORD RecordNo; // Number of this MFT Record
} FILE_RECORD_HEADER;
/******************************
Attribute
--------------------
| Attribute Header |
--------------------
| Attribute Data |
--------------------
*******************************/
// Attribute Header
#define ATTR_TYPE_STANDARD_INFORMATION 0x10
#define ATTR_TYPE_ATTRIBUTE_LIST 0x20
#define ATTR_TYPE_FILE_NAME 0x30
#define ATTR_TYPE_OBJECT_ID 0x40
#define ATTR_TYPE_SECURITY_DESCRIPTOR 0x50
#define ATTR_TYPE_VOLUME_NAME 0x60
#define ATTR_TYPE_VOLUME_INFORMATION 0x70
#define ATTR_TYPE_DATA 0x80
#define ATTR_TYPE_INDEX_ROOT 0x90
#define ATTR_TYPE_INDEX_ALLOCATION 0xA0
#define ATTR_TYPE_BITMAP 0xB0
#define ATTR_TYPE_REPARSE_POINT 0xC0
#define ATTR_TYPE_EA_INFORMATION 0xD0
#define ATTR_TYPE_EA 0xE0
#define ATTR_TYPE_LOGGED_UTILITY_STREAM 0x100
#define ATTR_FLAG_COMPRESSED 0x0001
#define ATTR_FLAG_ENCRYPTED 0x4000
#define ATTR_FLAG_SPARSE 0x8000
typedef struct tagATTR_HEADER_COMMON
{
DWORD Type; // Attribute Type
DWORD TotalSize; // Length (including this header)
BYTE NonResident; // 0 - resident, 1 - non resident
BYTE NameLength; // name length in words
WORD NameOffset; // offset to the name
WORD Flags; // Flags
WORD Id; // Attribute Id
} ATTR_HEADER_COMMON;
typedef struct tagATTR_HEADER_RESIDENT
{
ATTR_HEADER_COMMON Header; // Common data structure
DWORD AttrSize; // Length of the attribute body
WORD AttrOffset; // Offset to the Attribute
BYTE IndexedFlag; // Indexed flag
BYTE Padding; // Padding
} ATTR_HEADER_RESIDENT;
typedef struct tagATTR_HEADER_NON_RESIDENT
{
ATTR_HEADER_COMMON Header; // Common data structure
ULONGLONG StartVCN; // Starting VCN
ULONGLONG LastVCN; // Last VCN
WORD DataRunOffset; // Offset to the Data Runs
WORD CompUnitSize; // Compression unit size
DWORD Padding; // Padding
ULONGLONG AllocSize; // Allocated size of the attribute
ULONGLONG RealSize; // Real size of the attribute
ULONGLONG IniSize; // Initialized data size of the stream
} ATTR_HEADER_NON_RESIDENT;
// Attribute: STANDARD_INFORMATION
#define ATTR_STDINFO_PERMISSION_READONLY 0x00000001
#define ATTR_STDINFO_PERMISSION_HIDDEN 0x00000002
#define ATTR_STDINFO_PERMISSION_SYSTEM 0x00000004
#define ATTR_STDINFO_PERMISSION_ARCHIVE 0x00000020
#define ATTR_STDINFO_PERMISSION_DEVICE 0x00000040
#define ATTR_STDINFO_PERMISSION_NORMAL 0x00000080
#define ATTR_STDINFO_PERMISSION_TEMP 0x00000100
#define ATTR_STDINFO_PERMISSION_SPARSE 0x00000200
#define ATTR_STDINFO_PERMISSION_REPARSE 0x00000400
#define ATTR_STDINFO_PERMISSION_COMPRESSED 0x00000800
#define ATTR_STDINFO_PERMISSION_OFFLINE 0x00001000
#define ATTR_STDINFO_PERMISSION_NCI 0x00002000
#define ATTR_STDINFO_PERMISSION_ENCRYPTED 0x00004000
typedef struct tagATTR_STANDARD_INFORMATION
{
ULONGLONG CreateTime; // File creation time
ULONGLONG AlterTime; // File altered time
ULONGLONG MFTTime; // MFT changed time
ULONGLONG ReadTime; // File read time
DWORD Permission; // Dos file permission
DWORD MaxVersionNo; // Maxim number of file versions
DWORD VersionNo; // File version number
DWORD ClassId; // Class Id
DWORD OwnerId; // Owner Id
DWORD SecurityId; // Security Id
ULONGLONG QuotaCharged; // Quota charged
ULONGLONG USN; // USN Journel
} ATTR_STANDARD_INFORMATION;
// Attribute: ATTRIBUTE_LIST
typedef struct tagATTR_ATTRIBUTE_LIST
{
DWORD AttrType; // Attribute type
WORD RecordSize; // Record length
BYTE NameLength; // Name length in characters
BYTE NameOffset; // Name offset
ULONGLONG StartVCN; // Start VCN
ULONGLONG BaseRef; // Base file reference to the attribute
WORD AttrId; // Attribute Id
} ATTR_ATTRIBUTE_LIST;
// Attribute: FILE_NAME
#define ATTR_FILENAME_FLAG_READONLY 0x00000001
#define ATTR_FILENAME_FLAG_HIDDEN 0x00000002
#define ATTR_FILENAME_FLAG_SYSTEM 0x00000004
#define ATTR_FILENAME_FLAG_ARCHIVE 0x00000020
#define ATTR_FILENAME_FLAG_DEVICE 0x00000040
#define ATTR_FILENAME_FLAG_NORMAL 0x00000080
#define ATTR_FILENAME_FLAG_TEMP 0x00000100
#define ATTR_FILENAME_FLAG_SPARSE 0x00000200
#define ATTR_FILENAME_FLAG_REPARSE 0x00000400
#define ATTR_FILENAME_FLAG_COMPRESSED 0x00000800
#define ATTR_FILENAME_FLAG_OFFLINE 0x00001000
#define ATTR_FILENAME_FLAG_NCI 0x00002000
#define ATTR_FILENAME_FLAG_ENCRYPTED 0x00004000
#define ATTR_FILENAME_FLAG_DIRECTORY 0x10000000
#define ATTR_FILENAME_FLAG_INDEXVIEW 0x20000000
#define ATTR_FILENAME_NAMESPACE_POSIX 0x00
#define ATTR_FILENAME_NAMESPACE_WIN32 0x01
#define ATTR_FILENAME_NAMESPACE_DOS 0x02
typedef struct tagATTR_FILE_NAME
{
ULONGLONG ParentRef; // File reference to the parent directory
ULONGLONG CreateTime; // File creation time
ULONGLONG AlterTime; // File altered time
ULONGLONG MFTTime; // MFT changed time
ULONGLONG ReadTime; // File read time
ULONGLONG AllocSize; // Allocated size of the file
ULONGLONG RealSize; // Real size of the file
DWORD Flags; // Flags
DWORD ER; // Used by EAs and Reparse
BYTE NameLength; // Filename length in characters
BYTE NameSpace; // Filename space
WORD Name[1]; // Filename
} ATTR_FILE_NAME;
// Attribute: VOLUME_INFORMATION
#define ATTR_VOLINFO_FLAG_DIRTY 0x0001 // Dirty
#define ATTR_VOLINFO_FLAG_RLF 0x0002 // Resize logfile
#define ATTR_VOLINFO_FLAG_UOM 0x0004 // Upgrade on mount
#define ATTR_VOLINFO_FLAG_MONT 0x0008 // Mounted on NT4
#define ATTR_VOLINFO_FLAG_DUSN 0x0010 // Delete USN underway
#define ATTR_VOLINFO_FLAG_ROI 0x0020 // Repair object Ids
#define ATTR_VOLINFO_FLAG_MBC 0x8000 // Modified by chkdsk
typedef struct tagATTR_VOLUME_INFORMATION
{
BYTE Reserved1[8]; // Always 0 ?
BYTE MajorVersion; // Major version
BYTE MinorVersion; // Minor version
WORD Flags; // Flags
BYTE Reserved2[4]; // Always 0 ?
} ATTR_VOLUME_INFORMATION;
// Attribute: INDEX_ROOT
/******************************
INDEX_ROOT
---------------------
| Index Root Header |
---------------------
| Index Header |
---------------------
| Index Entry |
---------------------
| Index Entry |
---------------------
| ...... |
---------------------
*******************************/
#define ATTR_INDEXROOT_FLAG_SMALL 0x00 // Fits in Index Root File Record
#define ATTR_INDEXROOT_FLAG_LARGE 0x01 // Index Allocation and Bitmap needed
typedef struct tagATTR_INDEX_ROOT
{
// Index Root Header
DWORD AttrType; // Attribute type (ATTR_TYPE_FILE_NAME: Directory, 0: Index View)
DWORD CollRule; // Collation rule
DWORD IBSize; // Size of index block
BYTE ClustersPerIB; // Clusters per index block (same as BPB?)
BYTE Padding1[3]; // Padding
// Index Header
DWORD EntryOffset; // Offset to the first index entry, relative to this address(0x10)
DWORD TotalEntrySize; // Total size of the index entries
DWORD AllocEntrySize; // Allocated size of the index entries
BYTE Flags; // Flags
BYTE Padding2[3]; // Padding
} ATTR_INDEX_ROOT;
// INDEX ENTRY
#define INDEX_ENTRY_FLAG_SUBNODE 0x01 // Index entry points to a sub-node
#define INDEX_ENTRY_FLAG_LAST 0x02 // Last index entry in the node, no Stream
typedef struct tagINDEX_ENTRY
{
ULONGLONG FileReference; // Low 6B: MFT record index, High 2B: MFT record sequence number
WORD Size; // Length of the index entry
WORD StreamSize; // Length of the stream
BYTE Flags; // Flags
BYTE Padding[3]; // Padding
BYTE Stream[1]; // Stream
// VCN of the sub node in Index Allocation, Offset = Size - 8
} INDEX_ENTRY;
// INDEX BLOCK
/******************************
INDEX_BLOCK
-----------------------
| Index Block Header |
-----------------------
| Index Header |
-----------------------
| Index Entry |
-----------------------
| Index Entry |
-----------------------
| ...... |
-----------------------
*******************************/
#define INDEX_BLOCK_MAGIC 'XDNI'
typedef struct tagINDEX_BLOCK
{
// Index Block Header
DWORD Magic; // "INDX"
WORD OffsetOfUS; // Offset of Update Sequence
WORD SizeOfUS; // Size in words of Update Sequence Number & Array
ULONGLONG LSN; // $LogFile Sequence Number
ULONGLONG VCN; // VCN of this index block in the index allocation
// Index Header
DWORD EntryOffset; // Offset of the index entries, relative to this address(0x18)
DWORD TotalEntrySize; // Total size of the index entries
DWORD AllocEntrySize; // Allocated size of index entries
BYTE NotLeaf; // 1 if not leaf node (has children)
BYTE Padding[3]; // Padding
} INDEX_BLOCK;
#endif
+979
View File
@@ -0,0 +1,979 @@
/*
* NTFS Volume and File Record Class
*
* Copyright(C) 2010 cyb70289 <cyb70289@gmail.com>
*/
#ifndef __NTFS_FILERECORD_H_CYB70289
#define __NTFS_FILERECORD_H_CYB70289
///////////////////////////////////////
// NTFS Volume forward declaration
///////////////////////////////////////
class CNTFSVolume
{
public:
CNTFSVolume(_TCHAR volume);
virtual ~CNTFSVolume();
friend class CFileRecord;
friend class CAttrBase;
private:
WORD SectorSize;
DWORD ClusterSize;
DWORD FileRecordSize;
DWORD IndexBlockSize;
ULONGLONG MFTAddr;
HANDLE hVolume;
BOOL VolumeOK;
ATTR_RAW_CALLBACK AttrRawCallBack[ATTR_NUMS];
WORD Version;
// MFT file records ($MFT file itself) may be fragmented
// Get $MFT Data attribute to translate FileRecord to correct disk offset
CFileRecord *MFTRecord; // $MFT File Record
const CAttrBase *MFTData; // $MFT Data Attribute
BOOL OpenVolume(_TCHAR volume);
public:
__inline BOOL IsVolumeOK() const;
__inline WORD GetVersion() const;
__inline ULONGLONG GetRecordsCount() const;
__inline DWORD GetSectorSize() const;
__inline DWORD GetClusterSize() const;
__inline DWORD GetFileRecordSize() const;
__inline DWORD GetIndexBlockSize() const;
__inline ULONGLONG GetMFTAddr() const;
BOOL InstallAttrRawCB(DWORD attrType, ATTR_RAW_CALLBACK cb);
__inline void ClearAttrRawCB();
}; // CNTFSVolume
////////////////////////////////////////////
// List to hold Attributes of the same type
////////////////////////////////////////////
typedef class CSList<CAttrBase> CAttrList;
// It seems VC6.0 doesn't support template class friends
#if _MSC_VER <= 1200
class CAttrResident;
class CAttrNonResident;
template <class TYPE_RESIDENT> class CAttr_AttrList;
#endif
////////////////////////////////
// Process a single File Record
////////////////////////////////
class CFileRecord
{
public:
CFileRecord(const CNTFSVolume *volume);
virtual ~CFileRecord();
friend class CAttrBase;
#if _MSC_VER <= 1200
// Walk around VC6.0 compiler defect
friend class CAttr_AttrList<CAttrResident>;
friend class CAttr_AttrList<CAttrNonResident>;
#else
template <class TYPE_RESIDENT> friend class CAttr_AttrList; // Won't compiler in VC6.0, why?
#endif
private:
const CNTFSVolume *Volume;
FILE_RECORD_HEADER *FileRecord;
ULONGLONG FileReference;
ATTR_RAW_CALLBACK AttrRawCallBack[ATTR_NUMS];
DWORD AttrMask;
CAttrList AttrList[ATTR_NUMS]; // Attributes
void ClearAttrs();
BOOL PatchUS(WORD *sector, int sectors, WORD usn, WORD *usarray);
__inline void UserCallBack(DWORD attType, ATTR_HEADER_COMMON *ahc, BOOL *bDiscard);
CAttrBase* AllocAttr(ATTR_HEADER_COMMON *ahc, BOOL *bUnhandled);
BOOL ParseAttr(ATTR_HEADER_COMMON *ahc);
FILE_RECORD_HEADER* ReadFileRecord(ULONGLONG &fileRef);
BOOL VisitIndexBlock(const ULONGLONG &vcn, const _TCHAR *fileName, CIndexEntry &ieFound) const;
void TraverseSubNode(const ULONGLONG &vcn, SUBENTRY_CALLBACK seCallBack) const;
public:
BOOL ParseFileRecord(ULONGLONG fileRef);
BOOL ParseAttrs();
BOOL InstallAttrRawCB(DWORD attrType, ATTR_RAW_CALLBACK cb);
__inline void ClearAttrRawCB();
__inline void SetAttrMask(DWORD mask);
void TraverseAttrs(ATTRS_CALLBACK attrCallBack, void *context);
__inline const CAttrBase* FindFirstAttr(DWORD attrType) const;
const CAttrBase* FindNextAttr(DWORD attrType) const;
int GetFileName(_TCHAR *buf, DWORD bufLen) const;
__inline ULONGLONG GetFileSize() const;
void GetFileTime(FILETIME *writeTm, FILETIME *createTm = NULL, FILETIME *accessTm = NULL) const;
void TraverseSubEntries(SUBENTRY_CALLBACK seCallBack) const;
__inline const BOOL FindSubEntry(const _TCHAR *fileName, CIndexEntry &ieFound) const;
const CAttrBase* FindStream(_TCHAR *name = NULL);
__inline BOOL IsDeleted() const;
__inline BOOL IsDirectory() const;
__inline BOOL IsReadOnly() const;
__inline BOOL IsHidden() const;
__inline BOOL IsSystem() const;
__inline BOOL IsCompressed() const;
__inline BOOL IsEncrypted() const;
__inline BOOL IsSparse() const;
}; // CFileRecord
#include "NTFS_Attribute.h"
CFileRecord::CFileRecord(const CNTFSVolume *volume)
{
_ASSERT(volume);
Volume = volume;
FileRecord = NULL;
FileReference = (ULONGLONG)-1;
ClearAttrRawCB();
// Default to parse all attributes
AttrMask = MASK_ALL;
}
CFileRecord::~CFileRecord()
{
ClearAttrs();
if (FileRecord)
delete FileRecord;
}
// Free all CAttr_xxx
void CFileRecord::ClearAttrs()
{
for (int i = 0; i<ATTR_NUMS; i++)
{
AttrList[i].RemoveAll();
}
}
// Verify US and update sectors
BOOL CFileRecord::PatchUS(WORD *sector, int sectors, WORD usn, WORD *usarray)
{
int i;
for (i = 0; i<sectors; i++)
{
sector += ((Volume->SectorSize >> 1) - 1);
if (*sector != usn)
return FALSE; // USN error
*sector = usarray[i]; // Write back correct data
sector++;
}
return TRUE;
}
// Call user defined Callback routines for an attribute
__inline void CFileRecord::UserCallBack(DWORD attType, ATTR_HEADER_COMMON *ahc, BOOL *bDiscard)
{
*bDiscard = FALSE;
if (AttrRawCallBack[attType])
AttrRawCallBack[attType](ahc, bDiscard);
else if (Volume->AttrRawCallBack[attType])
Volume->AttrRawCallBack[attType](ahc, bDiscard);
}
CAttrBase* CFileRecord::AllocAttr(ATTR_HEADER_COMMON *ahc, BOOL *bUnhandled)
{
switch (ahc->Type)
{
case ATTR_TYPE_STANDARD_INFORMATION:
return new CAttr_StdInfo(ahc, this);
case ATTR_TYPE_ATTRIBUTE_LIST:
if (ahc->NonResident)
return new CAttr_AttrList<CAttrNonResident>(ahc, this);
else
return new CAttr_AttrList<CAttrResident>(ahc, this);
case ATTR_TYPE_FILE_NAME:
return new CAttr_FileName(ahc, this);
case ATTR_TYPE_VOLUME_NAME:
return new CAttr_VolName(ahc, this);
case ATTR_TYPE_VOLUME_INFORMATION:
return new CAttr_VolInfo(ahc, this);
case ATTR_TYPE_DATA:
if (ahc->NonResident)
return new CAttr_Data<CAttrNonResident>(ahc, this);
else
return new CAttr_Data<CAttrResident>(ahc, this);
case ATTR_TYPE_INDEX_ROOT:
return new CAttr_IndexRoot(ahc, this);
case ATTR_TYPE_INDEX_ALLOCATION:
return new CAttr_IndexAlloc(ahc, this);
case ATTR_TYPE_BITMAP:
if (ahc->NonResident)
return new CAttr_Bitmap<CAttrNonResident>(ahc, this);
else
// Resident Bitmap may exist in a directory's FileRecord
// or in $MFT for a very small volume in theory
return new CAttr_Bitmap<CAttrResident>(ahc, this);
// Unhandled Attributes
default:
*bUnhandled = TRUE;
if (ahc->NonResident)
return new CAttrNonResident(ahc, this);
else
return new CAttrResident(ahc, this);
}
}
// Parse a single Attribute
// Return False on error
BOOL CFileRecord::ParseAttr(ATTR_HEADER_COMMON *ahc)
{
DWORD attrIndex = ATTR_INDEX(ahc->Type);
if (attrIndex < ATTR_NUMS)
{
BOOL bDiscard = FALSE;
UserCallBack(attrIndex, ahc, &bDiscard);
if (!bDiscard)
{
BOOL bUnhandled = FALSE;
CAttrBase *attr = AllocAttr(ahc, &bUnhandled);
if (attr)
{
if (bUnhandled)
{
NTFS_TRACE1("Unhandled attribute: 0x%04X\n", ahc->Type);
}
AttrList[attrIndex].InsertEntry(attr);
return TRUE;
}
else
{
NTFS_TRACE1("Attribute Parse error: 0x%04X\n", ahc->Type);
return FALSE;
}
}
else
{
NTFS_TRACE1("User Callback has processed this Attribute: 0x%04X\n", ahc->Type);
return TRUE;
}
}
else
{
NTFS_TRACE1("Invalid Attribute Type: 0x%04X\n", ahc->Type);
return FALSE;
}
}
// Read File Record
FILE_RECORD_HEADER* CFileRecord::ReadFileRecord(ULONGLONG &fileRef)
{
FILE_RECORD_HEADER *fr = NULL;
DWORD len;
if (fileRef < MFT_IDX_USER || Volume->MFTData == NULL)
{
// Take as continuous disk allocation
LARGE_INTEGER frAddr;
frAddr.QuadPart = Volume->MFTAddr + (Volume->FileRecordSize) * fileRef;
frAddr.LowPart = SetFilePointer(Volume->hVolume, frAddr.LowPart, &frAddr.HighPart, FILE_BEGIN);
if (frAddr.LowPart == DWORD(-1) && GetLastError() != NO_ERROR)
return FALSE;
else
{
fr = (FILE_RECORD_HEADER*)new BYTE[Volume->FileRecordSize];
if (ReadFile(Volume->hVolume, fr, Volume->FileRecordSize, &len, NULL)
&& len == Volume->FileRecordSize)
return fr;
else
{
delete fr;
return NULL;
}
}
}
else
{
// May be fragmented $MFT
ULONGLONG frAddr;
frAddr = (Volume->FileRecordSize) * fileRef;
fr = (FILE_RECORD_HEADER*)new BYTE[Volume->FileRecordSize];
if (Volume->MFTData->ReadData(frAddr, fr, Volume->FileRecordSize, &len)
&& len == Volume->FileRecordSize)
return fr;
else
{
delete fr;
return NULL;
}
}
}
// Read File Record, verify and patch the US (update sequence)
BOOL CFileRecord::ParseFileRecord(ULONGLONG fileRef)
{
// Clear previous data
ClearAttrs();
if (FileRecord)
{
delete FileRecord;
FileRecord = NULL;
}
FILE_RECORD_HEADER *fr = ReadFileRecord(fileRef);
if (fr == NULL)
{
NTFS_TRACE1("Cannot read file record %I64u\n", fileRef);
FileReference = (ULONGLONG)-1;
}
else
{
FileReference = fileRef;
if (fr->Magic == FILE_RECORD_MAGIC)
{
// Patch US
WORD *usnaddr = (WORD*)((BYTE*)fr + fr->OffsetOfUS);
WORD usn = *usnaddr;
WORD *usarray = usnaddr + 1;
if (PatchUS((WORD*)fr, Volume->FileRecordSize / Volume->SectorSize, usn, usarray))
{
NTFS_TRACE1("File Record %I64u Found\n", fileRef);
FileRecord = fr;
return TRUE;
}
else
{
NTFS_TRACE("Update Sequence Number error\n");
}
}
else
{
NTFS_TRACE("Invalid file record\n");
}
delete fr;
}
return FALSE;
}
// Visit IndexBlocks recursivly to find a specific FileName
BOOL CFileRecord::VisitIndexBlock(const ULONGLONG &vcn, const _TCHAR *fileName, CIndexEntry &ieFound) const
{
CAttr_IndexAlloc *ia = (CAttr_IndexAlloc*)FindFirstAttr(ATTR_TYPE_INDEX_ALLOCATION);
if (ia == NULL)
return FALSE;
CIndexBlock ib;
if (ia->ParseIndexBlock(vcn, ib))
{
CIndexEntry *ie = ib.FindFirstEntry();
while (ie)
{
if (ie->HasName())
{
// Compare name
int i = ie->Compare(fileName);
if (i == 0)
{
ieFound = *ie;
return TRUE;
}
else if (i < 0) // fileName is smaller than IndexEntry
{
// Visit SubNode
if (ie->IsSubNodePtr())
{
// Search in SubNode (IndexBlock), recursive call
if (VisitIndexBlock(ie->GetSubNodeVCN(), fileName, ieFound))
return TRUE;
}
else
return FALSE; // not found
}
// Just step forward if fileName is bigger than IndexEntry
}
else if (ie->IsSubNodePtr())
{
// Search in SubNode (IndexBlock), recursive call
if (VisitIndexBlock(ie->GetSubNodeVCN(), fileName, ieFound))
return TRUE;
}
ie = ib.FindNextEntry();
}
}
return FALSE;
}
// Traverse SubNode recursivly in ascending order
// Call user defined callback routine once found an subentry
void CFileRecord::TraverseSubNode(const ULONGLONG &vcn, SUBENTRY_CALLBACK seCallBack) const
{
CAttr_IndexAlloc *ia = (CAttr_IndexAlloc*)FindFirstAttr(ATTR_TYPE_INDEX_ALLOCATION);
if (ia == NULL)
return;
CIndexBlock ib;
if (ia->ParseIndexBlock(vcn, ib))
{
CIndexEntry *ie = ib.FindFirstEntry();
while (ie)
{
if (ie->IsSubNodePtr())
TraverseSubNode(ie->GetSubNodeVCN(), seCallBack); // recursive call
if (ie->HasName())
seCallBack(ie);
ie = ib.FindNextEntry();
}
}
}
// Parse all the attributes in a File Record
// And insert them into a link list
BOOL CFileRecord::ParseAttrs()
{
_ASSERT(FileRecord);
// Clear previous data
ClearAttrs();
// Visit all attributes
DWORD dataPtr = 0; // guard if data exceeds FileRecordSize bounds
ATTR_HEADER_COMMON *ahc = (ATTR_HEADER_COMMON*)((BYTE*)FileRecord + FileRecord->OffsetOfAttr);
dataPtr += FileRecord->OffsetOfAttr;
while (ahc->Type != (DWORD)-1 && (dataPtr + ahc->TotalSize) <= Volume->FileRecordSize)
{
if (ATTR_MASK(ahc->Type) & AttrMask) // Skip unwanted attributes
{
if (!ParseAttr(ahc)) // Parse error
return FALSE;
if (IsEncrypted() || IsCompressed())
{
NTFS_TRACE("Compressed and Encrypted file not supported yet !\n");
return FALSE;
}
}
dataPtr += ahc->TotalSize;
ahc = (ATTR_HEADER_COMMON*)((BYTE*)ahc + ahc->TotalSize); // next attribute
}
return TRUE;
}
// Install Attribute raw data CallBack routines for a single File Record
BOOL CFileRecord::InstallAttrRawCB(DWORD attrType, ATTR_RAW_CALLBACK cb)
{
DWORD atIdx = ATTR_INDEX(attrType);
if (atIdx < ATTR_NUMS)
{
AttrRawCallBack[atIdx] = cb;
return TRUE;
}
else
return FALSE;
}
// Clear all Attribute CallBack routines
__inline void CFileRecord::ClearAttrRawCB()
{
for (int i = 0; i < ATTR_NUMS; i++)
AttrRawCallBack[i] = NULL;
}
// Choose attributes to handle, unwanted attributes will be discarded silently
__inline void CFileRecord::SetAttrMask(DWORD mask)
{
// Standard Information and Attribute List is needed always
AttrMask = mask | MASK_STANDARD_INFORMATION | MASK_ATTRIBUTE_LIST;
}
// Traverse all Attribute and return CAttr_xxx classes to User Callback routine
void CFileRecord::TraverseAttrs(ATTRS_CALLBACK attrCallBack, void *context)
{
_ASSERT(attrCallBack);
for (int i = 0; i < ATTR_NUMS; i++)
{
if (AttrMask & (((DWORD)1) << i)) // skip masked attributes
{
const CAttrBase *ab = AttrList[i].FindFirstEntry();
while (ab)
{
BOOL bStop;
bStop = FALSE;
attrCallBack(ab, context, &bStop);
if (bStop)
return;
ab = AttrList[i].FindNextEntry();
}
}
}
}
// Find Attributes
__inline const CAttrBase* CFileRecord::FindFirstAttr(DWORD attrType) const
{
DWORD attrIdx = ATTR_INDEX(attrType);
return attrIdx < ATTR_NUMS ? AttrList[attrIdx].FindFirstEntry() : NULL;
}
const CAttrBase* CFileRecord::FindNextAttr(DWORD attrType) const
{
DWORD attrIdx = ATTR_INDEX(attrType);
return attrIdx < ATTR_NUMS ? AttrList[attrIdx].FindNextEntry() : NULL;
}
// Get File Name (First Win32 name)
int CFileRecord::GetFileName(_TCHAR *buf, DWORD bufLen) const
{
// A file may have several filenames
// Return the first Win32 filename
CAttr_FileName *fn = (CAttr_FileName*)AttrList[ATTR_INDEX(ATTR_TYPE_FILE_NAME)].FindFirstEntry();
while (fn)
{
if (fn->IsWin32Name())
{
int len = fn->GetFileName(buf, bufLen);
if (len != 0)
return len; // success or fail
}
fn = (CAttr_FileName*)AttrList[ATTR_INDEX(ATTR_TYPE_FILE_NAME)].FindNextEntry();
}
return 0;
}
// Get File Size
__inline ULONGLONG CFileRecord::GetFileSize() const
{
CAttr_FileName *fn = (CAttr_FileName*)AttrList[ATTR_INDEX(ATTR_TYPE_FILE_NAME)].FindFirstEntry();
return fn ? fn->GetFileSize() : 0;
}
// Get File Times
void CFileRecord::GetFileTime(FILETIME *writeTm, FILETIME *createTm, FILETIME *accessTm) const
{
// Standard Information attribute hold the most updated file time
CAttr_StdInfo *si = (CAttr_StdInfo*)AttrList[ATTR_INDEX(ATTR_TYPE_STANDARD_INFORMATION)].FindFirstEntry();
if (si)
si->GetFileTime(writeTm, createTm, accessTm);
else
{
writeTm->dwHighDateTime = 0;
writeTm->dwLowDateTime = 0;
if (createTm)
{
createTm->dwHighDateTime = 0;
createTm->dwLowDateTime = 0;
}
if (accessTm)
{
accessTm->dwHighDateTime = 0;
accessTm->dwLowDateTime = 0;
}
}
}
// Traverse all sub directories and files contained
// Call user defined callback routine once found an entry
void CFileRecord::TraverseSubEntries(SUBENTRY_CALLBACK seCallBack) const
{
_ASSERT(seCallBack);
// Start traversing from IndexRoot (B+ tree root node)
CAttr_IndexRoot* ir = (CAttr_IndexRoot*)FindFirstAttr(ATTR_TYPE_INDEX_ROOT);
if (ir == NULL || !ir->IsFileName())
return;
CIndexEntryList *ieList = (CIndexEntryList*)ir;
CIndexEntry *ie = ieList->FindFirstEntry();
while (ie)
{
// Visit subnode first
if (ie->IsSubNodePtr())
TraverseSubNode(ie->GetSubNodeVCN(), seCallBack);
if (ie->HasName())
seCallBack(ie);
ie = ieList->FindNextEntry();
}
}
// Find a specific FileName from InexRoot described B+ tree
__inline const BOOL CFileRecord::FindSubEntry(const _TCHAR *fileName, CIndexEntry &ieFound) const
{
// Start searching from IndexRoot (B+ tree root node)
CAttr_IndexRoot *ir = (CAttr_IndexRoot*)FindFirstAttr(ATTR_TYPE_INDEX_ROOT);
if (ir == NULL || !ir->IsFileName())
return FALSE;
CIndexEntryList *ieList = (CIndexEntryList*)ir;
CIndexEntry *ie = ieList->FindFirstEntry();
while (ie)
{
if (ie->HasName())
{
// Compare name
int i = ie->Compare(fileName);
if (i == 0)
{
ieFound = *ie;
return TRUE;
}
else if (i < 0) // fileName is smaller than IndexEntry
{
// Visit SubNode
if (ie->IsSubNodePtr())
{
// Search in SubNode (IndexBlock)
if (VisitIndexBlock(ie->GetSubNodeVCN(), fileName, ieFound))
return TRUE;
}
else
return FALSE; // not found
}
// Just step forward if fileName is bigger than IndexEntry
}
else if (ie->IsSubNodePtr())
{
// Search in SubNode (IndexBlock)
if (VisitIndexBlock(ie->GetSubNodeVCN(), fileName, ieFound))
return TRUE;
}
ie = ieList->FindNextEntry();
}
return FALSE;
}
// Find Data attribute class of
const CAttrBase* CFileRecord::FindStream(_TCHAR *name)
{
const CAttrBase *data = FindFirstAttr(ATTR_TYPE_DATA);
while (data)
{
if (data->IsUnNamed() && name == NULL) // Unnamed stream
break;
if ((!data->IsUnNamed()) && name) // Named stream
{
_TCHAR an[MAX_PATH];
if (data->GetAttrName(an, MAX_PATH))
{
if (_tcscmp(an, name) == 0)
break;
}
}
data = FindNextAttr(ATTR_TYPE_DATA);
}
return data;
}
// Check if it's deleted or in use
__inline BOOL CFileRecord::IsDeleted() const
{
return !(FileRecord->Flags & FILE_RECORD_FLAG_INUSE);
}
// Check if it's a directory
__inline BOOL CFileRecord::IsDirectory() const
{
return FileRecord->Flags & FILE_RECORD_FLAG_DIR;
}
__inline BOOL CFileRecord::IsReadOnly() const
{
// Standard Information attribute holds the most updated file time
const CAttr_StdInfo *si = (CAttr_StdInfo*)AttrList[ATTR_INDEX(ATTR_TYPE_STANDARD_INFORMATION)].FindFirstEntry();
return si ? si->IsReadOnly() : FALSE;
}
__inline BOOL CFileRecord::IsHidden() const
{
const CAttr_StdInfo *si = (CAttr_StdInfo*)AttrList[ATTR_INDEX(ATTR_TYPE_STANDARD_INFORMATION)].FindFirstEntry();
return si ? si->IsHidden() : FALSE;
}
__inline BOOL CFileRecord::IsSystem() const
{
const CAttr_StdInfo *si = (CAttr_StdInfo*)AttrList[ATTR_INDEX(ATTR_TYPE_STANDARD_INFORMATION)].FindFirstEntry();
return si ? si->IsSystem() : FALSE;
}
__inline BOOL CFileRecord::IsCompressed() const
{
const CAttr_StdInfo *si = (CAttr_StdInfo*)AttrList[ATTR_INDEX(ATTR_TYPE_STANDARD_INFORMATION)].FindFirstEntry();
return si ? si->IsCompressed() : FALSE;
}
__inline BOOL CFileRecord::IsEncrypted() const
{
const CAttr_StdInfo *si = (CAttr_StdInfo*)AttrList[ATTR_INDEX(ATTR_TYPE_STANDARD_INFORMATION)].FindFirstEntry();
return si ? si->IsEncrypted() : FALSE;
}
__inline BOOL CFileRecord::IsSparse() const
{
const CAttr_StdInfo *si = (CAttr_StdInfo*)AttrList[ATTR_INDEX(ATTR_TYPE_STANDARD_INFORMATION)].FindFirstEntry();
return si ? si->IsSparse() : FALSE;
}
///////////////////////////////////////
// NTFS Volume Implementation
///////////////////////////////////////
CNTFSVolume::CNTFSVolume(_TCHAR volume)
{
hVolume = INVALID_HANDLE_VALUE;
VolumeOK = FALSE;
MFTRecord = NULL;
MFTData = NULL;
Version = 0;
ClearAttrRawCB();
if (!OpenVolume(volume))
return;
// Verify NTFS volume version (must >= 3.0)
CFileRecord vol(this);
vol.SetAttrMask(MASK_VOLUME_NAME | MASK_VOLUME_INFORMATION);
if (!vol.ParseFileRecord(MFT_IDX_VOLUME))
return;
vol.ParseAttrs();
CAttr_VolInfo *vi = (CAttr_VolInfo*)vol.FindFirstAttr(ATTR_TYPE_VOLUME_INFORMATION);
if (!vi)
return;
Version = vi->GetVersion();
NTFS_TRACE2("NTFS volume version: %u.%u\n", HIBYTE(Version), LOBYTE(Version));
if (Version < 0x0300) // NT4 ?
return;
#ifdef _DEBUG
CAttr_VolName *vn = (CAttr_VolName*)vol.FindFirstAttr(ATTR_TYPE_VOLUME_NAME);
if (vn)
{
char volname[MAX_PATH];
if (vn->GetName(volname, MAX_PATH) > 0)
{
NTFS_TRACE1("NTFS volume name: %s\n", volname);
}
}
#endif
VolumeOK = TRUE;
MFTRecord = new CFileRecord(this);
MFTRecord->SetAttrMask(MASK_DATA);
if (MFTRecord->ParseFileRecord(MFT_IDX_MFT))
{
MFTRecord->ParseAttrs();
MFTData = MFTRecord->FindFirstAttr(ATTR_TYPE_DATA);
if (MFTData == NULL)
{
delete MFTRecord;
MFTRecord = NULL;
}
}
}
CNTFSVolume::~CNTFSVolume()
{
if (hVolume != INVALID_HANDLE_VALUE)
CloseHandle(hVolume);
if (MFTRecord)
delete MFTRecord;
}
// Open a volume ('a' - 'z', 'A' - 'Z'), get volume handle and BPB
BOOL CNTFSVolume::OpenVolume(_TCHAR volume)
{
// Verify parameter
if (!_istalpha(volume))
{
NTFS_TRACE("Volume name error, should be like 'C', 'D'\n");
return FALSE;
}
_TCHAR volumePath[7];
_sntprintf(volumePath, 6, _T("\\\\.\\%c:"), volume);
volumePath[6] = _T('\0');
hVolume = CreateFile(volumePath, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, NULL);
if (hVolume != INVALID_HANDLE_VALUE)
{
DWORD num;
NTFS_BPB bpb;
// Read the first sector (boot sector)
if (ReadFile(hVolume, &bpb, 512, &num, NULL) && num == 512)
{
if (strncmp((const char*)bpb.Signature, NTFS_SIGNATURE, 8) == 0)
{
// Log important volume parameters
SectorSize = bpb.BytesPerSector;
NTFS_TRACE1("Sector Size = %u bytes\n", SectorSize);
ClusterSize = SectorSize * bpb.SectorsPerCluster;
NTFS_TRACE1("Cluster Size = %u bytes\n", ClusterSize);
int sz = (char)bpb.ClustersPerFileRecord;
if (sz > 0)
FileRecordSize = ClusterSize * sz;
else
FileRecordSize = 1 << (-sz);
NTFS_TRACE1("FileRecord Size = %u bytes\n", FileRecordSize);
sz = (char)bpb.ClustersPerIndexBlock;
if (sz > 0)
IndexBlockSize = ClusterSize * sz;
else
IndexBlockSize = 1 << (-sz);
NTFS_TRACE1("IndexBlock Size = %u bytes\n", IndexBlockSize);
MFTAddr = bpb.LCN_MFT * ClusterSize;
NTFS_TRACE1("MFT address = 0x%016I64X\n", MFTAddr);
}
else
{
NTFS_TRACE("Volume file system is not NTFS\n");
goto IOError;
}
}
else
{
NTFS_TRACE("Read boot sector error\n");
goto IOError;
}
}
else
{
NTFS_TRACE1("Cannnot open volume %c\n", (char)volume);
IOError:
if (hVolume != INVALID_HANDLE_VALUE)
{
CloseHandle(hVolume);
hVolume = INVALID_HANDLE_VALUE;
}
return FALSE;
}
return TRUE;
}
// Check if Volume is successfully opened
__inline BOOL CNTFSVolume::IsVolumeOK() const
{
return VolumeOK;
}
// Get NTFS volume version
__inline WORD CNTFSVolume::GetVersion() const
{
return Version;
}
// Get File Record count
__inline ULONGLONG CNTFSVolume::GetRecordsCount() const
{
return (MFTData->GetDataSize() / FileRecordSize);
}
// Get BPB information
__inline DWORD CNTFSVolume::GetSectorSize() const
{
return SectorSize;
}
__inline DWORD CNTFSVolume::GetClusterSize() const
{
return ClusterSize;
}
__inline DWORD CNTFSVolume::GetFileRecordSize() const
{
return FileRecordSize;
}
__inline DWORD CNTFSVolume::GetIndexBlockSize() const
{
return IndexBlockSize;
}
// Get MFT starting address
__inline ULONGLONG CNTFSVolume::GetMFTAddr() const
{
return MFTAddr;
}
// Install Attribute CallBack routines for the whole Volume
BOOL CNTFSVolume::InstallAttrRawCB(DWORD attrType, ATTR_RAW_CALLBACK cb)
{
DWORD atIdx = ATTR_INDEX(attrType);
if (atIdx < ATTR_NUMS)
{
AttrRawCallBack[atIdx] = cb;
return TRUE;
}
else
return FALSE;
}
// Clear all Attribute CallBack routines
__inline void CNTFSVolume::ClearAttrRawCB()
{
for (int i = 0; i < ATTR_NUMS; i++)
AttrRawCallBack[i] = NULL;
}
#endif
Binary file not shown.
+160
View File
@@ -0,0 +1,160 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{9622A76B-A2B2-4E45-B38B-1EBD2A0DDAEF}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>ntfsDump</RootNamespace>
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>
</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>
</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="NTFS.h" />
<ClInclude Include="NTFS_Attribute.h" />
<ClInclude Include="NTFS_Common.h" />
<ClInclude Include="NTFS_DataType.h" />
<ClInclude Include="NTFS_FileRecord.h" />
<ClInclude Include="stdafx.h" />
<ClInclude Include="targetver.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="ntfsDump.cpp" />
<ClCompile Include="stdafx.cpp" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
Binary file not shown.
Binary file not shown.
Binary file not shown.