From c2c1de78a4c4d904f89eeae8cc2ff082771f00df Mon Sep 17 00:00:00 2001 From: Beyley Thomas Date: Tue, 16 Jan 2024 16:43:42 -0800 Subject: [PATCH] Digital patching wip --- Refresher/Accessors/ConsolePatchAccessor.cs | 17 +++++- Refresher/Refresher.csproj | 14 ++--- Refresher/UI/IntegratedPatchForm.cs | 68 +++++++++++++++------ 3 files changed, 71 insertions(+), 28 deletions(-) diff --git a/Refresher/Accessors/ConsolePatchAccessor.cs b/Refresher/Accessors/ConsolePatchAccessor.cs index 5379213..a2db932 100644 --- a/Refresher/Accessors/ConsolePatchAccessor.cs +++ b/Refresher/Accessors/ConsolePatchAccessor.cs @@ -8,13 +8,28 @@ public class ConsolePatchAccessor : PatchAccessor, IDisposable private readonly FtpClient _client; private const string BasePath = "/dev_hdd0/"; + public string IdpsFile; + public ConsolePatchAccessor(string remoteIp) { this._client = new FtpClient(remoteIp, "anonymous", ""); this._client.Config.LogToConsole = true; this._client.AutoConnect(); + + UriBuilder idpsPs3 = new("http", remoteIp, 80, "idps.ps3"); + UriBuilder idpsHex = new("http", remoteIp, 80, "dev_hdd0/idps.hex"); + + HttpClient httpClient = new(); + + //Get the /idps.ps3 path, this creates the idps.hex file we can grab. + _ = httpClient.GetAsync(idpsPs3.Uri).Result; + + //Get a new path for an IDPS file + this.IdpsFile = Path.GetTempFileName(); + + File.WriteAllBytes(this.IdpsFile, httpClient.GetAsync(idpsHex.Uri).Result.Content.ReadAsByteArrayAsync().Result); } - + private static string GetPath(string path) { if (Path.IsPathRooted(path)) return path; diff --git a/Refresher/Refresher.csproj b/Refresher/Refresher.csproj index f21d984..3d15a3f 100644 --- a/Refresher/Refresher.csproj +++ b/Refresher/Refresher.csproj @@ -4,8 +4,8 @@ Exe enable enable - net7.0 - net7.0-windows + net8.0 + net8.0-windows Resources\refresher.ico true @@ -17,13 +17,13 @@ - - - + + + - + - + diff --git a/Refresher/UI/IntegratedPatchForm.cs b/Refresher/UI/IntegratedPatchForm.cs index 70a880b..d82a345 100644 --- a/Refresher/UI/IntegratedPatchForm.cs +++ b/Refresher/UI/IntegratedPatchForm.cs @@ -94,6 +94,8 @@ protected virtual void PathChanged(object? sender, EventArgs ev) } } + private readonly Dictionary _cachedContentIds = new(); + protected virtual void GameChanged(object? sender, EventArgs ev) { LibSceToolSharp.Init(); @@ -113,35 +115,50 @@ protected virtual void GameChanged(object? sender, EventArgs ev) string downloadedFile = this.Accessor.DownloadFile(ebootPath); + this.LogMessage($"Downloaded EBOOT Path: {downloadedFile}"); + if (!File.Exists(downloadedFile)) + { + this.FailVerify("Could not find the EBOOT. Patching cannot continue.", clear: false); + return; + } + + string contentId = LibSceToolSharp.GetContentId(downloadedFile).TrimEnd('\0'); + this._cachedContentIds[game.TitleId] = contentId; + string licenseDir = Path.Join(Path.GetTempPath(), "refresher-" + Random.Shared.Next()); Directory.CreateDirectory(licenseDir); - // if this is a NP game then download RIFs/RAPs, disc copies don't need anything else + // if this is a NP game then download the RIF for the right content ID, disc copies don't need anything else if (game.TitleId.StartsWith('N')) { - // TODO: the first user might not have the licenses necessary, should download from all users - IEnumerable licenseFiles = this.Accessor.GetFilesInDirectory(Path.Combine("home", "00000001", "exdata")); - foreach (string licenseFile in licenseFiles) + foreach (string user in this.Accessor.GetDirectoriesInDirectory(Path.Combine("home"))) { - // only download if it contains our game's title id - // TODO: determine content id directly so we skip dlc licenses - if(!licenseFile.Contains(game.TitleId)) continue; - - string downloadedLicenseFile = this.Accessor.DownloadFile(licenseFile); - File.Move(downloadedLicenseFile, Path.Join(licenseDir, Path.GetFileName(licenseFile))); + foreach (string licenseFile in this.Accessor.GetFilesInDirectory(Path.Combine(user, "exdata"))) + { + //If the license file does not contain the content ID in its path, skip it + if (!licenseFile.Contains(contentId)) + continue; + + //If it is a valid content id, lets download that user's exdata + string downloadedActDat = this.Accessor.DownloadFile(Path.Combine(user, "exdata", "act.dat")); + LibSceToolSharp.SetActDatFilePath(downloadedActDat); + + //And the license file + string downloadedLicenseFile = this.Accessor.DownloadFile(licenseFile); + File.Move(downloadedLicenseFile, Path.Join(licenseDir, Path.GetFileName(licenseFile))); + + Console.WriteLine($"Downloaded license file {licenseFile}."); + } } } - this.LogMessage($"Downloaded EBOOT Path: {downloadedFile}"); - if (!File.Exists(downloadedFile)) - { - this.FailVerify("Could not find the EBOOT. Patching cannot continue.", clear: false); - return; - } - this._tempFile = Path.GetTempFileName(); - - LibSceToolSharp.SetRapDirectory(licenseDir); + + //If we are using the console patch accessor, fill out the IDPS patch file. + if (this.Accessor is ConsolePatchAccessor consolePatchAccessor) + LibSceToolSharp.SetIdpsFilePath(consolePatchAccessor.IdpsFile); + + LibSceToolSharp.SetRifPath(licenseDir); LibSceToolSharp.Decrypt(downloadedFile, this._tempFile); this.LogMessage($"The EBOOT has been successfully decrypted. It's stored at {this._tempFile}."); @@ -160,8 +177,19 @@ public override void CompletePatch(object? sender, EventArgs e) { string fileToUpload; if (this.NeedsResign) { + GameItem? game = this.GameDropdown.SelectedValue as GameItem; + Debug.Assert(game != null); + string encryptedTempFile = Path.GetTempFileName(); - LibSceToolSharp.SetDiscEncryptOptions(); + if (game.TitleId.StartsWith('N')) + { + LibSceToolSharp.SetNpdrmEncryptOptions(); + LibSceToolSharp.SetNpdrmContentId(this._cachedContentIds[game.TitleId]); + } + else + { + LibSceToolSharp.SetDiscEncryptOptions(); + } LibSceToolSharp.Encrypt(this._tempFile, encryptedTempFile); fileToUpload = encryptedTempFile;