tags:

views:

505

answers:

5

Hi,

I wanted to know how to change the address of Test() which is in 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;
}

Answer will be greatly appreciated.

Thank in Advance

+4  A: 

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
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
+2  A: 

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
I wanted to know to change the address in vtable
mahesh
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
A: 

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
You mean MSVC doesn't optimize obvious overrides (if not used, for example)?
LiraNuna
+6  A: 

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;
}
280Z28
Thanks very much. :)
mahesh
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.
280Z28
+2  A: 
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;
}
Ganesh Kundapur
@Ganesh, Thanks you very much..simple and elegant. :)
mahesh
@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.
280Z28