public void TestReadBackLicenseDat() { using (var s = File.OpenRead(pkgFile.Path)) { var pkg = new PkgReader(s).ReadPkg(); Assert.IsNotNull(pkg.LicenseDat); } }
private void darkButton1_Click(object sender, EventArgs e) { FolderBrowserDialog savepath = new FolderBrowserDialog(); if (savepath.ShowDialog() == DialogResult.OK) { try { var numbersAndWords = idEntryList.Zip(nameEntryList, (n, w) => new { id = n, name = w }); foreach (var nw in numbersAndWords) { var pkgPath = filenames; var idx = int.Parse(nw.id); var name = nw.name; var outPath = savepath.SelectedPath + "\\" + name.Replace("_SHA", ".SHA").Replace("_DAT", ".DAT").Replace("_SFO", ".SFO").Replace("_XML", ".XML").Replace("_SIG", ".SIG").Replace("_PNG", ".PNG").Replace("_JSON", ".JSON").Replace("_DDS", ".DDS").Replace("_TRP", ".TRP").Replace("_AT9", ".AT9");; using (var pkgFile = File.OpenRead(pkgPath)) { var pkg = new PkgReader(pkgFile).ReadPkg(); if (idx < 0 || idx >= pkg.Metas.Metas.Count) { DarkMessageBox.ShowError("Error: entry number out of range", "PS4 PKG Tool"); return; } using (var outFile = File.Create(outPath)) { var meta = pkg.Metas.Metas[idx]; outFile.SetLength(meta.DataSize); if (meta.Encrypted) { if (passcode == null) { DarkMessageBox.ShowWarning("Warning: Entry is encrypted but no passcode was provided! Saving encrypted bytes.", "PS4 PKG Tool"); } else { var entry = new SubStream(pkgFile, meta.DataOffset, (meta.DataSize + 15) & ~15); var tmp = new byte[entry.Length]; entry.Read(tmp, 0, tmp.Length); tmp = LibOrbisPkg.PKG.Entry.Decrypt(tmp, pkg.Header.content_id, passcode, meta); outFile.Write(tmp, 0, (int)meta.DataSize); return; } } new SubStream(pkgFile, meta.DataOffset, meta.DataSize).CopyTo(outFile); } } } DarkMessageBox.ShowInformation("All entry item extracted", "PS4 PKG Tool"); } catch (Exception a) { DarkMessageBox.ShowError(a.Message, "PS4 PKG Tool"); } } }
public void Validate() { using (var pkgFile = new MemoryStream()) { new PkgBuilder(TestHelper.MakeProperties()).Write(pkgFile, s => { }); var pkg = new PkgReader(pkgFile).ReadPkg(); foreach (var v in new PkgValidator(pkg).Validate(pkgFile)) { Assert.IsTrue(v.Item2 == PkgValidator.ValidationResult.Ok, v.Item1.Name); } } }
public void Validate() { using (var pkgFile = new TempFile()) { new PkgBuilder(MakeProperties()).Write(pkgFile.Path, s => { }); using (var pkgStream = File.OpenRead(pkgFile.Path)) { var pkg = new PkgReader(pkgStream).ReadPkg(); foreach (var v in new PkgValidator(pkg).Validate(pkgStream)) { Assert.IsTrue(v.Item2, v.Item1.Name); } } } }
public static void OpenPkgFilesystem(System.IO.Stream pkgStream, Action <PfsReader> innerPfsAction) { Pkg pkg; pkg = new PkgReader(pkgStream).ReadPkg(); var ekpfs = LibOrbisPkg.Util.Crypto.ComputeKeys(pkg.Header.content_id, "00000000000000000000000000000000", 1); var outerPfsOffset = (long)pkg.Header.pfs_image_offset; using (var acc = new LibOrbisPkg.Util.StreamReader(pkgStream, outerPfsOffset)) { var outerPfs = new PfsReader(acc, pkg.Header.pfs_flags, ekpfs); var inner = new PfsReader(new PFSCReader(outerPfs.GetFile("pfs_image.dat").GetView())); // Check that the sce_sys directory exists innerPfsAction(inner); } }
public void ValidateGD_LargeSc0() { using (var pkgFile = new MemoryStream()) { const int size = 0x1023456; var properties = TestHelper.MakeProperties( VolumeType: VolumeType.pkg_ps4_app, sc0Files: new[] { new FSFile(s => s.Position += size, "save_data.png", size) }); new PkgBuilder(properties).Write(pkgFile, s => { }); var pkg = new PkgReader(pkgFile).ReadPkg(); foreach (var v in new PkgValidator(pkg).Validate(pkgFile)) { Assert.IsTrue(v.Item2 == PkgValidator.ValidationResult.Ok, v.Item1.Name); } } }
private void setPKGPFSFileMetadataToolStripMenuItem_Click(object sender, EventArgs e) { using (var ofd = new OpenFileDialog() { Title = "Select files", Filter = "PKG/PFS Files (*.pkg, *.dat)|*.pkg;*.dat", Multiselect = true }) { if (ofd.ShowDialog() != DialogResult.OK) { return; } foreach (var filename in ofd.FileNames) { DateTime creationTime = File.GetCreationTimeUtc(filename); DateTime modifiedTime = File.GetLastWriteTime(filename); using (var f = File.OpenRead(filename)) { if (filename.ToLowerInvariant().EndsWith(".dat")) { var header = PfsHeader.ReadFromStream(f); creationTime = modifiedTime = new DateTime(1970, 1, 1) .AddSeconds(header.InodeBlockSig.Time1_sec); } else if (filename.ToLowerInvariant().EndsWith(".pkg")) { var pkgHeader = new PkgReader(f).ReadHeader(); f.Position = (long)pkgHeader.pfs_image_offset; var header = PfsHeader.ReadFromStream(f); creationTime = modifiedTime = new DateTime(1970, 1, 1) .AddSeconds(header.InodeBlockSig.Time1_sec); } } File.SetCreationTimeUtc(filename, creationTime); File.SetLastWriteTimeUtc(filename, modifiedTime); } } }
// Helper for checking the internal files of a PKG private static void OpenPkgFilesystem(string pkgPath, Action <PfsReader> innerPfsAction) { Pkg pkg; using (var mmf = MemoryMappedFile.CreateFromFile(pkgPath)) { using (var s = mmf.CreateViewStream()) { pkg = new PkgReader(s).ReadPkg(); } var ekpfs = LibOrbisPkg.Util.Crypto.ComputeKeys(pkg.Header.content_id, "00000000000000000000000000000000", 1); var outerPfsOffset = (long)pkg.Header.pfs_image_offset; using (var acc = mmf.CreateViewAccessor(outerPfsOffset, (long)pkg.Header.pfs_image_size)) { var outerPfs = new PfsReader(acc, ekpfs); var inner = new PfsReader(new PFSCReader(outerPfs.GetFile("pfs_image.dat").GetView())); // Check that the sce_sys directory exists innerPfsAction(inner); } } }
public static void CreateProjectFromPKG(string outputDir, MemoryMappedFile pkgFile, string passcode = null) { Directory.CreateDirectory(outputDir); Pkg pkg; using (var f = pkgFile.CreateViewStream(0, 0, MemoryMappedFileAccess.Read)) pkg = new PkgReader(f).ReadPkg(); passcode = passcode ?? "00000000000000000000000000000000"; // Initialize project parameters var project = Gp4Project.Create(ContentTypeToVolumeType(pkg.Header.content_type)); project.volume.Package.Passcode = passcode; project.volume.Package.ContentId = pkg.Header.content_id; project.volume.Package.AppType = project.volume.Type == VolumeType.pkg_ps4_app ? "full" : null; project.volume.Package.StorageType = project.volume.Type == VolumeType.pkg_ps4_app ? "digital50" : null; if (pkg.Header.content_type == ContentType.AC || pkg.Header.content_type == ContentType.AL) { pkg.LicenseDat.DecryptSecretWithDebugKey(); var entitlementKey = new byte[16]; Buffer.BlockCopy(pkg.LicenseDat.Secret, 0x70, entitlementKey, 0, 16); pkg.LicenseDat.EncryptSecretWithDebugKey(); project.volume.Package.EntitlementKey = entitlementKey.ToHexCompact(); } // Extract entry filesystem var sys_dir = Path.Combine(outputDir, "sce_sys"); var sys_projdir = project.AddDir(null, "sce_sys"); Directory.CreateDirectory(sys_dir); foreach (var meta in pkg.Metas.Metas) { // Skip entries that are auto-generated or that we don't know the filenames for if (GeneratedEntries.Contains(meta.id)) { continue; } if (!EntryNames.IdToName.ContainsKey(meta.id)) { continue; } var entryName = EntryNames.IdToName[meta.id]; var filename = Path.Combine(sys_dir, entryName); // Create directories for entries within directories if (entryName.Contains('/')) { var entryDir = entryName.Substring(0, entryName.LastIndexOf('/')); Directory.CreateDirectory(Path.Combine(sys_dir, entryDir)); Dir d = sys_projdir; foreach (var breadcrumb in entryDir.Split('/')) { d = project.AddDir(d, breadcrumb); } } // Add the entry to the project project.files.Items.Add(new Gp4File() { OrigPath = "sce_sys/" + entryName, TargetPath = "sce_sys/" + entryName }); // Save to the filesystem using (var s = pkgFile.CreateViewStream(meta.DataOffset, meta.DataSize, MemoryMappedFileAccess.Read)) using (var entryFile = File.Create(filename)) { s.CopyTo(entryFile); } } // Fixup the param.sfo using (var f = File.Open(Path.Combine(outputDir, "sce_sys/param.sfo"), FileMode.Open)) { var sfo = SFO.ParamSfo.FromStream(f); var pubtoolinfo = (sfo["PUBTOOLINFO"] as SFO.Utf8Value).Value; var c_date = ""; var c_time = ""; foreach (var info in pubtoolinfo.Split(',')) { var info2 = info.Split('='); switch (info2[0]) { case "c_date": c_date = info2[1].Substring(0, 4) + "-" + info2[1].Substring(4, 2) + "-" + info2[1].Substring(6, 2); break; case "c_time": c_time = " " + info2[1].Substring(0, 2) + ":" + info2[1].Substring(2, 2) + ":" + info2[1].Substring(4, 2); break; } } project.volume.Package.CreationDate = c_date + c_time; sfo["PUBTOOLVER"] = null; sfo["PUBTOOLINFO"] = null; sfo.Write(f); } // Extract files from the PFS filesystem byte[] ekpfs; if (pkg.CheckPasscode(passcode)) { ekpfs = Crypto.ComputeKeys(pkg.Header.content_id, passcode, 1); } else { ekpfs = pkg.GetEkpfs(); } using (var va = pkgFile.CreateViewAccessor((long)pkg.Header.pfs_image_offset, (long)pkg.Header.pfs_image_size, MemoryMappedFileAccess.Read)) { var outerPfs = new PfsReader(va, pkg.Header.pfs_flags, ekpfs); var inner = new PfsReader(new PFSCReader(outerPfs.GetFile("pfs_image.dat").GetView())); // Convert PFS image timestamp from UNIX time and save it in the project project.volume.TimeStamp = new DateTime(1970, 1, 1) .AddSeconds(inner.Header.InodeBlockSig.Time1_sec); var uroot = inner.GetURoot(); Dir dir = null; var projectDirs = new Queue <Dir>(); var pfsDirs = new Queue <PfsReader.Dir>(); pfsDirs.Enqueue(uroot); projectDirs.Enqueue(dir); while (pfsDirs.Count > 0) { dir = projectDirs.Dequeue(); if (dir != null) { Directory.CreateDirectory(Path.Combine(outputDir, dir.Path)); } foreach (var f in pfsDirs.Dequeue().children) { if (f is PfsReader.Dir d) { pfsDirs.Enqueue(d); projectDirs.Enqueue(project.AddDir(dir, d.name)); } else if (f is PfsReader.File file) { // Remove "/uroot/" var path = file.FullName.Substring(7); project.files.Items.Add(new Gp4File() { OrigPath = path, TargetPath = path }); file.Save(Path.Combine(outputDir, path)); } } } } // Last step: save the project file using (var f = File.Create(Path.Combine(outputDir, "Project.gp4"))) { Gp4Project.WriteTo(project, f); } }
private void Trophy_Load(object sender, EventArgs e) { //extract all entry //add entry to array using (var file = File.OpenRead(filenames)) { var pkg = new PkgReader(file).ReadPkg(); var i = 0; foreach (var meta in pkg.Metas.Metas) { idEntryList.Add($"{i++,-6}"); nameEntryList.Add($"{meta.id}"); } idEntryList.ToArray(); nameEntryList.ToArray(); } //extract each entry from array PS4_Tools.PKG.SceneRelated.Unprotected_PKG PS4_PKG = PS4_Tools.PKG.SceneRelated.Read_PKG(filenames); string game_title = PS4_PKG.Param.Title; string filter = game_title.Replace(":", " -"); string title_filter_final = filter.Replace(" -", " -"); string path = tempPath + @"Trophy\"; try { Directory.CreateDirectory(path + title_filter_final); var numbersAndWords = idEntryList.Zip(nameEntryList, (n, w) => new { id = n, name = w }); foreach (var nw in numbersAndWords) { var pkgPath = filenames; var idx = int.Parse(nw.id); var name = nw.name; var outPath = path + title_filter_final + "\\" + name.Replace("_SHA", ".SHA").Replace("_DAT", ".DAT").Replace("_SFO", ".SFO").Replace("_XML", ".XML").Replace("_SIG", ".SIG").Replace("_PNG", ".PNG").Replace("_JSON", ".JSON").Replace("_DDS", ".DDS").Replace("_TRP", ".TRP").Replace("_AT9", ".AT9");; using (var pkgFile = File.OpenRead(pkgPath)) { var pkg = new PkgReader(pkgFile).ReadPkg(); if (idx < 0 || idx >= pkg.Metas.Metas.Count) { DarkMessageBox.ShowError("Error: entry number out of range", "PS4 PKG Tool"); return; } using (var outFile = File.Create(outPath)) { var meta = pkg.Metas.Metas[idx]; outFile.SetLength(meta.DataSize); if (meta.Encrypted) { if (passcode == null) { //MessageBox.Show("Warning: Entry is encrypted but no passcode was provided! Saving encrypted bytes."); } else { var entry = new SubStream(pkgFile, meta.DataOffset, (meta.DataSize + 15) & ~15); var tmp = new byte[entry.Length]; entry.Read(tmp, 0, tmp.Length); tmp = LibOrbisPkg.PKG.Entry.Decrypt(tmp, pkg.Header.content_id, passcode, meta); outFile.Write(tmp, 0, (int)meta.DataSize); return; } } new SubStream(pkgFile, meta.DataOffset, meta.DataSize).CopyTo(outFile); } } } //MessageBox.Show("All entry item extracted", "PS4 PKG Tool"); } catch (Exception a) { DarkMessageBox.ShowError(a.Message, "PS4 PKG Tool"); } //done exract, now open trp if (File.Exists(path + title_filter_final + "\\TROPHY__TROPHY00.TRP")) { trophy = new TRPReader(); trophy.Load(path + title_filter_final + "\\TROPHY__TROPHY00.TRP"); if (!trophy.IsError) { List <Archiver> .Enumerator enumerator = new List <Archiver> .Enumerator(); enumerator = trophy.TrophyList.GetEnumerator(); try { //listView1.Columns.Add("Icon"); //listView1.Columns.Add("Name"); //listView1.Columns.Add("Size"); //listView1.Columns.Add("Offset"); //listView1.View = View.Details; //_ImageListIcons.ImageSize = new Size(96, 96); //listView1.SmallImageList = _ImageListIcons; while (enumerator.MoveNext()) { Archiver current = enumerator.Current; if (current.Name.ToUpper().EndsWith(".PNG")) { imgList.Add(Utilities.BytesToImage(trophy.ExtractFileToMemory(current.Name))); ImageListIcons.Images.Add(imgList[checked (imgList.Count - 1)]); imageToExtract.Add(Utilities.BytesToImage(trophy.ExtractFileToMemory(current.Name))); NameToExtract.Add(current.Name); var image = Utilities.BytesToImage(trophy.ExtractFileToMemory(current.Name)); var resize = ResizeImage(image, image.Width / 2, image.Height / 2); darkDataGridView1.Rows.Add(resize, current.Name, Utilities.RoundBytes(current.Size), "0x" + current.Offset); // listView1.Items.Add(new ListViewItem() // { // SubItems = { // current.Name, Utilities.RoundBytes(current.Size) //}, // ImageIndex = checked(ImageListIcons.Images.Count - 1), // Tag = (object)imgList.Count // }); } //dataGridView1.DataSource = dt; Application.DoEvents(); } NameToExtract.ToArray(); //listView1.Columns[0].AutoResize(ColumnHeaderAutoResizeStyle.ColumnContent); //listView1.Columns[1].AutoResize(ColumnHeaderAutoResizeStyle.None); //listView1.Columns[1].Width = 347; //listView1.Columns[2].AutoResize(ColumnHeaderAutoResizeStyle.None); //listView1.Columns[2].Width = 103; } finally { enumerator.Dispose(); } if (!issaved) { if (Operators.CompareString(trophy.SHA1, trophy.CalculateSHA1Hash(), false) != 0) { DarkMessageBox.ShowError("This file is corrupted, mismatched SHA1 hash!", "PS4 PKG Tool"); } //else //MessageBox.Show("Loaded successfully."); } else { label1.Text = "Saved successfully."; } label1.Enabled = trophy.Version > 1; //this.Text = "[ Trophy v" + Conversions.ToString(trophy.Version > 1) + " - Files count: " + listView1.Items.Count + " ]"; try { string input = Encoding.UTF8.GetString(trophy.ExtractFileToMemory("TROP.SFM")); Match match1 = new Regex("(?<start>[<]title[-]name[>])(?<titlename>.+)(?<end>[<][/]title[-]name[>])").Match(input); if (match1.Success) { trophy.TitleName = match1.Groups["titlename"].Value; Text = "TRPViewer - " + trophy.TitleName; } Match match2 = new Regex("(?<start>[<]npcommid[>])(?<npcommid>.+)(?<end>[<][/]npcommid[>])").Match(input); if (match2.Success) { trophy.NPCommId = match2.Groups["npcommid"].Value; } } catch (Exception ex) { ProjectData.SetProjectError(ex); ProjectData.ClearProjectError(); } } ctrophy.SetVersion = trophy.Version; } this.Text += PS4_PKG.PS4_Title; /* * PS4_Tools.PKG.SceneRelated.Unprotected_PKG PS4_PKG = PS4_Tools.PKG.SceneRelated.Read_PKG(this.filenames); * this.Text = "Trophy List : " + PS4_PKG.PS4_Title; * * DataTable dttemp = new DataTable(); * dttemp.Columns.Add("Index"); * dttemp.Columns.Add("Trophy File"); * dttemp.Columns.Add("Offset"); * dttemp.Columns.Add("Size"); * * try * { * for (int i = 0; i < PS4_PKG.Trophy_File.trophyItemList.Count; i++) * { * dttemp.Rows.Add(PS4_PKG.Trophy_File.trophyItemList[i].Index, PS4_PKG.Trophy_File.trophyItemList[i].Name, PS4_PKG.Trophy_File.trophyItemList[i].Offset, PS4_PKG.Trophy_File.trophyItemList[i].Size); * //dttemp.Rows.Add(PS4_PKG.Param.Tables[i].Name, PS4_PKG.Param.Tables[i].Value); * * } * * * } * catch (Exception ex) * { * * } * dataGridView1.DataSource = dttemp; * filenames = ""; */ }