mono.cecil实现动态插入IL代码

准备

namespace ConsoleApp1
{
    internal class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Hello, World!");
            Console.ReadKey();
        }
    }
}

编译出来如下内容
在这里插入图片描述
使用ilspy打开
在这里插入图片描述
在这里插入图片描述

代码

安装Mono.Cecil
代码如下

using Mono.Cecil;
using Mono.Cecil.Cil;
using System.Diagnostics;

namespace ILInject
{
    internal class Program
    {
        static void Main(string[] args)
        {
            string path = @"G:\ConsoleApp1\bin\Debug\net8.0\ConsoleApp1.dll";
            Run(path, false);
            Console.ReadKey();
        }

        /// <summary>
        /// 注入IL代码
        /// </summary>
        /// <param name="path"></param>
        /// <param name="isBreak"></param>
        static void Run(string path, bool isBreak)
        {
            //加载程序集
            using var assembly = AssemblyDefinition.ReadAssembly(path, new ReaderParameters { ReadWrite = true });

            //查找入口方法
            var entryPoint = assembly.EntryPoint;

            //获取入口点方法的IL处理器
            var ilProcessor = entryPoint.Body.GetILProcessor();

            //创建添加说明
            Instruction[] instructions;
            if (isBreak)
            {
                var launchDebuggerInstruction = ilProcessor.Create(OpCodes.Call, assembly.MainModule.ImportReference(
                    typeof(Debugger).GetMethod(nameof(Debugger.Launch), Type.EmptyTypes)));
                instructions = new[]
                {
                    launchDebuggerInstruction,
                    Instruction.Create(OpCodes.Pop),
                };
            }
            else
            {
                var writeLineInstruction = ilProcessor.Create(OpCodes.Call, assembly.MainModule.ImportReference(
                    typeof(Console).GetMethod(nameof(Console.WriteLine), new Type[] { typeof(string) })));
                var readKeyInstruction = ilProcessor.Create(OpCodes.Call, assembly.MainModule.ImportReference(
                    typeof(Console).GetMethod(nameof(Console.ReadKey), Type.EmptyTypes)));

                instructions = new[]
                {
                    Instruction.Create(OpCodes.Ldstr, "Please attach debugger, then press any key"),
                    writeLineInstruction,
                    readKeyInstruction,
                    //使用Pop删除ReadKey的返回值
                    Instruction.Create(OpCodes.Pop),
                };
            }

            var firstInstruction = ilProcessor.Body.Instructions[0];
            // 在方法的开头插入新的说明
            for (int i = 0; i < instructions.Length; i++)
            {
                ilProcessor.InsertBefore(firstInstruction, instructions[i]);
            }
            // 保存修改后的组件
            assembly.Write();
            Console.WriteLine("已成功修改并保存程序集。");
        }
    }
}

再次运行exe即可看到效果

参考

https://www.bilibili.com/video/BV1WVbFeKEKD/?spm_id_from=333.999.0.0&vd_source=b7fa6e046b093a4aca400b429259cf8b
IL指令
https://github.com/yangzhongke/DotNetBreak/tree/main/DotNetWait

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

假装我不帅

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值