2

I'm calling a virtual method on the vmt by dereferencing until I get the pointer to the method.

This is all good however, how would I completely change the pointer to the VM table on the object?

Example:

PP A; // points to its default VM table

PP B; // points to a completely different VM table

A->MethodOne() // calls as mentioned above

B->MethodOne() // calls a completely different method since we override its pointer to the VM table to an alternate table with different method pointers

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;
}
Community
  • 1
  • 1
otc
  • 431
  • 4
  • 15
  • 3
    You can't portably examine or modify the vptr/vtable. It's just an implementation detail. – Brian Bi Aug 18 '15 at 23:46
  • You can override pointers on the vtable to detour virtual functions. Regarding portability, this is WinAPI focused in case you have an answer – otc Aug 18 '15 at 23:51
  • 2
    What we have here seems to be [an XY problem](http://meta.stackoverflow.com/questions/66377/what-is-the-xy-problem); you tell us a solution and ask for help fixing the solution, but you don't tell us what problem the solution actually tries to solve. – Some programmer dude Aug 18 '15 at 23:51
  • Modify the vtable an object uses without changing memory permissions. By default the vmt is in a read only page, however if you override the pointer to the table on an object at run time you can make it use a vm table you created yourself in read/write memory. – otc Aug 18 '15 at 23:53
  • 2
    You might want to specify in the question that you're looking for a Windows specific answer then. Usually people who browse the c++ tag won't give you highly nonportable solutions. – Brian Bi Aug 19 '15 at 00:05
  • If you want to play with internal compiler details, fine. But why don't you tell us what this compiler is? – curiousguy Aug 25 '15 at 19:42

2 Answers2

4

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. 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.

    *(void **)A = newVtable;
    

with newVtable defined with appropriate pointers-to-member-functions. 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. 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). This would be portable and safe.

  1. Define method pointers within the class, and update them individually.
1201ProgramAlarm
  • 32,384
  • 7
  • 42
  • 56
0

If I understand your question correctly - you want to replace the VM table of an object at runtime. Not sure why you use C++ language for such low level modifications?

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

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). And you could do your magic in inline assembly to replace the VM in the constructor.

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.

  • Impossible to control construction of objects as I am doing this in an injected dll into the process at runtime – otc Aug 19 '15 at 00:23
  • Are you writing a virus that modifies an existing process? ;) Not sure what you want to achieve. You can probably write an assembly routine rewriting memory of your process that you will call from your DLL (for example, in DllMain that is called when DLL is first loaded to memory). I don't have much knowledge about antivirus software, but that trick sounds a lot like something antivirus programs would want to flag as malware though. – Agata Staniak Aug 19 '15 at 00:41