私は 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を使用しています。リリース/デバッグでも違いはありませんでした。
私は自分のコードで何か間違ったことをしましたか、それとも私が見逃しているコンパイラのものですか?