using System; using System.Collections; using System.Collections.Generic; using System.Collections.ObjectModel; using System.ComponentModel; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Text; using Microsoft.CodeAnalysis; using Mono.Cecil; using Mono.Cecil.Cil; using Mono.Collections.Generic; using MonoDetour; using MonoDetour.Bindings.Reorg; using MonoDetour.Bindings.Reorg.MonoModUtils; using MonoDetour.Bindings.Reorg.RuntimeDetour; using MonoDetour.Cil; using MonoDetour.Cil.Analysis; using MonoDetour.DetourTypes; using MonoDetour.DetourTypes.Manipulation; using MonoDetour.Interop.Cecil; using MonoDetour.Interop.MonoModUtils; using MonoDetour.Interop.RuntimeDetour; using MonoDetour.Logging; using MonoDetour.Reflection.Unspeakable; using MonoMod.Cil; using MonoMod.RuntimeDetour; using MonoMod.SourceGen.Internal; using MonoMod.Utils; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: InternalsVisibleTo("com.github.MonoDetour.Interop.HarmonyX")] [assembly: InternalsVisibleTo("MonoDetour.UnitTests")] [assembly: InternalsVisibleTo("0.com.github.MonoDetour.BepInEx.5")] [assembly: InternalsVisibleTo("0.com.github.MonoDetour.BepInEx.6")] [assembly: TargetFramework(".NETStandard,Version=v2.0", FrameworkDisplayName = ".NET Standard 2.0")] [assembly: AssemblyCompany("Hamunii")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyDescription("Easy and convenient .NET detouring library, powered by MonoMod.RuntimeDetour.")] [assembly: AssemblyFileVersion("0.7.15.0")] [assembly: AssemblyInformationalVersion("0.7.15+1a18a29676a2bb7aac7cc682a044e466d5c9708d")] [assembly: AssemblyProduct("MonoDetour")] [assembly: AssemblyTitle("MonoDetour")] [assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/MonoDetour/MonoDetour")] [assembly: AssemblyVersion("0.7.15.0")] [module: RefSafetyRules(11)] internal class { static () { ModuleInitialization.InitializeModule(); } } [CompilerGenerated] internal sealed class <>z__ReadOnlyArray : IEnumerable, ICollection, IList, IEnumerable, IReadOnlyCollection, IReadOnlyList, ICollection, IList { int ICollection.Count => _items.Length; bool ICollection.IsSynchronized => false; object ICollection.SyncRoot => this; object IList.this[int index] { get { return _items[index]; } set { throw new NotSupportedException(); } } bool IList.IsFixedSize => true; bool IList.IsReadOnly => true; int IReadOnlyCollection.Count => _items.Length; T IReadOnlyList.this[int index] => _items[index]; int ICollection.Count => _items.Length; bool ICollection.IsReadOnly => true; T IList.this[int index] { get { return _items[index]; } set { throw new NotSupportedException(); } } public <>z__ReadOnlyArray(T[] items) { _items = items; } IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable)_items).GetEnumerator(); } void ICollection.CopyTo(Array array, int index) { ((ICollection)_items).CopyTo(array, index); } int IList.Add(object value) { throw new NotSupportedException(); } void IList.Clear() { throw new NotSupportedException(); } bool IList.Contains(object value) { return ((IList)_items).Contains(value); } int IList.IndexOf(object value) { return ((IList)_items).IndexOf(value); } void IList.Insert(int index, object value) { throw new NotSupportedException(); } void IList.Remove(object value) { throw new NotSupportedException(); } void IList.RemoveAt(int index) { throw new NotSupportedException(); } IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable)_items).GetEnumerator(); } void ICollection.Add(T item) { throw new NotSupportedException(); } void ICollection.Clear() { throw new NotSupportedException(); } bool ICollection.Contains(T item) { return ((ICollection)_items).Contains(item); } void ICollection.CopyTo(T[] array, int arrayIndex) { ((ICollection)_items).CopyTo(array, arrayIndex); } bool ICollection.Remove(T item) { throw new NotSupportedException(); } int IList.IndexOf(T item) { return ((IList)_items).IndexOf(item); } void IList.Insert(int index, T item) { throw new NotSupportedException(); } void IList.RemoveAt(int index) { throw new NotSupportedException(); } } [CompilerGenerated] internal sealed class <>z__ReadOnlySingleElementList : IEnumerable, ICollection, IList, IEnumerable, IReadOnlyCollection, IReadOnlyList, ICollection, IList { private sealed class Enumerator : IDisposable, IEnumerator, IEnumerator { object IEnumerator.Current => _item; T IEnumerator.Current => _item; public Enumerator(T item) { _item = item; } bool IEnumerator.MoveNext() { if (!_moveNextCalled) { return _moveNextCalled = true; } return false; } void IEnumerator.Reset() { _moveNextCalled = false; } void IDisposable.Dispose() { } } int ICollection.Count => 1; bool ICollection.IsSynchronized => false; object ICollection.SyncRoot => this; object IList.this[int index] { get { if (index != 0) { throw new IndexOutOfRangeException(); } return _item; } set { throw new NotSupportedException(); } } bool IList.IsFixedSize => true; bool IList.IsReadOnly => true; int IReadOnlyCollection.Count => 1; T IReadOnlyList.this[int index] { get { if (index != 0) { throw new IndexOutOfRangeException(); } return _item; } } int ICollection.Count => 1; bool ICollection.IsReadOnly => true; T IList.this[int index] { get { if (index != 0) { throw new IndexOutOfRangeException(); } return _item; } set { throw new NotSupportedException(); } } public <>z__ReadOnlySingleElementList(T item) { _item = item; } IEnumerator IEnumerable.GetEnumerator() { return new Enumerator(_item); } void ICollection.CopyTo(Array array, int index) { array.SetValue(_item, index); } int IList.Add(object value) { throw new NotSupportedException(); } void IList.Clear() { throw new NotSupportedException(); } bool IList.Contains(object value) { return EqualityComparer.Default.Equals(_item, (T)value); } int IList.IndexOf(object value) { if (!EqualityComparer.Default.Equals(_item, (T)value)) { return -1; } return 0; } void IList.Insert(int index, object value) { throw new NotSupportedException(); } void IList.Remove(object value) { throw new NotSupportedException(); } void IList.RemoveAt(int index) { throw new NotSupportedException(); } IEnumerator IEnumerable.GetEnumerator() { return new Enumerator(_item); } void ICollection.Add(T item) { throw new NotSupportedException(); } void ICollection.Clear() { throw new NotSupportedException(); } bool ICollection.Contains(T item) { return EqualityComparer.Default.Equals(_item, item); } void ICollection.CopyTo(T[] array, int arrayIndex) { array[arrayIndex] = _item; } bool ICollection.Remove(T item) { throw new NotSupportedException(); } int IList.IndexOf(T item) { if (!EqualityComparer.Default.Equals(_item, item)) { return -1; } return 0; } void IList.Insert(int index, T item) { throw new NotSupportedException(); } void IList.RemoveAt(int index) { throw new NotSupportedException(); } } namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] internal sealed class IsReadOnlyAttribute : Attribute { } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace System { [ExcludeFromCodeCoverage] internal readonly struct Index : IEquatable { private static class ThrowHelper { [DoesNotReturn] public static void ThrowValueArgumentOutOfRange_NeedNonNegNumException() { throw new ArgumentOutOfRangeException("value", "Non-negative number required."); } } private readonly int _value; public static Index Start => new Index(0); public static Index End => new Index(-1); public int Value { get { if (_value < 0) { return ~_value; } return _value; } } public bool IsFromEnd => _value < 0; [MethodImpl(MethodImplOptions.AggressiveInlining)] public Index(int value, bool fromEnd = false) { if (value < 0) { ThrowHelper.ThrowValueArgumentOutOfRange_NeedNonNegNumException(); } if (fromEnd) { _value = ~value; } else { _value = value; } } private Index(int value) { _value = value; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Index FromStart(int value) { if (value < 0) { ThrowHelper.ThrowValueArgumentOutOfRange_NeedNonNegNumException(); } return new Index(value); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Index FromEnd(int value) { if (value < 0) { ThrowHelper.ThrowValueArgumentOutOfRange_NeedNonNegNumException(); } return new Index(~value); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public int GetOffset(int length) { int num = _value; if (IsFromEnd) { num += length + 1; } return num; } public override bool Equals([NotNullWhen(true)] object? value) { if (value is Index) { return _value == ((Index)value)._value; } return false; } public bool Equals(Index other) { return _value == other._value; } public override int GetHashCode() { return _value; } public static implicit operator Index(int value) { return FromStart(value); } public override string ToString() { if (IsFromEnd) { return ToStringFromEnd(); } return ((uint)Value).ToString(); } private string ToStringFromEnd() { return "^" + Value; } } [ExcludeFromCodeCoverage] internal readonly struct Range : IEquatable { private static class HashHelpers { public static int Combine(int h1, int h2) { uint num = (uint)((h1 << 5) | (h1 >>> 27)); return ((int)num + h1) ^ h2; } } private static class ThrowHelper { [DoesNotReturn] public static void ThrowArgumentOutOfRangeException() { throw new ArgumentOutOfRangeException("length"); } } public Index Start { get; } public Index End { get; } public static Range All => Index.Start..Index.End; public Range(Index start, Index end) { Start = start; End = end; } public override bool Equals([NotNullWhen(true)] object? value) { if (value is Range { Start: var start } range && start.Equals(Start)) { return range.End.Equals(End); } return false; } public bool Equals(Range other) { if (other.Start.Equals(Start)) { return other.End.Equals(End); } return false; } public override int GetHashCode() { return HashHelpers.Combine(Start.GetHashCode(), End.GetHashCode()); } public override string ToString() { return Start.ToString() + ".." + End; } public static Range StartAt(Index start) { return start..Index.End; } public static Range EndAt(Index end) { return Index.Start..end; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public (int Offset, int Length) GetOffsetAndLength(int length) { Index start = Start; int num = ((!start.IsFromEnd) ? start.Value : (length - start.Value)); Index end = End; int num2 = ((!end.IsFromEnd) ? end.Value : (length - end.Value)); if ((uint)num2 > (uint)length || (uint)num > (uint)num2) { ThrowHelper.ThrowArgumentOutOfRangeException(); } return (Offset: num, Length: num2 - num); } } } namespace System.Runtime.Versioning { [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Module | AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Enum | AttributeTargets.Constructor | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Interface | AttributeTargets.Delegate, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class RequiresPreviewFeaturesAttribute : Attribute { public string? Message { get; } public string? Url { get; set; } public RequiresPreviewFeaturesAttribute() { } public RequiresPreviewFeaturesAttribute(string? message) { Message = message; } } } namespace System.Runtime.CompilerServices { [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Enum | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, Inherited = false, AllowMultiple = false)] [ExcludeFromCodeCoverage] internal sealed class AsyncMethodBuilderAttribute : Attribute { public Type BuilderType { get; } public AsyncMethodBuilderAttribute(Type builderType) { BuilderType = builderType; } } [AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class CallerArgumentExpressionAttribute : Attribute { public string ParameterName { get; } public CallerArgumentExpressionAttribute(string parameterName) { ParameterName = parameterName; } } [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Interface, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class CollectionBuilderAttribute : Attribute { public Type BuilderType { get; } public string MethodName { get; } public CollectionBuilderAttribute(Type builderType, string methodName) { BuilderType = builderType; MethodName = methodName; } } [AttributeUsage(AttributeTargets.All, AllowMultiple = true, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class CompilerFeatureRequiredAttribute : Attribute { public const string RefStructs = "RefStructs"; public const string RequiredMembers = "RequiredMembers"; public string FeatureName { get; } public bool IsOptional { get; set; } public CompilerFeatureRequiredAttribute(string featureName) { FeatureName = featureName; } } [AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class InterpolatedStringHandlerArgumentAttribute : Attribute { public string[] Arguments { get; } public InterpolatedStringHandlerArgumentAttribute(string argument) { Arguments = new string[1] { argument }; } public InterpolatedStringHandlerArgumentAttribute(params string[] arguments) { Arguments = arguments; } } [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, AllowMultiple = false, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class InterpolatedStringHandlerAttribute : Attribute { } [EditorBrowsable(EditorBrowsableState.Never)] [ExcludeFromCodeCoverage] internal static class IsExternalInit { } [AttributeUsage(AttributeTargets.Method, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class ModuleInitializerAttribute : Attribute { } [AttributeUsage(AttributeTargets.Constructor | AttributeTargets.Method | AttributeTargets.Property, AllowMultiple = false, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class OverloadResolutionPriorityAttribute : Attribute { public int Priority { get; } public OverloadResolutionPriorityAttribute(int priority) { Priority = priority; } } [AttributeUsage(AttributeTargets.Parameter, Inherited = true, AllowMultiple = false)] [ExcludeFromCodeCoverage] internal sealed class ParamCollectionAttribute : Attribute { } [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class RequiredMemberAttribute : Attribute { } [AttributeUsage(AttributeTargets.Parameter, Inherited = false)] [EditorBrowsable(EditorBrowsableState.Never)] [ExcludeFromCodeCoverage] internal sealed class RequiresLocationAttribute : Attribute { } [AttributeUsage(AttributeTargets.Module | AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Constructor | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Event | AttributeTargets.Interface, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class SkipLocalsInitAttribute : Attribute { } } namespace System.Diagnostics.CodeAnalysis { [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class AllowNullAttribute : Attribute { } [AttributeUsage(AttributeTargets.Parameter, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class ConstantExpectedAttribute : Attribute { public object? Min { get; set; } public object? Max { get; set; } } [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class DisallowNullAttribute : Attribute { } [AttributeUsage(AttributeTargets.Method, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class DoesNotReturnAttribute : Attribute { } [AttributeUsage(AttributeTargets.Parameter, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class DoesNotReturnIfAttribute : Attribute { public bool ParameterValue { get; } public DoesNotReturnIfAttribute(bool parameterValue) { ParameterValue = parameterValue; } } [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Module | AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Enum | AttributeTargets.Constructor | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Interface | AttributeTargets.Delegate, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class ExperimentalAttribute : Attribute { public string DiagnosticId { get; } public string? UrlFormat { get; set; } public ExperimentalAttribute(string diagnosticId) { DiagnosticId = diagnosticId; } } [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.ReturnValue, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class MaybeNullAttribute : Attribute { } [AttributeUsage(AttributeTargets.Parameter, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class MaybeNullWhenAttribute : Attribute { public bool ReturnValue { get; } public MaybeNullWhenAttribute(bool returnValue) { ReturnValue = returnValue; } } [AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, Inherited = false, AllowMultiple = true)] [ExcludeFromCodeCoverage] internal sealed class MemberNotNullAttribute : Attribute { public string[] Members { get; } public MemberNotNullAttribute(string member) { Members = new string[1] { member }; } public MemberNotNullAttribute(params string[] members) { Members = members; } } [AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, Inherited = false, AllowMultiple = true)] [ExcludeFromCodeCoverage] internal sealed class MemberNotNullWhenAttribute : Attribute { public bool ReturnValue { get; } public string[] Members { get; } public MemberNotNullWhenAttribute(bool returnValue, string member) { ReturnValue = returnValue; Members = new string[1] { member }; } public MemberNotNullWhenAttribute(bool returnValue, params string[] members) { ReturnValue = returnValue; Members = members; } } [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.ReturnValue, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class NotNullAttribute : Attribute { } [AttributeUsage(AttributeTargets.Property | AttributeTargets.Parameter | AttributeTargets.ReturnValue, AllowMultiple = true, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class NotNullIfNotNullAttribute : Attribute { public string ParameterName { get; } public NotNullIfNotNullAttribute(string parameterName) { ParameterName = parameterName; } } [AttributeUsage(AttributeTargets.Parameter, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class NotNullWhenAttribute : Attribute { public bool ReturnValue { get; } public NotNullWhenAttribute(bool returnValue) { ReturnValue = returnValue; } } [AttributeUsage(AttributeTargets.Constructor, AllowMultiple = false, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class SetsRequiredMembersAttribute : Attribute { } [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class StringSyntaxAttribute : Attribute { public const string CompositeFormat = "CompositeFormat"; public const string DateOnlyFormat = "DateOnlyFormat"; public const string DateTimeFormat = "DateTimeFormat"; public const string EnumFormat = "EnumFormat"; public const string GuidFormat = "GuidFormat"; public const string Json = "Json"; public const string NumericFormat = "NumericFormat"; public const string Regex = "Regex"; public const string TimeOnlyFormat = "TimeOnlyFormat"; public const string TimeSpanFormat = "TimeSpanFormat"; public const string Uri = "Uri"; public const string Xml = "Xml"; public string Syntax { get; } public object?[] Arguments { get; } public StringSyntaxAttribute(string syntax) { Syntax = syntax; Arguments = new object[0]; } public StringSyntaxAttribute(string syntax, params object?[] arguments) { Syntax = syntax; Arguments = arguments; } } [AttributeUsage(AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class UnscopedRefAttribute : Attribute { } } namespace MonoMod.SourceGen.Internal { internal sealed class CodeBuilder { private readonly StringBuilder sb; private readonly char indentChar = ' '; private readonly int indentAmount; private int indentLevel; private bool didWriteIndent; public CodeBuilder(StringBuilder sb, int indentAmount = 4) { this.sb = sb; this.indentAmount = indentAmount; } public CodeBuilder WriteHeader() { WriteLine("// "); WriteLine("#pragma warning disable"); WriteLine("#nullable enable"); WriteLine("using PrefixDetour = global::MonoDetour.DetourTypes.PrefixDetour;"); WriteLine("using PostfixDetour = global::MonoDetour.DetourTypes.PostfixDetour;"); WriteLine("using ILHookDetour = global::MonoDetour.DetourTypes.ILHookDetour;"); return this; } public CodeBuilder OpenBlock() { return WriteLine('{').IncreaseIndent(); } public CodeBuilder CloseBlock() { return DecreaseIndent().WriteLine('}'); } public CodeBuilder IncreaseIndent() { indentLevel++; return this; } public CodeBuilder DecreaseIndent() { indentLevel--; return this; } public CodeBuilder RemoveIndent() { indentLevel = 0; return this; } private void WriteIndentIfNeeded() { if (!didWriteIndent) { if (indentLevel > 0) { sb.Append(indentChar, indentLevel * indentAmount); } didWriteIndent = true; } } public CodeBuilder Write(int i) { return Write(i.ToString(CultureInfo.InvariantCulture)); } public CodeBuilder Write(string? s) { WriteIndentIfNeeded(); sb.Append(s); return this; } public CodeBuilder Write(char c) { WriteIndentIfNeeded(); sb.Append(c); return this; } public CodeBuilder WriteLine(int i) { return WriteLine(i.ToString(CultureInfo.InvariantCulture)); } public CodeBuilder WriteLine(string s) { WriteIndentIfNeeded(); sb.AppendLine(s); didWriteIndent = false; return this; } public CodeBuilder WriteLine(char c) { WriteIndentIfNeeded(); sb.Append(c).AppendLine(); didWriteIndent = false; return this; } public CodeBuilder WriteLine() { sb.AppendLine(); didWriteIndent = false; return this; } public override string ToString() { return sb.ToString(); } } } namespace MonoDetour { internal static class Helpers { [MethodImpl(MethodImplOptions.AggressiveInlining)] public static T ThrowIfNull([NotNull] T? argument, [CallerArgumentExpression("argument")] string name = "") { if (argument == null) { ThrowArgumentNull(name); } return argument; } [DoesNotReturn] private static void ThrowArgumentNull(string argName) { throw new ArgumentNullException(argName); } } public interface IMonoDetourHook : IReadOnlyMonoDetourHook, IDisposable { void Apply(); void Undo(); } public interface IReadOnlyMonoDetourHook { MethodBase Target { get; } MethodBase Manipulator { get; } Delegate? ManipulatorDelegate { get; } MonoDetourManager Owner { get; } MonoDetourConfig? Config { get; } bool IsValid { get; } bool IsApplied { get; } } internal static class ModuleInitialization { private static bool isInitialized; [ModuleInitializer] internal static void InitializeModule() { string environmentVariable = Environment.GetEnvironmentVariable("MONODETOUR_MANUAL_INIT"); if (!(environmentVariable == "1")) { Initialize(); } } internal static void Initialize() { if (!isInitialized) { isInitialized = true; MonoDetourLogger.ParseEnvironmentVariables(); ILHookInstructionILLabelCastFixes.InitHook(); ILHookDMDManipulation.InitHook(); LegacyILHookAntiExploder.InitHook(); } } } public class MonoDetourConfig : IMonoDetourConfig { public string? OverrideId { get; } public int Priority { get; } public IEnumerable Before { get; } public IEnumerable After { get; } public MonoDetourConfig(int priority = 0, IEnumerable? before = null, IEnumerable? after = null, string? overrideId = null) { Priority = priority; Before = AsFixedSize(before ?? Array.Empty()); After = AsFixedSize(after ?? Array.Empty()); OverrideId = overrideId; } private static IEnumerable AsFixedSize(IEnumerable enumerable) { if (enumerable == Enumerable.Empty()) { return enumerable; } if (enumerable is ICollection) { return enumerable; } return enumerable.ToArray(); } public MonoDetourConfig WithPriority(int priority) { return new MonoDetourConfig(priority, Before, After, OverrideId); } public MonoDetourConfig WithBefore(IEnumerable before) { return new MonoDetourConfig(Priority, before, After, OverrideId); } public MonoDetourConfig WithBefore(params string[] before) { return WithBefore(before.AsEnumerable()); } public MonoDetourConfig WithAfter(IEnumerable after) { return new MonoDetourConfig(Priority, Before, after, OverrideId); } public MonoDetourConfig WithAfter(params string[] after) { return WithAfter(after.AsEnumerable()); } public MonoDetourConfig AddBefore(IEnumerable before) { return WithBefore(Before.Concat(before)); } public MonoDetourConfig AddBefore(params string[] before) { return AddBefore(before.AsEnumerable()); } public MonoDetourConfig AddAfter(IEnumerable after) { return WithAfter(After.Concat(after)); } public MonoDetourConfig AddAfter(params string[] after) { return AddAfter(after.AsEnumerable()); } } public class MonoDetourHook : IMonoDetourHook, IReadOnlyMonoDetourHook, IDisposable { private static readonly Dictionary> s_TargetToHooks = new Dictionary>(); private static readonly ConditionalWeakTable s_ManipulatorToHook = new ConditionalWeakTable(); private static readonly object tableLock = new object(); private bool isDisposed; public MethodBase Target { get; } public MethodBase Manipulator { get; } public Delegate? ManipulatorDelegate { get; } public MonoDetourManager Owner { get; } public MonoDetourConfig? Config { get; } public ILHook Applier { get; } public Type ApplierType { get; } public bool IsValid => Applier.IsValid; public bool IsApplied => Applier.IsApplied; private MonoDetourHook(MethodBase target, MethodBase manipulator, Delegate? manipulatorDelegate, Type applierType, MonoDetourManager owner, MonoDetourConfig? config = null, bool applyByDefault = true) { //IL_018b: Unknown result type (might be due to invalid IL or missing references) //IL_0192: Expected O, but got Unknown Target = Helpers.ThrowIfNull(target, "target"); Manipulator = Helpers.ThrowIfNull(manipulator, "manipulator"); Owner = Helpers.ThrowIfNull(owner, "owner"); ManipulatorDelegate = manipulatorDelegate; ApplierType = applierType; Config = config; IMonoDetourHookApplier monoDetourHookApplier = (IMonoDetourHookApplier)Activator.CreateInstance(applierType); monoDetourHookApplier.Hook = this; owner.Hooks.Add(this); Type declaringType = Manipulator.DeclaringType; string text = (((object)declaringType != null) ? (declaringType.FullName + "." + Manipulator.Name) : Manipulator.Name); Type declaringType2 = Target.DeclaringType; string text2 = (((object)declaringType2 != null) ? (declaringType2.FullName + "." + Target.Name) : Target.Name); string text3; if (ApplierType.Name.EndsWith("Detour", StringComparison.Ordinal)) { string name = ApplierType.Name; text3 = name.Substring(0, name.Length - 6); } else { text3 = ApplierType.Name; } string text4 = (applyByDefault ? "Applied" : "Constructed"); owner.Log(MonoDetourLogger.LogChannel.Info, text4 + " " + text3 + " '" + text + "' targeting '" + text2 + "'"); Manipulator val = new Manipulator(monoDetourHookApplier.ApplierManipulator); Applier = ProxyILHookConstructor.ConstructILHook(target, val, (IMonoDetourConfig?)(object)config, owner.Id); lock (tableLock) { s_ManipulatorToHook.Add(val, this); if (s_TargetToHooks.TryGetValue(Target, out List value)) { value.Add(this); } else { s_TargetToHooks.Add(Target, new List(1) { this }); } } if (applyByDefault) { Applier.Apply(); } } public static MonoDetourHook Create(MethodBase target, Delegate manipulator, MonoDetourManager owner, MonoDetourConfig? config = null, bool applyByDefault = true) where TApplier : class, IMonoDetourHookApplier { return new MonoDetourHook(target, Helpers.ThrowIfNull(manipulator, "manipulator").Method, manipulator, typeof(TApplier), owner, config, applyByDefault); } public static MonoDetourHook Create(MethodBase target, MethodBase manipulator, MonoDetourManager owner, MonoDetourConfig? config = null, bool applyByDefault = true) where TApplier : class, IMonoDetourHookApplier { return new MonoDetourHook(target, manipulator, null, typeof(TApplier), owner, config, applyByDefault); } public static bool TryGetFrom(Manipulator key, [NotNullWhen(true)] out MonoDetourHook? monoDetourHook) { return s_ManipulatorToHook.TryGetValue(key, out monoDetourHook); } internal static bool HasActiveControlFlowMonoDetourHooks(MethodBase target, out int count) { count = 0; if (!s_TargetToHooks.TryGetValue(target, out List value)) { return false; } foreach (IReadOnlyMonoDetourHook item in value) { if (item.IsApplied && item.ModifiesControlFlow()) { count++; } } return count > 0; } public void Apply() { Applier.Apply(); } public void Undo() { Applier.Undo(); } public void Dispose() { if (!isDisposed) { Applier.Dispose(); GC.SuppressFinalize(this); isDisposed = true; } } } [AttributeUsage(AttributeTargets.Method, Inherited = false)] public class MonoDetourHookInitializeAttribute : Attribute { } public class MonoDetourManager : IDisposable, IMonoDetourLogSource { private bool isDisposed; public string Id { get; } = Helpers.ThrowIfNull(id, "id"); public MonoDetourLogger.LogChannel LogFilter { get; set; } = MonoDetourLogger.LogChannel.Warning | MonoDetourLogger.LogChannel.Error; public List Hooks { get; } = new List(); public event Action? OnHookThrew; public MonoDetourManager(string id) { } private void ThrowIfDisposed() { if (!isDisposed) { return; } throw new ObjectDisposedException(ToString()); } internal bool CallOnHookThrew(IReadOnlyMonoDetourHook hook) { if (this.OnHookThrew == null) { return false; } this.OnHookThrew(hook); return true; } public static void InvokeHookInitializers(Assembly assembly, bool reportUnloadableTypes = true) { Type[] typesFromAssembly = ReflectionUtils.GetTypesFromAssembly(assembly, reportUnloadableTypes); foreach (Type type in typesFromAssembly) { if (ReflectionUtils.HasCustomAttribute(type, reportUnloadableTypes)) { InvokeHookInitializers(type, reportUnloadableTypes); } } } public static void InvokeHookInitializers(Assembly assembly) { InvokeHookInitializers(assembly, reportUnloadableTypes: true); } public static void InvokeHookInitializers(Type type, bool reportUnloadableTypes = true) { MethodInfo[] methods = type.GetMethods((BindingFlags)(-1)); MethodInfo[] array = methods; foreach (MethodInfo methodInfo in array) { if (ReflectionUtils.HasCustomAttribute(methodInfo, reportUnloadableTypes)) { methodInfo.Invoke(null, null); } } } public static void InvokeHookInitializers(Type type) { InvokeHookInitializers(type, reportUnloadableTypes: true); } public void ApplyHooks() { Hooks.ForEach(delegate(IMonoDetourHook x) { x.Apply(); }); } public void UndoHooks() { Hooks.ForEach(delegate(IMonoDetourHook x) { x.Undo(); }); } public void DisposeHooks() { Hooks.ForEach(delegate(IMonoDetourHook x) { x.Dispose(); }); Hooks.Clear(); } public MonoDetourHook ILHook(Delegate target, ILManipulationInfo.Manipulator manipulator, MonoDetourConfig? config = null, bool applyByDefault = true) { return ILHook(target.Method, manipulator, config, applyByDefault); } public MonoDetourHook ILHook(MethodBase target, ILManipulationInfo.Manipulator manipulator, MonoDetourConfig? config = null, bool applyByDefault = true) { return Hook(target, manipulator, config, applyByDefault); } public MonoDetourHook Hook(Delegate target, Delegate manipulator, MonoDetourConfig? config = null, bool applyByDefault = true) where TApplier : class, IMonoDetourHookApplier { return Hook(target.Method, manipulator, config, applyByDefault); } public MonoDetourHook Hook(MethodBase target, Delegate manipulator, MonoDetourConfig? config = null, bool applyByDefault = true) where TApplier : class, IMonoDetourHookApplier { ThrowIfDisposed(); return MonoDetourHook.Create(target, manipulator, this, config, applyByDefault); } public MonoDetourHook Hook(MethodBase target, MethodBase manipulator, MonoDetourConfig? config = null, bool applyByDefault = true) where TApplier : class, IMonoDetourHookApplier { ThrowIfDisposed(); return MonoDetourHook.Create(target, manipulator, this, config, applyByDefault); } public void Dispose() { if (!isDisposed) { DisposeHooks(); GC.SuppressFinalize(this); isDisposed = true; } } } public interface IMonoDetourTargets { } internal static class ReflectionUtils { public static bool HasCustomAttribute(MemberInfo member, bool reportUnloadableTypes) { IEnumerable customAttributes; try { customAttributes = member.GetCustomAttributes(); } catch (TypeLoadException) { if (!reportUnloadableTypes) { return false; } bool flag = false; foreach (CustomAttributeData customAttribute in member.CustomAttributes) { try { if (typeof(T).IsAssignableFrom(customAttribute.AttributeType)) { flag = true; break; } } catch (TypeLoadException) { } } if (flag) { MonoDetourLogger.Log(MonoDetourLogger.LogChannel.Warning, "[InvokeHookInitializers]" + $" Skipping '{member}' ({member.Module.Assembly.GetName().Name}) due to unloadable type." + " Use 'reportUnloadableTypes: false' to hide this message."); } return false; } foreach (Attribute item in customAttributes) { if (item is T) { return true; } } return false; } public static Type[] GetTypesFromAssembly(Assembly assembly, bool reportUnloadableTypes) { try { Type[] types = assembly.GetTypes(); for (int i = 0; i < types.Length; i++) { if (types[i] == null) { ReportUnloadableAssemblyTypes(assembly, reportUnloadableTypes); return types.Where((Type type) => (object)type != null).ToArray(); } } return types; } catch (ReflectionTypeLoadException ex) { ReportUnloadableAssemblyTypes(assembly, reportUnloadableTypes); return ex.Types.Where((Type type) => (object)type != null).ToArray(); } } private static void ReportUnloadableAssemblyTypes(Assembly assembly, bool reportUnloadableTypes) { if (reportUnloadableTypes) { MonoDetourLogger.Log(MonoDetourLogger.LogChannel.Warning, "[InvokeHookInitializers] Unloadable type(s) found in '" + assembly.GetName().Name + "'. If such a type has hook initializers, they will be skipped. Use 'reportUnloadableTypes: false' to hide this message."); } } } } namespace MonoDetour.Logging { internal interface IMonoDetourLogSource { MonoDetourLogger.LogChannel LogFilter { get; set; } } public static class MonoDetourLogger { internal delegate void LogReceiver(LogChannel channel, string message); [Flags] public enum LogChannel { None = 0, Info = 2, IL = 4, Warning = 8, Error = 0x10 } private static LogChannel GlobalFilter { get; set; } = LogChannel.Warning | LogChannel.Error; private static LogChannel OverrideFilter { get; set; } = LogChannel.None; internal static event LogReceiver? OnLog; private static string LogChannelToString(LogChannel channel) { return channel switch { LogChannel.None => "None ", LogChannel.Info => "Info ", LogChannel.IL => "IL ", LogChannel.Warning => "Warning", LogChannel.Error => "Error ", _ => throw new NotSupportedException(), }; } internal static void ParseEnvironmentVariables() { string text = "MONODETOUR_LOG_OVERRIDE"; string environmentVariable = Environment.GetEnvironmentVariable(text); if (environmentVariable == null) { return; } string[] array = environmentVariable.Split(new char[1] { ':' }); string[] array2 = array; foreach (string text2 in array2) { if (!Enum.TryParse(text2, ignoreCase: true, out var result)) { Log(LogChannel.Error, "Failed to parse value '" + text2 + "' in '" + environmentVariable + "' from environment variable '" + text + "'"); } else { OverrideFilter |= result; } } } internal static bool IsEnabledFor(LogChannel caller, LogChannel channel) { return ((caller | OverrideFilter) & channel) != 0; } internal static void Log(this MonoDetourManager caller, LogChannel channel, Func message) { if (IsEnabledFor(caller.LogFilter, channel)) { string message2 = "[" + caller.Id + "] " + message(); if (MonoDetourLogger.OnLog == null) { DefaultLog(channel, message2); } else { MonoDetourLogger.OnLog(channel, message2); } } } internal static void Log(this IMonoDetourLogSource caller, LogChannel channel, Func message) { if (IsEnabledFor(caller.LogFilter, channel)) { if (MonoDetourLogger.OnLog == null) { DefaultLog(channel, message()); } else { MonoDetourLogger.OnLog(channel, message()); } } } internal static void Log(LogChannel channel, Func message) { if (IsEnabledFor(GlobalFilter, channel)) { if (MonoDetourLogger.OnLog == null) { DefaultLog(channel, message()); } else { MonoDetourLogger.OnLog(channel, message()); } } } internal static void Log(this MonoDetourManager caller, LogChannel channel, string message) { if (IsEnabledFor(caller.LogFilter, channel)) { message = "[" + caller.Id + "] " + message; if (MonoDetourLogger.OnLog == null) { DefaultLog(channel, message); } else { MonoDetourLogger.OnLog(channel, message); } } } internal static void Log(this IMonoDetourLogSource caller, LogChannel channel, string message) { if (IsEnabledFor(caller.LogFilter, channel)) { if (MonoDetourLogger.OnLog == null) { DefaultLog(channel, message); } else { MonoDetourLogger.OnLog(channel, message); } } } internal static void Log(LogChannel channel, string message) { if (IsEnabledFor(GlobalFilter, channel)) { if (MonoDetourLogger.OnLog == null) { DefaultLog(channel, message); } else { MonoDetourLogger.OnLog(channel, message); } } } private static void DefaultLog(LogChannel channel, string message) { LogWithChannel("[" + LogChannelToString(channel) + ": MonoDetour] " + message, channel); } private static void LogWithChannel(string message, LogChannel channel) { ConsoleColor foregroundColor = channel switch { LogChannel.Warning => ConsoleColor.Yellow, LogChannel.Error => ConsoleColor.Red, _ => Console.ForegroundColor, }; ConsoleColor foregroundColor2 = Console.ForegroundColor; Console.ForegroundColor = foregroundColor; if (channel == LogChannel.Error && MonoModVersion.IsReorg) { Console.Error.WriteLine(message); } else { Console.Out.WriteLine(message); } Console.ForegroundColor = foregroundColor2; } } } namespace MonoDetour.Interop.RuntimeDetour { internal static class ILHookDMDManipulation { [CompilerGenerated] private static class <>O { public static Manipulator <0>__GetDMDBeforeManipulation; public static ILManipulationInfo.Manipulator <1>__TryCatchAnalyzeCompilationReorg; public static ILManipulationInfo.Manipulator <2>__TryCatchAnalyzeCompilationLegacy; public static Func <3>__BorrowDMD; public static Action <4>__AnalyzeMethod; public static Func <5>__GetMethodBody; public static Action <6>__AnalyzeMethodBody; } internal static readonly ConditionalWeakTable> s_MethodDefinitionToOriginalInstructions = new ConditionalWeakTable>(); internal static readonly ConditionalWeakTable s_MethodDefinitionToOriginalMethod = new ConditionalWeakTable(); private static ConstructorInfo dmdConstructor = null; private static ILHook getDmdBeforeManipulationHook = null; private static readonly MonoDetourManager m = new MonoDetourManager(typeof(ILHookDMDManipulation).Assembly.GetName().Name); internal static MethodInfo? legacyContextRefreshMethod; private static bool initialized; internal static void InitHook() { if (initialized) { return; } initialized = true; try { if (MonoModVersion.IsReorg) { InitHookReorg(); } else { InitHookLegacy(); } } catch (Exception innerException) { throw new NotSupportedException("MonoDetour doesn't seem to support this MonoMod version, please report this issue: https://github.com/MonoDetour/MonoDetour: " + $"'{typeof(Hook).Assembly}'", innerException); } } private static void InitHookReorg() { //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Expected O, but got Unknown //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Expected O, but got Unknown dmdConstructor = typeof(DynamicMethodDefinition).GetConstructor(new Type[1] { typeof(DynamicMethodDefinition) }) ?? throw new NullReferenceException("DMD constructor not found."); Type type = Type.GetType("MonoMod.RuntimeDetour.DetourManager+ManagedDetourState, MonoMod.RuntimeDetour") ?? throw new NullReferenceException("Type 'MonoMod.RuntimeDetour.DetourManager+ManagedDetourState, MonoMod.RuntimeDetour' not found."); MethodInfo methodInfo = type.GetMethod("UpdateEndOfChain", BindingFlags.Instance | BindingFlags.NonPublic) ?? throw new NullReferenceException("Method 'UpdateEndOfChain' not found."); object obj = <>O.<0>__GetDMDBeforeManipulation; if (obj == null) { Manipulator val = GetDMDBeforeManipulation; <>O.<0>__GetDMDBeforeManipulation = val; obj = (object)val; } getDmdBeforeManipulationHook = new ILHook((MethodBase)methodInfo, (Manipulator)obj); m.ILHook(methodInfo, TryCatchAnalyzeCompilationReorg); } private static void InitHookLegacy() { //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Expected O, but got Unknown //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Expected O, but got Unknown dmdConstructor = typeof(DynamicMethodDefinition).GetConstructor(new Type[1] { typeof(MethodBase) }) ?? throw new NullReferenceException("DMD constructor not found."); Type type = Type.GetType("MonoMod.RuntimeDetour.ILHook+Context, MonoMod.RuntimeDetour") ?? throw new NullReferenceException("Type 'MonoMod.RuntimeDetour.ILHook+Context, MonoMod.RuntimeDetour' not found."); legacyContextRefreshMethod = type.GetMethod("Refresh") ?? throw new NullReferenceException("Method 'Refresh' not found."); MethodInfo? methodInfo = legacyContextRefreshMethod; object obj = <>O.<0>__GetDMDBeforeManipulation; if (obj == null) { Manipulator val = GetDMDBeforeManipulation; <>O.<0>__GetDMDBeforeManipulation = val; obj = (object)val; } getDmdBeforeManipulationHook = new ILHook((MethodBase)methodInfo, (Manipulator)obj); m.ILHook(legacyContextRefreshMethod, TryCatchAnalyzeCompilationLegacy); } private static void GetDMDBeforeManipulation(ILContext il) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Expected O, but got Unknown ILCursor val = new ILCursor(il); if (!val.TryGotoNext((MoveType)2, new Func[1] { (Instruction x) => ILPatternMatchingExt.MatchNewobj(x, (MethodBase)dmdConstructor) })) { throw new NullReferenceException("DMD construction not found. " + il.ToAnalyzedString()); } val.EmitDelegate>((Func)BorrowDMD); } private static DynamicMethodDefinition BorrowDMD(DynamicMethodDefinition dmd) { MethodDefinition definition = dmd.Definition; ReadOnlyCollection value = ((IEnumerable)definition.Body.Instructions).ToList().AsReadOnly(); s_MethodDefinitionToOriginalInstructions.Add(definition, value); s_MethodDefinitionToOriginalMethod.Add(definition, dmd.OriginalMethod); return dmd; } private static void TryCatchAnalyzeCompilationReorg(ILManipulationInfo info) { //IL_0163: Unknown result type (might be due to invalid IL or missing references) ILWeaver w = new ILWeaver(info); int localIndexDmd = 0; Instruction tryStart = null; int num = default(int); MethodReference val = default(MethodReference); w.MatchRelaxed((Instruction x) => ILPatternMatchingExt.MatchLdloc(x, ref localIndexDmd), (Instruction x) => ILPatternMatchingExt.MatchCallvirt(x, ref val), (Instruction x) => ILPatternMatchingExt.MatchStloc(x, ref num), (Instruction x) => ILPatternMatchingExt.MatchCall(x, ref val) && w.SetInstructionTo(ref tryStart, x), (Instruction x) => ILPatternMatchingExt.MatchLdloc(x, ref num), (Instruction x) => ILPatternMatchingExt.MatchCallvirt(x, ref val) && w.SetCurrentTo(x)).Extract(out ILWeaverResult result); if (!result.IsValid) { MonoDetourLogger.Log(MonoDetourLogger.LogChannel.Error, "MonoDetour's invalid IL analysis failed to be applied. Please report this issue: https://github.com/MonoDetour/MonoDetour: " + $"'{typeof(Hook).Assembly}'"); MonoDetourLogger.Log(MonoDetourLogger.LogChannel.Error, result.FailureMessage); return; } w.HandlerCreateCatch(typeof(InvalidProgramException), out WeaverExceptionCatchHandler handler); w.HandlerSetTryStart(tryStart, handler); w.HandlerSetTryEnd(w.Current, handler); w.InsertAfterCurrent(new <>z__ReadOnlyArray((Instruction[])(object)new Instruction[2] { w.Create(OpCodes.Ldloc, localIndexDmd), w.CreateCall(new Action(AnalyzeMethod)) })); w.HandlerSetHandlerEnd(w.Current, handler); w.HandlerApply(handler); } private static void TryCatchAnalyzeCompilationLegacy(ILManipulationInfo info) { //IL_00ef: Unknown result type (might be due to invalid IL or missing references) //IL_012b: Unknown result type (might be due to invalid IL or missing references) //IL_02c1: Unknown result type (might be due to invalid IL or missing references) ILWeaver w = new ILWeaver(info); int localIndexDmd = 0; int num = default(int); w.MatchRelaxed((Instruction x) => ILPatternMatchingExt.MatchLdloc(x, ref localIndexDmd) && w.SetCurrentTo(x), (Instruction x) => ILPatternMatchingExt.MatchCallvirt(x, "Generate"), (Instruction x) => ILPatternMatchingExt.MatchStloc(x, ref num)).Extract(out ILWeaverResult result); if (!result.IsValid) { MonoDetourLogger.Log(MonoDetourLogger.LogChannel.Error, "MonoDetour's invalid IL analysis failed to be applied. Please report this issue: https://github.com/MonoDetour/MonoDetour: " + $"'{typeof(Hook).Assembly}'"); MonoDetourLogger.Log(MonoDetourLogger.LogChannel.Error, result.FailureMessage); return; } VariableDefinition variable = w.DeclareVariable(typeof(MethodBody)); w.InsertAfterCurrent(new <>z__ReadOnlyArray((Instruction[])(object)new Instruction[3] { w.Create(OpCodes.Dup), w.CreateCall(new Func(GetMethodBody)), w.Create(OpCodes.Stloc, variable) })); Instruction tryStart = null; FieldReference val = default(FieldReference); w.MatchRelaxed((Instruction x) => ILPatternMatchingExt.MatchLdarg(x, ref num) && w.SetInstructionTo(ref tryStart, x), (Instruction x) => ILPatternMatchingExt.MatchLdarg(x, ref num), (Instruction x) => ILPatternMatchingExt.MatchLdfld(x, ref val), (Instruction x) => ILPatternMatchingExt.MatchLdloc(x, ref num), (Instruction x) => ILPatternMatchingExt.MatchLdsflda(x, ref val), (Instruction x) => ILPatternMatchingExt.MatchNewobj(x, ref val), (Instruction x) => ILPatternMatchingExt.MatchStfld(x, ref val) && w.SetCurrentTo(x)).Extract(out result); if (!result.IsValid) { MonoDetourLogger.Log(MonoDetourLogger.LogChannel.Error, "MonoDetour's invalid IL analysis failed to be applied. Please report this issue: https://github.com/MonoDetour/MonoDetour: " + $"'{typeof(Hook).Assembly}'"); MonoDetourLogger.Log(MonoDetourLogger.LogChannel.Error, result.FailureMessage); return; } w.HandlerCreateCatch(typeof(InvalidProgramException), out WeaverExceptionCatchHandler handler); w.HandlerSetTryStart(tryStart, handler); w.HandlerSetTryEnd(w.Current, handler); w.InsertAfterCurrent(new <>z__ReadOnlyArray((Instruction[])(object)new Instruction[2] { w.Create(OpCodes.Ldloc, variable), w.CreateCall(new Action(AnalyzeMethodBody)) })); w.HandlerSetHandlerEnd(w.Current, handler); w.HandlerApply(handler); } private static MethodBody GetMethodBody(DynamicMethodDefinition dmd) { return dmd.Definition.Body; } private static void AnalyzeMethod(InvalidProgramException ex, DynamicMethodDefinition dmd) { AnalyzeMethodBody(ex, dmd.Definition.Body); } private static void AnalyzeMethodBody(InvalidProgramException ex, MethodBody body) { string message; try { message = body.CreateInformationalSnapshotJIT().AnnotateErrors().ToErrorMessageString(); } catch (Exception ex2) { throw new Exception("MonoDetour failed to analyze invalid program: " + ex2, ex); } throw new InvalidProgramException(message, ex); } } internal static class LegacyILHookAntiExploder { private static readonly MonoDetourManager antiExploderManager = new MonoDetourManager(typeof(LegacyILHookAntiExploder).Assembly.GetName().Name); private static bool initialized; internal static void InitHook() { if (initialized) { return; } initialized = true; try { if (!MonoModVersion.IsReorg) { InitHookLegacy(); } } catch (Exception innerException) { throw new NotSupportedException("MonoDetour doesn't seem to support this MonoMod version, please report this issue: https://github.com/MonoDetour/MonoDetour: " + $"'{typeof(Hook).Assembly}'", innerException); } } private static void InitHookLegacy() { Type typeFromHandle = typeof(ILHook); MethodInfo target = typeFromHandle.GetMethod("Apply") ?? throw new NullReferenceException("Method 'Apply' not found."); if ((object)ILHookDMDManipulation.legacyContextRefreshMethod == null) { throw new NullReferenceException("ILHook.Context.Refresh is null"); } antiExploderManager.ILHook(target, TryCatchILHookApply); } private static void TryCatchILHookApply(ILManipulationInfo info) { //IL_0088: Unknown result type (might be due to invalid IL or missing references) ILWeaver w = new ILWeaver(info); ILWeaverResult iLWeaverResult = w.MatchRelaxed((Instruction x) => ILPatternMatchingExt.MatchCallvirt(x, (MethodBase)ILHookDMDManipulation.legacyContextRefreshMethod) && w.SetCurrentTo(x)); if (!iLWeaverResult.IsValid) { MonoDetourLogger.Log(MonoDetourLogger.LogChannel.Error, "MonoDetour's ILHook.Apply anti-exploder failed to be applied. Please report this issue: https://github.com/MonoDetour/MonoDetour: " + $"'{typeof(Hook).Assembly}'"); MonoDetourLogger.Log(MonoDetourLogger.LogChannel.Error, iLWeaverResult.FailureMessage); } else { w.HandlerWrapTryCatchStackSizeNonZeroOnCurrent(null, new <>z__ReadOnlyArray((Instruction[])(object)new Instruction[2] { w.Create(OpCodes.Ldarg_0), w.CreateCall(new Action(UndoFailedILHook)) })); } } private static void UndoFailedILHook(Exception ex, ILHook ilHook) { if (!ilHook.IsValid) { return; } try { ilHook.Undo(); } catch (Exception ex2) { throw new Exception("Undoing ILHook failed: " + ex2, ex); } throw new Exception("ILHook failed to apply and was disabled.", ex); } } internal static class ProxyILHookConstructor { private static readonly ILHook detourContextHook; static ProxyILHookConstructor() { //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Expected O, but got Unknown //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Expected O, but got Unknown if (!MonoModVersion.IsReorg) { detourContextHook = new ILHook((MethodBase)new Func(DetourContextGetCurrent).Method, new Manipulator(ILHook_DetourContextGetCurrent)); } } private static void ILHook_DetourContextGetCurrent(ILContext il) { //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Expected O, but got Unknown //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) MethodInfo methodInfo = typeof(DetourContext).GetProperty("Current", BindingFlags.Static | BindingFlags.NonPublic).GetGetMethod(nonPublic: true) ?? throw new NullReferenceException("Couldn't find 'DetourContext.get_Current'."); ILCursor val = new ILCursor(il); val.Body.Instructions.Clear(); val.Emit(OpCodes.Call, (MethodBase)methodInfo); val.Emit(OpCodes.Ret); } [MethodImpl(MethodImplOptions.NoInlining)] private static DetourContext DetourContextGetCurrent() { throw new NotImplementedException("DetourContextGetCurrent wasn't initialized."); } internal static ILHook ConstructILHook(MethodBase target, Manipulator manipulator, IMonoDetourConfig? config, string id) { if (MonoModVersion.IsReorg) { return ReorgILHook.ConstructILHook(target, manipulator, config, id); } return ConstructLegacyILHook(target, manipulator, config, id); } [MethodImpl(MethodImplOptions.NoInlining)] private static ILHook ConstructLegacyILHook(MethodBase target, Manipulator manipulator, IMonoDetourConfig? config, string id) { //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Expected O, but got Unknown //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Expected O, but got Unknown //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Expected O, but got Unknown //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Expected O, but got Unknown if (config == null) { DetourContext val = DetourContextGetCurrent(); if (val != null) { ILHookConfig iLHookConfig = val.ILHookConfig; if (!iLHookConfig.ManualApply) { ILHookConfig val2 = iLHookConfig; val2.ManualApply = true; ILHookConfig val3 = val2; return new ILHook(target, manipulator, val3); } return new ILHook(target, manipulator, iLHookConfig); } return new ILHook(target, manipulator, new ILHookConfig { ID = id, ManualApply = true }); } ILHookConfig val4 = new ILHookConfig { ID = (config.OverrideId ?? id), Priority = config.Priority, Before = config.Before, After = config.After, ManualApply = true }; return new ILHook(target, manipulator, val4); } } } namespace MonoDetour.Interop.MonoModUtils { internal static class InteropFastDelegateInvokers { private static MethodInfo? getDelegateInvoker; internal static (MethodInfo Invoker, Type Delegate)? GetDelegateInvoker(ILContext il, Type delegateType) { if (!MonoModVersion.IsReorg) { return LegacyGetDelegateInvoker(il, delegateType); } return ReorgFastDelegateInvokers.GetDelegateInvoker(delegateType); } [MethodImpl(MethodImplOptions.NoInlining)] private static (MethodInfo Invoker, Type Delegate)? LegacyGetDelegateInvoker(ILContext il, Type delegateType) { IILReferenceBag referenceBag = il.ReferenceBag; RuntimeILReferenceBag val = (RuntimeILReferenceBag)(object)((referenceBag is RuntimeILReferenceBag) ? referenceBag : null); if (val == null) { throw new Exception("ReferenceBag is not RuntimeILReferenceBag! If you are not in an ILHook managed by MonoMod, do not use this method."); } if ((object)getDelegateInvoker == null) { Type typeFromHandle = typeof(RuntimeILReferenceBag); MethodInfo method = typeFromHandle.GetMethod("GetDelegateInvoker"); getDelegateInvoker = method; } MethodInfo methodInfo = getDelegateInvoker.MakeGenericMethod(delegateType); MethodInfo methodInfo2 = (MethodInfo)methodInfo.Invoke(val, Array.Empty()); if ((object)methodInfo2 == null) { return null; } return (methodInfo2, delegateType); } } internal static class InteropILContext { private static MethodInfo? getGetter; internal static int InteropAddReference(this ILContext context, in T? t) { if (!MonoModVersion.IsReorg) { return LegacyAddReference(context, t); } return ReorgILContext.AddReference(context, ref t); } [MethodImpl(MethodImplOptions.NoInlining)] private static int LegacyAddReference(ILContext context, T? t) { return context.AddReference(t); } internal static IEnumerable InteropGetReference(this ILContext context, ILWeaver weaver, int id, Delegate @delegate) { if (!MonoModVersion.IsReorg) { return LegacyGetReference(@delegate.GetType(), context, weaver, id); } return ReorgILContext.GetReference(@delegate.GetType(), context, id); } [MethodImpl(MethodImplOptions.NoInlining)] private static IEnumerable LegacyGetReference(Type t, ILContext context, ILWeaver w, int id) { IILReferenceBag referenceBag = context.ReferenceBag; RuntimeILReferenceBag val = (RuntimeILReferenceBag)(object)((referenceBag is RuntimeILReferenceBag) ? referenceBag : null); if (val == null) { throw new Exception("ReferenceBag is not RuntimeILReferenceBag! If you are not in an ILHook managed by MonoMod, do not use this method."); } if ((object)getGetter == null) { Type typeFromHandle = typeof(RuntimeILReferenceBag); MethodInfo method = typeFromHandle.GetMethod("GetGetter"); getGetter = method; } MethodInfo methodInfo = getGetter.MakeGenericMethod(t); MethodInfo delegateInvoker = (MethodInfo)methodInfo.Invoke(val, Array.Empty()); yield return w.Create(OpCodes.Ldc_I4, id); yield return w.Create(OpCodes.Call, (MethodBase)delegateInvoker); } } internal static class InteropILCursor { internal static int InteropEmitReference(this ILCursor cursor, in T? t) { if (!MonoModVersion.IsReorg) { return LegacyEmitReference(cursor, t); } return ReorgILCursor.EmitReference(cursor, ref t); } [MethodImpl(MethodImplOptions.NoInlining)] private static int LegacyEmitReference(ILCursor cursor, T? t) { return cursor.EmitReference(t); } internal static int InteropEmitReferenceBefore(this ILContext context, Instruction target, in T? t) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) return new ILCursor(context).Goto(target, (MoveType)0, false).InteropEmitReference(in t); } internal static void EmitGetReferenceBefore(ILContext context, Instruction target, int id) where T : Delegate { //IL_0001: Unknown result type (might be due to invalid IL or missing references) new ILCursor(context).Goto(target, (MoveType)0, false).EmitGetReference(id); } internal static int EmitDelegateBefore(ILContext context, Instruction target, in T cb) where T : Delegate { //IL_0001: Unknown result type (might be due to invalid IL or missing references) return new ILCursor(context).Goto(target, (MoveType)0, false).EmitDelegate(cb); } } internal static class InteropILLabel { internal static Instruction? InteropGetTarget(this ILLabel label) { if (!MonoModVersion.IsReorg) { return LegacyGetTarget(label); } return ReorgILLabel.GetTarget(label); } internal static void InteropSetTarget(this ILLabel label, Instruction value) { if (MonoModVersion.IsReorg) { ReorgILLabel.SetTarget(label, value); } else { LegacySetTarget(label, value); } } [MethodImpl(MethodImplOptions.NoInlining)] private static Instruction? LegacyGetTarget(ILLabel label) { return label.Target; } [MethodImpl(MethodImplOptions.NoInlining)] private static Instruction? LegacySetTarget(ILLabel label, Instruction value) { return label.Target = value; } } } namespace MonoDetour.Interop.Cecil { internal static class ILHookInstructionILLabelCastFixes { [CompilerGenerated] private static class <>O { public static Manipulator <0>__ILHook_Instruction_ToString; public static Manipulator <1>__ILHook_Instruction_GetSize; public static Func <2>__IfILLabelThenReturnTargetInstruction; public static Func <3>__IfILLabelArrayThenReturnTargetInstruction; } private static ILHook castILLabelToInstructionToStringILHook; private static ILHook castILLabelToInstructionGetSizeILHook; private static bool initialized; internal static void InitHook() { if (initialized) { return; } initialized = true; try { InitHookToString(); InitHookGetSize(); } catch (Exception innerException) { throw new NotSupportedException("MonoDetour doesn't seem to support this Mono.Cecil version, please report this issue: https://github.com/MonoDetour/MonoDetour: " + $"'{typeof(Instruction).Assembly}'", innerException); } } private static void InitHookToString() { //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Expected O, but got Unknown //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Expected O, but got Unknown MethodInfo? method = typeof(Instruction).GetMethod("ToString", Array.Empty()); object obj = <>O.<0>__ILHook_Instruction_ToString; if (obj == null) { Manipulator val = ILHook_Instruction_ToString; <>O.<0>__ILHook_Instruction_ToString = val; obj = (object)val; } castILLabelToInstructionToStringILHook = new ILHook((MethodBase)method, (Manipulator)obj); } private static void InitHookGetSize() { //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Expected O, but got Unknown //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Expected O, but got Unknown MethodInfo? method = typeof(Instruction).GetMethod("GetSize", Array.Empty()); object obj = <>O.<1>__ILHook_Instruction_GetSize; if (obj == null) { Manipulator val = ILHook_Instruction_GetSize; <>O.<1>__ILHook_Instruction_GetSize = val; obj = (object)val; } castILLabelToInstructionGetSizeILHook = new ILHook((MethodBase)method, (Manipulator)obj); } private static void ILHook_Instruction_ToString(ILContext il) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Expected O, but got Unknown ILCursor val = new ILCursor(il); if (!val.TryGotoNext(new Func[1] { (Instruction x) => ILPatternMatchingExt.MatchCastclass(x) })) { MonoDetourLogger.Log(MonoDetourLogger.LogChannel.Error, "ILHook_Instruction_ToString] Could not find 'castclass Mono.Cecil.Cil.Instruction'!"); return; } val.EmitDelegate>((Func)IfILLabelThenReturnTargetInstruction); if (!val.TryGotoNext(new Func[1] { (Instruction x) => ILPatternMatchingExt.MatchCastclass(x) })) { MonoDetourLogger.Log(MonoDetourLogger.LogChannel.Error, "ILHook_Instruction_ToString] Could not find 'castclass class Mono.Cecil.Cil.Instruction[]'!"); } else { val.EmitDelegate>((Func)IfILLabelArrayThenReturnTargetInstruction); } } private static void ILHook_Instruction_GetSize(ILContext il) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Expected O, but got Unknown ILCursor val = new ILCursor(il); if (!val.TryGotoNext(new Func[1] { (Instruction x) => ILPatternMatchingExt.MatchCastclass(x) })) { MonoDetourLogger.Log(MonoDetourLogger.LogChannel.Error, "[ILHook_Instruction_GetSize] Could not find 'castclass class Mono.Cecil.Cil.Instruction[]'!"); } else { val.EmitDelegate>((Func)IfILLabelArrayThenReturnTargetInstruction); } } private static object? IfILLabelThenReturnTargetInstruction(object operand) { ILLabel val = (ILLabel)((operand is ILLabel) ? operand : null); if (val != null) { return val.InteropGetTarget() ?? throw new NullReferenceException("ILLabel.Target must not not be null!"); } return operand; } private static object IfILLabelArrayThenReturnTargetInstruction(object operand) { if (operand is ILLabel[] source) { return source.Select((ILLabel l) => l.InteropGetTarget()).ToArray(); } return operand; } } } namespace MonoDetour.DetourTypes { public class ILHookDetour : IMonoDetourHookApplier { private IReadOnlyMonoDetourHook _hook; private ILManipulationInfo.Manipulator invoker; public IReadOnlyMonoDetourHook Hook { get { return _hook; } set { _hook = value; invoker = ((ILManipulationInfo.Manipulator)_hook.ManipulatorDelegate) ?? ((ILManipulationInfo.Manipulator)Delegate.CreateDelegate(typeof(ILManipulationInfo.Manipulator), (Hook.Manipulator as MethodInfo) ?? throw new InvalidCastException("Hook Manipulator method is not MethodInfo!"))); } } public void ApplierManipulator(ILContext il) { Action invokeOnManipulatorFinished; ILManipulationInfo info = new ILManipulationInfo(il, Hook, out invokeOnManipulatorFinished); invoker(info); invokeOnManipulatorFinished(); Hook.Owner.Log(MonoDetourLogger.LogChannel.IL, delegate { IInformationalMethodBody arg = il.Body.CreateInformationalSnapshotJIT().AnnotateErrors(); return $"Manipulated by ILHook: {Hook.Manipulator.Name} ({Hook.Owner.Id}):\n{arg}"; }); } } public interface IMonoDetourHookApplier { IReadOnlyMonoDetourHook Hook { get; set; } void ApplierManipulator(ILContext il); } public class PostfixDetour : IMonoDetourHookApplier { private IReadOnlyMonoDetourHook hook; private static readonly List postfixDelegates = new List(); private static readonly List postfixHooks = new List(); private int delegateId = -1; private int hookId = -1; public IReadOnlyMonoDetourHook Hook { get { return hook; } set { hook = value; hookId = postfixHooks.Count; postfixHooks.Add(hook); Delegate manipulatorDelegate = value.ManipulatorDelegate; if ((object)manipulatorDelegate != null) { delegateId = postfixDelegates.Count; postfixDelegates.Add(manipulatorDelegate); } } } private static Delegate GetDelegate(int id) { return postfixDelegates[id]; } private static IReadOnlyMonoDetourHook GetHook(int id) { return postfixHooks[id]; } public void ApplierManipulator(ILContext il) { //IL_00dc: Unknown result type (might be due to invalid IL or missing references) //IL_01e5: Unknown result type (might be due to invalid IL or missing references) //IL_02a9: Unknown result type (might be due to invalid IL or missing references) //IL_0280: Unknown result type (might be due to invalid IL or missing references) //IL_02eb: Unknown result type (might be due to invalid IL or missing references) //IL_02f0: Unknown result type (might be due to invalid IL or missing references) if (Hook.ModifiesControlFlow()) { throw new NotSupportedException("A PostfixDetour may not modify control flow."); } HookTargetRecords.HookTargetInfo hookTargetInfo = HookTargetRecords.GetHookTargetInfo(il); Action invokeOnManipulatorFinished; ILWeaver w = new ILWeaver(new ILManipulationInfo(il, Hook, out invokeOnManipulatorFinished)); w.CurrentTo(w.Last); List firstPostfixInstructions = hookTargetInfo.PostfixInfo.FirstPostfixInstructions; ILLabel label = RedirectEarlyReturnsToLabel(w, hookTargetInfo); IEnumerable incomingLabelsFor = w.GetIncomingLabelsFor(label.InteropGetTarget()); w.MarkLabelToFutureNextInsert(label); w.HandlerCreateCatch(null, out WeaverExceptionCatchHandler handler); w.DefineLabel(out ILLabel label2); w.HandlerSetTryStart(label2, handler); Instruction callMaybeInsertGetDelegate; if (hookTargetInfo.ReturnValue != null) { w.InsertBeforeCurrent(new <>z__ReadOnlySingleElementList(w.Create(OpCodes.Stloc, hookTargetInfo.ReturnValue))); w.MarkLabelToFutureNextInsert(label2); callMaybeInsertGetDelegate = Utils.GetCallMaybeInsertGetDelegate(w, Hook, delegateId, GetDelegate); w.EmitParamsAndReturnValueBeforeCurrent(hookTargetInfo.ReturnValue, Hook); } else { w.MarkLabelToFutureNextInsert(label2); callMaybeInsertGetDelegate = Utils.GetCallMaybeInsertGetDelegate(w, Hook, delegateId, GetDelegate); w.EmitParamsBeforeCurrent(Hook); } w.InsertBeforeCurrent(new <>z__ReadOnlySingleElementList(callMaybeInsertGetDelegate)); w.HandlerSetTryEnd(w.Previous, handler); w.InsertBeforeCurrent(new <>z__ReadOnlyArray((Instruction[])(object)new Instruction[3] { w.Create(OpCodes.Ldc_I4, hookId), w.CreateCall(new Func(GetHook)), w.CreateCall(new Action(Utils.DisposeBadHooks)) })); w.HandlerSetHandlerEnd(w.Previous, handler); if (hookTargetInfo.ReturnValue != null) { w.InsertBeforeCurrent(new <>z__ReadOnlySingleElementList(w.Create(OpCodes.Ldloc, hookTargetInfo.ReturnValue))); } else { w.InsertBeforeCurrent(new <>z__ReadOnlySingleElementList(w.Create(OpCodes.Nop))); } w.RetargetLabels(incomingLabelsFor, label.InteropGetTarget()); firstPostfixInstructions.Add(label.InteropGetTarget()); Enumerator enumerator = il.Body.ExceptionHandlers.GetEnumerator(); try { while (enumerator.MoveNext()) { ExceptionHandler current = enumerator.Current; if (current.HandlerEnd == w.Last) { current.HandlerEnd = label.InteropGetTarget(); } } } finally { ((IDisposable)enumerator/*cast due to .constrained prefix*/).Dispose(); } invokeOnManipulatorFinished(); Hook.Owner.Log(MonoDetourLogger.LogChannel.IL, delegate { IInformationalMethodBody arg = w.Body.CreateInformationalSnapshotJIT().AnnotateErrors(); return $"Manipulated by Postfix: {Hook.Manipulator.Name} ({Hook.Owner.Id}):\n{arg}"; }); } private static ILLabel RedirectEarlyReturnsToLabel(ILWeaver w, HookTargetRecords.HookTargetInfo info) { //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_02f8: Unknown result type (might be due to invalid IL or missing references) //IL_02f1: Unknown result type (might be due to invalid IL or missing references) //IL_0200: Unknown result type (might be due to invalid IL or missing references) //IL_0205: Unknown result type (might be due to invalid IL or missing references) //IL_022b: Unknown result type (might be due to invalid IL or missing references) //IL_0237: Unknown result type (might be due to invalid IL or missing references) //IL_023c: Unknown result type (might be due to invalid IL or missing references) //IL_024c: Unknown result type (might be due to invalid IL or missing references) //IL_0251: Unknown result type (might be due to invalid IL or missing references) //IL_0288: Unknown result type (might be due to invalid IL or missing references) //IL_02bf: Unknown result type (might be due to invalid IL or missing references) //IL_0142: Unknown result type (might be due to invalid IL or missing references) //IL_0147: Unknown result type (might be due to invalid IL or missing references) //IL_017d: Unknown result type (might be due to invalid IL or missing references) //IL_0189: Unknown result type (might be due to invalid IL or missing references) //IL_018e: Unknown result type (might be due to invalid IL or missing references) //IL_019e: Unknown result type (might be due to invalid IL or missing references) //IL_01a3: Unknown result type (might be due to invalid IL or missing references) List firstPostfixInstructions = info.PostfixInfo.FirstPostfixInstructions; VariableDefinition? returnValue = info.ReturnValue; int? num = ((returnValue != null) ? new int?(((VariableReference)returnValue).Index) : ((int?)null)); if (w.Body.Instructions.Count == 0) { w.Body.Instructions.Add(w.Create(OpCodes.Nop)); } Collection instructions = w.Body.Instructions; Instruction last = w.Last; w.DefineAndMarkLabelTo(last, out ILLabel markedLabel); bool flag = false; foreach (Instruction item in ((IEnumerable)w.Body.Instructions).Where((Instruction ins) => ILPatternMatchingExt.MatchRet(ins))) { flag = true; Instruction next = item.Next; if (next == null) { continue; } if (num.HasValue) { int valueOrDefault = num.GetValueOrDefault(); Instruction next2 = next.Next; if (((next2 != null) ? next2.Next : null) != null) { Instruction previous = item.Previous; if (((previous != null) ? new bool?(ILPatternMatchingExt.MatchLdloc(previous, valueOrDefault)) : ((bool?)null)) ?? false) { if (next.Next.OpCode == OpCodes.Ret && ILPatternMatchingExt.MatchLdloc(next, valueOrDefault)) { continue; } Instruction previous2 = item.Previous.Previous; OpCode? val = ((previous2 != null) ? new OpCode?(previous2.OpCode) : ((OpCode?)null)); OpCode ret = OpCodes.Ret; if (val.HasValue && val.GetValueOrDefault() == ret) { Instruction previous3 = item.Previous.Previous.Previous; if (((previous3 != null) ? new bool?(ILPatternMatchingExt.MatchLdloc(previous3, valueOrDefault)) : ((bool?)null)) ?? false) { continue; } } } } } else if (next.Next != null) { if (next.OpCode == OpCodes.Ret) { continue; } Instruction previous4 = item.Previous; OpCode? val = ((previous4 != null) ? new OpCode?(previous4.OpCode) : ((OpCode?)null)); OpCode ret = OpCodes.Ret; if (val.HasValue && val.GetValueOrDefault() == ret) { continue; } } bool flag2 = false; foreach (Instruction item2 in firstPostfixInstructions) { if (item2 != null && instructions.IndexOf(item) < instructions.IndexOf(item2)) { item.OpCode = OpCodes.Br; item.Operand = item2; flag2 = true; break; } } if (!flag2) { item.OpCode = OpCodes.Br; item.Operand = markedLabel; } } last.OpCode = (flag ? OpCodes.Ret : OpCodes.Nop); last.Operand = null; return markedLabel; } } public class PrefixDetour : IMonoDetourHookApplier { private IReadOnlyMonoDetourHook hook; private static readonly List prefixDelegates = new List(); private static readonly List prefixHooks = new List(); private int delegateId = -1; private int hookId = -1; public IReadOnlyMonoDetourHook Hook { get { return hook; } set { hook = value; hookId = prefixHooks.Count; prefixHooks.Add(hook); Delegate manipulatorDelegate = value.ManipulatorDelegate; if ((object)manipulatorDelegate != null) { delegateId = prefixDelegates.Count; prefixDelegates.Add(manipulatorDelegate); } } } private static Delegate GetDelegate(int id) { return prefixDelegates[id]; } private static IReadOnlyMonoDetourHook GetHook(int id) { return prefixHooks[id]; } public void ApplierManipulator(ILContext il) { //IL_0151: Unknown result type (might be due to invalid IL or missing references) //IL_0104: Unknown result type (might be due to invalid IL or missing references) //IL_01ee: Unknown result type (might be due to invalid IL or missing references) //IL_0213: Unknown result type (might be due to invalid IL or missing references) //IL_036a: Unknown result type (might be due to invalid IL or missing references) //IL_0388: Unknown result type (might be due to invalid IL or missing references) //IL_03b4: Unknown result type (might be due to invalid IL or missing references) //IL_02cf: Unknown result type (might be due to invalid IL or missing references) //IL_02e2: Unknown result type (might be due to invalid IL or missing references) //IL_03ed: Unknown result type (might be due to invalid IL or missing references) //IL_0288: Unknown result type (might be due to invalid IL or missing references) //IL_0260: Unknown result type (might be due to invalid IL or missing references) //IL_044c: Unknown result type (might be due to invalid IL or missing references) //IL_0506: Unknown result type (might be due to invalid IL or missing references) HookTargetRecords.HookTargetInfo hookTargetInfo = HookTargetRecords.GetHookTargetInfo(il); Action invokeOnManipulatorFinished; ILWeaver w = new ILWeaver(new ILManipulationInfo(il, Hook, out invokeOnManipulatorFinished)); bool flag = Hook.ModifiesControlFlow() && hookTargetInfo.ReturnValue != null; w.HandlerCreateCatch(null, out WeaverExceptionCatchHandler handler); w.DefineAndMarkLabelToFutureNextInsert(out ILLabel futureMarkedLabel); w.HandlerSetTryStart(futureMarkedLabel, handler); Instruction callMaybeInsertGetDelegate = Utils.GetCallMaybeInsertGetDelegate(w, Hook, delegateId, GetDelegate); if (flag) { w.EmitParamsAndReturnValueBeforeCurrent(hookTargetInfo.ReturnValue, Hook); } else { w.EmitParamsBeforeCurrent(Hook); } w.InsertBeforeCurrent(new <>z__ReadOnlySingleElementList(callMaybeInsertGetDelegate)); if (Hook.ModifiesControlFlow()) { w.InsertBeforeCurrent(new <>z__ReadOnlySingleElementList(w.Create(OpCodes.Stloc, hookTargetInfo.PrefixInfo.TemporaryControlFlow))); } w.HandlerSetTryEnd(w.Previous, handler); w.InsertBeforeCurrent(new <>z__ReadOnlyArray((Instruction[])(object)new Instruction[3] { w.Create(OpCodes.Ldc_I4, hookId), w.CreateCall(new Func(GetHook)), w.CreateCall(new Action(Utils.DisposeBadHooks)) })); w.HandlerSetHandlerEnd(w.Previous, handler); if (Hook.ModifiesControlFlow()) { Instruction val = w.Create(OpCodes.Switch, new object()); w.InsertBeforeCurrent(new <>z__ReadOnlyArray((Instruction[])(object)new Instruction[2] { w.Create(OpCodes.Ldloc, hookTargetInfo.PrefixInfo.TemporaryControlFlow), val })); w.DefineAndMarkLabelToFutureNextInsert(out ILLabel futureMarkedLabel2); for (int i = 0; i < 2; i++) { if (hookTargetInfo.ReturnValue != null) { w.InsertBeforeCurrent(new <>z__ReadOnlySingleElementList(w.Create(OpCodes.Ldloc, hookTargetInfo.ReturnValue))); } w.InsertBeforeCurrent(new <>z__ReadOnlySingleElementList(hookTargetInfo.MarkPersistentInstruction(w.Create(OpCodes.Ret)))); } w.DefineAndMarkLabelToFutureNextInsert(out ILLabel futureMarkedLabel3); w.InsertBeforeCurrent(new <>z__ReadOnlyArray((Instruction[])(object)new Instruction[2] { w.Create(OpCodes.Ldc_I4_1), w.Create(OpCodes.Stloc, hookTargetInfo.PrefixInfo.ControlFlow) })); w.DefineAndMarkLabelToCurrentOrFutureNextInsert(out ILLabel futureMarkedLabel4); val.Operand = new ILLabel[3] { futureMarkedLabel4, futureMarkedLabel3, futureMarkedLabel2 }; } if (!hookTargetInfo.PrefixInfo.ControlFlowImplemented) { hookTargetInfo.PrefixInfo.SetControlFlowImplemented(); w.DefineAndMarkLabelToCurrent(out ILLabel markedLabel); w.InsertBeforeCurrent(new <>z__ReadOnlyArray((Instruction[])(object)new Instruction[2] { w.Create(OpCodes.Ldloc, hookTargetInfo.PrefixInfo.ControlFlow), w.Create(OpCodes.Brfalse, (object)markedLabel) })); if (hookTargetInfo.ReturnValue != null) { w.InsertBeforeCurrent(new <>z__ReadOnlySingleElementList(w.Create(OpCodes.Ldloc, hookTargetInfo.ReturnValue))); } if (hookTargetInfo.PostfixInfo.FirstPostfixInstructions.FirstOrDefault() == null) { w.InsertBeforeCurrent(new <>z__ReadOnlySingleElementList(w.Create(OpCodes.Ret))); } else { bool flag2 = false; foreach (Instruction firstPostfixInstruction in hookTargetInfo.PostfixInfo.FirstPostfixInstructions) { if (w.Body.Instructions.Contains(firstPostfixInstruction)) { w.InsertBeforeCurrent(new <>z__ReadOnlySingleElementList(w.Create(OpCodes.Br, firstPostfixInstruction))); flag2 = true; break; } } if (!flag2) { Hook.Owner.Log(MonoDetourLogger.LogChannel.Warning, "While applying Prefix: " + Hook.Manipulator.Name + " (" + Hook.Owner.Id + "): No postfix labels found despite postfixes being applied on the method. " + $"Postfixes might not run on method '{Hook.Target}'. "); w.InsertBeforeCurrent(new <>z__ReadOnlySingleElementList(w.Create(OpCodes.Ret))); } } } invokeOnManipulatorFinished(); if (Hook.ModifiesControlFlow()) { hookTargetInfo.PrefixInfo.MarkControlFlowPrefixAsApplied(); } Hook.Owner.Log(MonoDetourLogger.LogChannel.IL, delegate { IInformationalMethodBody arg = w.Body.CreateInformationalSnapshotJIT().AnnotateErrors(); return $"Manipulated by Prefix: {Hook.Manipulator.Name} ({Hook.Owner.Id}):\n{arg}"; }); } } public enum ReturnFlow { None, SkipOriginal, HardReturn } } namespace MonoDetour.DetourTypes.Manipulation { public static class HookTargetRecords { public class HookTargetInfo { [CompilerGenerated] private ReadOnlyCollection k__BackingField; private bool isOriginalInstructionsHashSetDirty; [CompilerGenerated] private HashSet k__BackingField; public TargetPrefixInfo PrefixInfo { get; } public TargetPostfixInfo PostfixInfo { get; } = new TargetPostfixInfo(); public VariableDefinition? ReturnValue { get; } public ReadOnlyCollection OriginalInstructions { [CompilerGenerated] get { return k__BackingField; } internal set { k__BackingField = value; isOriginalInstructionsHashSetDirty = true; } } internal HashSet OriginalInstructionsHashSet { get { if (!isOriginalInstructionsHashSetDirty) { HashSet hashSet = k__BackingField; HashSet hashSet2 = hashSet; if (hashSet2 == null) { HashSet hashSet3 = new HashSet(); foreach (Instruction originalInstruction in OriginalInstructions) { hashSet3.Add(originalInstruction); } hashSet2 = (k__BackingField = hashSet3); } return hashSet2; } HashSet hashSet4 = new HashSet(); foreach (Instruction originalInstruction2 in OriginalInstructions) { hashSet4.Add(originalInstruction2); } return k__BackingField = hashSet4; } } internal HashSet PersistentInstructions { get; } = new HashSet(); internal Dictionary InstructionToSource { get; } = new Dictionary(); internal HookTargetInfo(MethodDefinition method, VariableDefinition? returnValue, ReadOnlyCollection originalInstructions) { PrefixInfo = new TargetPrefixInfo(method); ReturnValue = returnValue; OriginalInstructions = originalInstructions; } internal Instruction MarkPersistentInstruction(Instruction instruction) { PersistentInstructions.Add(instruction); return instruction; } internal bool IsPersistentInstruction(Instruction instruction) { return PersistentInstructions.Contains(instruction); } } public class TargetPrefixInfo { public VariableDefinition ControlFlow { get; } public VariableDefinition TemporaryControlFlow { get; } public bool ControlFlowImplemented { get; private set; } internal int AppliedControlFlowPrefixes { get; private set; } internal TargetPrefixInfo(MethodDefinition method) { ControlFlow = method.DeclareVariable(typeof(int)); TemporaryControlFlow = method.DeclareVariable(typeof(int)); } public void SetControlFlowImplemented() { ControlFlowImplemented = true; } internal void MarkControlFlowPrefixAsApplied() { AppliedControlFlowPrefixes++; } } public class TargetPostfixInfo { public List FirstPostfixInstructions { get; } = new List(); internal TargetPostfixInfo() { } } private static readonly ConditionalWeakTable s_MethodToInfo = new ConditionalWeakTable(); internal static ReadOnlyCollection GetOriginalInstructions(MethodDefinition method) { ConditionalWeakTable> s_MethodDefinitionToOriginalInstructions = ILHookDMDManipulation.s_MethodDefinitionToOriginalInstructions; if (s_MethodDefinitionToOriginalInstructions.TryGetValue(method, out var value)) { return value; } return new ReadOnlyCollection(new List()); } internal static void SwapOriginalInstructionsCollection(MethodDefinition method, HookTargetInfo info, ReadOnlyCollection replacement) { ILHookDMDManipulation.s_MethodDefinitionToOriginalInstructions.Remove(method); ILHookDMDManipulation.s_MethodDefinitionToOriginalInstructions.Add(method, replacement); info.OriginalInstructions = replacement; } public static HookTargetInfo GetHookTargetInfo(ILContext il) { return GetHookTargetInfo(il.Method); } public static HookTargetInfo GetHookTargetInfo(MethodDefinition method) { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Invalid comparison between Unknown and I4 //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Expected O, but got Unknown if (s_MethodToInfo.TryGetValue(method, out HookTargetInfo value)) { return value; } VariableDefinition val = null; if ((int)((MethodReference)method).ReturnType.MetadataType != 1) { val = new VariableDefinition(((MethodReference)method).ReturnType); method.Body.Variables.Add(val); } value = new HookTargetInfo(method, val, GetOriginalInstructions(method)); s_MethodToInfo.Add(method, value); return value; } private static VariableDefinition DeclareVariable(this MethodDefinition method, Type type) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Expected O, but got Unknown VariableDefinition val = new VariableDefinition(((MemberReference)method).Module.ImportReference(type)); method.Body.Variables.Add(val); return val; } } internal static class Utils { private static void WriteSpeakableEnumerator(ILWeaver w, Type speakableEnumeratorType, Type enumeratorType) { //IL_002c: Unknown result type (might be due to invalid IL or missing references) MethodInfo method = speakableEnumeratorType.GetMethod("PreBuildFieldReferenceGetters"); method.Invoke(null, new object[1] { enumeratorType }); MethodInfo method2 = speakableEnumeratorType.GetMethod("GetOrCreate"); w.InsertBeforeCurrent(new <>z__ReadOnlySingleElementList(w.Create(OpCodes.Call, (MethodBase)method2))); } public static bool ModifiesControlFlow(this IReadOnlyMonoDetourHook hook) { if (hook.Manipulator is MethodInfo methodInfo) { return methodInfo.ReturnType == typeof(ReturnFlow); } return false; } public static void EmitParamsAndReturnValueBeforeCurrent(this ILWeaver w, VariableDefinition returnValue, IReadOnlyMonoDetourHook hook) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) Helpers.ThrowIfNull(returnValue, "returnValue"); w.EmitParamsBeforeCurrent(hook); w.InsertBeforeCurrent(new <>z__ReadOnlySingleElementList(w.Create(OpCodes.Ldloca, returnValue))); } public static void EmitParamsBeforeCurrent(this ILWeaver w, IReadOnlyMonoDetourHook hook) { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_00fc: Unknown result type (might be due to invalid IL or missing references) //IL_00dd: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) bool isStatic = hook.Target.IsStatic; Enumerator enumerator = ((MethodReference)w.Method).Parameters.GetEnumerator(); try { while (enumerator.MoveNext()) { ParameterDefinition current = enumerator.Current; if (!isStatic && ((ParameterReference)current).Index == 0) { Type parameterType = hook.Manipulator.GetParameters().First().ParameterType; if (typeof(ISpeakableEnumerator).IsAssignableFrom(parameterType)) { Type enumeratorType = hook.Target.DeclaringType ?? throw new NullReferenceException("Declaring type of target method is null!"); w.InsertBeforeCurrent(new <>z__ReadOnlySingleElementList(w.Create(OpCodes.Ldarg, ((ParameterReference)current).Index))); WriteSpeakableEnumerator(w, parameterType, enumeratorType); } else { w.InsertBeforeCurrent(new <>z__ReadOnlySingleElementList(w.Create(OpCodes.Ldarg, ((ParameterReference)current).Index))); } } else if (((ParameterReference)current).ParameterType.IsByReference) { w.InsertBeforeCurrent(new <>z__ReadOnlySingleElementList(w.Create(OpCodes.Ldarg, ((ParameterReference)current).Index))); } else { w.InsertBeforeCurrent(new <>z__ReadOnlySingleElementList(w.Create(OpCodes.Ldarga, ((ParameterReference)current).Index))); } } } finally { ((IDisposable)enumerator/*cast due to .constrained prefix*/).Dispose(); } } internal static void DisposeBadHooks(Exception ex, IReadOnlyMonoDetourHook hook) { MethodBase manipulator = hook.Manipulator; MethodBase target = hook.Target; string text = target.DeclaringType?.FullName; int hooksCount = hook.Owner.Hooks.Count; hook.Owner.Log(MonoDetourLogger.LogChannel.Error, () => "Exception caught in a hook belonging to MonoDetourManager '" + hook.Owner.Id + "'" + $" (disposing all {hooksCount} of its hooks in an attempt to minimize potential damage):\n" + ex); try { if (!hook.Owner.CallOnHookThrew(hook)) { hook.Owner.Log(MonoDetourLogger.LogChannel.Warning, () => "No disposal event handler for the MonoDetourManager was registered. You can subscribe to the MonoDetourManager.OnHookThrew event to clean up the rest of your resources."); } } catch (Exception ex2) { Exception ex3 = ex2; Exception disposalEx = ex3; hook.Owner.Log(MonoDetourLogger.LogChannel.Error, () => $"Disposal event handler threw an exception:\n{disposalEx}"); } finally { hook.Owner.DisposeHooks(); } } internal static void ThrowIfHookManipulatorDelegateIsNull(IReadOnlyMonoDetourHook hook, out Delegate manipulatorDelegate) { Delegate manipulatorDelegate2 = hook.ManipulatorDelegate; if ((object)manipulatorDelegate2 != null) { manipulatorDelegate = manipulatorDelegate2; return; } throw new NullReferenceException("IReadOnlyMonoDetourHook.Manipulator is not static, and IReadOnlyMonoDetourHook.ManipulatorDelegate is null. Please use a constructor which takes a Delegate instead of a MethodBase for Manipulator."); } internal static Instruction GetCallMaybeInsertGetDelegate(ILWeaver w, IReadOnlyMonoDetourHook hook, int id, Func getDelegate) { //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) if (hook.Manipulator.IsStatic) { return w.Create(OpCodes.Call, hook.Manipulator); } ThrowIfHookManipulatorDelegateIsNull(hook, out Delegate manipulatorDelegate); w.InsertBeforeCurrent(new <>z__ReadOnlyArray((Instruction[])(object)new Instruction[2] { w.Create(OpCodes.Ldc_I4, id), w.CreateCall(getDelegate) })); MethodInfo method = manipulatorDelegate.GetType().GetMethod("Invoke"); return w.Create(OpCodes.Callvirt, (MethodBase)method); } [Conditional("DEBUG")] internal static void DebugValidateCILValidatorNoErrors(IReadOnlyMonoDetourHook hook, MethodBody body) { IInformationalMethodBody informationalMethodBody = body.CreateInformationalSnapshotJIT().AnnotateErrors(); if (informationalMethodBody.HasErrors()) { hook.Owner.Log(MonoDetourLogger.LogChannel.Error, "Hook CIL validation failed! " + hook.Manipulator.Name + "\n" + informationalMethodBody.ToErrorMessageString()); } } } } namespace MonoDetour.Cil { public static class ILContextExtensions { public static string ToAnalyzedString(this ILContext context) { return context.Body.CreateInformationalSnapshotJIT().AnnotateErrors().ToString(); } } public class ILManipulationInfo { public delegate void Manipulator(ILManipulationInfo info); private ILContext? _unmanipulated; public MethodBase? Original { get; } public ILContext Context { get; } public ReadOnlyCollection OriginalInstructions { get; } public ILContext UnmanipulatedContext { get { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Expected O, but got Unknown //IL_0027: Expected O, but got Unknown ILContext obj = _unmanipulated; if (obj == null) { ILContext val = new ILContext(new DynamicMethodDefinition(Original).Definition); ILContext val2 = val; _unmanipulated = val; obj = val2; } return obj; } } internal IReadOnlyMonoDetourHook? Hook { get; } public event Action? OnManipulatorFinished; public ILManipulationInfo(ILContext il, IReadOnlyMonoDetourHook hook, out Action invokeOnManipulatorFinished) : this(il, hook.Target, out invokeOnManipulatorFinished) { Hook = Helpers.ThrowIfNull(hook, "hook"); } public ILManipulationInfo(ILContext il, MethodBase? original, out Action invokeOnManipulatorFinished) { Original = original; Context = il; OriginalInstructions = HookTargetRecords.GetOriginalInstructions(il.Method); invokeOnManipulatorFinished = delegate { this.OnManipulatorFinished?.Invoke(); }; } [Obsolete("Use ILManipulationInfo(ILContext il, MethodBase? original) instead.", true)] public ILManipulationInfo(ILContext il, MethodBase? original, ReadOnlyCollection? originalInstructions) { Original = original; Context = il; OriginalInstructions = originalInstructions ?? HookTargetRecords.GetOriginalInstructions(il.Method); } public override string ToString() { return Context.ToAnalyzedString(); } } public class ILWeaver : IMonoDetourLogSource { private enum InsertType { BeforeAndStealLabels, Before, After } private enum MatchPassType { StrictNoOriginalPass, RelaxedAllowOriginalPass, IsOriginalPass } private const string obsoleteMessageRemoveAt = "Removing a range by count is prone to causing invalid IL if the target method's instructions have changed. Use ILWeaver.InsertBranchOver instead as it doesn't have this design flaw. Note that these two methods behave slightly differently; please read the method's remarks in detail."; private Instruction current; private Instruction? temporaryInstruction; private readonly List pendingFutureNextInsertLabels = new List(); private readonly List pendingHandlers = new List(); private readonly HookTargetRecords.HookTargetInfo targetInfo; private const string gotoMatchingDocsLink = ""; public ILManipulationInfo ManipulationInfo { get; } public ILContext Context { get; } public ILProcessor IL => Context.IL; public MethodBody Body => Context.Body; public MethodDefinition Method => Context.Method; public Collection Instructions => Context.Instrs; public Instruction Current { get { return current; } set { CurrentTo(value); } } public Instruction Previous => Current.Previous; public Instruction Next => Current.Next; public Instruction First => Instructions[0]; public Instruction Last { get { Collection instructions = Instructions; return instructions[instructions.Count - 1]; } } public int Index { get { return Instructions.IndexOf(Current); } [Obsolete("Offsetting the index is error-prone; see https://github.com/MonoDetour/MonoDetour/issues/10\nIf you know what you are doing, use ILWeaver.CurrentTo(int) directly.", true)] set { CurrentTo(value); } } public MonoDetourLogger.LogChannel LogFilter { get; set; } = MonoDetourLogger.LogChannel.Warning | MonoDetourLogger.LogChannel.Error; public ILWeaver(ILManipulationInfo il) { ManipulationInfo = Helpers.ThrowIfNull(il, "il"); Context = il.Context; targetInfo = HookTargetRecords.GetHookTargetInfo(il.Context); Instruction val = ((IEnumerable)Instructions).FirstOrDefault(); if (val != null) { current = val; } else { InsertTemporaryCurrentTarget(); } il.OnManipulatorFinished += delegate { if (temporaryInstruction != null) { int num = Instructions.IndexOf(temporaryInstruction); if (num != -1) { RemoveAndShiftLabelsInternal(num, 1, insertTemporaryIfNeeded: false); } } IWeaverExceptionHandler[] array = pendingHandlers.ToArray(); foreach (IWeaverExceptionHandler handler in array) { HandlerApply(handler); } }; } public ILWeaver(ILWeaver weaver, bool copyState = true) : this(weaver.ManipulationInfo) { if (copyState) { Current = weaver.Current; } } [MemberNotNull("current")] private void InsertTemporaryCurrentTarget() { //IL_000a: Unknown result type (might be due to invalid IL or missing references) if (temporaryInstruction == null) { temporaryInstruction = Create(OpCodes.Nop, (object)"ILWeaver temporary instruction."); } Instructions.Add(temporaryInstruction); CurrentTo(temporaryInstruction); } public ILWeaver New() { return new ILWeaver(this, copyState: false); } public ILWeaver Clone() { return new ILWeaver(this); } public VariableDefinition DeclareVariable(Type type) { DeclareVariable(type, out VariableDefinition variableDefinition); return variableDefinition; } public ILWeaver DeclareVariable(Type type, out VariableDefinition variableDefinition) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Expected O, but got Unknown variableDefinition = new VariableDefinition(Context.Import(type)); Body.Variables.Add(variableDefinition); return this; } public ILWeaver HandlerCreateCatch(Type? catchType, out WeaverExceptionCatchHandler handler) { handler = new WeaverExceptionCatchHandler(Extensions.Import(IL, catchType ?? typeof(Exception))); pendingHandlers.Add(handler); return this; } public ILWeaver HandlerCreateFilter(Type? catchType, out WeaverExceptionFilterHandler handler) { handler = new WeaverExceptionFilterHandler(Extensions.Import(IL, catchType ?? typeof(Exception))); pendingHandlers.Add(handler); return this; } public ILWeaver HandlerCreateFinally(out WeaverExceptionFinallyHandler handler) { handler = new WeaverExceptionFinallyHandler(); pendingHandlers.Add(handler); return this; } public ILWeaver HandlerCreateFault(out WeaverExceptionFaultHandler handler) { handler = new WeaverExceptionFaultHandler(); pendingHandlers.Add(handler); return this; } public ILWeaver HandlerSetTryStart(ILLabel tryStart, IWeaverExceptionHandler handler) { handler.TryStart = tryStart; return this; } public ILWeaver HandlerSetTryStart(Instruction tryStart, IWeaverExceptionHandler handler) { handler.TryStart = Context.DefineLabel(tryStart); return this; } public ILWeaver HandlerSetTryEnd(ILLabel tryEnd, IWeaverExceptionHandler handler) { handler.TryEnd = tryEnd; return this; } public ILWeaver HandlerSetTryEnd(Instruction tryEnd, IWeaverExceptionHandler handler) { handler.TryEnd = Context.DefineLabel(tryEnd); return this; } public ILWeaver HandlerSetFilterStart(ILLabel filterStart, WeaverExceptionFilterHandler handler) { handler.FilterStart = filterStart; return this; } public ILWeaver HandlerSetFilterStart(Instruction filterStart, WeaverExceptionFilterHandler handler) { handler.FilterStart = Context.DefineLabel(filterStart); return this; } public ILWeaver HandlerSetHandlerStart(ILLabel handlerStart, IWeaverExceptionHandler handler) { handler.HandlerStart = handlerStart; return this; } public ILWeaver HandlerSetHandlerStart(Instruction handlerStart, IWeaverExceptionHandler handler) { handler.HandlerStart = Context.DefineLabel(handlerStart); return this; } public ILWeaver HandlerSetHandlerEnd(ILLabel handlerEnd, IWeaverExceptionHandler handler) { handler.HandlerEnd = handlerEnd; return this; } public ILWeaver HandlerSetHandlerEnd(Instruction handlerEnd, IWeaverExceptionHandler handler) { handler.HandlerEnd = Context.DefineLabel(handlerEnd); return this; } public ILWeaver HandlerWrapTryCatchStackSizeNonZeroOnCurrent(Type? catchType, [ParamCollection] IEnumerable catchInstructions) { return HandlerWrapTryCatchStackSizeNonZeroOnCurrent(catchType, delegate { InsertAfterCurrent(catchInstructions); }); } public ILWeaver HandlerWrapTryCatchStackSizeNonZeroOnCurrent(Type? catchType, [ParamCollection] IEnumerable catchInstructions) { return HandlerWrapTryCatchStackSizeNonZeroOnCurrent(catchType, catchInstructions.Unwrap()); } public ILWeaver HandlerWrapTryCatchStackSizeNonZeroOnCurrent(Type? catchType, Action writeCatch) { Instruction afterCatch; return HandlerWrapTryCatchStackSizeNonZero(catchType, Current, out afterCatch, delegate(Instruction tryEnd) { CurrentTo(tryEnd); writeCatch(); return Current; }).CurrentTo(afterCatch); } public ILWeaver HandlerWrapTryCatchStackSizeNonZero(Type? catchType, Instruction origin, out Instruction afterCatch, [ParamCollection] IEnumerable catchInstructions) { Instruction[] instructions = catchInstructions.Where((Instruction x) => x != null).ToArray(); HandlerWrapTryCatchStackSizeNonZero(catchType, origin, out afterCatch, delegate(Instruction tryEnd) { InsertAfter(tryEnd, instructions); return instructions.Last(); }); return this; } public ILWeaver HandlerWrapTryCatchStackSizeNonZero(Type? catchType, Instruction origin, out Instruction afterCatch, [ParamCollection] IEnumerable catchInstructions) { return HandlerWrapTryCatchStackSizeNonZero(catchType, origin, out afterCatch, catchInstructions.Unwrap()); } public ILWeaver HandlerWrapTryCatchStackSizeNonZero(Type? catchType, Instruction origin, out Instruction afterCatch, Func writeCatch) { //IL_0051: Unknown result type (might be due to invalid IL or missing references) HandlerCreateCatch(catchType, out WeaverExceptionCatchHandler handler); var (tryStart, val) = GetStackSizeZeroAreaContinuous(origin); HandlerSetTryStart(tryStart, handler); HandlerSetTryEnd(val, handler); Instruction val2 = writeCatch(val); HandlerSetHandlerEnd(val2, handler); afterCatch = val2.Next; if (afterCatch == null) { afterCatch = Create(OpCodes.Nop); InsertAfter(val2, new <>z__ReadOnlySingleElementList(afterCatch)); } HandlerApply(handler); return this; } public ILWeaver HandlerApply(IWeaverExceptionHandler handler) { //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Expected O, but got Unknown //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_0140: Unknown result type (might be due to invalid IL or missing references) //IL_0146: Invalid comparison between Unknown and I4 //IL_0251: Unknown result type (might be due to invalid IL or missing references) //IL_0256: Unknown result type (might be due to invalid IL or missing references) //IL_0213: Unknown result type (might be due to invalid IL or missing references) //IL_026a: Unknown result type (might be due to invalid IL or missing references) //IL_02aa: Unknown result type (might be due to invalid IL or missing references) //IL_02b0: Invalid comparison between Unknown and I4 //IL_02d4: Unknown result type (might be due to invalid IL or missing references) //IL_02ba: Unknown result type (might be due to invalid IL or missing references) //IL_0299: Unknown result type (might be due to invalid IL or missing references) pendingHandlers.Remove(handler); if (handler.TryStart == null) { throw new NullReferenceException("TryStart was not set!"); } if (handler.HandlerEnd == null) { throw new NullReferenceException("HandlerEnd was not set!"); } if (handler.TryStart.InteropGetTarget() == null) { throw new NullReferenceException("TryStart target was not set!"); } if (handler.HandlerEnd.InteropGetTarget() == null) { throw new NullReferenceException("HandlerEnd target was not set!"); } ExceptionHandlerType val; if (!(handler is WeaverExceptionFilterHandler)) { if (!(handler is WeaverExceptionCatchHandler)) { if (!(handler is WeaverExceptionFinallyHandler)) { if (!(handler is WeaverExceptionFaultHandler)) { throw new Exception("Unsupported exception handler type."); } val = (ExceptionHandlerType)4; } else { val = (ExceptionHandlerType)2; } } else { val = (ExceptionHandlerType)0; } } else { val = (ExceptionHandlerType)1; } ExceptionHandler val2 = new ExceptionHandler(val); val2.CatchType = (handler as WeaverExceptionCatchHandler)?.CatchType; val2.TryStart = handler.TryStart.InteropGetTarget(); val2.TryEnd = handler.TryEnd?.InteropGetTarget(); val2.FilterStart = (handler as WeaverExceptionFilterHandler)?.FilterStart?.InteropGetTarget(); val2.HandlerStart = handler.HandlerStart?.InteropGetTarget(); val2.HandlerEnd = handler.HandlerEnd.InteropGetTarget(); ExceptionHandler val3 = val2; bool flag = (int)val3.HandlerType == 1; if (val3.TryEnd != null && val3.TryEnd == val3.HandlerStart) { string text = " Either don't set HandlerStart and let it be set implicitly, or set it to the next instruction."; throw new InvalidOperationException("TryEnd was set to the same instruction as HandlerStart." + (flag ? null : text)); } if (val3.TryEnd == null) { if (flag) { if (val3.FilterStart == null) { throw new NullReferenceException("FilterStart was not set!"); } val3.TryEnd = val3.FilterStart; } else { if (val3.HandlerStart == null) { throw new NullReferenceException("TryEnd and HandlerStart were not set! Note that only one of then needs to be set."); } val3.TryEnd = val3.HandlerStart; } } else { val3.TryEnd = val3.TryEnd.Next; } if (val3.HandlerStart == null) { if (flag) { throw new NullReferenceException("HandlerStart must be set when HandlerType is Filter!"); } val3.HandlerStart = val3.TryEnd; } if (val3.HandlerEnd.Next == null) { GhostInsertAfter(val3.HandlerEnd, Create(OpCodes.Nop)); } val3.HandlerEnd = val3.HandlerEnd.Next; ILLabel operand = Context.DefineLabel(val3.HandlerEnd); if (val3.TryEnd.Previous.OpCode != OpCodes.Throw) { GhostInsertBefore(val3.TryEnd, Create(OpCodes.Leave, (object)operand)); } if (flag) { if (val3.FilterStart == null) { throw new NullReferenceException("FilterStart was not set!"); } GhostInsertBefore(val3.HandlerStart, Create(OpCodes.Endfilter)); } if ((int)val3.HandlerType == 2) { GhostInsertBefore(val3.HandlerEnd, Create(OpCodes.Endfinally)); } else { GhostInsertBefore(val3.HandlerEnd, Create(OpCodes.Leave, (object)operand)); } Context.Body.ExceptionHandlers.Add(val3); return this; } public ILWeaver Replace(Instruction target, Instruction replacement) { InsertAfter(target, new <>z__ReadOnlySingleElementList(replacement)); return RemoveAndShiftLabels(target); } public ILWeaver Replace(Instruction target, [ParamCollection] IEnumerable replacement) { IEnumerable source = replacement.Where((Instruction x) => x != null); Instruction val = source.FirstOrDefault(); if (val == null) { return this; } Replace(target, val); IEnumerable instructions = source.Skip(1); return InsertAfter(val, instructions); } public ILWeaver Replace(Instruction target, [ParamCollection] IEnumerable replacement) { return Replace(target, replacement.Unwrap()); } public ILWeaver ReplaceCurrent(Instruction replacement) { Replace(Current, replacement); return this; } public ILWeaver ReplaceCurrent([ParamCollection] IEnumerable replacement) { return Replace(Current, replacement); } public ILWeaver ReplaceCurrent([ParamCollection] IEnumerable replacement) { return ReplaceCurrent(replacement.Unwrap()); } public ILWeaver ReplaceOperand(Instruction target, object replacementOperand) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) Instruction replacement = Create(target.OpCode, replacementOperand); return Replace(target, replacement); } public ILWeaver ReplaceCurrentOperand(object replacementOperand) { return ReplaceOperand(Current, replacementOperand); } public ILWeaver RemoveAndShiftLabels(Instruction instruction) { return RemoveAndShiftLabelsInternal(Instructions.IndexOf(instruction), 1); } public ILWeaver RemoveCurrentAndShiftLabels() { return RemoveAndShiftLabels(Current); } public ILWeaver RemoveRangeAndShiftLabels(Instruction start, Instruction end) { int num = Instructions.IndexOf(start); if (num == -1) { throw new ArgumentException("'start' is not part of the method body."); } int num2 = Instructions.IndexOf(end); if (num2 == -1) { throw new ArgumentException("'end' is not part of the method body."); } int index = Math.Min(num, num2); int count = Math.Abs(num - num2) + 1; return RemoveAndShiftLabelsInternal(index, count); } private ILWeaver RemoveAndShiftLabelsInternal(int index, int count, bool insertTemporaryIfNeeded = true) { int num = index + count - 1; int index2 = Index; if (count < 0) { throw new IndexOutOfRangeException("Can not remove a negative amount of instructions."); } if (index == -1) { throw new IndexOutOfRangeException("The index -1 or target instruction to be removed does not exist in the method body."); } if (num >= Instructions.Count) { throw new IndexOutOfRangeException("Attempted to remove more instructions than there are available."); } Instruction val; if (num + 1 < Instructions.Count) { val = Instructions[num + 1]; } else { if (index == 0) { foreach (ILLabel item in Context.Labels.Where((ILLabel x) => x.InteropGetTarget() != null)) { pendingFutureNextInsertLabels.Add(item); } Instructions.Clear(); if (insertTemporaryIfNeeded) { InsertTemporaryCurrentTarget(); } return this; } val = Instructions[index - 1]; } if (index2 >= index && index2 <= num) { Current = val; } List handlersWithHandlerStart = null; while (count-- > 0) { Instruction val2 = Instructions[index]; RetargetLabels(val2, val); StealHandlerRole(val2, val, ref handlersWithHandlerStart); Instructions.RemoveAt(index); } return this; } [Browsable(false)] [EditorBrowsable(EditorBrowsableState.Never)] [Obsolete("Removing a range by count is prone to causing invalid IL if the target method's instructions have changed. Use ILWeaver.InsertBranchOver instead as it doesn't have this design flaw. Note that these two methods behave slightly differently; please read the method's remarks in detail.", true)] public ILWeaver RemoveAt(int index, int instructions, out IEnumerable orphanedLabels) { int num = index + instructions - 1; int index2 = Index; if (instructions < 0) { throw new IndexOutOfRangeException("Can not remove a negative amount of instructions."); } if (num > Instructions.Count) { throw new IndexOutOfRangeException("Attempted to remove more instructions than there are available."); } if (index2 >= index && index2 <= num) { Current = Instructions[num + 1]; } List list = new List(); while (instructions-- > 0) { foreach (ILLabel incomingLabel in Context.GetIncomingLabels(Instructions[index])) { list.Add(incomingLabel); } Instructions.RemoveAt(index); } orphanedLabels = list; return this; } [Browsable(false)] [EditorBrowsable(EditorBrowsableState.Never)] [Obsolete("Removing a range by count is prone to causing invalid IL if the target method's instructions have changed. Use ILWeaver.InsertBranchOver instead as it doesn't have this design flaw. Note that these two methods behave slightly differently; please read the method's remarks in detail.", true)] public ILWeaver RemoveAtCurrent(int instructions, out IEnumerable orphanedLabels) { return RemoveAt(Index, instructions, out orphanedLabels); } [Browsable(false)] [EditorBrowsable(EditorBrowsableState.Never)] [Obsolete("Use RemoveAndShiftLabels instead.")] public ILWeaver Remove(Instruction instruction, out ILLabel? orphanedLabel) { RemoveAt(Instructions.IndexOf(instruction), 1, out IEnumerable orphanedLabels); orphanedLabel = orphanedLabels.FirstOrDefault(); return this; } [Browsable(false)] [EditorBrowsable(EditorBrowsableState.Never)] [Obsolete("Use RemoveCurrentAndShiftLabels instead.")] public ILWeaver RemoveCurrent(out ILLabel? orphanedLabel) { Instruction next = Next; Remove(Current, out orphanedLabel); CurrentTo(next); return this; } private ILWeaver InsertAtInternal(ref int refIndex, Instruction instruction, InsertType insertType) { Helpers.ThrowIfNull(instruction, "instruction"); int num = refIndex; if (num == -1) { if (Instructions.Count != 0) { throw new IndexOutOfRangeException("The index -1 or target instruction to be inserted at does not exist in the method body."); } refIndex = 0; num = 0; InsertTemporaryCurrentTarget(); } if (insertType == InsertType.After) { num++; } if (num > Instructions.Count) { throw new IndexOutOfRangeException($"The index to be inserted is out of range; index: {num} / instructions: {Instructions.Count}"); } if (insertType == InsertType.BeforeAndStealLabels) { Instruction target = Instructions[num]; StealHandlerRole(target, instruction); RetargetLabels(GetIncomingLabelsFor(target), instruction); } RetargetLabels((IEnumerable)pendingFutureNextInsertLabels, instruction); pendingFutureNextInsertLabels.Clear(); ProcessInstructionForInsert(instruction); Instructions.Insert(num, instruction); return this; } private void StealHandlerRole(Instruction target, Instruction replacement) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) Enumerator enumerator = Body.ExceptionHandlers.GetEnumerator(); try { while (enumerator.MoveNext()) { ExceptionHandler val = enumerator.Current; if (val.TryStart == target) { val.TryStart = replacement; } if (val.HandlerStart == target) { val.HandlerStart = replacement; } if (val.FilterStart == target) { val.FilterStart = replacement; } if (val.TryEnd == target) { val.TryEnd = replacement; } if (val.HandlerEnd == target) { val.HandlerEnd = replacement; } } } finally { ((IDisposable)enumerator/*cast due to .constrained prefix*/).Dispose(); } } private void StealHandlerRole(Instruction target, Instruction replacement, ref List? handlersWithHandlerStart) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) List list = null; Enumerator enumerator = Body.ExceptionHandlers.GetEnumerator(); try { while (enumerator.MoveNext()) { ExceptionHandler val = enumerator.Current; if (val.TryStart == target) { val.TryStart = replacement; } if (val.HandlerStart == target) { val.HandlerStart = replacement; if (handlersWithHandlerStart == null) { handlersWithHandlerStart = new List(1) { val }; } else { handlersWithHandlerStart.Add(val); } } if (val.FilterStart == target) { val.FilterStart = replacement; } if (val.TryEnd == target) { val.TryEnd = replacement; } Instruction handlerEnd = val.HandlerEnd; if (((handlerEnd != null) ? handlerEnd.Previous : null) == target) { List? obj = handlersWithHandlerStart; if (obj != null && obj.Contains(val)) { if (list == null) { list = new List(1) { val }; } else { list.Add(val); } } } if (val.HandlerEnd == target) { val.HandlerEnd = replacement; } } } finally { ((IDisposable)enumerator/*cast due to .constrained prefix*/).Dispose(); } if (list == null) { return; } foreach (ExceptionHandler item in list) { Body.ExceptionHandlers.Remove(item); } } private void ProcessInstructionForInsert(Instruction instruction) { InstructionOperandToILLabel(instruction); targetInfo.InstructionToSource[instruction] = ManipulationInfo.Hook; } private void InstructionOperandToILLabel(Instruction instruction) { object operand = instruction.Operand; Instruction val = (Instruction)((operand is Instruction) ? operand : null); if (val != null) { instruction.Operand = DefineAndMarkLabelTo(val); } else if (instruction.Operand is Instruction[] array) { ILLabel[] array2 = (ILLabel[])(object)new ILLabel[array.Length]; for (int i = 0; i < array.Length; i++) { array2[i] = DefineAndMarkLabelTo(array[i]); } instruction.Operand = array2; } } private ILWeaver GhostInsertBefore(Instruction target, Instruction instruction) { ProcessInstructionForInsert(instruction); Instructions.Insert(Instructions.IndexOf(target), instruction); return this; } private ILWeaver GhostInsertAfter(Instruction target, Instruction instruction) { ProcessInstructionForInsert(instruction); Instructions.Insert(Instructions.IndexOf(target) + 1, instruction); return this; } [OverloadResolutionPriority(1)] public ILWeaver InsertBeforeStealLabels(int index, [ParamCollection] IEnumerable instructions) { IEnumerable source = instructions.Where((Instruction x) => x != null); Instruction val = source.FirstOrDefault(); if (val == null) { return this; } InsertAtInternal(ref index, val, InsertType.BeforeAndStealLabels); index++; foreach (Instruction item in source.Skip(1)) { InsertAtInternal(ref index, item, InsertType.Before); index++; } return this; } public ILWeaver InsertBeforeStealLabels(int index, [ParamCollection] IEnumerable instructions) { return InsertBeforeStealLabels(index, instructions.Unwrap()); } [OverloadResolutionPriority(1)] public ILWeaver InsertBeforeStealLabels(Instruction target, [ParamCollection] IEnumerable instructions) { return InsertBeforeStealLabels(Instructions.IndexOf(target), instructions); } public ILWeaver InsertBeforeStealLabels(Instruction target, [ParamCollection] IEnumerable instructions) { return InsertBeforeStealLabels(target, instructions.Unwrap()); } [OverloadResolutionPriority(1)] public ILWeaver InsertBeforeCurrentStealLabels([ParamCollection] IEnumerable instructions) { return InsertBeforeStealLabels(Index, instructions); } public ILWeaver InsertBeforeCurrentStealLabels([ParamCollection] IEnumerable instructions) { return InsertBeforeCurrentStealLabels(instructions.Unwrap()); } [OverloadResolutionPriority(1)] public ILWeaver InsertBefore(int index, [ParamCollection] IEnumerable instructions) { foreach (Instruction item in instructions.Where((Instruction x) => x != null)) { InsertAtInternal(ref index, item, InsertType.Before); index++; } return this; } public ILWeaver InsertBefore(int index, [ParamCollection] IEnumerable instructions) { return InsertBefore(index, instructions.Unwrap()); } [OverloadResolutionPriority(1)] public ILWeaver InsertBefore(Instruction target, [ParamCollection] IEnumerable instructions) { return InsertBefore(Instructions.IndexOf(target), instructions); } public ILWeaver InsertBefore(Instruction target, [ParamCollection] IEnumerable instructions) { return InsertBefore(target, instructions.Unwrap()); } [OverloadResolutionPriority(1)] public ILWeaver InsertBeforeCurrent([ParamCollection] IEnumerable instructions) { return InsertBefore(Index, instructions); } public ILWeaver InsertBeforeCurrent([ParamCollection] IEnumerable instructions) { return InsertBeforeCurrent(instructions.Unwrap()); } [OverloadResolutionPriority(1)] public ILWeaver InsertAfter(int index, [ParamCollection] IEnumerable instructions) { foreach (Instruction item in instructions.Where((Instruction x) => x != null)) { InsertAtInternal(ref index, item, InsertType.After); index++; } return this; } public ILWeaver InsertAfter(int index, [ParamCollection] IEnumerable instructions) { return InsertAfter(index, instructions.Unwrap()); } [OverloadResolutionPriority(1)] public ILWeaver InsertAfter(Instruction target, [ParamCollection] IEnumerable instructions) { return InsertAfter(Instructions.IndexOf(target), instructions); } public ILWeaver InsertAfter(Instruction target, [ParamCollection] IEnumerable instructions) { return InsertAfter(target, instructions.Unwrap()); } [OverloadResolutionPriority(1)] public ILWeaver InsertAfterCurrent([ParamCollection] IEnumerable instructions) { int refIndex = Index; foreach (Instruction item in instructions.Where((Instruction x) => x != null)) { InsertAtInternal(ref refIndex, item, InsertType.After); CurrentTo(item); refIndex++; } return this; } public ILWeaver InsertAfterCurrent([ParamCollection] IEnumerable instructions) { return InsertAfterCurrent(instructions.Unwrap()); } private ILWeaver InsertBranchOverIfX(Instruction start, Instruction end, OpCode opCode, [ParamCollection] IEnumerable condition) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) int index = Instructions.IndexOf(start); InsertBeforeStealLabels(index, new <>z__ReadOnlySingleElementList(Create(opCode, end.Next))); InsertBeforeStealLabels(index, condition); return this; } [OverloadResolutionPriority(1)] public ILWeaver InsertBranchOverIfTrue(Instruction start, Instruction end, [ParamCollection] IEnumerable condition) { //IL_0003: Unknown result type (might be due to invalid IL or missing references) return InsertBranchOverIfX(start, end, OpCodes.Brtrue, condition); } public ILWeaver InsertBranchOverIfTrue(Instruction start, Instruction end, [ParamCollection] IEnumerable condition) { return InsertBranchOverIfTrue(start, end, condition.Unwrap()); } [OverloadResolutionPriority(1)] public ILWeaver InsertBranchOverIfTrue((Instruction start, Instruction end) range, [ParamCollection] IEnumerable condition) { return InsertBranchOverIfTrue(range.start, range.end, condition); } public ILWeaver InsertBranchOverIfTrue((Instruction start, Instruction end) range, [ParamCollection] IEnumerable condition) { return InsertBranchOverIfTrue(range, condition.Unwrap()); } [OverloadResolutionPriority(1)] public ILWeaver InsertBranchOverIfFalse(Instruction start, Instruction end, [ParamCollection] IEnumerable condition) { //IL_0003: Unknown result type (might be due to invalid IL or missing references) return InsertBranchOverIfX(start, end, OpCodes.Brfalse, condition); } public ILWeaver InsertBranchOverIfFalse(Instruction start, Instruction end, [ParamCollection] IEnumerable condition) { return InsertBranchOverIfFalse(start, end, condition.Unwrap()); } [OverloadResolutionPriority(1)] public ILWeaver InsertBranchOverIfFalse((Instruction start, Instruction end) range, [ParamCollection] IEnumerable condition) { return InsertBranchOverIfFalse(range.start, range.end, condition); } public ILWeaver InsertBranchOverIfFalse((Instruction start, Instruction end) range, [ParamCollection] IEnumerable condition) { return InsertBranchOverIfFalse(range, condition.Unwrap()); } public ILWeaver InsertBranchOver(Instruction start, Instruction end) { //IL_0003: Unknown result type (might be due to invalid IL or missing references) InsertBeforeStealLabels(start, new <>z__ReadOnlySingleElementList(Create(OpCodes.Br, end.Next))); return this; } public ILWeaver InsertBranchOver((Instruction start, Instruction end) range) { return InsertBranchOver(range.start, range.end); } public ILWeaver EmitReferenceBefore(Instruction target, in T? value, out int id) { id = Context.InteropEmitReferenceBefore(target, in value); return this; } public ILWeaver EmitReferenceBeforeCurrent(in T? value, out int id) { return EmitReferenceBefore(Current, in value, out id); } public Instruction Create(OpCode opcode, ParameterDefinition parameter) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) return IL.Create(opcode, parameter); } public Instruction Create(OpCode opcode, VariableDefinition variable) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) return IL.Create(opcode, variable); } public Instruction Create(OpCode opcode, Instruction[] targets) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) return IL.Create(opcode, targets); } public Instruction Create(OpCode opcode, Instruction target) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) return IL.Create(opcode, target); } public Instruction Create(OpCode opcode, double value) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) return IL.Create(opcode, value); } public Instruction Create(OpCode opcode, float value) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) return IL.Create(opcode, value); } public Instruction Create(OpCode opcode, long value) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) return IL.Create(opcode, value); } public Instruction Create(OpCode opcode, sbyte value) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) return IL.Create(opcode, value); } public Instruction Create(OpCode opcode, byte value) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) return IL.Create(opcode, value); } public Instruction Create(OpCode opcode, string value) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) return IL.Create(opcode, value); } public Instruction Create(OpCode opcode, FieldReference field) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) return IL.Create(opcode, field); } public Instruction Create(OpCode opcode, CallSite site) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) return IL.Create(opcode, site); } public Instruction Create(OpCode opcode, TypeReference type) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) return IL.Create(opcode, type); } public Instruction Create(OpCode opcode) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) return IL.Create(opcode); } public Instruction Create(OpCode opcode, int value) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) return IL.Create(opcode, value); } public Instruction Create(OpCode opcode, MethodReference method) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) return IL.Create(opcode, method); } public Instruction Create(OpCode opcode, FieldInfo field) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) return Extensions.Create(IL, opcode, field); } public Instruction Create(OpCode opcode, MethodBase method) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) return Extensions.Create(IL, opcode, method); } public Instruction Create(OpCode opcode, Type type) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) return Extensions.Create(IL, opcode, type); } public Instruction Create(OpCode opcode, object operand) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) return Extensions.Create(IL, opcode, operand); } public Instruction CreateCall(Delegate method) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) return Extensions.Create(IL, OpCodes.Call, (MethodBase)method.Method); } public Instruction[] CreateDelegateCall(T @delegate) where T : Delegate { //IL_014b: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_00f5: Unknown result type (might be due to invalid IL or missing references) Helpers.ThrowIfNull(@delegate, "@delegate"); if (@delegate.GetInvocationList().Length == 1 && @delegate.Target == null) { return (Instruction[])(object)new Instruction[1] { Create(OpCodes.Call, (MethodBase)@delegate.Method) }; } List list = new List(); (MethodInfo, Type)? delegateInvoker = InteropFastDelegateInvokers.GetDelegateInvoker(Context, @delegate.GetType()); if (delegateInvoker.HasValue) { (MethodInfo, Type) valueOrDefault = delegateInvoker.GetValueOrDefault(); if (MonoModVersion.IsReorg) { Delegate t = Extensions.CastDelegate((Delegate)@delegate, valueOrDefault.Item2); int id = Context.InteropAddReference(in t); list.AddRange(Context.InteropGetReference(this, id, t)); } else { int id = Context.InteropAddReference(in @delegate); list.AddRange(Context.InteropGetReference(this, id, @delegate)); } Context.InteropAddReference(in valueOrDefault.Item1); list.Add(Create(OpCodes.Call, (MethodBase)valueOrDefault.Item1)); } else { int id = Context.InteropAddReference(in @delegate); list.AddRange(Context.InteropGetReference(this, id, @delegate)); MethodInfo method = typeof(T).GetMethod("Invoke"); list.Add(Create(OpCodes.Callvirt, (MethodBase)method)); } return list.ToArray(); } public Instruction Create(OpCode opcode, string memberName) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) return Extensions.Create(IL, opcode, typeof(T).GetMember(memberName, (BindingFlags)(-1)).First()); } public IEnumerable GetIncomingLabelsFor(Instruction target) { return Context.GetIncomingLabels(target); } public IEnumerable GetIncomingLabelsForCurrent() { return Context.GetIncomingLabels(Current); } public ILWeaver RetargetLabels(IEnumerable labels, Instruction target) { foreach (ILLabel label in labels) { label.InteropSetTarget(target); } return this; } public ILWeaver RetargetLabels(Instruction source, Instruction target) { return RetargetLabels(GetIncomingLabelsFor(source), target); } public ILWeaver RetargetLabels(ILLabel? label, Instruction target) { label?.InteropSetTarget(target); return this; } public ILLabel DefineLabel() { return Context.DefineLabel(); } public ILWeaver DefineLabel(out ILLabel label) { label = Context.DefineLabel(); return this; } public ILWeaver MarkLabelTo(Instruction target, ILLabel label) { Helpers.ThrowIfNull(target, "target"); label.InteropSetTarget(target); return this; } public ILWeaver DefineAndMarkLabelTo(Instruction target, out ILLabel markedLabel) { Helpers.ThrowIfNull(target, "target"); markedLabel = Context.DefineLabel(target); return this; } public ILLabel DefineAndMarkLabelTo(Instruction target) { DefineAndMarkLabelTo(target, out ILLabel markedLabel); return markedLabel; } public ILWeaver MarkLabelToFutureNextInsert(ILLabel label) { Helpers.ThrowIfNull(label, "label"); pendingFutureNextInsertLabels.Add(label); return this; } public ILWeaver DefineAndMarkLabelToFutureNextInsert(out ILLabel futureMarkedLabel) { futureMarkedLabel = Context.DefineLabel(); pendingFutureNextInsertLabels.Add(futureMarkedLabel); return this; } public ILLabel DefineAndMarkLabelToFutureNextInsert() { DefineAndMarkLabelToFutureNextInsert(out ILLabel futureMarkedLabel); return futureMarkedLabel; } public ILWeaver MarkLabelToCurrentOrFutureNextInsert(ILLabel label) { Helpers.ThrowIfNull(label, "label"); label.InteropSetTarget(Current); pendingFutureNextInsertLabels.Add(label); return this; } public ILWeaver DefineAndMarkLabelToCurrentOrFutureNextInsert(out ILLabel futureMarkedLabel) { futureMarkedLabel = Context.DefineLabel(Current); pendingFutureNextInsertLabels.Add(futureMarkedLabel); return this; } public ILLabel DefineAndMarkLabelToCurrentOrFutureNextInsert() { DefineAndMarkLabelToCurrentOrFutureNextInsert(out ILLabel futureMarkedLabel); return futureMarkedLabel; } public ILWeaver MarkLabelToCurrent(ILLabel label) { Helpers.ThrowIfNull(label, "label"); label.InteropSetTarget(Current); return this; } public ILWeaver DefineAndMarkLabelToCurrent(out ILLabel markedLabel) { markedLabel = Context.DefineLabel(Current); return this; } public ILLabel DefineAndMarkLabelToCurrent() { DefineAndMarkLabelToCurrent(out ILLabel markedLabel); return markedLabel; } public ILWeaver MarkLabelToCurrentPrevious(ILLabel label) { Helpers.ThrowIfNull(label, "label"); label.InteropSetTarget(Current.Previous); return this; } public ILWeaver DefineAndMarkLabelToCurrentPrevious(out ILLabel markedLabel) { markedLabel = Context.DefineLabel(Current.Previous); return this; } public ILLabel DefineAndMarkLabelToCurrentPrevious() { DefineAndMarkLabelToCurrentPrevious(out ILLabel markedLabel); return markedLabel; } public ILWeaver MarkLabelToCurrentNext(ILLabel label) { Helpers.ThrowIfNull(label, "label"); label.InteropSetTarget(Current.Next); return this; } public ILWeaver DefineAndMarkLabelToCurrentNext(out ILLabel markedLabel) { markedLabel = Context.DefineLabel(Current.Next); return this; } public ILLabel DefineAndMarkLabelToCurrentNext() { DefineAndMarkLabelToCurrentNext(out ILLabel markedLabel); return markedLabel; } public ILWeaver CurrentTo(int index) { int num = index; if (num < 0) { num += Instructions.Count; } Instruction val = ((num >= Instructions.Count) ? null : Instructions[num]); if (val == null) { throw new IndexOutOfRangeException("Attempted to set ILWeaver's position out of bounds. " + $"Attempted index: {num}; valid range: 0 to {Instructions.Count - 1}" + ((index == num) ? "" : $" (actual index without loop back: {index})")); } CurrentTo(val); return this; } [MemberNotNull("current")] public ILWeaver CurrentTo(Instruction instruction) { if (instruction == null) { throw new ArgumentNullException("instruction", "Attempted to set Current to a null instruction."); } current = instruction; return this; } public bool SetCurrentTo(Instruction instruction) { if (!Instructions.Contains(instruction)) { return false; } CurrentTo(instruction); return true; } public bool SetInstructionTo([NotNull] ref Instruction? toBeSet, Instruction target) { Helpers.ThrowIfNull(target, "target"); toBeSet = target; if (!Instructions.Contains(target)) { return false; } return true; } public ILWeaver CurrentToNext() { return CurrentTo(Current.Next); } public ILWeaver CurrentToPrevious() { return CurrentTo(Current.Previous); } public Instruction GetStackSizeZeroBeforeContinuous(Instruction start, IInformationalMethodBody? informationalBody = null) { if (informationalBody == null) { informationalBody = Body.CreateInformationalSnapshotEvaluateAll(); } IInformationalInstruction informationalInstruction = informationalBody.GetInformationalInstruction(start); IInformationalInstruction informationalInstruction2 = informationalInstruction; while (informationalInstruction2 == null || !informationalInstruction2.IsEvaluated || informationalInstruction2.IncomingStackSize > 0) { informationalInstruction2 = informationalInstruction2.Previous; if (informationalInstruction2 == null) { throw new NullReferenceException("There was no previous empty stack."); } } return informationalInstruction2.Instruction; } public Instruction GetStackSizeZeroAfterContinuous(Instruction start, IInformationalMethodBody? informationalBody = null) { if (informationalBody == null) { informationalBody = Body.CreateInformationalSnapshotEvaluateAll(); } IInformationalInstruction informationalInstruction = informationalBody.GetInformationalInstruction(start); IInformationalInstruction informationalInstruction2 = informationalInstruction; while (informationalInstruction2 == null || !informationalInstruction2.IsEvaluated || informationalInstruction2.StackSize > 0) { informationalInstruction2 = informationalInstruction2.Next ?? throw new NullReferenceException("There was no next empty stack."); } return informationalInstruction2.Instruction; } public (Instruction start, Instruction end) GetStackSizeZeroAreaContinuous(Instruction start, IInformationalMethodBody? informationalBody = null) { if (informationalBody == null) { informationalBody = Body.CreateInformationalSnapshotEvaluateAll(); } Instruction stackSizeZeroBeforeContinuous = GetStackSizeZeroBeforeContinuous(start, informationalBody); Instruction stackSizeZeroAfterContinuous = GetStackSizeZeroAfterContinuous(start, informationalBody); return (start: stackSizeZeroBeforeContinuous, end: stackSizeZeroAfterContinuous); } public ILWeaverResult MatchRelaxed(params Predicate[] predicates) { return MatchInternal(allowMultipleMatches: false, null, MatchPassType.RelaxedAllowOriginalPass, predicates, null); } public ILWeaverResult MatchStrict(params Predicate[] predicates) { return MatchInternal(allowMultipleMatches: false, null, MatchPassType.StrictNoOriginalPass, predicates, null); } public ILWeaverResult MatchInRangeRelaxed(Instruction start, Instruction end, params Predicate[] predicates) { return MatchInternal(allowMultipleMatches: false, null, MatchPassType.RelaxedAllowOriginalPass, predicates, (start, end)); } public ILWeaverResult MatchInRangeStrict(Instruction start, Instruction end, params Predicate[] predicates) { return MatchInternal(allowMultipleMatches: false, null, MatchPassType.StrictNoOriginalPass, predicates, (start, end)); } public ILWeaverResult MatchMultipleRelaxed(Action onMatch, params Predicate[] predicates) { return MatchInternal(allowMultipleMatches: true, onMatch, MatchPassType.RelaxedAllowOriginalPass, predicates, null); } public ILWeaverResult MatchMultipleStrict(Action onMatch, params Predicate[] predicates) { return MatchInternal(allowMultipleMatches: true, onMatch, MatchPassType.StrictNoOriginalPass, predicates, null); } private ILWeaverResult MatchInternal(bool allowMultipleMatches, Action? onMatched, MatchPassType passType, Predicate[] predicates, (Instruction start, Instruction end)? matchRange) { Helpers.ThrowIfNull(predicates, "predicates"); if (allowMultipleMatches) { Helpers.ThrowIfNull(onMatched, "onMatched"); } Instruction instruction = Current; List matchedIndexes = new List(); List list = new List(); List<(int count, int indexBeforeFailed)> bestAttempts = new List<(int, int)>(1) { (0, 0) }; IList list2; if (passType != MatchPassType.IsOriginalPass) { IList instructions = (IList)Instructions; list2 = instructions; } else { IList instructions = ManipulationInfo.OriginalInstructions; list2 = instructions; } IList instructions2 = list2; int num = 0; int num2 = instructions2.Count; if (matchRange.HasValue) { var (val, val2) = matchRange.GetValueOrDefault(); while (val != null) { num = instructions2.IndexOf(val); if (num != -1) { break; } val = val.Previous; } if (val == null) { num = 0; } while (val2 != null) { num2 = instructions2.IndexOf(val2); if (num2 != -1) { num2++; break; } val2 = val2.Next; } if (val2 == null) { num2 = instructions2.Count; } } int num3 = 0; for (int i = num; i < num2; i++) { if (!predicates[num3](instructions2[i])) { if (num3 > 0) { if (bestAttempts[0].count < num3) { bestAttempts.Clear(); bestAttempts.Add((num3, i - 1)); } else if (bestAttempts[0].count == num3) { bestAttempts.Add((num3, i - 1)); } } i -= num3; num3 = 0; } else { num3++; if (num3 == predicates.Length) { num3 = 0; matchedIndexes.Add(i); list.Add(instructions2[i - predicates.Length + 1]); } } } if (allowMultipleMatches) { if (matchedIndexes.Count > 0) { foreach (Instruction item5 in list) { int num4 = instructions2.IndexOf(item5); int num5 = num4 + predicates.Length; int num6 = 0; for (int j = num4; j < num5; j++) { predicates[num6](instructions2[j]); num6++; } onMatched(Clone()); } CurrentTo(instruction); return new ILWeaverResult(this, null); } CurrentTo(instruction); if (passType == MatchPassType.RelaxedAllowOriginalPass) { ILWeaverResult iLWeaverResult = MatchInternal(allowMultipleMatches, onMatched, MatchPassType.IsOriginalPass, predicates, matchRange); if (iLWeaverResult.IsValid) { LogFailure(GetResult().FailureMessage); return new ILWeaverResult(this, null); } } } else { if (matchedIndexes.Count == 1) { Instruction item2 = list.First(); int num7 = instructions2.IndexOf(item2); int num8 = num7 + predicates.Length; int num9 = 0; for (int k = num7; k < num8; k++) { predicates[num9](instructions2[k]); num9++; } return new ILWeaverResult(this, null); } if (passType == MatchPassType.RelaxedAllowOriginalPass) { ILWeaverResult iLWeaverResult2 = MatchInternal(allowMultipleMatches, onMatched, MatchPassType.IsOriginalPass, predicates, matchRange); if (iLWeaverResult2.IsValid) { LogFailure(GetResult().FailureMessage); return new ILWeaverResult(this, null); } CurrentTo(instruction); } } return GetResult(); string GetMatchedTooManyError() { Extensions.RecalculateILOffsets(Method); CodeBuilder codeBuilder = new CodeBuilder(new StringBuilder(), 2); codeBuilder.WriteLine("ILWeaver matched all predicates more than once in the target method.").Write("Total matches: ").WriteLine(matchedIndexes.Count); int num10 = 0; foreach (int item6 in matchedIndexes) { num10++; codeBuilder.Write(num10).Write(". At indexes: ").Write(item6 - predicates.Length + 1) .Write(" to ") .Write(item6) .Write(" (") .Write(instructions2[item6 - predicates.Length + 1].ToStringSafe()) .Write(" to ") .Write(instructions2[item6].ToStringSafe()) .WriteLine(")"); } codeBuilder.WriteLine("Help: Add more predicates to find a unique match or lessen the match range" + (matchRange.HasValue ? ((object)'.') : " using a MatchInRange method.")?.ToString() + "\nDocumentation: ").WriteLine("Info: Use ILWeaver.MatchMultiple* methods if you intend to match multiple instances."); codeBuilder.RemoveIndent().WriteLine().WriteLine("This message originates from:") .WriteLine(new StackTrace(fNeedFileInfo: true).ToString()); return codeBuilder.ToString(); } string GetNotMatchedAllError() { //IL_00ec: Unknown result type (might be due to invalid IL or missing references) //IL_00f2: Expected O, but got Unknown Extensions.RecalculateILOffsets(Method); CodeBuilder codeBuilder = new CodeBuilder(new StringBuilder(), 2); codeBuilder.Write("ILWeaver couldn't match all predicates for method: ").WriteLine(((MemberReference)Context.Method).FullName).Write("Matched predicates required: ") .WriteLine(predicates.Length) .Write("The following best attempts matched the number of predicates: ") .WriteLine(bestAttempts[0].count); if (bestAttempts[0].count == 0) { codeBuilder.WriteLine().WriteLine("(first predicate was never matched)"); } else { Predicate predicate = predicates[bestAttempts[0].count]; string text = null; if (!predicate.Method.Name.StartsWith("<", StringComparison.InvariantCulture)) { text = predicate.Method.Name; } else { DynamicMethodDefinition val3 = new DynamicMethodDefinition((MethodBase)predicate.Method); try { List list3 = new List(); MethodReference val6 = default(MethodReference); IEnumerable enumerable = ((IEnumerable)val3.Definition.Body.Instructions).Where((Instruction x) => ILPatternMatchingExt.MatchCallOrCallvirt(x, ref val6)); foreach (Instruction item7 in enumerable) { object operand = item7.Operand; MethodReference val5 = (MethodReference)((operand is MethodReference) ? operand : null); if (val5 != null) { list3.Add(((MemberReference)val5).Name); } } if (list3.Count > 0) { text = string.Join(", ", list3); } } finally { ((IDisposable)val3)?.Dispose(); } } codeBuilder.Write("The first predicate which failed is at index ").Write(bestAttempts[0].count).WriteLine(", failing to match any of the following instructions:"); if (text != null) { codeBuilder.Write("(The predicate consists of the method calls: ").Write(text).WriteLine(')'); } for (int num10 = 0; num10 < bestAttempts.Count; num10++) { (int count, int indexBeforeFailed) tuple2 = bestAttempts[num10]; int item3 = tuple2.count; int item4 = tuple2.indexBeforeFailed; Instruction instruction2 = instructions2[item4 + 1]; codeBuilder.RemoveIndent().WriteLine().Write(num10 + 1) .Write(". Matched a range: (") .Write(item4 - item3 + 1) .Write(" to ") .Write(item4) .Write(" | ") .Write(instructions2[item4 - item3 + 1].ToStringSafe()) .Write(" to ") .Write(instructions2[item4].ToStringSafe()) .WriteLine(") but failed to match the next instruction:") .IncreaseIndent() .Write(' ') .Write(item4 + 1) .Write(' ') .WriteLine(instruction2.ToStringSafe()); } } codeBuilder.RemoveIndent().WriteLine("\nHelp: Use MonoMod's ILPatternMatchingExt extension methods.\nThe general format is 'Match{OpCode}' and the methods have overloads for matching just the OpCode or also the Operand.\n Example 1: x => x.MatchLdarg(0) // Match Ldarg with Operand 0\n Example 2: x => x.MatchLdfld(out _) // Match Ldfld with any Operand and discard 'out' Operand value\n Example 3: x => x.MatchBrtrue(out branchTarget) // Match Brtrue and store Operand value to a local variable\n Example 4: x => x.MatchCall(out var method) && method.Name.StartsWith(\"\") // Match Call with any method starting with ''\n\nThis message originates from:").WriteLine(new StackTrace(fNeedFileInfo: true).ToString()); return codeBuilder.ToString(); } ILWeaverResult GetResult() { if (matchedIndexes.Count > 0) { return new ILWeaverResult(this, GetMatchedTooManyError); } return new ILWeaverResult(this, GetNotMatchedAllError); } void LogFailure(string failureMessage) { this.Log(MonoDetourLogger.LogChannel.Warning, "Match succeeded against 'original' instructions as a fallback but failed against current ones. This ILHook still probably works.\nHere's what went wrong when matching against current instructions:\n" + failureMessage); } } } public class ILWeaverResult { private string? invalidActionMessage; private readonly Func? getFailureMessage; private readonly ILWeaver weaver; [MemberNotNullWhen(false, "FailureMessage")] public bool IsValid { [MemberNotNullWhen(false, "FailureMessage")] get; } = true; public string? FailureMessage => invalidActionMessage ?? (invalidActionMessage = getFailureMessage?.Invoke()); public ILWeaverResult(ILWeaver weaver, Func? failureMessage) { this.weaver = weaver; if (failureMessage != null) { IsValid = false; getFailureMessage = failureMessage; } } public ILWeaver ThrowIfFailure() { if (IsValid) { return weaver; } throw new ILWeaverResultException("Failed result was thrown.\n" + FailureMessage); } public ILWeaver Extract(out ILWeaverResult result) { result = this; return weaver; } } [Serializable] public class ILWeaverResultException : Exception { public ILWeaverResultException() { } public ILWeaverResultException(string message) : base(message) { } public ILWeaverResultException(string message, Exception inner) : base(message, inner) { } } public static class InstructionExtensions { public static Instruction Get(this Instruction source, out Instruction instruction) { instruction = source; return source; } public static Instruction MarkLabel(this Instruction instruction, ILLabel label) { label.InteropSetTarget(instruction); return instruction; } public static Instruction Clone(this Instruction instruction) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) Instruction val = Instruction.Create(OpCodes.Nop); val.OpCode = instruction.OpCode; val.Operand = instruction.Operand; return val; } public static string ToStringSafe(this Instruction instruction) { //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Invalid comparison between Unknown and I4 //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Invalid comparison between Unknown and I4 //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Invalid comparison between Unknown and I4 //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Invalid comparison between Unknown and I4 StringBuilder stringBuilder = new StringBuilder(); AppendLabel(stringBuilder, instruction); stringBuilder.Append(':'); stringBuilder.Append(' '); OpCode opCode = instruction.OpCode; stringBuilder.Append(((OpCode)(ref opCode)).Name); if (instruction.Operand == null) { return stringBuilder.ToString(); } stringBuilder.Append(' '); opCode = instruction.OpCode; OperandType operandType = ((OpCode)(ref opCode)).OperandType; if ((int)operandType <= 9) { if ((int)operandType == 0) { goto IL_0083; } if ((int)operandType != 9) { goto IL_01b8; } stringBuilder.Append('"'); stringBuilder.Append(instruction.Operand); stringBuilder.Append('"'); } else { if ((int)operandType != 10) { if ((int)operandType == 15) { goto IL_0083; } goto IL_01b8; } object operand = instruction.Operand; Instruction[] array2; if (!(operand is ILLabel[] source)) { if (!(operand is Instruction[] array)) { if (operand != null) { AppendInvalidOperandType(stringBuilder, operand); return stringBuilder.ToString(); } return stringBuilder.ToString(); } array2 = array; } else { array2 = source.Select((ILLabel l) => l.InteropGetTarget()).ToArray(); } for (int num = 0; num < array2.Length; num++) { if (num > 0) { stringBuilder.Append(','); } Instruction val = array2[num]; if (val == null) { stringBuilder.Append("null"); } else { AppendLabel(stringBuilder, val); } } } goto IL_01c5; IL_01c5: return stringBuilder.ToString(); IL_01b8: stringBuilder.Append(instruction.Operand); goto IL_01c5; IL_0083: object operand2 = instruction.Operand; ILLabel val2 = (ILLabel)((operand2 is ILLabel) ? operand2 : null); Instruction val4; if (val2 == null) { Instruction val3 = (Instruction)((operand2 is Instruction) ? operand2 : null); if (val3 == null) { if (operand2 != null) { AppendInvalidOperandType(stringBuilder, operand2); return stringBuilder.ToString(); } return stringBuilder.ToString(); } val4 = val3; } else { val4 = val2.InteropGetTarget(); if (val4 == null) { return stringBuilder.ToString(); } } AppendLabel(stringBuilder, val4); goto IL_01c5; } private static void AppendInvalidOperandType(StringBuilder sb, object value) { sb.Append(""); } private static void AppendLabel(StringBuilder builder, Instruction instruction) { builder.Append("IL_"); builder.Append(instruction.Offset.ToString("x4", CultureInfo.InvariantCulture)); } } public sealed class InstructionOrEnumerable : IEnumerable, IEnumerable { private readonly IEnumerable _instructions; public InstructionOrEnumerable(IEnumerable instructions) { _instructions = instructions; } public InstructionOrEnumerable(Instruction instruction) { _instructions = new <>z__ReadOnlySingleElementList(instruction); } public static implicit operator InstructionOrEnumerable(Instruction instruction) { return new InstructionOrEnumerable(instruction); } public static implicit operator InstructionOrEnumerable(Instruction?[] instructions) { return new InstructionOrEnumerable((IEnumerable)instructions); } public static implicit operator InstructionOrEnumerable(List instructions) { return new InstructionOrEnumerable((IEnumerable)instructions); } public static implicit operator Instruction?[](InstructionOrEnumerable instructions) { return instructions._instructions.ToArray(); } public static implicit operator List(InstructionOrEnumerable instructions) { return instructions._instructions.ToList(); } public IEnumerator GetEnumerator() { return _instructions.GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } } public static class InstructionOrEnumerableExtensions { public static IEnumerable Unwrap(this IEnumerable instructions) { return instructions.Where((InstructionOrEnumerable x) => x != null).SelectMany((InstructionOrEnumerable x) => x); } } public interface IWeaverExceptionHandler { ILLabel? TryStart { get; set; } ILLabel? TryEnd { get; set; } ILLabel? HandlerStart { get; set; } ILLabel? HandlerEnd { get; set; } } public class WeaverExceptionCatchHandler(TypeReference catchType) : IWeaverExceptionHandler { public TypeReference CatchType { get; } = catchType; public ILLabel? TryStart { get; set; } public ILLabel? TryEnd { get; set; } public ILLabel? HandlerStart { get; set; } public ILLabel? HandlerEnd { get; set; } } public sealed class WeaverExceptionFilterHandler : WeaverExceptionCatchHandler { public ILLabel? FilterStart { get; set; } public WeaverExceptionFilterHandler(TypeReference catchType) : base(catchType) { } } public sealed class WeaverExceptionFinallyHandler : IWeaverExceptionHandler { public ILLabel? TryStart { get; set; } public ILLabel? TryEnd { get; set; } public ILLabel? HandlerStart { get; set; } public ILLabel? HandlerEnd { get; set; } } public sealed class WeaverExceptionFaultHandler : IWeaverExceptionHandler { public ILLabel? TryStart { get; set; } public ILLabel? TryEnd { get; set; } public ILLabel? HandlerStart { get; set; } public ILLabel? HandlerEnd { get; set; } } public static class MethodDefinitionExtensions { public static void ILWeave(this MethodDefinition method, ILManipulationInfo.Manipulator manipulator) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Expected O, but got Unknown //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Expected O, but got Unknown ILContext val = new ILContext(method); try { val.Invoke((Manipulator)delegate(ILContext il) { Action invokeOnManipulatorFinished; ILManipulationInfo info = new ILManipulationInfo(il, (MethodBase?)null, out invokeOnManipulatorFinished); manipulator(info); invokeOnManipulatorFinished(); }); } finally { ((IDisposable)val)?.Dispose(); } } } } namespace MonoDetour.Cil.Analysis { internal static class CilAnalyzer { internal static IInformationalMethodBody AnnotateErrors(this IInformationalMethodBody informationalBody) { List list = informationalBody.InformationalInstructions.ToList(); list.Sort((IInformationalInstruction x, IInformationalInstruction y) => x.RelativeDistance - y.RelativeDistance); List list2 = list; IInformationalInstruction informationalInstruction = list.FirstOrDefault((IInformationalInstruction x) => x.ErrorAnnotations.Any((IInformationalInstruction.IAnnotation annotation) => annotation is InformationalInstruction.AnnotationStackSizeMismatch)); if (informationalInstruction != null) { List list3 = informationalInstruction.CollectIncoming().ToList(); list3.Sort((IInformationalInstruction x, IInformationalInstruction y) => x.RelativeDistance - y.RelativeDistance); list2 = list3; } HashSet types = new HashSet(); foreach (IInformationalInstruction item in list2) { AnalyzeAndAnnotateInstruction(item, types); } return informationalBody; } private static void AnalyzeAndAnnotateInstruction(IInformationalInstruction instruction, HashSet types) { //IL_0175: Unknown result type (might be due to invalid IL or missing references) //IL_017a: Unknown result type (might be due to invalid IL or missing references) //IL_017e: Unknown result type (might be due to invalid IL or missing references) //IL_0184: Invalid comparison between Unknown and I4 //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) int stackSize = instruction.StackSize; ReadOnlyCollection handlerInfos = instruction.HandlerInfos; if (!instruction.IsReachable) { return; } if (instruction.StackPop > instruction.IncomingStackSize) { if (types.Contains(typeof(InformationalInstruction.AnnotationPoppingMoreThanStackSize))) { return; } types.Add(typeof(InformationalInstruction.AnnotationPoppingMoreThanStackSize)); int num = 0; object operand = instruction.Instruction.Operand; IMethodSignature val = (IMethodSignature)((operand is IMethodSignature) ? operand : null); if (val != null) { Enumerator enumerator = val.Parameters.GetEnumerator(); try { while (enumerator.MoveNext()) { ParameterDefinition current = enumerator.Current; if (current.IsOptional) { num++; } } } finally { ((IDisposable)enumerator/*cast due to .constrained prefix*/).Dispose(); } } string text = $"Error: Popping more than stack size; cannot pop {instruction.StackPop} " + $"value(s) when stack size was {instruction.IncomingStackSize}"; if (num > 0) { text += ". Tip: Optional parameters are required in CIL - they are a C# compile-time feature."; } instruction.ErrorAnnotations.Add(new InformationalInstruction.AnnotationPoppingMoreThanStackSize(text)); } else if (stackSize != 0 && handlerInfos.Any((IInformationalInstruction.IHandlerInfo x) => x.HandlerPart.HasFlag(IInformationalInstruction.HandlerPart.BeforeTryStart))) { if (!types.Contains(typeof(InformationalInstruction.AnnotationStackSizeMustBeX))) { types.Add(typeof(InformationalInstruction.AnnotationStackSizeMustBeX)); instruction.ErrorAnnotations.Add(new InformationalInstruction.AnnotationStackSizeMustBeX($"Error: Stack size before try start must be 0; it was {stackSize}", new InformationalInstruction.AnnotationRangeWalkBack(instruction, stackSize))); } } else if (stackSize != 0) { OpCode opCode = instruction.Instruction.OpCode; if ((int)((OpCode)(ref opCode)).FlowControl == 7 && !types.Contains(typeof(InformationalInstruction.AnnotationStackSizeMustBeX))) { types.Add(typeof(InformationalInstruction.AnnotationStackSizeMustBeX)); instruction.ErrorAnnotations.Add(new InformationalInstruction.AnnotationStackSizeMustBeX($"Error: Stack size on return must be 0; it was {stackSize}", new InformationalInstruction.AnnotationRangeWalkBack(instruction, stackSize))); } } } } public interface IInformationalInstruction { public interface IAnnotation { } public interface IHandlerInfo { HandlerPart HandlerPart { get; } ExceptionHandler Handler { get; } void Deconstruct(out HandlerPart handlerPart, out ExceptionHandler exceptionHandler); } [Flags] public enum HandlerPart { None = 0, TryStart = 1, TryEnd = 2, FilterStart = 4, HandlerStart = 8, HandlerEnd = 0x10, BeforeTryStart = 0x20, TryOrHandlerEnd = 0x12, FilterOrHandlerStart = 0xC } HashSet IncomingBranches { get; } IInformationalInstruction? PreviousChronological { get; } IInformationalInstruction? Previous { get; } IInformationalInstruction? Next { get; } Instruction Instruction { get; } int StackSize { get; } int IncomingStackSize { get; } int StackDelta { get; } int StackPop { get; } int StackPush { get; } int RelativeDistance { get; } bool IsReachable { get; } bool IsEvaluated { get; } List ErrorAnnotations { get; } bool HasErrorAnnotations { get; } ReadOnlyCollection HandlerInfos { get; } HashSet CollectIncoming(); new string ToString(); string ToStringWithAnnotations(); } internal sealed class InformationalInstruction : IInformationalInstruction { internal class HandlerInfo(IInformationalInstruction.HandlerPart handlerPart, ExceptionHandler handler) : IInformationalInstruction.IHandlerInfo { public IInformationalInstruction.HandlerPart HandlerPart => handlerPart; public ExceptionHandler Handler => handler; public void Deconstruct(out IInformationalInstruction.HandlerPart part, out ExceptionHandler exceptionHandler) { part = HandlerPart; exceptionHandler = Handler; } } public class AnnotationStackSizeMustBeX : Annotation { public AnnotationStackSizeMustBeX(string Message, AnnotationRange? Range) : base(Message, Range) { } public override string ToString() { return base.ToString(); } } public class AnnotationPoppingMoreThanStackSize : Annotation { public AnnotationPoppingMoreThanStackSize(string Message) : base(Message, null) { } public override string ToString() { return base.ToString(); } } public class AnnotationDuplicateInstance : Annotation { public AnnotationDuplicateInstance() : base("Warning: Duplicate instruction instance; This may break the method and analysis.", null) { } public override string ToString() { return base.ToString(); } } public class AnnotationNullOperand : Annotation { public AnnotationNullOperand() : base("Error: Operand is null", null) { } public override string ToString() { return base.ToString(); } } public class AnnotationNullSwitchTarget : Annotation { public AnnotationNullSwitchTarget() : base("Error: Null switch target", null) { } public override string ToString() { return base.ToString(); } } public class AnnotationStackSizeMismatch : Annotation { private readonly string message; public AnnotationStackSizeMismatch(string Message, InformationalInstruction MismatchInstruction) { P = MismatchInstruction; message = Message; base..ctor(Message, null); } public override string ToString() { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append(message); HashSet incomingBranches = P.IncomingBranches; string variableEmptyPad = VariableEmptyPad; IInformationalInstruction informationalInstruction = incomingBranches.Last(); foreach (IInformationalInstruction item in incomingBranches) { if (item == informationalInstruction) { break; } stringBuilder.Append(", ").Append(item.StackSize); } stringBuilder.Append(" and ").AppendLine(informationalInstruction.StackSize.ToString(CultureInfo.InvariantCulture)); IInformationalInstruction previousChronological = P.PreviousChronological; if (previousChronological == null) { stringBuilder.Append(variableEmptyPad).AppendLine("│ Info: Previous instruction:"); stringBuilder.Append(variableEmptyPad).Append("├ ").AppendLine(" 0 | "); } else if (!incomingBranches.Contains(previousChronological)) { stringBuilder.Append(variableEmptyPad).AppendLine("│ Info: Previous instruction:"); stringBuilder.Append(variableEmptyPad).Append("├ ").AppendLine(previousChronological.ToString()); } stringBuilder.Append(variableEmptyPad).AppendLine("│ Info: Incoming branches:"); foreach (IInformationalInstruction item2 in incomingBranches) { if (item2 == informationalInstruction) { break; } stringBuilder.Append(variableEmptyPad).Append("├ ").AppendLine(item2.ToString()); } stringBuilder.Append(variableEmptyPad).Append("└ ").Append(informationalInstruction.ToString()); return stringBuilder.ToString(); } } public class Annotation(string Message, AnnotationRange? Range) : IInformationalInstruction.IAnnotation { public override string ToString() { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append(Message); if (Range == null || Range.Instructions.Count == 0) { return stringBuilder.ToString(); } List instructions = Range.Instructions; int num = 0; int num2 = instructions.Count - 1; string variableEmptyPad = VariableEmptyPad; stringBuilder.AppendLine(); stringBuilder.Append(variableEmptyPad).AppendLine("│ Info: Stack imbalance starts at:"); if (num != num2) { stringBuilder.Append(variableEmptyPad).Append("├ ").AppendLine(instructions[num].ToString()); } for (int i = num + 1; i < num2; i++) { stringBuilder.Append(variableEmptyPad).Append("│ ").AppendLine(instructions[i].ToString()); } stringBuilder.Append(variableEmptyPad).Append("└ ").Append(instructions[num2].ToString()); return stringBuilder.ToString(); } } public class AnnotationRangeWalkBack : AnnotationRange { public AnnotationRangeWalkBack(IInformationalInstruction Instruction, int RequiredStackSize) : base(GetProblematicInstructionsWithWalkBack(Instruction, RequiredStackSize)) { } } public class AnnotationRange(List Instructions) { public List Instructions { get; } = Instructions; } internal InformationalInstruction? next; internal IReadOnlyMonoDetourHook? source; internal bool isFromILHook; private bool explored; internal const char LongPipe = '│'; internal const char LeftWall = '│'; internal const string Spacer25Chars = " "; private const int SpaceForId = 25; private const int SpaceForIdMinus1 = 24; internal const string EmptyPad = "│ ¦ "; internal static string VariableEmptyPad = string.Format("{0} {1} ¦ ", '│', " "); public HashSet IncomingBranches { get; private set; } public IInformationalInstruction? PreviousChronological { get; internal set; } public IInformationalInstruction? Previous { get; internal set; } public IInformationalInstruction? Next => next; public Instruction Instruction => P; public int StackSize { get; private set; } public int StackDelta { get; private set; } public int IncomingStackSize => PreviousChronological?.StackSize ?? (HandlerParts.Any((IInformationalInstruction.IHandlerInfo x) => (x.HandlerPart & IInformationalInstruction.HandlerPart.FilterOrHandlerStart) != 0) ? 1 : 0); public int StackPop { get; private set; } public int StackPush { get; private set; } public int RelativeDistance { get; internal set; } public bool IsReachable { get; private set; } public bool IsEvaluated => explored; public List HandlerParts => P; public ReadOnlyCollection HandlerInfos => HandlerParts.AsReadOnly(); public List ErrorAnnotations { get; } public bool HasErrorAnnotations => ErrorAnnotations.Count != 0; public InformationalInstruction(Instruction instruction, IReadOnlyMonoDetourHook? source, bool isFromILHook, List handlerParts) { P = instruction; P = handlerParts; IncomingBranches = new HashSet(); this.source = source; this.isFromILHook = isFromILHook; ErrorAnnotations = new List(); base..ctor(); } public override string ToString() { return ToStringInternal(withAnnotations: false); } public string ToStringWithAnnotations() { return ToStringInternal(withAnnotations: true); } internal string ToStringInternal(bool withAnnotations) { //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_034f: Unknown result type (might be due to invalid IL or missing references) //IL_0354: Unknown result type (might be due to invalid IL or missing references) //IL_0358: Unknown result type (might be due to invalid IL or missing references) //IL_035d: Unknown result type (might be due to invalid IL or missing references) //IL_035f: Unknown result type (might be due to invalid IL or missing references) //IL_0363: Unknown result type (might be due to invalid IL or missing references) //IL_0366: Invalid comparison between Unknown and I4 //IL_0368: Unknown result type (might be due to invalid IL or missing references) //IL_036b: Unknown result type (might be due to invalid IL or missing references) //IL_036d: Invalid comparison between Unknown and I4 //IL_0110: Unknown result type (might be due to invalid IL or missing references) //IL_0116: Invalid comparison between Unknown and I4 //IL_0127: Unknown result type (might be due to invalid IL or missing references) StringBuilder stringBuilder = new StringBuilder(); if (withAnnotations) { IInformationalInstruction.HandlerPart handlerPart; ExceptionHandler exceptionHandler; foreach (IInformationalInstruction.IHandlerInfo handlerPart4 in HandlerParts) { handlerPart4.Deconstruct(out handlerPart, out exceptionHandler); IInformationalInstruction.HandlerPart handlerPart2 = handlerPart; ExceptionHandler val = exceptionHandler; if (handlerPart2.HasFlag(IInformationalInstruction.HandlerPart.TryEnd)) { stringBuilder.AppendLine("│ ¦ } // end try"); } if (handlerPart2.HasFlag(IInformationalInstruction.HandlerPart.HandlerEnd)) { stringBuilder.AppendLine(HandlerTypeToStringEnd(val.HandlerType)); } } foreach (IInformationalInstruction.IHandlerInfo handlerPart5 in HandlerParts) { handlerPart5.Deconstruct(out handlerPart, out exceptionHandler); IInformationalInstruction.HandlerPart handlerPart3 = handlerPart; ExceptionHandler val2 = exceptionHandler; if (handlerPart3.HasFlag(IInformationalInstruction.HandlerPart.TryStart)) { stringBuilder.AppendLine("│ ¦ .try\n│ ¦ {"); } if (handlerPart3.HasFlag(IInformationalInstruction.HandlerPart.FilterStart)) { stringBuilder.AppendLine("│ ¦ filter\n│ ¦ {"); } if (handlerPart3.HasFlag(IInformationalInstruction.HandlerPart.HandlerStart)) { if ((int)val2.HandlerType == 1) { stringBuilder.AppendLine("│ ¦ } // end filter"); } stringBuilder.AppendLine(HandlerTypeToStringStart(val2.HandlerType, ((object)val2.CatchType)?.ToString())); } } } string value = ((!isFromILHook) ? " " : Truncate(source?.Owner.Id ?? "").PadRight(25)); if (!IsEvaluated) { stringBuilder.Append('│').Append(' ').Append(value) .Append(" - | ") .Append(Instruction.ToStringSafe()); } else { string value2 = StackSize.ToString(CultureInfo.InvariantCulture).PadLeft(2); if (withAnnotations) { TryAppendIncomingBranchesInfo(stringBuilder, IncomingBranches); stringBuilder.Append('│').Append(' ').Append(value) .Append(value2) .Append(" | ") .Append(Instruction.ToStringSafe()); } else { stringBuilder.Append(value2).Append(" | ").Append(Instruction.ToStringSafe()); } } if (withAnnotations) { if (HasErrorAnnotations) { string text = string.Format("{0} {1}", '│', " "); VariableEmptyPad = $"{text} {'│'} ¦ "; List errorAnnotations = ErrorAnnotations; IInformationalInstruction.IAnnotation annotation = errorAnnotations[errorAnnotations.Count - 1]; foreach (IInformationalInstruction.IAnnotation errorAnnotation in ErrorAnnotations) { stringBuilder.AppendLine(); if (errorAnnotation != annotation) { stringBuilder.Append(text).Append(" ├ "); } else { stringBuilder.Append(text).Append(" └ "); VariableEmptyPad = "│ ¦ "; } stringBuilder.Append(errorAnnotation.ToString()); } } else { OpCode opCode = Instruction.OpCode; FlowControl flowControl = ((OpCode)(ref opCode)).FlowControl; if (((int)flowControl == 0 || (int)flowControl == 3 || flowControl - 7 <= 1) ? true : false) { IInformationalInstruction? informationalInstruction = Next; if (informationalInstruction != null && !informationalInstruction.HandlerInfos.Any((IInformationalInstruction.IHandlerInfo x) => (x.HandlerPart & IInformationalInstruction.HandlerPart.TryOrHandlerEnd) != 0)) { stringBuilder.AppendLine().Append("│ ¦ "); } } } } return stringBuilder.ToString(); static string Truncate(string str) { if (str.Length <= 25) { return str; } return str.Substring(0, 24) + "…"; } } private static void TryAppendIncomingBranchesInfo(StringBuilder sb, IEnumerable incomingBranches) { if (incomingBranches.FirstOrDefault() == null) { return; } sb.Append("│ ¦ ┌ Incoming branches:"); foreach (IInformationalInstruction incomingBranch in incomingBranches) { sb.Append(" IL_"); sb.Append(incomingBranch.Instruction.Offset.ToString("x4", CultureInfo.InvariantCulture)); sb.Append(';'); } sb.AppendLine(); } private unsafe static string HandlerTypeToStringStart(ExceptionHandlerType handlerType, string? catchType) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Expected I4, but got Unknown return (int)handlerType switch { 0 => "│ ¦ catch (" + catchType + ")\n│ ¦ {", 1 => "│ ¦ catch (" + catchType + ")\n│ ¦ {", 4 => "│ ¦ fault\n│ ¦ {", 2 => "│ ¦ finally\n│ ¦ {", _ => throw new ArgumentOutOfRangeException(((object)(*(ExceptionHandlerType*)(&handlerType))/*cast due to .constrained prefix*/).ToString()), }; } private unsafe static string HandlerTypeToStringEnd(ExceptionHandlerType handlerType) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Expected I4, but got Unknown return (int)handlerType switch { 0 => "│ ¦ } // end catch", 1 => "│ ¦ } // end catch", 4 => "│ ¦ } // end fault", 2 => "│ ¦ } // end finally", _ => throw new ArgumentOutOfRangeException(((object)(*(ExceptionHandlerType*)(&handlerType))/*cast due to .constrained prefix*/).ToString()), }; } internal static void CrawlInstructions(InformationalInstruction instruction, Dictionary map, int stackSize, MethodBody body, int distance, bool outsideExceptionHandler = true) { //IL_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: Invalid comparison between Unknown and I4 InformationalInstruction informationalInstruction = instruction; while (true) { if (informationalInstruction.explored) { if (informationalInstruction.IncomingStackSize != stackSize) { if (!informationalInstruction.HasErrorAnnotations && distance >= 0) { informationalInstruction.ErrorAnnotations.Add(new AnnotationStackSizeMismatch("Error: Stack size mismatch; incoming stack size " + $"is both {informationalInstruction.IncomingStackSize}", informationalInstruction)); } break; } if (!outsideExceptionHandler || distance < 0 || distance >= informationalInstruction.RelativeDistance) { break; } } else { ComputeStackDelta(informationalInstruction, ref stackSize, body); informationalInstruction.explored = true; if (distance >= 0) { informationalInstruction.IsReachable = true; } } stackSize = informationalInstruction.StackSize; informationalInstruction.RelativeDistance = distance; distance = ((!outsideExceptionHandler) ? (distance + 1) : (distance + 10000)); TryCrawlBranch(informationalInstruction, map, stackSize, body, distance, outsideExceptionHandler); OpCode opCode = informationalInstruction.Instruction.OpCode; FlowControl flowControl = ((OpCode)(ref opCode)).FlowControl; if (((int)flowControl == 0 || flowControl - 7 <= 1) ? true : false) { break; } InformationalInstruction previousChronological = informationalInstruction; informationalInstruction = informationalInstruction.next; if (informationalInstruction == null) { break; } informationalInstruction.PreviousChronological = previousChronological; } } private static void TryCrawlBranch(InformationalInstruction informationalInstruction, Dictionary map, int stackSize, MethodBody body, int distance, bool outsideExceptionHandler) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Invalid comparison between Unknown and I4 //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Invalid comparison between Unknown and I4 Instruction instruction = informationalInstruction.Instruction; OpCode opCode = instruction.OpCode; OperandType operandType = ((OpCode)(ref opCode)).OperandType; InformationalInstruction informationalInstruction2; if ((int)operandType != 0) { if ((int)operandType == 10) { Instruction[] array = (Instruction[])((!(instruction.Operand is ILLabel[] array2)) ? ((Array)(instruction.Operand as Instruction[])) : ((Array)array2.Select((ILLabel x) => x.InteropGetTarget()).ToArray())); if (array == null) { informationalInstruction.ErrorAnnotations.Add(new AnnotationNullOperand()); return; } foreach (Instruction val in array) { if (val == null) { informationalInstruction.ErrorAnnotations.Add(new AnnotationNullSwitchTarget()); continue; } informationalInstruction2 = map[val]; informationalInstruction2.IncomingBranches.Add(informationalInstruction); if (!informationalInstruction2.explored) { informationalInstruction2.PreviousChronological = informationalInstruction; } CrawlInstructions(informationalInstruction2, map, stackSize, body, distance, outsideExceptionHandler); } return; } if ((int)operandType != 15) { return; } } object operand = instruction.Operand; ILLabel val2 = (ILLabel)((operand is ILLabel) ? operand : null); Instruction val3 = (Instruction)((val2 == null) ? ((object)/*isinst with value type is only supported in some contexts*/) : ((object)val2.InteropGetTarget())); if (val3 == null) { informationalInstruction.ErrorAnnotations.Add(new AnnotationNullOperand()); return; } informationalInstruction2 = map[val3]; informationalInstruction2.IncomingBranches.Add(informationalInstruction); if (!informationalInstruction2.explored) { informationalInstruction2.PreviousChronological = informationalInstruction; } CrawlInstructions(informationalInstruction2, map, stackSize, body, distance, outsideExceptionHandler); } private static void ComputeStackDelta(InformationalInstruction informationalInstruction, ref int stackSize, MethodBody body) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Invalid comparison between Unknown and I4 //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Invalid comparison between Unknown and I4 //IL_00ea: Unknown result type (might be due to invalid IL or missing references) //IL_00ef: Unknown result type (might be due to invalid IL or missing references) //IL_0106: Unknown result type (might be due to invalid IL or missing references) //IL_010c: Invalid comparison between Unknown and I4 //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Invalid comparison between Unknown and I4 //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Invalid comparison between Unknown and I4 //IL_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Invalid comparison between Unknown and I4 //IL_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: Invalid comparison between Unknown and I4 Instruction instruction = informationalInstruction.Instruction; int num = stackSize; OpCode opCode = instruction.OpCode; FlowControl flowControl = ((OpCode)(ref opCode)).FlowControl; if ((int)flowControl != 2) { if ((int)flowControl == 7) { if (instruction.OpCode == OpCodes.Ret && (int)((MethodReference)body.Method).ReturnType.MetadataType != 1) { stackSize--; informationalInstruction.StackPop = 1; } } else { ComputePopDelta(instruction, ref stackSize); informationalInstruction.StackPop = num - stackSize; int num2 = stackSize; ComputePushDelta(instruction, ref stackSize); informationalInstruction.StackPush = stackSize - num2; } } else { object operand = instruction.Operand; IMethodSignature val = (IMethodSignature)((operand is IMethodSignature) ? operand : null); if (val == null) { informationalInstruction.ErrorAnnotations.Add(new AnnotationNullOperand()); } else { if (val.HasThis && !val.ExplicitThis) { opCode = instruction.OpCode; if ((int)((OpCode)(ref opCode)).Code != 114) { stackSize--; } } if (val.HasParameters) { stackSize -= val.Parameters.Count; } opCode = instruction.OpCode; if ((int)((OpCode)(ref opCode)).Code == 40) { stackSize--; } informationalInstruction.StackPop = num - stackSize; if ((int)val.ReturnType.MetadataType == 1) { opCode = instruction.OpCode; if ((int)((OpCode)(ref opCode)).Code != 114) { goto IL_0142; } } stackSize++; informationalInstruction.StackPush = 1; } } goto IL_0142; IL_0142: informationalInstruction.StackSize = stackSize; informationalInstruction.StackDelta = stackSize - num; } private static void ComputePopDelta(Instruction instruction, ref int stack_size) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Expected I4, but got Unknown OpCode opCode = instruction.OpCode; StackBehaviour stackBehaviourPop = ((OpCode)(ref opCode)).StackBehaviourPop; switch (stackBehaviourPop - 1) { case 0: case 2: case 9: stack_size--; break; case 1: case 3: case 4: case 5: case 7: case 8: case 10: case 11: stack_size -= 2; break; case 6: case 12: case 13: case 14: case 15: case 16: stack_size -= 3; break; case 17: stack_size = 0; break; } } private static void ComputePushDelta(Instruction instruction, ref int stack_size) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Expected I4, but got Unknown OpCode opCode = instruction.OpCode; StackBehaviour stackBehaviourPush = ((OpCode)(ref opCode)).StackBehaviourPush; switch (stackBehaviourPush - 20) { case 0: case 2: case 3: case 4: case 5: case 6: stack_size++; break; case 1: stack_size += 2; break; } } internal static List GetProblematicInstructionsWithWalkBack(IInformationalInstruction instruction, int requiredStackSize) { Stack stack = new Stack(); int num = 0; IInformationalInstruction informationalInstruction = instruction; while (true) { stack.Push(informationalInstruction); num += informationalInstruction.StackDelta; if (num == requiredStackSize) { break; } IInformationalInstruction informationalInstruction2 = informationalInstruction.PreviousChronological; if (informationalInstruction2 == null) { break; } foreach (IInformationalInstruction incomingBranch in informationalInstruction.IncomingBranches) { if (incomingBranch.RelativeDistance < informationalInstruction2.RelativeDistance) { informationalInstruction2 = incomingBranch; } } informationalInstruction = informationalInstruction2; } Stack stack2 = stack; List list = new List(stack2.Count); foreach (IInformationalInstruction item in stack2) { list.Add(item); } return list; } public HashSet CollectIncoming() { HashSet collected = new HashSet(); CollectIncoming(this, ref collected); collected.Remove(this); return collected; } public static void CollectIncoming(IInformationalInstruction instruction, ref HashSet collected) { while (collected.Add(instruction)) { foreach (IInformationalInstruction incomingBranch in instruction.IncomingBranches) { CollectIncoming(incomingBranch, ref collected); } IInformationalInstruction previousChronological = instruction.PreviousChronological; if (previousChronological != null) { instruction = previousChronological; continue; } break; } } } public interface IInformationalMethodBody { MethodBody Body { get; } ReadOnlyCollection InformationalInstructions { get; } IInformationalInstruction GetInformationalInstruction(Instruction instruction); bool HasErrors(); new string ToString(); string ToStringWithAnnotations(); string ToStringWithAnnotationsExclusive(); } internal sealed class InformationalMethodBody : IInformationalMethodBody { private readonly Dictionary map = new Dictionary(); public MethodBody Body { get; } public ReadOnlyCollection InformationalInstructions { get; } public HashSet Duplicates { get; } = new HashSet(); public bool HasDuplicates => Duplicates.Count != 0; private InformationalMethodBody(MethodBody body) { //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: Unknown result type (might be due to invalid IL or missing references) //IL_0241: Unknown result type (might be due to invalid IL or missing references) //IL_0246: Unknown result type (might be due to invalid IL or missing references) Body = body; List list = new List(); Collection instructions = body.Instructions; if (instructions.Count == 0) { InformationalInstructions = list.AsReadOnly(); return; } HashSet hashSet = new HashSet(); Enumerator enumerator = instructions.GetEnumerator(); try { while (enumerator.MoveNext()) { Instruction current = enumerator.Current; if (!hashSet.Add(current)) { Duplicates.Add(current); } } } finally { ((IDisposable)enumerator/*cast due to .constrained prefix*/).Dispose(); } try { Extensions.RecalculateILOffsets(body.Method); } catch (Exception) { } InformationalInstruction instruction = null; InformationalInstruction informationalInstruction = null; HookTargetRecords.HookTargetInfo hookTargetInfo = HookTargetRecords.GetHookTargetInfo(body.Method); for (int i = 0; i < instructions.Count; i++) { Instruction val = instructions[i]; List list2 = new List(); Enumerator enumerator2 = body.ExceptionHandlers.GetEnumerator(); try { while (enumerator2.MoveNext()) { ExceptionHandler current2 = enumerator2.Current; IInformationalInstruction.HandlerPart handlerPart = IInformationalInstruction.HandlerPart.None; if (current2.TryStart.Previous == val) { handlerPart |= IInformationalInstruction.HandlerPart.BeforeTryStart; } if (current2.TryStart == val) { handlerPart |= IInformationalInstruction.HandlerPart.TryStart; } if (current2.TryEnd == val) { handlerPart |= IInformationalInstruction.HandlerPart.TryEnd; } if (current2.FilterStart == val) { handlerPart |= IInformationalInstruction.HandlerPart.FilterStart; } if (current2.HandlerStart == val) { handlerPart |= IInformationalInstruction.HandlerPart.HandlerStart; } if (current2.HandlerEnd == val) { handlerPart |= IInformationalInstruction.HandlerPart.HandlerEnd; } if (handlerPart != IInformationalInstruction.HandlerPart.None) { list2.Add(new InformationalInstruction.HandlerInfo(handlerPart, current2)); } } } finally { ((IDisposable)enumerator2/*cast due to .constrained prefix*/).Dispose(); } IReadOnlyMonoDetourHook value; bool flag = hookTargetInfo.InstructionToSource.TryGetValue(val, out value); if (!flag) { flag = !hookTargetInfo.OriginalInstructionsHashSet.Contains(val); } InformationalInstruction informationalInstruction2 = new InformationalInstruction(val, value, flag, list2); list.Add(informationalInstruction2); map[val] = informationalInstruction2; if (Duplicates.Contains(val)) { informationalInstruction2.ErrorAnnotations.Add(new InformationalInstruction.AnnotationDuplicateInstance()); } if (informationalInstruction == null) { instruction = informationalInstruction2; } else { informationalInstruction.next = informationalInstruction2; } informationalInstruction2.Previous = informationalInstruction; informationalInstruction = informationalInstruction2; } int stackSize = 0; InformationalInstruction.CrawlInstructions(instruction, map, stackSize, body, 0); Enumerator enumerator3 = body.ExceptionHandlers.GetEnumerator(); try { while (enumerator3.MoveNext()) { ExceptionHandler current3 = enumerator3.Current; if (map.TryGetValue(current3.TryStart, out InformationalInstruction value2) && value2.IsReachable) { CrawlExceptionHandler(current3); } } } finally { ((IDisposable)enumerator3/*cast due to .constrained prefix*/).Dispose(); } InformationalInstructions = list.AsReadOnly(); } public void CrawlExceptionHandler(ExceptionHandler handler) { //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Invalid comparison between Unknown and I4 int stackSize = 0; ExceptionHandlerType handlerType = handler.HandlerType; if ((int)handlerType <= 1) { stackSize = 1; } if (handler.HandlerStart != null && handler.HandlerEnd != null) { Instruction handlerStart = handler.HandlerStart; Instruction handlerEnd = handler.HandlerEnd; InformationalInstruction.CrawlInstructions(map[handlerStart], map, stackSize, Body, map[handlerEnd].RelativeDistance - 9000, outsideExceptionHandler: false); if (handler.FilterStart != null) { Instruction filterStart = handler.FilterStart; InformationalInstruction.CrawlInstructions(map[filterStart], map, stackSize, Body, map[handlerEnd].RelativeDistance - 10000 + 1, outsideExceptionHandler: false); } } } public static InformationalMethodBody CreateInformationalSnapshotJIT(MethodBody body) { return new InformationalMethodBody(body); } public static InformationalMethodBody CreateInformationalSnapshotEvaluateAll(MethodBody body) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) InformationalMethodBody informationalMethodBody = new InformationalMethodBody(body); Enumerator enumerator = body.ExceptionHandlers.GetEnumerator(); try { while (enumerator.MoveNext()) { ExceptionHandler current = enumerator.Current; if (current.HandlerEnd != null) { informationalMethodBody.map[current.HandlerEnd].RelativeDistance = -2147383648; informationalMethodBody.CrawlExceptionHandler(current); } } } finally { ((IDisposable)enumerator/*cast due to .constrained prefix*/).Dispose(); } foreach (IInformationalInstruction item in informationalMethodBody.InformationalInstructions.Where((IInformationalInstruction x) => !x.IsReachable)) { if (!(item is InformationalInstruction informationalInstruction)) { throw new InvalidCastException("Not InformationalInstruction!"); } informationalInstruction.PreviousChronological = informationalInstruction.Previous; int num = informationalInstruction.Previous.StackSize; if (num < 0) { num = 0; } InformationalInstruction.CrawlInstructions(informationalInstruction, informationalMethodBody.map, num, body, int.MinValue); } return informationalMethodBody; } public IInformationalInstruction GetInformationalInstruction(Instruction instruction) { if (map.TryGetValue(instruction, out InformationalInstruction value)) { return value; } throw new KeyNotFoundException(string.Format("The instruction '{0}' is not a part of the {1}.", instruction, "IInformationalMethodBody")); } public override string ToString() { return ((MemberReference)Body.Method).FullName + "\n" + ToStringWithAnnotations(); } public string ToStringWithAnnotations() { StringBuilder stringBuilder = new StringBuilder(); foreach (IInformationalInstruction informationalInstruction in InformationalInstructions) { stringBuilder.AppendLine(informationalInstruction.ToStringWithAnnotations()); } return stringBuilder.ToString(); } public string ToStringWithAnnotationsExclusive() { StringBuilder stringBuilder = new StringBuilder(); foreach (IInformationalInstruction item in InformationalInstructions.Where((IInformationalInstruction x) => x.HasErrorAnnotations)) { stringBuilder.AppendLine(item.ToStringWithAnnotations()); } return stringBuilder.ToString(); } public bool HasErrors() { if (Duplicates.Count != 0 || InformationalInstructions.Any((IInformationalInstruction x) => x.HasErrorAnnotations)) { return true; } return false; } internal void ThrowIfErrorAnnotations() { if (HasErrors()) { throw new Exception("Informational instructions had exception annotations."); } } internal void ThrowIfNoErrorAnnotations() { if (!HasErrors()) { throw new Exception("Informational instructions had exception annotations."); } } } internal static class IInformationalMethodBodyExtensions { internal static string ToErrorMessageString(this IInformationalMethodBody informationalBody) { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.AppendLine("An ILHook manipulation target method threw on compilation:"); stringBuilder.AppendLine(((MemberReference)informationalBody.Body.Method).FullName); stringBuilder.AppendLine("--- MonoDetour CIL Analysis Start Full Method ---"); stringBuilder.AppendLine(); stringBuilder.AppendLine("Info: Format is: | | \n If instruction is known to have existed initially, instruction source is left empty.\n MonoDetour only knows the exact instruction source if MonoDetour.Cil.ILWeaver was used."); stringBuilder.AppendLine(); if (informationalBody.InformationalInstructions.Count == 0) { stringBuilder.AppendLine("Method has 0 instructions."); } else { stringBuilder.Append(informationalBody.ToStringWithAnnotations()); stringBuilder.AppendLine(); stringBuilder.AppendLine("--- MonoDetour CIL Analysis Summary ---"); stringBuilder.AppendLine(); if (!informationalBody.HasErrors()) { stringBuilder.AppendLine("MonoDetour didn't catch any mistakes.").AppendLine("The errors may not be directly stack behavior related.").AppendLine("Operands or types on the stack aren't validated.") .AppendLine("You can improve the analysis:") .AppendLine("https://github.com/MonoDetour/MonoDetour/issues/28"); } else { stringBuilder.AppendLine("Info: Format is: | | "); stringBuilder.AppendLine(); stringBuilder.Append(informationalBody.ToStringWithAnnotationsExclusive()); stringBuilder.AppendLine(); stringBuilder.AppendLine("Note: This analysis may not be perfect.").AppendLine("In case of false positives, leave an issue: https://github.com/MonoDetour/MonoDetour/issues"); } } stringBuilder.AppendLine(); stringBuilder.Append("--- MonoDetour CIL Analysis End ---"); return stringBuilder.ToString(); } } public static class MethodBodyExtensions { public static IInformationalMethodBody CreateInformationalSnapshotJIT(this MethodBody body) { return InformationalMethodBody.CreateInformationalSnapshotJIT(body); } public static IInformationalMethodBody CreateInformationalSnapshotEvaluateAll(this MethodBody body) { return InformationalMethodBody.CreateInformationalSnapshotEvaluateAll(body); } } }