如何在 MSIL 中调用执行程序集外部的方法?
How can I call a method outside the executing assembly in 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 Class 中。此 class 位于正在编辑的方法的程序集之外。
这就是我改变原始(NestedFoo(...)
)方法主体的方式:
byte[] ilCodes = NestedFooInfo.GetMethodBody().GetILAsByteArray();
InjectionHelper.UpdateILCodes(NestedFooInfo, callIL.Concat(ilCodes).ToArray());
然后我得到一个:
System.BadImageFormatException: 'Index not found. (Exception from HRESULT: 0x80131124)'
但是 只有 如果挂钩方法 OnChangeField
在执行程序集之外(或者据我所知)。如果我将 OnChangeField
移动到与 NestedFoo 相同的 class 或 NestedFoo
程序集的另一个 class 中,它可以完美运行。
我知道元数据令牌指向一个无效的内存位置。有办法改变吗?
这里的参考资料是:
更改后的方法的方法体是什么样的:
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);
您可以查看 this link,其中显示了如何在运行时编辑 Il 代码。
您需要将记录添加到 MemberRef
并连续添加 TypeRef
或 TypeSpec
元数据表以包含对类型的引用并引用这些标记。这还涉及正确编写签名 blob。
参见 ECMA-335
的第二部分 22.38、22.25
我可以访问这样的函数体中间语言:
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 Class 中。此 class 位于正在编辑的方法的程序集之外。
这就是我改变原始(NestedFoo(...)
)方法主体的方式:
byte[] ilCodes = NestedFooInfo.GetMethodBody().GetILAsByteArray();
InjectionHelper.UpdateILCodes(NestedFooInfo, callIL.Concat(ilCodes).ToArray());
然后我得到一个:
System.BadImageFormatException: 'Index not found. (Exception from HRESULT: 0x80131124)'
但是 只有 如果挂钩方法 OnChangeField
在执行程序集之外(或者据我所知)。如果我将 OnChangeField
移动到与 NestedFoo 相同的 class 或 NestedFoo
程序集的另一个 class 中,它可以完美运行。
我知道元数据令牌指向一个无效的内存位置。有办法改变吗?
这里的参考资料是: 更改后的方法的方法体是什么样的:
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);
您可以查看 this link,其中显示了如何在运行时编辑 Il 代码。
您需要将记录添加到 MemberRef
并连续添加 TypeRef
或 TypeSpec
元数据表以包含对类型的引用并引用这些标记。这还涉及正确编写签名 blob。
参见 ECMA-335
的第二部分 22.38、22.25