#c# #hook #clr #jit #cil
#c# #перехват #clr #jit #cil
Вопрос:
У меня есть доступ к промежуточному языку тела функции, подобному этому :
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 amp; 0xFF);
callIL[2] = (byte)(OnStfld.MetadataToken >> 8 amp; 0xFF);
callIL[3] = (byte)(OnStfld.MetadataToken >> 16 amp; 0xFF);
callIL[4] = (byte)(OnStfld.MetadataToken >> 24 amp; 0xFF);
Обратите внимание, что OnChangeField находится в классе MethodBoundaryAspect . Этот класс находится вне сборки редактируемого метода.
И вот как я изменяю исходное NestedFoo(...)
тело метода () :
byte[] ilCodes = NestedFooInfo.GetMethodBody().GetILAsByteArray();
InjectionHelper.UpdateILCodes(NestedFooInfo, callIL.Concat(ilCodes).ToArray());
И я получаю :
Система.Исключение BadImageFormatException: ‘Индекс не найден. (Исключение из HRESULT: 0x80131124) ‘
Но только если метод подключения OnChangeField
находится вне (или, как я понял) исполняемой сборки. Если я перейду OnChangeField
в тот же класс, что и NestedFoo, или в другой класс NestedFoo
сборки, он работает отлично.
Я понимаю, что metadatatoken указывает на ячейку памяти, которая недействительна. Есть ли способ это изменить?
Для ссылок здесь: как выглядит тело метода измененного метода:
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-код во время выполнения.
Ответ №1:
Вам нужно добавить записи в MemberRef
и последовательно TypeRef
или TypeSpec
таблицы метаданных, чтобы содержать ссылки на типы и ссылаться на эти токены. Это также включает в себя правильное написание больших двоичных объектов подписи.
См. Раздел II 22.38, 22.25 ECMA-335