用C ++反向工程虚函数代码

时间:2011-06-25 09:38:43

标签: c++ reverse-engineering virtual-functions

我刚刚在VS2010上编译了以下内容(关闭了优化)。

class Shape {
  public:
    int x,y;
    Shape() {
      x=10;
      y=20;
    }

    virtual void function1() {
      cout<<"function1";
    }

    virtual void function2() {
      cout<<"function2";
    }
};

int main() {
    Shape *s = new Shape();
    s->function1();
    s->function2();    
    return 0;
}

反汇编不显示与虚函数对应的代码块或对它的任何调用,因此我假设这是因为使用vftable查找虚函数的方式。我正在使用IDA Pro,因此可能无法解决此类问题。如果我错了,请纠正我。

在这方面我也有一些疑问。

  1. 有什么办法可以像拆卸过程中的其他功能一样查看虚拟功能吗?我可以使用的任何脚本(IDAPython)/方法吗?
  2. 有什么办法可以列出可执行文件中的所有虚函数吗?
  3. 推荐阅读?

4 个答案:

答案 0 :(得分:10)

虚拟分派仅在对象的动态类型与其静态类型(指向派生类的指针到Base)不同时才会涉及。由于您甚至没有继承,并且在调用站点上没有确切的类型,为什么要在vtable中进行查找?

答案 1 :(得分:4)

由于你已经在类定义中定义了你的虚函数,我认为你的函数可能被编译器内联,因为它知道调用站点的确切类型。尝试将函数体移出类体。他们肯定应该出现在拆卸中。我怀疑他们现在可能会被链接器剥死。

答案 2 :(得分:2)

正如其他人所说:你没有任何继承,所以编译器通过消除虚拟调度而变得聪明。

建议阅读:Stroustrup的C ++设计与演变。它不会解决您的所有问题,但会为您提供一个框架,以帮助您更有效地回答或研究他们的答案。

答案 3 :(得分:1)

我没有你的编译器,这高度依赖于编译器和选项。使用g ++ 4.5,使用默认选项(并在修复代码中的一些问题之后),我已经编译成汇编(g++ -S -o test.asm test.cpp)代码,它确实通过虚拟调度机制显示函数和调用(在{ {1}}在调用构造函数之后,它会提取vptr,对其进行偏移并通过寄存器中的值调用。)

  

Shape :: function2的定义(注意.weak表示内联

main
  

Shape :: function1的定义(再次,.weak表示内联

.globl __ZN5Shape9function2Ev
____.weak_definition __ZN5Shape9function2Ev
__ZN5Shape9function2Ev:
[...]
  

为形状定义vtable本身:

.globl __ZN5Shape9function1Ev
____.weak_definition __ZN5Shape9function1Ev
__ZN5Shape9function1Ev:
[...]
  

主要定义:

.globl __ZTV5Shape
    .weak_definition __ZTV5Shape
    .section __DATA,__const_coal,coalesced
    .align 5
__ZTV5Shape:
    .quad   0
    .quad   __ZTI5Shape                # Ptr to type_info object
    .quad   __ZN5Shape9function1Ev     # vtable[0] is Shape::function1
    .quad   __ZN5Shape9function2Ev     # vtable[1] is Shape::function2

至于其他人一直在说编译器可以完全忽略虚拟调度或内联函数,这是真的。这个版本的g ++并不是针对那段特定的代码,而是通过删除指针(使用具有静态存储持续时间的.globl _main _main: [...] movq %rax, %rbx movq %rbx, %rdi call __ZN5ShapeC1Ev # Call to constructor this will setup the vptr movq %rbx, -24(%rbp) movq -24(%rbp), %rax # load **vptr into rax i.e. *vptr[0]: Shape::function1 movq (%rax), %rax movq (%rax), %rax movq -24(%rbp), %rdi call *%rax # call it