Beispiel #1
0
        public DynamicMethod ComposePatchedMethod()
        {
            DynamicMethod          method    = AllocatePatchMethod();
            var                    generator = new LoggingIlGenerator(method.GetILGenerator(), PrintMsil ? LogLevel.Info : LogLevel.Trace);
            List <MsilInstruction> il        = EmitPatched((type, pinned) => new MsilLocal(generator.DeclareLocal(type, pinned))).ToList();

            if (PrintMsil)
            {
                lock (_log)
                {
                    MethodTranspiler.IntegrityAnalysis(LogLevel.Info, il);
                }
            }

            MethodTranspiler.EmitMethod(il, generator);

            try
            {
                PatchUtilities.Compile(method);
            }
            catch
            {
                lock (_log)
                {
                    var ctx = new MethodContext(method);
                    ctx.Read();
                    MethodTranspiler.IntegrityAnalysis(LogLevel.Warn, ctx.Instructions);
                }

                throw;
            }

            return(method);
        }
Beispiel #2
0
        private void SavePatchedMethod(string target)
        {
            var asmBuilder =
                AppDomain.CurrentDomain.DefineDynamicAssembly(new AssemblyName("SomeName"), AssemblyBuilderAccess.RunAndSave, Path.GetDirectoryName(target));
            var moduleBuilder = asmBuilder.DefineDynamicModule(Path.GetFileNameWithoutExtension(target), Path.GetFileName(target));
            var typeBuilder   = moduleBuilder.DefineType("Test", TypeAttributes.Public);


            var methodName     = _method.Name + $"_{_patchSalt}";
            var returnType     = _method is MethodInfo meth ? meth.ReturnType : typeof(void);
            var parameters     = _method.GetParameters();
            var parameterTypes = (_method.IsStatic ? Enumerable.Empty <Type>() : new[] { _method.DeclaringType })
                                 .Concat(parameters.Select(x => x.ParameterType)).ToArray();

            var patchMethod = typeBuilder.DefineMethod(methodName, MethodAttributes.Public | MethodAttributes.Static, CallingConventions.Standard,
                                                       returnType, parameterTypes);

            if (!_method.IsStatic)
            {
                patchMethod.DefineParameter(0, ParameterAttributes.None, INSTANCE_PARAMETER);
            }
            for (var i = 0; i < parameters.Length; i++)
            {
                patchMethod.DefineParameter((patchMethod.IsStatic ? 0 : 1) + i, parameters[i].Attributes, parameters[i].Name);
            }

            var generator             = new LoggingIlGenerator(patchMethod.GetILGenerator(), LogLevel.Trace);
            List <MsilInstruction> il = EmitPatched((type, pinned) => new MsilLocal(generator.DeclareLocal(type, pinned))).ToList();

            MethodTranspiler.EmitMethod(il, generator);

            Type res = typeBuilder.CreateType();

            asmBuilder.Save(Path.GetFileName(target));
            foreach (var method in res.GetMethods(BindingFlags.Public | BindingFlags.Static))
            {
                _log.Info($"Information " + method);
            }
        }
Beispiel #3
0
        private IEnumerable <MsilInstruction> EmitPatched(Func <Type, bool, MsilLocal> declareLocal)
        {
            var methodBody = _method.GetMethodBody();

            Debug.Assert(methodBody != null, "Method body is null");
            foreach (var localVar in methodBody.LocalVariables)
            {
                Debug.Assert(localVar.LocalType != null);
                declareLocal(localVar.LocalType, localVar.IsPinned);
            }

            var instructions     = new List <MsilInstruction>();
            var specialVariables = new Dictionary <string, MsilLocal>();

            var labelAfterOriginalContent = new MsilLabel();
            var labelSkipMethodContent    = new MsilLabel();


            Type      returnType     = _method is MethodInfo meth ? meth.ReturnType : typeof(void);
            MsilLocal resultVariable = null;

            if (returnType != typeof(void))
            {
                if (Prefixes.Concat(Suffixes).SelectMany(x => x.GetParameters()).Any(x => x.Name == RESULT_PARAMETER) ||
                    Prefixes.Any(x => x.ReturnType == typeof(bool)))
                {
                    resultVariable = declareLocal(returnType, false);
                }
            }

            if (resultVariable != null)
            {
                instructions.AddRange(resultVariable.SetToDefault());
            }
            MsilLocal prefixSkippedVariable = null;

            if (Prefixes.Count > 0 && Suffixes.Any(x => x.GetParameters()
                                                   .Any(y => y.Name.Equals(PREFIX_SKIPPED_PARAMETER))))
            {
                prefixSkippedVariable = declareLocal(typeof(bool), false);
                specialVariables.Add(PREFIX_SKIPPED_PARAMETER, prefixSkippedVariable);
            }

            if (resultVariable != null)
            {
                specialVariables.Add(RESULT_PARAMETER, resultVariable);
            }

            // Create special variables
            foreach (var m in Prefixes.Concat(Suffixes))
            {
                foreach (var param in m.GetParameters())
                {
                    if (param.Name.StartsWith(LOCAL_PARAMETER))
                    {
                        var requiredType = param.ParameterType.IsByRef ? param.ParameterType.GetElementType() : param.ParameterType;
                        if (specialVariables.TryGetValue(param.Name, out var existingParam))
                        {
                            if (existingParam.Type != requiredType)
                            {
                                throw new ArgumentException(
                                          $"Trying to use injected local {param.Name} for {m.DeclaringType?.FullName}#{m.ToString()} with type {requiredType} but a local with the same name already exists with type {existingParam.Type}",
                                          param.Name);
                            }
                        }
                        else
                        {
                            specialVariables.Add(param.Name, declareLocal(requiredType, false));
                        }
                    }
                }
            }

            foreach (MethodInfo prefix in Prefixes)
            {
                instructions.AddRange(EmitMonkeyCall(prefix, specialVariables));
                if (prefix.ReturnType == typeof(bool))
                {
                    instructions.Add(new MsilInstruction(OpCodes.Brfalse).InlineTarget(labelSkipMethodContent));
                }
                else if (prefix.ReturnType != typeof(void))
                {
                    throw new Exception(
                              $"Prefixes must return void or bool.  {prefix.DeclaringType?.FullName}.{prefix.Name} returns {prefix.ReturnType}");
                }
            }

            instructions.AddRange(MethodTranspiler.Transpile(_method, (x) => declareLocal(x, false), Transpilers, labelAfterOriginalContent));

            instructions.Add(new MsilInstruction(OpCodes.Nop).LabelWith(labelAfterOriginalContent));
            if (resultVariable != null)
            {
                instructions.Add(new MsilInstruction(OpCodes.Stloc).InlineValue(resultVariable));
            }
            var notSkip = new MsilLabel();

            instructions.Add(new MsilInstruction(OpCodes.Br).InlineTarget(notSkip));
            instructions.Add(new MsilInstruction(OpCodes.Nop).LabelWith(labelSkipMethodContent));
            if (prefixSkippedVariable != null)
            {
                instructions.Add(new MsilInstruction(OpCodes.Ldc_I4_1));
                instructions.Add(new MsilInstruction(OpCodes.Stloc).InlineValue(prefixSkippedVariable));
            }

            instructions.Add(new MsilInstruction(OpCodes.Nop).LabelWith(notSkip));

            foreach (MethodInfo suffix in Suffixes)
            {
                instructions.AddRange(EmitMonkeyCall(suffix, specialVariables));
                if (suffix.ReturnType != typeof(void))
                {
                    throw new Exception($"Suffixes must return void.  {suffix.DeclaringType?.FullName}.{suffix.Name} returns {suffix.ReturnType}");
                }
            }

            if (resultVariable != null)
            {
                instructions.Add(new MsilInstruction(OpCodes.Ldloc).InlineValue(resultVariable));
            }
            instructions.Add(new MsilInstruction(OpCodes.Ret));

            var result = MethodTranspiler.Transpile(_method, instructions, (x) => declareLocal(x, false), PostTranspilers, null).ToList();

            if (result.Last().OpCode != OpCodes.Ret)
            {
                result.Add(new MsilInstruction(OpCodes.Ret));
            }
            return(result);
        }
Beispiel #4
0
        public DynamicMethod ComposePatchedMethod()
        {
            DynamicMethod method    = AllocatePatchMethod();
            var           generator = new LoggingIlGenerator(method.GetILGenerator(),
                                                             PrintMode.HasFlag(PrintModeEnum.EmittedReflection) ? LogLevel.Info : LogLevel.Trace);
            List <MsilInstruction> il = EmitPatched((type, pinned) => new MsilLocal(generator.DeclareLocal(type, pinned))).ToList();

            var dumpTarget = DumpTarget != null?File.CreateText(DumpTarget) : null;

            try
            {
                const string gap = "\n\n\n\n\n";

                void LogTarget(PrintModeEnum mode, bool err, string msg)
                {
                    if (DumpMode.HasFlag(mode))
                    {
                        dumpTarget?.WriteLine((err ? "ERROR " : "") + msg);
                    }
                    if (!PrintMode.HasFlag(mode))
                    {
                        return;
                    }
                    if (err)
                    {
                        _log.Error(msg);
                    }
                    else
                    {
                        _log.Info(msg);
                    }
                }

                if (PrintMsil || DumpTarget != null)
                {
                    lock (_log)
                    {
                        var ctx = new MethodContext(_method);
                        ctx.Read();
                        LogTarget(PrintModeEnum.Original, false, "========== Original method ==========");
                        MethodTranspiler.IntegrityAnalysis((a, b) => LogTarget(PrintModeEnum.Original, a, b), ctx.Instructions, true);
                        LogTarget(PrintModeEnum.Original, false, gap);

                        LogTarget(PrintModeEnum.Emitted, false, "========== Desired method ==========");
                        MethodTranspiler.IntegrityAnalysis((a, b) => LogTarget(PrintModeEnum.Emitted, a, b), il);
                        LogTarget(PrintModeEnum.Emitted, false, gap);
                    }
                }

                MethodTranspiler.EmitMethod(il, generator);

                try
                {
                    PatchUtilities.Compile(method);
                }
                catch
                {
                    lock (_log)
                    {
                        var ctx = new MethodContext(method);
                        ctx.Read();
                        MethodTranspiler.IntegrityAnalysis((err, msg) => _log.Warn(msg), ctx.Instructions);
                    }

                    throw;
                }

                if (PrintMsil || DumpTarget != null)
                {
                    lock (_log)
                    {
                        var ctx = new MethodContext(method);
                        ctx.Read();
                        LogTarget(PrintModeEnum.Patched, false, "========== Patched method ==========");
                        MethodTranspiler.IntegrityAnalysis((a, b) => LogTarget(PrintModeEnum.Patched, a, b), ctx.Instructions, true);
                        LogTarget(PrintModeEnum.Patched, false, gap);
                    }
                }
            }
            finally
            {
                dumpTarget?.Close();
            }

            return(method);
        }
Beispiel #5
0
 /// <summary>
 /// Analyzes the integrity of a set of instructions.
 /// </summary>
 /// <param name="level">default logging level</param>
 /// <param name="instructions">instructions</param>
 public static void IntegrityAnalysis(LogLevel level, IReadOnlyList <MsilInstruction> instructions)
 {
     MethodTranspiler.IntegrityAnalysis(level, instructions);
 }
Beispiel #6
0
 /// <summary>
 /// Writes the given instruction stream to the given IL generator, fixing short branch instructions.
 /// </summary>
 /// <param name="insn">Instruction stream</param>
 /// <param name="generator">Output</param>
 public static void EmitInstructions(IEnumerable <MsilInstruction> insn, LoggingIlGenerator generator)
 {
     MethodTranspiler.EmitMethod(insn.ToList(), generator);
 }
Beispiel #7
0
 /// <summary>
 /// Analyzes the integrity of a set of instructions.
 /// </summary>
 /// <param name="handler">Logger</param>
 /// <param name="instructions">instructions</param>
 public static void IntegrityAnalysis(DelPrintIntegrityInfo handler, IReadOnlyList <MsilInstruction> instructions)
 {
     MethodTranspiler.IntegrityAnalysis(handler, instructions);
 }