我通过解除引用在vmt上调用虚方法,直到我得到指向该方法的指针。
这一切都很好,但是如何完全更改指向对象上VM表的指针?
实施例
PP A; //指向其默认VM表
PP B; //指向一个完全不同的VM表A-> MethodOne()//如上所述调用
B-> MethodOne()//调用一个完全不同的方法,因为我们将其指向VM表的指针覆盖到具有不同方法指针的备用表
我将如何做到这一点?
我的代码:
#include <Windows.h>
#include <iostream>
class PP
{
public:
PP() { }
~PP() { }
virtual void MethodOne() { std::cout << "1" << std::endl; }
virtual void MethodTwo() { std::cout << "2" << std::endl; }
};
typedef void (*MyFunc)(void);
int main()
{
PP* A = new PP();
//(*(void(**)(void))(*(DWORD*)A + (4*1)))();
( *(MyFunc*) ( *(DWORD*)A + (4*0) ) )(); // call index 0 (4bytes*0)
A->MethodOne();
A->MethodTwo();
system("PAUSE");
delete A;
return 0;
}
答案 0 :(得分:4)
由于推导另一个课程的常用方法不适合你,我可以想到三种解决方案。
更改vtable指针。这是不可移植的,并且有许多方法可以解决可怕的错误。假设vtable位于类的开头(它适用于WinAPI中的简单类),您可以将该指针替换为您自己的表。
*(void **)A = newVtable;
使用适当的指向成员函数的指针定义newVtable。你必须非常谨慎地设置它。它还可能搞乱删除和异常处理。
创建自己的vtable。使用所需的指向方法函数的函数定义一个类,然后在类中将指针定义为其中一个。然后,您可以根据需要更改指向表的指针。虽然你可以定义其他成员函数来隐藏丑陋的代码,但这在调用时会更加冗长。
class vtable;
class PP {
public:
PP();
~PP() { }
void MethodOne() { std::cout << "1" << std::endl; }
void MethodTwo() { std::cout << "2" << std::endl; }
const vtable *pVtable;
};
class vtable {
public:
void (PP::*MethodOne)();
};
vtable One = {&PP::MethodOne};
vtable Two = {&PP::MethodTwo};
PP::PP(): pVtable(&One) { }
void main() {
PP* A = new PP();
A->pVtable = &One;
// call with
(A->*(A->pVtable->MethodOne))(); // calls MethodOne
A->pVtable = &Two;
(A->*(A->pVtable->MethodOne))(); // calls MethodTwo
}
(使用VS2015社区进行编译和测试)。这将是便携和安全的。
答案 1 :(得分:0)
如果我正确理解您的问题 - 您希望在运行时替换对象的VM表。不确定为什么使用C ++语言进行这种低级修改?
无论如何,Microsoft C / C ++支持称为&#34; naked&#34;调用约定(而不是&#34; stdcall&#34;,&#34; fastcall&#34;等等,它们在如何/什么顺序传递给函数以及它们是否在堆栈上传递或不同在寄存器中)。在裸调用约定中,您可以完全控制如何传递params - 您可以编写自己的内联汇编代码片段,负责将内容放入堆栈并进行堆栈展开。
https://msdn.microsoft.com/en-us/library/5ekezyy2.aspx
例如,您可以使用构造函数的裸调用约定(如果编译器不会抱怨)并将新VM表作为&#34;隐藏&#34; param,就像&#34;这个&#34; param是一个隐藏的&#34; param传递给成员函数(在&#34; thiscall&#34;调用约定中)。你可以在内联汇编中发挥你的魔力来替换构造函数中的VM。这整个事情似乎是一个可怕的,脆弱的想法,但因为更新其内部(通常不会暴露给您)的新版本的编译器可能会破坏您的代码。如果你真的需要某种动态机制来选择要调用的方法,那么你应该实现自己的机制,而不是在C ++的VMT机制之上作为黑客攻击。