【发布时间】:2016-06-20 04:18:05
【问题描述】:
作为一个了解更多关于 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,该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);
编辑:
我决定做一个简单的小测试,我把 oFunction 改成了 vmtable[2]
oFunction = Marshal.GetDelegateForFunctionPointer<orgFunction>(*(IntPtr*) vtable[1] );
上面的代码让我崩溃了,我很惊讶,这让我想到获取 ClassI 实例的地址可能会作为第一个函数的地址而不是 vmtable 的地址,我不认为是这种情况。
-
感谢您阅读本文,祝您早日/晚安。
最好的问候。
【问题讨论】: