1

私は 3 つのクラス (猫、HouseCat:Cat、Lion:Cat) を持っています。私がやろうとしているのは、HouseCat の VTable を変更して、HouseCat がキャット フードの代わりに肉を食べられるようにすることです。

私が使用するクラス:

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

作成した VTable 構造体でこれらのクラスの VTable エントリを編集しようとしています。

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

VTable[0] = eat() であることを確認したので、Vtable を次のように変更してみることにしました。

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;

}

出力しました。

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

HomeCat[0] が 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]

問題は、関数の出力がまったく変化しないことです。

- -ベース - -

ミート2

ニャー!2

- -ライオン - -

ミート2

ロア!2

- -家 - -

キャットフード2

ニャー!2

- -終わり - -

私はVisual Studio 2013を使用しています。リリース/デバッグでも違いはありませんでした。

私は自分のコードで何か間違ったことをしましたか、それとも私が見逃しているコンパイラのものですか?

4

1 に答える 1