예제 #1
0
 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;
 }
예제 #2
0
        private void EditPatch_Click(object sender, EventArgs e)
        {
            PatchEntry patchEntry = (lbxPatchEntryListBox.SelectedElement as Actions.DefaultDragItem <PatchEntry>)?.Item;

            if (patchEntry == null)
            {
                return;
            }
            EditEntry(patchEntry);
        }
예제 #3
0
        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);
        }
예제 #4
0
 private void AddStartPatch(PatchEntry patch, string content)
 {
     if (patch.Filename == null)
     {
         _patcher.AddAtStart(content);
     }
     else
     {
         _patcher.AddAtStart(patch.Filename, content);
     }
 }
예제 #5
0
 private void AddTokenPatch(PatchEntry patch, string content)
 {
     if (patch.Filename == null)
     {
         _patcher.AddTokenPatch(patch.Tokens, content);
     }
     else
     {
         _patcher.AddTokenPatch(patch.Filename, patch.Tokens, content);
     }
 }
예제 #6
0
 private void AddEndPatch(PatchEntry patch, string content)
 {
     if (patch.Filename == null)
     {
         _patcher.AddAtEnd(content);
     }
     else
     {
         _patcher.AddAtEnd(patch.Filename, content);
     }
 }
예제 #7
0
        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);
        }
예제 #8
0
        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));
            }
        }
예제 #9
0
        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);
            }
        }
예제 #10
0
            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);
                            }
                        }
                    }
                }
            }
예제 #11
0
        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);
        }
예제 #12
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);
        }
예제 #13
0
        // 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);
        }
예제 #14
0
        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");
            }
        }