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 +}