好的,不久前我被介绍了挂钩/绕行的概念,我花了一些时间来了解,但尽管缺乏可用信息,但最终我能够挂钩BeginScene和EndScene使用IDA,MS Detours以及其中之一d3d9用于测试的示例应用程序。
但我意识到,这只是一种方法,所以我决定我也想熟悉我见过的其他方法。
这让我对 V-Table 进行了一些研究,更具体地说,是一种被描述为 V-Table 动态修补的实践。
我发现这样做的典型方法DirectX是创建一个“虚拟设备”,然后更改它的 V-Table,这可能会影响设备类的所有实例。
我继续尝试使用我自己的类创建一个缩小的环境,其中包含一个虚拟函数和一些实例化所述类的代码,然后连续调用所述函数。
然后我注入了一些可以访问此类副本的代码,它创建了一个新实例并尝试用另一个函数的指针修补 V-Table 函数指针。
但我很快发现我设置它的方式并没有像我预期的那样工作。我很确定它修改了 V-Table,但仅限于该类的实例。(我通过将代码组合到一个程序中进行了测试,该程序简单地调用了该函数,抓取了 V-Table,将其修改为指向另一个函数,然后再次调用该函数以确认它已被交换)
所以我想知道,DirectX 是什么让使用设备类/对象的新实例修补原始 V-Table 成为可能?
热修补是特定于 COM 的,还是有其他解释,也许我都错了?
(编辑)这就是我想要做的。
目标:
using namespace std;
class A {
public:
virtual void doThing() {
cout << "Class A doThing" << endl;
}
};
void dynamicOverride() {
cout << "Function replaced" << endl;
}
int main()
{
A* a = new A();
while (1)
{
a->doThing();
Sleep(2000);
}
system("pause");
return 0;
}
注入代码:
using namespace std;
class A {
public:
virtual void doThing() {
cout << "Class A doThing" << endl;
}
};
void dynamicOverride() {
cout << "Function replaced" << endl;
}
void MainThread()
{
A* a = new A();
void** vtable = *(void***)a;
DWORD curProtection;
VirtualProtect(&vtable[0], 4, PAGE_EXECUTE_READWRITE, &curProtection);
vtable[0] = dynamicOverride;
}
我已经在挂钩各种d3d9功能的代码中看到了这一点,大多数人将其称为创建虚拟设备。但是在这种情况下,当我尝试在 DLL 中使用一个类并注入代码来修改该类的 V-Table 时。它永远不会影响目标进程中该类的实例。