1

I have 3 classes (Cat, HouseCat:Cat, Lion:Cat). What I'm trying to do is change HouseCat's VTable to make HouseCat eat Meat instead of cat food.

Classes I Use:

class Cat
{
public:
    int age = 2;
    virtual void eat() {
        cout << "Meat" << this->age << endl;
    };

    virtual void sound() {
        cout << "Meow!" << this->age << endl;
    };
};


class HouseCat : public Cat
{
public:
    virtual void eat() {
        cout << "Cat Food" << this->age << endl;
    };
};

class Lion : public Cat
{
public:
    virtual void sound() {
        cout << "ROAR!" << this->age << endl;
    };
};

I'm trying to edit those classes' VTable entries by a VTable struct I created.

static void __memcpy(void * set, void * data, int size){
    DWORD old;
    VirtualProtect(set, size, PAGE_EXECUTE_READWRITE, &old);
    char*dest = (char*)set;
    char*src = (char*)data;
    for (int i = 0; i < size; i++)dest[i] = src[i];
    VirtualProtect(set, size, old, &old);
}

struct VTable{

    static VTable read(void * object){
        VTable  vt = *(VTable*)(object);
        int i = 0;
        while ((DWORD)vt.functions[i] != 0x0)
            i++;
        vt.size = i;
        return vt;
    }
    void ** functions;
    int size;

    void redirectFunction(int i, void * redirect){
        __memcpy(&functions[i], &redirect, 4);
    }
};

I confirmed that VTable[0] = eat(), so i decided to try making a change on the Vtable like this :

int main(int argc, char* argv[])
{

    Lion lion = Lion();
    Cat base = Cat();
    HouseCat home = HouseCat();



    VTable lionVTable = VTable::read(&lion);
    VTable baseVTable = VTable::read(&base);
    VTable homeVTable = VTable::read(&home);
    cout << "-------------- BEFORE EDIT -----------------" << endl
    << "Base:" << endl
    << (baseVTable.functions[0]) << endl
    << (baseVTable.functions[1]) << endl
    << "HomeCat:" << endl
    << (homeVTable.functions[0]) << endl
    << (homeVTable.functions[1]) << endl
    << "Lion:" << endl
    << (lionVTable.functions[0]) << endl
    << (lionVTable.functions[1]) << endl;

    homeVTable.redirectFunction(0, lionVTable.functions[0]);


    cout << "-------------- AFTER EDIT -----------------" << endl
    << "Base:" << endl
    << (baseVTable.functions[0]) << endl
    << (baseVTable.functions[1]) << endl
    << "HomeCat:" << endl
    << (homeVTable.functions[0]) << endl
    << (homeVTable.functions[1]) << endl
    << "Lion:" << endl
    << (lionVTable.functions[0]) << endl
    << (lionVTable.functions[1]) << endl;

    pause();




    cout << "---Base---" << endl << endl;
    base.eat();
    base.sound();
    cout << "---Lion---" << endl << endl;
    lion.eat();
    lion.sound();
    cout << "---Home---" << endl << endl;
    home.eat();
    home.sound();
    cout << "---End---" << endl;



    pause();
    return 0;

}

It outputed;

-------------- BEFORE EDIT ----------------
Base:
0031106E
0031121C
HomeCat:
00311285
0031121C
Lion:
0031106E
003113F2
-------------- AFTER EDIT -----------------
Base:
0031106E
0031121C
HomeCat:
0031106E
0031121C
Lion:
0031106E
003113F2

You can see that HomeCat[0] changed from 0x311285->0x31106E

VMT.exe+11285 - E9 B6350000           - jmp VirtualMethodTable test.HouseCat::eat
[Cat Food]
->
VMT.exe+1106E - E9 ED450000           - jmp VirtualMethodTable test.Cat::eat
[Meat]

The problem is the output of the functions didnt change at all.

---Base---

Meat2

Meow!2

---Lion---

Meat2

ROAR!2

---Home---

Cat Food2

Meow!2

---End---

I'm using Visual Studio 2013. Release/Debug didnt make a difference either.

Did i do something wrong in my code or is it somekind of compiler stuff I'm missing?

user2596732
  • 47
  • 1
  • 8
  • Why would you do this horrible hack, rather than just implementing the behaviour properly in the first place? I mean you seem to be literally saying 'Make Cat eat Meat, then make HouseCat eat CatFood, but then I want HouseCat to go back to eating Meat, so here's a horrible mess that I hope will subvert the compiler for no reason.' – underscore_d Jul 14 '15 at 23:01
  • @underscore_d I'm trying to understand how VTables work? Since when trying to understand compliers is considered 'Horrible Hack'? – user2596732 Jul 14 '15 at 23:07
  • 1
    You would be trying to understand one should-be-hidden detail of one specific implementation, and thereby learning something that would not be portable, as a way to do something that the language already provides in a standard and portable way by using inheritance properly. I'm not out to stifle education, but any learning you could get from this would be nearly useless and not the best use of the time that would be spent. – underscore_d Jul 14 '15 at 23:11
  • @underscore_d I can use the information I get here to hook functions in virtual classes that can be useful when I'm creating addons for applications that i dont have the source code? I remember tagging this as "reverse-engineering". – user2596732 Jul 14 '15 at 23:23

1 Answers1

2

I agree that this is a horrible hacky thing to do... however, to get it working I'd try changing your lion/base/home variables to be pointers to objects. Right now since they are not pointers, the compiler may be automatically calling the correct function without using the vtable (since it knows exactly what type the object is).

Buddy
  • 10,874
  • 5
  • 41
  • 58
  • "HouseCat * house2 = new HouseCat();" fixed the issue, so it was a compiler optimization. Altough I dont understand why trying to understand reverseengineering is "horrible hacky", thank you for your answer. – user2596732 Jul 14 '15 at 23:38
  • I was thinking that compiling in debug mode would stop compiler optimizations meh ;( – user2596732 Jul 14 '15 at 23:39