如何在我的方法的指针中替换指向重写(虚拟)方法的指针? (发布x64和x86)

问题动态替换C#方法的内容? 我从@ Logman那里得到了很好的回应。 我没有资格在评论中提出这个问题。

using System; using System.Reflection; using System.Runtime.CompilerServices; namespace ReplaceHandles { class Program { static void Main(string[] args) { Injection.replace(); Target target = new Target(); target.test(); Console.Read(); } } public class Injection { public static void replace() { MethodInfo methodToReplace = typeof(Target).GetMethod("test", BindingFlags.Instance | BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public); MethodInfo methodToInject = typeof(Target2).GetMethod("test", BindingFlags.Instance | BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public); RuntimeHelpers.PrepareMethod(methodToReplace.MethodHandle); RuntimeHelpers.PrepareMethod(methodToInject.MethodHandle); ReplaceInner(methodToReplace, methodToInject); } static void ReplaceInner(MethodInfo methodToReplace, MethodInfo methodToInject) { unsafe { if (IntPtr.Size == 4) { int* inj = (int*)methodToInject.MethodHandle.Value.ToPointer() + 2; int* tar = (int*)methodToReplace.MethodHandle.Value.ToPointer() + 2; *tar = *inj; } else { ulong* inj = (ulong*)methodToInject.MethodHandle.Value.ToPointer() + 1; ulong* tar = (ulong*)methodToReplace.MethodHandle.Value.ToPointer() + 1; *tar = *inj; } } } } public class Base { public virtual void test() { } } public class Target : Base { public override void test() { Console.WriteLine("Target.test()"); } public void test3() { Console.WriteLine("Target.test3()"); } } public class Target2 { public void test() { Console.WriteLine("Target.test2()"); } } } 

一切正常,但不能替代被覆盖的方法。

更新的答案

首先,请记住这一点

方法地址=方法虚拟地址+ 声明此成员的类的基地址。

如果要替换的方法是虚拟重写方法,请使用以下方法。

 if (methodToReplace.IsVirtual) { ReplaceVirtualInner(methodToReplace, methodToInject); } else { ReplaceInner(methodToReplace, methodToInject); } 

使用平台目标x86x64进行测试:它可以工作 !!!

 static void ReplaceVirtualInner(MethodInfo methodToReplace, MethodInfo methodToInject) { unsafe { UInt64* methodDesc = (UInt64*)(methodToReplace.MethodHandle.Value.ToPointer()); int index = (int)(((*methodDesc) >> 32) & 0xFF); if (IntPtr.Size == 4) { uint* classStart = (uint*)methodToReplace.DeclaringType.TypeHandle.Value.ToPointer(); classStart += 10; classStart = (uint*)*classStart; uint* tar = classStart + index; uint* inj = (uint*)methodToInject.MethodHandle.Value.ToPointer() + 2; //int* tar = (int*)methodToReplace.MethodHandle.Value.ToPointer() + 2; *tar = *inj; } else { ulong* classStart = (ulong*)methodToReplace.DeclaringType.TypeHandle.Value.ToPointer(); classStart += 8; classStart = (ulong*)*classStart; ulong* tar = classStart + index; ulong* inj = (ulong*)methodToInject.MethodHandle.Value.ToPointer() + 1; //ulong* tar = (ulong*)methodToReplace.MethodHandle.Value.ToPointer() + 1; *tar = *inj; } } } 

原始答案

你必须运行(从cmd出售)在Release模式下编译的exe ,而不是在Debug

我已经尝试过,并且我确认在这种情况下不会抛出exception。

 C:\dev\Calc>C:\dev\Calc\bin\Release\Calc.exe Target.targetMethod1() Target.targetMethod2() Not injected 2 Target.targetMethod3(Test) Target.targetMethod4() Version x64 Release Version x64 Release Version x64 Release Version x64 Release Injection.injectionMethod1 Injection.injectionMethod2 Injected 2 Injection.injectionMethod3 Test 

正如您所看到的,上面的运行没有以下exception

 C:\dev\Calc>C:\dev\Calc\bin\Debug\Calc.exe Target.targetMethod1() Target.targetMethod2() Not injected 2 Target.targetMethod3(Test) Target.targetMethod4() Version x64 Debug Version x64 Debug Version x64 Debug Version x64 Debug Unhandled Exception: System.AccessViolationException: Attempted to read or write protected memory. This is often an indication that other memory is corrupt. at InjectionTest.Target.targetMethod1() in C:\dev\Calc\Program.cs:line 38 at InjectionTest.Target.test() in C:\dev\Calc\Program.cs:line 31 at InjectionTest.Program.Main(String[] args) in C:\dev\Calc\Program.cs:line 21 

这个评论中解释了原因

在调试编译器中添加一些中间人代码并注入您的方法,您需要重新计算您的方法的地址

问题编辑后

查看修订后的问题,我确认如果将Base方法声明为virtual ,则存在问题。 我正在努力寻找解决方法。

解决方法1

我的第一个想法是替换new keyworkd而不是override (所以当Base方法不是virtual )。 这使它工作 ,所以我想(当我们有一个虚拟方法)注入应该发生在基类级别可能……并且不同的行为必须与使用callvirt vs call