Target
新建项目CecilTest
创建待注入类
Target.cs
public class Target { public string GetInputIntReturnIntString(int i) { Console.WriteLine("GetInputIntReturnIntString + " + i.ToString()); return i.ToString(); } }
Program.cs
Console.WriteLine(Target.GetInputIntReturnIntString(123)); Console.ReadLine();
运行控制台程序,输出如下
Target.cs的IL代码是这样的
.method public hidebysig static string GetInputIntReturnIntString(int32 i) cil managed { .custom instance void System.Runtime.CompilerServices.NullableContextAttribute::.ctor(uint8) = ( 01 00 01 00 00 ) // 代码大小 36 (0x24) .maxstack 2 .locals init (string V_0) IL_0000: nop IL_0001: ldstr "GetInputIntReturnIntString + " IL_0006: ldarga.s i IL_0008: call instance string [System.Runtime]System.Int32::ToString() IL_000d: call string [System.Runtime]System.String::Concat(string, string) IL_0012: call void [System.Console]System.Console::WriteLine(string) IL_0017: nop IL_0018: ldarga.s i IL_001a: call instance string [System.Runtime]System.Int32::ToString() IL_001f: stloc.0 IL_0020: br.s IL_0022 IL_0022: ldloc.0 IL_0023: ret } // end of method Target::GetInputIntReturnIntString
Injector
仿照Moq测试时注入对象的写法,注入方法形如
injector.Setup(() => Target.GetInputIntReturnIntString(112)) .Returns("Bazinga!");
新建项目CecilInject
添加项目引用CecilTest,引入Nuget包Mono.Cecil
Injector.cs
using Mono.Cecil;
public class Injector { private string _assembly; private AssemblyDefinition _assemblyDefinition; public Injector(string assembly) { _assembly = assembly; _assemblyDefinition = AssemblyDefinition.ReadAssembly(_assembly); } public SetupContext Setup(Expression<Action> expression) { var methodCall = expression.Body as MethodCallExpression; var methodDeclaringType = methodCall!.Method.DeclaringType; var type = _assemblyDefinition.MainModule.Types .Single(t => t.Name == methodDeclaringType!.Name); var method = type.Methods .Single(m => m.Name == methodCall.Method.Name); return new SetupContext { MainModule = _assemblyDefinition.MainModule, Method = method }; } }
SetupContext.cs
public class SetupContext { public ModuleDefinition MainModule { get; internal set; } public MethodDefinition Method { get; internal set; } public void Returns(string rtn) { var returnString = rtn; var ilProcessor = Method.Body.GetILProcessor(); var firstInstruction = ilProcessor.Body.Instructions.First(); ilProcessor.InsertBefore(firstInstruction, ilProcessor.Create(OpCodes.Ldstr, returnString)); ilProcessor.InsertBefore(firstInstruction, ilProcessor.Create(OpCodes.Ret)); MainModule.Write("New.dll"); } }
运行Injector,查看输出的New.dll如下
.method public hidebysig static string GetInputIntReturnIntString(int32 i) cil managed { // 代码大小 42 (0x2a) .maxstack 2 .locals init (string V_0) IL_0000: ldstr "Bazinga!" IL_0005: ret IL_0006: nop IL_0007: ldstr "GetInputIntReturnIntString + " IL_000c: ldarga.s i IL_000e: call instance string [System.Runtime]System.Int32::ToString() IL_0013: call string [System.Runtime]System.String::Concat(string, string) IL_0018: call void [System.Console]System.Console::WriteLine(string) IL_001d: nop IL_001e: ldarga.s i IL_0020: call instance string [System.Runtime]System.Int32::ToString() IL_0025: stloc.0 IL_0026: br.s IL_0028 IL_0028: ldloc.0 IL_0029: ret } // end of method Target::GetInputIntReturnIntString
标记的两行IL代码就是通过Injector插入的内容
用注入后的New.dll替换原dll
运行Target.exe,可以看到dll中的函数输出
标签:string,Mono,System,Cecil,IL,GetInputIntReturnIntString,public,Target From: https://www.cnblogs.com/orcation/p/17156031.html