如何将指针替换为从系统类继承的方法的类中的方法指针

本文关键字:指针 方法 继承 系统 替换 | 更新日期: 2023-09-27 18:03:00

已经问过这个问题了。如何替换指针覆盖(虚拟)方法在我的方法的指针?(x64和x86版本)谢谢机器学习,解决了问题。但是一个新的问题出现了。如果系统继承自类,如"system . windows . net"。form",那么更改不起作用。例子:

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是通信对象的基类通过交换消息来跨越应用程序域边界代理。不从MarshalByRefObject继承的对象是按值隐式封送。当远程应用程序引用按值对象封送,传递对象的副本应用程序域边界。

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

但是当目标类从Content派生时,ReplaceVirtualInner(用于overridden方法)也停止工作。

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

不同的方法和选择

你可能想考虑一种不同的方法:一个用PostSharp和面向方面编程跟踪的基本例子,一篇CodeProject文章和关于跟踪的文档。

此外,另一种选择(不知道您是否可能)是使用WPF的UserControl而不是Forms,在这种情况下,normal方法替换将工作良好(在您导入所需的程序集并制作主[STAThread]之后)

逆向工程的最终解

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

使用CFF资源管理器打开编译后的.exe。

找到。net目录> MetaData Streams下的表并取消Method Tables组。您将发现两个具有相同名称和不同RVA的方法对应于两个类(TypeDef)。您只需使用注入方法RVA覆盖目标RVA,并使用新名称保存反转的exe。