Mono.Cecil
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 == )
{
int* inj = (int*)methodToInject.MethodHandle.Value.ToPointer() + ;
int* tar = (int*)methodToReplace.MethodHandle.Value.ToPointer() + ;
#if DEBUG
Console.WriteLine("\nVersion x86 Debug\n");
byte* injInst = (byte*)*inj;
byte* tarInst = (byte*)*tar;
int* injSrc = (int*)(injInst + );
int* tarSrc = (int*)(tarInst + );
*tarSrc = (((int)injInst + ) + *injSrc) - ((int)tarInst + );
#else
Console.WriteLine("\nVersion x86 Release\n");
*tar = *inj;
#endif
}
else
{
long* inj = (long*)methodToInject.MethodHandle.Value.ToPointer()+;
long* tar = (long*)methodToReplace.MethodHandle.Value.ToPointer()+;
#if DEBUG
Console.WriteLine("\nVersion x64 Debug\n");
byte* injInst = (byte*)*inj;
byte* tarInst = (byte*)*tar;
int* injSrc = (int*)(injInst + );
int* tarSrc = (int*)(tarInst + );
*tarSrc = (((int)injInst + ) + *injSrc) - ((int)tarInst + );
#else
Console.WriteLine("\nVersion x64 Release\n");
*tar = *inj;
#endif
}
}
参考文章:
注:Emit也能跟Mono.Cecil一样动态生成IL,但它貌似只支持PC平台:
Mono.Cecil与.NET Reflection的反射对比
- Comparing reflection using Mono.Cecil and .NET Reflection. · GitHub
- Mono.Cecil vs. System.Reflection
- Use Mono.Cecil to Reflect Assembly Metadata with Better Performance
Mono.Cecil的更多相关文章
- 运用Mono.Cecil 反射读取.NET程序集元数据
CLR自带的反射机智和API可以很轻松的读取.NET程序集信息,但是不能对程序集进行修改.CLR提供的是只读的API,但是开源项目Mono.Cecil不仅仅可以读取.NET程序集的元数据,还可以进行修 ...
- Mono.Cecil 初探(一):实现AOP
序言 本篇文章介绍基于Mono.Cecil实现静态AOP的两种方式:无交互AOP和交互式AOP. 概念介绍 Mono.Cecil:一个可加载并浏览现有程序集并进行动态修改并保存的.NET框架. AOP ...
- 基于Mono.Cecil的静态注入
Aop注入有2种方式:动态注入和静态注入,其中动态注入有很多实现了 动态注入有几种方式: 利用Remoting的ContextBoundObject或MarshalByRefObject. 动态代理( ...
- 使用Mono Cecil 动态获取运行时数据 (Atribute形式 进行注入 用于写Log) [此文报考 xxx is declared in another module and needs to be imported的解决方法]-摘自网络
目录 一:普通写法 二:注入定义 三:Weave函数 四:参数构造 五:业务编写 六:注入调用 7. 怎么调用别的程序集的方法示例 8. [is declared in another module ...
- C# Asp.net中的AOP框架 Microsoft.CCI, Mono.Cecil, Typemock Open-AOP API, PostSharp -摘自网络 (可以利用反射 Attribute 进行面向切面编程 可以用在记录整个方法的Log方面)
Both Microsoft.CCI and Mono.Cecil are low-level, and don't validate produced assemblies. It takes lo ...
- 利用Mono.Cecil动态修改程序集来破解商业组件(仅用于研究学习)
原文 利用Mono.Cecil动态修改程序集来破解商业组件(仅用于研究学习) Mono.Cecil是一个强大的MSIL的注入工具,利用它可以实现动态创建程序集,也可以实现拦截器横向切入动态方法,甚至还 ...
- 教你怎么用Mono Cecil - 动态注入 (注意代码的注释)
原文 教你怎么用Mono Cecil - 动态注入 (注意代码的注释) 使用 Mono Cecil 进行反编译:using Mono.Cecil; using Mono.Cecil.Cil; //.. ...
- 使用 Mono.Cecil 辅助 Unity3D 手游进行性能测试
Unity3D 引擎在 UnityEngine 名字空间下,提供了 Profiler 类(Unity 5.6 开始似乎改变了这个名字空间),用于辅助对项目性能进行测试.以 Android 平台为例 ...
- 巧用Mono.Cecil反射加载类型和方法信息
最近在做服务的细粒度治理,统一管理所有服务的方法.参数.返回值信息.方便后续的各个模块之间的对接和协作. 目前系统中所有的服务,管理到接口契约粒度,即服务接口声明和服务接口实现.要做服务的细粒度治理: ...
随机推荐
- JAVA多线程之volatile 与 synchronized 的比较
一,volatile关键字的可见性 要想理解volatile关键字,得先了解下JAVA的内存模型,Java内存模型的抽象示意图如下: 从图中可以看出: ①每个线程都有一个自己的本地内存空间--线程栈空 ...
- 由AC自动机引发的灵感
一,WA自动机 #include <cstdio> using namespace std; int main() { printf("☺"); ; } 二,TLE自动 ...
- vue2.0项目实战(4)生命周期和钩子函数详解
最近的项目都使用vue2.0来开发,不得不说,vue真的非常好用,大大减少了项目的开发周期.在踩坑的过程中,因为对vue的生命周期不是特别了解,所以有时候会在几个钩子函数里做一些事情,什么时候做,在哪 ...
- react-native中的state
我们使用两种数据来控制一个组件:props和state.props是在父组件中指定, 而且一经指定,在被指定的组件的生命周期中则不再改变. 对于需要改变的数据,我们需要使用state. 假如我们需要制 ...
- Linux系统调用之内存管理
brk 改变数据段空间的分配 sbrk 参见brk mlock 内存页面加锁 munlock 内存页面解锁 mlockall 调用进程所有内存页面加锁 munlockall 调用进程所有内存页面解锁 ...
- Java实现二叉树的前序、中序、后序、层序遍历(递归方法)
在数据结构中,二叉树是树中我们见得最多的,二叉查找树可以加速我们查找的效率,那么输出一个二叉树也变得尤为重要了. 二叉树的遍历方法分为四种,分别为前序遍历.中序遍历.后序.层序遍历.下图即为一 ...
- spring MVC 如何接收前台传入的JSON对象数组并处理
spring MVC 如何接收前台传入的JSON对象数组 主要方法: (主要用到的包是 net.sf.json 即:json-lib-2.3-jdk15.jar 完整相关jar包: commons- ...
- 【译】2. Java反射——Class对象
原文地址:http://tutorials.jenkov.com/java-reflection/classes.html ====================================== ...
- C sockets Errno
在Windows下进行网络编程,免不了出现各种错误.在Linux下可以使用errno查看错误,但是根据stackoverflow上说,windows下应该使用: FormatMessage() WSA ...
- C++基础知识--DAY1
1. C语言是面向过程的语言,C++是面向对象的语言,相对于C语言来说,C++语法规则更为严格,其存在类型增强的问题. 类型增强,顾名思义就是C++相对于C语言来说有更加严格的类型检查,很多C语言的语 ...