public Ini1(Stream stream) { StreamSource = new SharedStreamSource(stream); Stream initStream = StreamSource.CreateStream(); var reader = new BinaryReader(initStream); Magic = reader.ReadAscii(4); if (Magic != "INI1") { throw new InvalidDataException("Invalid INI1 file!"); } Size = reader.ReadInt32(); KipCount = reader.ReadInt32(); Kips = new Kip[KipCount]; int offset = 0x10; for (int i = 0; i < KipCount; i++) { // How to get the KIP's size the lazy way var kip = new Kip(StreamSource.CreateStream(offset)); Kips[i] = new Kip(StreamSource.CreateStream(offset, kip.Size)); offset += kip.Size; } }
public Savefile(Keyset keyset, Stream file, IntegrityCheckLevel integrityCheckLevel) { SavefileSource = new SharedStreamSource(file); Header = new Header(keyset, SavefileSource); FsLayout layout = Header.Layout; DataRemapStorage = new RemapStorage(SavefileSource.CreateStream(layout.FileMapDataOffset, layout.FileMapDataSize), Header.FileRemap, Header.FileMapEntries); DuplexData = InitDuplexStream(DataRemapStorage, Header); MetaRemapStorage = new RemapStorage(DuplexData, Header.MetaRemap, Header.MetaMapEntries); Stream journalTable = MetaRemapStorage.OpenStream(layout.JournalTableOffset, layout.JournalTableSize); MappingEntry[] journalMap = JournalStream.ReadMappingEntries(journalTable, Header.Journal.MainDataBlockCount); Stream journalData = DataRemapStorage.OpenStream(layout.JournalDataOffset, layout.JournalDataSizeB + layout.SizeReservedArea); var journalStream = new JournalStream(journalData, journalMap, (int)Header.Journal.BlockSize); JournalStreamSource = new SharedStreamSource(journalStream); IvfcStream = InitIvfcStream(integrityCheckLevel); SaveFs = new SaveFs(IvfcStream, MetaRemapStorage.OpenStream(layout.FatOffset, layout.FatSize), Header.Save); IvfcStreamSource = new SharedStreamSource(IvfcStream); }
public Romfs(Stream stream) { StreamSource = new SharedStreamSource(stream); byte[] dirMetaTable; byte[] fileMetaTable; using (var reader = new BinaryReader(StreamSource.CreateStream(), Encoding.Default, true)) { Header = new RomfsHeader(reader); reader.BaseStream.Position = Header.DirMetaTableOffset; dirMetaTable = reader.ReadBytes((int)Header.DirMetaTableSize); reader.BaseStream.Position = Header.FileMetaTableOffset; fileMetaTable = reader.ReadBytes((int)Header.FileMetaTableSize); } using (var reader = new BinaryReader(new MemoryStream(dirMetaTable))) { int position = 0; while (position + 20 < Header.DirMetaTableSize) { var dir = new RomfsDir(reader) { Offset = position }; Directories.Add(dir); if (dir.ParentDirOffset == position) { RootDir = dir; } position = (int)reader.BaseStream.Position; } } using (var reader = new BinaryReader(new MemoryStream(fileMetaTable))) { int position = 0; while (position + 20 < Header.FileMetaTableSize) { var file = new RomfsFile(reader) { Offset = position }; Files.Add(file); position = (int)reader.BaseStream.Position; } } SetReferences(); RomfsEntry.ResolveFilenames(Files); RomfsEntry.ResolveFilenames(Directories); FileDict = Files.ToDictionary(x => x.FullPath, x => x); }
public Kip(Stream stream) { StreamSource = new SharedStreamSource(stream); Header = new KipHeader(StreamSource.CreateStream()); Size = HeaderSize; for (int index = 0; index < Header.Sections.Length; index++) { int sectionSize = Header.Sections[index].CompressedSize; SectionOffsets[index] = Size; Size += sectionSize; } }
public Nso(Stream stream) { StreamSource = new SharedStreamSource(stream); var reader = new BinaryReader(StreamSource.CreateStream()); if (reader.ReadAscii(4) != "NSO0") { throw new InvalidDataException("NSO magic is incorrect!"); } reader.ReadUInt32(); // Version reader.ReadUInt32(); // Reserved/Unused var flags = new BitArray(new[] { (int)reader.ReadUInt32() }); var textSection = new NsoSection(StreamSource); var rodataSection = new NsoSection(StreamSource); var dataSection = new NsoSection(StreamSource); textSection.IsCompressed = flags[0]; rodataSection.IsCompressed = flags[1]; dataSection.IsCompressed = flags[2]; textSection.CheckHash = flags[3]; rodataSection.CheckHash = flags[4]; dataSection.CheckHash = flags[5]; textSection.ReadSegmentHeader(reader); reader.ReadUInt32(); // Module offset (TODO) rodataSection.ReadSegmentHeader(reader); reader.ReadUInt32(); // Module file size dataSection.ReadSegmentHeader(reader); BssSize = reader.ReadUInt32(); reader.Read(BuildId, 0, 0x20); textSection.CompressedSize = reader.ReadUInt32(); rodataSection.CompressedSize = reader.ReadUInt32(); dataSection.CompressedSize = reader.ReadUInt32(); reader.ReadBytes(0x1C); // Padding RodataRelativeExtents = new[] { new RodataRelativeExtent(reader), new RodataRelativeExtent(reader), new RodataRelativeExtent(reader) }; reader.Read(textSection.Hash, 0, 0x20); reader.Read(rodataSection.Hash, 0, 0x20); reader.Read(dataSection.Hash, 0, 0x20); Sections = new[] { textSection, rodataSection, dataSection }; reader.Close(); }
public Package2(Keyset keyset, Stream stream) { StreamSource = new SharedStreamSource(stream); SharedStream headerStream = StreamSource.CreateStream(0, 0x200); KeyRevision = FindKeyGeneration(keyset, headerStream); Key = keyset.Package2Keys[KeyRevision]; Header = new Package2Header(headerStream, Key); PackageSize = BitConverter.ToInt32(Header.Counter, 0) ^ BitConverter.ToInt32(Header.Counter, 8) ^ BitConverter.ToInt32(Header.Counter, 12); HeaderVersion = Header.Counter[4] ^ Header.Counter[6] ^ Header.Counter[7]; if (PackageSize != 0x200 + Header.SectionSizes[0] + Header.SectionSizes[1] + Header.SectionSizes[2]) { throw new InvalidDataException("Package2 Header is corrupt!"); } }
public Package1(Keyset keyset, Stream stream) { StreamSource = new SharedStreamSource(stream); var reader = new BinaryReader(stream); BuildHash = reader.ReadBytes(0x10); BuildDate = reader.ReadAscii(0xE); Field1E = reader.ReadUInt16(); reader.BaseStream.Position = 0x3FE0; Pk11Size = reader.ReadInt32(); reader.BaseStream.Position += 0xC; Counter = reader.ReadBytes(0x10); // Try decrypting the PK11 blob with all known package1 keys Stream encStream = StreamSource.CreateStream(0x4000, Pk11Size); var decBuffer = new byte[0x10]; for (int i = 0; i < 0x20; i++) { var dec = new Aes128CtrStream(encStream, keyset.Package1Keys[i], Counter); dec.Read(decBuffer, 0, 0x10); if (BitConverter.ToUInt32(decBuffer, 0) == Pk11Magic) { KeyRevision = i; dec.Position = 0; Pk11 = new Pk11(new RandomAccessSectorStream(dec)); return; } } throw new InvalidDataException("Failed to decrypt PK11! Is the correct key present?"); }
public Savefile(Keyset keyset, Stream file, bool enableIntegrityChecks) { SavefileSource = new SharedStreamSource(file); using (var reader = new BinaryReader(SavefileSource.CreateStream(), Encoding.Default, true)) { Header = new Header(keyset, reader); FsLayout layout = Header.Layout; FileRemap = new RemapStream( SavefileSource.CreateStream(layout.FileMapDataOffset, layout.FileMapDataSize), Header.FileMapEntries, Header.FileRemap.MapSegmentCount); FileRemapSource = new SharedStreamSource(FileRemap); var duplexLayers = new DuplexFsLayerInfo[3]; duplexLayers[0] = new DuplexFsLayerInfo { DataA = new MemoryStream(Header.DuplexMasterA), DataB = new MemoryStream(Header.DuplexMasterB), Info = Header.Duplex.Layers[0] }; duplexLayers[1] = new DuplexFsLayerInfo { DataA = FileRemapSource.CreateStream(layout.DuplexL1OffsetA, layout.DuplexL1Size), DataB = FileRemapSource.CreateStream(layout.DuplexL1OffsetB, layout.DuplexL1Size), Info = Header.Duplex.Layers[1] }; duplexLayers[2] = new DuplexFsLayerInfo { DataA = FileRemapSource.CreateStream(layout.DuplexDataOffsetA, layout.DuplexDataSize), DataB = FileRemapSource.CreateStream(layout.DuplexDataOffsetB, layout.DuplexDataSize), Info = Header.Duplex.Layers[2] }; DuplexL1A = FileRemapSource.CreateStream(layout.DuplexL1OffsetA, layout.DuplexL1Size); DuplexL1B = FileRemapSource.CreateStream(layout.DuplexL1OffsetB, layout.DuplexL1Size); DuplexDataA = FileRemapSource.CreateStream(layout.DuplexDataOffsetA, layout.DuplexDataSize); DuplexDataB = FileRemapSource.CreateStream(layout.DuplexDataOffsetB, layout.DuplexDataSize); JournalData = FileRemapSource.CreateStream(layout.JournalDataOffset, layout.JournalDataSizeB + layout.SizeReservedArea); DuplexData = new LayeredDuplexFs(duplexLayers, Header.Layout.DuplexIndex == 1); MetaRemap = new RemapStream(DuplexData, Header.MetaMapEntries, Header.MetaRemap.MapSegmentCount); MetaRemapSource = new SharedStreamSource(MetaRemap); JournalTable = MetaRemapSource.CreateStream(layout.JournalTableOffset, layout.JournalTableSize); JournalBitmapUpdatedPhysical = MetaRemapSource.CreateStream(layout.JournalBitmapUpdatedPhysicalOffset, layout.JournalBitmapUpdatedPhysicalSize); JournalBitmapUpdatedVirtual = MetaRemapSource.CreateStream(layout.JournalBitmapUpdatedVirtualOffset, layout.JournalBitmapUpdatedVirtualSize); JournalBitmapUnassigned = MetaRemapSource.CreateStream(layout.JournalBitmapUnassignedOffset, layout.JournalBitmapUnassignedSize); JournalLayer1Hash = MetaRemapSource.CreateStream(layout.IvfcL1Offset, layout.IvfcL1Size); JournalLayer2Hash = MetaRemapSource.CreateStream(layout.IvfcL2Offset, layout.IvfcL2Size); JournalLayer3Hash = MetaRemapSource.CreateStream(layout.IvfcL3Offset, layout.IvfcL3Size); JournalFat = MetaRemapSource.CreateStream(layout.FatOffset, layout.FatSize); AllocationTable = new AllocationTable(JournalFat); MappingEntry[] journalMap = JournalStream.ReadMappingEntries(JournalTable, Header.Journal.MainDataBlockCount); SharedStream journalData = FileRemapSource.CreateStream(layout.JournalDataOffset, layout.JournalDataSizeB + layout.SizeReservedArea); JournalStream = new JournalStream(journalData, journalMap, (int)Header.Journal.BlockSize); JournalStreamSource = new SharedStreamSource(JournalStream); IvfcStream = InitIvfcStream(enableIntegrityChecks); IvfcStreamSource = new SharedStreamSource(IvfcStream); ReadFileInfo(); var dictionary = new Dictionary <string, FileEntry>(); foreach (FileEntry entry in Files) { dictionary[entry.FullPath] = entry; } FileDict = dictionary; } }
public Header(Keyset keyset, SharedStreamSource streamSource) { var reader = new BinaryReader(streamSource.CreateStream()); reader.BaseStream.Position = 0; Data = reader.ReadBytes(0x4000); reader.BaseStream.Position = 0; Cmac = reader.ReadBytes(0x10); reader.BaseStream.Position = 0x100; Layout = new FsLayout(reader); reader.BaseStream.Position = 0x300; Duplex = new DuplexHeader(reader); reader.BaseStream.Position = 0x344; Ivfc = new IvfcHeader(reader); reader.BaseStream.Position = 0x408; Journal = new JournalHeader(reader); reader.BaseStream.Position = 0x608; Save = new SaveHeader(reader); reader.BaseStream.Position = 0x650; FileRemap = new RemapHeader(reader); reader.BaseStream.Position = 0x690; MetaRemap = new RemapHeader(reader); reader.BaseStream.Position = 0x6D8; ExtraData = new ExtraData(reader); reader.BaseStream.Position = Layout.IvfcMasterHashOffsetA; MasterHashA = reader.ReadBytes((int)Layout.IvfcMasterHashSize); reader.BaseStream.Position = Layout.IvfcMasterHashOffsetB; MasterHashB = reader.ReadBytes((int)Layout.IvfcMasterHashSize); MasterHash = streamSource.CreateStream(Layout.IvfcMasterHashOffsetA, Layout.IvfcMasterHashSize); reader.BaseStream.Position = Layout.DuplexMasterOffsetA; DuplexMasterA = reader.ReadBytes((int)Layout.DuplexMasterSize); reader.BaseStream.Position = Layout.DuplexMasterOffsetB; DuplexMasterB = reader.ReadBytes((int)Layout.DuplexMasterSize); reader.BaseStream.Position = Layout.FileMapEntryOffset; FileMapEntries = new MapEntry[FileRemap.MapEntryCount]; for (int i = 0; i < FileRemap.MapEntryCount; i++) { FileMapEntries[i] = new MapEntry(reader); } reader.BaseStream.Position = Layout.MetaMapEntryOffset; MetaMapEntries = new MapEntry[MetaRemap.MapEntryCount]; for (int i = 0; i < MetaRemap.MapEntryCount; i++) { MetaMapEntries[i] = new MapEntry(reader); } HeaderHashValidity = Crypto.CheckMemoryHashTable(Data, Layout.Hash, 0x300, 0x3d00); SignatureValidity = ValidateSignature(keyset); }