关于修改虚拟表绕行的问题
Posted
技术标签:
【中文标题】关于修改虚拟表绕行的问题【英文标题】:Questions regarding detouring by modifying the virtual table 【发布时间】:2012-07-11 15:01:26 【问题描述】:我一直在使用与 Microsoft Detours 相同的方法练习 detours(将前五个字节替换为 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)
方法)。这是因为如果可能,编译器将尝试在编译期间决定任何虚拟调用(如果我错了,请纠正我)。这是否意味着你是否修补虚拟表并不重要,只要你使用堆栈上的对象(不是堆分配的)?
【问题讨论】:
【参考方案1】:堆栈与堆无关紧要 - 重要的是编译器在编译时知道对象的类型。除非优化器非常聪明,否则以下可能会产生相同的结果:
Foo foo2; // Created on the stack
Foo * foo = &foo2; // Also on the stack, in fact the same object
由于foo2
的类型是已知的,编译器可以直接调用该函数而无需查看任何vtable。 foo
不能这样做,因为指针也可以指向派生对象。
【讨论】:
【参考方案2】:当你使用 foo2.call() 编译器不应该使用 vtable 来确定你要调用哪个函数,它会调用类中的函数而不调用 vtable。
【讨论】:
以上是关于关于修改虚拟表绕行的问题的主要内容,如果未能解决你的问题,请参考以下文章