首页 > 其他分享 >使用Mono.Cecil实现IL代码注入

使用Mono.Cecil实现IL代码注入

时间:2023-02-26 18:55:09浏览次数:35  
标签:string Mono System Cecil IL GetInputIntReturnIntString public Target

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

相关文章