Mono.Cecil: 获取抽象方法的实现
Mono.Cecil: get implementation of abstract method
我正在使用 Cecil 检查我的程序。除了一个例外,它真的很好用。如何使用 Cecil 找到抽象方法的实现?
1。要检查的代码示例
这是一个代码示例,其中方法 CallingType::CallAbstractMethod() 调用 ImplementingType::MyMethod() .
public abstract class AbstractBase
{
public abstract bool MyMethod();
}
public class ImplementingType : AbstractBase
{
public override bool MyMethod()
{
return true;
}
}
public class CallingType
{
public void CallAbstractMethod()
{
var implementingType = new ImplementingType();
var result = implementingType.MyMethod();
}
}
2。问题
当我使用下面的 Cecil 代码检查我的程序时,变量 myMethodDefinition 表示抽象方法 AbstractBase::MyMethod() ImplementingType::MyMethod()。后者是我想找到的方法。只要阅读源代码,很明显 CallAbstractMethod 方法实际上是在调用 ImplementingType::MyMethod().
var assembly = AssemblyDefinition.ReadAssembly(Assembly.GetExecutingAssembly().Location);
var callingType = assembly.MainModule.Types
.Single(t => t.Name == "CallingType");
var callAbstractMethodDefinition = callingType.Methods
.Single(m => m.Name == "CallAbstractMethod");
var myMethodReference = callAbstractMethodDefinition.Body.Instructions
.Where(i => i.OpCode == OpCodes.Callvirt)
.Select(i => (MethodReference)i.Operand)
.Single();
var myMethodDefinition = myMethodReference.Resolve();
3。我的问题
如何让我的 Cecil 代码找到实现方法 ImplementingType::MyMethod()?
来自 CallAbstractMethod 的 IL
.method public hidebysig
instance void CallAbstractMethod () cil managed
{
// Method begins at RVA 0x2078
// Code size 15 (0xf)
.maxstack 1
.locals init (
[0] class ConsoleApplication1.ImplementingType, //first variable
[1] bool
)
IL_0000: nop
IL_0001: newobj instance void ConsoleApplication1.ImplementingType::.ctor()
IL_0006: stloc.0
IL_0007: ldloc.0
IL_0008: callvirt instance bool ConsoleApplication1.AbstractBase::MyMethod()
IL_000d: stloc.1
IL_000e: ret
} // end of method CallingType::CallAbstractMethod
如您所见,callvirt OpCode 正在调用基础 class,如果您想获得包含 MyMethod 实现的真实 class你必须像 IL 一样工作,使用堆栈。
因此,当您 运行 行 IL_0001
Your stack will have 1 item, that is the instance of ImplementingType
那你运行IL_0006
Your stack will have 0 items, and the instance of ImplementingType will be saved in first variable
那你运行IL_0007
Your stack will have 1 item again, that is the instance of ImplementingType
那你运行IL_0008,
Call MyMethod from first item in the stack, that is the instance of ImplementingType.
因此无法仅通过行 IL_0008 获取对 ImplementingType 的引用,您必须 "execute" 代码,伪堆栈过程然后您将能够发现持有的实例将执行的方法。
同样的代码可以优化,见下图:
.method public hidebysig
instance void CallAbstractMethod () cil managed
{
// Method begins at RVA 0x2065
// Code size 12 (0xc)
.maxstack 8
IL_0000: newobj instance void ConsoleApplication1.ImplementingType::.ctor()
IL_0005: callvirt instance bool ConsoleApplication1.AbstractBase::MyMethod()
IL_000a: pop
IL_000b: ret
} // end of method CallingType::CallAbstractMethod
我不知道你想用这个做什么,但你有解决方案、csprojs 和 c# class 文件,并且你想阅读代码,我建议你使用 Roslyn要做到这一点。
我正在使用 Cecil 检查我的程序。除了一个例外,它真的很好用。如何使用 Cecil 找到抽象方法的实现?
1。要检查的代码示例
这是一个代码示例,其中方法 CallingType::CallAbstractMethod() 调用 ImplementingType::MyMethod() .
public abstract class AbstractBase
{
public abstract bool MyMethod();
}
public class ImplementingType : AbstractBase
{
public override bool MyMethod()
{
return true;
}
}
public class CallingType
{
public void CallAbstractMethod()
{
var implementingType = new ImplementingType();
var result = implementingType.MyMethod();
}
}
2。问题
当我使用下面的 Cecil 代码检查我的程序时,变量 myMethodDefinition 表示抽象方法 AbstractBase::MyMethod() ImplementingType::MyMethod()。后者是我想找到的方法。只要阅读源代码,很明显 CallAbstractMethod 方法实际上是在调用 ImplementingType::MyMethod().
var assembly = AssemblyDefinition.ReadAssembly(Assembly.GetExecutingAssembly().Location);
var callingType = assembly.MainModule.Types
.Single(t => t.Name == "CallingType");
var callAbstractMethodDefinition = callingType.Methods
.Single(m => m.Name == "CallAbstractMethod");
var myMethodReference = callAbstractMethodDefinition.Body.Instructions
.Where(i => i.OpCode == OpCodes.Callvirt)
.Select(i => (MethodReference)i.Operand)
.Single();
var myMethodDefinition = myMethodReference.Resolve();
3。我的问题
如何让我的 Cecil 代码找到实现方法 ImplementingType::MyMethod()?
来自 CallAbstractMethod 的 IL
.method public hidebysig
instance void CallAbstractMethod () cil managed
{
// Method begins at RVA 0x2078
// Code size 15 (0xf)
.maxstack 1
.locals init (
[0] class ConsoleApplication1.ImplementingType, //first variable
[1] bool
)
IL_0000: nop
IL_0001: newobj instance void ConsoleApplication1.ImplementingType::.ctor()
IL_0006: stloc.0
IL_0007: ldloc.0
IL_0008: callvirt instance bool ConsoleApplication1.AbstractBase::MyMethod()
IL_000d: stloc.1
IL_000e: ret
} // end of method CallingType::CallAbstractMethod
如您所见,callvirt OpCode 正在调用基础 class,如果您想获得包含 MyMethod 实现的真实 class你必须像 IL 一样工作,使用堆栈。
因此,当您 运行 行 IL_0001
Your stack will have 1 item, that is the instance of ImplementingType
那你运行IL_0006
Your stack will have 0 items, and the instance of ImplementingType will be saved in first variable
那你运行IL_0007
Your stack will have 1 item again, that is the instance of ImplementingType
那你运行IL_0008,
Call MyMethod from first item in the stack, that is the instance of ImplementingType.
因此无法仅通过行 IL_0008 获取对 ImplementingType 的引用,您必须 "execute" 代码,伪堆栈过程然后您将能够发现持有的实例将执行的方法。
同样的代码可以优化,见下图:
.method public hidebysig
instance void CallAbstractMethod () cil managed
{
// Method begins at RVA 0x2065
// Code size 12 (0xc)
.maxstack 8
IL_0000: newobj instance void ConsoleApplication1.ImplementingType::.ctor()
IL_0005: callvirt instance bool ConsoleApplication1.AbstractBase::MyMethod()
IL_000a: pop
IL_000b: ret
} // end of method CallingType::CallAbstractMethod
我不知道你想用这个做什么,但你有解决方案、csprojs 和 c# class 文件,并且你想阅读代码,我建议你使用 Roslyn要做到这一点。