15

I would like to know how to change the address of Test which is in the virtual table with that of HackedVTable.

void HackedVtable()
{
    cout << "Hacked V-Table" << endl;
}

class Base
{    
public:
    virtual Test()  { cout <<"base";    }
    virtual Test1() { cout << "Test 1"; }
    void *prt;
    Base(){}
};

class Derived : public Base
{
public: 
    Test()
    {
        cout <<"derived";
    }
};

int main()
{    
    Base b1;

    b1.Test(); // how to change this so that `HackedVtable` should be called instead of `Test`?

    return 0;
}
halfer
  • 19,824
  • 17
  • 99
  • 186
Priyanka Mishra
  • 10,400
  • 18
  • 62
  • 75

9 Answers9

19

This works for 32-bit MSVC builds (it's a very simplified version of some production code that's been in use for well over a year). Note that your replacement method must explicitly specify the this parameter (pointer).

// you can get the VTable location either by dereferencing the
// first pointer in the object or by analyzing the compiled binary.
unsigned long VTableLocation = 0U;
// then you have to figure out which slot the function is in. this is easy
// since they're in the same order as they are declared in the class definition.
// just make sure to update the index if 1) the function declarations are
// re-ordered and/or 2) virtual methods are added/removed from any base type.
unsigned VTableOffset = 0U;
typedef void (__thiscall Base::*FunctionType)(const Base*);
FunctionType* vtable = reinterpret_cast<FunctionType*>(VTableLocation);

bool hooked = false;
HANDLE process = ::GetCurrentProcess();
DWORD protection = PAGE_READWRITE;
DWORD oldProtection;
if ( ::VirtualProtectEx( process, &vtable[VTableOffset], sizeof(int), protection, &oldProtection ) )
{
    vtable[VTableOffset] = static_cast<FunctionType>(&ReplacementMethod);

    if ( ::VirtualProtectEx( process, &vtable[VTableOffset], sizeof(int), oldProtection, &oldProtection ) )
        hooked = true;
}
Sam Harwell
  • 97,721
  • 20
  • 209
  • 280
  • 1
    NP. I had to use it to correct a faulty parameter validation that showed up on my machine configuration in a 3rd party application that caused a crash every time I tried to use the program. – Sam Harwell Oct 09 '09 at 07:08
11

The V-Table is an implementation detail.

The compiler is not required to use one (it just happens to be the easiest way to implement virtual functions). But saying that each compiler can (and does) implement it slightly differently as a result there is no answer to your question.

If you ask how do I hack a vtable for a program built with:

Compiler <X> Version <Y> Build <Z>

Then somebody may know the answer.

Martin York
  • 257,169
  • 86
  • 333
  • 562
  • 3
    Well said. Furthermore even the compilers that use a V-Table sometimes produce code with static linking if the semantics of the program allows it. – mjv Oct 09 '09 at 06:35
  • @mjv the compilers I've seen are actually very consistent - if you're not accessing the object through a pointer or reference, they'll use static linking every time. It's simpler and more performant. – Mark Ransom Sep 08 '20 at 22:28
7
void HackedVtable()
{
    cout << "Hacked V-Table" << endl;
}

class Base
{

public:
       virtual Test()  { cout <<"base";    }
       virtual Test1() { cout << "Test 1"; }
       void *prt;
       Base(){}
};

class Derived:public Base
{
    public: 
           Test() 
           {
                   cout <<"derived";
           }
};

typedef void (*FUNPTR)();
typedef struct
{
   FUNPTR funptr;
} VTable;


int main()
{

    Base b1;
    Base *b1ptr = &b;

    VTable vtable;
    vtable.funptr = HackedVtable;

    VTable *vptr = &vtable;
    memcpy ( &b1, &vptr, sizeof(long) );

    b1ptr->Test();

    //b1.Test(); // how to change this so that HackedVtable() should be called instead of Test()

    return 0;
}
Luc Touraille
  • 79,925
  • 15
  • 92
  • 137
Ganesh Kundapur
  • 525
  • 1
  • 6
  • 13
  • @Ganesh, Thanks you very much..simple and elegant. :) – Priyanka Mishra Oct 10 '09 at 07:02
  • 1
    @mahesh, this is *completely* different resulting functionality than mine. Here, it replaces the functions for a single instance (b1). In mine, it replaces the functions for *all* instances of a specific type. – Sam Harwell Oct 10 '09 at 07:32
2

Under Mac OS X 10.10.3 + gcc 4.8.3, following code works well.

void HackedVtable()
{
    cout << "Hacked V-Table" << endl;
}

class Base
{    
public:
    virtual void Test()  { cout << "base" << endl;    }
    virtual void Test1() { cout << "Test 1" << endl; }
    void *prt;
    Base(){}
};

class Derived : public Base
{
public: 
    void Test()
    {
        cout << "derived" << endl;
    }
};

int main()
{    
    Base b1;
    Base* pb1 = &b1;

    *(*(void***)pb1) = (void*) HackedVtable;
    pb1->Test();

    //It works for all the Base instance
    Base b2;
    Base* pb2 = &b2;
    pb2->Test();

    //But Derived's virtual function table is separated from Base's
    Derived d1;
    Derived* pd1 = &d1;
    pd1->Test();
    *(*(void***)pd1) = (void*) HackedVtable;
    pd1->Test();

    return 0;
}

Its output:

$ g++ h.cpp; ./a.out
Hacked V-Table
Hacked V-Table
derived
Hacked V-Table

I test the same code under Ubuntu 12.04 + g++ 4.9.0. However, it does not work and arises segmentation fault. It seems Linux assigns the virtual function table in a read only area (e.g. rodata) to forbid hacking.

chetui
  • 21
  • 1
1

I don't think there is a portable way. Mostly because of compiler optimization and different architecture ABI between every target.

But C++ provides you with that exact same capability, why not use it?

void HackedVtable()
{
    cout << "Hacked V-Table" << endl;
}

class Base
{
public:
       virtual Test()  { cout <<"base";    }
       virtual Test1() { cout << "Test 1"; }
       void *prt;
       Base(){}
};

class Derived : public Base
{
    public: 
           Test() 
           {
                HackedVtable(); // <-- NOTE
           }
};

int main()
{
    Derived b1; // <-- NOTE

    b1.Test();

    return 0;
}
LiraNuna
  • 64,916
  • 15
  • 117
  • 140
  • I wanted to know to change the address in vtable – Priyanka Mishra Oct 09 '09 at 06:39
  • 3
    You don't want to know. Even for educational purposes, theory is *fine* in this case. The compiler knows much more than you about your program than you might think, so messing with a table that may or may not exist (in this case, never, since it's not in use) is a bad idea and will only cause you to think you're a bad programmer by segfaulting too much. Don't. – LiraNuna Oct 09 '09 at 06:52
  • 1
    Yes I definitely want to know. The difference is that your method is compile-time, while I need run-time changing of the virtual functions / table. – Carlo Wood Dec 09 '18 at 20:28
1

Another way to achieve the same thing is by cheking similar code:

GObject:

http://en.wikipedia.org/wiki/Gobject

GLib:

http://en.wikipedia.org/wiki/GLib

Vala:

http://en.wikipedia.org/wiki/Vala_%28programming_language%29

Those guys wanted to work with a object and class oriented programming language, but "C++", didn't fit their requisites. Then , they took "plain C", and simulate objects withn records & pointers, including Virtual Method Tables. Eventually got a similar language called "Vala", their own "C++" alike language (with their own V.M.T.).

Another related links:

http://en.wikipedia.org/wiki/Virtual_method_table

http://www.artima.com/insidejvm/ed2/jvmP.html

Cheers.

umlcat
  • 4,091
  • 3
  • 19
  • 29
0

well its quite easy to figure out. Find hte VTAble pointer (In visual studio its the first 4/8 bytes). Then step into a normal call of Test (into the assembler) and you'll see it jump to the Vtable and then to your test function. To override test just replace the pointer where you jumped from in the VTable.

Goz
  • 61,365
  • 24
  • 124
  • 204
0

I don't think the vTable is in read only area because is it dynamically populated. The only way it can fail is when the compiler is absolutely sure which implementation will be called in compile time and skip the vTable lookup with direct function call(de-virtualization).

EDIT: As @groovyspaceman pointed out, I see that I used wrong wording. The vTable class member pointer is mutable, the vTable itself is compiler generated and it depends on the system and the compiler if it can, or cannot be modified.

The Storm
  • 71
  • 8
  • Sorry but still can't post a comments. Feel free to delete this post if it is not useful... – The Storm Jun 07 '15 at 22:49
  • VTables are not dynamically populated but laid down at compile-time. Whether or not that segment is writable is system dependent. The vtable pointer (within the class instance) is fair-game and *could* be rewritten to point at a custom vtable. Just sayin'. – groovyspaceman Oct 11 '18 at 09:58
  • You are right. I used wrong wording. The vtable pointer is the one that can be changed, not the vTable itself. – The Storm Mar 19 '19 at 13:44
0

This is usually called "virtual table hooking" or something like that. If you are going to use it much, then I suggest the SourceHook library. It was developed for hacking closed source game engines in game mods. For instance, it was used in The Dark Mod before idTech4 became open source.

stgatilov
  • 5,333
  • 31
  • 54