Mono.Cecil

摘要:
MonoCecil十分强大,强大到可以静态注入程序集和动态注入程序集,它甚至可以用来调试PDBMDB调试符号格式文件。assembly一旦别加载,cecil是无法修改它的。若想实现动态注入,动态修改已经被加载了的程序集功能,可以参考这个教程:DynamicallyreplacethecontentsofaC#method?

Mono Cecil十分强大,强大到可以静态注入程序集(注入后生成新的程序集)和动态注入程序集(注入后不改变目标程序集,只在运行时改变程序集行为),它甚至可以用来调试PDB MDB调试符号格式文件。

注:仔细看了下,并不支持“动态”注入,cecil只支持从硬盘加载或从内存读取一个已经被加载了的assembly,然后修改它的副本,最后另存为或者直接调用这个副本。

原程序集并不会发生任何改变,也就是说,如果你要修改一个程序集的行为,那么你必须在原软件加载它之前,修改它,并代替旧的。assembly一旦别加载,cecil是无法修改它的。

若想实现动态注入,动态修改已经被加载了的程序集功能(最典型的就是Unity的游戏,程序集的加载由mono.dll加载,我们比较难去操控它的加载),

可以参考这个教程:Dynamically replace the contents of a C# method?

或者这个开源库:Harmony

他们的原理都是,先用RuntimeHelpers预先从内存中加载原函数,以及要替换掉原函数的注入函数,然后分别获取它们的指针,即它们在内存中的位置,

然后交换它们指针,交换内存空间,即可以实现,替换已经加载了的程序集里的函数内容。

(32位跟64位需要分别处理,因为指针大小不一样,还有这个只支持X86架构,ARM需要另外处理)

       MethodInfo methodToReplace = typeof(Target).GetMethod("targetMethod"+ funcNum, BindingFlags.Instance | BindingFlags.Static | BindingFlags.NonPublic |BindingFlags.Public);
            MethodInfo methodToInject = typeof(Injection).GetMethod("injectionMethod"+ funcNum, BindingFlags.Instance | BindingFlags.Static | BindingFlags.NonPublic |BindingFlags.Public);
            RuntimeHelpers.PrepareMethod(methodToReplace.MethodHandle);
            RuntimeHelpers.PrepareMethod(methodToInject.MethodHandle);
            unsafe
            {
                if (IntPtr.Size == 4)
                {
                    int* inj = (int*)methodToInject.MethodHandle.Value.ToPointer() + 2;
                    int* tar = (int*)methodToReplace.MethodHandle.Value.ToPointer() + 2;
#if DEBUG
                    Console.WriteLine("Version x86 Debug
");
                    byte* injInst = (byte*)*inj;
                    byte* tarInst = (byte*)*tar;
                    int* injSrc = (int*)(injInst + 1);
                    int* tarSrc = (int*)(tarInst + 1);
                    *tarSrc = (((int)injInst + 5) + *injSrc) - ((int)tarInst + 5);
#else
                    Console.WriteLine("Version x86 Release
");
                    *tar = *inj;
#endif
                }
                else
                {
                    long* inj = (long*)methodToInject.MethodHandle.Value.ToPointer()+1;
                    long* tar = (long*)methodToReplace.MethodHandle.Value.ToPointer()+1;
#if DEBUG
                    Console.WriteLine("Version x64 Debug
");
                    byte* injInst = (byte*)*inj;
                    byte* tarInst = (byte*)*tar;
                    int* injSrc = (int*)(injInst + 1);
                    int* tarSrc = (int*)(tarInst + 1);
                    *tarSrc = (((int)injInst + 5) + *injSrc) - ((int)tarInst + 5);
#else
                    Console.WriteLine("Version x64 Release
");
                    *tar = *inj;
#endif
                }
            }

参考文章:

注:Emit也能跟Mono.Cecil一样动态生成IL,但它貌似只支持PC平台:

Mono.Cecil与.NET Reflection的反射对比

免责声明:文章转载自《Mono.Cecil》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇【推荐】iOS汉字转拼音第三方库青岛公司法人实名举报恒丰银行青岛分行行长韩民下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

MVC5模板部署到mono

VS2013中的MVC5模板部署到mono上的艰辛历程 2014-10-27 09:30 by FuzhePan, 771 阅读, 9 评论, 收藏, 编辑 部署环境:CentOS7 + Mono 3.10 + Jexus 5.6 在Xamarin.Studio创建的asp.net项目,部署过程非常顺利,没有遇到什么问题;但在VS2013中创建的asp...

ThinkPHP5——动态展示网站title和mate,优化seo

一般情况下head和foot都是公共页面,这就导致网站的title和meta都是一样的,这不利于SEO,如果想要网站更容易被用户搜索到,就必须把title和meta设置动态 第一步:先建SEO表 表名是seo,结构如下: 动态展示的数据内容 第二步:把查询到的数据放在公共区域 动态展示title,就必须把查询到的数据放在公共区域,例如:Frontend...

Python列表操作与深浅拷贝(5)——数字处理函数、类型判断、列表链表队列栈

python内建数据结构 分类 数值型:  int  float  complex  bool 序列对象: 字符串str  列表list  元组tuple 键值对:  集合set  字典dict 数值型 (list float complex bool都是class) int:python3 中 int 就是长整型,没有大小限制 float:支持十进制和科...

QTableView 固定列宽度(鼠标拖动后,仍可固定)

QTableView 提供一个函数: void QTableView::setColumnWidth ( int column, int width ) 用于设置column指定的列的宽度 但setColumnWidth设置后,用户可以通过鼠标拖拽列头重新设置宽度, 如何固定宽度不变? 联想到QWidget的setFixedWidth, 是不是QTable...

js中动态载入css js样式

js中动态载入css样式,方法如下: //<link rel="stylesheet" type="text/css" href="http://t.zoukankan.com/http://css.static.m1905.cn/base.min.css"> var addCssLink =function(url){ var lin...

poj2349最小生成树prim算法

题目:有s个satellite channels,但有p(p>s)个地方,若任意两个地方有satellite channels,则无视该距离,并且剩余的地方只能与其他地方通过无线电连接,需要距离,且需要的距离只与最大距离有关,问该最大距离的最小值(大概是这样啦)分析:实际上就是求最小生成树中的第p-s大的数,可以先通过prim算法生成最小生成树,然后...