c# - 如何在 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 代码。
解决方案
您需要将记录MemberRef
连续添加到元数据表TypeRef
或TypeSpec
元数据表以包含对类型的引用并引用这些标记。这还涉及正确编写签名 blob。
请参阅ECMA-335的第 II 部分 22.38、22.25
推荐阅读
- vba - 通过带有自定义标头的 shdocvw.dll 下载文件
- apache-kafka - JDBC Sink 连接器抛出 java.sql.BatchUpdateException
- snort - 如何创建 snort 内容规则
- angular - 如何使用chartsJS和Angular更新图表数组中的值
- angular - Angular ngIf 不显示 then 或 else
- android - Dagger2 在 Module 中创建重复的接口实例
- scala - 连接 HikarCP 时意外重置 autoCommit
- angular - 如何将 formGroup 传递给父元素?
- javascript - 从外部静态 JSON 文件中检索数据并在 AWS Lambda 中使用
- python - Odoo API:发票在验证后具有“已付款”状态