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

时间:2016-08-19 08:03:51

标签: c#

已经问过这个问题。 How to replace the pointer to the overridden (virtual) method in the pointer of my method? (Release x64 and 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
                }
            }
        }
    }

1 个答案:

答案 0 :(得分:2)

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

  

MarshalByRefObject是通信对象的基类   通过使用a交换消息跨应用程序域边界   代理。不从MarshalByRefObject继承的对象是   隐含地按价值编组。当远程应用程序引用a时   按值对象编组,传递对象的副本   应用领域边界。

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

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

不幸的是Windows.Forms来自两者,所以我看不到简单的解决方法。

不同的方法和备选方案

您可能需要考虑一种不同的方法:tracing with PostSharp and Aspect-Oriented Programming的基本示例,CodeProject article和关于跟踪的doc

此外,另一种选择(不知道你是否可能)是使用 WPF的UserControl而不是表格,在这种情况下正常方法替换将正常工作(在您导入所需的程序集并创建主[STAThread]后)

逆向工程的最终解决方案

好的,如果你真的想让它免费工作,让我们继续逆转目标。

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

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