Exemple #1
0
        private void ScanForBadBlocks(bool throwException = true, uint blocksize = 0x4000, uint nextBlock = 0x41F0)
        {
            if (!HasSpare || MetaType == NANDSpare.MetaType.MetaTypeUnInitialized)
            {
                if (throwException)
                {
                    throw new NotSupportedException();
                }
                return;
            }
            _badBlocks.Clear();
            RawSeek(0x200, SeekOrigin.Begin); // Seek to first page spare data...
            var tBlocks = Length / blocksize;

            for (uint block = 0; block < tBlocks; block++)
            {
                var meta = NANDSpare.GetMetaData(RawReadBytes(0x10), MetaType);
                if (NANDSpare.CheckIsBadBlock(meta))
                {
                    _badBlocks.Add(block);
                    if (Main.VerifyVerbosityLevel(Main.VerbosityLevels.High))
                    {
                        Main.SendInfo("{1}BadBlock Marker detected @ block 0x{0:X}", block, Environment.NewLine);
                    }
                }
                RawSeek(nextBlock, SeekOrigin.Current);
            }
            _badBlocksScanned = true;
        }
Exemple #2
0
 public SmartNANDReader(string file, bool fastScan = false)
 {
     if (Main.VerifyVerbosityLevel(Main.VerbosityLevels.Debug))
     {
         Main.SendInfo("Creating SmartNANDReader for {0}{1}", file, Environment.NewLine);
     }
     _binaryReader = new BinaryReader(File.Open(file, FileMode.Open, FileAccess.Read, FileShare.Read));
     if (Main.VerifyVerbosityLevel(Main.VerbosityLevels.Debug))
     {
         Main.SendInfo("Verifying Magic Bytes... ");
     }
     if (!VerifyMagic())
     {
         if (Main.VerifyVerbosityLevel(Main.VerbosityLevels.Debug))
         {
             Main.SendInfo("Failed!{0}", Environment.NewLine);
         }
         throw new X360UtilsException(X360UtilsException.X360UtilsErrors.BadMagic);
     }
     if (Main.VerifyVerbosityLevel(Main.VerbosityLevels.Debug))
     {
         Main.SendInfo("OK!{0}", Environment.NewLine);
     }
     if (Main.VerifyVerbosityLevel(Main.VerbosityLevels.Debug))
     {
         Main.SendInfo("Checking for spare... ");
     }
     HasSpare = CheckForSpare();
     if (Main.VerifyVerbosityLevel(Main.VerbosityLevels.Debug))
     {
         Main.SendInfo(HasSpare ? "Spare detected!{0}" : "No Spare detected!{0}", Environment.NewLine);
     }
     if (HasSpare)
     {
         Main.SendMaxBlocksChanged((int)(_binaryReader.BaseStream.Length / 0x4200));
         _doSendPosition = true;
         if (Main.VerifyVerbosityLevel(Main.VerbosityLevels.Debug))
         {
             Main.SendInfo("Detecting spare type... ");
         }
         MetaType = NANDSpare.DetectSpareType(this);
         if (Main.VerifyVerbosityLevel(Main.VerbosityLevels.Debug))
         {
             Main.SendInfo("{0}{1}", MetaType, Environment.NewLine);
         }
         if (fastScan)
         {
             return;
         }
         if (Main.VerifyVerbosityLevel(Main.VerbosityLevels.Debug))
         {
             Main.SendInfo("Scanning for FSRoot/Mobile entries");
         }
         ScanForFsRootAndMobiles();
         return;
     }
     Main.SendMaxBlocksChanged((int)(_binaryReader.BaseStream.Length / 0x4000));
     _doSendPosition = true;
     MetaType        = NANDSpare.MetaType.MetaTypeNone;
 }
Exemple #3
0
 internal MobileEntry(long offset, ref NANDSpare.MetaData meta)
 {
     Offset     = offset;
     _rawOffset = (offset / 0x200) * 0x210;
     Version    = NANDSpare.GetFsSequence(ref meta);
     MobileType = NANDSpare.GetBlockType(ref meta);
     Size       = NANDSpare.GetFsSize(ref meta);
 }
Exemple #4
0
        private static long GetBaseBlockForMeta2(ref NANDReader reader)
        {
            reader.RawSeek(reader.FsRoot.Offset / 0x200 * 0x210 + 0x200, SeekOrigin.Begin);
            var meta     = NANDSpare.GetMetaData(reader.RawReadBytes(0x10));
            var reserved = 0x1E0;

            reserved -= meta.Meta2.FsPageCount;
            reserved -= meta.Meta2.FsSize0 << 2;
            return(reserved * 8);
        }
Exemple #5
0
        private bool CheckForSpare()
        {
            RawSeek(0, SeekOrigin.Begin);
            var tmp = _binaryReader.ReadBytes(0x630);

            RawSeek(0, SeekOrigin.Begin);
            var ret = true;

            for (var i = 0; i < tmp.Length; i += 0x210)
            {
                if (!NANDSpare.CheckPageEcd(ref tmp, i))
                {
                    ret = false;
                }
            }
            return(ret);
        }
Exemple #6
0
        public void SeekToLbaEx(uint lba)
        {
            Lba = lba;
            if (_badBlocks.Contains(lba))
            {
                var block = MetaType == NANDSpare.MetaType.MetaType2 ? 0xFFF : 0x3FF;
                while (true)
                {
                    NANDSpare.MetaData meta;
                    switch (MetaType)
                    {
                    case NANDSpare.MetaType.MetaType0:
                    case NANDSpare.MetaType.MetaType1:
                        Seek(block * 0x4000, SeekOrigin.Begin);
                        RawSeek(0x200, SeekOrigin.Current);
                        meta = NANDSpare.GetMetaData(RawReadBytes(0x10), MetaType);
                        if (NANDSpare.GetLba(ref meta) == lba)
                        {
                            Seek(block * 0x4000, SeekOrigin.Begin);
                            return;
                        }
                        break;

                    case NANDSpare.MetaType.MetaType2:
                        Seek(block * 0x4000, SeekOrigin.Begin);
                        RawSeek(0x200, SeekOrigin.Current);
                        meta = NANDSpare.GetMetaData(RawReadBytes(0x10), MetaType);
                        if (NANDSpare.GetLba(ref meta) == lba / 8)
                        {
                            Seek(block * 0x4000 + ((lba % 8) * 0x4000), SeekOrigin.Begin);
                            return;
                        }
                        break;

                    default:
                        Seek(lba * 0x4000, SeekOrigin.Begin);
                        return;
                    }
                    block--;
                }
            }
            Seek(MetaType == NANDSpare.MetaType.MetaType2 ? ((lba / 8) * 0x20000) + ((lba % 8) * 0x4000) : lba * 0x4000, SeekOrigin.Begin);
        }
Exemple #7
0
        public long[] FindBadBlocks(bool forceSb = false)
        {
            if (!HasSpare || MetaType == NANDSpare.MetaType.MetaTypeUnInitialized)
            {
                throw new NotSupportedException();
            }
            if (_forcedSb && !forceSb || !_forcedSb && forceSb)
            {
                _badBlocks.Clear();
            }
            if (_badBlocks.Count > 0)
            {
                return(_badBlocks.ToArray());
            }
            _forcedSb = forceSb;
            _badBlocks.Clear();
            RawSeek(0x200, SeekOrigin.Begin); // Seek to first page spare data...
            var totalBlocks = Length / (MetaType == NANDSpare.MetaType.MetaType2 ? (!forceSb ? 0x20000 : 0x4000) : 0x4000);

            for (var block = 0; block < totalBlocks; block++)
            {
                var spare = RawReadBytes(0x10);
                if (NANDSpare.CheckIsBadBlockSpare(ref spare, MetaType))
                {
                    if (Main.VerifyVerbosityLevel(1))
                    {
                        Main.SendInfo("{1}BadBlock Marker detected @ block 0x{0:X}", block, Environment.NewLine);
                    }
                    _badBlocks.Add(block);
                }
                RawSeek(MetaType == NANDSpare.MetaType.MetaType2 ? (!forceSb ? 0x20FF0 : 0x41F0) : 0x41F0, SeekOrigin.Current);
            }
            if (Main.VerifyVerbosityLevel(1))
            {
                Main.SendInfo(Environment.NewLine);
            }
            if (_badBlocks.Count > 0)
            {
                return(_badBlocks.ToArray());
            }
            throw new X360UtilsException(X360UtilsException.X360UtilsErrors.DataNotFound);
        }
Exemple #8
0
        public void SeekToLba(uint lba)
        {
            if (_badBlocks.Contains(lba))
            {
                var block = 0;
                while (true)
                {
                    NANDSpare.MetaData meta;
                    switch (MetaType)
                    {
                    case NANDSpare.MetaType.MetaType0:
                    case NANDSpare.MetaType.MetaType1:
                        Seek((lba * 0x4000) - block * 0x4000, SeekOrigin.Begin);
                        RawSeek(0x200, SeekOrigin.Current);
                        meta = NANDSpare.GetMetaData(RawReadBytes(0x10), MetaType);
                        if (NANDSpare.GetLba(ref meta) == lba)
                        {
                            Seek((lba * 0x4000) - block * 0x4000, SeekOrigin.Begin);
                            return;
                        }
                        break;

                    case NANDSpare.MetaType.MetaType2:
                        Seek((lba * 0x20000) - block * 0x20000, SeekOrigin.Begin);
                        RawSeek(0x200, SeekOrigin.Current);
                        meta = NANDSpare.GetMetaData(RawReadBytes(0x10), MetaType);
                        if (NANDSpare.GetLba(ref meta) == lba)
                        {
                            Seek((lba * 0x20000) - block * 0x20000, SeekOrigin.Begin);
                            return;
                        }
                        break;

                    default:
                        Seek(lba * 0x4000, SeekOrigin.Begin);
                        return;
                    }
                    block++;
                }
            }
            Seek(lba * (MetaType != NANDSpare.MetaType.MetaType2 ? 0x4000 : 0x20000), SeekOrigin.Begin);
        }
Exemple #9
0
        public void ScanForFsRootAndMobile()
        {
            if (FsRootEntries.Count > 0)
            {
                return;
            }
            if (!HasSpare)
            {
                #region MMC (No Spare)

                if (Length < 0x2FF0000)
                {
                    throw new X360UtilsException(X360UtilsException.X360UtilsErrors.DataTooSmall);
                }
                Seek(0x2FE8018, SeekOrigin.Begin); // Seek to MMC Anchor number offset
                var ver1 = BitOperations.Swap(BitConverter.ToUInt32(ReadBytes(4), 0));
                Seek(0x2FEC018, SeekOrigin.Begin); // Seek to MMC Anchor number offset
                var ver2 = BitOperations.Swap(BitConverter.ToUInt32(ReadBytes(4), 0));
                if (ver1 == 0 || ver2 == 0)
                {
                    throw new X360UtilsException(X360UtilsException.X360UtilsErrors.DataNotFound);
                }
                Seek(ver1 > ver2 ? 0x2FE8000 : 0x2FEC000, SeekOrigin.Begin); // Seek to MMC Anchor Block Offset
                var buf = ReadBytes(0x4000);                                 // We want the first anchor buffer
                FsRootEntries.Add(new FsRootEntry(NANDSpare.GetMmcMobileBlock(ref buf, 0) * 0x4000, 0, true));
                for (byte i = 0x31; i < 0x3F; i++)
                {
                    var size = NANDSpare.GetMmcMobileSize(ref buf, i);
                    MobileEntries.Add(new MobileEntry(NANDSpare.GetMmcMobileBlock(ref buf, i) * 0x4000, 0, size > 0 ? size : 0x4000, i));
                }

                #endregion
            }
            else
            {
                #region NAND (With Spare)

                var maximumOffset = BitOperations.GetSmallest(_binaryReader.BaseStream.Length, 0x4200000); // Only read the filesystem area of BB NANDs (for faster processing)

                #region FSRoot

                RawSeek(0x8600, SeekOrigin.Begin); //Seek to block 3 page 0 on small block
                for (; _binaryReader.BaseStream.Position < maximumOffset - 0x10;)
                {
                    var meta = NANDSpare.GetMetaData(_binaryReader.ReadBytes(0x10), MetaType);
                    if (NANDSpare.PageIsFsRoot(ref meta))
                    {
                        Debug.SendDebug("FSRoot found @ 0x{0:X} version: {1}", Position - 0x200, NANDSpare.GetFsSequence(ref meta));
                        FsRootEntries.Add(new FsRootEntry(Position - 0x200, NANDSpare.GetFsSequence(ref meta)));
                        RawSeek(0x41f0, SeekOrigin.Current); // Seek to the next small block
                    }
                    else
                    {
                        if (NANDSpare.IsMobilePage(ref meta))
                        {
                            Debug.SendDebug("Mobile found @ 0x{0:X} version: {1}", Position - 0x200, NANDSpare.GetFsSequence(ref meta));
                            MobileEntries.Add(new MobileEntry(Position - 0x200, ref meta));
                        }
                        for (var i = 0; i < 31; i++)
                        {
                            RawSeek(0x200, SeekOrigin.Current);
                            meta = NANDSpare.GetMetaData(_binaryReader.ReadBytes(0x10), MetaType);
                            if (NANDSpare.IsMobilePage(ref meta))
                            {
                                Debug.SendDebug("Mobile found @ 0x{0:X} version: {1}", Position - 0x200, NANDSpare.GetFsFreePages(ref meta));
                                MobileEntries.Add(new MobileEntry(Position - 0x200, ref meta));
                            }
                        }
                        RawSeek(0x200, SeekOrigin.Current);
                    }
                }

                #endregion

                #region Mobile*.dat

                RawSeek(0x8600, SeekOrigin.Begin); //Seek to block 3 page 0 on small block
                for (; _binaryReader.BaseStream.Position < maximumOffset - 0x10;)
                {
                    var meta = NANDSpare.GetMetaData(_binaryReader.ReadBytes(0x10), MetaType);
                    if (NANDSpare.PageIsFsRoot(ref meta))
                    {
                        RawSeek(0x41f0, SeekOrigin.Current); // Seek to the next small block
                        continue;                            // Skip this one
                    }

                    if (NANDSpare.IsMobilePage(ref meta))
                    {
                        Debug.SendDebug("Mobile found @ 0x{0:X} version: {1}", Position - 0x200, NANDSpare.GetFsSequence(ref meta));
                        MobileEntries.Add(new MobileEntry(Position - 0x200, ref meta));
                        var size = NANDSpare.GetFsSize(ref meta);
                        RawSeek(size / 0x200 * 0x210 - 0x10, SeekOrigin.Current);
                        if (size % 0x200 > 0)                   // There's data still to be saved...
                        {
                            RawSeek(0x210, SeekOrigin.Current); // Seek 1 page
                        }
                        while (Position % 0x800 > 0)            // We want to have an even 4 pages!
                        {
                            RawSeek(0x210, SeekOrigin.Current); // Seek 1 page
                        }
                    }
                    else
                    {
                        RawSeek(0x830, SeekOrigin.Current); // Skip 4 pages
                    }
                }

                #endregion

                #endregion
            }
            RawSeek(0, SeekOrigin.Begin); //Reset the stream

            if (FsRootEntries.Count <= 0)
            {
                throw new X360UtilsException(X360UtilsException.X360UtilsErrors.DataNotFound);
            }
            FindLatestFsRoot();
            FillMobileArray();
        }
Exemple #10
0
 public NANDReader(string file, bool fastScan = false)
 {
     Debug.SendDebug("Creating NANDReader for: {0}", file);
     _binaryReader = new BinaryReader(File.Open(file, FileMode.Open, FileAccess.Read, FileShare.Read));
     if (!VerifyMagic())
     {
         throw new Exception("Bad Magic");
     }
     if (Main.VerifyVerbosityLevel(1))
     {
         Main.SendInfo("\r\nChecking for spare... ");
     }
     HasSpare = CheckForSpare();
     if (HasSpare)
     {
         if (Main.VerifyVerbosityLevel(1))
         {
             Main.SendInfo("Image has Spare...");
         }
         Main.SendMaxBlocksChanged((int)(_binaryReader.BaseStream.Length / 0x4200));
         _doSendPosition = true;
         if (Main.VerifyVerbosityLevel(1))
         {
             Main.SendInfo("\r\nChecking for MetaType...");
         }
         MetaType = NANDSpare.DetectSpareType(this);
         if (Main.VerifyVerbosityLevel(1))
         {
             Main.SendInfo("\r\nMetaType: {0}\r\n", MetaType);
         }
         if (fastScan)
         {
             return;
         }
         if (Main.VerifyVerbosityLevel(1))
         {
             Main.SendInfo("Checking for bad blocks...");
         }
         try {
             FindBadBlocks();
         }
         catch (X360UtilsException ex) {
             if (ex.ErrorCode != X360UtilsException.X360UtilsErrors.DataNotFound)
             {
                 throw;
             }
         }
     }
     else
     {
         if (Main.VerifyVerbosityLevel(1))
         {
             Main.SendInfo("Image does NOT have Spare...");
         }
         if (Main.VerifyVerbosityLevel(1))
         {
             Main.SendInfo("\r\n");
         }
         Main.SendMaxBlocksChanged((int)(_binaryReader.BaseStream.Length / 0x4000));
         _doSendPosition = true;
         MetaType        = NANDSpare.MetaType.MetaTypeNone;
     }
 }
Exemple #11
0
        private void SeekToSmallBlock(uint blockLba)
        {
            if (MetaType == NANDSpare.MetaType.MetaTypeNone)
            {
                RawSeek(blockLba * 0x4000, SeekOrigin.Begin);
                return;
            }
            if (MetaType == NANDSpare.MetaType.MetaTypeUnInitialized)
            {
                RawSeek(blockLba * 0x4200, SeekOrigin.Begin);
                return;
            }
            RawSeek(0x200 + (blockLba * 0x4200), SeekOrigin.Begin); // Seek to the first page spare of the block we're looking for
            var meta = NANDSpare.GetMetaData(RawReadBytes(0x10), MetaType);

            switch (MetaType)
            {
            case NANDSpare.MetaType.MetaType2:
                if (NANDSpare.GetLba(ref meta) == blockLba / 8)
                {
                    RawSeek(blockLba * 0x4200, SeekOrigin.Begin);
                    return;
                }
                break;

            default:
                if (NANDSpare.GetLba(ref meta) == blockLba)
                {
                    RawSeek(blockLba * 0x4200, SeekOrigin.Begin);
                    return;
                }
                break;
            }

            #region Find the block starting from the end...

            var block = LastBlock();
            while (true)
            {
                RawSeek(0x200 + (block * 0x4200), SeekOrigin.Begin);
                meta = NANDSpare.GetMetaData(RawReadBytes(0x10), MetaType);
                switch (MetaType)
                {
                case NANDSpare.MetaType.MetaType2:
                    if (NANDSpare.GetLba(ref meta) == blockLba / 8)
                    {
                        RawSeek(block * 0x4200, SeekOrigin.Begin);
                        return;
                    }
                    break;

                default:
                    if (NANDSpare.GetLba(ref meta) == blockLba)
                    {
                        RawSeek(block * 0x4200, SeekOrigin.Begin);
                        return;
                    }
                    break;
                }
                block--;
            }

            #endregion
        }
Exemple #12
0
        private void ScanForFsRootAndMobiles()
        {
            if (FsRoot != null)
            {
                return;
            }
            var mobiles = new List <MobileEntry>();
            var fsroots = new List <FsRootEntry>();

            if (!HasSpare)
            {
                #region MMC

                if (Length < 0x2FF0000)
                {
                    throw new X360UtilsException(X360UtilsException.X360UtilsErrors.DataTooSmall);
                }
                Seek(0x2FE8018, SeekOrigin.Begin); // Seek to MMC Anchor number offset
                var ver1 = BitOperations.Swap(BitConverter.ToUInt32(ReadBytes(4), 0));
                Seek(0x2FEC018, SeekOrigin.Begin); // Seek to MMC Anchor number offset
                var ver2 = BitOperations.Swap(BitConverter.ToUInt32(ReadBytes(4), 0));
                if (ver1 == 0 || ver2 == 0)
                {
                    throw new X360UtilsException(X360UtilsException.X360UtilsErrors.DataNotFound);
                }
                Seek(ver1 > ver2 ? 0x2FE8000 : 0x2FEC000, SeekOrigin.Begin); // Seek to MMC Anchor Block Offset
                var buf = ReadBytes(0x4000);                                 // We want the first anchor buffer
                fsroots.Add(new FsRootEntry(NANDSpare.GetMmcMobileBlock(ref buf, 0) * 0x4000, 0, true));
                for (byte i = 0x31; i < 0x3F; i++)
                {
                    var size = NANDSpare.GetMmcMobileSize(ref buf, i);
                    mobiles.Add(new MobileEntry(NANDSpare.GetMmcMobileBlock(ref buf, i) * 0x4000, 0, size > 0 ? size : 0x4000, i));
                }

                #endregion
            }
            else
            {
                #region NAND

                var maximumOffset = BitOperations.GetSmallest(_binaryReader.BaseStream.Length, 0x4200000); // Only read the filesystem area of BB NANDs (for faster processing)
                RawSeek(0x8600, SeekOrigin.Begin);                                                         // Seek to Page 0 on Block 3 (SB) Nothing before this will be valid FSRoot...
                for (; RawPosition < maximumOffset - 0x10;)
                {
                    var meta = NANDSpare.GetMetaData(RawReadBytes(0x10), MetaType);
                    if (!NANDSpare.PageIsFsRoot(ref meta))
                    {
                        continue;
                    }
                    if (Main.VerifyVerbosityLevel(Main.VerbosityLevels.Debug))
                    {
                        Main.SendInfo("FSRoot found @ 0x{0:X} Version: {1}{2}", Position - 0x200, NANDSpare.GetFsSequence(ref meta));
                    }
                    fsroots.Add(new FsRootEntry(Position - 0x200, NANDSpare.GetFsSequence(ref meta)));
                }

                #region Mobile

                RawSeek(0x8600, SeekOrigin.Begin); //Seek to block 3 page 0 on small block
                for (; _binaryReader.BaseStream.Position < maximumOffset - 0x10;)
                {
                    var meta = NANDSpare.GetMetaData(_binaryReader.ReadBytes(0x10), MetaType);
                    if (NANDSpare.PageIsFsRoot(ref meta))
                    {
                        RawSeek(0x41f0, SeekOrigin.Current); // Seek to the next small block
                        continue;                            // Skip this one
                    }

                    if (NANDSpare.IsMobilePage(ref meta))
                    {
                        if (Main.VerifyVerbosityLevel(Main.VerbosityLevels.Debug))
                        {
                            Main.SendInfo("Mobile found @ 0x{0:X} Version: {1}{2}", Position - 0x200, NANDSpare.GetFsSequence(ref meta));
                        }
                        mobiles.Add(new MobileEntry(Position - 0x200, ref meta));
                        var size = NANDSpare.GetFsSize(ref meta);
                        RawSeek(size / 0x200 * 0x210 - 0x10, SeekOrigin.Current);
                        if (size % 0x200 > 0)                   // There's data still to be saved...
                        {
                            RawSeek(0x210, SeekOrigin.Current); // Seek 1 page
                        }
                        while (Position % 0x800 > 0)            // We want to have an even 4 pages!
                        {
                            RawSeek(0x210, SeekOrigin.Current); // Seek 1 page
                        }
                    }
                    else
                    {
                        RawSeek(0x830, SeekOrigin.Current); // Skip 4 pages
                    }
                }

                #endregion

                #endregion
            }
            FileSystemEntries = fsroots.ToArray();
            FindLatestFsRoot();
            FindLatestMobiles(mobiles);
        }