Уже задал этот вопрос. Как заменить указатель на переопределенный (виртуальный) метод на указатель моего метода? (Release x64 и x86) Спасибо @Machine Learning, решила проблему. Но возникла новая проблема. Если система унаследовала от класса, например "Systems.Windows.Forms", то это изменение не работает. Пример:
using System;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Windows.Forms;
namespace ReplaceHandles
{
public class Target1 : UserControl
{
public void test()
{
Console.WriteLine("Target1.test()");
}
}
public class Target2
{
public void test()
{
Console.WriteLine("Target2.test()");
}
}
class Program
{
static void Main(string[] args)
{
Injection.Replace();
var target = new Target1();
target.test();
Console.Read();
}
}
}
Класс, который заменяет указатели
public class Injection
{
public static void Replace()
{
var methodToReplace = typeof(Target1).GetMethod("test", BindingFlags.Instance | BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public);
var methodToInject = typeof(Target2).GetMethod("test", BindingFlags.Instance | BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public);
RuntimeHelpers.PrepareMethod(methodToReplace.MethodHandle);
RuntimeHelpers.PrepareMethod(methodToInject.MethodHandle);
if (methodToReplace.IsVirtual) ReplaceVirtualInner(methodToReplace, methodToInject);
else ReplaceInner(methodToReplace, methodToInject);
}
Замена виртуальных методов
static void ReplaceVirtualInner(MethodInfo methodToReplace, MethodInfo methodToInject)
{
unsafe
{
var methodDesc = (UInt64*)(methodToReplace.MethodHandle.Value.ToPointer());
var index = (int)(((*methodDesc) >> 32) & 0xFF);
if (IntPtr.Size == 4)
{
if (methodToReplace.DeclaringType != null)
{
var classStart = (uint*)methodToReplace.DeclaringType.TypeHandle.Value.ToPointer();
classStart += 10;
classStart = (uint*)*classStart;
var tar = classStart + index;
var inj = (uint*)methodToInject.MethodHandle.Value.ToPointer() + 2;
#if DEBUG
var injInst = (byte*)*inj;
var tarInst = (byte*)*tar;
var injSrc = (int*)(injInst + 1);
var tarSrc = (int*)(tarInst + 1);
*tarSrc = (((int)injInst + 5) + *injSrc) - ((int)tarInst + 5);
#else
*tar = *inj;
#endif
}
}
else
{
if (methodToReplace.DeclaringType != null)
{
var classStart = (ulong*)methodToReplace.DeclaringType.TypeHandle.Value.ToPointer();
classStart += 8;
classStart = (ulong*)*classStart;
var tar = classStart + index;
var inj = (ulong*)methodToInject.MethodHandle.Value.ToPointer() + 1;
#if DEBUG
var injInst = (byte*)*inj;
var tarInst = (byte*)*tar;
var injSrc = (int*)(injInst + 1);
var tarSrc = (int*)(tarInst + 1);
*tarSrc = (((int)injInst + 5) + *injSrc) - ((int)tarInst + 5);
#else
*tar = *inj;
#endif
}
}
}
}
и замена не виртуальных методов
static void ReplaceInner(MethodInfo methodToReplace, MethodInfo methodToInject)
{
unsafe
{
if (IntPtr.Size == 4)
{
var inj = (int*)methodToInject.MethodHandle.Value.ToPointer() + 2;
var tar = (int*)methodToReplace.MethodHandle.Value.ToPointer() + 2;
#if DEBUG
var injInst = (byte*)*inj;
var tarInst = (byte*)*tar;
var injSrc = (int*)(injInst + 1);
var tarSrc = (int*)(tarInst + 1);
*tarSrc = (((int)injInst + 5) + *injSrc) - ((int)tarInst + 5);
#else
*tar = *inj;
#endif
}
else
{
ulong* inj = (ulong*)methodToInject.MethodHandle.Value.ToPointer() + 1;
ulong* tar = (ulong*)methodToReplace.MethodHandle.Value.ToPointer() + 1;
#if DEBUG
var injInst = (byte*)*inj;
var tarInst = (byte*)*tar;
var injSrc = (int*)(injInst + 1);
var tarSrc = (int*)(tarInst + 1);
*tarSrc = (((int)injInst + 5) + *injSrc) - ((int)tarInst + 5);
#else
*tar = *inj;
#endif
}
}
}
}