Ejemplo n.º 1
0
            public bool Sign(byte[] XboxHDKey, bool skipContentHashing, out string errorMessage)
            {
                if (Equals(null, XboxHDKey) || XboxHDKey.Length != 0x10)
                {
                    errorMessage = "Bad key";
                    return(false);
                }

                byte[] buffer, hash;

                //calculate content hashes
                if (!skipContentHashing)
                {
                    object result;
                    if (!GetSection(Types.SectionType.TableOfContents, out result))
                    {
                        errorMessage = "Failed to parse section data";
                        return(false);
                    }

                    Types.Section         section   = Sections[1];
                    Types.TableOfContents fileTable = (Types.TableOfContents)result; //parsed toc data
                    foreach (Types.TableEntry file in fileTable.entries)
                    {
                        if (!file.Exists(Path.GetDirectoryName(FilePath)))
                        {
                            errorMessage = string.Format("Content file not found: {0}", file.fileName);
                            return(false);
                        }

                        uint hashStartOffset = file.fileHashOffset;
                        uint hashLength      = file.fileHashLength;
                        uint size            = (uint)new FileInfo(Path.Combine(Path.GetDirectoryName(FilePath), file.fileName)).Length;
                        if (size != file.fileSize)
                        {
                            //errorMessage = string.Format("The size of the file \"{0}\" is invalid\n\nExpected size: {1} ({2} bytes)\nActual size: {3} ({4} bytes)", file.fileName, file.fileSize.RoundBytes(), file.fileSize, size.RoundBytes(), size);
                            //return false;

                            //instead of returning an error here I decided to correct the file size, in case of modders :)
                            buffer      = BitConverter.GetBytes(size);
                            IO.Position = (((section.sectionOffset + fileTable.entryTableOffset) + file.entryOffset) + 0x8);
                            IO.Write(buffer, 0, 4); //file size

                            //set hash to cover entire file
                            IO.Write(new byte[4], 0, 4); //hash start offset
                            IO.Write(buffer, 0, 4);      //hash length

                            hashStartOffset = 0;
                            hashLength      = size;
                        }

                        buffer = File.ReadAllBytes(Path.Combine(Path.GetDirectoryName(FilePath), file.fileName));
                        hash   = XCalcSig.CalculateDigest(buffer, (int)hashStartOffset, (int)hashLength);

                        IO.Position = ((section.sectionOffset + 0xC) + (file.fileHashIndex * 0x14));
                        IO.Write(hash, 0, 0x14);
                    }
                    IO.Flush();
                }

                //calculate section hashes
                foreach (Types.Section section in Sections)
                {
                    if (!section.IsAllocated)
                    {
                        continue;
                    }
                    buffer      = new byte[section.sectionLength];
                    IO.Position = section.sectionOffset;
                    IO.Read(buffer, 0, (int)section.sectionLength);
                    hash        = XCalcSig.CalculateDigest(buffer);
                    IO.Position = section.hashOffset;
                    IO.Write(hash, 0, 0x14);
                }
                IO.Flush();

                //calculate header "signature"
                buffer      = new byte[(Header.headerSize - 0x14)];
                IO.Position = 0x14;
                IO.Read(buffer, 0, (int)(Header.headerSize - 0x14));
                hash        = XCalcSig.CalculateNonRoamable(BitConverter.GetBytes(Header.titleId), XboxHDKey, buffer);
                IO.Position = 0;
                IO.Write(hash, 0, 0x14);
                IO.Flush();

                buffer = null;
                hash   = null;

                errorMessage = null;
                return(true);
            }
Ejemplo n.º 2
0
            /// <summary>
            /// Parses and returns a section
            /// </summary>
            /// <param name="type">Section type to parse</param>
            /// <param name="result">Contains parsed section type. Must be casted to proper type</param>
            /// <returns>Whether parse was successful</returns>
            public bool GetSection(Types.SectionType type, out object result)
            {
                result = null;
                if (Header.headerType == Types.HeaderType.Content && type == Types.SectionType.Unknown)
                {
                    return(false);
                }
                if (Header.headerType == Types.HeaderType.Update)
                {
                    if (type == Types.SectionType.Language || type == Types.SectionType.Optional)
                    {
                        return(false);
                    }
                }

                byte[] sectionData = null; //buffer to hold section data
                foreach (Types.Section section in Sections)
                {
                    if (section.sectionType == type)
                    {
                        sectionData = section.sectionData;
                        break;
                    }
                }

                if (Equals(sectionData, null) || sectionData.Length == 0 && type != Types.SectionType.Optional)
                {
                    return(false);
                }

                if (type == Types.SectionType.Optional || type == Types.SectionType.Unknown)
                {
                    result = sectionData;
                    return(true);
                }

                if (type == Types.SectionType.Language)
                {
                    result = sectionData.ToUnicode().ToString(CultureInfo.InvariantCulture);
                    return(true);
                }

                if (type == Types.SectionType.TableOfContents)
                {
                    Types.TableOfContents toc = new Types.TableOfContents();

                    using (Stream stream = new MemoryStream(sectionData))
                    {
                        byte[] buffer = new byte[0x4];

                        stream.Read(buffer, 0, 4);
                        toc.entryCount = buffer.ToUInt32(false);

                        stream.Read(buffer, 0, 4);
                        toc.unknown_0 = buffer.ToUInt32(false);

                        stream.Read(buffer, 0, 4);
                        toc.entryTableOffset = buffer.ToUInt32(false);

                        List <ushort> chain = new List <ushort>();
                        chain.Add(0);                        //always exists
                        ushort a, b;
                        while (chain.Count < toc.entryCount) //i doubt this is the proper way to parse the entry chain but this works
                        {
                            for (int i = 0; i < chain.Count; i++)
                            {
                                stream.Position = (toc.entryTableOffset + chain[i]);

                                stream.Read(buffer, 0, 2);
                                a = buffer.ToUInt16(false); //entry pointer a

                                stream.Read(buffer, 0, 2);
                                b = buffer.ToUInt16(false); //entry pointer b

                                if (a != 0 && !chain.Contains(a))
                                {
                                    chain.Add(a);
                                }
                                if (b != 0 && !chain.Contains(b))
                                {
                                    chain.Add(b);
                                }
                            }
                        }
                        toc.entryChain = chain.ToArray();

                        List <Types.TableEntry> entries = new List <Types.TableEntry>();
                        Types.TableEntry        entry;
                        foreach (ushort offset in toc.entryChain)
                        {
                            stream.Position = ((toc.entryTableOffset + offset) + 0x4);
                            entry           = new Types.TableEntry();

                            entry.entryOffset = offset;

                            Array.Resize <byte>(ref buffer, 4);

                            stream.Read(buffer, 0, 2);
                            entry.unk_0 = buffer.ToUInt16(false);

                            stream.Read(buffer, 0, 2);
                            entry.filenameLength = buffer.ToUInt16(false);

                            stream.Read(buffer, 0, 4);
                            entry.fileSize = buffer.ToUInt32(false);

                            stream.Read(buffer, 0, 4);
                            entry.fileHashOffset = buffer.ToUInt32(false);

                            stream.Read(buffer, 0, 4);
                            entry.fileHashLength = buffer.ToUInt32(false);

                            stream.Read(buffer, 0, 2);
                            entry.fileHashIndex = buffer.ToUInt16(false);

                            Array.Resize <byte>(ref buffer, entry.filenameLength);

                            stream.Read(buffer, 0, entry.filenameLength);
                            entry.fileName = buffer.ToUTF8();

                            stream.Position = ((entry.fileHashIndex * 0x14) + 0xC);
                            entry.fileHash  = new byte[0x14];
                            stream.Read(entry.fileHash, 0, 0x14);

                            entries.Add(entry);
                        }
                        toc.entries = entries.ToArray();
                    }
                    result = toc;
                    return(true);
                }

                return(false);
            }