如何识别将传递给 Mono.Cecil 中特定 IL 方法调用的参数
本文关键字:Cecil IL 方法 参数 调用 Mono 何识别 识别 | 更新日期: 2023-09-27 18:34:24
我正在使用Mono.Cecil对程序集进行一些分析和重写。在某些情况下,这很容易:您可以在调用之前查看参数的加载位置:
// Math.Pow(2, 4)
IL_0001: ldc.r8 00 00 00 00 00 00 00 40
IL_000A: ldc.r8 00 00 00 00 00 00 10 40
IL_0013: call System.Math.Pow
但是,当函数的参数本身是复杂的表达式时,这变得更加复杂:
// Math.Pow(2, Math.Abs(Math.Max(17, "123".GetHashCode())));
IL_0001: ldc.r8 00 00 00 00 00 00 00 40
IL_000A: ldc.i4.s 11
IL_000C: ldstr "123"
IL_0011: callvirt System.Object.GetHashCode
IL_0016: call System.Math.Max
IL_001B: call System.Math.Abs
IL_0020: conv.r8
IL_0021: call System.Math.Pow
在这种情况下,在加载第一个参数和加载第二个参数之间会发生一堆事情。我想知道:Mono.Cecil 是否公开了任何用于查找负责推动每个参数的 IL 指令的工具?
ILSpy是一个基于Cecil的开源IL到C#反编译器,它也可以用作一个名为ICSharpCode.Decompiler的库。它可以将IL转换为"IL AST",我认为这正是您所要求的。
如果你像这样使用它:
var decompiled = new ILAstBuilder().Build(method, true, new DecompilerContext(module));
var block = new ILBlock(decompiled);
new ILInlining(block).InlineAllVariables();
然后对于以下方法(在发布模式下编译):
static double F()
{
return Math.Pow(2, Math.Abs(Math.Max(17, "123".GetHashCode())));
}
变量block
将包含:
ret(call(Math::Pow, ldc.r8(2), conv.r8(call(Math::Abs, call(Math::Max, ldc.i4(17), callvirt(object::GetHashCode, ldstr("123")))))));
请注意,我没有使用ICSharpCode.Decompiler的经验,所以可能有更好的方法可以做到这一点。