如何删除cecil指令

Jai*_*ews 1 .net mono mono.cecil

我有这个方法:

public int Test()
{
    ExternalClass cls = new ExternalClass();
    return cls.ExternalMethod();
}
Run Code Online (Sandbox Code Playgroud)

我需要使用IL Injection更改它,因此我可以将类型作为参数传递并删除直接对象创建,如下所示:

public int Test(ExternalClass cls)
{

    return cls.ExternalMethod();
}
Run Code Online (Sandbox Code Playgroud)

我可以使用<>.Parameters.Add(_ ___)添加附加参数,并生成新的Assembly.

问题是我无法删除新对象创建的指令.以下是我用来删除它的行.

ILProcessor ilProcessor = <<MethodDefinition>>.Body.GetILProcessor();
ilProcessor.Remove(<<newobj instruction>>);
Run Code Online (Sandbox Code Playgroud)

一旦我尝试调用如下所示的修改后的汇编方法,就会抛出错误"Common Language Runtime检测到无效程序".

ExternalClass ext = new ExternalClass();
int i = prg1.Test(ext);
Run Code Online (Sandbox Code Playgroud)

我知道我可能也需要处理内存分配相关的东西.如果有人能够在这里提供额外的步骤,我将不胜感激.

cdh*_*wie 6

你不能只是删除newobj指令; 你留下了一个无效的程序,正如运行时告诉你的那样.这里大致是原始方法如何转换为IL:

public Int32 Test()
{
    .local ExternalClass 0;

    // ExternalClass cls = new ExternalClass();
    newobj class ExternalClass();
    stloc.0;

    // return cls.ExternalMethod();
    ldloc.0;
    callvirt Int32 class ExternalClass:ExternalMethod();
    ret;
}
Run Code Online (Sandbox Code Playgroud)

如果仅删除newobj指令,则stloc指令将不会在堆栈中存储任何内容以存储在本地.您需要将方法转换为:

public Int32 Test(ExternalClass cls)
{
    // return cls.ExternalMethod();
    ldarg.1;
    callvirt Int32 class ExternalClass:ExternalMethod();
    ret;
}
Run Code Online (Sandbox Code Playgroud)

所以你需要做三件事:

  1. 将参数添加到方法签名,
  2. 删除一切至并包括ldloc指令.
  3. ldarg.1在方法的开头插入指令.

或者,您也可以删除ExternalClass本地.(这将通过JIT编译器进行优化,但会使IL图像膨胀.)