public void Read() { if (!IsOpen || IsDisposed) { throw new Exception("XenonPatch.Read: The Xenon patch is not open."); } if (HasBeenRead) { throw new Exception("XenonPatch.Read: The Xenon patch has already been read."); } eio.SetPosition(0); Patches = new List <PatchEntry>(); //Just has Kernel+XAM. { var nextAddr = eio.Reader.ReadUInt32(); while (nextAddr != uint.MaxValue) { eio.SetPosition(-4, SeekOrigin.Current); var entry = new PatchEntry(); entry.Read(eio.Reader); Patches.Add(entry); nextAddr = eio.Reader.ReadUInt32(); } } HasBeenRead = true; }
private void EditPatch_Click(object sender, EventArgs e) { PatchEntry patchEntry = (lbxPatchEntryListBox.SelectedElement as Actions.DefaultDragItem <PatchEntry>)?.Item; if (patchEntry == null) { return; } EditEntry(patchEntry); }
public void EditEntry(PatchEntry patchEntry) { if (editorFactory == null) { editorFactory = new EditorFactory(); } PatchBuilder patchBuilder = new PatchBuilder(dataStruct, editorFactory); patchBuilder.SetPatchData(patchEntry ?? dataStruct.EntryFactory.CreateEntryByType(typeof(PatchEntry))); PushPanel(patchBuilder, patchBuilder.PanelName); }
private void AddStartPatch(PatchEntry patch, string content) { if (patch.Filename == null) { _patcher.AddAtStart(content); } else { _patcher.AddAtStart(patch.Filename, content); } }
private void AddTokenPatch(PatchEntry patch, string content) { if (patch.Filename == null) { _patcher.AddTokenPatch(patch.Tokens, content); } else { _patcher.AddTokenPatch(patch.Filename, patch.Tokens, content); } }
private void AddEndPatch(PatchEntry patch, string content) { if (patch.Filename == null) { _patcher.AddAtEnd(content); } else { _patcher.AddAtEnd(patch.Filename, content); } }
private void AddRegexPatch(PatchEntry patch, string content) { var patchObj = patch.Filename == null ? new RegexPatch(patch.Regex) : new RegexPatch(patch.Filename, patch.Regex); patchObj.Multiple = patch.Multiple; patchObj.Optional = patch.Optional; patchObj.ReplacementString = content; _patcher.AddPatch(patchObj); }
private static void HandlePatchState(PatchState state, PatchEntry patch) { switch (state) { case PatchState.Success: Log.Info("Patch Successfully Applied [ {0} ]", patch.Description); break; case PatchState.AlreadyPatched: Log.Info("Patch was Already Applied [ {0} ]", patch.Description); break; case PatchState.NotUnique: throw new InvalidOperationException(string.Format("Patch was not unique, multiple matches were found, [ {0} ]", patch.Description)); case PatchState.SequenceNotFound: throw new InvalidOperationException(string.Format("Could not find the specified hex value for patch [ {0} ]", patch.Description)); } }
private (bool, string) ApplyEntry(PatchEntry entry, long[] addresses) { try { if (entry.Match == PatchEntry.MatchBy.Address) { addresses = entry.Address.HasValue ? new[] { entry.Address.Value } : null; } if (addresses == null || addresses.Length == 0) { return(false, "No address specified!"); } var newBytes = entry.NewData.Bytes; foreach (var address in addresses) { _stream.Position = address; foreach (var newByte in newBytes) { if (newByte.IsValue) { _stream.WriteByte(newByte.Value); } else { _stream.Position += 1; } } } return(true, (string)null); } catch (Exception e) { return(false, e.Message); } }
private void EnsurePatched() { using (var unknownScope = Scope.Create(() => Marshal.GetIUnknownForObject(this), pUnknown => Marshal.Release(pUnknown))) { var pUnknown = unknownScope.Value; using (var dispatchExScope = Scope.Create(() => UnknownHelpers.QueryInterface <IDispatchEx>(pUnknown), pDispatchEx => Marshal.Release(pDispatchEx))) { lock (VTablePatcher.PatchLock) { var pDispatchEx = dispatchExScope.Value; var pVTable = Marshal.ReadIntPtr(pDispatchEx); if (!patchMap.ContainsKey(pVTable)) { var entry = new PatchEntry(); var origGetDispID = VTableHelpers.GetMethodDelegate <RawGetDispID>(pDispatchEx, 7); entry.AddDelegate(VTableHelpers.SetMethodDelegate(pDispatchEx, 7, new RawGetDispID((IntPtr pThis, string name, DispatchNameFlags nameFlags, out int dispid) => { try { return((Marshal.GetObjectForIUnknown(pThis) is DispatchExHostItem item) ? item.GetDispID(name, nameFlags, out dispid) : origGetDispID(pThis, name, nameFlags, out dispid)); } catch (Exception exception) { dispid = SpecialDispIDs.Unknown; return(exception.HResult); } }))); var origDeleteMemberByName = VTableHelpers.GetMethodDelegate <RawDeleteMemberByName>(pDispatchEx, 9); entry.AddDelegate(VTableHelpers.SetMethodDelegate(pDispatchEx, 9, new RawDeleteMemberByName((pThis, name, nameFlags) => { try { return((Marshal.GetObjectForIUnknown(pThis) is DispatchExHostItem item) ? item.DeleteMemberByName(name, nameFlags) : origDeleteMemberByName(pThis, name, nameFlags)); } catch (Exception exception) { return(exception.HResult); } }))); var origDeleteMemberByDispID = VTableHelpers.GetMethodDelegate <RawDeleteMemberByDispID>(pDispatchEx, 10); entry.AddDelegate(VTableHelpers.SetMethodDelegate(pDispatchEx, 10, new RawDeleteMemberByDispID((pThis, dispid) => { try { return((Marshal.GetObjectForIUnknown(pThis) is DispatchExHostItem item) ? item.DeleteMemberByDispID(dispid) : origDeleteMemberByDispID(pThis, dispid)); } catch (Exception exception) { return(exception.HResult); } }))); var origGetMemberProperties = VTableHelpers.GetMethodDelegate <RawGetMemberProperties>(pDispatchEx, 11); entry.AddDelegate(VTableHelpers.SetMethodDelegate(pDispatchEx, 11, new RawGetMemberProperties((IntPtr pThis, int dispid, DispatchPropFlags fetchFlags, out DispatchPropFlags propFlags) => { try { var item = Marshal.GetObjectForIUnknown(pThis) as DispatchExHostItem; if (item == null) { return(origGetMemberProperties(pThis, dispid, fetchFlags, out propFlags)); } var result = item.GetMemberProperties(dispid, fetchFlags, out propFlags); if (result == HResult.DISP_E_MEMBERNOTFOUND) { return(origGetMemberProperties(pThis, dispid, fetchFlags, out propFlags)); } return(result); } catch (Exception exception) { propFlags = 0; return(exception.HResult); } }))); var origGetMemberName = VTableHelpers.GetMethodDelegate <RawGetMemberName>(pDispatchEx, 12); entry.AddDelegate(VTableHelpers.SetMethodDelegate(pDispatchEx, 12, new RawGetMemberName((IntPtr pThis, int dispid, out string name) => { try { return((Marshal.GetObjectForIUnknown(pThis) is DispatchExHostItem item) ? item.GetMemberName(dispid, out name) : origGetMemberName(pThis, dispid, out name)); } catch (Exception exception) { name = null; return(exception.HResult); } }))); var origGetNextDispID = VTableHelpers.GetMethodDelegate <RawGetNextDispID>(pDispatchEx, 13); entry.AddDelegate(VTableHelpers.SetMethodDelegate(pDispatchEx, 13, new RawGetNextDispID((IntPtr pThis, DispatchEnumFlags enumFlags, int dispidCurrent, out int dispidNext) => { try { return((Marshal.GetObjectForIUnknown(pThis) is DispatchExHostItem item) ? item.GetNextDispID(dispidCurrent, out dispidNext) : origGetNextDispID(pThis, enumFlags, dispidCurrent, out dispidNext)); } catch (Exception exception) { dispidNext = SpecialDispIDs.Unknown; return(exception.HResult); } }))); patchMap.Add(pVTable, entry); Debug.Assert(patchMap.Count < 16); } } } } }
private static int Run(string inputPath, string patchPath, string outputPath, string verifyHash, bool addCave, long?desiredCaveAddress, long?desiredCaveSize, long?originalCodeSize) { using (var inputData = File.OpenRead(inputPath)) using (var patchData = File.OpenRead(patchPath)) { var inputElf = ElfHeader.Read(inputData); if (string.IsNullOrWhiteSpace(verifyHash) == false) { var inputHash = HashElf(inputElf, 0, inputData); if (inputHash != verifyHash) { Console.WriteLine("Hash of input ELF does not match:"); Console.WriteLine(" desired: {0}", verifyHash); Console.WriteLine(" actual: {0}", inputHash); return(1); } } int codeIndex = -1; long newCodeSize = 0; ulong caveVirtualAddress = 0; long caveFileOffset = 0; long caveFileSize = 0; if (addCave == true) { codeIndex = Array.FindIndex( inputElf.ProgramHeaders, ph => ph.Type == Elf.ProgramType.Loadable && (ph.Flags & Elf.ProgramFlags.Executable) != 0); if (codeIndex + 1 >= inputElf.ProgramHeaders.Length) { Console.WriteLine("No program following code program."); return(2); } var codeHeader = inputElf.ProgramHeaders[codeIndex + 0]; var nextHeader = inputElf.ProgramHeaders[codeIndex + 1]; if ((ulong)codeHeader.FileSize != codeHeader.MemorySize) { Console.WriteLine("Code file size does not match memory size!"); return(3); } if (originalCodeSize.HasValue == true && originalCodeSize.Value != codeHeader.FileSize) { Console.WriteLine("Original code size does not match:"); Console.WriteLine(" desired: {0}", originalCodeSize.Value); Console.WriteLine(" actual: {0}", codeHeader.FileSize); return(4); } caveFileSize = nextHeader.FileOffset - (codeHeader.FileOffset + codeHeader.FileSize); caveVirtualAddress = codeHeader.VirtualAddress + (ulong)codeHeader.FileSize; caveFileOffset = codeHeader.FileOffset + codeHeader.FileSize; if (desiredCaveAddress.HasValue == true && (ulong)desiredCaveAddress.Value != caveVirtualAddress) { Console.WriteLine("Desired cave virtual address does not match:"); Console.WriteLine(" desired: {0}", desiredCaveAddress.Value); Console.WriteLine(" actual: {0}", caveVirtualAddress); return(5); } if (desiredCaveSize.HasValue == true && desiredCaveSize.Value != caveFileSize) { Console.WriteLine("Desired cave size does not match:"); Console.WriteLine(" desired: {0}", desiredCaveSize.Value); Console.WriteLine(" actual: {0}", caveFileSize); return(6); } newCodeSize = nextHeader.FileOffset - codeHeader.FileOffset; codeHeader.FileSize = newCodeSize; codeHeader.MemorySize = (ulong)newCodeSize; inputElf.ProgramHeaders[codeIndex] = codeHeader; } var patchElf = ElfHeader.Read(patchData); var patchListSectionIndex = Array.IndexOf(patchElf.SectionNames, ".patch_list"); if (patchListSectionIndex < 0) { Console.WriteLine("No .patch_list section."); return(7); } var patchSection = patchElf.SectionHeaders[patchListSectionIndex]; var patchCount = patchSection.FileSize / 32; var patches = new PatchEntry[patchCount]; patchData.Position = patchSection.FileOffset; for (int i = 0; i < patchSection.FileSize / 32; i++) { var patchAddress = patchData.ReadValueS64(Endian.Big); var patchSize = patchData.ReadValueS64(Endian.Big); var patchSectionIndex = patchData.ReadValueS64(Endian.Big); var patchFlags = patchData.ReadValueS64(Endian.Big); patches[i] = new PatchEntry(patchAddress, patchSize, patchSectionIndex, (PatchFlags)patchFlags); } File.Copy(inputPath, outputPath, true); var attributes = File.GetAttributes(outputPath); if ((attributes & FileAttributes.ReadOnly) != 0) { attributes &= ~FileAttributes.ReadOnly; File.SetAttributes(outputPath, attributes); } using (var outputData = File.Open(outputPath, FileMode.Open, FileAccess.ReadWrite)) { if (addCave == true) { outputData.Position = outputData.Length; var sectionHeadersPosition = outputData.Position; var newSectionHeaders = new List <Elf.SectionHeader>(inputElf.SectionHeaders); newSectionHeaders.Add(new Elf.SectionHeader() { Name = 0x1C, Type = Elf.SectionType.Program, Flags = Elf.SectionFlags.Alloc | Elf.SectionFlags.Executable, VirtualAddress = caveVirtualAddress, FileOffset = caveFileOffset, FileSize = caveFileSize, Link = 0, Info = 0, Align = 4, EntrySize = 0, }); foreach (var newSectionHeader in newSectionHeaders) { newSectionHeader.Swap(); outputData.WriteStructure(newSectionHeader); } // Update section headers info outputData.Position = Marshal.OffsetOf(typeof(Elf.FileHeader), "SectionHeadersOffset").ToInt64(); outputData.WriteValueS64(sectionHeadersPosition, Endian.Big); outputData.Position = Marshal.OffsetOf(typeof(Elf.FileHeader), "SectionHeaderCount").ToInt64(); outputData.WriteValueU16((ushort)newSectionHeaders.Count, Endian.Big); // Update code program info var programHeaderPosition = inputElf.FileHeader.ProgramHeadersOffset + (codeIndex * Marshal.SizeOf(typeof(Elf.ProgramHeader))); outputData.Position = programHeaderPosition + Marshal.OffsetOf(typeof(Elf.ProgramHeader), "FileSize").ToInt64(); outputData.WriteValueS64(newCodeSize, Endian.Big); outputData.Position = programHeaderPosition + Marshal.OffsetOf(typeof(Elf.ProgramHeader), "MemorySize").ToInt64(); outputData.WriteValueS64(newCodeSize, Endian.Big); } foreach (var patch in patches.OrderBy(p => p.Address)) { var sectionName = (patch.Flags & PatchFlags.IsCave) != 0 ? ".cave" : (patch.Flags & PatchFlags.IsData) == 0 ? $".text{patch.SectionIndex}" : $".data{patch.SectionIndex}"; var sourceSectionIndex = Array.IndexOf(patchElf.SectionNames, sectionName); if (sourceSectionIndex < 0) { Console.WriteLine($"No {sectionName} section."); return(8); } var sourceSection = patchElf.SectionHeaders[sourceSectionIndex]; var inputOffset = sourceSection.FileOffset + (long)((ulong)patch.Address - sourceSection.VirtualAddress); patchData.Position = inputOffset; var outputOffset = inputElf.GetFileOffset((ulong)patch.Address, (uint)patch.Size); outputData.Position = outputOffset; //Console.WriteLine($"Patching {patch.Size} bytes at {outputOffset:X} from {patch.Address:X} ({sectionName})"); outputData.WriteFromStream(patchData, patch.Size); } } } return(0); }
public static CatalogFile Read(Stream input) { const Endian endian = Endian.Little; var magic1 = input.ReadValueU64(endian); var magic2 = input.ReadValueU64(endian); if (magic1 != Signature || magic2 != Signature) { throw new FormatException(); } var instance = new CatalogFile(); var normalCount = input.ReadValueU32(endian); var patchCount = input.ReadValueU32(endian); var encryptedCount = input.ReadValueU32(endian); var unknown1C = input.ReadValueS32(endian); // patch version related? var unknown20 = input.ReadValueS32(endian); // patch version related? var unknown24 = input.ReadValueS32(endian); // patch version related? instance.NormalEntries.Clear(); for (int i = 0; i < normalCount; i++) { var entry = NormalEntry.Read(input, endian); if (entry.IsEncrypted == true) { throw new FormatException(); } instance.NormalEntries.Add(entry); } instance.EncryptedEntries.Clear(); for (int i = 0; i < encryptedCount; i++) { var encryptedEntry = EncryptedChunkEntry.Read(input, endian); if (encryptedEntry.Entry.IsEncrypted == false) { throw new FormatException(); } if (encryptedEntry.Entry.Size != encryptedEntry.CryptoInfo.Size) { throw new FormatException(); } instance.EncryptedEntries.Add(encryptedEntry); } instance.PatchEntries.Clear(); for (int i = 0; i < patchCount; i++) { var entry = PatchEntry.Read(input, endian); instance.PatchEntries.Add(entry); } if (input.Position != input.Length) { throw new FormatException(); } return(instance); }
// Tests required private (bool, string, long[]) ValidateEntry(PatchEntry entry) { bool isSuccess = false; string message = null; long[] addresses = null; switch (entry.Match) { case PatchEntry.MatchBy.Address: if (!entry.Address.HasValue) { // Should not happen, otherwise parser is incorrect! message = "Entry address not specified"; break; } var pattern = entry.OldData; var patternLength = pattern.Length; var buffer = new byte[patternLength]; _stream.Position = entry.Address.Value; var readCount = _stream.Read(buffer, 0, patternLength); if (readCount == patternLength && Helper.CompareBytes(buffer, pattern.Bytes)) { isSuccess = true; } else { message = "Pattern do not match at its address"; } break; case PatchEntry.MatchBy.EveryMatch: case PatchEntry.MatchBy.FirstMatch: var addrs = FindPattern(entry.OldData).ToArray(); if (addrs.Length > 0) { isSuccess = true; if (entry.Match == PatchEntry.MatchBy.FirstMatch) { Array.Resize(ref addrs, 1); } addresses = addrs; } else { message = "Pattern not found"; } break; case PatchEntry.MatchBy.SingleMatch: var take2 = FindPattern(entry.OldData).Take(2).ToArray(); var take2Count = take2.Length; if (take2Count == 1) { isSuccess = true; addresses = new[] { take2[0] }; } else { message = take2Count == 0 ? "Pattern not found" : "Pattern is not unique"; } break; default: message = "Patch entry type not supported"; break; } return(isSuccess, message, addresses); }
public static void Main(String?[]?args) { if (args is null || args.Length == 0) { Console.WriteLine("Invalid arguments"); return; } String?path = args[0]; if (path.IsNullOrWhiteSpace()) { Console.WriteLine("Empty path provided"); return; } var file = new FileInfo(path); if (!file.Exists) { Console.WriteLine("No file found"); return; } ModuleContext ctx = ModuleDef.CreateModuleContext(); AssemblyDef? asm; try { Byte[]? b = File.ReadAllBytes(file.FullName); asm = AssemblyDef.Load(b, ctx); } catch { Console.WriteLine("Error loading assembly"); return; } if (asm is null) { Console.WriteLine("Error loading assembly"); return; } String?loc = Assembly.GetExecutingAssembly().Location; if (!loc.IsNullOrWhiteSpace()) { var f = new FileInfo(loc); LoadAssemblies(f.Directory.CreateSubdirectory("Extensions")); } for (Int32 i = 1; i < args.Length; ++i) { LoadAssemblies(new DirectoryInfo(args[i])); } if (PatchEntry.PatchAssembly(asm, ctx, new Logger())) { Console.WriteLine("Patch success, saving"); var opt = new ModuleWriterOptions(asm.ManifestModule); asm.Write(path, opt); for (Int32 i = 0; i < asm.Modules.Count; ++i) { ModuleDef?mod = asm.Modules[i]; if (mod.IsManifestModule) { continue; } var subOpt = new ModuleWriterOptions(mod); mod.Write(path + mod.FullName + ".netmodule", subOpt); } } else { Console.WriteLine("Patch failed, will not save"); } }