public bool IsApplicable(Game game)
        {
            var patchInfo = Harmony.GetPatchInfo(TargetMethodInfo);

            if (AlreadyPatched(patchInfo))
            {
                return(false);
            }

            var bytes = TargetMethodInfo.GetCilBytes();

            if (bytes == null)
            {
                return(false);
            }

            var hash = bytes.GetSha256();

            return(hash.SequenceEqual(new byte[] {
                0x31, 0x81, 0x47, 0x2b, 0x6a, 0xde, 0xc8, 0x26,
                0x37, 0x68, 0xb3, 0x81, 0x0a, 0x47, 0x57, 0x51,
                0x37, 0x30, 0xa4, 0xa4, 0xb3, 0xde, 0xa7, 0x59,
                0x1a, 0x75, 0x90, 0x8a, 0x18, 0xdf, 0xa7, 0x2b
            }));
        }
        public bool IsApplicable(Game game)
        {
            var patchInfo = Harmony.GetPatchInfo(TargetMethodInfo);

            if (AlreadyPatchedByOthers(patchInfo))
            {
                return(false);
            }

            var bytes = TargetMethodInfo.GetCilBytes();

            if (bytes == null)
            {
                return(false);
            }

            var hash = bytes.GetSha256();

            return(hash.SequenceEqual(new byte[] {
                0x4C, 0x29, 0xDC, 0x2D, 0x78, 0x89, 0xA7, 0xA8,
                0xC6, 0xDA, 0x84, 0xDB, 0x07, 0x2E, 0x7D, 0xB4,
                0x99, 0xED, 0xB2, 0xB9, 0xC4, 0xBB, 0xAD, 0xE4,
                0xC9, 0xD1, 0xC8, 0x0F, 0xD7, 0x8C, 0x25, 0x15
            }));
        }
        public bool IsApplicable(Game game)
        {
            var patchInfo = Harmony.GetPatchInfo(TargetMethodInfo);

            if (AlreadyPatchedByOthers(patchInfo))
            {
                return(false);
            }

            var hash = TargetMethodInfo.MakeCilSignatureSha256();

            return(hash.MatchesAnySha256(Hashes));
        }
예제 #4
0
        internal static MethodInfo ReversePatch(HarmonyMethod standin, MethodBase original, MethodInfo postTranspiler)
        {
            if (standin == null)
            {
                throw new ArgumentNullException(nameof(standin));
            }
            if (standin.method == null)
            {
                throw new ArgumentNullException($"{nameof(standin)}.{nameof(standin.method)}");
            }

            var debug = (standin.debug ?? false) || Harmony.DEBUG;

            var transpilers = new List <MethodInfo>();

            if (standin.reversePatchType == HarmonyReversePatchType.Snapshot)
            {
                var info = Harmony.GetPatchInfo(original);
                transpilers.AddRange(GetSortedPatchMethods(original, info.Transpilers.ToArray(), debug));
            }
            if (postTranspiler != null)
            {
                transpilers.Add(postTranspiler);
            }

            var empty       = new List <MethodInfo>();
            var patcher     = new MethodPatcher(standin.method, original, empty, empty, transpilers, empty, debug);
            var replacement = patcher.CreateReplacement(out var finalInstructions);

            if (replacement == null)
            {
                throw new MissingMethodException($"Cannot create replacement for {standin.method.FullDescription()}");
            }

            try
            {
                var errorString = Memory.DetourMethod(standin.method, replacement);
                if (errorString != null)
                {
                    throw new FormatException($"Method {standin.method.FullDescription()} cannot be patched. Reason: {errorString}");
                }
            }
            catch (Exception ex)
            {
                throw HarmonyException.Create(ex, finalInstructions);
            }

            PatchTools.RememberObject(standin.method, replacement);
            return(replacement);
        }
예제 #5
0
        internal static MethodInfo ReversePatch(HarmonyMethod standin, MethodBase original, Harmony instance, MethodInfo postTranspiler)
        {
            if (standin == null)
            {
                throw new ArgumentNullException(nameof(standin));
            }
            if (standin.method == null)
            {
                throw new ArgumentNullException($"{nameof(standin)}.{nameof(standin.method)}");
            }

            var transpilers = new List <MethodInfo>();

            if (standin.reversePatchType == HarmonyReversePatchType.Snapshot)
            {
                var info = Harmony.GetPatchInfo(original);
                transpilers.AddRange(GetSortedPatchMethods(original, info.Transpilers.ToArray()));
            }
            if (postTranspiler != null)
            {
                transpilers.Add(postTranspiler);
            }

            var empty       = new List <MethodInfo>();
            var replacement = MethodPatcher.CreatePatchedMethod(standin.method, original, instance.Id, empty, empty, transpilers, empty);

            if (replacement == null)
            {
                throw new MissingMethodException($"Cannot create dynamic replacement for {standin.method.FullDescription()}");
            }

            var errorString = Memory.DetourMethod(standin.method, replacement);

            if (errorString != null)
            {
                throw new FormatException($"Method {standin.method.FullDescription()} cannot be patched. Reason: {errorString}");
            }

            PatchTools.RememberObject(standin.method, replacement);
            return(replacement);
        }
예제 #6
0
        internal static MethodInfo ReversePatch(HarmonyMethod standin, MethodBase original, MethodInfo postTranspiler, MethodInfo postManipulator)
        {
            if (standin is null)
            {
                throw new ArgumentNullException(nameof(standin));
            }
            if (standin.method is null)
            {
                throw new ArgumentNullException($"{nameof(standin)}.{nameof(standin.method)}");
            }

            var transpilers    = new List <MethodInfo>();
            var ilmanipulators = new List <MethodInfo>();

            if (standin.reversePatchType == HarmonyReversePatchType.Snapshot)
            {
                var info = Harmony.GetPatchInfo(original);
                transpilers.AddRange(GetSortedPatchMethods(original, info.Transpilers.ToArray()));
                ilmanipulators.AddRange(GetSortedPatchMethods(original, info.ILManipulators.ToArray()));
            }
            if (postTranspiler is object)
            {
                transpilers.Add(postTranspiler);
            }
            if (postManipulator is object)
            {
                ilmanipulators.Add(postManipulator);
            }

            MethodBody patchBody = null;
            var        hook      = new ILHook(standin.method, ctx =>
            {
                if (!(original is MethodInfo mi))
                {
                    return;
                }

                patchBody = ctx.Body;

                var patcher = mi.GetMethodPatcher();
                var dmd     = patcher.CopyOriginal();

                if (dmd == null)
                {
                    throw new NullReferenceException($"Cannot reverse patch {mi.FullDescription()}: method patcher ({patcher.GetType().FullDescription()}) can't copy original method body");
                }

                var manipulator = new ILManipulator(dmd.Definition.Body);

                // Copy over variables from the original code
                ctx.Body.Variables.Clear();
                foreach (var variableDefinition in manipulator.Body.Variables)
                {
                    ctx.Body.Variables.Add(new VariableDefinition(ctx.Module.ImportReference(variableDefinition.VariableType)));
                }

                foreach (var methodInfo in transpilers)
                {
                    manipulator.AddTranspiler(methodInfo);
                }

                manipulator.WriteTo(ctx.Body, standin.method);

                HarmonyManipulator.ApplyILManipulators(ctx, original, ilmanipulators, null);

                // Write a ret in case it got removed (wrt. HarmonyManipulator)
                ctx.IL.Emit(OpCodes.Ret);
            }, new ILHookConfig {
        public static void GenerateReport()
        {
            var sb = new StringBuilder();

            try {
                sb.AppendLine("Recorded Unhandled Exceptions:");
                var i = 0;
                foreach (var exc in RecordedUnhandledExceptions)
                {
                    var excStr = exc.ToString();
                    sb.Append("  ").Append(++i).Append(". ").AppendLine(excStr.Replace("\n", "\n    "));
                    var iex = exc;
                    var j   = 0;
                    while (iex.InnerException != null)
                    {
                        iex = iex.InnerException;
                        sb.Append("    ").Append(i).Append(".").Append(++j).Append(". ").AppendLine(excStr.Replace("\n", "\n    "));
                    }
                }

                if (i == 0)
                {
                    sb.AppendLine("  None.");
                }
            }
            catch (Exception ex) {
                sb.Append("  *** ERROR: ").Append(ex.GetType().Name).Append(": ").AppendLine(ex.Message);
            }

            sb.AppendLine();

            try {
                sb.AppendLine("Recorded First Chance Exceptions:");
                var i = 0;
                foreach (var exc in RecordedFirstChanceExceptions)
                {
                    var excStr = exc.ToString();
                    sb.Append("  ").Append(++i).Append(". ").AppendLine(excStr.Replace("\n", "\n    "));
                    var iex = exc;
                    var j   = 0;
                    while (iex.InnerException != null)
                    {
                        iex = iex.InnerException;
                        sb.Append("    ").Append(i).Append(".").Append(++j).Append(". ").AppendLine(excStr.Replace("\n", "\n    "));
                    }
                }

                if (RecordFirstChanceExceptions)
                {
                    if (i == 0)
                    {
                        sb.AppendLine("  None recorded.");
                    }
                }
                else
                {
                    sb.AppendLine("  Recording disabled.");
                }
            }
            catch (Exception ex) {
                sb.Append("  *** ERROR: ").Append(ex.GetType().Name).Append(": ").AppendLine(ex.Message);
            }

            sb.AppendLine();

            try {
                sb.AppendLine("Modules Information:");
                var i = 0;
                foreach (var mi in ModuleInfo.GetModules())
                {
                    sb.Append("  ").Append(++i).Append(". ").Append(mi.Id).Append(" ").Append(mi.Version.ToString());
                    if (mi.IsSelected)
                    {
                        sb.Append(" *Selected*");
                    }
                    sb.AppendLine();
                    sb.Append("    ").Append(mi.Name);
                    if (!String.IsNullOrWhiteSpace(mi.Alias))
                    {
                        sb.Append(" (").Append(mi.Alias).Append(")");
                    }
                    if (mi.IsOfficial)
                    {
                        sb.Append(" *Official*");
                    }
                    sb.AppendLine();
                    if (mi.DependedModuleIds.Count <= 0)
                    {
                        continue;
                    }

                    sb.Append("  ").AppendLine("Dependencies:");
                    var j = 0;
                    foreach (var dep in mi.DependedModuleIds)
                    {
                        sb.Append("    ").Append(++j).Append(". ").AppendLine(dep);
                    }
                }
            }
            catch (Exception ex) {
                sb.Append("  *** ERROR: ").Append(ex.GetType().Name).Append(": ").AppendLine(ex.Message);
            }

            sb.AppendLine();

            try {
                sb.AppendLine("Harmony Patch Information:");
                var i = 0;
                foreach (var patchedMethod in Harmony.GetAllPatchedMethods())
                {
                    var patchInfo = Harmony.GetPatchInfo(patchedMethod);
                    sb.Append("  ").Append(++i).Append(". ").AppendLine(patchedMethod.FullDescription());

                    if (patchInfo.Prefixes.Count > 0)
                    {
                        var j = 0;
                        sb.Append("    ").AppendLine("Prefixes:");
                        foreach (var patch in patchInfo.Prefixes)
                        {
                            sb.Append("      ").Append(++j).Append(". ").AppendLine(patch.PatchMethod.FullDescription());
                            sb.Append("        ").AppendLine($"Owner: {patch.owner}, Priority: {patch.priority}");
                        }
                    }

                    if (patchInfo.Postfixes.Count > 0)
                    {
                        var j = 0;
                        sb.Append("    ").AppendLine("Postfixes:");
                        foreach (var patch in patchInfo.Postfixes)
                        {
                            sb.Append("      ").Append(++j).Append(". ").AppendLine(patch.PatchMethod.FullDescription());
                            sb.Append("        ").AppendLine($"Owner: {patch.owner}, Priority: {patch.priority}");
                        }
                    }

                    if (patchInfo.Finalizers.Count > 0)
                    {
                        var j = 0;
                        sb.Append("    ").AppendLine("Finalizers:");
                        foreach (var patch in patchInfo.Finalizers)
                        {
                            sb.Append("      ").Append(++j).Append(". ").AppendLine(patch.PatchMethod.FullDescription());
                            sb.Append("        ").AppendLine($"Owner: {patch.owner}, Priority: {patch.priority}");
                        }
                    }

                    if (patchInfo.Transpilers.Count > 0)
                    {
                        var j = 0;
                        sb.Append("    ").AppendLine("Transpilers:");
                        foreach (var patch in patchInfo.Transpilers)
                        {
                            sb.Append("      ").Append(++j).Append(". ").AppendLine(patch.PatchMethod.FullDescription());
                            sb.Append("        ").AppendLine($"Owner: {patch.owner}, Priority: {patch.priority}");
                        }
                    }
                }
            }
            catch (Exception ex) {
                sb.Append("  *** ERROR: ").Append(ex.GetType().Name).Append(": ").AppendLine(ex.Message);
            }

            sb.AppendLine();

            try {
                sb.AppendLine("Community Patch Information:");
                var i = 0;
                foreach (var patch in CommunityPatchSubModule.Patches)
                {
                    var type = patch.GetType();
                    sb.Append("  ").Append(++i).Append(". ").Append(type.Name);
                    if (ActivePatches.ContainsKey(type))
                    {
                        sb.Append(" *Active*");
                    }
                    var applicability = patch.IsApplicable(Game.Current);
                    if (applicability ?? false)
                    {
                        sb.Append(" *Applicable*");
                    }
                    if (applicability == null)
                    {
                        sb.Append(" *Maybe Applicable*");
                    }
                    if (patch.Applied)
                    {
                        sb.Append(" *Applied*");
                    }
                    sb.AppendLine();
                }
            }
            catch (Exception ex) {
                sb.Append("  *** ERROR: ").Append(ex.GetType().Name).Append(": ").AppendLine(ex.Message);
            }

            sb.AppendLine();

            try {
                sb.AppendLine("Loaded SubModules:");
                var i = 0;
                foreach (var sm in Module.CurrentModule.SubModules)
                {
                    try {
                        var type = sm.GetType();
                        var asm  = type.Assembly;
                        sb.Append("  ").Append(++i).Append(". ").AppendLine(type.AssemblyQualifiedName);
                        foreach (var version in asm.GetCustomAttributes <AssemblyInformationalVersionAttribute>())
                        {
                            sb.Append("    v").AppendLine(version.InformationalVersion);
                        }
                    }
                    catch (Exception ex) {
                        sb.Append("  *** ERROR: ").Append(ex.GetType().Name).Append(": ").AppendLine(ex.Message);
                    }
                }
            }
            catch (Exception ex) {
                sb.Append("  *** ERROR: ").Append(ex.GetType().Name).Append(": ").AppendLine(ex.Message);
            }

            sb.AppendLine();

            AppendSystemReport(sb);

            try {
                var reportStr = sb.ToString();

                ShowMessage("Saving to \"My Documents\\Mount and Blade II Bannerlord\\diagnostic-report.txt\"");

                try {
                    var docsMnb2 = new Uri(System.IO.Path.Combine(PathHelpers.GetConfigsDir(), "..")).LocalPath;
                    var now      = DateTime.UtcNow;
                    Random.GetNonZeroBytes(RandomIntBuf);
                    var randomInt = Unsafe.ReadUnaligned <uint>(ref RandomIntBuf[0]);
                    File.WriteAllText(System.IO.Path.Combine(docsMnb2, $"diagnostic-report.{now.Year:0000}{now.Month:00}{now.Day:00}{now.Hour:00}{now.Minute:00}{now.Second:00}{now.Millisecond}.{randomInt:X8}.txt"), reportStr);
                }
                catch (Exception ex2) {
                    ShowMessage($"Failed to save diagnostic report!\n{ex2.GetType().Name}: {ex2.Message}");
                }

                try {
                    Input.SetClipboardText(reportStr);
                    ShowMessage("Diagnostics also copied to system clipboard.");
                }
                catch (Exception ex) {
                    ShowMessage($"Writing to system clipboard failed!\n{ex.GetType().Name}: {ex.Message}");
                }
            }
            catch (Exception ex) {
                ShowMessage($"Failed to generate string from diagnostic report string buffer!\n{ex.GetType().Name}: {ex.Message}");
            }
        }