【发布时间】:2021-02-25 10:18:35
【问题描述】:
我可以访问这样的函数体中间语言:
byte[] ilCodes = NestedFooInfo.GetMethodBody().GetILAsByteArray();
我希望能够修改它的 IL 代码,以便每当有 stfld IL 命令时,我都会调用以下名为 OnChangeField 的方法:
public static void OnChangeField(object obj, object value)
{
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);
然后我将原来的(NestedFoo(...)) 方法体代码改成这样:
byte[] ilCodes = NestedFooInfo.GetMethodBody().GetILAsByteArray();
var stfldOpCode = (byte)OpCodes.Stfld.Value;
for (int i = 0; i < ilCodes.Length; i++)
{
if (ilCodes[i] == stfldOpCode)
{
byte[] newIlCodes = ilCodes.Take(i).Concat(callIL).Concat(ilCodes.Skip(i)).ToArray(); // Insert the call instruction before the s
InjectionHelper.UpdateILCodes(NestedFooInfo, newIlCodes); // Explanation below
break; // Currently I just want to hook the first stfld as a PoC
}
}
在我的测试用例中改变的方法体是这样的:
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);
我得到一个:
System.InvalidProgramException: 'Common Language Runtime 检测到无效程序。'
或者一个
System.BadImageFormatException: '未找到索引。 (HRESULT 异常:0x80131124)'
如果我从 ExceptionHandlingService 中删除 postsharp 和服务接口
我想我以导致无效代码流的方式编辑 Il 代码,但查看 call 和 stfld 文档 here(p368 和 p453)我不知道我做错了什么。
对于那些想知道魔法发生在什么地方的人
InjectionHelper.UpdateILCodes(NestedFooInfo, newIlCodes); 你可以查看this link,它显示了如何在运行时编辑 Il 代码。
【问题讨论】:
-
您能否展示一个示例输入 IL 流示例以及您希望最终 IL 在注射后的样子?我之所以这么问,是因为还不清楚最终的 IL 会是什么样子。特别是我想知道您从哪里获得对
OnChangeField的调用的参数值。