mirror of
https://github.com/LBPUnion/UnionPatcher.git
synced 2025-04-19 19:15:28 +00:00
Merge UnionRemotePatcher into UnionPatcher
Squashed commit of the following: commit db54f752b1a7d876c8e8ac23f64fac0e133c6c42 Author: jvyden <jvyden@jvyden.xyz> Date: Tue Jun 14 21:50:24 2022 -0400 Fix warnings in Program.cs, remove version commit abab75e00a9fa5c762669365a130025b7fa28522 Author: jvyden <jvyden@jvyden.xyz> Date: Tue Jun 14 21:45:08 2022 -0400 Enforce file-scoped namespaces commit d004b8dd77546b0dedc572bc3e7849677a707697 Author: jvyden <jvyden@jvyden.xyz> Date: Tue Jun 14 21:43:53 2022 -0400 Cleanup remote patching commit d611df7e2e5ad86466acb3fe95b835e5df3efa38 Author: jvyden <jvyden@jvyden.xyz> Date: Tue Jun 14 21:25:57 2022 -0400 Theoretically working state commit 18b362e268d800bac3c6fa5c3ae0c0b896627648 Author: jvyden <jvyden@jvyden.xyz> Date: Tue Jun 14 21:10:58 2022 -0400 Import code from UnionRemotePatcher Co-authored-by: Logan Lowe <loganr.lowe@gmail.com>
This commit is contained in:
parent
ff38cd2bd6
commit
447ca7b4a5
11 changed files with 2287 additions and 65 deletions
403
.gitignore
vendored
403
.gitignore
vendored
|
@ -1,5 +1,398 @@
|
|||
bin/
|
||||
obj/
|
||||
/packages/
|
||||
riderModule.iml
|
||||
/_ReSharper.Caches/
|
||||
## Ignore Visual Studio temporary files, build results, and
|
||||
## files generated by popular Visual Studio add-ons.
|
||||
##
|
||||
## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore
|
||||
|
||||
# User-specific files
|
||||
*.rsuser
|
||||
*.suo
|
||||
*.user
|
||||
*.userosscache
|
||||
*.sln.docstates
|
||||
|
||||
# User-specific files (MonoDevelop/Xamarin Studio)
|
||||
*.userprefs
|
||||
|
||||
# Mono auto generated files
|
||||
mono_crash.*
|
||||
|
||||
# Build results
|
||||
[Dd]ebug/
|
||||
[Dd]ebugPublic/
|
||||
[Rr]elease/
|
||||
[Rr]eleases/
|
||||
x64/
|
||||
x86/
|
||||
[Ww][Ii][Nn]32/
|
||||
[Aa][Rr][Mm]/
|
||||
[Aa][Rr][Mm]64/
|
||||
bld/
|
||||
[Bb]in/
|
||||
[Oo]bj/
|
||||
[Ll]og/
|
||||
[Ll]ogs/
|
||||
|
||||
# Visual Studio 2015/2017 cache/options directory
|
||||
.vs/
|
||||
# Uncomment if you have tasks that create the project's static files in wwwroot
|
||||
#wwwroot/
|
||||
|
||||
# Visual Studio 2017 auto generated files
|
||||
Generated\ Files/
|
||||
|
||||
# MSTest test Results
|
||||
[Tt]est[Rr]esult*/
|
||||
[Bb]uild[Ll]og.*
|
||||
|
||||
# NUnit
|
||||
*.VisualState.xml
|
||||
TestResult.xml
|
||||
nunit-*.xml
|
||||
|
||||
# Build Results of an ATL Project
|
||||
[Dd]ebugPS/
|
||||
[Rr]eleasePS/
|
||||
dlldata.c
|
||||
|
||||
# Benchmark Results
|
||||
BenchmarkDotNet.Artifacts/
|
||||
|
||||
# .NET Core
|
||||
project.lock.json
|
||||
project.fragment.lock.json
|
||||
artifacts/
|
||||
|
||||
# ASP.NET Scaffolding
|
||||
ScaffoldingReadMe.txt
|
||||
|
||||
# StyleCop
|
||||
StyleCopReport.xml
|
||||
|
||||
# Files built by Visual Studio
|
||||
*_i.c
|
||||
*_p.c
|
||||
*_h.h
|
||||
*.ilk
|
||||
*.meta
|
||||
*.obj
|
||||
*.iobj
|
||||
*.pch
|
||||
*.pdb
|
||||
*.ipdb
|
||||
*.pgc
|
||||
*.pgd
|
||||
*.rsp
|
||||
*.sbr
|
||||
*.tlb
|
||||
*.tli
|
||||
*.tlh
|
||||
*.tmp
|
||||
*.tmp_proj
|
||||
*_wpftmp.csproj
|
||||
*.log
|
||||
*.tlog
|
||||
*.vspscc
|
||||
*.vssscc
|
||||
.builds
|
||||
*.pidb
|
||||
*.svclog
|
||||
*.scc
|
||||
|
||||
# Chutzpah Test files
|
||||
_Chutzpah*
|
||||
|
||||
# Visual C++ cache files
|
||||
ipch/
|
||||
*.aps
|
||||
*.ncb
|
||||
*.opendb
|
||||
*.opensdf
|
||||
*.sdf
|
||||
*.cachefile
|
||||
*.VC.db
|
||||
*.VC.VC.opendb
|
||||
|
||||
# Visual Studio profiler
|
||||
*.psess
|
||||
*.vsp
|
||||
*.vspx
|
||||
*.sap
|
||||
|
||||
# Visual Studio Trace Files
|
||||
*.e2e
|
||||
|
||||
# TFS 2012 Local Workspace
|
||||
$tf/
|
||||
|
||||
# Guidance Automation Toolkit
|
||||
*.gpState
|
||||
|
||||
# ReSharper is a .NET coding add-in
|
||||
_ReSharper*/
|
||||
*.[Rr]e[Ss]harper
|
||||
*.DotSettings.user
|
||||
|
||||
# TeamCity is a build add-in
|
||||
_TeamCity*
|
||||
|
||||
# DotCover is a Code Coverage Tool
|
||||
*.dotCover
|
||||
|
||||
# AxoCover is a Code Coverage Tool
|
||||
.axoCover/*
|
||||
!.axoCover/settings.json
|
||||
|
||||
# Coverlet is a free, cross platform Code Coverage Tool
|
||||
coverage*.json
|
||||
coverage*.xml
|
||||
coverage*.info
|
||||
|
||||
# Visual Studio code coverage results
|
||||
*.coverage
|
||||
*.coveragexml
|
||||
|
||||
# NCrunch
|
||||
_NCrunch_*
|
||||
.*crunch*.local.xml
|
||||
nCrunchTemp_*
|
||||
|
||||
# MightyMoose
|
||||
*.mm.*
|
||||
AutoTest.Net/
|
||||
|
||||
# Web workbench (sass)
|
||||
.sass-cache/
|
||||
|
||||
# Installshield output folder
|
||||
[Ee]xpress/
|
||||
|
||||
# DocProject is a documentation generator add-in
|
||||
DocProject/buildhelp/
|
||||
DocProject/Help/*.HxT
|
||||
DocProject/Help/*.HxC
|
||||
DocProject/Help/*.hhc
|
||||
DocProject/Help/*.hhk
|
||||
DocProject/Help/*.hhp
|
||||
DocProject/Help/Html2
|
||||
DocProject/Help/html
|
||||
|
||||
# Click-Once directory
|
||||
publish/
|
||||
|
||||
# Publish Web Output
|
||||
*.[Pp]ublish.xml
|
||||
*.azurePubxml
|
||||
# Note: Comment the next line if you want to checkin your web deploy settings,
|
||||
# but database connection strings (with potential passwords) will be unencrypted
|
||||
*.pubxml
|
||||
*.publishproj
|
||||
|
||||
# Microsoft Azure Web App publish settings. Comment the next line if you want to
|
||||
# checkin your Azure Web App publish settings, but sensitive information contained
|
||||
# in these scripts will be unencrypted
|
||||
PublishScripts/
|
||||
|
||||
# NuGet Packages
|
||||
*.nupkg
|
||||
# NuGet Symbol Packages
|
||||
*.snupkg
|
||||
# The packages folder can be ignored because of Package Restore
|
||||
**/[Pp]ackages/*
|
||||
# except build/, which is used as an MSBuild target.
|
||||
!**/[Pp]ackages/build/
|
||||
# Uncomment if necessary however generally it will be regenerated when needed
|
||||
#!**/[Pp]ackages/repositories.config
|
||||
# NuGet v3's project.json files produces more ignorable files
|
||||
*.nuget.props
|
||||
*.nuget.targets
|
||||
|
||||
# Microsoft Azure Build Output
|
||||
csx/
|
||||
*.build.csdef
|
||||
|
||||
# Microsoft Azure Emulator
|
||||
ecf/
|
||||
rcf/
|
||||
|
||||
# Windows Store app package directories and files
|
||||
AppPackages/
|
||||
BundleArtifacts/
|
||||
Package.StoreAssociation.xml
|
||||
_pkginfo.txt
|
||||
*.appx
|
||||
*.appxbundle
|
||||
*.appxupload
|
||||
|
||||
# Visual Studio cache files
|
||||
# files ending in .cache can be ignored
|
||||
*.[Cc]ache
|
||||
# but keep track of directories ending in .cache
|
||||
!?*.[Cc]ache/
|
||||
|
||||
# Others
|
||||
ClientBin/
|
||||
~$*
|
||||
*~
|
||||
*.dbmdl
|
||||
*.dbproj.schemaview
|
||||
*.jfm
|
||||
*.pfx
|
||||
*.publishsettings
|
||||
orleans.codegen.cs
|
||||
|
||||
# Including strong name files can present a security risk
|
||||
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
|
||||
#*.snk
|
||||
|
||||
# Since there are multiple workflows, uncomment next line to ignore bower_components
|
||||
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
|
||||
#bower_components/
|
||||
|
||||
# RIA/Silverlight projects
|
||||
Generated_Code/
|
||||
|
||||
# Backup & report files from converting an old project file
|
||||
# to a newer Visual Studio version. Backup files are not needed,
|
||||
# because we have git ;-)
|
||||
_UpgradeReport_Files/
|
||||
Backup*/
|
||||
UpgradeLog*.XML
|
||||
UpgradeLog*.htm
|
||||
ServiceFabricBackup/
|
||||
*.rptproj.bak
|
||||
|
||||
# SQL Server files
|
||||
*.mdf
|
||||
*.ldf
|
||||
*.ndf
|
||||
|
||||
# Business Intelligence projects
|
||||
*.rdl.data
|
||||
*.bim.layout
|
||||
*.bim_*.settings
|
||||
*.rptproj.rsuser
|
||||
*- [Bb]ackup.rdl
|
||||
*- [Bb]ackup ([0-9]).rdl
|
||||
*- [Bb]ackup ([0-9][0-9]).rdl
|
||||
|
||||
# Microsoft Fakes
|
||||
FakesAssemblies/
|
||||
|
||||
# GhostDoc plugin setting file
|
||||
*.GhostDoc.xml
|
||||
|
||||
# Node.js Tools for Visual Studio
|
||||
.ntvs_analysis.dat
|
||||
node_modules/
|
||||
|
||||
# Visual Studio 6 build log
|
||||
*.plg
|
||||
|
||||
# Visual Studio 6 workspace options file
|
||||
*.opt
|
||||
|
||||
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
|
||||
*.vbw
|
||||
|
||||
# Visual Studio 6 auto-generated project file (contains which files were open etc.)
|
||||
*.vbp
|
||||
|
||||
# Visual Studio 6 workspace and project file (working project files containing files to include in project)
|
||||
*.dsw
|
||||
*.dsp
|
||||
|
||||
# Visual Studio 6 technical files
|
||||
*.ncb
|
||||
*.aps
|
||||
|
||||
# Visual Studio LightSwitch build output
|
||||
**/*.HTMLClient/GeneratedArtifacts
|
||||
**/*.DesktopClient/GeneratedArtifacts
|
||||
**/*.DesktopClient/ModelManifest.xml
|
||||
**/*.Server/GeneratedArtifacts
|
||||
**/*.Server/ModelManifest.xml
|
||||
_Pvt_Extensions
|
||||
|
||||
# Paket dependency manager
|
||||
.paket/paket.exe
|
||||
paket-files/
|
||||
|
||||
# FAKE - F# Make
|
||||
.fake/
|
||||
|
||||
# CodeRush personal settings
|
||||
.cr/personal
|
||||
|
||||
# Python Tools for Visual Studio (PTVS)
|
||||
__pycache__/
|
||||
*.pyc
|
||||
|
||||
# Cake - Uncomment if you are using it
|
||||
# tools/**
|
||||
# !tools/packages.config
|
||||
|
||||
# Tabs Studio
|
||||
*.tss
|
||||
|
||||
# Telerik's JustMock configuration file
|
||||
*.jmconfig
|
||||
|
||||
# BizTalk build output
|
||||
*.btp.cs
|
||||
*.btm.cs
|
||||
*.odx.cs
|
||||
*.xsd.cs
|
||||
|
||||
# OpenCover UI analysis results
|
||||
OpenCover/
|
||||
|
||||
# Azure Stream Analytics local run output
|
||||
ASALocalRun/
|
||||
|
||||
# MSBuild Binary and Structured Log
|
||||
*.binlog
|
||||
|
||||
# NVidia Nsight GPU debugger configuration file
|
||||
*.nvuser
|
||||
|
||||
# MFractors (Xamarin productivity tool) working folder
|
||||
.mfractor/
|
||||
|
||||
# Local History for Visual Studio
|
||||
.localhistory/
|
||||
|
||||
# Visual Studio History (VSHistory) files
|
||||
.vshistory/
|
||||
|
||||
# BeatPulse healthcheck temp database
|
||||
healthchecksdb
|
||||
|
||||
# Backup folder for Package Reference Convert tool in Visual Studio 2017
|
||||
MigrationBackup/
|
||||
|
||||
# Ionide (cross platform F# VS Code tools) working folder
|
||||
.ionide/
|
||||
|
||||
# Fody - auto-generated XML schema
|
||||
FodyWeavers.xsd
|
||||
|
||||
# VS Code files for those working on multiple tools
|
||||
.vscode/*
|
||||
!.vscode/settings.json
|
||||
!.vscode/tasks.json
|
||||
!.vscode/launch.json
|
||||
!.vscode/extensions.json
|
||||
*.code-workspace
|
||||
|
||||
# Local History for Visual Studio Code
|
||||
.history/
|
||||
|
||||
# Windows Installer files from build outputs
|
||||
*.cab
|
||||
*.msi
|
||||
*.msix
|
||||
*.msm
|
||||
*.msp
|
||||
|
||||
# JetBrains Rider
|
||||
*.sln.iml
|
||||
|
|
|
@ -1,17 +1,16 @@
|
|||
using System.Diagnostics;
|
||||
using LBPUnion.UnionPatcher;
|
||||
|
||||
namespace LBPUnion.UnionPatcher.Cli;
|
||||
namespace UnionPatcher.Cli;
|
||||
|
||||
public static class Program {
|
||||
public const string Version = "1.0";
|
||||
|
||||
private static string fileName;
|
||||
|
||||
|
||||
private static string? fileName;
|
||||
public static string FileName {
|
||||
get {
|
||||
if(fileName != null) return fileName;
|
||||
|
||||
return fileName = Path.GetFileName(Process.GetCurrentProcess().MainModule?.FileName);
|
||||
return fileName = (Path.GetFileName(Process.GetCurrentProcess().MainModule?.FileName) ?? "");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -46,7 +45,7 @@ public static class Program {
|
|||
}
|
||||
|
||||
public static void PrintHelp() {
|
||||
Console.WriteLine($"UnionPatcher {Version}");
|
||||
Console.WriteLine("UnionPatcher");
|
||||
Console.WriteLine($" Usage: {FileName} <Input EBOOT.elf> <Server URL> <Output filename>");
|
||||
}
|
||||
}
|
|
@ -4,49 +4,13 @@ using Eto;
|
|||
using Eto.Drawing;
|
||||
using Eto.Forms;
|
||||
|
||||
namespace LBPUnion.UnionPatcher.Gui;
|
||||
namespace LBPUnion.UnionPatcher.Gui.Forms;
|
||||
|
||||
public class MainForm : Form {
|
||||
public class FilePatchForm : Form {
|
||||
#region UI
|
||||
private readonly FilePicker filePicker;
|
||||
private readonly TextBox serverUrl;
|
||||
private readonly FilePicker outputFileName;
|
||||
|
||||
public Dialog CreateOkDialog(string title, string errorMessage) {
|
||||
DynamicLayout layout = new();
|
||||
Button button;
|
||||
|
||||
layout.Spacing = new Size(5, 5);
|
||||
layout.MinimumSize = new Size(350, 100);
|
||||
|
||||
layout.BeginHorizontal();
|
||||
layout.Add(new Label {
|
||||
Text = errorMessage,
|
||||
});
|
||||
|
||||
layout.BeginHorizontal();
|
||||
layout.BeginVertical();
|
||||
layout.Add(null);
|
||||
layout.Add(button = new Button {
|
||||
Text = "OK",
|
||||
});
|
||||
|
||||
layout.EndVertical();
|
||||
layout.EndHorizontal();
|
||||
layout.EndHorizontal();
|
||||
|
||||
Dialog dialog = new() {
|
||||
Content = layout,
|
||||
Padding = new Padding(10, 10, 10, 10),
|
||||
Title = title,
|
||||
};
|
||||
|
||||
button.Click += delegate {
|
||||
dialog.Close();
|
||||
};
|
||||
|
||||
return dialog;
|
||||
}
|
||||
|
||||
public Control CreatePatchButton(int tabIndex = 0) {
|
||||
Button control = new() {
|
||||
|
@ -54,7 +18,7 @@ public class MainForm : Form {
|
|||
TabIndex = tabIndex,
|
||||
};
|
||||
|
||||
control.Click += Patch;
|
||||
control.Click += this.Patch;
|
||||
|
||||
return control;
|
||||
}
|
||||
|
@ -76,8 +40,8 @@ public class MainForm : Form {
|
|||
return control;
|
||||
}
|
||||
|
||||
public MainForm() {
|
||||
this.Title = "Union Patcher";
|
||||
public FilePatchForm() {
|
||||
this.Title = "UnionPatcher - File Patch";
|
||||
this.ClientSize = new Size(500, -1);
|
||||
this.Content = new TableLayout {
|
||||
Spacing = new Size(5,5),
|
||||
|
@ -109,27 +73,27 @@ public class MainForm : Form {
|
|||
|
||||
private void Patch() {
|
||||
if(string.IsNullOrWhiteSpace(this.filePicker.FilePath)) {
|
||||
this.CreateOkDialog("Form Error", "No file specified!").ShowModal();
|
||||
Gui.CreateOkDialog("Form Error", "No file specified!").ShowModal();
|
||||
return;
|
||||
}
|
||||
|
||||
if(string.IsNullOrWhiteSpace(this.serverUrl.Text)) {
|
||||
this.CreateOkDialog("Form Error", "No server URL specified!").ShowModal();
|
||||
Gui.CreateOkDialog("Form Error", "No server URL specified!").ShowModal();
|
||||
return;
|
||||
}
|
||||
|
||||
if(string.IsNullOrWhiteSpace(this.outputFileName.FilePath)) {
|
||||
this.CreateOkDialog("Form Error", "No output file specified!").ShowModal();
|
||||
Gui.CreateOkDialog("Form Error", "No output file specified!").ShowModal();
|
||||
return;
|
||||
}
|
||||
|
||||
if(this.filePicker.FilePath == this.outputFileName.FilePath) {
|
||||
this.CreateOkDialog("Form Error", "Input and output filename are the same! Please save the patched file with a different name so you have a backup of your the original EBOOT.ELF.").ShowModal();
|
||||
Gui.CreateOkDialog("Form Error", "Input and output filename are the same! Please save the patched file with a different name so you have a backup of your the original EBOOT.ELF.").ShowModal();
|
||||
return;
|
||||
}
|
||||
|
||||
if(!Uri.TryCreate(this.serverUrl.Text, UriKind.Absolute, out _)) {
|
||||
this.CreateOkDialog("Form Error", "Server URL is invalid! Please enter a valid URL.").ShowModal();
|
||||
Gui.CreateOkDialog("Form Error", "Server URL is invalid! Please enter a valid URL.").ShowModal();
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -138,17 +102,17 @@ public class MainForm : Form {
|
|||
ElfFile eboot = new(this.filePicker.FilePath);
|
||||
|
||||
if(eboot.IsValid == false) {
|
||||
this.CreateOkDialog("EBOOT Error", $"{eboot.Name} is not a valid ELF file (magic number mismatch)\n" + "The EBOOT must be decrypted before using this tool").ShowModal();
|
||||
Gui.CreateOkDialog("EBOOT Error", $"{eboot.Name} is not a valid ELF file (magic number mismatch)\n" + "The EBOOT must be decrypted before using this tool").ShowModal();
|
||||
return;
|
||||
}
|
||||
|
||||
if(eboot.Is64Bit == null) {
|
||||
this.CreateOkDialog("EBOOT Error", $"{eboot.Name} does not target a valid system").ShowModal();
|
||||
Gui.CreateOkDialog("EBOOT Error", $"{eboot.Name} does not target a valid system").ShowModal();
|
||||
return;
|
||||
}
|
||||
|
||||
if(string.IsNullOrWhiteSpace(eboot.Architecture)) {
|
||||
this.CreateOkDialog("EBOOT Error", $"{eboot.Name} does not target a valid architecture (PowerPC or ARM)").ShowModal();
|
||||
Gui.CreateOkDialog("EBOOT Error", $"{eboot.Name} does not target a valid architecture (PowerPC or ARM)").ShowModal();
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -156,10 +120,10 @@ public class MainForm : Form {
|
|||
Patcher.PatchFile(this.filePicker.FilePath, this.serverUrl.Text, this.outputFileName.FilePath);
|
||||
}
|
||||
catch(Exception e) {
|
||||
this.CreateOkDialog("Error occurred while patching", "An error occured while patching:\n" + e).ShowModal();
|
||||
Gui.CreateOkDialog("Error occurred while patching", "An error occured while patching:\n" + e).ShowModal();
|
||||
return;
|
||||
}
|
||||
|
||||
this.CreateOkDialog("Success!", "The Server URL has been patched to " + this.serverUrl.Text).ShowModal();
|
||||
Gui.CreateOkDialog("Success!", "The Server URL has been patched to " + this.serverUrl.Text).ShowModal();
|
||||
}
|
||||
}
|
42
UnionPatcher.Gui/Forms/ModeSelectionForm.cs
Normal file
42
UnionPatcher.Gui/Forms/ModeSelectionForm.cs
Normal file
|
@ -0,0 +1,42 @@
|
|||
using System;
|
||||
using Eto.Drawing;
|
||||
using Eto.Forms;
|
||||
|
||||
namespace LBPUnion.UnionPatcher.Gui.Forms;
|
||||
|
||||
public class ModeSelectionForm : Form {
|
||||
#region UI
|
||||
public ModeSelectionForm() {
|
||||
this.Title = "Welcome to UnionPatcher";
|
||||
this.ClientSize = new Size(500, -1);
|
||||
this.Content = new TableLayout {
|
||||
Spacing = new Size(5, 5),
|
||||
Padding = new Padding(10, 10, 10, 10),
|
||||
Rows = {
|
||||
new TableRow(
|
||||
new TableCell(new Button(openRemotePatcher) { Text = "Remote Patcher (PS3)" })
|
||||
),
|
||||
new TableRow(
|
||||
new TableCell(new Button(openLocalPatcher) { Text = "Local Patch (RPCS3)", Enabled = false })
|
||||
),
|
||||
new TableRow(
|
||||
new TableCell(new Button(openFilePatcher) { Text = "File Patch (PS3/RPCS3)" })
|
||||
),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
private void openRemotePatcher(object sender, EventArgs e) {
|
||||
new RemotePatchForm().Show();
|
||||
this.Close();
|
||||
}
|
||||
private void openLocalPatcher(object sender, EventArgs e) {
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
private void openFilePatcher(object sender, EventArgs e) {
|
||||
new FilePatchForm().Show();
|
||||
this.Close();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
182
UnionPatcher.Gui/Forms/RemotePatchForm.cs
Normal file
182
UnionPatcher.Gui/Forms/RemotePatchForm.cs
Normal file
|
@ -0,0 +1,182 @@
|
|||
using System;
|
||||
using System.Diagnostics;
|
||||
using Eto.Drawing;
|
||||
using Eto.Forms;
|
||||
|
||||
namespace LBPUnion.UnionPatcher.Gui.Forms;
|
||||
|
||||
public class RemotePatchForm : Form
|
||||
{
|
||||
public RemotePatchForm()
|
||||
{
|
||||
this.InitializeComponent();
|
||||
Console.WriteLine("Welcome to UnionRemotePatcher");
|
||||
}
|
||||
|
||||
public readonly RemotePatch RemotePatcher = new();
|
||||
|
||||
private TextBox ps3LocalIP;
|
||||
private TextBox lbpGameID;
|
||||
private TextBox serverUrl;
|
||||
private TextBox ftpUser;
|
||||
private TextBox ftpPass;
|
||||
|
||||
#region UI
|
||||
public Control CreatePatchButton(int tabIndex = 0)
|
||||
{
|
||||
Button control = new()
|
||||
{
|
||||
Text = "Patch!",
|
||||
TabIndex = tabIndex,
|
||||
Width = 200,
|
||||
};
|
||||
|
||||
control.Click += delegate {
|
||||
if (string.IsNullOrEmpty(this.ps3LocalIP.Text))
|
||||
{
|
||||
Gui.CreateOkDialog("Error", "No PS3 IP address specified!").ShowModal();
|
||||
return;
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(this.lbpGameID.Text))
|
||||
{
|
||||
Gui.CreateOkDialog("Error", "No title ID specified!").ShowModal();
|
||||
return;
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(this.serverUrl.Text))
|
||||
{
|
||||
Gui.CreateOkDialog("Error", "No server URL specified!").ShowModal();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Uri.TryCreate(this.serverUrl.Text, UriKind.Absolute, out _))
|
||||
{
|
||||
Gui.CreateOkDialog("Error", "Server URL is invalid! Please enter a valid URL.").ShowModal();
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
if (this.lbpGameID.Text.ToUpper().StartsWith('B'))
|
||||
{
|
||||
this.RemotePatcher.DiscEBOOTRemotePatch(this.ps3LocalIP.Text, this.lbpGameID.Text, this.serverUrl.Text, this.ftpUser.Text, this.ftpPass.Text);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.RemotePatcher.PSNEBOOTRemotePatch(this.ps3LocalIP.Text, this.lbpGameID.Text, this.serverUrl.Text, this.ftpUser.Text, this.ftpPass.Text);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Gui.CreateOkDialog("Error occurred while patching", "An error occured while patching:\n" + e).ShowModal();
|
||||
return;
|
||||
}
|
||||
|
||||
Gui.CreateOkDialog("Success!", $"The Server URL for {this.lbpGameID.Text} on the PS3 at {this.ps3LocalIP.Text} has been patched to {this.serverUrl.Text}").ShowModal();
|
||||
};
|
||||
|
||||
return control;
|
||||
}
|
||||
|
||||
public Control CreateRevertEBOOTButton(int tabIndex = 0)
|
||||
{
|
||||
Button control = new()
|
||||
{
|
||||
Text = "Revert EBOOT",
|
||||
TabIndex = tabIndex,
|
||||
Width = 200,
|
||||
};
|
||||
|
||||
control.Click += delegate {
|
||||
if (string.IsNullOrEmpty(this.ps3LocalIP.Text))
|
||||
{
|
||||
Gui.CreateOkDialog("Form Error", "No PS3 IP address specified!").ShowModal();
|
||||
return;
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(this.lbpGameID.Text))
|
||||
{
|
||||
Gui.CreateOkDialog("Form Error", "No game ID specified!").ShowModal();
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
this.RemotePatcher.RevertEBOOT(this.ps3LocalIP.Text, this.lbpGameID.Text, this.serverUrl.Text, this.ftpUser.Text, this.ftpPass.Text);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Gui.CreateOkDialog("Error occurred while reverting EBOOT", "An error occured while patching:\n" + e).ShowModal();
|
||||
return;
|
||||
}
|
||||
|
||||
Gui.CreateOkDialog("Success!", $"UnionRemotePatcher reverted your the EBOOT for {this.lbpGameID.Text} to stock. You're ready to patch your EBOOT again.").ShowModal();
|
||||
};
|
||||
|
||||
return control;
|
||||
}
|
||||
|
||||
public Control CreateHelpButton(int tabIndex = 0)
|
||||
{
|
||||
Button control = new()
|
||||
{
|
||||
Text = "Help",
|
||||
TabIndex = tabIndex,
|
||||
};
|
||||
|
||||
control.Click += delegate {
|
||||
Process process = new();
|
||||
|
||||
process.StartInfo.UseShellExecute = true;
|
||||
process.StartInfo.FileName = "https://www.lbpunion.com";
|
||||
process.Start();
|
||||
};
|
||||
|
||||
return control;
|
||||
}
|
||||
|
||||
void InitializeComponent()
|
||||
{
|
||||
this.Title = "UnionPatcher - Remote Patch";
|
||||
this.MinimumSize = new Size(450, 200);
|
||||
this.Resizable = false;
|
||||
this.Padding = 10;
|
||||
|
||||
this.Content = new TableLayout
|
||||
{
|
||||
Spacing = new Size(5, 5),
|
||||
Padding = new Padding(10, 10, 10, 10),
|
||||
Rows = {
|
||||
new TableRow(
|
||||
new TableCell(new Label { Text = "PS3 Local IP: ", VerticalAlignment = VerticalAlignment.Center }),
|
||||
new TableCell(this.ps3LocalIP = new TextBox { TabIndex = 0 })
|
||||
),
|
||||
new TableRow(
|
||||
new TableCell(new Label { Text = "Server URL: ", VerticalAlignment = VerticalAlignment.Center }),
|
||||
new TableCell(this.serverUrl = new TextBox { TabIndex = 1 })
|
||||
),
|
||||
new TableRow(
|
||||
new TableCell(new Label { Text = "Title ID (e.g. BCUS98245): ", VerticalAlignment = VerticalAlignment.Center }),
|
||||
new TableCell(this.lbpGameID = new TextBox { TabIndex = 2 })
|
||||
),
|
||||
new TableRow(
|
||||
new TableCell(new Label { Text = "FTP Username: ", VerticalAlignment = VerticalAlignment.Center }),
|
||||
new TableCell(this.ftpUser = new TextBox { TabIndex = 3, Text = "anonymous" })
|
||||
),
|
||||
new TableRow(
|
||||
new TableCell(new Label { Text = "FTP Password: ", VerticalAlignment = VerticalAlignment.Center }),
|
||||
new TableCell(this.ftpPass = new TextBox { TabIndex = 4 })
|
||||
),
|
||||
new TableRow(
|
||||
new TableCell(this.CreateHelpButton(7)),
|
||||
new TableRow(
|
||||
new TableCell(this.CreatePatchButton(5)),
|
||||
new TableCell(this.CreateRevertEBOOTButton(6))
|
||||
)
|
||||
),
|
||||
},
|
||||
};
|
||||
}
|
||||
#endregion
|
||||
}
|
|
@ -1,9 +1,47 @@
|
|||
using Eto.Forms;
|
||||
using Eto.Drawing;
|
||||
using Eto.Forms;
|
||||
using LBPUnion.UnionPatcher.Gui.Forms;
|
||||
|
||||
namespace LBPUnion.UnionPatcher.Gui;
|
||||
|
||||
public static class Gui {
|
||||
public static void Show() {
|
||||
new Application().Run(new MainForm());
|
||||
new Application().Run(new ModeSelectionForm());
|
||||
}
|
||||
|
||||
public static Dialog CreateOkDialog(string title, string errorMessage) {
|
||||
DynamicLayout layout = new();
|
||||
Button button;
|
||||
|
||||
layout.Spacing = new Size(5, 5);
|
||||
layout.MinimumSize = new Size(350, 100);
|
||||
|
||||
layout.BeginHorizontal();
|
||||
layout.Add(new Label {
|
||||
Text = errorMessage,
|
||||
});
|
||||
|
||||
layout.BeginHorizontal();
|
||||
layout.BeginVertical();
|
||||
layout.Add(null);
|
||||
layout.Add(button = new Button {
|
||||
Text = "OK",
|
||||
});
|
||||
|
||||
layout.EndVertical();
|
||||
layout.EndHorizontal();
|
||||
layout.EndHorizontal();
|
||||
|
||||
Dialog dialog = new() {
|
||||
Content = layout,
|
||||
Padding = new Padding(10, 10, 10, 10),
|
||||
Title = title,
|
||||
};
|
||||
|
||||
button.Click += delegate {
|
||||
dialog.Close();
|
||||
};
|
||||
|
||||
return dialog;
|
||||
}
|
||||
}
|
|
@ -1,4 +1,10 @@
|
|||
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=FTP/@EntryIndexedValue">FTP</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=ID/@EntryIndexedValue">ID</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=IDPS/@EntryIndexedValue">IDPS</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=IP/@EntryIndexedValue">IP</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=MAPI/@EntryIndexedValue">MAPI</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=PS/@EntryIndexedValue">PS</s:String>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=EBOOT/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=LITTLEBIGPLANETPSP/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=Restitcher/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
|
141
UnionPatcher/Communication/FTP.cs
Normal file
141
UnionPatcher/Communication/FTP.cs
Normal file
|
@ -0,0 +1,141 @@
|
|||
#nullable enable
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
|
||||
namespace LBPUnion.UnionPatcher.Communication;
|
||||
|
||||
public static class FTP
|
||||
{
|
||||
public static bool FileExists(string url, string user, string pass)
|
||||
{
|
||||
FtpWebRequest request = (FtpWebRequest)WebRequest.Create(url);
|
||||
request.Credentials = new NetworkCredential(user, pass);
|
||||
request.Method = WebRequestMethods.Ftp.GetDateTimestamp;
|
||||
|
||||
try
|
||||
{
|
||||
Console.Write($"FTP: Checking if file {url} exists... ");
|
||||
request.GetResponse();
|
||||
}
|
||||
catch (WebException ex)
|
||||
{
|
||||
FtpWebResponse? response = (FtpWebResponse?)ex.Response;
|
||||
if (response == null || response.StatusCode == FtpStatusCode.ActionNotTakenFileUnavailable)
|
||||
{
|
||||
Console.WriteLine("No");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Console.WriteLine("Yes");
|
||||
return true;
|
||||
}
|
||||
|
||||
public static string[] ListDirectory(string url, string user, string pass)
|
||||
{
|
||||
FtpWebRequest request = (FtpWebRequest)WebRequest.Create(url);
|
||||
request.Credentials = new NetworkCredential(user, pass);
|
||||
request.Method = WebRequestMethods.Ftp.ListDirectory;
|
||||
|
||||
try
|
||||
{
|
||||
Console.WriteLine($"FTP: Listing directory {url}");
|
||||
|
||||
FtpWebResponse response = (FtpWebResponse)request.GetResponse();
|
||||
|
||||
string names = new StreamReader(response.GetResponseStream()).ReadToEnd();
|
||||
|
||||
List<string> dirs = names
|
||||
.Split("\r\n")
|
||||
.Where(dir => !string.IsNullOrWhiteSpace(dir) && dir != "." && dir != "..")
|
||||
.ToList();
|
||||
|
||||
foreach(string dir in dirs.ToArray())
|
||||
{
|
||||
Console.WriteLine($"/{dir}");
|
||||
}
|
||||
|
||||
Console.WriteLine("");
|
||||
|
||||
return dirs.ToArray();
|
||||
}
|
||||
catch
|
||||
{
|
||||
return Array.Empty<string>();
|
||||
}
|
||||
}
|
||||
|
||||
public static void UploadFile(string source, string destination, string user, string pass)
|
||||
{
|
||||
FtpWebRequest request = (FtpWebRequest)WebRequest.Create(destination);
|
||||
request.Credentials = new NetworkCredential(user, pass);
|
||||
request.Method = WebRequestMethods.Ftp.UploadFile;
|
||||
|
||||
byte[] fileContents = File.ReadAllBytes(source);
|
||||
|
||||
request.ContentLength = fileContents.Length;
|
||||
|
||||
try
|
||||
{
|
||||
Console.WriteLine($"FTP: Uploading file {source} to {destination}");
|
||||
|
||||
using Stream requestStream = request.GetRequestStream();
|
||||
requestStream.Write(fileContents, 0, fileContents.Length);
|
||||
}
|
||||
catch
|
||||
{
|
||||
throw new WebException("Could not upload file");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static void DownloadFile(string source, string destination, string user, string pass)
|
||||
{
|
||||
FtpWebRequest request = (FtpWebRequest)WebRequest.Create(source);
|
||||
request.Credentials = new NetworkCredential(user, pass);
|
||||
request.Method = WebRequestMethods.Ftp.DownloadFile;
|
||||
|
||||
try
|
||||
{
|
||||
Console.WriteLine($"FTP: Downloading file {source} to {destination}");
|
||||
|
||||
FtpWebResponse response = (FtpWebResponse)request.GetResponse();
|
||||
|
||||
Stream responseStream = response.GetResponseStream();
|
||||
|
||||
using Stream s = File.Create(destination);
|
||||
responseStream.CopyTo(s);
|
||||
}
|
||||
catch
|
||||
{
|
||||
throw new WebException("Could not download file");
|
||||
}
|
||||
}
|
||||
|
||||
public static string ReadFile(string url, string user, string pass)
|
||||
{
|
||||
FtpWebRequest request = (FtpWebRequest)WebRequest.Create(url);
|
||||
request.Credentials = new NetworkCredential(user, pass);
|
||||
request.Method = WebRequestMethods.Ftp.DownloadFile;
|
||||
|
||||
try
|
||||
{
|
||||
Console.WriteLine($"FTP: Reading file {url}");
|
||||
|
||||
FtpWebResponse response = (FtpWebResponse)request.GetResponse();
|
||||
|
||||
Stream responseStream = response.GetResponseStream();
|
||||
|
||||
using StreamReader reader = new(responseStream);
|
||||
return reader.ReadToEnd();
|
||||
|
||||
}
|
||||
catch
|
||||
{
|
||||
return "<Error Downloading File>";
|
||||
}
|
||||
}
|
||||
}
|
1208
UnionPatcher/Communication/PS3MAPI.cs
Normal file
1208
UnionPatcher/Communication/PS3MAPI.cs
Normal file
File diff suppressed because it is too large
Load diff
27
UnionPatcher/IDPSHelper.cs
Normal file
27
UnionPatcher/IDPSHelper.cs
Normal file
|
@ -0,0 +1,27 @@
|
|||
using System;
|
||||
|
||||
namespace LBPUnion.UnionPatcher;
|
||||
|
||||
public static class IDPSHelper
|
||||
{
|
||||
public static byte[] StringToByteArray(string hex)
|
||||
{
|
||||
if (hex.Length % 2 == 1)
|
||||
throw new Exception("The binary key cannot have an odd number of digits");
|
||||
|
||||
byte[] arr = new byte[hex.Length >> 1];
|
||||
|
||||
for (int i = 0; i < hex.Length >> 1; ++i)
|
||||
{
|
||||
arr[i] = (byte)((GetHexVal(hex[i << 1]) << 4) + (GetHexVal(hex[(i << 1) + 1])));
|
||||
}
|
||||
|
||||
return arr;
|
||||
}
|
||||
|
||||
public static int GetHexVal(char hex)
|
||||
{
|
||||
int val = (int)hex;
|
||||
return val - (val < 58 ? 48 : (val < 97 ? 55 : 87));
|
||||
}
|
||||
}
|
222
UnionPatcher/RemotePatch.cs
Normal file
222
UnionPatcher/RemotePatch.cs
Normal file
|
@ -0,0 +1,222 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Runtime.InteropServices;
|
||||
using LBPUnion.UnionPatcher.Communication;
|
||||
|
||||
namespace LBPUnion.UnionPatcher;
|
||||
|
||||
public class RemotePatch
|
||||
{
|
||||
private readonly PS3MAPI _ps3Mapi = new();
|
||||
|
||||
private static Dictionary<string, string> GetUsers(string ps3Ip, string user, string pass)
|
||||
{
|
||||
Console.WriteLine("Getting users...");
|
||||
|
||||
Dictionary<string, string> users = new();
|
||||
|
||||
string[] userFolders = FTP.ListDirectory($"ftp://{ps3Ip}/dev_hdd0/home/", user, pass);
|
||||
|
||||
string username = "";
|
||||
|
||||
for (int i = 0; i < userFolders.Length; i++)
|
||||
{
|
||||
username = FTP.ReadFile($"ftp://{ps3Ip}/dev_hdd0/home/{userFolders[i]}/localusername", user,
|
||||
pass);
|
||||
users.Add(userFolders[i], username);
|
||||
|
||||
Console.WriteLine("User found: " + username + $" <{userFolders[i]}>");
|
||||
}
|
||||
|
||||
return users;
|
||||
}
|
||||
|
||||
public static void LaunchSCETool(string args)
|
||||
{
|
||||
string platformExecutable = "";
|
||||
|
||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
||||
platformExecutable = "scetool/win64/scetool.exe";
|
||||
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
|
||||
platformExecutable = "scetool/linux64/scetool";
|
||||
else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) platformExecutable = "";
|
||||
|
||||
if (platformExecutable != "")
|
||||
{
|
||||
ProcessStartInfo startInfo = new();
|
||||
startInfo.UseShellExecute = false;
|
||||
startInfo.FileName = Path.GetFullPath(platformExecutable);
|
||||
startInfo.WorkingDirectory = Path.GetFullPath(".");
|
||||
startInfo.Arguments = args;
|
||||
startInfo.RedirectStandardOutput = true;
|
||||
|
||||
Console.WriteLine("\n\n===== START SCETOOL =====\n");
|
||||
using (Process proc = Process.Start(startInfo))
|
||||
{
|
||||
while (!proc.StandardOutput.EndOfStream) Console.WriteLine(proc.StandardOutput.ReadLine());
|
||||
proc.WaitForExit();
|
||||
}
|
||||
|
||||
Console.WriteLine("\n===== END SCETOOL =====\n\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception("Error starting SCETool. Your platform may not be supported yet.");
|
||||
}
|
||||
}
|
||||
|
||||
public void RevertEBOOT(string ps3ip, string gameID, string serverURL, string user, string pass)
|
||||
{
|
||||
Console.WriteLine("Restoring original EBOOT.BIN from EBOOT.BIN.BAK");
|
||||
|
||||
// Create a simple directory structure
|
||||
Directory.CreateDirectory(@"eboot");
|
||||
Directory.CreateDirectory($@"eboot/{gameID}");
|
||||
Directory.CreateDirectory($@"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);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new WebException("Could not find EBOOT.BIN.BAK on server.");
|
||||
}
|
||||
}
|
||||
|
||||
public void PSNEBOOTRemotePatch(string ps3ip, string gameID, string serverURL, string user, string pass)
|
||||
{
|
||||
Console.WriteLine("Detected Digital Copy - Running in Full Mode");
|
||||
|
||||
string idps = "";
|
||||
string contentID = "";
|
||||
Dictionary<string, string> users;
|
||||
|
||||
this._ps3Mapi.ConnectTarget(ps3ip);
|
||||
this._ps3Mapi.PS3.RingBuzzer(PS3MAPI.PS3Cmd.BuzzerMode.Double);
|
||||
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");
|
||||
|
||||
// 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);
|
||||
|
||||
// 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://{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));
|
||||
|
||||
// Scan the users on the system
|
||||
users = GetUsers(ps3ip, user, pass);
|
||||
|
||||
// Scan the system for a license for the game
|
||||
foreach (string currentUser in users.Keys.ToArray())
|
||||
{
|
||||
if (FTP.FileExists($"ftp://{ps3ip}/dev_hdd0/home/{currentUser}/exdata", user, pass))
|
||||
{
|
||||
foreach (string fileName in FTP.ListDirectory(
|
||||
$"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",
|
||||
user,
|
||||
pass);
|
||||
|
||||
FTP.DownloadFile($"ftp://{ps3ip}/dev_hdd0/home/{currentUser}/exdata/{fileName}",
|
||||
@$"rifs/{fileName}", user, pass);
|
||||
|
||||
contentID = fileName.Substring(0, fileName.Length - 4);
|
||||
|
||||
Console.WriteLine($"Got content ID {contentID}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Finally, let's decrypt the EBOOT.BIN
|
||||
LaunchSCETool($" -v -d \"{Path.GetFullPath(@$"eboot/{gameID}/original/EBOOT.BIN")}\" \"{Path.GetFullPath(@$"eboot/{gameID}/original/EBOOT.ELF")}\"");
|
||||
|
||||
// Now, patch the EBOOT;
|
||||
Patcher.PatchFile($"eboot/{gameID}/original/EBOOT.ELF", serverURL, $"eboot/{gameID}/patched/EBOOT.ELF");
|
||||
|
||||
// Encrypt the EBOOT (PSN)
|
||||
LaunchSCETool($"--verbose " +
|
||||
$"--sce-type=SELF" +
|
||||
$" --skip-sections=FALSE" +
|
||||
$" --self-add-shdrs=TRUE" +
|
||||
$" --compress-data=TRUE" +
|
||||
$" --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=NPDRM" +
|
||||
$" --self-fw-version=0003005500000000" +
|
||||
$" --np-license-type=FREE" +
|
||||
$" --np-app-type=SPRX" +
|
||||
$" --np-content-id={contentID}" +
|
||||
$" --np-real-fname=EBOOT.BIN" +
|
||||
$" --encrypt eboot/{gameID}/patched/EBOOT.ELF eboot/{gameID}/patched/EBOOT.BIN");
|
||||
|
||||
// And upload the encrypted, patched EBOOT to the system.
|
||||
FTP.UploadFile(@$"eboot/{gameID}/patched/EBOOT.BIN",
|
||||
$"ftp://{ps3ip}/dev_hdd0/game/{gameID}/USRDIR/EBOOT.BIN", user, pass);
|
||||
}
|
||||
|
||||
// Cut-down version that only patches disc copies
|
||||
public void DiscEBOOTRemotePatch(string ps3ip, string gameID, string serverURL, string user, string pass)
|
||||
{
|
||||
Console.WriteLine("Detected Disc Copy - Running in Simplified Mode");
|
||||
|
||||
// Create a simple directory structure
|
||||
Directory.CreateDirectory(@"eboot");
|
||||
Directory.CreateDirectory($@"eboot/{gameID}");
|
||||
Directory.CreateDirectory($@"eboot/{gameID}/original");
|
||||
Directory.CreateDirectory($@"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);
|
||||
|
||||
// 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://{ps3ip}/dev_hdd0/game/{gameID}/USRDIR/EBOOT.BIN.BAK", user, pass);
|
||||
|
||||
// Check for keys in the data directory
|
||||
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");
|
||||
|
||||
// Now, patch the EBOOT;
|
||||
Patcher.PatchFile($"eboot/{gameID}/original/EBOOT.ELF", serverURL, $"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")}\"");
|
||||
|
||||
// And upload the encrypted, patched EBOOT to the system.
|
||||
FTP.UploadFile(@$"eboot/{gameID}/patched/EBOOT.BIN",
|
||||
$"ftp://{ps3ip}/dev_hdd0/game/{gameID}/USRDIR/EBOOT.BIN", user, pass);
|
||||
}
|
||||
}
|
Loading…
Add table
Reference in a new issue