如何替换指向inheritance自系统类的方法类中的方法的指针?

已经问过这个问题。 如何在我的方法的指针中替换指向重写(虚拟)方法的指针? (发布x64和x86)感谢@Machine Learning,解决了这个问题。 但是出现了一个新问题。 如果系统inheritance自该类,例如“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 } } } } 

当目标类派生自MarshalByRefObject ,则ReplaceInner (对于普通方法)停止工作,但ReplaceVirtualInner (对于overridden方法)是可以的。

MarshalByRefObject是通过使用代理交换消息跨应用程序域边界进行通信的对象的基类。 不从MarshalByRefObjectinheritance的对象按值隐式编组。 当远程应用程序引用按值对象编组时,对象的副本将跨应用程序域边界传递。

这可以通过将要替换的方法标记为virtual来部分修复。

但是,当目标类派生自ContentReplaceVirtualInner (用于overridden方法)也会停止工作。

不幸的是, Windows.Forms是从它们两个派生的,所以我看不到简单的解决方法。

不同的方法和选择

您可能需要考虑一种不同的方法: 使用PostSharp和面向方面编程跟踪的基本示例,CodeProject 文章和有关跟踪的文档 。

此外,另一个替代方案(不知道你是否可能)是使用WPFUserControl 而不是Forms ,在这种情况下, 正常的方法替换可以正常 工作 (在导入所需的程序集并生成Main [STAThread]

逆向工程的最终解决方案

好吧,如果你真的想让它不惜任何代价 ,让我们继续逆转目标。

使用CFF Explorer打开已编译的.exe文件。

找到.Net目录 > MetaData Streams下的表并取消组合Method Tables 。 你会发现2个方法具有相同的名称和不同的RVA对应于2个类( TypeDef )。 您只需使用注入方法RVA对目标RVA进行ovverride,并使用新名称保存反向exe。