教你怎么用Mono Cecil - 动态注入 (注意代码的注释)

简介: 原文 教你怎么用Mono Cecil - 动态注入 (注意代码的注释) 使用 Mono Cecil 进行反编译:using Mono.Cecil; using Mono.Cecil.Cil; //.

原文 教你怎么用Mono Cecil - 动态注入 (注意代码的注释)

使用 Mono Cecil 进行反编译:using Mono.Cecil;
using Mono.Cecil.Cil;

//......

AssemblyDefinition asm = AssemblyFactory.GetAssembly("MyLibrary.dll");
foreach (TypeDefinition type in asm.MainModule.Types)
{
   if (type.Name == "Class1") //获取类名
   {
     foreach (MethodDefinition method in type.Methods) 遍历方法名称
     {
       Console.WriteLine(".maxstack {0}", method.Body.MaxStack);
       foreach (Instruction ins in method.Body.Instructions)
       {
         Console.WriteLine("L_{0}: {1} {2}", ins.Offset.ToString("x4"),
           ins.OpCode.Name,
           ins.Operand is String ? String.Format("\"{0}\"", ins.Operand) : ins.Operand);
       }
     }
   }
}
输出:

.maxstack 8
L_0000: nop
L_0001: ldstr "Hello, World!"
L_0006: call System.Void System.Console::WriteLine(System.String)
L_000b: nop
L_000c: ret

nop ---->

ldstr ---->

call ---->

nop ---->

ret ---->

=================》下面我们开始进行注入了

AssemblyDefinition asm = AssemblyFactory.GetAssembly("MyLibrary.dll");
foreach (TypeDefinition type in asm.MainModule.Types)
{
   if (type.Name == "Class1")
   {
     foreach (MethodDefinition method in type.Methods)
     {
       if (method.Name == "Test")
       {
         foreach (Instruction ins in method.Body.Instructions)
         {
           if (ins.OpCode.Name == "ldstr" && (string)ins.Operand == "Hello, World!") //如果发现操作数为"Hello, World! ===>改为"Hello, C#!";
           {
             ins.Operand = "Hello, C#!";
           }
         }
       }
     }
   }
}

AssemblyFactory.SaveAssembly(asm, "Test.dll");

用 Lutz Roeder's Reflector 打开 Test.dll 看看结果。
.method public hidebysig instance void Test() cil managed
{
   .maxstack 8
   L_0000: nop
   L_0001: ldstr "Hello, C#!"
   L_0006: call void [mscorlib]System.Console::WriteLine(string)
   L_000b: nop
   L_000c: ret
}


达成所愿~~~~~


完成代码修改以后,我们玩一个更难点的,注入额外的代码。(好像有点做病毒的意思,呵呵~)

任务目标是在 Console.WriteLine("Hello, World!"); 前注入 Console.WriteLine("Virus? No!");,还好这不是真的破坏性代码

AssemblyDefinition asm = AssemblyFactory.GetAssembly("MyLibrary.dll");
foreach (TypeDefinition type in asm.MainModule.Types)
{
   if (type.Name == "Class1")
   {
     foreach (MethodDefinition method in type.Methods)
     {
       if (method.Name == "Test")
       {
         foreach (Instruction ins in method.Body.Instructions)
         {
           if (ins.OpCode.Name == "ldstr" && (string)ins.Operand == "Hello, World!") //关键的地方,找到目的地
           {
             CilWorker worker = method.Body.CilWorker;
            
             Instruction insStr = worker.Create(OpCodes.Ldstr, "Virus? NO!");
             worker.InsertBefore(ins, insStr);

         

             MethodReference refernce = asm.MainModule.Import(typeof(Console).GetMethod("WriteLine",
               new Type[]{typeof(string)}));

             Instruction insCall = worker.Create(OpCodes.Call, refernce);
             worker.InsertAfter(insStr, insCall);

             Instruction insNop = worker.Create(OpCodes.Nop);
             worker.InsertAfter(insCall, insNop);

             break;
           }
         }
       }
     }
   }
}
用反射测试一下修改后的程序集。
AssemblyFactory.SaveAssembly(asm, "Test.dll");

Assembly testAssembly = Assembly.LoadFrom("Test.dll");
Type class1Type = testAssembly.GetType("MyLibrary.Class1");
Object o = Activator.CreateInstance(class1Type);
class1Type.InvokeMember("Test", BindingFlags.Instance | BindingFlags.Public | BindingFlags.InvokeMethod, null, o, null);4. 获取程序集信息
AssemblyDefinition asm = AssemblyFactory.GetAssembly("Learn.Library.dll");

Console.WriteLine("Kind:{0}", asm.Kind);
Console.WriteLine("Runtime:{0}", asm.Runtime);
输出:
Kind:Dll
Runtime:NET_2_0

利用 ModuleDefinition.Image 属性,我们可以获取程序集几乎全部的细节信息。包括 CLIHeader、DebugHeader、DOSHeader、FileInformation、HintNameTable、ImportAddressTable、ImportLookupTable、ImportTable、MetadataRoot、PEFileHeader、PEOptionalHeader、ResourceDirectoryRoot、Sections、TextSection 等。

 

目录
相关文章
|
4月前
|
JSON Java 数据格式
使用`MockMvc`额外的补充和高级用法
使用`MockMvc`额外的补充和高级用法
52 3
|
2月前
|
SQL Java 测试技术
SpringBoot单元测试快速写法问题之PorkService 接口中的 getPork 方法的作用如何解决
SpringBoot单元测试快速写法问题之PorkService 接口中的 getPork 方法的作用如何解决
|
5月前
|
Oracle Java 关系型数据库
Generator【SpringBoot集成】代码生成+knife4j接口文档(2种模板设置、逻辑删除、字段填充 含代码粘贴可用)保姆级教程(注意事项+建表SQL+代码生成类封装+测试类)
Generator【SpringBoot集成】代码生成+knife4j接口文档(2种模板设置、逻辑删除、字段填充 含代码粘贴可用)保姆级教程(注意事项+建表SQL+代码生成类封装+测试类)
88 0
|
存储 前端开发 Java
二十三.SpringCloudConfig源码-初始化配置
今天这篇文章我们来分析一下Spring Cloud Config 配置中心的源码,这应该是Spring Cloud Netflix的源码分析的最后一篇。下一个系列我将会继续分析Spring Cloud Alibaba相关组件的源码。Spring Cloud Config 基础使用请移步 《[配置中心Spring Cloud Config](https://blog.csdn.net/u014494148/article/details/117253831)》
VC 不同版本代码注入的区别
VC 不同版本代码注入的区别
58 0
|
数据挖掘 Perl
Mummer 用法简析
Mummer 用法简析
115 0
逆向工程的Example类用法
逆向工程的Example类用法
81 0
逆向工程的Example类用法
|
存储 缓存 前端开发
Yii2.0的AssetBundle类一共有哪些方法?可以实现哪些功能?底层原理是什么?
Yii2.0的AssetBundle类一共有哪些方法?可以实现哪些功能?底层原理是什么?
115 0
|
开发框架 Java 开发者
Hello World细节-自动配置|学习笔记
快速学习Hello World细节-自动配置
104 0
Hello World细节-自动配置|学习笔记
|
XML JSON API
通过配置文件避免硬编码的一个例子
通过配置文件避免硬编码的一个例子
通过配置文件避免硬编码的一个例子