Beispiel #1
0
 /// <summary>
 /// Adds an existing attribute.
 /// </summary>
 /// <param name="attrRec">The attribute to add</param>
 /// <returns>The new Id of the attribute</returns>
 /// <remarks>This method is used to move an attribute between different MFT records</remarks>
 public ushort AddAttribute(AttributeRecord attrRec)
 {
     attrRec.AttributeId = _nextAttributeId++;
     _attributes.Add(attrRec);
     _attributes.Sort();
     return(attrRec.AttributeId);
 }
Beispiel #2
0
        protected override void Read(byte[] buffer, int offset)
        {
            _logFileSequenceNumber = Utilities.ToUInt64LittleEndian(buffer, offset + 0x08);
            _sequenceNumber        = Utilities.ToUInt16LittleEndian(buffer, offset + 0x10);
            _hardLinkCount         = Utilities.ToUInt16LittleEndian(buffer, offset + 0x12);
            _firstAttributeOffset  = Utilities.ToUInt16LittleEndian(buffer, offset + 0x14);
            _flags               = (FileRecordFlags)Utilities.ToUInt16LittleEndian(buffer, offset + 0x16);
            _recordRealSize      = Utilities.ToUInt32LittleEndian(buffer, offset + 0x18);
            _recordAllocatedSize = Utilities.ToUInt32LittleEndian(buffer, offset + 0x1C);
            _baseFile            = new FileRecordReference(Utilities.ToUInt64LittleEndian(buffer, offset + 0x20));
            _nextAttributeId     = Utilities.ToUInt16LittleEndian(buffer, offset + 0x28);

            if (UpdateSequenceOffset >= 0x30)
            {
                _index     = Utilities.ToUInt32LittleEndian(buffer, offset + 0x2C);
                _haveIndex = true;
            }

            _attributes = new List <AttributeRecord>();
            int focus = _firstAttributeOffset;

            while (true)
            {
                int             length;
                AttributeRecord attr = AttributeRecord.FromBytes(buffer, focus, out length);
                if (attr == null)
                {
                    break;
                }

                _attributes.Add(attr);
                focus += (int)length;
            }
        }
Beispiel #3
0
 public void SetExtent(FileRecordReference containingFile, AttributeRecord record)
 {
     _cachedRawBuffer = null;
     _containingFile  = containingFile;
     _primaryRecord   = record;
     _extents.Clear();
     _extents.Add(new AttributeReference(containingFile, record.AttributeId), record);
 }
Beispiel #4
0
 protected NtfsAttribute(File file, FileRecordReference containingFile, AttributeRecord record)
 {
     _file           = file;
     _containingFile = containingFile;
     _primaryRecord  = record;
     _extents        = new Dictionary <AttributeReference, AttributeRecord>();
     _extents.Add(new AttributeReference(containingFile, record.AttributeId), _primaryRecord);
 }
Beispiel #5
0
        /// <summary>
        /// Creates a new attribute at a fixed cluster.
        /// </summary>
        /// <param name="type">The type of the new attribute</param>
        /// <param name="name">The name of the new attribute</param>
        /// <param name="flags">The flags of the new attribute</param>
        /// <param name="firstCluster">The first cluster to assign to the attribute</param>
        /// <param name="numClusters">The number of sequential clusters to assign to the attribute</param>
        /// <param name="bytesPerCluster">The number of bytes in each cluster</param>
        /// <returns>The new attribute</returns>
        private NtfsAttribute CreateAttribute(AttributeType type, string name, AttributeFlags flags, long firstCluster, ulong numClusters, uint bytesPerCluster)
        {
            bool   indexed = _context.AttributeDefinitions.IsIndexed(type);
            ushort id      = _records[0].CreateNonResidentAttribute(type, name, flags, firstCluster, numClusters, bytesPerCluster);

            AttributeRecord newAttrRecord = _records[0].GetAttribute(id);
            NtfsAttribute   newAttr       = NtfsAttribute.FromRecord(this, MftReference, newAttrRecord);

            _attributes.Add(newAttr);
            UpdateAttributeList();
            MarkMftRecordDirty();
            return(newAttr);
        }
Beispiel #6
0
        /// <summary>
        /// Creates a new attribute.
        /// </summary>
        /// <param name="type">The type of the new attribute</param>
        /// <param name="name">The name of the new attribute</param>
        /// <param name="flags">The flags of the new attribute</param>
        /// <returns>The new attribute</returns>
        private NtfsAttribute CreateAttribute(AttributeType type, string name, AttributeFlags flags)
        {
            bool   indexed = _context.AttributeDefinitions.IsIndexed(type);
            ushort id      = _records[0].CreateAttribute(type, name, indexed, flags);

            AttributeRecord newAttrRecord = _records[0].GetAttribute(id);
            NtfsAttribute   newAttr       = NtfsAttribute.FromRecord(this, MftReference, newAttrRecord);

            _attributes.Add(newAttr);
            UpdateAttributeList();

            MarkMftRecordDirty();

            return(newAttr);
        }
Beispiel #7
0
        private void MoveAttribute(FileRecord record, AttributeRecord attrRec, FileRecord targetRecord)
        {
            AttributeReference oldRef = new AttributeReference(record.Reference, attrRec.AttributeId);

            record.RemoveAttribute(attrRec.AttributeId);
            targetRecord.AddAttribute(attrRec);

            AttributeReference newRef = new AttributeReference(targetRecord.Reference, attrRec.AttributeId);

            foreach (var attr in _attributes)
            {
                attr.ReplaceExtent(oldRef, newRef, attrRec);
            }

            UpdateAttributeList();
        }
Beispiel #8
0
        private bool ExpelAttribute(FileRecord record)
        {
            if (record.MasterFileTableIndex == MasterFileTable.MftIndex)
            {
                // Special case for MFT - can't fully expel attributes, instead split most of the data runs off.
                List <AttributeRecord> attrs = record.Attributes;
                for (int i = attrs.Count - 1; i >= 0; --i)
                {
                    AttributeRecord attr = attrs[i];
                    if (attr.AttributeType == AttributeType.Data)
                    {
                        if (SplitAttribute(record, (NonResidentAttributeRecord)attr, true))
                        {
                            return(true);
                        }
                    }
                }
            }
            else
            {
                List <AttributeRecord> attrs = record.Attributes;
                for (int i = attrs.Count - 1; i >= 0; --i)
                {
                    AttributeRecord attr = attrs[i];
                    if (attr.AttributeType > AttributeType.AttributeList)
                    {
                        foreach (var targetRecord in _records)
                        {
                            if (_mft.RecordSize - targetRecord.Size >= attr.Size)
                            {
                                MoveAttribute(record, attr, targetRecord);
                                return(true);
                            }
                        }

                        FileRecord newFileRecord = _mft.AllocateRecord(FileRecordFlags.None, record.IsMftRecord);
                        newFileRecord.BaseFile = record.Reference;
                        _records.Add(newFileRecord);
                        MoveAttribute(record, attr, newFileRecord);
                        return(true);
                    }
                }
            }

            return(false);
        }
Beispiel #9
0
        public static AttributeListRecord FromAttribute(AttributeRecord attr, FileRecordReference mftRecord)
        {
            AttributeListRecord newRecord = new AttributeListRecord()
            {
                Type              = attr.AttributeType,
                Name              = attr.Name,
                StartVcn          = 0,
                BaseFileReference = mftRecord,
                AttributeId       = attr.AttributeId
            };

            if (attr.IsNonResident)
            {
                newRecord.StartVcn = (ulong)((NonResidentAttributeRecord)attr).StartVcn;
            }

            return(newRecord);
        }
Beispiel #10
0
        public bool ReplaceExtent(AttributeReference oldRef, AttributeReference newRef, AttributeRecord record)
        {
            _cachedRawBuffer = null;

            if (!_extents.Remove(oldRef))
            {
                return(false);
            }
            else
            {
                if (oldRef.Equals(Reference) || _extents.Count == 0)
                {
                    _primaryRecord  = record;
                    _containingFile = newRef.File;
                }

                _extents.Add(newRef, record);
                return(true);
            }
        }
Beispiel #11
0
        internal void MakeAttributeNonResident(AttributeReference attrRef, int maxData)
        {
            NtfsAttribute attr = GetAttribute(attrRef);

            if (attr.IsNonResident)
            {
                throw new InvalidOperationException("Attribute is already non-resident");
            }

            ushort          id            = _records[0].CreateNonResidentAttribute(attr.Type, attr.Name, attr.Flags);
            AttributeRecord newAttrRecord = _records[0].GetAttribute(id);

            IBuffer attrBuffer = attr.GetDataBuffer();

            byte[] tempData = Utilities.ReadFully(attrBuffer, 0, (int)Math.Min(maxData, attrBuffer.Capacity));

            RemoveAttributeExtents(attr);
            attr.SetExtent(_records[0].Reference, newAttrRecord);

            attr.GetDataBuffer().Write(0, tempData, 0, tempData.Length);

            UpdateAttributeList();
        }
Beispiel #12
0
        public static NtfsAttribute FromRecord(File file, FileRecordReference recordFile, AttributeRecord record)
        {
            switch (record.AttributeType)
            {
            case AttributeType.StandardInformation:
                return(new StructuredNtfsAttribute <StandardInformation>(file, recordFile, record));

            case AttributeType.FileName:
                return(new StructuredNtfsAttribute <FileNameRecord>(file, recordFile, record));

            case AttributeType.SecurityDescriptor:
                return(new StructuredNtfsAttribute <SecurityDescriptor>(file, recordFile, record));

            case AttributeType.Data:
                return(new NtfsAttribute(file, recordFile, record));

            case AttributeType.Bitmap:
                return(new NtfsAttribute(file, recordFile, record));

            case AttributeType.VolumeName:
                return(new StructuredNtfsAttribute <VolumeName>(file, recordFile, record));

            case AttributeType.VolumeInformation:
                return(new StructuredNtfsAttribute <VolumeInformation>(file, recordFile, record));

            case AttributeType.IndexRoot:
                return(new NtfsAttribute(file, recordFile, record));

            case AttributeType.IndexAllocation:
                return(new NtfsAttribute(file, recordFile, record));

            case AttributeType.ObjectId:
                return(new StructuredNtfsAttribute <ObjectId>(file, recordFile, record));

            case AttributeType.ReparsePoint:
                return(new StructuredNtfsAttribute <ReparsePointRecord>(file, recordFile, record));

            case AttributeType.AttributeList:
                return(new StructuredNtfsAttribute <AttributeList>(file, recordFile, record));

            default:
                return(new NtfsAttribute(file, recordFile, record));
            }
        }
Beispiel #13
0
        private bool VerifyMftRecord(byte[] recordData, bool presentInBitmap, int bytesPerSector)
        {
            bool ok = true;

            //
            // Verify the attributes seem OK...
            //
            byte[] tempBuffer = new byte[recordData.Length];
            Array.Copy(recordData, tempBuffer, tempBuffer.Length);
            GenericFixupRecord genericRecord = new GenericFixupRecord(bytesPerSector);

            genericRecord.FromBytes(tempBuffer, 0);

            int pos = Utilities.ToUInt16LittleEndian(genericRecord.Content, 0x14);

            while (Utilities.ToUInt32LittleEndian(genericRecord.Content, pos) != 0xFFFFFFFF)
            {
                int attrLen;
                try
                {
                    AttributeRecord ar = AttributeRecord.FromBytes(genericRecord.Content, pos, out attrLen);
                    if (attrLen != ar.Size)
                    {
                        ReportError("Attribute size is different to calculated size.  AttrId={0}", ar.AttributeId);
                        ok = false;
                    }

                    if (ar.IsNonResident)
                    {
                        NonResidentAttributeRecord nrr = (NonResidentAttributeRecord)ar;
                        if (nrr.DataRuns.Count > 0)
                        {
                            long totalVcn = 0;
                            foreach (var run in nrr.DataRuns)
                            {
                                totalVcn += run.RunLength;
                            }

                            if (totalVcn != nrr.LastVcn - nrr.StartVcn + 1)
                            {
                                ReportError("Declared VCNs doesn't match data runs.  AttrId={0}", ar.AttributeId);
                                ok = false;
                            }
                        }
                    }
                }
                catch
                {
                    ReportError("Failure parsing attribute at pos={0}", pos);
                    return(false);
                }

                pos += attrLen;
            }

            //
            // Now consider record as a whole
            //
            FileRecord record = new FileRecord(bytesPerSector);

            record.FromBytes(recordData, 0);

            bool inUse = (record.Flags & FileRecordFlags.InUse) != 0;

            if (inUse != presentInBitmap)
            {
                ReportError("MFT bitmap and record in-use flag don't agree.  Mft={0}, Record={1}", presentInBitmap ? "InUse" : "Free", inUse ? "InUse" : "Free");
                ok = false;
            }

            if (record.Size != record.RealSize)
            {
                ReportError("MFT record real size is different to calculated size.  Stored in MFT={0}, Calculated={1}", record.RealSize, record.Size);
                ok = false;
            }

            if (Utilities.ToUInt32LittleEndian(recordData, (int)record.RealSize - 8) != uint.MaxValue)
            {
                ReportError("MFT record is not correctly terminated with 0xFFFFFFFF");
                ok = false;
            }

            return(ok);
        }
Beispiel #14
0
        private bool SplitAttribute(FileRecord record, NonResidentAttributeRecord targetAttr, bool atStart)
        {
            if (targetAttr.DataRuns.Count <= 1)
            {
                return(false);
            }

            int splitIndex = 1;

            if (!atStart)
            {
                // Approximation only - assumes each run is at least one byte saved.  Could calculate the
                // actual index here.
                splitIndex = (int)(targetAttr.DataRuns.Count - (record.Size - record.AllocatedSize));
            }

            AttributeRecord newAttr = targetAttr.Split(splitIndex);

            // Find a home for the new attribute record
            FileRecord newAttrHome = null;

            foreach (var targetRecord in _records)
            {
                if (!targetRecord.IsMftRecord && _mft.RecordSize - targetRecord.Size >= newAttr.Size)
                {
                    targetRecord.AddAttribute(newAttr);
                    newAttrHome = targetRecord;
                }
            }

            if (newAttrHome == null)
            {
                newAttrHome          = _mft.AllocateRecord(_records[0].Flags & (~FileRecordFlags.InUse), record.IsMftRecord);
                newAttrHome.BaseFile = record.BaseFile.IsNull ? record.Reference : record.BaseFile;
                _records.Add(newAttrHome);
                newAttrHome.AddAttribute(newAttr);
            }

            // Add the new attribute record as an extent on the attribute it split from
            bool added = false;

            foreach (var attr in _attributes)
            {
                foreach (var existingRecord in attr.Extents)
                {
                    if (existingRecord.Key.File == record.Reference && existingRecord.Key.AttributeId == targetAttr.AttributeId)
                    {
                        attr.AddExtent(newAttrHome.Reference, newAttr);
                        added = true;
                        break;
                    }
                }

                if (added)
                {
                    break;
                }
            }

            UpdateAttributeList();

            return(true);
        }
Beispiel #15
0
        private void LoadAttributes()
        {
            Dictionary <long, FileRecord> extraFileRecords = new Dictionary <long, FileRecord>();

            AttributeRecord attrListRec = _records[0].GetAttribute(AttributeType.AttributeList);

            if (attrListRec != null)
            {
                NtfsAttribute lastAttr = null;

                StructuredNtfsAttribute <AttributeList> attrListAttr = (StructuredNtfsAttribute <AttributeList>)NtfsAttribute.FromRecord(this, MftReference, attrListRec);
                var attrList = attrListAttr.Content;
                _attributes.Add(attrListAttr);

                foreach (var record in attrList)
                {
                    FileRecord attrFileRecord = _records[0];
                    if (record.BaseFileReference.MftIndex != _records[0].MasterFileTableIndex)
                    {
                        if (!extraFileRecords.TryGetValue(record.BaseFileReference.MftIndex, out attrFileRecord))
                        {
                            attrFileRecord = _context.Mft.GetRecord(record.BaseFileReference);
                            if (attrFileRecord != null)
                            {
                                extraFileRecords[attrFileRecord.MasterFileTableIndex] = attrFileRecord;
                            }
                        }
                    }

                    if (attrFileRecord != null)
                    {
                        AttributeRecord attrRec = attrFileRecord.GetAttribute(record.AttributeId);

                        if (attrRec != null)
                        {
                            if (record.StartVcn == 0)
                            {
                                lastAttr = NtfsAttribute.FromRecord(this, record.BaseFileReference, attrRec);
                                _attributes.Add(lastAttr);
                            }
                            else
                            {
                                lastAttr.AddExtent(record.BaseFileReference, attrRec);
                            }
                        }
                    }
                }

                foreach (var extraFileRecord in extraFileRecords)
                {
                    _records.Add(extraFileRecord.Value);
                }
            }
            else
            {
                foreach (var record in _records[0].Attributes)
                {
                    _attributes.Add(NtfsAttribute.FromRecord(this, MftReference, record));
                }
            }
        }
Beispiel #16
0
 public StructuredNtfsAttribute(File file, FileRecordReference containingFile, AttributeRecord record)
     : base(file, containingFile, record)
 {
     _structure = new T();
 }
Beispiel #17
0
 public void AddExtent(FileRecordReference containingFile, AttributeRecord record)
 {
     _cachedRawBuffer = null;
     _extents.Add(new AttributeReference(containingFile, record.AttributeId), record);
 }