From 4a68509d2b3077ca06e83bb0b42da975c99a53db Mon Sep 17 00:00:00 2001 From: Jake <505e06b2@gmail.com> Date: Sun, 20 Feb 2022 16:39:00 +0000 Subject: [PATCH 1/5] Preliminary ELF file checks --- UnionPatcher.Gui/MainForm.cs | 38 +++++++++++++----- UnionPatcher/ElfFile.cs | 74 ++++++++++++++++++++++++++++++++++++ UnionPatcher/Program.cs | 25 ++++++++++-- 3 files changed, 124 insertions(+), 13 deletions(-) create mode 100644 UnionPatcher/ElfFile.cs diff --git a/UnionPatcher.Gui/MainForm.cs b/UnionPatcher.Gui/MainForm.cs index 9276123..4c75668 100644 --- a/UnionPatcher.Gui/MainForm.cs +++ b/UnionPatcher.Gui/MainForm.cs @@ -1,4 +1,5 @@ using System; +using System.IO; using System.Diagnostics; using Eto; using Eto.Drawing; @@ -21,14 +22,14 @@ namespace LBPUnion.UnionPatcher.Gui { 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(); @@ -42,10 +43,10 @@ namespace LBPUnion.UnionPatcher.Gui { button.Click += delegate { dialog.Close(); }; - + return dialog; } - + public Control CreatePatchButton(int tabIndex = 0) { Button control = new() { Text = EasterEgg.Restitch ? "Restitch!" : "Patch!", @@ -53,21 +54,38 @@ namespace LBPUnion.UnionPatcher.Gui { }; control.Click += delegate { - if(string.IsNullOrEmpty(this.filePicker.FilePath)) { + if(string.IsNullOrWhiteSpace(this.filePicker.FilePath)) { this.CreateOkDialog("Form Error", "No file specified!").ShowModal(); return; } - if(string.IsNullOrEmpty(this.serverUrl.Text)) { + if(string.IsNullOrWhiteSpace(this.serverUrl.Text)) { this.CreateOkDialog("Form Error", "No server URL specified!").ShowModal(); return; } - if(string.IsNullOrEmpty(this.outputFileName.FilePath)) { + if(string.IsNullOrWhiteSpace(this.outputFileName.FilePath)) { this.CreateOkDialog("Form Error", "No output file specified!").ShowModal(); return; } + 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)").ShowModal(); + return; + } + + if(eboot.Is64Bit == null) { + this.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(); + return; + } + try { Patcher.PatchFile(this.filePicker.FilePath, this.serverUrl.Text, this.outputFileName.FilePath); } @@ -87,7 +105,7 @@ namespace LBPUnion.UnionPatcher.Gui { Text = "Help", TabIndex = tabIndex, }; - + control.Click += delegate { Process process = new(); @@ -98,7 +116,7 @@ namespace LBPUnion.UnionPatcher.Gui { return control; } - + public MainForm() { this.Title = EasterEgg.Restitch ? "Union Restitcher" : "Union Patcher"; this.ClientSize = new Size(500, -1); @@ -126,4 +144,4 @@ namespace LBPUnion.UnionPatcher.Gui { }; } } -} \ No newline at end of file +} diff --git a/UnionPatcher/ElfFile.cs b/UnionPatcher/ElfFile.cs new file mode 100644 index 0000000..b578773 --- /dev/null +++ b/UnionPatcher/ElfFile.cs @@ -0,0 +1,74 @@ +using System; +using System.IO; +using System.Linq; +using System.Buffers.Binary; + +/* +Linux ELF header refspec: https://refspecs.linuxfoundation.org/elf/gabi4+/ch4.eheader.html +Wikipedia entry on ELF: https://en.wikipedia.org/wiki/Executable_and_Linkable_Format +*/ + +namespace LBPUnion.UnionPatcher { + public class ElfFile { + private enum WordSize : byte { + ThirtyTwoBits = 0x01, + SixtyFourBits = 0x02 + } + + private enum Endianness : byte { + Little = 0x01, + Big = 0x02 + } + + private enum InstructionSetArchitecture : UInt16 { + PowerPC = 0x15, //64-bit PowerPC (PS3) + ARM = 0x28 //32-bit ARM (Vita) + } + + public string Name { get; } = "Binary Blob"; + + public bool IsValid { get; } + public bool? Is64Bit { get; } = null; + public bool? IsBigEndian { get; } = null; + public string Architecture { get; } = null; + + public byte[] Contents { get; } = null; + + public ElfFile(byte[] fileContents) { + IsValid = fileContents[0x00..0x04].SequenceEqual(new byte[] {0x7F, (byte)'E', (byte)'L', (byte)'F'}); + if(IsValid == false) return; + + byte identClassValue = fileContents[0x04]; + byte identDataValue = fileContents[0x05]; + + if(identClassValue == (byte)WordSize.ThirtyTwoBits || identClassValue == (byte)WordSize.SixtyFourBits) + Is64Bit = identClassValue == (byte)WordSize.SixtyFourBits; + + if(identDataValue == (byte)Endianness.Little || identDataValue == (byte)Endianness.Big) + IsBigEndian = identDataValue == (byte)Endianness.Big; + + Architecture = GetFileArchitecture(fileContents, IsBigEndian == true); + + Contents = fileContents; + } + + public ElfFile(FileInfo file) : this(File.ReadAllBytes(file.FullName)) { + Name = file.Name; + } + + public ElfFile(string fileName) : this(new FileInfo(fileName)) {} + + private string GetFileArchitecture(byte[] elfHeader, bool isBigEndian) { + byte[] architectureBytes = elfHeader[0x12..0x14]; + UInt16 fileArch = (isBigEndian) ? + BinaryPrimitives.ReadUInt16BigEndian(architectureBytes) : + BinaryPrimitives.ReadUInt16LittleEndian(architectureBytes); + + foreach(InstructionSetArchitecture arch in Enum.GetValues(typeof(InstructionSetArchitecture))) { + if(fileArch == (UInt16)arch) + return arch.ToString(); + } + return null; + } + } +} diff --git a/UnionPatcher/Program.cs b/UnionPatcher/Program.cs index 371ff24..de1881e 100644 --- a/UnionPatcher/Program.cs +++ b/UnionPatcher/Program.cs @@ -15,13 +15,32 @@ namespace LBPUnion.UnionPatcher { return fileName = Path.GetFileName(Process.GetCurrentProcess().MainModule?.FileName); } } - + public static void Main(string[] args) { if(args.Length < 3) { PrintHelp(); return; } - + + ElfFile eboot = new(new FileInfo(args[0])); + + if(eboot.IsValid == false) { + Console.WriteLine($"{eboot.Name} is not a valid ELF file (magic number mismatch)"); + return; + } + + if(eboot.Is64Bit == null) { + Console.WriteLine($"{eboot.Name} does not target a valid system"); + return; + } + + if(string.IsNullOrWhiteSpace(eboot.Architecture)) { + Console.WriteLine($"{eboot.Name} does not target a valid architecture (PowerPC or ARM)"); + return; + } + + Console.WriteLine($"{eboot.Name} targets {eboot.Architecture}"); + Patcher.PatchFile(args[0], args[1], args[2]); Console.WriteLine($"Successfully patched Server URL to {args[1]}."); } @@ -31,4 +50,4 @@ namespace LBPUnion.UnionPatcher { Console.WriteLine($" Usage: {FileName} "); } } -} \ No newline at end of file +} From 8e267a9cd27e83e59211dcd1b84ca37adb8bafe9 Mon Sep 17 00:00:00 2001 From: Jake <505e06b2@gmail.com> Date: Sun, 20 Feb 2022 16:41:09 +0000 Subject: [PATCH 2/5] Reflow tabs --- UnionPatcher.Gui/MainForm.cs | 24 ++++----- UnionPatcher/ElfFile.cs | 94 ++++++++++++++++++------------------ UnionPatcher/Program.cs | 24 ++++----- 3 files changed, 71 insertions(+), 71 deletions(-) diff --git a/UnionPatcher.Gui/MainForm.cs b/UnionPatcher.Gui/MainForm.cs index 4c75668..f77d7db 100644 --- a/UnionPatcher.Gui/MainForm.cs +++ b/UnionPatcher.Gui/MainForm.cs @@ -71,20 +71,20 @@ namespace LBPUnion.UnionPatcher.Gui { 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)").ShowModal(); - return; - } + if(eboot.IsValid == false) { + this.CreateOkDialog("Eboot Error", $"{eboot.Name} is not a valid ELF file (magic number mismatch)").ShowModal(); + return; + } - if(eboot.Is64Bit == null) { - this.CreateOkDialog("Eboot Error", $"{eboot.Name} does not target a valid system").ShowModal(); - return; - } + if(eboot.Is64Bit == null) { + this.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(); - return; - } + if(string.IsNullOrWhiteSpace(eboot.Architecture)) { + this.CreateOkDialog("Eboot Error", $"{eboot.Name} does not target a valid architecture (PowerPC or ARM)").ShowModal(); + return; + } try { Patcher.PatchFile(this.filePicker.FilePath, this.serverUrl.Text, this.outputFileName.FilePath); diff --git a/UnionPatcher/ElfFile.cs b/UnionPatcher/ElfFile.cs index b578773..a7a12bb 100644 --- a/UnionPatcher/ElfFile.cs +++ b/UnionPatcher/ElfFile.cs @@ -9,66 +9,66 @@ Wikipedia entry on ELF: https://en.wikipedia.org/wiki/Executable_and_Linkable_Fo */ namespace LBPUnion.UnionPatcher { - public class ElfFile { - private enum WordSize : byte { - ThirtyTwoBits = 0x01, - SixtyFourBits = 0x02 - } + public class ElfFile { + private enum WordSize : byte { + ThirtyTwoBits = 0x01, + SixtyFourBits = 0x02 + } - private enum Endianness : byte { - Little = 0x01, - Big = 0x02 - } + private enum Endianness : byte { + Little = 0x01, + Big = 0x02 + } - private enum InstructionSetArchitecture : UInt16 { - PowerPC = 0x15, //64-bit PowerPC (PS3) - ARM = 0x28 //32-bit ARM (Vita) - } + private enum InstructionSetArchitecture : UInt16 { + PowerPC = 0x15, //64-bit PowerPC (PS3) + ARM = 0x28 //32-bit ARM (Vita) + } - public string Name { get; } = "Binary Blob"; + public string Name { get; } = "Binary Blob"; - public bool IsValid { get; } - public bool? Is64Bit { get; } = null; - public bool? IsBigEndian { get; } = null; - public string Architecture { get; } = null; + public bool IsValid { get; } + public bool? Is64Bit { get; } = null; + public bool? IsBigEndian { get; } = null; + public string Architecture { get; } = null; - public byte[] Contents { get; } = null; + public byte[] Contents { get; } = null; - public ElfFile(byte[] fileContents) { - IsValid = fileContents[0x00..0x04].SequenceEqual(new byte[] {0x7F, (byte)'E', (byte)'L', (byte)'F'}); - if(IsValid == false) return; + public ElfFile(byte[] fileContents) { + IsValid = fileContents[0x00..0x04].SequenceEqual(new byte[] {0x7F, (byte)'E', (byte)'L', (byte)'F'}); + if(IsValid == false) return; - byte identClassValue = fileContents[0x04]; - byte identDataValue = fileContents[0x05]; + byte identClassValue = fileContents[0x04]; + byte identDataValue = fileContents[0x05]; - if(identClassValue == (byte)WordSize.ThirtyTwoBits || identClassValue == (byte)WordSize.SixtyFourBits) - Is64Bit = identClassValue == (byte)WordSize.SixtyFourBits; + if(identClassValue == (byte)WordSize.ThirtyTwoBits || identClassValue == (byte)WordSize.SixtyFourBits) + Is64Bit = identClassValue == (byte)WordSize.SixtyFourBits; - if(identDataValue == (byte)Endianness.Little || identDataValue == (byte)Endianness.Big) - IsBigEndian = identDataValue == (byte)Endianness.Big; + if(identDataValue == (byte)Endianness.Little || identDataValue == (byte)Endianness.Big) + IsBigEndian = identDataValue == (byte)Endianness.Big; - Architecture = GetFileArchitecture(fileContents, IsBigEndian == true); + Architecture = GetFileArchitecture(fileContents, IsBigEndian == true); - Contents = fileContents; - } + Contents = fileContents; + } - public ElfFile(FileInfo file) : this(File.ReadAllBytes(file.FullName)) { - Name = file.Name; - } + public ElfFile(FileInfo file) : this(File.ReadAllBytes(file.FullName)) { + Name = file.Name; + } - public ElfFile(string fileName) : this(new FileInfo(fileName)) {} + public ElfFile(string fileName) : this(new FileInfo(fileName)) {} - private string GetFileArchitecture(byte[] elfHeader, bool isBigEndian) { - byte[] architectureBytes = elfHeader[0x12..0x14]; - UInt16 fileArch = (isBigEndian) ? - BinaryPrimitives.ReadUInt16BigEndian(architectureBytes) : - BinaryPrimitives.ReadUInt16LittleEndian(architectureBytes); + private string GetFileArchitecture(byte[] elfHeader, bool isBigEndian) { + byte[] architectureBytes = elfHeader[0x12..0x14]; + UInt16 fileArch = (isBigEndian) ? + BinaryPrimitives.ReadUInt16BigEndian(architectureBytes) : + BinaryPrimitives.ReadUInt16LittleEndian(architectureBytes); - foreach(InstructionSetArchitecture arch in Enum.GetValues(typeof(InstructionSetArchitecture))) { - if(fileArch == (UInt16)arch) - return arch.ToString(); - } - return null; - } - } + foreach(InstructionSetArchitecture arch in Enum.GetValues(typeof(InstructionSetArchitecture))) { + if(fileArch == (UInt16)arch) + return arch.ToString(); + } + return null; + } + } } diff --git a/UnionPatcher/Program.cs b/UnionPatcher/Program.cs index de1881e..3e50c76 100644 --- a/UnionPatcher/Program.cs +++ b/UnionPatcher/Program.cs @@ -25,21 +25,21 @@ namespace LBPUnion.UnionPatcher { ElfFile eboot = new(new FileInfo(args[0])); if(eboot.IsValid == false) { - Console.WriteLine($"{eboot.Name} is not a valid ELF file (magic number mismatch)"); - return; - } + Console.WriteLine($"{eboot.Name} is not a valid ELF file (magic number mismatch)"); + return; + } - if(eboot.Is64Bit == null) { - Console.WriteLine($"{eboot.Name} does not target a valid system"); - return; - } + if(eboot.Is64Bit == null) { + Console.WriteLine($"{eboot.Name} does not target a valid system"); + return; + } - if(string.IsNullOrWhiteSpace(eboot.Architecture)) { - Console.WriteLine($"{eboot.Name} does not target a valid architecture (PowerPC or ARM)"); - return; - } + if(string.IsNullOrWhiteSpace(eboot.Architecture)) { + Console.WriteLine($"{eboot.Name} does not target a valid architecture (PowerPC or ARM)"); + return; + } - Console.WriteLine($"{eboot.Name} targets {eboot.Architecture}"); + Console.WriteLine($"{eboot.Name} targets {eboot.Architecture}"); Patcher.PatchFile(args[0], args[1], args[2]); Console.WriteLine($"Successfully patched Server URL to {args[1]}."); From 58c418362bf12bf18acfd54a730a990acca9a739 Mon Sep 17 00:00:00 2001 From: Jake <505e06b2@gmail.com> Date: Sun, 20 Feb 2022 19:05:05 +0000 Subject: [PATCH 3/5] Added filesize check; fixed formatting --- UnionPatcher.Gui/MainForm.cs | 2 +- UnionPatcher/ElfFile.cs | 7 ++++++- UnionPatcher/Program.cs | 3 ++- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/UnionPatcher.Gui/MainForm.cs b/UnionPatcher.Gui/MainForm.cs index f77d7db..cd650c0 100644 --- a/UnionPatcher.Gui/MainForm.cs +++ b/UnionPatcher.Gui/MainForm.cs @@ -72,7 +72,7 @@ namespace LBPUnion.UnionPatcher.Gui { 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)").ShowModal(); + this.CreateOkDialog("Eboot Error", $"{eboot.Name} is not a valid ELF file (magic number mismatch)\nThe EBOOT must be decrypted before using this tool").ShowModal(); return; } diff --git a/UnionPatcher/ElfFile.cs b/UnionPatcher/ElfFile.cs index a7a12bb..6a24bfc 100644 --- a/UnionPatcher/ElfFile.cs +++ b/UnionPatcher/ElfFile.cs @@ -35,8 +35,13 @@ namespace LBPUnion.UnionPatcher { public byte[] Contents { get; } = null; public ElfFile(byte[] fileContents) { + if(fileContents.length < 52) { + IsValid = false; + return; + } + IsValid = fileContents[0x00..0x04].SequenceEqual(new byte[] {0x7F, (byte)'E', (byte)'L', (byte)'F'}); - if(IsValid == false) return; + if(!IsValid) return; byte identClassValue = fileContents[0x04]; byte identDataValue = fileContents[0x05]; diff --git a/UnionPatcher/Program.cs b/UnionPatcher/Program.cs index 3e50c76..6cd7fb4 100644 --- a/UnionPatcher/Program.cs +++ b/UnionPatcher/Program.cs @@ -24,8 +24,9 @@ namespace LBPUnion.UnionPatcher { ElfFile eboot = new(new FileInfo(args[0])); - if(eboot.IsValid == false) { + if(!eboot.IsValid) { Console.WriteLine($"{eboot.Name} is not a valid ELF file (magic number mismatch)"); + Console.WriteLine("The EBOOT must be decrypted before using this tool"); return; } From 77b693ae0891ef9509f047d7d5b603bca4290b31 Mon Sep 17 00:00:00 2001 From: Jake <505e06b2@gmail.com> Date: Sun, 20 Feb 2022 23:57:12 +0000 Subject: [PATCH 4/5] Fixed compilation error; formatting fixes --- UnionPatcher.Gui/MainForm.cs | 6 +++--- UnionPatcher/ElfFile.cs | 6 ++---- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/UnionPatcher.Gui/MainForm.cs b/UnionPatcher.Gui/MainForm.cs index cd650c0..e35daa6 100644 --- a/UnionPatcher.Gui/MainForm.cs +++ b/UnionPatcher.Gui/MainForm.cs @@ -72,17 +72,17 @@ namespace LBPUnion.UnionPatcher.Gui { 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)\nThe EBOOT must be decrypted before using this tool").ShowModal(); + this.CreateOkDialog("EBOOT Error", $"{eboot.Name} is not a valid ELF file (magic number mismatch)\nThe 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(); + this.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(); + this.CreateOkDialog("EBOOT Error", $"{eboot.Name} does not target a valid architecture (PowerPC or ARM)").ShowModal(); return; } diff --git a/UnionPatcher/ElfFile.cs b/UnionPatcher/ElfFile.cs index 6a24bfc..1fb4f5b 100644 --- a/UnionPatcher/ElfFile.cs +++ b/UnionPatcher/ElfFile.cs @@ -27,7 +27,7 @@ namespace LBPUnion.UnionPatcher { public string Name { get; } = "Binary Blob"; - public bool IsValid { get; } + public bool IsValid { get; } = false; public bool? Is64Bit { get; } = null; public bool? IsBigEndian { get; } = null; public string Architecture { get; } = null; @@ -35,10 +35,8 @@ namespace LBPUnion.UnionPatcher { public byte[] Contents { get; } = null; public ElfFile(byte[] fileContents) { - if(fileContents.length < 52) { - IsValid = false; + if(fileContents.Length < 52) return; - } IsValid = fileContents[0x00..0x04].SequenceEqual(new byte[] {0x7F, (byte)'E', (byte)'L', (byte)'F'}); if(!IsValid) return; From 3d0d7d052f448d271bd224e2de3ac6f049fbeaa4 Mon Sep 17 00:00:00 2001 From: Jake <505e06b2@gmail.com> Date: Mon, 21 Feb 2022 00:17:56 +0000 Subject: [PATCH 5/5] Reflow tabs --- UnionPatcher/ElfFile.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/UnionPatcher/ElfFile.cs b/UnionPatcher/ElfFile.cs index 1fb4f5b..2561ee7 100644 --- a/UnionPatcher/ElfFile.cs +++ b/UnionPatcher/ElfFile.cs @@ -35,8 +35,8 @@ namespace LBPUnion.UnionPatcher { public byte[] Contents { get; } = null; public ElfFile(byte[] fileContents) { - if(fileContents.Length < 52) - return; + if(fileContents.Length < 52) + return; IsValid = fileContents[0x00..0x04].SequenceEqual(new byte[] {0x7F, (byte)'E', (byte)'L', (byte)'F'}); if(!IsValid) return;