private long partitionStreamWrite(LongRef outSize, Stream inStream, Stream target, long size, DatData settingsData, NkitPartitionPatchInfo patchInfo, WiiHashStore hashes, Coordinator pc) { DatData data = settingsData; List <string> addedFiles = new List <string>(); DateTime dt = DateTime.Now; MemorySection hdr = MemorySection.Read(inStream, 0x440); long srcPos = hdr.Size; long outPos = 0; long imageSize = 0; try { if (hdr.ReadString(0, 4) == "\0\0\0\0") { long nullsPos = 0; long fileLength = -1; LongRef gapLength = new LongRef() { Value = -1 }; target.Write(hdr.Data, 0, (int)hdr.Size); MemorySection sz = MemorySection.Read(inStream, 4); srcPos += 4; outPos += hdr.Size; imageSize = sz.ReadUInt32B(0) * 4L; outSize.Value = NStream.HashedLenToData(imageSize); JunkStream junk = new JunkStream(hdr.Read(0, 4), hdr.Read8(6), outSize.Value); //SET LENGTH FROM HEADER outPos += writeGap(ref fileLength, gapLength, ref nullsPos, ref srcPos, outPos, inStream, target, junk, true, patchInfo.ScrubManager); } else { string idVer = hdr.ReadString(0x200, 8); if (idVer != "NKIT v01") { throw new Exception(string.Format("{0} not supported by this version", idVer)); } bool isNkit = idVer.StartsWith("NKIT"); imageSize = NStream.HashedLenToData((hdr.ReadUInt32B(0x210) * 4L)); outSize.Value = imageSize; string junkId = hdr.ReadString(0x214, 4); JunkStream junk = new JunkStream(hdr.Read(0, 4), hdr.Read8(6), imageSize); //SET LENGTH FROM HEADER MemorySection fst; long mainDolAddr = hdr.ReadUInt32B(0x420); //############################################################################ //# READ DISC START MemorySection hdrToFst = MemorySection.Read(inStream, (hdr.ReadUInt32B(0x424) * 4L) - hdr.Size); srcPos += hdrToFst.Size; fst = MemorySection.Read(inStream, hdr.ReadUInt32B(0x428) * 4L); long postFstPos = (hdr.ReadUInt32B(0x424) * 4L) + fst.Size; srcPos += fst.Size; hashes.WriteFlagsData(imageSize, inStream); srcPos += hashes.FlagsLength; patchInfo.PartitionDataHeader = hdr; patchInfo.Fst = fst; //############################################################################ //# WRITE DISC START target.Write(hdr.Data, 0, (int)hdr.Size); target.Write(hdrToFst.Data, 0, (int)hdrToFst.Size); //padded when read target.Write(fst.Data, 0, fst.Data.Length); hdrToFst = null; //let this be collected if needed outPos = (hdr.ReadUInt32B(0x424) * 4L) + fst.Size; long nullsPos = outPos + 0x1c; string error; List <ConvertFile> conFiles = NkitFormat.GetConvertFstFiles(inStream, size, hdr, fst, false, -1, out error); if (conFiles == null) { if (error != null) { _log?.LogDetail(error); } ConvertFile cf = new ConvertFile(imageSize - srcPos, true) //result.ImageInfo.IsoSize { FstFile = new FstFile(null) { DataOffset = hdr.ReadUInt32B(0x424), Offset = hdr.ReadUInt32B(0x424), Length = (int)fst.Size }, }; outPos += writeGap(cf, ref nullsPos, ref srcPos, outPos, inStream, target, junk, true, patchInfo.ScrubManager); } else { conFiles[0].GapLength -= hashes.FlagsLength; //fix for a few customs (no gap between the fst and the first file on the source image, but the hash mask makes it look like there is) //########### FILES bool firstFile = true; for (int i = 0; i < conFiles.Count; i++) //read the files and write them out as goodFiles (possible order difference { ConvertFile f = conFiles[i]; FstFile ff = f.FstFile; if (!firstFile) //fst already written { //Debug.WriteLine(string.Format(@"{0}>{1} : {2}>{3} : {4} : {5}/{6}", ff.DataOffset.ToString("X8"), outPos.ToString("X8"), (ff.DataOffset + ff.Length).ToString("X8"), (outPos + ff.Length).ToString("X8"), ff.Length.ToString("X8"), ff.Path, ff.Name)); if (srcPos < ff.DataOffset) //skip any padding (not written for wii currently) { inStream.Copy(ByteStream.Zeros, ff.DataOffset - srcPos); //skip any 32k align padding etc srcPos += ff.DataOffset - srcPos; } //write file if (ff.DataOffset == mainDolAddr) { hdr.WriteUInt32B(0x420, (uint)(outPos / 4L)); } fst.WriteUInt32B(ff.OffsetInFstFile, (uint)(outPos / 4L)); outPos += copyFile(f, ref nullsPos, ref srcPos, outPos, inStream, target); } if (outPos < imageSize) { long gapLen = writeGap(f, ref nullsPos, ref srcPos, outPos, inStream, target, junk, i == 0 || i == conFiles.Count - 1, patchInfo.ScrubManager); outPos += gapLen; if (!firstFile) { fst.WriteUInt32B(ff.OffsetInFstFile + 4, (uint)(ff.Length)); } } firstFile = false; } } } return(srcPos); } catch (Exception ex) { throw pc.SetReaderException(ex, "NkitReaderWii.Read - partitionRead"); } }
public bool Unscrub(List <JunkRedumpPatch> junkPatches) { bool changed = false; //bool performCheck = true; //start on the assumption last was valid as it would be hassle to work out List <FstFile> nulls = new List <FstFile>(); bool good = _data.IsValid(false); //forces decrypt and hash cache build and test - does not test data in blocks matchs H0 table Parallel.For(0, _data.UsedBlocks, bi => _unscrubValid[bi] = _data.BlockIsValid(bi)); //test data matches H0 table for (int bi = 0; bi < _data.UsedBlocks; bi++) { if (!_unscrubValid[bi]) { if (_junk == null) { _junk = new JunkStream(_partHdr.Id, _partHdr.DiscNo, _partHdr.PartitionDataSize); } _junk.Position = NStream.OffsetToData(this.Offset + _data.BlockDataOffset(bi), true); _junk.Read(_data.Decrypted, _data.BlockDataOffset(bi), 0x7c00); _data.MarkBlockUnscrubbedAndDirty(bi); changed = true; } } if (junkPatches != null && junkPatches.Count != 0) { foreach (JunkRedumpPatch jp in junkPatches) { if (jp.Offset >= this.DiscOffset && jp.Offset < this.DiscOffset + this.Size) { Array.Copy(jp.Data, 0, _data.Decrypted, jp.Offset - this.DiscOffset, jp.Data.Length); _data.MarkBlockDirty((int)((jp.Offset - this.DiscOffset) / 0x8000)); //560de532 } } } if (changed) { good = _data.IsValid(true); //true as changes were made if (!good) { bool zerod = false; List <Tuple <long, int, FstFile> > h3Nulls = new List <Tuple <long, int, FstFile> >(_partHdr.ScrubManager.H3Nulls); if (h3Nulls.Count != 0) { int dataLen = (int)NStream.HashedLenToData(this.Decrypted.Length); foreach (Tuple <long, int, FstFile> n in h3Nulls) { if (n.Item1 >= this.DataOffset && n.Item1 < this.DataOffset + dataLen) { int idx = (int)((n.Item1 - this.DataOffset) / 0x7c00); _data.MarkBlockDirty(idx); int pos = (int)NStream.DataToOffset(n.Item1 - this.DataOffset, true); Array.Clear(_data.Decrypted, pos, n.Item2); zerod = true; } } } if (zerod) { good = _data.IsValid(true); } if (!good) { this.H3Errors++; } } } return(changed); }
internal WiiPartitionHeaderSection(WiiDiscHeaderSection header, NStream stream, long discOffset, byte[] data, long size) : base(stream, discOffset, data, size) { _hdr = header; _fileSystem = null; Aes = Aes.Create(); _sha1 = SHA1.Create(); Aes.Padding = PaddingMode.None; _dataOffset = this.ReadUInt32B(0x2b8) * 4L; PartitionSize = this.ReadUInt32B(0x2bc) * 4L; PartitionDataSize = NStream.HashedLenToData(PartitionSize); int h3Offset = (int)this.ReadUInt32B(0x2b4) * 4; int tmdOffset = (int)(this.ReadUInt32B(0x2a8) * 4); if (h3Offset != 0) { H3Table = this.Read(h3Offset, 0x18000); } if (tmdOffset != 0) { ContentSha1 = this.Read(tmdOffset + 0x1e4 + 0x10, 20); } // Determine the common key to use. string issuer = Encoding.ASCII.GetString(this.Read(0x140, 64)).TrimEnd('\0'); IsRvt = issuer == "Root-CA00000002-XS00000006"; //Use the RVT-R key. IsKorean = !IsRvt && this.Read8(0x1f1) == 1; //Use the Korean Key IsRvtR = !(IsRvtH = IsRvt && PartitionSize == 0); if (IsRvtH) { return; //notsupported } int i = IsRvt ? 0 : IsKorean ? 1 : 2; byte[] lame = Convert.FromBase64String(_lame); byte[] l = new byte[lame.Length / 3]; for (int j = 0; j < l.Length; i += 3) { l[j++] = lame[i]; } Aes.Key = l; byte[] titleKey = this.Read(0x1bf, 16); byte[] iv = this.Read(0x1dc, 16); Array.Clear(iv, 8, 8); Aes.IV = iv; using (ICryptoTransform cryptor = Aes.CreateDecryptor()) cryptor.TransformBlock(titleKey, 0, 16, titleKey, 0); this.Key = titleKey; Aes.Key = this.Key; //decrypt scrubbed values. This is to allow the comparison of scrubbed partition data in the decrypted layer DecryptedScrubbed00 = new byte[16]; DecryptedScrubbedFF = new byte[] { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; Aes.IV = (byte[])DecryptedScrubbedFF.Clone(); //if properly scrubbed then the KEY is FFs too using (ICryptoTransform cryptor = Aes.CreateDecryptor()) cryptor.TransformBlock(DecryptedScrubbedFF, 0, 16, DecryptedScrubbedFF, 0); Aes.IV = new byte[16]; using (ICryptoTransform cryptor = Aes.CreateDecryptor()) cryptor.TransformBlock(DecryptedScrubbed00, 0, 16, DecryptedScrubbed00, 0); _scrubManager = new ScrubManager(this); }