public static MasterBootRecord ParseMBR(byte[] buffer)
        {
            var mbr = new MasterBootRecord();

            //copy raw data bytes
            mbr.RawBytes = new byte[buffer.Length];
            Array.Copy(buffer, mbr.RawBytes, mbr.RawBytes.Length);

            //copy bootcode
            mbr.BootCode = new byte[MasterBootRecord.BootCodeSize];
            Array.Copy(buffer, 0, mbr.BootCode, 0, mbr.BootCode.Length);

            //parse drive serial and protection status
            mbr.DriveSerialNo      = Num.ArrayToHexString(buffer, MasterBootRecord.BootCodeSize, 4);
            mbr.CopyProtectionFlag = Num.ArrayToHexString(buffer, MasterBootRecord.BootCodeSize + 4, 2);

            //copy signature
            mbr.Signature = Num.ArrayToHexString(buffer, 510, 2);

            //parse MBR partition table
            mbr.PartitionTable = new List <MbrPartitionTable>();
            for (int i = 0; i < MasterBootRecord.MaxPartition; i++)
            {
                var pdata = new byte[MbrPartitionTable.Length];
                Array.Copy(buffer, MasterBootRecord.PartitionTableIndex + MbrPartitionTable.Length * i, pdata, 0, pdata.Length);
                var ps = new MbrPartitionTable
                {
                    BootFlag      = Num.ArrayToHexString(pdata, 0, 1),
                    ChsBegin      = Num.ArrayToHexString(pdata, 1, 3),
                    FileSystemMbr = Num.ArrayToInt(pdata, 4, 1),
                    ChsEnd        = Num.ArrayToHexString(pdata, 5, 3),
                    StartSector   = Num.ArrayToInt(pdata, 8, 4),
                    TotalSectors  = Num.ArrayToInt(pdata, 12, 4)
                };

                //file system validity check
                if (ps.FileSystemMbr >= (int)FsTypesMbr.FAT12_CHS &&
                    ps.FileSystemMbr <= (int)FsTypesMbr.Extended_LBA &&
                    ps.StartSector > 0 && ps.TotalSectors > 0)
                {
                    mbr.PartitionTable.Add(ps);
                }
                else if (ps.FileSystemMbr == (int)FsTypesMbr.GptParitionSignature)
                {
                    mbr.PartitionTable.Add(ps);
                }
            }

            return(mbr);
        }
Esempio n. 2
0
        /// <summary>
        /// Load the file system from the container image
        /// </summary>
        /// <returns>The file system found on the image</returns>
        protected virtual PartitionTable LoadPartitionTable()
        {
            // TODO: introduce a factory system that tries and then fails as required, like file systems have

            using BinaryReader br = new BinaryReader(Content, Encoding.ASCII, true);
            br.BaseStream.Seek(0x1FE, SeekOrigin.Begin);
            var signature = br.ReadUInt16();

            if (signature != 0xaa55)
            {
                return(new NoPartitionTable(this));
            }

            var mbrPartition = new MbrPartitionTable(this);

            if (mbrPartition.Partitions.Count >= 1)
            {
                if (mbrPartition.Partitions[0] is MbrPartitionTable.MbrPartitionEntry entry &&
                    (entry.Offset + entry.Length) > uint.MaxValue &&
                    entry.Type == MbrPartitionTable.MbrPartitionType.GptProtectivePartition)
                {
                    return(new GptPartitionTable(this));
                }

                // check partitions seem fine (ie, no overlapping)
                bool sanity     = true;
                long lastOffset = 512;
                foreach (var partition in mbrPartition.Partitions)
                {
                    sanity    &= (partition.Offset >= lastOffset);
                    sanity    &= (partition.Length > 0);
                    lastOffset = partition.Offset + partition.Length;
                    sanity    &= (lastOffset <= br.BaseStream.Length);
                }

                if (sanity)
                {
                    return(mbrPartition);
                }
            }

            return(new NoPartitionTable(this));
        }
        public static BootSectorCommon ParseBootSector(MbrPartitionTable pt, byte[] buffer)
        {
            var bscmn = new BootSectorCommon();

            bscmn.FsType = FsType.Unknown;

            //copy raw data bytes
            bscmn.RawBytes = new byte[buffer.Length];
            Array.Copy(buffer, bscmn.RawBytes, bscmn.RawBytes.Length);

            //add parition table
            bscmn.MbrPartitionTable = new List <MbrPartitionTable>();
            bscmn.MbrPartitionTable.Add(pt);

            //parse common properties
            bscmn.JumpCode          = Num.ArrayToHexString(buffer, 0, 3);
            bscmn.OemName           = Encoding.ASCII.GetString(buffer, 3, 8);
            bscmn.BytesPerSector    = Num.ArrayToInt(buffer, 11, 2);
            bscmn.SectorPerCluster  = Num.ArrayToInt(buffer, 13, 1);
            bscmn.ResvSectorCount   = Num.ArrayToInt(buffer, 14, 2);
            bscmn.NumOfFat          = Num.ArrayToInt(buffer, 16, 1);
            bscmn.RootEntryCount    = Num.ArrayToInt(buffer, 17, 2);
            bscmn.TotalSector16     = Num.ArrayToInt(buffer, 19, 2);
            bscmn.MediaType         = Num.ArrayToInt(buffer, 21, 1);
            bscmn.FatSizeInSector   = Num.ArrayToInt(buffer, 22, 2);
            bscmn.SectorPerTrack    = Num.ArrayToInt(buffer, 24, 2);
            bscmn.NumOfHeads        = Num.ArrayToInt(buffer, 26, 2);
            bscmn.HiddenSectorCount = Num.ArrayToLong(buffer, 28, 4);
            bscmn.TotalSector32     = Num.ArrayToLong(buffer, 32, 4);
            bscmn.BootCode          = new byte[BootSectorCommon.BootCodeLength];
            Array.Copy(buffer, 62, bscmn.BootCode, 0, bscmn.BootCode.Length);
            bscmn.Signature    = Num.ArrayToHexString(buffer, 510, 2);
            bscmn.TotalSectors = bscmn.TotalSector16 != 0 ? bscmn.TotalSector16 : bscmn.TotalSector32;

            //try detect FS exFAT or NTFS from OEM name
            if (bscmn.FsType == FsType.Unknown)
            {
                if (bscmn.OemName.Contains("EXFAT"))
                {
                    bscmn.FsType = FsType.ExFAT;
                }
                else if (bscmn.OemName.Contains("NTFS"))
                {
                    bscmn.FsType = FsType.NTFS;
                }
            }

            //try detect FS from total cluster count
            if (bscmn.FsType == FsType.Unknown)
            {
                if (bscmn.SectorPerCluster > 0 && bscmn.TotalSectors > 0)
                {
                    var clscount = bscmn.TotalSectors / bscmn.SectorPerCluster;
                    if (clscount >= ClusterNum.BadFAT16)
                    {
                        bscmn.FsType = FsType.FAT32;
                    }
                    else if (clscount >= ClusterNum.BadFAT12)
                    {
                        bscmn.FsType = FsType.FAT16;
                    }
                    else if (clscount > 0)
                    {
                        bscmn.FsType = FsType.FAT12;
                    }
                }
            }

            //parse FS specific properties
            if (bscmn.FsType == FsType.ExFAT)
            {
                var exfat = new BootSectorExFAT();
                bscmn.ExFatBS = new List <BootSectorExFAT>();
                bscmn.ExFatBS.Add(exfat);

                //parse exFAT properties
                exfat.PartitionOffset       = Num.ArrayToULong(buffer, 64, 8);
                exfat.VolumeLength          = Num.ArrayToULong(buffer, 72, 8);
                exfat.FatOffset             = Num.ArrayToUInt(buffer, 80, 4);
                exfat.FATsize               = Num.ArrayToUInt(buffer, 84, 4);
                exfat.ClusterHeapOffset     = Num.ArrayToUInt(buffer, 88, 4);
                exfat.ClusterCount          = Num.ArrayToUInt(buffer, 92, 4);
                exfat.RootDirClusterNum     = Num.ArrayToUInt(buffer, 96, 4);
                exfat.VolumeSerialNum       = Num.ArrayToUInt(buffer, 100, 4);
                exfat.FsRevision            = Num.ArrayToUInt(buffer, 104, 4);
                exfat.VolumeFlags           = Num.ArrayToUInt(buffer, 102, 2);
                exfat.BytesPerSectorShift   = buffer[108];
                exfat.SectorPerClusterShift = buffer[109];
                exfat.NumOfFat              = buffer[110];
                exfat.DriveSelect           = buffer[111];
                exfat.PercentInUse          = buffer[112];
                exfat.Reserved              = new byte[7];
                Array.Copy(buffer, 113, exfat.Reserved, 0, exfat.Reserved.Length);
                bscmn.BootCode = new byte[390];
                Array.Copy(buffer, 120, bscmn.BootCode, 0, bscmn.BootCode.Length);

                //pre-calculate common properties
                bscmn.FatSizeInSector     = (int)exfat.FATsize;
                bscmn.BytesPerSector      = 1 << exfat.BytesPerSectorShift;
                bscmn.SectorPerCluster    = 1 << exfat.SectorPerClusterShift;
                bscmn.ClusterSizeInBytes  = bscmn.SectorPerCluster * bscmn.BytesPerSector;
                bscmn.FatSizeInBytes      = bscmn.FatSizeInSector * bscmn.BytesPerSector;
                bscmn.TotalSectors        = bscmn.MbrPartitionTable[0].TotalSectors;
                bscmn.PartitionSize       = exfat.ClusterCount * bscmn.ClusterSizeInBytes;
                bscmn.FatLocation         = (bscmn.MbrPartitionTable[0].StartSector + exfat.FatOffset) * bscmn.BytesPerSector;
                bscmn.DataClusterLocation = (bscmn.MbrPartitionTable[0].StartSector + exfat.ClusterHeapOffset) * bscmn.BytesPerSector;
                bscmn.RootDirLocation     = bscmn.DataClusterLocation + GetClusterOffset(exfat.RootDirClusterNum, bscmn.ClusterSizeInBytes);
            }
            else if (bscmn.FsType == FsType.NTFS)
            {
                var ntfsbs = new BootSectorNTFS();
                bscmn.NtfsBS = new List <BootSectorNTFS>();
                bscmn.NtfsBS.Add(ntfsbs);

                //parse NTFS properties
                ntfsbs.TotalSectors                 = Num.ArrayToULong(buffer, 40, 8);
                ntfsbs.MftMirrFileClusterNum        = Num.ArrayToLong(buffer, 48, 8);
                ntfsbs.MftFileClusterNum            = Num.ArrayToLong(buffer, 56, 8);
                ntfsbs.ClustersPerFileRecordSegment = Num.ArrayToInt(buffer, 64, 4);
                ntfsbs.ClusterPerIndexBuffer        = buffer[68];
                ntfsbs.VolumeSerial                 = new byte[8];
                Array.Copy(buffer, 72, ntfsbs.VolumeSerial, 0, ntfsbs.VolumeSerial.Length);
                ntfsbs.Checksum = Num.ArrayToInt(buffer, 80, 4);
                bscmn.BootCode  = new byte[426];
                Array.Copy(buffer, 84, bscmn.BootCode, 0, bscmn.BootCode.Length);

                //pre-calculate common properties
                bscmn.ClusterSizeInBytes = bscmn.SectorPerCluster * bscmn.BytesPerSector;
                bscmn.TotalSectors       = (long)ntfsbs.TotalSectors;
                bscmn.PartitionSize      = bscmn.TotalSectors * bscmn.BytesPerSector;
            }
            else // FAT12/16/32
            {
                var fatbs = new BootSectorFAT();
                bscmn.FatBS = new List <BootSectorFAT>();
                bscmn.FatBS.Add(fatbs);

                //pre-calculate common properties
                bscmn.ClusterSizeInBytes  = bscmn.BytesPerSector * bscmn.SectorPerCluster;
                bscmn.PartitionSize       = bscmn.TotalSectors * bscmn.BytesPerSector;
                bscmn.FatSizeInBytes      = bscmn.FatSizeInSector * bscmn.BytesPerSector;
                bscmn.FatLocation         = (bscmn.MbrPartitionTable[0].StartSector + bscmn.ResvSectorCount) * bscmn.BytesPerSector;
                bscmn.RootDirLocation     = bscmn.FatLocation + (bscmn.FatSizeInSector * bscmn.NumOfFat * bscmn.BytesPerSector);
                bscmn.DataClusterLocation = bscmn.RootDirLocation + (bscmn.RootEntryCount * FatEntry.Length);

                var fat32offset = 0;
                if (bscmn.FsType == FsType.FAT32)
                {
                    //parse FAT32 properties
                    fatbs.FATsize32         = Num.ArrayToLong(buffer, 36, 4);
                    fatbs.ExtFlags          = Num.ArrayToInt(buffer, 40, 2);
                    fatbs.FSver             = Num.ArrayToInt(buffer, 42, 2);
                    fatbs.RootDirClusterNum = Num.ArrayToUInt(buffer, 44, 4);
                    fatbs.FSInfoSector      = Num.ArrayToInt(buffer, 48, 2);
                    fatbs.BackupBootSect    = Num.ArrayToInt(buffer, 50, 2);
                    fatbs.ReservedFAT32     = new byte[12];
                    Array.Copy(buffer, 52, fatbs.ReservedFAT32, 0, fatbs.ReservedFAT32.Length);
                    bscmn.BootCode = new byte[420];
                    Array.Copy(buffer, 90, bscmn.BootCode, 0, bscmn.BootCode.Length);
                    fat32offset = 28;

                    //pre-calculate FAT32 properties
                    bscmn.BytesPerFatConst = FatConst.ClusterByteCountFAT32;
                    if (bscmn.FatSizeInBytes <= 0)
                    {
                        bscmn.FatSizeInBytes      = fatbs.FATsize32 * bscmn.BytesPerSector;
                        bscmn.DataClusterLocation = bscmn.FatLocation + (fatbs.FATsize32 * bscmn.NumOfFat * bscmn.BytesPerSector);
                        bscmn.RootDirLocation     = bscmn.DataClusterLocation + GetClusterOffset(fatbs.RootDirClusterNum, bscmn.ClusterSizeInBytes);
                    }
                }

                //common properties FAT12/16, FAT32 with offset
                fatbs.DriveNumber   = Num.ArrayToInt(buffer, fat32offset + 36, 1);
                fatbs.Reserved1     = Num.ArrayToInt(buffer, fat32offset + 37, 1);
                fatbs.BootSignature = Num.ArrayToInt(buffer, fat32offset + 38, 1);
                fatbs.VolumeId      = Num.ArrayToHexString(buffer, fat32offset + 39, 4);
                fatbs.VolumeLabel   = Encoding.ASCII.GetString(buffer, fat32offset + 43, 11);
                fatbs.FileSysString = Encoding.ASCII.GetString(buffer, fat32offset + 54, 8);

                //concat volume name
                var idx = fatbs.VolumeLabel.IndexOf('\0');
                if (idx >= 0)
                {
                    fatbs.VolumeLabel = fatbs.VolumeLabel.Substring(0, idx);
                }

                //concat FS name
                idx = fatbs.FileSysString.IndexOf('\0');
                if (idx >= 0)
                {
                    fatbs.FileSysString = fatbs.FileSysString.Substring(0, idx);
                }

                //try detect FS from boot sector
                if (bscmn.FsType == FsType.Unknown)
                {
                    if (fatbs.FileSysString.Contains("FAT12"))
                    {
                        bscmn.FsType = FsType.FAT12;
                    }
                    else if (fatbs.FileSysString.Contains("FAT16"))
                    {
                        bscmn.FsType = FsType.FAT16;
                    }
                }
            }

            //pre-load FS dependent const
            if (bscmn.FsType == FsType.FAT12)
            {
                bscmn.BadClusterFlagConst = ClusterNum.BadFAT12;
                bscmn.EofClusterFlagConst = ClusterNum.EofFAT12;
            }
            else if (bscmn.FsType == FsType.FAT16)
            {
                bscmn.BytesPerFatConst    = FatConst.ClusterByteCountFAT16;
                bscmn.BadClusterFlagConst = ClusterNum.BadFAT16;
                bscmn.EofClusterFlagConst = ClusterNum.EofFAT16;
            }
            else if (bscmn.FsType == FsType.FAT32)
            {
                bscmn.BytesPerFatConst    = FatConst.ClusterByteCountFAT32;
                bscmn.BadClusterFlagConst = ClusterNum.BadFAT32;
                bscmn.EofClusterFlagConst = ClusterNum.EofFAT32;
            }
            else if (bscmn.FsType == FsType.ExFAT)
            {
                bscmn.BytesPerFatConst    = FatConst.ClusterByteCountFAT32;
                bscmn.BadClusterFlagConst = ClusterNum.BadexFAT;
                bscmn.EofClusterFlagConst = ClusterNum.EofExFAT;
            }
            else if (bscmn.FsType == FsType.NTFS)
            {
                bscmn.BytesPerFatConst    = FatConst.ClusterByteCountFAT32;
                bscmn.BadClusterFlagConst = ClusterNum.BadexFAT;
                bscmn.EofClusterFlagConst = ClusterNum.EofExFAT;
            }

            return(bscmn);
        }