2012-07-11 39 views
2

我一直在使用与Microsoft Detours相同的方法练习弯路(用jmp和地址替换前五个字节)。最近我一直在通过修改虚拟表来阅读关于绕行的内容。如果有人能够通过提及这种方法的一些优点和缺点,与前面提到的方法相比,我会很感激的。有关绕行虚拟表的问题

我也想问一下堆栈上的vatch和对象。考虑以下情况:

// 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)法)。这是因为如果可能的话,编译器会在编译时尝试决定任何虚拟调用(如果我错了,请纠正我)。这是否意味着你是否修补虚拟表并不重要,只要你使用栈上的对象(不是堆分配)?

回答

2

堆栈与堆无关紧要 - 重要的是编译器在编译时知道对象的类型。下面可能会产生相同的结果,除非优化器是很聪明:

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

由于foo2类型是已知的,编译器可以调用该函数直接不看任何虚函数表。它不能为foo做同样的事情,因为指针也可以指向派生对象。

0

当您使用foo2.call()编译器不应该使用vtable来确定要调用哪个函数时,它会在不调用vtable的情况下在类中调用函数。