C# 使用Emit动态注入代码,实现监控属性的目的
public class DynamicProxyGenerator{private const string DynamicAssemblyName = "DynamicAssembly";//动态程序集名称private const string DynamicModuleName = "DynamicAssemblyModule";private const string DynamicModuleDllName = "DynamicAssembly.dll";//动态模块名称private const string ProxyClassNameFormater = "{0}Proxy";private const string ModifiedPropertyNamesFieldName = "ModifiedPropertyNames";private const MethodAttributes GetSetMethodAttributes = MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.CheckAccessOnOverride | MethodAttributes.Virtual | MethodAttributes.HideBySig;/// <summary>/// 创建动态程序集,返回AssemblyBuilder/// </summary>/// <param name="isSavaDll"></param>/// <returns></returns>private static AssemblyBuilder DefineDynamicAssembly(bool isSavaDll = false){//动态创建程序集AssemblyName DemoName = new AssemblyName(DynamicAssemblyName);AssemblyBuilderAccess assemblyBuilderAccess = isSavaDll ? AssemblyBuilderAccess.RunAndSave : AssemblyBuilderAccess.Run;AssemblyBuilder dynamicAssembly = AppDomain.CurrentDomain.DefineDynamicAssembly(DemoName, assemblyBuilderAccess);return dynamicAssembly;}/// <summary>/// 创建动态模块,返回ModuleBuilder/// </summary>/// <param name="isSavaDll"></param>/// <returns>ModuleBuilder</returns>private static ModuleBuilder DefineDynamicModule(AssemblyBuilder dynamicAssembly, bool isSavaDll = false){ModuleBuilder moduleBuilder = null;//动态创建模块if (isSavaDll)moduleBuilder = dynamicAssembly.DefineDynamicModule(DynamicModuleName, DynamicModuleDllName);elsemoduleBuilder = dynamicAssembly.DefineDynamicModule(DynamicModuleName);return moduleBuilder;}/// <summary>/// 创建动态代理类,重写属性Get Set 方法,并监控属性的Set方法,把变更的属性名加入到list集合中,需要监控的属性必须是virtual/// 如果你想保存修改的属性名和属性值,修改Set方法的IL实现/// </summary>/// <typeparam name="T"></typeparam>/// <param name="isSavaDynamicModule"></param>/// <returns></returns>public static T CreateDynamicProxy<T>(bool isSavaDynamicModule = false){Type modifiedPropertyNamesType = typeof(HashSet<string>);Type typeNeedProxy = typeof(T);AssemblyBuilder assemblyBuilder = DefineDynamicAssembly(isSavaDynamicModule);//动态创建模块ModuleBuilder moduleBuilder = DefineDynamicModule(assemblyBuilder, isSavaDynamicModule);string proxyClassName = string.Format(ProxyClassNameFormater, typeNeedProxy.Name);//动态创建类代理TypeBuilder typeBuilderProxy = moduleBuilder.DefineType(proxyClassName, TypeAttributes.Public, typeNeedProxy);//定义一个变量存放属性变更名FieldBuilder fbModifiedPropertyNames = typeBuilderProxy.DefineField(ModifiedPropertyNamesFieldName, modifiedPropertyNamesType, FieldAttributes.Public);/** 构造函数 实例化 ModifiedPropertyNames,生成类似于下面的代码ModifiedPropertyNames = new List<string>();*/ConstructorBuilder constructorBuilder = typeBuilderProxy.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, null);ILGenerator ilgCtor = constructorBuilder.GetILGenerator();ilgCtor.Emit(OpCodes.Ldarg_0);//加载当前类ilgCtor.Emit(OpCodes.Newobj, modifiedPropertyNamesType.GetConstructor(new Type[0]));//实例化对象入栈ilgCtor.Emit(OpCodes.Stfld, fbModifiedPropertyNames);//设置fbModifiedPropertyNames值,为刚入栈的实例化对象ilgCtor.Emit(OpCodes.Ret);//返回//获取被代理对象的所有属性,循环属性进行重写PropertyInfo[] properties = typeNeedProxy.GetProperties();foreach (PropertyInfo propertyInfo in properties){string propertyName = propertyInfo.Name;Type typePepropertyInfo = propertyInfo.PropertyType;//动态创建字段和属性FieldBuilder fieldBuilder = typeBuilderProxy.DefineField("_" + propertyName, typePepropertyInfo, FieldAttributes.Private);PropertyBuilder propertyBuilder = typeBuilderProxy.DefineProperty(propertyName, PropertyAttributes.SpecialName, typePepropertyInfo, null);//重写属性的Get Set方法var methodGet = typeBuilderProxy.DefineMethod("get_" + propertyName, GetSetMethodAttributes, typePepropertyInfo, Type.EmptyTypes);var methodSet = typeBuilderProxy.DefineMethod("set_" + propertyName, GetSetMethodAttributes, null, new Type[] { typePepropertyInfo });//il of get methodvar ilGetMethod = methodGet.GetILGenerator();ilGetMethod.Emit(OpCodes.Ldarg_0);ilGetMethod.Emit(OpCodes.Ldfld, fieldBuilder);ilGetMethod.Emit(OpCodes.Ret);//il of set methodILGenerator ilSetMethod = methodSet.GetILGenerator();ilSetMethod.Emit(OpCodes.Ldarg_0);ilSetMethod.Emit(OpCodes.Ldarg_1);ilSetMethod.Emit(OpCodes.Stfld, fieldBuilder);ilSetMethod.Emit(OpCodes.Ldarg_0);ilSetMethod.Emit(OpCodes.Ldfld, fbModifiedPropertyNames);ilSetMethod.Emit(OpCodes.Ldstr, propertyInfo.Name);ilSetMethod.Emit(OpCodes.Callvirt, modifiedPropertyNamesType.GetMethod("Add", new Type[] { typeof(string) }));ilSetMethod.Emit(OpCodes.Pop);ilSetMethod.Emit(OpCodes.Ret);//设置属性的Get Set方法propertyBuilder.SetGetMethod(methodGet);propertyBuilder.SetSetMethod(methodSet);}//使用动态类创建类型Type proxyClassType = typeBuilderProxy.CreateType();//保存动态创建的程序集if (isSavaDynamicModule)assemblyBuilder.Save(DynamicModuleDllName);//创建类实例var instance = Activator.CreateInstance(proxyClassType);return (T)instance;}/// <summary>/// 获取属性的变更名称,/// 此处只检测调用了Set方法的属性,不会检测值是否真的有变/// </summary>/// <param name="obj"></param>/// <returns></returns>public static HashSet<string> GetModifiedProperties(object obj){FieldInfo fieldInfo = obj.GetType().GetField(ModifiedPropertyNamesFieldName);if (fieldInfo == null) return null;object value = fieldInfo.GetValue(obj);return value as HashSet<string>;}}
使用:
Person p = DynamicProxyGenerator.CreateDynamicProxy<Person>(true);
p.Name = "tom";
p.Name = "tony";
p.Age = 111;
var changes = DynamicProxyGenerator.GetModifiedProperties(p);
本文转自这个地址
C# 使用Emit动态注入代码,实现监控属性的目的相关推荐
- 【转载】使用javassist动态注入代码
关于java字节码的处理,目前有很多工具,如bcel,asm.不过这些都需要直接跟虚拟机指令打交道.如果你不想了解虚拟机指令,可以采用javassist.javassist是jboss的一个子项目,其 ...
- 使用javassist动态注入代码
http://dennis-zane.iteye.com/blog/57540 关于java字节码的处理,目前有很多工具,如bcel,asm.不过这些都需要直接跟虚拟机指令打交道.如果你不想了解虚拟机 ...
- 【Android 逆向】Android 进程代码注入原理 ( 注入本质 | 静态注入和动态注入 | 静态注入两种方式 | 修改动态库重打包 | 修改 /data/app/xx/libs 动态库 )
文章目录 一.注入本质 二.静态注入和动态注入 三.静态注入两种方式 ( 修改动态库重打包 | 修改 /data/app/packageName/libs/ 下的动态库 ) 一.注入本质 进程注入本质 ...
- 【Android 逆向】Android 进程注入工具开发 ( 注入代码分析 | 注入工具收尾操作 | 关闭注入的动态库 | 恢复寄存器 | 脱离远程调试附着 )
文章目录 一.dlclose 函数简介 二.关闭注入的 libbridge.so 动态库 三.恢复寄存器 四.脱离远程调试附着 一.dlclose 函数简介 dlclose 函数的作用是 卸载一个 指 ...
- 【Android 逆向】Android 进程注入工具开发 ( 注入代码分析 | 获取注入的 libbridge.so 动态库中的 load 函数地址 并 通过 远程调用 执行该函数 )
文章目录 一.dlsym 函数简介 二.获取 目标进程 linker 中的 dlsym 函数地址 三.远程调用 目标进程 linker 中的 dlsym 函数 获取 注入的 libbridge.so ...
- 【Android 逆向】Android 进程注入工具开发 ( 注入代码分析 | 远程调用 目标进程中 libc.so 动态库中的 mmap 函数 三 | 等待远程函数执行完毕 | 寄存器获取返回值 )
文章目录 前言 一.等待远程进程 mmap 函数执行完毕 二.从寄存器中获取进程返回值 三.博客资源 前言 前置博客 : [Android 逆向]Android 进程注入工具开发 ( 注入代码分析 | ...
- 【Android 逆向】Android 进程注入工具开发 ( 注入代码分析 | 远程调用 目标进程中 libc.so 动态库中的 mmap 函数 二 | 准备参数 | 远程调用 mmap 函数 )
文章目录 一.准备 mmap 函数的参数 二.mmap 函数远程调用 一.准备 mmap 函数的参数 上一篇博客 [Android 逆向]Android 进程注入工具开发 ( 注入代码分析 | 远程调 ...
- Spring Boot轻松理解动态注入,删除bean
原文地址:http://412887952-qq-com.iteye.com/blog/2348445 我们通过getBean来获得对象,但这些对象都是事先定义好的,我们有时候要在程序中动态的加入 ...
- PE病毒初探——向exe注入代码
PE文件其实就是Windows可执行文件,关于它的一些简要介绍摘自百度: PE文件被称为可移植的执行体是Portable Execute的全称,常见的EXE.DLL.OCX.SYS.COM都是PE文件 ...
最新文章
- php批量请求url_php请求url的方法小结
- 泛在电力物联网(能源互联网+物联网)浅析
- C# this关键字
- win10如何关闭文件夹或者照片的最近浏览?
- 端口复用突破防火墙(图)
- 小红书成立六周年内部信:月活用户量已经突破8500万
- 腾讯已问灵魂,鹅厂新立家风
- java 管道流_Java IO7:管道流、对象流
- 三种基于感知哈希算法的相似图像检索技术
- java使用elasticsearch进行模糊查询-已在项目中实际应用
- smartprinter注册版_SmartPrinter下载 4.2 共享版
- Html 页面底部添加版权信息11
- java 数字拆分_如何在java中分割数字?
- 在不借助第三方变量情况下实现两个变量的交换(借助于异或运算)
- linux操作的进程调度没有采用,Linux进程调度分析
- 推荐几款公众号写作必备工具
- JavaScript知识之正则表达式(RegExp)
- Android 时间轴的实现
- Translation idea插件
- 经典数字游戏——数独(Sudoku)解法的Python代码实现