C# 钩取 vmtable

3
作为一个学习C#本机端的副业项目,我想要挂接虚拟方法表中的虚拟方法。我成功地调用了该函数,但当该函数被调用时,将虚拟方法的指针更改为我的方法会导致崩溃。我为这个学习目的制作了一个小的C++应用程序,以下是它。

#include <iostream>
#include <conio.h>
using namespace std;

class Class
{
 public:
 virtual void Function ( ) = 0;
 virtual void Function2 ( ) = 0;
 virtual void Function3 ( ) = 0;
};


class ClassI : Class
{
 public:
 void Function ( )
 {
  cout << "Function1" << endl;
 }

 void Function2 ( )
 {
  cout << "Function2" << endl;
 }

 void Function3 ( )
 {
  cout << "Function3" << endl;
 }


};



int main ( )
{
 ClassI* a = new ClassI ( );
 int aaaa = 10;

 int* aaa = &aaaa;

 cout << "AddressOfClass: " << &a << endl;
 getch ( );

 a->Function ( );

 getch ( );
 delete a;
 return 0;
}

我获取类指针的实例并将其输出,然后等待输入。
在输入后,我运行想要挂钩的函数。
现在在我的c#端,我创建了一个dll,并通过clr注入将该dll放在进程的内存空间中。
我用各种方法验证了注入是否有效。

 public class EntryPoint
    {
        #region Delegates
        private delegate void orgFunction();
        private static orgFunction oFunction;
        #endregion




        public static void Hooked()
        {
            Console.WriteLine("HookedFunction");
            oFunction();
        }



        [DllExport("DllMain",CallingConvention.Cdecl)]
        public static void DllMain()
        {

            unsafe
            {
                Delegate Hook = new Action(Hooked);
                IntPtr* vtable = (IntPtr*)*(IntPtr*)0x00F3FE10;
                oFunction = Marshal.GetDelegateForFunctionPointer<orgFunction>(*(IntPtr*)vtable[0]);
                uint OldProtection;
                MUtil.MEMORY_BASIC_INFORMATION mbi;
                MUtil.VirtualQuery((IntPtr)vtable, out mbi, (IntPtr)sizeof(MUtil.MEMORY_BASIC_INFORMATION));
                MUtil.VirtualProtect(mbi.BaseAddress, (uint)mbi.RegionSize, 0x04, out OldProtection);
                vtable[0] = Marshal.GetFunctionPointerForDelegate(Hook);
                MUtil.VirtualProtect(mbi.BaseAddress, (uint)mbi.RegionSize, OldProtection, out OldProtection);
            }
        }
    }

这就是我在C#方面正在做的事情。

得到oFunction后,为了测试我调用了它并删除了其他代码,结果它工作正常。

但是,当在C++程序中发送输入并运行我们挂钩的函数时,一切都很好,但应用程序会崩溃。

我每次运行C++程序时也会更新地址,所以没问题。

        [StructLayout(LayoutKind.Sequential)]
        public struct MEMORY_BASIC_INFORMATION
        {
            public IntPtr BaseAddress;
            public IntPtr AllocationBase;
            public uint AllocationProtect;
            public IntPtr RegionSize;
            public uint State;
            public uint Protect;
            public uint Type;
        }

        [DllImport("kernel32.dll")]
        public static extern UIntPtr VirtualQuery(IntPtr lpAddress, out MEMORY_BASIC_INFORMATION lpBuffer, IntPtr dwLength);


        [DllImport("kernel32.dll", SetLastError = true)]
        internal static extern bool VirtualProtect(IntPtr address, uint size, uint newProtect, out uint oldProtect);


编辑:

我决定做一个简单的测试,我将oFunction更改为vmtable [2]

oFunction = Marshal.GetDelegateForFunctionPointer<orgFunction>(*(IntPtr*) vtable[1]  );

上面的代码让我崩溃了,这让我想到获取ClassI实例的地址可能会给出第一个函数的地址,而不是vmtable的地址,但我认为这不是情况。


-

谢谢阅读,祝你有一个美好的白天/晚上。

最好的问候。

1个回答

0

要执行vmtable hook,您只需使用新的函数指针覆盖vtable内部的函数指针即可,为此,您只需使用VirtualProtect()获取必要的写入权限,然后使用WriteProcessMemory()进行覆盖。

您需要手动反转vtable并手动使用WriteProcessMemory()进行覆盖。

  1. 获取vtable的地址
  2. 添加vTableIndex*4或vTableIndex*8(取决于x86 vs x64)
  3. 使用WriteProcessMemory覆盖此地址

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接