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); } }
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); } }
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); }
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); } }
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()); } }
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); } } }
/// <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); }
/// <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); } }
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(); }); } }
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); }
public PkgValidator(Pkg pkg, Action <string> onError = null) { pkg_ = pkg; errorHandler = onError; }
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); }
/// <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); } }
/// <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); }
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; }