09≪ 12345678910111213141516171819202122232425262728293031≫11
| Home |
スポンサーサイト
上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

スポンサー広告】 | top↑
vtableの上書き
仮想関数テーブル, vtbl, vtable, virtual table, virtual dispatch table など色々名称がありますがこれの上書きの方法。
こんな特殊なケース全くないと思いますが、もしかしたらvtableを別のオブジェクトの上に上書きしたい!なんてケースがあるかもしれません。

例えばclass Aとclass Bのインスタンスのサイズが全く同じなのは分かっているけど、何らかの理由でBのインスタンスがvtableの情報を忘れた、または「取っておいたvtable情報で復元したい」という時に便利かと思って書きます。
v つまりB classのC++インスタンスの全フィールドの情報とclass Bのインスタンス用のvtableの位置がわかればclass AでインスタンスをつくってもBに変身(厳密には違うけど)させることができます。
長々と書いても仕方ないのでコードを:
(必ず-m32オプションで32bitでコンパイルしてください)
(vtableを完全に書き換えるように修正、Ubuntuでコンパイルするように修正)
#include 
#include 

using namespace std;


class A {
public:
	int x;
	virtual void foo() {
		cout << "A::foo" << endl;
		cout << x << endl;
	}
};
class B : public A {
public:
	void foo() {
		cout << "B::foo" << endl;
		cout << x << endl;
	}
};

int main() {
	A *b = new B;
	A *a = new A;
	a->x = 255;
	b->x = 15;

	void* vp = reinterpret_cast(b);
	int* ip = static_cast(vp);
	void* vvtable = (void*)ip[0];
	int* vtable = (int*)vvtable;

	void* vp2 = reinterpret_cast(a);
	int* ip2 = static_cast(vp2);

	// これで上書き
	*ip2 = *ip;
	a->foo();
	b->foo();

	return 1;
}

これをコンパイルして実行すると:
B::foo
255
B::foo
15

が出力されます。どっちもB::fooを呼びました。
ちなみにコメントアウトされてる部分を消すと(上書きされた)vtable2を使ってるのでどちらもB::fooを呼びます。
環境:
Mac OSX GCC(g++) V4.2
-m32で32ビットモードでコンパイル。64だとうまくいかない。
おそらく32bitのUbuntuとかでやっても同じかと。

補足:
スタックにアロケートされたオブジェクトもthisをとればいくらでも行ける。でもデストラクタがディスパッチしてくれない。
おそらくコンパイルしたらこうなるんだと思う
A a;
...
a.A::~A();
デストラクタの中でvtable書きなおして仮想関数を読んでもやはりディスパッチしてくれなかった。。。orz

THEME:プログラミング - GENRE:コンピュータ
プログラミングTB(0) | CM(0) | top↑
<<V8でGCをコール(推奨)する | Home | な、なな・・七夕>>
comments
please comment














Only Admin
| Home |
プロフィール

りん

Author:りん
〃∩ ∧_∧   ブログっと…
⊂⌒( ´・ω・)
  `ヽ_っ_/ ̄ ̄ ̄/ ζ
      \/___/ 旦
ランキングだお

こんなところもやってます。
最近はもっぱらこっちでボヤいてます。

応援中

airy[F]airy
『airy[F]airy (エアリィフェアリィ)』応援中!
rococoworksさん

ナツユメナギサ
サガプラネッツ最新作「ナツユメナギサ」
SAGA PLANETSさん

上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。