修改VTable表项没有重定向功能

Changing VTable entries doesnt redirect function?

本文关键字:重定向 功能 VTable 修改      更新时间:2023-10-16

我有3个班级(猫,家猫:猫,狮子:猫)。我想做的是改变家猫的VTable,让家猫吃肉而不是猫粮。

我使用的类:

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]

问题是函数的输出根本没有改变。

——基础——

Meat2

喵!2

——狮子

Meat2

咆哮!2

——回家——

猫Food2

喵!2

——结束

我使用的是Visual Studio 2013。发布/调试也没有影响

我做错了什么在我的代码或它是某种编译器的东西我错过了?

我同意这是一个可怕的黑客的事情…然而,为了让它工作,我会试着改变你的lion/base/home变量是指向对象的指针。现在,由于它们不是指针,编译器可能会自动调用正确的函数,而不使用虚函数表(因为它确切地知道对象的类型)。