Beispiel #1
0
        private bool DecryptBaseFile(Stream outBaseFile)
        {
            var tempStream = new MemoryStream();
            var ci         = Get <XexCompressionInfo>();

            // Incase its compressed
            XexCompressedBaseFile compBlock;

            #region Decrypt if encrypted

            if (ci.EncryptionType == XexEncryptionType.Encrypted)
            {
                #region Calculate our key

                var aes = Rijndael.Create();
                aes.Padding = PaddingMode.None;
                var ms         = new MemoryStream(Header.AesKey);
                var decryptKey = new byte[0x10];
                using (var decrypt = new CryptoStream(ms, aes.CreateDecryptor(_retailKey2, new byte[0x10]), CryptoStreamMode.Read))
                {
                    decrypt.Read(decryptKey, 0, 0x10);
                }

                #endregion

                // Now decrypt our data
                aes         = Rijndael.Create();
                aes.Padding = PaddingMode.None;
                var dataStream = Binary.GetStream();
                dataStream.Seek(DataOffset, SeekOrigin.Begin);
                using (var decrypt = new CryptoStream(dataStream, aes.CreateDecryptor(decryptKey, new byte[0x10]), CryptoStreamMode.Read))
                {
                    #region Decrypt non compressed

                    if (ci.CompressionType == XexCompressionType.NotCompressed)
                    {
                        // Loop through each section and decrypt
                        foreach (var block in ci.RawBlocks)
                        {
                            var buffer = new byte[block.DataSize];
                            decrypt.Read(buffer, 0, buffer.Length);
                            outBaseFile.Write(buffer, 0, buffer.Length);
                            outBaseFile.Write(new byte[block.ZeroSize], 0, block.ZeroSize);
                        }

                        // Set our length to image size
                        outBaseFile.Seek(0, SeekOrigin.Begin);
                        outBaseFile.SetLength(Header.ImageSize);

                        // Return true
                        return(true);
                    }

                    #endregion

                    #region Decrypt compressed

                    compBlock = ci.CompressedBaseFile;

                    var index = 0;
                    while (compBlock.DataSize != 0)
                    {
                        var testData = new byte[compBlock.DataSize];
                        dataStream.Read(testData, 0, compBlock.DataSize);
                        dataStream.Seek(compBlock.DataSize * -1, SeekOrigin.Current);

                        // Decrypt our data size
                        var buffer = new byte[compBlock.DataSize];
                        decrypt.Read(buffer, 0, buffer.Length);

                        // Verify our hash
                        var hash = SHA1.Create().ComputeHash(buffer);
                        for (var x = 0; x < 0x14; x++)
                        {
                            if (hash[x] != compBlock.Hash[x])
                            {
                                throw new Exception("Bad hash");
                            }
                        }

                        // Write each block
                        tempStream.Write(buffer, 0, compBlock.DataSize);

                        compBlock = ModelFactory.GetModel <XexCompressedBaseFile>(buffer);
                        index     = index + 1;
                    }

                    tempStream.Seek(0, SeekOrigin.Begin);

                    #endregion
                }
                dataStream.Close();
            }
            else
            {
                #region Write out non compressed

                if (ci.CompressionType == XexCompressionType.NotCompressed)
                {
                    // Loop through each section and decrypt
                    foreach (var block in ci.RawBlocks)
                    {
                        var buffer = Binary.ReadBytes((int)DataOffset, block.DataSize);
                        outBaseFile.Write(buffer, 0, buffer.Length);
                        outBaseFile.Write(new byte[block.ZeroSize], 0, block.ZeroSize);
                    }

                    // Set our length to image size
                    outBaseFile.Seek(0, SeekOrigin.Begin);
                    outBaseFile.SetLength(Header.ImageSize);

                    // Return true
                    return(true);
                }

                #endregion

                // Since we didnt write to the temp stream
                // lets just take it from the file
            }

            #endregion

            // Time to work with compresed
            var sizeLeft = (int)Header.ImageSize;
            compBlock = ci.CompressedBaseFile;

            #region Handle Delta Compresed

            if (ci.CompressionType == XexCompressionType.DeltaCompressed)
            {
                while (compBlock.DataSize != 0)
                {
                    var buffer = new byte[compBlock.DataSize];
                    tempStream.Read(buffer, 0, buffer.Length);
                    outBaseFile.Write(buffer, 0, compBlock.DataSize);

                    compBlock = ModelFactory.GetModel <XexCompressedBaseFile>(buffer);
                }

                // Seek back to start
                outBaseFile.Seek(0, SeekOrigin.Begin);

                // return
                return(true);
            }

            #endregion

            #region Decompress if compressed

            #region Create Decompression Ctx

            int maxSize = 0x8000, ctx = -1, unknown = 0;
            XCompress.LzxDecompress lzx;
            lzx.CpuType    = 1;
            lzx.WindowSize = ci.CompressedBaseFile.CompressionWindow;
            IntPtr allocate = Marshal.AllocHGlobal(0x23200);
            if (XCompress.LDICreateDecompression(ref maxSize, ref lzx,
                                                 0, 0, allocate, ref unknown, ref ctx) != 0)
            {
                throw new Exception("Failed to create decompression");
            }

            #endregion

            while (compBlock.DataSize != 0)
            {
                var buffer = new byte[compBlock.DataSize];
                tempStream.Read(buffer, 0, buffer.Length);

                compBlock = ModelFactory.GetModel <XexCompressedBaseFile>(buffer);
                var offset = compBlock.OffsetTableSize;

                #region Decompress

                while (true)
                {
                    int compressedLen = BitConverter.ToUInt16(buffer, offset);
                    if (compressedLen == 0)
                    {
                        break;
                    }
                    offset += 2;
                    var compressedData = new byte[compressedLen];
                    Buffer.BlockCopy(buffer, offset, compressedData, 0, compressedLen);
                    offset += compressedLen;
                    var decompressedLength = (sizeLeft < 0x8000) ? sizeLeft : 0x8000;
                    var decompressedData   = new byte[decompressedLength];
                    if (XCompress.LDIDecompress(ctx, compressedData,
                                                compressedLen, decompressedData, ref decompressedLength) != 0)
                    {
                        throw new Exception("Failed to decompress");
                    }
                    outBaseFile.Write(decompressedData, 0, decompressedLength);
                    sizeLeft -= decompressedLength;
                }

                #endregion
            }

            #region Destroy ctx

            if (XCompress.LDIDestroyDecompression(ctx) != 0)
            {
                throw new Exception("Failed to destroy decompression");
            }
            Marshal.FreeHGlobal(allocate);

            #endregion

            #endregion

            // Move back to the begining
            outBaseFile.Seek(0, SeekOrigin.Begin);
            outBaseFile.SetLength(Header.ImageSize);

            // All done
            return(true);
        }