예제 #1
0
        public string ReadAsciiString(FileStream fs, long BaseOffset, long UtfOffset)
        {
            byte encryptedByte;
            byte decryptedByte;

            var asciiVal = new StringBuilder();
            // byte xorByte;
            var fileSize = fs.Length;

            if (IsEncrypted)
            {
                fs.Position = BaseOffset + UtfOffset;

                if (UtfOffset < CurrentUtfStringOffset)
                {
                    // reset, maybe add some sort of index later?
                    CurrentUtfStringOffset = 0;
                }

                if (CurrentUtfStringOffset == 0)
                {
                    // reset or initialize
                    CurrentStringXor = Seed;
                }

                for (var j = CurrentUtfStringOffset; j < UtfOffset; j++)
                {
                    if (j > 0)
                    {
                        CurrentStringXor *= Increment;
                    }

                    CurrentUtfStringOffset++;
                }

                for (var i = UtfOffset; i < fileSize - (BaseOffset + UtfOffset); i++)
                {
                    CurrentStringXor *= Increment;
                    CurrentUtfStringOffset++;

                    encryptedByte = (byte)fs.ReadByte();
                    decryptedByte = (byte)(encryptedByte ^ CurrentStringXor);

                    if (decryptedByte == 0)
                    {
                        break;
                    }
                    else
                    {
                        asciiVal.Append(Convert.ToChar(decryptedByte));
                    }
                }
            }
            else
            {
                asciiVal.Append(ParseFile.ReadAsciiString(fs, BaseOffset + UtfOffset));
            }

            return(asciiVal.ToString());
        }
예제 #2
0
        public string ReadAsciiString(FileStream fs, long BaseOffset, long UtfOffset)
        {
            byte encryptedByte;
            byte decryptedByte;

            StringBuilder asciiVal = new StringBuilder();
            byte          xorByte;
            long          fileSize = fs.Length;

            if (this.IsEncrypted)
            {
                fs.Position = (BaseOffset + UtfOffset);

                if (UtfOffset < this.CurrentUtfStringOffset)
                {
                    // reset, maybe add some sort of index later?
                    this.CurrentUtfStringOffset = 0;
                }

                if (this.CurrentUtfStringOffset == 0)
                {
                    // reset or initialize
                    this.CurrentStringXor = this.Seed;
                }

                for (long j = this.CurrentUtfStringOffset; j < UtfOffset; j++)
                {
                    if (j > 0)
                    {
                        this.CurrentStringXor *= this.Increment;
                    }

                    this.CurrentUtfStringOffset++;
                }

                for (long i = UtfOffset; i < (fileSize - (BaseOffset + UtfOffset)); i++)
                {
                    this.CurrentStringXor *= this.Increment;
                    this.CurrentUtfStringOffset++;

                    encryptedByte = (byte)fs.ReadByte();
                    decryptedByte = (byte)(encryptedByte ^ this.CurrentStringXor);

                    if (decryptedByte == 0)
                    {
                        break;
                    }
                    else
                    {
                        asciiVal.Append(Convert.ToChar(decryptedByte));
                    }
                }
            }
            else
            {
                asciiVal.Append(ParseFile.ReadAsciiString(fs, BaseOffset + UtfOffset));
            }

            return(asciiVal.ToString());
        }
예제 #3
0
        private NintendoU8File getFileNode(FileStream fs, int nodeIndex, string parentDirectory)
        {
            // get node
            u8Node node = this.NodeList[nodeIndex];

            // get directory name
            string fileName = ParseFile.ReadAsciiString(fs, this.NameTableOffset + node.NameOffset);

            // create file item
            NintendoU8File newFile = new NintendoU8File(parentDirectory, this.SourceFileName,
                                                        fileName, node.DataOffset, this.VolumeBaseOffset, node.DataOffset, node.DataSize);

            return(newFile);
        }
예제 #4
0
        private void initializeUtfHeader(FileStream UtfTableFs)
        {
            this.TableSize = ParseFile.ReadUintBE(UtfTableFs, 4);

            this.Unknown1 = ParseFile.ReadUshortBE(UtfTableFs, 8);

            this.RowOffset         = (uint)ParseFile.ReadUshortBE(UtfTableFs, 0xA) + 8;
            this.StringTableOffset = ParseFile.ReadUintBE(UtfTableFs, 0xC) + 8;
            this.DataOffset        = ParseFile.ReadUintBE(UtfTableFs, 0x10) + 8;

            this.TableNameOffset = ParseFile.ReadUintBE(UtfTableFs, 0x14);
            this.TableName       = ParseFile.ReadAsciiString(UtfTableFs, this.StringTableOffset + this.TableNameOffset);

            this.NumberOfFields = ParseFile.ReadUshortBE(UtfTableFs, 0x18);

            this.RowSize      = ParseFile.ReadUshortBE(UtfTableFs, 0x1A);
            this.NumberOfRows = ParseFile.ReadUintBE(UtfTableFs, 0x1C);
        }
        public void ParseFileTable(FileStream isoStream)
        {
            FileTableEntry tableEntry = new FileTableEntry();
            long           fileTableMinOffset;
            long           fileTableMaxOffset;

            long fileSize = isoStream.Length;

            // get offset for blocks
            fileTableMinOffset = ComputeBlockNumberAndGetOffset(this.FileTableBlockNumber, this.HeaderSize, this.BlockSeparation);
            fileTableMaxOffset = ComputeBlockNumberAndGetOffset(this.FileTableBlockNumber + this.FileTableBlockCount, this.HeaderSize, this.BlockSeparation);

            // check offsets
            if ((fileTableMinOffset >= MicrosoftSTFS.FIRST_BLOCK_OFFSET) &&
                (fileTableMinOffset < fileTableMaxOffset) &&
                (fileTableMaxOffset < fileSize))
            {
                for (long i = fileTableMinOffset; i < fileTableMaxOffset; i += 0x40)
                {
                    tableEntry.FileName = ParseFile.ReadAsciiString(isoStream, i);

                    if (!String.IsNullOrEmpty(tableEntry.FileName))
                    {
                        tableEntry.Flags                  = ParseFile.ReadByte(isoStream, i + 0x28);
                        tableEntry.BlocksForFileLE1       = ParseFile.ReadInt24LE(isoStream, i + 0x29);
                        tableEntry.BlocksForFileLE2       = ParseFile.ReadInt24LE(isoStream, i + 0x2C);
                        tableEntry.StartingBlockForFileLE = ParseFile.ReadInt24LE(isoStream, i + 0x2F);
                        tableEntry.PathIndicator          = ParseFile.ReadInt16BE(isoStream, i + 0x32);
                        tableEntry.FileSize               = ParseFile.ReadUintBE(isoStream, i + 0x34);
                        tableEntry.UpdateDateTime         = ParseFile.ReadInt32BE(isoStream, i + 0x38);
                        tableEntry.AccessDateTime         = ParseFile.ReadInt32BE(isoStream, i + 0x3C);

                        FileTableEntryArray.Add(tableEntry);
                    }
                }
            }
            else
            {
                throw new IndexOutOfRangeException("File Table block IDs do not make sense.");
            }
        }
예제 #6
0
        private void ParseNcchHeader(FileStream fs, long offset)
        {
            this.NcsdHash    = ParseFile.ParseSimpleOffset(fs, offset, 0x100);
            this.MagicBytes  = ParseFile.ReadUintBE(fs, offset + 0x100);
            this.ContentSize = ParseFile.ReadUintLE(fs, offset + 0x104);
            this.PartitionId = ParseFile.ReadUlongLE(fs, offset + 0x108);

            this.MakerCode      = ParseFile.ReadUshortLE(fs, offset + 0x110);
            this.Version        = ParseFile.ReadUshortLE(fs, offset + 0x112);
            this.Reserved01     = ParseFile.ReadUintLE(fs, offset + 0x114);
            this.ProgramId      = ParseFile.ReadUlongLE(fs, offset + 0x118);
            this.Reserved02     = ParseFile.ParseSimpleOffset(fs, offset + 0x120, 0x10);
            this.LogoRegionHash = ParseFile.ParseSimpleOffset(fs, offset + 0x130, 0x20);
            this.ProductCode    = ParseFile.ReadAsciiString(fs, offset + 0x150);

            this.ExtendedHeaderHash = ParseFile.ParseSimpleOffset(fs, offset + 0x160, 0x10);
            this.ExtendedHeaderSize = ParseFile.ReadUintLE(fs, offset + 0x180);

            this.Reserved03 = ParseFile.ReadUintLE(fs, offset + 0x184);
            this.Flags      = ParseFile.ReadUlongLE(fs, offset + 0x188);

            this.PlainRegionOffset = ParseFile.ReadUintLE(fs, offset + 0x190);
            this.PlainRegionSize   = ParseFile.ReadUintLE(fs, offset + 0x194);

            this.LogoRegionOffset = ParseFile.ReadUintLE(fs, offset + 0x198);
            this.LogoRegionSize   = ParseFile.ReadUintLE(fs, offset + 0x19C);

            this.ExeFsOffset   = ParseFile.ReadUintLE(fs, offset + 0x1A0);
            this.ExeFsSize     = ParseFile.ReadUintLE(fs, offset + 0x1A4);
            this.ExeFsHashSize = ParseFile.ReadUintLE(fs, offset + 0x1A8);
            this.Reserved04    = ParseFile.ReadUintLE(fs, offset + 0x1AC);

            this.RomFsOffset   = ParseFile.ReadUintLE(fs, offset + 0x1B0);
            this.RomFsSize     = ParseFile.ReadUintLE(fs, offset + 0x1B4);
            this.RomFsHashSize = ParseFile.ReadUintLE(fs, offset + 0x1B8);
            this.Reserved05    = ParseFile.ReadUintLE(fs, offset + 0x1BC);

            this.ExeSuperblockHash   = ParseFile.ParseSimpleOffset(fs, offset + 0x1C0, 0x20);
            this.RomFsSuperblockHash = ParseFile.ParseSimpleOffset(fs, offset + 0x1E0, 0x20);
        }
예제 #7
0
        public void InitializeExeFileSystem(FileStream isoStream, long offset, string nextDirectoryName)
        {
            string fileName;
            long   fileOffset;
            uint   fileLength;

            byte[] hash;
            long   hashOffset;

            Nintendo3dsCtrFile file;

            // parse file entries
            for (int i = 0; i < 10; i++)
            {
                // check if row has data
                if (ParseFile.ReadByte(isoStream, offset + (0x10 * i)) != 0)
                {
                    // read VFS items
                    fileName = ParseFile.ReadAsciiString(isoStream, offset + (0x10 * i));

                    fileOffset  = ParseFile.ReadUintLE(isoStream, offset + (0x10 * i) + 8);
                    fileOffset += offset + 0x200;

                    fileLength = ParseFile.ReadUintLE(isoStream, offset + (0x10 * i) + 0xC);

                    // read SHA256 hash
                    hashOffset = offset + 0x200 - (0x20 * (i + 1));
                    hash       = ParseFile.ParseSimpleOffset(isoStream, hashOffset, 0x20);

                    // build file object
                    file = new Nintendo3dsCtrFile(isoStream, nextDirectoryName, this.SourceFilePath,
                                                  fileName, fileOffset, fileLength, this.FileSystem, null);
                    file.Sha256Hash = hash;
                    this.FileArray.Add(file);
                }
            }
        }
예제 #8
0
        private void initializeUtfSchema(FileStream SourceFs, FileStream UtfTableFs, long schemaOffset)
        {
            long nameOffset;

            long constantOffset;

            long dataOffset;
            long dataSize;

            long rowDataOffset;
            long rowDataSize;

            long currentOffset = schemaOffset;
            long currentRowBase;
            long currentRowOffset = 0;

            CriField field;

            for (uint i = 0; i < this.NumberOfRows; i++)
            {
                //if (i == 0x1a2a)
                //{
                //    int yuuuu = 1;
                //}
                //try
                //{
                currentOffset    = schemaOffset;
                currentRowBase   = this.RowOffset + (this.RowSize * i);
                currentRowOffset = 0;
                this.Rows[i]     = new Dictionary <string, CriField>();

                // parse fields
                for (ushort j = 0; j < this.NumberOfFields; j++)
                {
                    field = new CriField();

                    field.Type = ParseFile.ReadByte(UtfTableFs, currentOffset);
                    nameOffset = ParseFile.ReadUintBE(UtfTableFs, currentOffset + 1);
                    field.Name = ParseFile.ReadAsciiString(UtfTableFs, this.StringTableOffset + nameOffset);

                    // each row will have a constant
                    if (((field.Type & COLUMN_STORAGE_MASK) == COLUMN_STORAGE_CONSTANT) ||
                        ((field.Type & COLUMN_STORAGE_MASK) == COLUMN_STORAGE_CONSTANT2))
                    {
                        // capture offset of constant
                        constantOffset = currentOffset + 5;

                        // read the constant depending on the type
                        switch (field.Type & COLUMN_TYPE_MASK)
                        {
                        case COLUMN_TYPE_STRING:
                            dataOffset     = ParseFile.ReadUintBE(UtfTableFs, constantOffset);
                            field.Value    = ParseFile.ReadAsciiString(UtfTableFs, this.StringTableOffset + dataOffset);
                            currentOffset += 4;
                            break;

                        case COLUMN_TYPE_8BYTE:
                            field.Value    = ParseFile.ReadUlongBE(UtfTableFs, constantOffset);
                            currentOffset += 8;
                            break;

                        case COLUMN_TYPE_DATA:
                            dataOffset   = ParseFile.ReadUintBE(UtfTableFs, constantOffset);
                            dataSize     = ParseFile.ReadUintBE(UtfTableFs, constantOffset + 4);
                            field.Offset = (ulong)(this.BaseOffset + this.DataOffset + dataOffset);
                            field.Size   = (ulong)dataSize;

                            // don't think this is encrypted, need to check
                            field.Value    = ParseFile.ParseSimpleOffset(SourceFs, (long)field.Offset, (int)dataSize);
                            currentOffset += 8;
                            break;

                        case COLUMN_TYPE_FLOAT:
                            field.Value    = ParseFile.ReadFloatBE(UtfTableFs, constantOffset);
                            currentOffset += 4;
                            break;

                        case COLUMN_TYPE_4BYTE2:
                            field.Value    = ParseFile.ReadInt32BE(UtfTableFs, constantOffset);
                            currentOffset += 4;
                            break;

                        case COLUMN_TYPE_4BYTE:
                            field.Value    = ParseFile.ReadUintBE(UtfTableFs, constantOffset);
                            currentOffset += 4;
                            break;

                        case COLUMN_TYPE_2BYTE2:
                            field.Value    = ParseFile.ReadInt16BE(UtfTableFs, constantOffset);
                            currentOffset += 2;
                            break;

                        case COLUMN_TYPE_2BYTE:
                            field.Value    = ParseFile.ReadUshortBE(UtfTableFs, constantOffset);
                            currentOffset += 2;
                            break;

                        case COLUMN_TYPE_1BYTE2:
                            field.Value    = ParseFile.ReadSByte(UtfTableFs, constantOffset);
                            currentOffset += 1;
                            break;

                        case COLUMN_TYPE_1BYTE:
                            field.Value    = ParseFile.ReadByte(UtfTableFs, constantOffset);
                            currentOffset += 1;
                            break;

                        default:
                            throw new FormatException(String.Format("Unknown COLUMN TYPE at offset: 0x{0}", currentOffset.ToString("X8")));
                        }     // switch (field.Type & COLUMN_TYPE_MASK)
                    }
                    else if ((field.Type & COLUMN_STORAGE_MASK) == COLUMN_STORAGE_PERROW)
                    {
                        // read the constant depending on the type
                        switch (field.Type & COLUMN_TYPE_MASK)
                        {
                        case COLUMN_TYPE_STRING:
                            rowDataOffset     = ParseFile.ReadUintBE(UtfTableFs, currentRowBase + currentRowOffset);
                            field.Value       = ParseFile.ReadAsciiString(UtfTableFs, this.StringTableOffset + rowDataOffset);
                            currentRowOffset += 4;
                            break;

                        case COLUMN_TYPE_8BYTE:
                            field.Value       = ParseFile.ReadUlongBE(UtfTableFs, currentRowBase + currentRowOffset);
                            currentRowOffset += 8;
                            break;

                        case COLUMN_TYPE_DATA:
                            rowDataOffset = ParseFile.ReadUintBE(UtfTableFs, currentRowBase + currentRowOffset);
                            rowDataSize   = ParseFile.ReadUintBE(UtfTableFs, currentRowBase + currentRowOffset + 4);
                            field.Offset  = (ulong)(this.BaseOffset + this.DataOffset + rowDataOffset);
                            field.Size    = (ulong)rowDataSize;

                            // don't think this is encrypted
                            field.Value       = ParseFile.ParseSimpleOffset(SourceFs, (long)field.Offset, (int)rowDataSize);
                            currentRowOffset += 8;
                            break;

                        case COLUMN_TYPE_FLOAT:
                            field.Value       = ParseFile.ReadFloatBE(UtfTableFs, currentRowBase + currentRowOffset);
                            currentRowOffset += 4;
                            break;

                        case COLUMN_TYPE_4BYTE2:
                            field.Value       = ParseFile.ReadInt32BE(UtfTableFs, currentRowBase + currentRowOffset);
                            currentRowOffset += 4;
                            break;

                        case COLUMN_TYPE_4BYTE:
                            field.Value       = ParseFile.ReadUintBE(UtfTableFs, currentRowBase + currentRowOffset);
                            currentRowOffset += 4;
                            break;

                        case COLUMN_TYPE_2BYTE2:
                            field.Value       = ParseFile.ReadInt16BE(UtfTableFs, currentRowBase + currentRowOffset);
                            currentRowOffset += 2;
                            break;

                        case COLUMN_TYPE_2BYTE:
                            field.Value       = ParseFile.ReadUshortBE(UtfTableFs, currentRowBase + currentRowOffset);
                            currentRowOffset += 2;
                            break;

                        case COLUMN_TYPE_1BYTE2:
                            field.Value       = ParseFile.ReadSByte(UtfTableFs, currentRowBase + currentRowOffset);
                            currentRowOffset += 1;
                            break;

                        case COLUMN_TYPE_1BYTE:
                            field.Value       = ParseFile.ReadByte(UtfTableFs, currentRowBase + currentRowOffset);
                            currentRowOffset += 1;
                            break;

                        default:
                            throw new FormatException(String.Format("Unknown COLUMN TYPE at offset: 0x{0}", currentOffset.ToString("X8")));
                        } // switch (field.Type & COLUMN_TYPE_MASK)
                    }     // if ((fields[i].Type & COLUMN_STORAGE_MASK) == COLUMN_STORAGE_CONSTANT)

                    // add field to dictionary
                    this.Rows[i].Add(field.Name, field);

                    // move to next field
                    currentOffset += 5; //  sizeof(CriField.Type + CriField.NameOffset)
                }                       // for (ushort j = 0; j < this.NumberOfFields; j++)
                //}
                //catch (Exception ex)
                //{
                //    int xxxx = 1;
                //}
            } // for (uint i = 0; i < this.NumberOfRows; i++)
        }
예제 #9
0
        private NintendoU8Directory getDirectoryNode(FileStream fs, int nodeIndex,
                                                     string parentDirectory, out int lastIndexProcessed)
        {
            string newParentDirectoryName;
            uint   maxNodeIndex;
            NintendoU8Directory newSubDirectory;

            lastIndexProcessed = nodeIndex;

            // get node
            u8Node node = this.NodeList[nodeIndex];

            // get directory name
            string directoryName = ParseFile.ReadAsciiString(fs, this.NameTableOffset + node.NameOffset);

            // create directory item
            NintendoU8Directory newDirectory = new NintendoU8Directory(this.SourceFileName, directoryName, parentDirectory);

            // parse other items
            maxNodeIndex = node.DataSize;


            for (int i = (nodeIndex + 1); i < maxNodeIndex; i = (lastIndexProcessed + 1))
            {
                node = this.NodeList[i];
                newParentDirectoryName = Path.Combine(parentDirectory, directoryName);

                if (node.IsDirectory())
                {
                    newSubDirectory = this.getDirectoryNode(fs, i, newParentDirectoryName, out lastIndexProcessed);

                    if (!newSubDirectory.DirectoryName.Equals("."))
                    {
                        newDirectory.SubDirectoryArray.Add(newSubDirectory);
                    }
                    else // in current folder "."
                    {
                        // move folders to this folder
                        foreach (NintendoU8Directory d in newSubDirectory.SubDirectories)
                        {
                            newDirectory.SubDirectoryArray.Add(d);
                        }

                        // move files to this folder
                        foreach (NintendoU8File f in newSubDirectory.Files)
                        {
                            newDirectory.FileArray.Add(f);
                        }
                    }
                }
                else
                {
                    newDirectory.FileArray.Add(this.getFileNode(fs, i, newParentDirectoryName));
                    lastIndexProcessed = i;
                }
            }



            return(newDirectory);
        }