C# 钩住一个 vmtable

问题描述 投票:3回答:1

作为学习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;
}

我得到一个Class指针的实例,然后输出它并等待输入。

在输入之后,我运行我想挂接的函数。

现在在我的c#端,我创建了一个dll,并且这个dll通过clr注入进入了进程的内存空间。

我用很多方法验证了注入的效果。

 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);

编辑:我决定做一个简单的小测试,在C++程序中,我发送一个输入,然后运行我们钩住的函数,应用程序崩溃。

我决定做一个简单的小测试,我把oFunction改成了vmtable[2]。

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

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


-

谢谢你的阅读,祝你晚安。

问好。

c# c++ hook native vtable
1个回答
0
投票

要做vmtable钩子,你要做的就是用一个新的指针覆盖vtable里面的函数指针,要做到这一点,你只需要在必要的时候使用VirtualProtect()获得写权限,然后使用WriteProcessMemory()来覆盖它。

你需要手动反转vtable,然后使用WriteProcessMemory()手动覆盖它。

  1. 获取vtable的地址
  2. 添加vTableIndex*4或vTableIndex*8(取决于x86与x64)。
  3. 用WriteProcessMemory覆盖这个地址。
© www.soinside.com 2019 - 2024. All rights reserved.