コード例 #1
0
ファイル: PkgView.cs プロジェクト: ntchris/LibOrbisPkg
        public PkgView(IFile pkg)
        {
            InitializeComponent();
            using (var s = pkg.GetStream())
                ObjectPreview(new LibOrbisPkg.PKG.PkgReader(s).ReadHeader());
            using (var s = pkg.GetStream())
                this.pkg = new PkgReader(s).ReadPkg();
            try
            {
                var package  = PackageReader.ReadPackageFromFile(pkg);
                var innerPfs = PackageReader.ReadPackageFromFile(package.GetFile("/pfs_image.dat"));
                var view     = new PackageView(innerPfs, PackageManager.GetInstance());
                view.Dock = DockStyle.Fill;
                filesTab.Controls.Add(view);
            } catch (Exception) {
                tabControl1.TabPages.Remove(filesTab);
            }

            foreach (var e in this.pkg.Metas.Metas)
            {
                var lvi = new ListViewItem(new[] {
                    e.id.ToString(),
                    string.Format("0x{0:X}", e.DataSize),
                    string.Format("0x{0:X}", e.DataOffset),
                    e.Encrypted ? "Yes" : "No",
                    e.KeyIndex.ToString(),
                });
                lvi.Tag = e;
                entriesListView.Items.Add(lvi);
            }
        }
コード例 #2
0
 public void WriteBody(Pkg pkg)
 {
     s.Position = (long)pkg.Header.body_offset;
     foreach (var entry in pkg.Entries)
     {
         // Align to 16 bytes
         s.Position += (16 - (s.Position % 16)) % 16;
         entry.Write(s);
     }
 }
コード例 #3
0
        public Pkg ReadPkg()
        {
            var header = ReadHeader();

            s.Position = 0xFE0;
            var headerDigest    = s.ReadBytes(32);
            var headerSignature = s.ReadBytes(256);

            s.Position = header.entry_table_offset;
            var metasEntry = new MetasEntry();

            for (var i = 0; i < header.entry_count; i++)
            {
                metasEntry.Metas.Add(MetaEntry.Read(s));
            }
            var pkg = new Pkg
            {
                Header          = header,
                HeaderDigest    = headerDigest,
                HeaderSignature = headerSignature,
                Metas           = metasEntry,
            };

            foreach (var entry in pkg.Metas.Metas)
            {
                switch (entry.id)
                {
                case EntryId.PARAM_SFO:
                    s.Position   = entry.DataOffset;
                    pkg.ParamSfo = new SfoEntry(SFO.ParamSfo.FromStream(s));
                    break;

                case EntryId.ENTRY_KEYS:
                    pkg.EntryKeys = KeysEntry.Read(entry, s);
                    break;

                case EntryId.IMAGE_KEY:
                    s.Position   = entry.DataOffset;
                    pkg.ImageKey = new GenericEntry(EntryId.IMAGE_KEY)
                    {
                        FileData = s.ReadBytes((int)entry.DataSize),
                        meta     = entry
                    };
                    break;

                case EntryId.GENERAL_DIGESTS:
                    s.Position         = entry.DataOffset;
                    pkg.GeneralDigests = GeneralDigestsEntry.Read(s);
                    break;
                }
            }
            return(pkg);
        }
コード例 #4
0
 public void WritePkg(Pkg pkg)
 {
     WriteHeader(pkg.Header);
     s.Position = 0xFE0;
     Write(pkg.PackageDigest);
     s.Position = 0x1000;
     Write(pkg.UnkKey);
     s.Position = (long)pkg.Header.body_offset;
     foreach (var entry in pkg.Entries)
     {
         entry.Write(s);
     }
 }
コード例 #5
0
        private byte[] GenLicenseInfo(Pkg pkg)
        {
            var info = new LicenseInfo(
                pkg.Header.content_id,
                pkg.Header.content_type,
                project.volume.Package.EntitlementKey.FromHexCompact());

            using (var ms = new MemoryStream())
            {
                new LicenseInfoWriter(ms).Write(info);
                ms.SetLength(0x200);
                return(ms.ToArray());
            }
        }
コード例 #6
0
 public void WriteBody(Pkg pkg, string contentId, string passcode)
 {
     foreach (var entry in pkg.Entries)
     {
         s.Position = entry.meta.DataOffset;
         if (entry.meta.Encrypted)
         {
             entry.WriteEncrypted(s, contentId, passcode);
         }
         else
         {
             entry.Write(s);
         }
     }
 }
コード例 #7
0
        /// <summary>
        /// Decrypts the given entry using the entry encryption.
        /// Throws an exception if it can't be decrypted.
        /// </summary>
        public static byte[] Decrypt(byte[] entryBytes, Pkg pkg, MetaEntry meta)
        {
            if (meta.KeyIndex != 3)
            {
                throw new Exception("We only have the key for encryption key 3");
            }
            var iv_key = Crypto.Sha256(
                meta.GetBytes()
                .Concat(Crypto.RSA2048Decrypt(pkg.EntryKeys.Keys[3].key, RSAKeyset.PkgDerivedKey3Keyset))
                .ToArray());
            var tmp = new byte[entryBytes.Length];

            Crypto.AesCbcCfb128Decrypt(tmp, entryBytes, tmp.Length, iv_key.Skip(16).Take(16).ToArray(), iv_key.Take(16).ToArray());
            return(tmp);
        }
コード例 #8
0
        /// <summary>
        /// Calculates and writes the digests for the body (entries / SC filesystem)
        /// </summary>
        /// <param name="pkg"></param>
        /// <param name="s"></param>
        private static void CalcBodyDigests(Pkg pkg, Stream s)
        {
            // Entry digests
            var digests       = pkg.Digests;
            var digestsOffset = pkg.Metas.Metas.Where(m => m.id == EntryId.DIGESTS).First().DataOffset;

            for (var i = 1; i < pkg.Metas.Metas.Count; i++)
            {
                var meta = pkg.Metas.Metas[i];
                var hash = Crypto.Sha256(s, meta.DataOffset, meta.DataSize);
                Buffer.BlockCopy(hash, 0, digests.FileData, 32 * i, 32);
                s.Position = digestsOffset + 32 * i;
                s.Write(hash, 0, 32);
            }

            // Body Digest: SHA256 hash of entire body segment
            pkg.Header.body_digest = Crypto.Sha256(s, (long)pkg.Header.body_offset, (long)pkg.Header.body_size);
            // Digest table hash: SHA256 hash of digest table
            pkg.Header.digest_table_hash = Crypto.Sha256(pkg.Digests.FileData);

            using (var ms = new MemoryStream())
            {
                // SC Entries Hash 1: Hash of 5 SC entries
                foreach (var entry in new Entry[] { pkg.EntryKeys, pkg.ImageKey, pkg.GeneralDigests, pkg.Metas, pkg.Digests })
                {
                    new SubStream(s, entry.meta.DataOffset, entry.meta.DataSize).CopyTo(ms);
                }
                pkg.Header.sc_entries1_hash = Crypto.Sha256(ms);
                if (ms.Length != pkg.Header.main_ent_data_size)
                {
                    throw new Exception("main_ent_data_size did not match SC entries 1 size. Report this bug.");
                }
                // SC Entries Hash 2: Hash of 4 SC entries
                ms.SetLength(0);
                foreach (var entry in new Entry[] { pkg.EntryKeys, pkg.ImageKey, pkg.GeneralDigests, pkg.Metas })
                {
                    long size = entry.meta.DataSize;
                    if (entry.Id == EntryId.METAS)
                    {
                        size = pkg.Header.sc_entry_count * 0x20;
                    }
                    new SubStream(s, entry.meta.DataOffset, size).CopyTo(ms);
                }
                pkg.Header.sc_entries2_hash = Crypto.Sha256(ms);
            }
        }
コード例 #9
0
        private static void CalcPlaygoDigests(Pkg pkg, MemoryMappedFile file)
        {
            const int CHUNK_SIZE  = 0x10000;
            int       totalChunks = (int)(pkg.Header.pfs_image_size / CHUNK_SIZE);
            int       chunkOffset = (int)(pkg.Header.pfs_image_offset / CHUNK_SIZE);
            var       FileData    = pkg.ChunkSha.FileData;

            using (var view = file.CreateViewAccessor(0, (long)pkg.Header.package_size))
            {
                Parallel.ForEach(
                    Enumerable.Range(chunkOffset, totalChunks),
                    () => Tuple.Create(SHA256.Create(), new byte[CHUNK_SIZE]),
                    (chunk, _, local) =>
                {
                    var(sha, buffer) = local;
                    view.ReadArray(chunk * CHUNK_SIZE, buffer, 0, CHUNK_SIZE);
                    Buffer.BlockCopy(sha.ComputeHash(buffer), 0, FileData, chunk * 4, 4);
                    return(local);
                },
                    buffer => { buffer.Item1.Dispose(); });
            }
        }
コード例 #10
0
        public Pkg BuildPkg()
        {
            var pkg     = new Pkg();
            var volType = GP4.VolumeTypeUtil.OfString(project.volume.Type);

            pkg.Header = new Header
            {
                CNTMagic           = "\u007fCNT",
                flags              = PKGFlags.Unknown,
                unk_0x08           = 0,
                unk_0x0C           = 0xF,
                entry_count        = 6,
                sc_entry_count     = 6,
                entry_count_2      = 6,
                entry_table_offset = 0x2A80,
                main_ent_data_size = 0xD00,
                body_offset        = 0x2000,
                body_size          = 0x7E000,
                content_id         = project.volume.Package.ContentId,
                drm_type           = DrmType.PS4,
                content_type       = VolTypeToContentType(volType),
                content_flags      = ContentFlags.Unk_x8000000 | VolTypeToContentFlags(volType),
                // TODO
                promote_size         = 0,
                version_date         = 0x20161020,
                version_hash         = 0x1738551,
                unk_0x88             = 0,
                unk_0x8C             = 0,
                unk_0x90             = 0,
                unk_0x94             = 0,
                iro_tag              = IROTag.None,
                ekc_version          = 1,
                sc_entries1_hash     = new byte[32],
                sc_entries2_hash     = new byte[32],
                digest_table_hash    = new byte[32],
                body_digest          = new byte[32],
                unk_0x400            = 1,
                pfs_image_count      = 1,
                pfs_flags            = 0x80000000000003CC,
                pfs_image_offset     = 0x80000,
                pfs_image_size       = 0,
                mount_image_offset   = 0,
                mount_image_size     = 0,
                package_size         = 0,
                pfs_signed_size      = 0x10000,
                pfs_cache_size       = 0x90000,
                pfs_image_digest     = new byte[32],
                pfs_signed_digest    = new byte[32],
                pfs_split_size_nth_0 = 0,
                pfs_split_size_nth_1 = 0
            };
            pkg.PackageDigest = new byte[32];
            pkg.UnkKey        = new byte[0x100];
            pkg.EntryKeys     = new KeysEntry();
            pkg.ImageKey      = new GenericEntry(EntryId.IMAGE_KEY)
            {
                FileData = new byte[0x100]
            };
            pkg.GeneralDigests = new GeneralDigestsEntry()
            {
                UnknownDigest = new byte[] {
                    0xD2, 0x56, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE
                },
                ContentDigest    = new byte[32],
                GameDigest       = new byte[32],
                HeaderDigest     = new byte[32],
                UnknownDigest2   = new byte[32],
                MajorParamDigest = new byte[32],
                ParamDigest      = new byte[32],
            };
            pkg.Metas      = new MetasEntry();
            pkg.Digests    = new GenericEntry(EntryId.DIGESTS);
            pkg.EntryNames = new NameTableEntry();
            pkg.LicenseDat = new GenericEntry(EntryId.LICENSE_DAT)
            {
                FileData = new byte[1024]
            };
            pkg.LicenseInfo = new GenericEntry(EntryId.LICENSE_INFO)
            {
                FileData = new byte[512]
            };
            var paramSfoPath = project.files.Where(f => f.TargetPath == "sce_sys/param.sfo").First().OrigPath;

            using (var paramSfo = File.OpenRead(Path.Combine(projectDir, paramSfoPath)))
                pkg.ParamSfo = new GenericEntry(EntryId.PARAM_SFO, "param.sfo")
                {
                    FileData = SFO.ParamSfo.Update(paramSfo)
                };
            pkg.PsReservedDat = new GenericEntry(EntryId.PSRESERVED_DAT)
            {
                FileData = new byte[0x2000]
            };
            pkg.Entries = new List <Entry>
            {
                pkg.EntryKeys,
                pkg.ImageKey,
                pkg.GeneralDigests,
                pkg.Metas,
                pkg.Digests,
                pkg.EntryNames,
                pkg.LicenseDat,
                pkg.LicenseInfo,
                pkg.ParamSfo,
                pkg.PsReservedDat
            };
            pkg.Digests.FileData = new byte[pkg.Entries.Count * Pkg.HASH_SIZE];

            // 1st pass: set names
            foreach (var entry in pkg.Entries)
            {
                pkg.EntryNames.GetOffset(entry.Name);
            }
            // 2nd pass: set sizes, offsets in meta table
            var dataOffset = 0x2000u;

            foreach (var entry in pkg.Entries)
            {
                var e = new MetaEntry
                {
                    id = entry.Id,
                    NameTableOffset = pkg.EntryNames.GetOffset(entry.Name),
                    DataOffset      = dataOffset,
                    DataSize        = entry.Length,
                    // TODO
                    Flags1 = 0,
                    Flags2 = 0,
                };
                pkg.Metas.Metas.Add(e);
                if (entry == pkg.Metas)
                {
                    e.DataSize = (uint)pkg.Entries.Count * 32;
                }

                dataOffset += e.DataSize;

                var align = dataOffset % 16;
                if (align != 0)
                {
                    dataOffset += 16 - align;
                }
            }
            pkg.Metas.Metas.Sort((e1, e2) => e1.id.CompareTo(e2.id));
            pkg.Header.entry_count   = (uint)pkg.Entries.Count;
            pkg.Header.entry_count_2 = (ushort)pkg.Entries.Count;
            pkg.Header.body_size     = dataOffset;
            // TODO: mount_image_size, package_size
            return(pkg);
        }
コード例 #11
0
 public PkgValidator(Pkg pkg, Action <string> onError = null)
 {
     pkg_         = pkg;
     errorHandler = onError;
 }
コード例 #12
0
ファイル: PkgReader.cs プロジェクト: maxton/LibOrbisPkg
        public Pkg ReadPkg()
        {
            var header = ReadHeader();

            s.Position = 0xFE0;
            var headerDigest    = s.ReadBytes(32);
            var headerSignature = s.ReadBytes(256);

            s.Position = header.entry_table_offset;
            var metasEntry = new MetasEntry();

            for (var i = 0; i < header.entry_count; i++)
            {
                metasEntry.Metas.Add(MetaEntry.Read(s));
            }
            var pkg = new Pkg
            {
                Header          = header,
                HeaderDigest    = headerDigest,
                HeaderSignature = headerSignature,
                Metas           = metasEntry,
            };

            foreach (var entry in pkg.Metas.Metas)
            {
                switch (entry.id)
                {
                case EntryId.METAS:
                    pkg.Metas.meta = entry;
                    break;

                case EntryId.ENTRY_NAMES:
                    pkg.EntryNames = NameTableEntry.Read(entry, s);
                    break;

                case EntryId.PARAM_SFO:
                    s.Position        = entry.DataOffset;
                    pkg.ParamSfo      = new SfoEntry(SFO.ParamSfo.FromStream(s));
                    pkg.ParamSfo.meta = entry;
                    break;

                case EntryId.ENTRY_KEYS:
                    pkg.EntryKeys      = KeysEntry.Read(entry, s);
                    pkg.EntryKeys.meta = entry;
                    break;

                case EntryId.IMAGE_KEY:
                    s.Position   = entry.DataOffset;
                    pkg.ImageKey = new GenericEntry(EntryId.IMAGE_KEY)
                    {
                        FileData = s.ReadBytes((int)entry.DataSize),
                        meta     = entry
                    };
                    break;

                case EntryId.GENERAL_DIGESTS:
                    s.Position              = entry.DataOffset;
                    pkg.GeneralDigests      = GeneralDigestsEntry.Read(s);
                    pkg.GeneralDigests.meta = entry;
                    break;

                case EntryId.DIGESTS:
                    s.Position  = entry.DataOffset;
                    pkg.Digests = new GenericEntry(EntryId.DIGESTS)
                    {
                        FileData = s.ReadBytes((int)entry.DataSize),
                        meta     = entry,
                    };
                    break;

                case EntryId.LICENSE_DAT:
                    try
                    {
                        var licenseDatBytes = new byte[entry.DataSize];
                        s.Position = entry.DataOffset;
                        s.Read(licenseDatBytes, 0, (int)entry.DataSize);
                        using (var ms = new System.IO.MemoryStream(Entry.Decrypt(licenseDatBytes, pkg, entry)))
                        {
                            pkg.LicenseDat      = new Rif.LicenseDatReader(ms).Read();
                            pkg.LicenseDat.meta = entry;
                        }
                    }
                    catch (Exception) { }
                    break;
                }
            }
            return(pkg);
        }
コード例 #13
0
        /// <summary>
        /// Creates the Pkg object. Initializes the header and body.
        /// </summary>
        public void BuildPkg(long pfsSize)
        {
            pkg = new Pkg();
            var volType = project.VolumeType;

            pkg.Header = new Header
            {
                CNTMagic           = "\u007fCNT",
                flags              = PKGFlags.Unknown,
                unk_0x08           = 0,
                unk_0x0C           = 0xF,
                entry_count        = 6,
                sc_entry_count     = 6,
                entry_count_2      = 6,
                entry_table_offset = 0x2A80,
                main_ent_data_size = 0xD00,
                body_offset        = 0x2000,
                body_size          = 0x7E000,
                content_id         = project.ContentId,
                drm_type           = DrmType.PS4,
                content_type       = VolTypeToContentType(volType),
                content_flags      = ContentFlags.Unk_x8000000 | VolTypeToContentFlags(volType),
                // TODO
                promote_size         = 0,
                version_date         = 0x20161020,
                version_hash         = 0x1738551,
                unk_0x88             = 0,
                unk_0x8C             = 0,
                unk_0x90             = 0,
                unk_0x94             = 0,
                iro_tag              = IROTag.None,
                ekc_version          = 1,
                sc_entries1_hash     = new byte[32],
                sc_entries2_hash     = new byte[32],
                digest_table_hash    = new byte[32],
                body_digest          = new byte[32],
                unk_0x400            = 1,
                pfs_image_count      = 1,
                pfs_flags            = 0x80000000000003CC,
                pfs_image_offset     = 0x80000,
                pfs_image_size       = (ulong)pfsSize,
                mount_image_offset   = 0,
                mount_image_size     = 0,
                package_size         = (ulong)(0x80000 + pfsSize),
                pfs_signed_size      = 0x10000,
                pfs_cache_size       = 0xD0000,
                pfs_image_digest     = new byte[32],
                pfs_signed_digest    = new byte[32],
                pfs_split_size_nth_0 = 0,
                pfs_split_size_nth_1 = 0
            };
            pkg.HeaderDigest    = new byte[32];
            pkg.HeaderSignature = new byte[0x100];
            pkg.EntryKeys       = new KeysEntry(
                project.ContentId,
                project.Passcode);
            pkg.ImageKey = new GenericEntry(EntryId.IMAGE_KEY)
            {
                FileData = Crypto.RSA2048EncryptKey(RSAKeyset.FakeKeyset.Modulus, EKPFS)
            };
            pkg.GeneralDigests = new GeneralDigestsEntry();
            pkg.Metas          = new MetasEntry();
            pkg.Digests        = new GenericEntry(EntryId.DIGESTS);
            pkg.EntryNames     = new NameTableEntry();
            pkg.LicenseDat     = GenLicense();
            pkg.LicenseInfo    = new GenericEntry(EntryId.LICENSE_INFO)
            {
                FileData = GenLicenseInfo()
            };
            var paramSfoFile = project.RootDir.GetFile("sce_sys/param.sfo");

            if (paramSfoFile == null)
            {
                throw new Exception("Missing param.sfo!");
            }
            using (var paramSfo = new MemoryStream())
            {
                paramSfoFile.Write(paramSfo);
                paramSfo.Position = 0;
                var sfo = SFO.ParamSfo.FromStream(paramSfo);
                pkg.ParamSfo = new SfoEntry(sfo);
                string date = "", time = "";
                if (project.CreationDate == default)
                {
                    date = "c_date=" + DateTime.UtcNow.ToString("yyyyMMdd");
                    if (project.UseCreationTime)
                    {
                        time = ",c_time=" + DateTime.UtcNow.ToString("HHmmss");
                    }
                }
                else
                {
                    date = "c_date=" + project.CreationDate.ToString("yyyyMMdd");
                    if (project.UseCreationTime)
                    {
                        time = ",c_time=" + project.CreationDate.ToString("HHmmss");
                    }
                }
                var sizeInfo = $",img0_l0_size={(pkg.Header.package_size + 0xFFFFF) / (1024 * 1024)}" +
                               $",img0_l1_size=0" +
                               $",img0_sc_ksize=512" +
                               $",img0_pc_ksize=832";
                sfo["PUBTOOLINFO"] = new SFO.Utf8Value("PUBTOOLINFO", date + time + sizeInfo, 0x200);
                sfo["PUBTOOLVER"]  = new SFO.IntegerValue("PUBTOOLVER", 0x02890000);
            }

            pkg.PsReservedDat = new GenericEntry(EntryId.PSRESERVED_DAT)
            {
                FileData = new byte[0x2000]
            };
            pkg.Entries = new List <Entry>
            {
                pkg.EntryKeys,
                pkg.ImageKey,
                pkg.GeneralDigests,
                pkg.Metas,
                pkg.Digests,
                pkg.EntryNames
            };
            if (pkg.Header.content_type == ContentType.GD)
            {
                pkg.ChunkDat = PlayGo.ChunkDat.FromProject(project.ContentId);
                pkg.ChunkSha = new GenericEntry(EntryId.PLAYGO_CHUNK_SHA, "playgo-chunk.sha");
                pkg.ChunkXml = new GenericEntry(EntryId.PLAYGO_MANIFEST_XML, "playgo-manifest.xml")
                {
                    FileData = PlayGo.Manifest.Default
                };
                // Add playgo entries for GD PKGs
                pkg.Entries.AddRange(new Entry[]
                {
                    pkg.ChunkDat,
                    pkg.ChunkSha,
                    pkg.ChunkXml
                });
            }
            pkg.Entries.AddRange(new Entry[]
            {
                pkg.LicenseDat,
                pkg.LicenseInfo,
                pkg.ParamSfo,
                pkg.PsReservedDat
            });
            foreach (var file in project.RootDir.Dirs.Where(f => f.name == "sce_sys").First().Files.Where(f => EntryNames.NameToId.ContainsKey(f.name)))
            {
                var name = file.name;
                if (name == "param.sfo")
                {
                    continue;
                }
                var entry = new FileEntry(EntryNames.NameToId[name], file.Write, (uint)file.Size);
                pkg.Entries.Add(entry);
            }
            pkg.Digests.FileData = new byte[pkg.Entries.Count * Pkg.HASH_SIZE];

            // 1st pass: set names
            foreach (var entry in pkg.Entries.OrderBy(e => e.Name))
            {
                pkg.EntryNames.GetOffset(entry.Name);
            }
            // estimate size for playgo
            if (pkg.Header.content_type == ContentType.GD)
            {
                long bodySize = 0;
                foreach (var e in pkg.Entries)
                {
                    bodySize += (e.Length + 15) & ~15; // round up to nearest 16
                }
                bodySize += 32 * pkg.Entries.Count;    // metas
                bodySize += 4 * (pfsSize / 0x10000);   // playgo hashes of pfs
                if (bodySize + (long)pkg.Header.body_offset >= (long)pkg.Header.pfs_image_offset)
                {
                    pkg.Header.pfs_image_offset = (ulong)((bodySize + (long)pkg.Header.body_offset + 0xFFFF) & ~0xFFFFL);
                }
                pkg.ChunkSha.FileData = new byte[4 * ((pkg.Header.pfs_image_offset + pkg.Header.pfs_image_size) / 0x10000)];
            }
            // 2nd pass: set sizes, offsets in meta table
            var dataOffset = 0x2000u;
            var flagMap    = new Dictionary <EntryId, uint>()
            {
                { EntryId.DIGESTS, 0x40000000 },
                { EntryId.ENTRY_KEYS, 0x60000000 },
                { EntryId.IMAGE_KEY, 0xE0000000 },
                { EntryId.GENERAL_DIGESTS, 0x60000000 },
                { EntryId.METAS, 0x60000000 },
                { EntryId.ENTRY_NAMES, 0x40000000 },
                { EntryId.LICENSE_DAT, 0x80000000 },
                { EntryId.LICENSE_INFO, 0x80000000 },
            };
            var keyMap = new Dictionary <EntryId, uint>
            {
                { EntryId.IMAGE_KEY, 3u << 12 },
                { EntryId.LICENSE_DAT, 3u << 12 },
                { EntryId.LICENSE_INFO, 2u << 12 },
            };

            foreach (var entry in pkg.Entries)
            {
                var e = new MetaEntry
                {
                    id = entry.Id,
                    NameTableOffset = pkg.EntryNames.GetOffset(entry.Name),
                    DataOffset      = dataOffset,
                    DataSize        = entry.Length,
                    // TODO
                    Flags1 = flagMap.GetOrDefault(entry.Id),
                    Flags2 = keyMap.GetOrDefault(entry.Id),
                };
                pkg.Metas.Metas.Add(e);
                if (entry == pkg.Metas)
                {
                    e.DataSize = (uint)pkg.Entries.Count * 32;
                }

                dataOffset += e.DataSize;

                var align = dataOffset % 16;
                if (align != 0)
                {
                    dataOffset += 16 - align;
                }
                entry.meta = e;
            }
            pkg.Metas.Metas.Sort((e1, e2) => e1.id.CompareTo(e2.id));
            pkg.Header.entry_count   = (uint)pkg.Entries.Count;
            pkg.Header.entry_count_2 = (ushort)pkg.Entries.Count;
            pkg.Header.body_size     = pkg.Header.pfs_image_offset - pkg.Header.body_offset;
            pkg.Header.package_size  = pkg.Header.mount_image_size = pkg.Header.pfs_image_offset + pkg.Header.pfs_image_size;

            if (pkg.Header.content_type == ContentType.GD)
            {
                // Important sizes for PlayGo ChunkDat
                pkg.ChunkDat.MchunkAttrs[0].size      = pkg.Header.package_size;
                pkg.ChunkDat.InnerMChunkAttrs[0].size = (ulong)innerPfs.CalculatePfsSize();
                // GD pkgs set promote_size to the size of the PKG before the PFS image?
                pkg.Header.promote_size = (uint)(pkg.Header.body_size + pkg.Header.body_offset);
            }
        }
コード例 #14
0
        /// <summary>
        /// Create the Pkg struct. Does not compute hashes or data sizes.
        /// </summary>
        public Pkg BuildPkg()
        {
            var pkg     = new Pkg();
            var volType = GP4.VolumeTypeUtil.OfString(project.volume.Type);

            pkg.Header = new Header
            {
                CNTMagic           = "\u007fCNT",
                flags              = PKGFlags.Unknown,
                unk_0x08           = 0,
                unk_0x0C           = 0xF,
                entry_count        = 6,
                sc_entry_count     = 6,
                entry_count_2      = 6,
                entry_table_offset = 0x2A80,
                main_ent_data_size = 0xD00,
                body_offset        = 0x2000,
                body_size          = 0x7E000,
                content_id         = project.volume.Package.ContentId,
                drm_type           = DrmType.PS4,
                content_type       = VolTypeToContentType(volType),
                content_flags      = ContentFlags.Unk_x8000000 | VolTypeToContentFlags(volType),
                // TODO
                promote_size         = 0,
                version_date         = 0x20161020,
                version_hash         = 0x1738551,
                unk_0x88             = 0,
                unk_0x8C             = 0,
                unk_0x90             = 0,
                unk_0x94             = 0,
                iro_tag              = IROTag.None,
                ekc_version          = 1,
                sc_entries1_hash     = new byte[32],
                sc_entries2_hash     = new byte[32],
                digest_table_hash    = new byte[32],
                body_digest          = new byte[32],
                unk_0x400            = 1,
                pfs_image_count      = 1,
                pfs_flags            = 0x80000000000003CC,
                pfs_image_offset     = 0x80000,
                pfs_image_size       = 0,
                mount_image_offset   = 0,
                mount_image_size     = 0,
                package_size         = 0,
                pfs_signed_size      = 0x10000,
                pfs_cache_size       = 0xD0000,
                pfs_image_digest     = new byte[32],
                pfs_signed_digest    = new byte[32],
                pfs_split_size_nth_0 = 0,
                pfs_split_size_nth_1 = 0
            };
            pkg.HeaderDigest    = new byte[32];
            pkg.HeaderSignature = new byte[0x100];
            pkg.EntryKeys       = new KeysEntry(
                project.volume.Package.ContentId,
                project.volume.Package.Passcode);
            pkg.ImageKey = new GenericEntry(EntryId.IMAGE_KEY)
            {
                FileData = new byte[0x100]
            };
            pkg.GeneralDigests = new GeneralDigestsEntry();
            pkg.Metas          = new MetasEntry();
            pkg.Digests        = new GenericEntry(EntryId.DIGESTS);
            pkg.EntryNames     = new NameTableEntry();
            pkg.LicenseDat     = new GenericEntry(EntryId.LICENSE_DAT)
            {
                FileData = GenLicense(pkg)
            };
            pkg.LicenseInfo = new GenericEntry(EntryId.LICENSE_INFO)
            {
                FileData = GenLicenseInfo(pkg)
            };
            var paramSfoPath = project.files.Where(f => f.TargetPath == "sce_sys/param.sfo").First().OrigPath;

            using (var paramSfo = File.OpenRead(Path.Combine(projectDir, paramSfoPath)))
            {
                var sfo = SFO.ParamSfo.FromStream(paramSfo);
                pkg.ParamSfo = new SfoEntry(sfo);
                string date = "", time = "";
                if ((project.volume.Package.CreationDate ?? "") == "")
                {
                    date = "c_date=" + DateTime.UtcNow.ToString("yyyyMMdd");
                }
                else
                {
                    var split    = project.volume.Package.CreationDate.Split(' ');
                    var dateTime = DateTime.Parse(project.volume.Package.CreationDate).ToUniversalTime();
                    if (split.Length == 2) // Date and time specified
                    {
                        date = "c_date=" + dateTime.ToString("yyyyMMdd");
                        time = ",c_time=" + dateTime.ToString("HHmmss");
                    }
                    else //  just date is specified
                    {
                        date = "c_date=" + dateTime.ToString("yyyyMMdd");
                    }
                }
                sfo.Values.Add(new SFO.Utf8Value("PUBTOOLINFO", date + time, 0x200));
                sfo.Values.Add(new SFO.IntegerValue("PUBTOOLVER", 0x02890000));
            }
            pkg.PsReservedDat = new GenericEntry(EntryId.PSRESERVED_DAT)
            {
                FileData = new byte[0x2000]
            };
            pkg.Entries = new List <Entry>
            {
                pkg.EntryKeys,
                pkg.ImageKey,
                pkg.GeneralDigests,
                pkg.Metas,
                pkg.Digests,
                pkg.EntryNames,
                pkg.LicenseDat,
                pkg.LicenseInfo,
                pkg.ParamSfo,
                pkg.PsReservedDat
            };
            pkg.Digests.FileData = new byte[pkg.Entries.Count * Pkg.HASH_SIZE];

            // 1st pass: set names
            foreach (var entry in pkg.Entries)
            {
                pkg.EntryNames.GetOffset(entry.Name);
            }
            // 2nd pass: set sizes, offsets in meta table
            var dataOffset = 0x2000u;
            var flagMap    = new Dictionary <EntryId, uint>()
            {
                { EntryId.DIGESTS, 0x40000000 },
                { EntryId.ENTRY_KEYS, 0x60000000 },
                { EntryId.IMAGE_KEY, 0xE0000000 },
                { EntryId.GENERAL_DIGESTS, 0x60000000 },
                { EntryId.METAS, 0x60000000 },
                { EntryId.ENTRY_NAMES, 0x40000000 },
                { EntryId.LICENSE_DAT, 0x80000000 },
                { EntryId.LICENSE_INFO, 0x80000000 },
            };
            var keyMap = new Dictionary <EntryId, uint>
            {
                { EntryId.IMAGE_KEY, 3u << 12 },
                { EntryId.LICENSE_DAT, 3u << 12 },
                { EntryId.LICENSE_INFO, 2u << 12 },
            };

            foreach (var entry in pkg.Entries)
            {
                var e = new MetaEntry
                {
                    id = entry.Id,
                    NameTableOffset = pkg.EntryNames.GetOffset(entry.Name),
                    DataOffset      = dataOffset,
                    DataSize        = entry.Length,
                    // TODO
                    Flags1 = flagMap.GetOrDefault(entry.Id),
                    Flags2 = keyMap.GetOrDefault(entry.Id),
                };
                pkg.Metas.Metas.Add(e);
                if (entry == pkg.Metas)
                {
                    e.DataSize = (uint)pkg.Entries.Count * 32;
                }

                dataOffset += e.DataSize;

                var align = dataOffset % 16;
                if (align != 0)
                {
                    dataOffset += 16 - align;
                }
                entry.meta = e;
            }
            pkg.Metas.Metas.Sort((e1, e2) => e1.id.CompareTo(e2.id));
            pkg.Header.entry_count   = (uint)pkg.Entries.Count;
            pkg.Header.entry_count_2 = (ushort)pkg.Entries.Count;
            pkg.Header.body_size     = dataOffset;
            return(pkg);
        }
コード例 #15
0
 private void UpdateHeaderInfo(Pkg pkg, long stream_length, long pfs_length)
 {
     pkg.Header.package_size     = (ulong)stream_length;
     pkg.Header.mount_image_size = (ulong)stream_length;
     pkg.Header.pfs_image_size   = (ulong)pfs_length;
 }