在STFLD之前添加对方法的调用会导致InvalidProgramException



我可以访问函数体中间语言,如下所示:

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

我希望能够修改其IL代码,以便每当有stfldIL命令时,我都会调用以下名为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:"公共语言运行时检测到无效程序。">

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

如果我从ExceptionHandlingService中删除postsharp和服务接口

我想我编辑Il代码的方式会导致无效的代码流,但看看这里的callstfld文档(p368和p453(,我不知道我做错了什么。

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

IL有点脆弱,它并不是真正的手工组装:(在任何情况下,你都不能仅仅通过寻找一个单字节值来找到stfld——你需要确保你真正读取的是操作码,而不是参数等。

如果你没有一个压倒一切的理由不这样做,我建议使用Expression树来编译";生的";IL-这应该可以帮你省去很多头痛。无论如何,尝试通过非常小的步骤进行移动-例如,首先尝试在方法开始时注入调用,尝试一个没有参数的方法,然后尝试找到stfld,处理更复杂的情况(装箱等(…

为了向前发展,使用编译器和反编译器会有所帮助。编译调用方法的普通C#代码,并将其反编译为IL。尝试注入,并反编译生成的完整IL字节数组-你可能会发现错误(尽管我不会说"足够容易",因为它需要一点IL经验才能发现大多数错误:(。

有一点很突出,那就是您保留了stfldcall,但只传递了一次参数。同样,作为识别问题的一部分,它有助于一次做一件事——用call替换stfld,以确保该部分正常工作;然后处理堆栈上的值的CCD_ 15,以允许您调用这两个操作。

以下异常是由执行程序集外部的OnChangeField((方法的元数据标记引起的。

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

下面的异常是由应用于NestedFoo函数的postsharp方面引起的,但也因为我没有在堆栈上推送任何要传递给OnchangeField参数的参数:

System.InvalidProgramException:"公共语言运行时检测到无效程序。">

相关内容

  • 没有找到相关文章

最新更新