首页 > 解决方案 > 如何在 MSIL 中调用执行程序集之外的方法?

问题描述

我可以访问这样的函数体中间语言:

byte[] ilCodes = NestedFooInfo.GetMethodBody().GetILAsByteArray();

我可以修改它的 IL 代码,以便在执行方法主体之前调用以下名为的方法OnChangeField

public static void OnChangeField()
{
    Console.WriteLine("VICTORY");
    return;
}

到目前为止,我这样做:

我将调用指令定义为我要调用的方法:

MethodInfo OnStfld = typeof(MethodBoundaryAspect).GetMethod("OnChangeField");
byte[] callIL = new byte[5];
callIL[0] = (byte)OpCodes.Call.Value;
callIL[1] = (byte)(OnStfld.MetadataToken & 0xFF);
callIL[2] = (byte)(OnStfld.MetadataToken >> 8 & 0xFF);
callIL[3] = (byte)(OnStfld.MetadataToken >> 16 & 0xFF);
callIL[4] = (byte)(OnStfld.MetadataToken >> 24 & 0xFF);

请注意,OnChangeField 位于 MethodBoundaryAspect 类中。此类位于正在编辑的方法的程序集之外。

这就是我改变 original( NestedFoo(...)) 方法体的方式:

byte[] ilCodes = NestedFooInfo.GetMethodBody().GetILAsByteArray();
InjectionHelper.UpdateILCodes(NestedFooInfo, callIL.Concat(ilCodes).ToArray());

我得到一个:

System.BadImageFormatException: '未找到索引。(来自 HRESULT 的异常:0x80131124)'

但前提 挂钩方法OnChangeField在执行程序集之外(或者我理解)。如果我移动OnChangeField到与 NestedFoo 相同的类或另一个类的NestedFoo程序集中,它会完美运行。

我了解元数据令牌指向无效的内存位置。有没有办法改变它?

这里的参考是:改变方法的方法体是什么样的:

public class ExceptionHandlingService : IExceptionHandlingService
{
        public static string var1 = "initialValue";
        public static string Var2 { get; set; } = "initialValue";
        public string var3 = "initialValue";
        public string Var4 { get; set; } = "initialValue";

        public string NestedFoo(SampleClass bar)
        {
            var1 = "value set in NestedFoo()";
            Var2 = "value set in NestedFoo()";
            var3 = "value set in NestedFoo()";
            Var4 = "value set in NestedFoo()";
            AddPerson("From", "NestedFoo", 2);
            return Foo();
        }
        [...]
}

以及我如何调用更改后的方法:

var a = new ExceptionHandlingService();
var b = new SampleClass("bonjour", 2, 3L); // Not really relevant
a.NestedFoo(b);

对于那些想知道发生了什么魔法的人, InjectionHelper.UpdateILCodes(NestedFooInfo, newIlCodes);您可以查看此链接,该链接显示了如何在运行时编辑 Il 代码。

标签: c#hookclrjitcil

解决方案


您需要将记录MemberRef连续添加到元数据表TypeRefTypeSpec元数据表以包含对类型的引用并引用这些标记。这还涉及正确编写签名 blob。

请参阅ECMA-335的第 II 部分 22.38、22.25


推荐阅读