Skip to content

Commit

Permalink
Remove macOS staging directory requirement, and update to .NET 8.0 (#41)
Browse files Browse the repository at this point in the history
* Code cleanup and update to .NET 8

* Fix macOS requiring staging directory to be selected.
Also places eboots on Desktop on macos, to avoid them being inside the app bundle.

* Fix keys discovery on mac

* Removed debug logging, made GetExecutablePath more robust.

* Created a script for building on mac, as creating a universal binary is somewhat involved

* Update UnionPatcher.Gui/Forms/ModeSelectionForm.cs

Co-authored-by: sudokoko <[email protected]>

* Apply suggestions from code review

Co-authored-by: Josh <[email protected]>

---------

Co-authored-by: sudokoko <[email protected]>
Co-authored-by: Josh <[email protected]>
  • Loading branch information
3 people authored Jan 19, 2024
1 parent 7b88e27 commit c45b9ec
Show file tree
Hide file tree
Showing 14 changed files with 155 additions and 59 deletions.
8 changes: 4 additions & 4 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,17 @@ jobs:
fail-fast: false
matrix:
os:
- { prettyName: Windows, platform: windows-latest, configurationName: Windows, extraArgs: "", buildPath: "Release/net6.0-windows/publish"}
- { prettyName: Linux, platform: ubuntu-latest, configurationName: Linux, extraArgs: "", buildPath: "Release/net6.0/publish"}
- { prettyName: Windows, platform: windows-latest, configurationName: Windows, extraArgs: "", buildPath: "Release/net8.0-windows/publish"}
- { prettyName: Linux, platform: ubuntu-latest, configurationName: Linux, extraArgs: "", buildPath: "Release/net8.0/publish"}
# - { prettyName: MacOS, platform: ubuntu-latest, configurationName: Release, platform: osx-x64 }
steps:
- name: Checkout
uses: actions/checkout@v2

- name: Install .NET 6.0
- name: Install .NET 8.0
uses: actions/setup-dotnet@v1
with:
dotnet-version: "6.0.x"
dotnet-version: "8.0.x"

- name: Compile for ${{ matrix.os.prettyName }}
run: dotnet publish -c ${{ matrix.os.configurationName }} ${{ matrix.os.extraArgs }}
Expand Down
2 changes: 1 addition & 1 deletion UnionPatcher.Cli/UnionPatcher.Cli.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<AssemblyName>UnionPatcher</AssemblyName>
Expand Down
2 changes: 1 addition & 1 deletion UnionPatcher.Gui.Linux/UnionPatcher.Gui.Linux.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
<RuntimeIdentifiers>linux-x64</RuntimeIdentifiers>
<AssemblyName>LBPUnion.UnionPatcher.Gui.Linux</AssemblyName>
<RootNamespace>LBPUnion.UnionPatcher.Gui.Linux</RootNamespace>
Expand Down
34 changes: 34 additions & 0 deletions UnionPatcher.Gui.MacOS/Info.plist
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleIdentifier</key>
<string>com.lbpunion.unionpatcher</string>
<key>NSHumanReadableCopyright</key>
<string>Copyright LBP Union 2024©</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleIconFile</key>
<string>Icon.icns</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>NSPrincipalClass</key>
<string>NSApplication</string>
<key>CFBundleName</key>
<string>UnionPatcher</string>
<key>CFBundleExecutable</key>
<string>LBPUnion.UnionPatcher.Gui.MacOS</string>
<key>LSMinimumSystemVersion</key>
<string>10.14</string>
<key>NSRequiresAquaSystemAppearance</key>
<string>False</string>
</dict>
</plist>
4 changes: 3 additions & 1 deletion UnionPatcher.Gui.MacOS/UnionPatcher.Gui.MacOS.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
<RuntimeIdentifiers>osx-x64;osx-arm64</RuntimeIdentifiers>
<AssemblyName>LBPUnion.UnionPatcher.Gui.MacOS</AssemblyName>
<RootNamespace>LBPUnion.UnionPatcher.Gui.MacOS</RootNamespace>
<ApplicationIcon>Icon64.ico</ApplicationIcon>
<PublishSingleFile>true</PublishSingleFile>
<SelfContained>true</SelfContained>
</PropertyGroup>

<ItemGroup>
Expand Down
2 changes: 1 addition & 1 deletion UnionPatcher.Gui.Windows/UnionPatcher.Gui.Windows.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net6.0-windows</TargetFramework>
<TargetFramework>net8.0-windows</TargetFramework>
<RootNamespace>LBPUnion.UnionPatcher.Gui.Windows</RootNamespace>
<AssemblyName>LBPUnion.UnionPatcher.Gui.Windows</AssemblyName>
<ApplicationIcon>Icon64.ico</ApplicationIcon>
Expand Down
9 changes: 7 additions & 2 deletions UnionPatcher.Gui/Forms/ModeSelectionForm.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
using System;
using System.IO;
using System.Reflection;
using System.Text;
using Eto;
using Eto.Drawing;
using Eto.Forms;

Expand Down Expand Up @@ -29,11 +32,13 @@ public ModeSelectionForm() {

private void openRemotePatcher(object sender, EventArgs e)
{
if (!Directory.Exists("scetool"))
// If we're on macOS then set the CWD to the app bundle MacOS folder, so that SCETool can be found.
if (OSUtil.GetPlatform() == OSPlatform.OSX) Directory.SetCurrentDirectory(OSUtil.GetExecutablePath());

if (!Directory.Exists($"{OSUtil.GetExecutablePath()}/scetool"))
{
// This will always occur on macOS, so don't show this message for macOS users.
if (OSUtil.GetPlatform() != OSPlatform.OSX) Gui.CreateOkDialog("Workaround Triggered", ".NET could not locate the required files, triggering workaround.");

Gui.CreateOkDialog("Workaround", "UnionPatcher RemotePatcher requires a staging folder on macOS or in special circumstances on Windows, please set this to the directory of the UnionPatcher app or executable!");
SelectFolderDialog dialog = new SelectFolderDialog();
if (dialog.ShowDialog(this) != DialogResult.Ok)
Expand Down
5 changes: 2 additions & 3 deletions UnionPatcher.Gui/Gui.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using Eto.Drawing;
using Eto.Forms;
using Eto.Forms;
using LBPUnion.UnionPatcher.Gui.Forms;

namespace LBPUnion.UnionPatcher.Gui;
Expand All @@ -10,7 +9,7 @@ public static void Show() {
}

public static void CreateOkDialog(string title, string errorMessage) {
MessageBox.Show(errorMessage, title, MessageBoxButtons.OK, MessageBoxType.Information);
MessageBox.Show(errorMessage, title, MessageBoxButtons.OK);
}
public static bool CreateConfirmationDialog(string title, string errorMessage) {
DialogResult result = MessageBox.Show(errorMessage, title, MessageBoxButtons.YesNo, MessageBoxType.Question);
Expand Down
4 changes: 2 additions & 2 deletions UnionPatcher.Gui/UnionPatcher.Gui.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@
</PropertyGroup>

<PropertyGroup Condition=" '$(Configuration)' != 'Windows' ">
<TargetFramework>net6.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
</PropertyGroup>

<PropertyGroup Condition=" '$(Configuration)' == 'Windows' ">
<TargetFramework>net6.0-windows</TargetFramework>
<TargetFramework>net8.0-windows</TargetFramework>
</PropertyGroup>

<ItemGroup>
Expand Down
14 changes: 14 additions & 0 deletions UnionPatcher/OSUtil.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;

namespace LBPUnion.UnionPatcher
Expand Down Expand Up @@ -29,6 +32,17 @@ public static OSPlatform GetPlatform()
return EnumeratePlatforms().FirstOrDefault(p
=> RuntimeInformation.IsOSPlatform(p.Value.RuntimePlatform))?.Platform ?? default;
}

public static string GetExecutablePath()
{
var path = Path.GetDirectoryName(Assembly.GetEntryAssembly()?.Location);
if (string.IsNullOrEmpty(path))
path = Path.GetDirectoryName(Process.GetCurrentProcess().MainModule?.FileName);
if (string.IsNullOrEmpty(path))
path = AppContext.BaseDirectory;

return path;
}
}
}

81 changes: 51 additions & 30 deletions UnionPatcher/RemotePatch.cs
Original file line number Diff line number Diff line change
Expand Up @@ -91,16 +91,23 @@ public void RevertEBOOT(string ps3ip, string gameID, string serverURL, string us
{
Console.WriteLine("Restoring original EBOOT.BIN from EBOOT.BIN.BAK");

string workingDir = ".";
if (OSUtil.GetPlatform() == OSPlatform.OSX)
{
workingDir = $"{Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments)}/UnionPatcher";
Directory.CreateDirectory(workingDir);
}

// Create a simple directory structure
Directory.CreateDirectory(@"eboot");
Directory.CreateDirectory($@"eboot/{gameID}");
Directory.CreateDirectory($@"eboot/{gameID}/original");
Directory.CreateDirectory($@"{workingDir}/eboot");
Directory.CreateDirectory($@"{workingDir}/eboot/{gameID}");
Directory.CreateDirectory($@"{workingDir}/eboot/{gameID}/original");

// Now we'll check and see if a backup exists on the server, if so download it and then upload it back as EBOOT.BIN
if (FTP.FileExists($"ftp://{ps3ip}/dev_hdd0/game/{gameID}/USRDIR/EBOOT.BIN.BAK", user, pass))
{
FTP.DownloadFile($"ftp://{ps3ip}/dev_hdd0/game/{gameID}/USRDIR/EBOOT.BIN.BAK", @$"eboot/{gameID}/original/EBOOT.BIN.BAK", user, pass);
FTP.UploadFile(@$"eboot/{gameID}/original/EBOOT.BIN.BAK", $"ftp://{ps3ip}/dev_hdd0/game/{gameID}/USRDIR/EBOOT.BIN", user, pass);
FTP.DownloadFile($"ftp://{ps3ip}/dev_hdd0/game/{gameID}/USRDIR/EBOOT.BIN.BAK", @$"{workingDir}/eboot/{gameID}/original/EBOOT.BIN.BAK", user, pass);
FTP.UploadFile(@$"{workingDir}/eboot/{gameID}/original/EBOOT.BIN.BAK", $"ftp://{ps3ip}/dev_hdd0/game/{gameID}/USRDIR/EBOOT.BIN", user, pass);
}
else
{
Expand All @@ -111,6 +118,13 @@ public void RevertEBOOT(string ps3ip, string gameID, string serverURL, string us
public void PSNEBOOTRemotePatch(string ps3ip, string gameID, string serverURL, string user, string pass)
{
Console.WriteLine("Detected Digital Copy - Running in Full Mode");

string workingDir = ".";
if (OSUtil.GetPlatform() == OSPlatform.OSX)
{
workingDir = $"{Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments)}/UnionPatcher";
Directory.CreateDirectory(workingDir);
}

string idps = "";
string contentID = "";
Expand All @@ -121,25 +135,25 @@ public void PSNEBOOTRemotePatch(string ps3ip, string gameID, string serverURL, s
this._ps3Mapi.PS3.Notify("UnionRemotePatcher Connected! Patching...");

// Create simple directory structure
Directory.CreateDirectory(@"rifs");
Directory.CreateDirectory(@"eboot");
Directory.CreateDirectory($@"eboot/{gameID}");
Directory.CreateDirectory($@"eboot/{gameID}/original");
Directory.CreateDirectory($@"eboot/{gameID}/patched");
Directory.CreateDirectory($@"{workingDir}/rifs");
Directory.CreateDirectory($@"{workingDir}/eboot");
Directory.CreateDirectory($@"{workingDir}/eboot/{gameID}");
Directory.CreateDirectory($@"{workingDir}/eboot/{gameID}/original");
Directory.CreateDirectory($@"{workingDir}/eboot/{gameID}/patched");

// Let's grab and backup our EBOOT
FTP.DownloadFile($"ftp://{ps3ip}/dev_hdd0/game/{gameID}/USRDIR/EBOOT.BIN",
@$"eboot/{gameID}/original/EBOOT.BIN", user, pass);
@$"{workingDir}/eboot/{gameID}/original/EBOOT.BIN", user, pass);

// Now we'll check and see if a backup exists on the server or not, if we don't have one on the server, then upload one
if (!FTP.FileExists($"ftp://{ps3ip}/dev_hdd0/game/{gameID}/USRDIR/EBOOT.BIN.BAK", user, pass))
FTP.UploadFile(@$"eboot/{gameID}/original/EBOOT.BIN",
FTP.UploadFile(@$"{workingDir}/eboot/{gameID}/original/EBOOT.BIN",
$"ftp://{ps3ip}/dev_hdd0/game/{gameID}/USRDIR/EBOOT.BIN.BAK", user, pass);

// Start getting idps and act.dat - these will help us decrypt a PSN eboot
idps = PS3MAPI.PS3MAPIClientServer.PS3_GetIDPS();

File.WriteAllBytes(@"data/idps", IDPSHelper.StringToByteArray(idps));
File.WriteAllBytes($@"data/idps", IDPSHelper.StringToByteArray(idps));

// Scan the users on the system
users = GetUsers(ps3ip, user, pass);
Expand All @@ -153,12 +167,12 @@ public void PSNEBOOTRemotePatch(string ps3ip, string gameID, string serverURL, s
$"ftp://{ps3ip}/dev_hdd0/home/{currentUser}/exdata/", user, pass))
if (fileName.Contains(gameID))
{
FTP.DownloadFile($"ftp://{ps3ip}/dev_hdd0/home/{currentUser}/exdata/act.dat", @"data/act.dat",
FTP.DownloadFile($"ftp://{ps3ip}/dev_hdd0/home/{currentUser}/exdata/act.dat", $@"{workingDir}/data/act.dat",
user,
pass);

FTP.DownloadFile($"ftp://{ps3ip}/dev_hdd0/home/{currentUser}/exdata/{fileName}",
@$"rifs/{fileName}", user, pass);
@$"{workingDir}/rifs/{fileName}", user, pass);

contentID = fileName.Substring(0, fileName.Length - 4);

Expand All @@ -168,10 +182,10 @@ public void PSNEBOOTRemotePatch(string ps3ip, string gameID, string serverURL, s
}

// Finally, let's decrypt the EBOOT.BIN
LaunchSCETool($" -v -d \"{Path.GetFullPath(@$"eboot/{gameID}/original/EBOOT.BIN")}\" \"{Path.GetFullPath(@$"eboot/{gameID}/original/EBOOT.ELF")}\"");
LaunchSCETool($" -v -d \"{Path.GetFullPath(@$"{workingDir}/eboot/{gameID}/original/EBOOT.BIN")}\" \"{Path.GetFullPath(@$"{workingDir}/eboot/{gameID}/original/EBOOT.ELF")}\"");

// Now, patch the EBOOT;
Patcher.PatchFile($"eboot/{gameID}/original/EBOOT.ELF", serverURL, $"eboot/{gameID}/patched/EBOOT.ELF");
Patcher.PatchFile($"{workingDir}/eboot/{gameID}/original/EBOOT.ELF", serverURL, $"{workingDir}/eboot/{gameID}/patched/EBOOT.ELF");

// Encrypt the EBOOT (PSN)
LaunchSCETool($"--verbose " +
Expand All @@ -191,10 +205,10 @@ public void PSNEBOOTRemotePatch(string ps3ip, string gameID, string serverURL, s
$" --np-app-type=SPRX" +
$" --np-content-id={contentID}" +
$" --np-real-fname=EBOOT.BIN" +
$" --encrypt eboot/{gameID}/patched/EBOOT.ELF eboot/{gameID}/patched/EBOOT.BIN");
$" --encrypt {workingDir}/eboot/{gameID}/patched/EBOOT.ELF {workingDir}/eboot/{gameID}/patched/EBOOT.BIN");

// And upload the encrypted, patched EBOOT to the system.
FTP.UploadFile(@$"eboot/{gameID}/patched/EBOOT.BIN",
FTP.UploadFile(@$"{workingDir}/eboot/{gameID}/patched/EBOOT.BIN",
$"ftp://{ps3ip}/dev_hdd0/game/{gameID}/USRDIR/EBOOT.BIN", user, pass);
}

Expand All @@ -203,38 +217,45 @@ public void DiscEBOOTRemotePatch(string ps3ip, string gameID, string serverURL,
{
Console.WriteLine("Detected Disc Copy - Running in Simplified Mode");

string workingDir = ".";
if (OSUtil.GetPlatform() == OSPlatform.OSX)
{
workingDir = $"{Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments)}/UnionPatcher";
Directory.CreateDirectory(workingDir);
}

// Create a simple directory structure
Directory.CreateDirectory(@"eboot");
Directory.CreateDirectory($@"eboot/{gameID}");
Directory.CreateDirectory($@"eboot/{gameID}/original");
Directory.CreateDirectory($@"eboot/{gameID}/patched");
Directory.CreateDirectory($@"{workingDir}/eboot");
Directory.CreateDirectory($@"{workingDir}/eboot/{gameID}");
Directory.CreateDirectory($@"{workingDir}/eboot/{gameID}/original");
Directory.CreateDirectory($@"{workingDir}/eboot/{gameID}/patched");

// Let's grab and backup our EBOOT
FTP.DownloadFile($"ftp://{ps3ip}/dev_hdd0/game/{gameID}/USRDIR/EBOOT.BIN",
@$"eboot/{gameID}/original/EBOOT.BIN", user, pass);
@$"{workingDir}/eboot/{gameID}/original/EBOOT.BIN", user, pass);

// Now we'll check and see if a backup exists on the server or not, if we don't have one on the server, then upload one
if (!FTP.FileExists($"ftp://{ps3ip}/dev_hdd0/game/{gameID}/USRDIR/EBOOT.BIN.BAK", user, pass))
FTP.UploadFile(@$"eboot/{gameID}/original/EBOOT.BIN",
FTP.UploadFile(@$"{workingDir}/eboot/{gameID}/original/EBOOT.BIN",
$"ftp://{ps3ip}/dev_hdd0/game/{gameID}/USRDIR/EBOOT.BIN.BAK", user, pass);

// Check for keys in the data directory
if (!File.Exists("data/keys"))
if (!File.Exists($"./data/keys"))
throw new FileNotFoundException(
"UnionRemotePatcher cannot find the keys, ldr_curves, or vsh_curves files required to continue. Please make sure you have copies of these files placed in the data directory where you found the executable to run UnionRemotePatcher. Without them, we can't patch your game.");

// Decrypt the EBOOT
LaunchSCETool($"-v -d eboot/{gameID}/original/EBOOT.BIN eboot/{gameID}/original/EBOOT.ELF");
LaunchSCETool($"-v -d {workingDir}/eboot/{gameID}/original/EBOOT.BIN {workingDir}/eboot/{gameID}/original/EBOOT.ELF");

// Now, patch the EBOOT;
Patcher.PatchFile($"eboot/{gameID}/original/EBOOT.ELF", serverURL, $"eboot/{gameID}/patched/EBOOT.ELF");
Patcher.PatchFile($"{workingDir}/eboot/{gameID}/original/EBOOT.ELF", serverURL, $"{workingDir}/eboot/{gameID}/patched/EBOOT.ELF");

// Encrypt the EBOOT (Disc)
LaunchSCETool(
$" -v --sce-type=SELF --skip-sections=FALSE --key-revision=0A --self-app-version=0001000000000000 --self-auth-id=1010000001000003 --self-vendor-id=01000002 --self-ctrl-flags=0000000000000000000000000000000000000000000000000000000000000000 --self-cap-flags=00000000000000000000000000000000000000000000003B0000000100040000 --self-type=APP --self-fw-version=0003005500000000 --compress-data true --encrypt \"{Path.GetFullPath(@$"eboot/{gameID}/patched/EBOOT.ELF")}\" \"{Path.GetFullPath(@$"eboot/{gameID}/patched/EBOOT.BIN")}\"");
$" -v --sce-type=SELF --skip-sections=FALSE --key-revision=0A --self-app-version=0001000000000000 --self-auth-id=1010000001000003 --self-vendor-id=01000002 --self-ctrl-flags=0000000000000000000000000000000000000000000000000000000000000000 --self-cap-flags=00000000000000000000000000000000000000000000003B0000000100040000 --self-type=APP --self-fw-version=0003005500000000 --compress-data true --encrypt \"{Path.GetFullPath(@$"{workingDir}/eboot/{gameID}/patched/EBOOT.ELF")}\" \"{Path.GetFullPath(@$"{workingDir}/eboot/{gameID}/patched/EBOOT.BIN")}\"");

// And upload the encrypted, patched EBOOT to the system.
FTP.UploadFile(@$"eboot/{gameID}/patched/EBOOT.BIN",
FTP.UploadFile(@$"{workingDir}/eboot/{gameID}/patched/EBOOT.BIN",
$"ftp://{ps3ip}/dev_hdd0/game/{gameID}/USRDIR/EBOOT.BIN", user, pass);
}
}
2 changes: 1 addition & 1 deletion UnionPatcher/UnionPatcher.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<AssemblyName>LBPUnion.UnionPatcher</AssemblyName>
<RootNamespace>LBPUnion.UnionPatcher</RootNamespace>
<Configurations>Debug;Release;Windows</Configurations>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
<Platforms>AnyCPU</Platforms>
<ApplicationIcon>Icon64.ico</ApplicationIcon>
</PropertyGroup>
Expand Down
Loading

0 comments on commit c45b9ec

Please sign in to comment.