简体   繁体   English

完全覆盖VMT(虚拟方法表)

[英]Completely overriding the VMT (Virtual Method Table)

I'm calling a virtual method on the vmt by dereferencing until I get the pointer to the method. 我通过取消引用直到在该方法的指针之前在vmt上调用虚拟方法。

This is all good however, how would I completely change the pointer to the VM table on the object? 一切都很好,但是我将如何完全更改对象上VM表的指针?

Example: 例:

PP A; PP A; // points to its default VM table //指向其默认VM表

PP B; PP B; // points to a completely different VM table //指向完全不同的VM表

A->MethodOne() // calls as mentioned above A-> MethodOne()//如上所述调用

B->MethodOne() // calls a completely different method since we override its pointer to the VM table to an alternate table with different method pointers B-> MethodOne()//调用完全不同的方法,因为我们将其指向VM表的指针覆盖为具有不同方法指针的备用表

How would I accomplish this? 我将如何完成?

My Code: 我的代码:

#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;
}

Since the usual method of deriving another class won't work for you, there are three solutions I can think of. 由于派生另一个类的通常方法对您不起作用,因此我可以想到三种解决方案。

  1. Change the vtable pointer. 更改vtable指针。 This is non-portable and has many ways to just go horribly wrong. 这是不可移植的,并且有很多方法可以导致严重错误。 Assuming the vtable is at the start of the class (which it is for simple classes in the WinAPI), you can replace that pointer with one to a table of your own. 假设vtable在类的开头(对于WinAPI中的简单类),则可以将该指针替换为一个指向您自己的表的指针。

     *(void **)A = newVtable; 

with newVtable defined with appropriate pointers-to-member-functions. 使用newVtable定义了适当的指向成员函数的指针。 You'll have to use extreme caution to set this up. 您必须格外小心地进行设置。 It could also mess up deletes and exception handling. 它还可能使删除和异常处理混乱。

  1. Create your own vtable. 创建自己的vtable。 Define a class with the required pointer-to-method-functions, then define a pointer in your class to one of these. 使用所需的方法指针指针定义一个类,然后在您的类中定义一个指向其中之一的指针。 You can then change the pointer to the table as necessary. 然后可以根据需要更改指向表的指针。 This would be a bit more verbose on calling, although you could define other member functions to hide the ugly code. 尽管可以定义其他成员函数来隐藏丑陋的代码,但这在调用时会更加冗长。

     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 } 

(Compiled and tested with VS2015 Community). (使用VS2015社区进行编译和测试)。 This would be portable and safe. 这将是便携式且安全的。

  1. Define method pointers within the class, and update them individually. 在类中定义方法指针,然后分别更新它们。

If I understand your question correctly - you want to replace the VM table of an object at runtime. 如果我正确理解您的问题-您想在运行时替换对象的VM表。 Not sure why you use C++ language for such low level modifications? 不确定为什么要使用C ++语言进行此类低级修改?

Anyways, Microsoft C/C++ supports something called a "naked" calling convention (as opposed to "stdcall", "fastcall" etc. that differ in how/what order params are passed to a function and whether they're passed on a stack or in registers). 无论如何,Microsoft C / C ++支持一种称为“裸”的调用约定(与“ stdcall”,“ fastcall”等相反),它们在如何/以何种顺序将参数传递给函数以及是否在堆栈上传递参数方面有所不同或在寄存器中)。 In naked calling convention, YOU have absolute control of how you pass params - you write your own inline assembly snippets responsible for putting stuff on stack and stack unwinding. 在裸调用约定中,您可以完全控制传递参数的方式-您编写自己的内联汇编代码片段,这些代码片段负责将内容放到堆栈上并展开堆栈。

https://msdn.microsoft.com/en-us/library/5ekezyy2.aspx https://msdn.microsoft.com/en-us/library/5ekezyy2.aspx

You could, for example, use the naked calling convention for the constructor (if compiler won't complain) and pass in the new VM table as a "hidden" param, just like "this" param is a "hidden" param passed to member functions (in the "thiscall" calling convention). 例如,您可以对构造函数使用裸调用约定(如果编译器不会抱怨),并将新的VM表作为“隐藏”参数传递,就像“ this”参数是传递给成员函数(在“ thiscall”调用约定中)。 And you could do your magic in inline assembly to replace the VM in the constructor. 您可以在内联汇编中发挥神奇作用,以替换构造函数中的VM。

This whole thing seems like a horrible, fragile idea though because a new version of the compiler that changes its internals (normally not exposed to you) may potentially break your code. 整个事情看起来像一个可怕的,脆弱的想法,因为更改其内部结构的编译器的新版本(通常不向您公开)可能会破坏您的代码。 If you really need some sort of dynamic mechanism of choosing what method to call, sounds like you should implement your own mechanism instead of piggybacking as a hack on top of C++'s VMT mechanism. 如果您确实需要某种动态机制来选择要调用的方法,听起来您应该实现自己的机制,而不是像C ++的VMT机制那样piggy带。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM