コード例 #1
0
        /*
         * Fix for detour jump overriding the method that's right next in memory
         * See https://github.com/MonoMod/MonoMod.Common/blob/58702d64645aba613ad16275c0b78278ff0d2055/RuntimeDetour/Platforms/Native/DetourNativeX86Platform.cs#L77
         *
         * It happens for any very small method, not just virtual, but it just so happens that
         * virtual methods are usually the only empty ones. The problem is with the detour code
         * overriding the method that's right next in memory.
         *
         * The 64bit absolute jump detour requires 14 bytes but on Linux an empty method is just
         * 10 bytes. On Windows, due to prologue differences, an empty method is exactly 14 bytes
         * as required.
         *
         * Now, the small code size wouldn't be a problem if it wasn't for the way Mono compiles
         * trampolines. Usually methods on x64 are 16 bytes aligned, so no actual code could get
         * overriden by the detour, but trampolines don't follow this rule and a trampoline generated
         * for the dynamic method from the patch is placed right after the method being detoured.
         *
         * The detour code then overrides the beggining of the trampoline and that leads to a
         * segfault on execution.
         *
         * There's also the fact that Linux seems to allocate the detour code far away in memory
         * so it uses the 64 bit jump in the first place. On Windows with Mono usually the 32 bit
         * smaller jumps suffice.
         *
         * The fix changes the order in which methods are JITted so that no trampoline is placed
         * after the detoured method (or at least the trampoline that causes this specific crash)
         */
        internal static void PadShortMethods(MethodBase method)
        {
            if (isWindows)
            {
                return;
            }
            var count = method.GetMethodBody()?.GetILAsByteArray()?.Length ?? 0;

            if (count == 0)
            {
                return;
            }

            // the 16 here is arbitrary but high enough to prevent the jitted code from getting under 14 bytes
            // and high enough to not generate too many fix methods
            if (count >= 16)
            {
                return;
            }

            var methodDef = new DynamicMethodDefinition($"PadMethod-{Guid.NewGuid()}", typeof(void), new Type[0]);

            methodDef.GetILGenerator().Emit(OpCodes.Ret);
            _ = GetMethodStart(methodDef.Generate(), out var _);             // trigger allocation/generation of jitted assembler
        }
コード例 #2
0
ファイル: PatchProcessor.cs プロジェクト: walterhcain/Harmony
        /// <summary>A low level way to read the body of a method. Used for quick searching in methods</summary>
        /// <param name="method">The original method</param>
        /// <returns>All instructions as opcode/operand pairs</returns>
        ///
        public static IEnumerable <KeyValuePair <OpCode, object> > ReadMethodBody(MethodBase method)
        {
            var dummyMethod = new DynamicMethodDefinition($"{method.Name}_Dummy{Guid.NewGuid()}", typeof(void), new Type[0]);

            return(MethodBodyReader.GetInstructions(dummyMethod.GetILGenerator(), method)
                   .Select(instr => new KeyValuePair <OpCode, object>(instr.opcode, instr.operand)));
        }
コード例 #3
0
ファイル: AccessTools.cs プロジェクト: ICanHazCode/HarmonyX
        /// <summary>Creates a field reference</summary>
        /// <typeparam name="T">The class the field is defined in or "object" if type cannot be accessed at compile time</typeparam>
        /// <typeparam name="U">The type of the field</typeparam>
        /// <param name="fieldInfo">FieldInfo for the field</param>
        /// <returns>A read and writable field reference</returns>
        ///
        public static FieldRef <T, U> FieldRefAccess <T, U>(FieldInfo fieldInfo)
        {
            if (fieldInfo == null)
            {
                throw new ArgumentNullException(nameof(fieldInfo));
            }
            if (!typeof(U).IsAssignableFrom(fieldInfo.FieldType))
            {
                throw new ArgumentException("FieldInfo type does not match FieldRefAccess return type.");
            }
            if (typeof(T) != typeof(object))
            {
                if (fieldInfo.DeclaringType == null || !fieldInfo.DeclaringType.IsAssignableFrom(typeof(T)))
                {
                    throw new MissingFieldException(typeof(T).Name, fieldInfo.Name);
                }
            }

            var dm = new DynamicMethodDefinition($"__refget_{typeof(T).Name}_fi_{fieldInfo.Name}", typeof(U).MakeByRefType(), new[] { typeof(T) });

            var il = dm.GetILGenerator();

            il.Emit(OpCodes.Ldarg_0);
            il.Emit(OpCodes.Ldflda, fieldInfo);
            il.Emit(OpCodes.Ret);

            return((FieldRef <T, U>)dm.Generate().CreateDelegate <FieldRef <T, U> >());
        }
コード例 #4
0
ファイル: MethodPatcher.cs プロジェクト: riQQ/HarmonyX
        private DynamicMethodDefinition GenerateManagedOriginal()
        {
            // Here we generate the "managed" version of the native method
            // It simply calls the trampoline generated by MonoMod
            // As a result, we can pass the managed original to HarmonyManipulator like a normal method

            var orig = Original;

            var dmd = new DynamicMethodDefinition($"NativeDetour<{orig.GetID(simple: true)}>", _returnType, _argTypes);

            dmd.Definition.Name += $"?{dmd.GetHashCode()}";

            var def = dmd.Definition;

            for (var i = 0; i < _argTypeNames.Length; i++)
            {
                def.Parameters[i].Name = _argTypeNames[i];
            }

            var il = dmd.GetILGenerator();

            il.Emit(OpCodes.Ldc_I4, dmd.GetHashCode());
            il.Emit(OpCodes.Call, GetTrampolineMethod);
            for (var i = 0; i < _argTypes.Length; i++)
            {
                il.Emit(OpCodes.Ldarg, i);
            }
            il.Emit(OpCodes.Call, _invokeTrampolineMethod);
            il.Emit(OpCodes.Ret);

            return(dmd);
        }
コード例 #5
0
ファイル: Tools.cs プロジェクト: Windows10CE/Harmony
        internal static FieldRef <T, F> FieldRefAccess <T, F>(FieldInfo fieldInfo, bool needCastclass)
        {
            ValidateFieldType <F>(fieldInfo);
            var delegateInstanceType = typeof(T);
            var declaringType        = fieldInfo.DeclaringType;

            var dm = new DynamicMethodDefinition($"__refget_{delegateInstanceType.Name}_fi_{fieldInfo.Name}",
                                                 typeof(F).MakeByRefType(), new[] { delegateInstanceType });

            var il = dm.GetILGenerator();

            // Backwards compatibility: This supports static fields, even those defined in structs.
            if (fieldInfo.IsStatic)
            {
                // ldarg.0 + ldflda actually works for static fields, but the potential castclass (and InvalidCastException) below must be avoided
                // so might as well use the singular ldsflda for static fields.
                il.Emit(OpCodes.Ldsflda, fieldInfo);
            }
            else
            {
                il.Emit(OpCodes.Ldarg_0);
                // The castclass is needed when T is a parent class or interface of declaring type (e.g. if T is object),
                // since there's no guarantee the instance passed to the delegate is actually of the declaring type.
                // In such a situation, the castclass will throw an InvalidCastException and thus prevent undefined behavior.
                if (needCastclass)
                {
                    il.Emit(OpCodes.Castclass, declaringType);
                }
                il.Emit(OpCodes.Ldflda, fieldInfo);
            }
            il.Emit(OpCodes.Ret);

            return((FieldRef <T, F>)dm.Generate().CreateDelegate(typeof(FieldRef <T, F>)));
        }
コード例 #6
0
ファイル: MethodPatcher.cs プロジェクト: CyberShadow/Harmony
        internal MethodPatcher(MethodBase original, MethodBase source, string harmonyInstanceID, List <MethodInfo> prefixes, List <MethodInfo> postfixes, List <MethodInfo> transpilers, List <MethodInfo> finalizers)
        {
            if (original == null)
            {
                throw new ArgumentNullException(nameof(original));
            }

            this.original          = original;
            this.source            = source;
            this.harmonyInstanceID = harmonyInstanceID;
            this.prefixes          = prefixes;
            this.postfixes         = postfixes;
            this.transpilers       = transpilers;
            this.finalizers        = finalizers;

            Memory.MarkForNoInlining(original);

            if (Harmony.DEBUG)
            {
                FileLog.LogBuffered($"### Patch {original.FullDescription()}");
                FileLog.FlushBuffer();
            }

            idx = prefixes.Count() + postfixes.Count() + finalizers.Count();
            firstArgIsReturnBuffer = NativeThisPointer.NeedsNativeThisPointerFix(original);
            returnType             = AccessTools.GetReturnedType(original);
            patch = CreateDynamicMethod(original, $"_Patch{idx}");
            if (patch == null)
            {
                throw new Exception("Could not create dynamic method");
            }

            il      = patch.GetILGenerator();
            emitter = new Emitter(il);
        }
コード例 #7
0
        public static MethodInfo Prefix(MethodBase method)
        {
            var dynamicMethod = new DynamicMethodDefinition(method.Name + "_Class11Patch_Prefix", typeof(bool),
                                                            new[] { typeof(string).MakeByRefType(), typeof(int) });

            dynamicMethod.Definition.Parameters[0].Name = "__result";
            dynamicMethod.Definition.Parameters[1].Name = "dummy";

            var il = dynamicMethod.GetILGenerator();

            //load "patched" into __result
            il.Emit(OpCodes.Ldarg_0);
            il.Emit(OpCodes.Ldstr, "patched");
            il.Emit(OpCodes.Stind_Ref);

            //set prefixed to true
            il.Emit(OpCodes.Ldnull);
            il.Emit(OpCodes.Ldc_I4_1);
            il.Emit(OpCodes.Stfld, typeof(Class11Patch).GetField(nameof(prefixed)));

            //return false
            il.Emit(OpCodes.Ldc_I4_0);
            il.Emit(OpCodes.Ret);

            return(dynamicMethod.Generate());
        }
コード例 #8
0
ファイル: Memory.cs プロジェクト: Windows10CE/Harmony
        /*
         * Fix for detour jump overriding the method that's right next in memory
         * See https://github.com/MonoMod/MonoMod.Common/blob/58702d64645aba613ad16275c0b78278ff0d2055/RuntimeDetour/Platforms/Native/DetourNativeX86Platform.cs#L77
         *
         * It happens for any very small method, not just virtual, but it just so happens that
         * virtual methods are usually the only empty ones. The problem is with the detour code
         * overriding the method that's right next in memory.
         *
         * The 64bit absolute jump detour requires 14 bytes but on Linux an empty method is just
         * 10 bytes. On Windows, due to prologue differences, an empty method is exactly 14 bytes
         * as required.
         *
         * Now, the small code size wouldn't be a problem if it wasn't for the way Mono compiles
         * trampolines. Usually methods on x64 are 16 bytes aligned, so no actual code could get
         * overriden by the detour, but trampolines don't follow this rule and a trampoline generated
         * for the dynamic method from the patch is placed right after the method being detoured.
         *
         * The detour code then overrides the beggining of the trampoline and that leads to a
         * segfault on execution.
         *
         * There's also the fact that Linux seems to allocate the detour code far away in memory
         * so it uses the 64 bit jump in the first place. On Windows with Mono usually the 32 bit
         * smaller jumps suffice.
         *
         * The fix changes the order in which methods are JITted so that no trampoline is placed
         * after the detoured method (or at least the trampoline that causes this specific crash)
         */
        internal static void PadShortMethods(MethodBase method)
        {
            if (isWindows)
            {
                return;
            }
            var count = method.GetMethodBody()?.GetILAsByteArray()?.Length ?? 0;

            if (count == 0)
            {
                return;
            }

            // the 16 here is arbitrary but high enough to prevent the jitted code from getting under 14 bytes
            // and high enough to not generate too many fix methods
            if (count >= 16)
            {
                return;
            }

            var methodDef = new DynamicMethodDefinition($"PadMethod-{Guid.NewGuid()}", typeof(void), new Type[0]);

            methodDef.GetILGenerator().Emit(OpCodes.Ret);

            // invoke the method so that it generates a trampoline that will later get overridden by the detour code
            _ = methodDef.Generate().Invoke(null, null);
        }
コード例 #9
0
ファイル: Transpilers.cs プロジェクト: ICanHazCode/HarmonyX
        /// <summary>
        /// Returns an instruction to call the specified delegate.
        /// </summary>
        /// <typeparam name="T">The delegate type to emit.</typeparam>
        /// <param name="action">The delegate to emit.</param>
        /// <returns>The instruction to </returns>
        public static CodeInstruction EmitDelegate <T>(T action) where T : Delegate
        {
            if (action.Method.IsStatic && action.Target == null)
            {
                return(new CodeInstruction(OpCodes.Call, action.Method));
            }

            var paramTypes = action.Method.GetParameters().Select(x => x.ParameterType).ToArray();

            var dynamicMethod = new DynamicMethodDefinition(action.Method.Name,
                                                            action.Method.ReturnType,
                                                            paramTypes);

            var il = dynamicMethod.GetILGenerator();

            var targetType = action.Target.GetType();

            var preserveContext = action.Target != null && targetType.GetFields().Any(x => !x.IsStatic);

            if (preserveContext)
            {
                var currentDelegateCounter = _delegateCounter++;

                _delegateCache[currentDelegateCounter] = action;

                var cacheField = AccessTools.Field(typeof(Transpilers), nameof(_delegateCache));

                var getMethod = AccessTools.Method(typeof(Dictionary <int, Delegate>), "get_Item");

                il.Emit(OpCodes.Ldsfld, cacheField);
                il.Emit(OpCodes.Ldc_I4, currentDelegateCounter);
                il.Emit(OpCodes.Callvirt, getMethod);
            }
            else
            {
                if (action.Target == null)
                {
                    il.Emit(OpCodes.Ldnull);
                }
                else
                {
                    il.Emit(OpCodes.Newobj, AccessTools.FirstConstructor(targetType, x => x.GetParameters().Length == 0 && !x.IsStatic));
                }

                il.Emit(OpCodes.Ldftn, action.Method);
                il.Emit(OpCodes.Newobj, AccessTools.Constructor(typeof(T), new[] { typeof(object), typeof(IntPtr) }));
            }


            for (var i = 0; i < paramTypes.Length; i++)
            {
                il.Emit(OpCodes.Ldarg_S, (short)i);
            }

            il.Emit(OpCodes.Callvirt, typeof(T).GetMethod("Invoke"));

            il.Emit(OpCodes.Ret);

            return(new CodeInstruction(OpCodes.Call, dynamicMethod.Generate()));
        }
コード例 #10
0
ファイル: PatchProcessor.cs プロジェクト: walterhcain/Harmony
        /// <summary>Returns the methods unmodified list of code instructions</summary>
        /// <param name="original">The original method/constructor</param>
        /// <param name="generator">A new generator that now contains all local variables and labels contained in the result</param>
        /// <returns>A list containing all the original <see cref="CodeInstruction"/></returns>
        ///
        public static List <CodeInstruction> GetOriginalInstructions(MethodBase original, out ILGenerator generator)
        {
            var method = new DynamicMethodDefinition($"{original.Name}_Dummy{Guid.NewGuid()}", typeof(void), new Type[0]);

            generator = method.GetILGenerator();
            var reader = MethodBodyReader.GetInstructions(generator, original);

            return(reader.Select(ins => ins.GetCodeInstruction()).ToList());
        }
コード例 #11
0
        static ILHookExtensions()
        {
            var detourGetter = new DynamicMethodDefinition("GetDetour", typeof(Detour), new[] { typeof(ILHook) });
            var il           = detourGetter.GetILGenerator();

            il.Emit(OpCodes.Ldarg_0);
            il.Emit(OpCodes.Call, AccessTools.PropertyGetter(typeof(ILHook), "_Ctx"));
            il.Emit(OpCodes.Ldfld, AccessTools.Field(AccessTools.Inner(typeof(ILHook), "Context"), "Detour"));
            il.Emit(OpCodes.Ret);
            GetAppliedDetour = detourGetter.Generate().CreateDelegate <Func <ILHook, Detour> >() as Func <ILHook, Detour>;
        }
コード例 #12
0
        /// <summary>Creates a new <see cref="ILGenerator">generator</see> matching the method/constructor to use when reading method bodies</summary>
        /// <param name="original">The original method/constructor to copy method information from</param>
        /// <returns>A new <see cref="ILGenerator"/></returns>
        ///
        public static ILGenerator CreateILGenerator(MethodBase original)
        {
            var returnType     = original is MethodInfo m ? m.ReturnType : typeof(void);
            var parameterTypes = original.GetParameters().Select(pi => pi.ParameterType).ToList();

            if (original.IsStatic is false)
            {
                parameterTypes.Insert(0, original.DeclaringType);
            }
            var method = new DynamicMethodDefinition($"ILGenerator_{original.Name}", returnType, parameterTypes.ToArray());

            return(method.GetILGenerator());
        }
コード例 #13
0
ファイル: Tools.cs プロジェクト: Windows10CE/Harmony
        internal static StructFieldRef <T, F> StructFieldRefAccess <T, F>(FieldInfo fieldInfo) where T : struct
        {
            ValidateFieldType <F>(fieldInfo);

            var dm = new DynamicMethodDefinition($"__refget_{typeof(T).Name}_struct_fi_{fieldInfo.Name}",
                                                 typeof(F).MakeByRefType(), new[] { typeof(T).MakeByRefType() });

            var il = dm.GetILGenerator();

            il.Emit(OpCodes.Ldarg_0);
            il.Emit(OpCodes.Ldflda, fieldInfo);
            il.Emit(OpCodes.Ret);

            return((StructFieldRef <T, F>)dm.Generate().CreateDelegate(typeof(StructFieldRef <T, F>)));
        }
コード例 #14
0
        public static InstantiationHandler CreateInstantiationHandler(Type type)
        {
            var constructorInfo = type.GetConstructor(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance, null, new Type[0], null);

            if (constructorInfo is null)
            {
                throw new ApplicationException(string.Format("The type {0} must declare an empty constructor (the constructor may be private, internal, protected, protected internal, or public).", type));
            }
            var dynamicMethod = new DynamicMethodDefinition($"InstantiateObject_{type.Name}", type, null);
            var generator     = dynamicMethod.GetILGenerator();

            generator.Emit(OpCodes.Newobj, constructorInfo);
            generator.Emit(OpCodes.Ret);
            return((InstantiationHandler)dynamicMethod.Generate().CreateDelegate(typeof(InstantiationHandler)));
        }
コード例 #15
0
        /// <summary>Returns an instruction to call the specified closure</summary>
        /// <typeparam name="T">The delegate type to emit</typeparam>
        /// <param name="closure">The closure that defines the method to call</param>
        /// <returns>A <see cref="CodeInstruction"/> that calls the closure as a method</returns>
        ///
        public static CodeInstruction CallClosure <T>(T closure) where T : Delegate
        {
            if (closure.Method.IsStatic && closure.Target == null)
            {
                return(new CodeInstruction(OpCodes.Call, closure.Method));
            }

            var parameters    = closure.Method.GetParameters().Select(x => x.ParameterType).ToArray();
            var closureMethod = new DynamicMethodDefinition(closure.Method.Name, closure.Method.ReturnType, parameters);

            var il         = closureMethod.GetILGenerator();
            var targetType = closure.Target.GetType();

            var preserveContext = closure.Target != null && targetType.GetFields().Any(x => !x.IsStatic);

            if (preserveContext)
            {
                var n = State.closureCache.Count;
                State.closureCache[n] = closure;
                il.Emit(OpCodes.Ldsfld, AccessTools.Field(typeof(Transpilers), nameof(State.closureCache)));
                il.Emit(OpCodes.Ldc_I4, n);
                il.Emit(OpCodes.Callvirt, AccessTools.PropertyGetter(typeof(Dictionary <int, Delegate>), "Item"));
            }
            else
            {
                if (closure.Target == null)
                {
                    il.Emit(OpCodes.Ldnull);
                }
                else
                {
                    il.Emit(OpCodes.Newobj, AccessTools.FirstConstructor(targetType, x => x.IsStatic == false && x.GetParameters().Length == 0));
                }

                il.Emit(OpCodes.Ldftn, closure.Method);
                il.Emit(OpCodes.Newobj, AccessTools.Constructor(typeof(T), new[] { typeof(object), typeof(IntPtr) }));
            }

            for (var i = 0; i < parameters.Length; i++)
            {
                il.Emit(OpCodes.Ldarg, i);
            }

            il.Emit(OpCodes.Callvirt, AccessTools.Method(typeof(T), nameof(Action.Invoke)));
            il.Emit(OpCodes.Ret);

            return(new CodeInstruction(OpCodes.Call, closureMethod.Generate()));
        }
コード例 #16
0
        private static Delegate CreateGetStaticFieldDelegate <TField>(FieldInfo fi)
        {
            var dm = new DynamicMethodDefinition
                     (
                "__FieldAccess" + fi.DeclaringType?.Name + fi.Name,
                typeof(TField),
                new Type[0]
                     );

            ILGenerator gen = dm.GetILGenerator();

            gen.Emit(OpCodes.Ldsfld, fi);
            gen.Emit(OpCodes.Ret);

            return(dm.Generate().CreateDelegate(typeof(Func <TField>)));
        }
コード例 #17
0
        private static Delegate CreateGetStaticFieldRefDelegate <TField>(FieldInfo fi)
        {
            var dm = new DynamicMethodDefinition
                     (
                "__ReturnByRef" + fi.DeclaringType?.Name + fi.Name,
                fi.FieldType.MakeByRefType(),
                new Type[0]
                     );

            ILGenerator gen = dm.GetILGenerator();

            gen.Emit(OpCodes.Ldsflda, fi);
            gen.Emit(OpCodes.Ret);

            return(dm.Generate().CreateDelegate(typeof(FuncByRef <TField>)));
        }
コード例 #18
0
        private static Delegate CreateGetFieldRefDelegate <TClass, TField>(FieldInfo info)
        {
            var dm = new DynamicMethodDefinition
                     (
                "__ReturnByRef" + info.DeclaringType?.Name + info.Name,
                typeof(TField).MakeByRefType(),
                new[] { typeof(TClass) }
                     );

            ILGenerator gen = dm.GetILGenerator();

            gen.Emit(OpCodes.Ldarg_0);
            gen.Emit(OpCodes.Ldflda, info);
            gen.Emit(OpCodes.Ret);

            return(dm.Generate().CreateDelegate(typeof(FuncByRef <TClass, TField>)));
        }
コード例 #19
0
        static int SizeOf(Type type)
        {
            if (sizes.TryGetValue(type, out var size))
            {
                return(size);
            }

            var dm = new DynamicMethodDefinition("SizeOfType", typeof(int), new Type[0]);
            var il = dm.GetILGenerator();

            il.Emit(OpCodes.Sizeof, type);
            il.Emit(OpCodes.Ret);
            size = (int)dm.Generate().Invoke(null, null);

            sizes.Add(type, size);
            return(size);
        }
コード例 #20
0
ファイル: AccessTools.cs プロジェクト: ICanHazCode/HarmonyX
        /// <summary>Creates a static field reference delegate</summary>
        /// <typeparam name="F">The type of the field</typeparam>
        /// <param name="fieldInfo">FieldInfo for the field</param>
        /// <returns>A read and writable field reference delegate</returns>
        ///
        public static FieldRef <F> StaticFieldRefAccess <F>(FieldInfo fieldInfo)
        {
            if (fieldInfo == null)
            {
                throw new ArgumentNullException(nameof(fieldInfo));
            }
            var t = fieldInfo.DeclaringType;

            var dm = new DynamicMethodDefinition($"__refget_{t.Name}_static_fi_{fieldInfo.Name}", typeof(F).MakeByRefType(), new Type[0]);

            var il = dm.GetILGenerator();

            il.Emit(OpCodes.Ldsflda, fieldInfo);
            il.Emit(OpCodes.Ret);

            return((FieldRef <F>)dm.Generate().CreateDelegate <FieldRef <F> >());
        }
コード例 #21
0
        private static Delegate CreateSetStaticFieldDelegate <TField>(FieldInfo fi)
        {
            var dm = new DynamicMethodDefinition
                     (
                "__FieldSet" + fi.DeclaringType?.Name + fi.Name,
                typeof(void),
                new[] { typeof(TField) }
                     );

            ILGenerator gen = dm.GetILGenerator();

            gen.Emit(OpCodes.Ldarg_0);
            gen.Emit(OpCodes.Stsfld, fi);
            gen.Emit(OpCodes.Ret);

            return(dm.Generate().CreateDelegate(typeof(Action <TField>)));
        }
コード例 #22
0
        /// <inheritdoc />
        public override DynamicMethodDefinition CopyOriginal()
        {
            if (!(Original is MethodInfo mi))
            {
                return(null);
            }
            var dmd = new DynamicMethodDefinition("OrigWrapper", returnType, argTypes);
            var il  = dmd.GetILGenerator();

            for (var i = 0; i < argTypes.Length; i++)
            {
                il.Emit(OpCodes.Ldarg, i);
            }
            il.Emit(OpCodes.Call, mi);
            il.Emit(OpCodes.Ret);
            return(dmd);
        }
コード例 #23
0
ファイル: Tools.cs プロジェクト: Windows10CE/Harmony
        internal static FieldRef <F> StaticFieldRefAccess <F>(FieldInfo fieldInfo)
        {
            if (fieldInfo.IsStatic is false)
            {
                throw new ArgumentException("Field must be static");
            }
            Tools.ValidateFieldType <F>(fieldInfo);

            var dm = new DynamicMethodDefinition($"__refget_{fieldInfo.DeclaringType?.Name ?? "null"}_static_fi_{fieldInfo.Name}",
                                                 typeof(F).MakeByRefType(), new Type[0]);

            var il = dm.GetILGenerator();

            il.Emit(OpCodes.Ldsflda, fieldInfo);
            il.Emit(OpCodes.Ret);

            return((FieldRef <F>)dm.Generate().CreateDelegate(typeof(FieldRef <F>)));
        }
コード例 #24
0
        private static void HookSystemRuntimeTypeGetMethodBase()
        {
            var systemRuntimeTypeType = typeof(Type).Assembly.GetType("System.RuntimeType");

            var getMethodBase1 = systemRuntimeTypeType.GetMethods(BindingFlags.Static | BindingFlags.NonPublic)
                                 .Where(m => m.Name == "GetMethodBase")
                                 .Where(m => m.GetParameters().Length == 2)
                                 .FirstOrDefault(m =>
                                                 m.GetParameters().First().ParameterType == systemRuntimeTypeType &&
                                                 m.GetParameters().Last().ParameterType.Name == "IRuntimeMethodInfo");

            var getMethodBase2 = systemRuntimeTypeType.GetMethods(BindingFlags.Static | BindingFlags.NonPublic)
                                 .FirstOrDefault(m => m.Name == "GetMethodBase" && m.GetParameters().Length == 1);

            var myMethod = typeof(Program).GetMethod(nameof(Hook5), BindingFlags.Static | BindingFlags.Public);

            var replacementMethod = new DynamicMethodDefinition(
                getMethodBase2.Name,
                getMethodBase2.ReturnType,
                getMethodBase2.GetParameters().Select(x => x.ParameterType).ToArray()
                )
            {
                OwnerType = getMethodBase1.DeclaringType
            };

            var iLGenerator = replacementMethod.GetILGenerator();

            iLGenerator.DeclareLocal(typeof(MethodBase), false);

            iLGenerator.Emit(System.Reflection.Emit.OpCodes.Ldnull);
            iLGenerator.Emit(System.Reflection.Emit.OpCodes.Stloc_0);
            iLGenerator.Emit(System.Reflection.Emit.OpCodes.Ldnull);
            iLGenerator.Emit(System.Reflection.Emit.OpCodes.Ldarg_0);
            iLGenerator.Emit(System.Reflection.Emit.OpCodes.Call, getMethodBase1);
            iLGenerator.Emit(System.Reflection.Emit.OpCodes.Stloc_0);
            iLGenerator.Emit(System.Reflection.Emit.OpCodes.Ldloca, 0);
            iLGenerator.Emit(System.Reflection.Emit.OpCodes.Call, myMethod);
            iLGenerator.Emit(System.Reflection.Emit.OpCodes.Ldloc_0);
            iLGenerator.Emit(System.Reflection.Emit.OpCodes.Ret);

            var replacementMethodInfo = replacementMethod.Generate();

            Memory.SimpleHook(getMethodBase2, replacementMethodInfo);
        }
コード例 #25
0
ファイル: FastAccess.cs プロジェクト: riQQ/HarmonyX
        /// <summary>Creates an instantiation delegate</summary>
        /// <typeparam name="T">Type that constructor creates</typeparam>
        /// <returns>The new instantiation delegate</returns>
        ///
        public static InstantiationHandler <T> CreateInstantiationHandler <T>()
        {
            var constructorInfo =
                typeof(T).GetConstructor(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance, null,
                                         new Type[0], null);

            if (constructorInfo == null)
            {
                throw new ApplicationException(
                          $"The type {typeof(T)} must declare an empty constructor (the constructor may be private, internal, protected, protected internal, or public).");
            }

            var dmd = new DynamicMethodDefinition($"InstantiateObject_{typeof(T).Name}", typeof(T), null);
            var il  = dmd.GetILGenerator();

            il.Emit(OpCodes.Newobj, constructorInfo);
            il.Emit(OpCodes.Ret);
            return((InstantiationHandler <T>)dmd.Generate().CreateDelegate <InstantiationHandler <T> >());
        }
コード例 #26
0
ファイル: MethodPatcher.cs プロジェクト: fbondia/Harmony
        internal MethodPatcher(MethodBase original, MethodBase source, List <MethodInfo> prefixes, List <MethodInfo> postfixes, List <MethodInfo> transpilers, List <MethodInfo> finalizers, bool debug)
        {
            if (original is null)
            {
                throw new ArgumentNullException(nameof(original));
            }

            this.debug       = debug;
            this.original    = original;
            this.source      = source;
            this.prefixes    = prefixes;
            this.postfixes   = postfixes;
            this.transpilers = transpilers;
            this.finalizers  = finalizers;

            Memory.MarkForNoInlining(original);

            if (debug)
            {
                FileLog.LogBuffered($"### Patch: {original.FullDescription()}");
                FileLog.FlushBuffer();
            }

            idx = prefixes.Count() + postfixes.Count() + finalizers.Count();
            useStructReturnBuffer = StructReturnBuffer.NeedsFix(original);
            if (debug && useStructReturnBuffer)
            {
                FileLog.Log($"### Note: A buffer for the returned struct is used. That requires an extra IntPtr argument before the first real argument");
            }
            returnType = AccessTools.GetReturnedType(original);
            patch      = CreateDynamicMethod(original, $"_Patch{idx}", debug);
            if (patch is null)
            {
                throw new Exception("Could not create replacement method");
            }

            il      = patch.GetILGenerator();
            emitter = new Emitter(il, debug);
        }
コード例 #27
0
ファイル: MethodPatcher.cs プロジェクト: AmonKing/Harmony
        internal MethodPatcher(MethodBase original, MethodBase source, List <MethodInfo> prefixes, List <MethodInfo> postfixes, List <MethodInfo> transpilers, List <MethodInfo> finalizers, bool debug)
        {
            if (original == null)
            {
                throw new ArgumentNullException(nameof(original));
            }

            this.debug       = debug;
            this.original    = original;
            this.source      = source;
            this.prefixes    = prefixes;
            this.postfixes   = postfixes;
            this.transpilers = transpilers;
            this.finalizers  = finalizers;

            Memory.MarkForNoInlining(original);

            if (debug)
            {
                FileLog.LogBuffered($"### Patch {original.FullDescription()}");
                FileLog.FlushBuffer();
            }

            idx = prefixes.Count() + postfixes.Count() + finalizers.Count();
            firstArgIsReturnBuffer = NativeThisPointer.NeedsNativeThisPointerFix(original);
            if (debug && firstArgIsReturnBuffer)
            {
                FileLog.Log($"### Special case: extra argument after 'this' is pointer to valuetype (simulate return value)");
            }
            returnType = AccessTools.GetReturnedType(original);
            patch      = CreateDynamicMethod(original, $"_Patch{idx}", debug);
            if (patch == null)
            {
                throw new Exception("Could not create replacement method");
            }

            il      = patch.GetILGenerator();
            emitter = new Emitter(il, debug);
        }
コード例 #28
0
        public static MethodInfo WrapInterop(MethodInfo transpiler)
        {
            lock (Wrappers)
            {
                if (Wrappers.TryGetValue(transpiler, out var wrapped))
                {
                    return(wrapped);
                }
            }

            using (var dmd = new DynamicMethodDefinition($"TranspilerWrapper<{transpiler.GetID(simple: true)}>",
                                                         typeof(IEnumerable <CodeInstruction>), new[]
            {
                typeof(IEnumerable <CodeInstruction>),
                typeof(ILGenerator),
                typeof(MethodBase)
            }))
            {
                var il = dmd.GetILGenerator();
                il.Emit(OpCodes.Ldtoken, transpiler);
                il.Emit(OpCodes.Call, ResolveToken);
                il.Emit(OpCodes.Castclass, typeof(MethodInfo));
                il.Emit(OpCodes.Ldarg_0);
                il.Emit(OpCodes.Ldarg_1);
                il.Emit(OpCodes.Ldarg_2);
                il.Emit(OpCodes.Call, ApplyTranspilerMethod);
                il.Emit(OpCodes.Ret);

                var generatedWrapper = dmd.GenerateWith <DMDCecilGenerator>();

                lock (Wrappers)
                {
                    Wrappers[transpiler] = generatedWrapper;
                }

                return(generatedWrapper);
            }
        }
コード例 #29
0
        private static Func <Scene, Vector2, Color> GetHueIL()
        {
            string methodName = "ColorHelper._getHue";

            DynamicMethodDefinition method = new DynamicMethodDefinition(methodName, typeof(Color), new[] { typeof(Scene), typeof(Vector2) });

            var gen = method.GetILGenerator();

            FieldInfo crystalSpinner = typeof(ColorHelper).GetField(nameof(ColorHelper.crystalSpinner), BindingFlags.NonPublic | BindingFlags.Static);

            // ColorHelper.crystalSpinner.Scene = scene;
            gen.Emit(OpCodes.Ldsfld, crystalSpinner);
            gen.Emit(OpCodes.Ldarg_0);
            gen.Emit(OpCodes.Call, typeof(Entity).GetProperty("Scene").GetSetMethod(true));

            // return ColorHelper.crystalSpinner.GetHue(position);
            gen.Emit(OpCodes.Ldsfld, crystalSpinner);
            gen.Emit(OpCodes.Ldarg_1);
            gen.Emit(OpCodes.Call, typeof(CrystalStaticSpinner).GetMethod("GetHue", BindingFlags.NonPublic | BindingFlags.Instance));
            gen.Emit(OpCodes.Ret);

            return((Func <Scene, Vector2, Color>)method.Generate().CreateDelegate(typeof(Func <Scene, Vector2, Color>)));
        }
コード例 #30
0
        private DynamicMethodDefinition GenerateManagedOriginal()
        {
            // Here we generate the "managed" version of the native method
            // It simply calls the trampoline generated by MonoMod
            // As a result, we can pass the managed original to HarmonyManipulator like a normal method

            var orig = Original;

            lock (CounterLock)
            {
                newOriginal = counter;
                counter++;
            }

            var dmd = new DynamicMethodDefinition($"NativeDetour_Wrapper<{orig.GetID(simple: true)}>?{newOriginal}", returnType, argTypes);

            var def = dmd.Definition;

            for (var i = 0; i < argTypeNames.Length; i++)
            {
                def.Parameters[i].Name = argTypeNames[i];
            }

            var il = dmd.GetILGenerator();

            il.Emit(OpCodes.Ldc_I4, newOriginal);
            il.Emit(OpCodes.Call, GetTrampolineMethod);
            for (var i = 0; i < argTypes.Length; i++)
            {
                il.Emit(OpCodes.Ldarg, i);
            }
            il.Emit(OpCodes.Call, invokeTrampolineMethod);
            il.Emit(OpCodes.Ret);

            return(dmd);
        }