2

Microsoft Detours と同じアプローチを使用して迂回を練習してきました (最初の 5 バイトを jmp とアドレスに置き換えます)。最近、仮想テーブルを変更して迂回することについて読んでいます。前述の方法と比較して、この方法の長所と短所をいくつか挙げて、誰かがこの問題に光を当てることができれば幸いです!

また、パッチを適用した vtable とスタック上のオブジェクトについてもお尋ねしたいと思います。次の状況を考慮してください。

// Class definition
struct Foo
{
 virtual void Call(void) { std::cout << "FooCall\n"; }
};

// If it's GCC, 'this' is passed as the first parameter
void MyCall(Foo * object)
{
 std::cout << "MyCall\n";
}

// In some function
Foo * foo = new Foo; // Allocated on the heap
Foo foo2; // Created on the stack

// Arguments: void ** vtable, uint offset, void * replacement
PatchVTable(*reinterpret_cast<void***>(foo), 0, MyCall);

// Call the methods
foo->Call(); // Outputs: 'MyCall'
foo2.Call(); // Outputs: 'FooCall'

この場合、元の関数 (つまりメソッド)foo->Call()を呼び出しMyCall(Foo * object)ながら呼び出すことになります。これは、可能な場合、コンパイラがコンパイル時に仮想呼び出しを決定しようとするためです (間違っている場合は修正してください)。スタック上のオブジェクトを使用する限り (ヒープが割り当てられていない場合)、仮想テーブルにパッチを適用するかどうかは問題ではないということですか?foo2.Call()Foo::Call(void)

4

2 に答える 2

2

スタックとヒープは関係ありません。重要なのは、コンパイラがコンパイル時にオブジェクトの型を認識していることです。オプティマイザーが非常に巧妙でない限り、以下はおそらく同じ結果を生成します。

Foo foo2; // Created on the stack
Foo * foo = &foo2; // Also on the stack, in fact the same object

の型foo2がわかっているため、コンパイラは vtable を調べずに関数を直接呼び出すことができます。fooポインターは派生オブジェクトも指すことができるため、同じことはできません。

于 2012-07-11T15:38:35.180 に答える
0

foo2.call() を使用する場合、コンパイラは呼び出したい関数を決定するために vtable を使用すべきではありません。vtable を呼び出さずにクラス内の関数を呼び出します。

于 2012-07-11T15:13:49.943 に答える