【问题标题】:Reverse Engineering virtual functions code in C++C++ 中的逆向工程虚函数代码
【发布时间】:2011-06-25 09:38:43
【问题描述】:

我刚刚在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. 推荐阅读?

【问题讨论】:

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


    【解决方案1】:

    仅当对象的动态类型不同于其静态类型(指向派生类的指向基址的指针)时才涉及虚拟调度。既然你甚至没有继承,也没有调用站点的确切类型,为什么要在 vtable 中进行查找?

    【讨论】:

      【解决方案2】:

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

      【讨论】:

        【解决方案3】:

        正如其他人所指出的:您没有任何继承,因此编译器通过消除虚拟调度变得更加智能。

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

        【讨论】:

          【解决方案4】:

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

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

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

          Shape::function1 的定义(同样,.weak 表示内联

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

          Shape 的 vtable 本身的定义:

          .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
          

          主要定义:

          .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 
          

          至于其他人所说的编译器可以完全省略虚拟调度或内联函数,这是真的。这个版本的 g++ 并没有针对那段特定的代码执行此操作,而是通过删除指针(使用具有静态存储持续时间的 Shape

          【讨论】:

            猜你喜欢
            • 2010-09-11
            • 2015-04-13
            • 2011-12-28
            • 1970-01-01
            • 2018-09-20
            • 1970-01-01
            • 1970-01-01
            • 2013-07-03
            • 2015-04-21
            相关资源
            最近更新 更多