C++ 中的逆向工程虚拟函数代码

发布于 2024-11-17 00:54:10 字数 643 浏览 3 评论 0原文

我刚刚在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. 建议阅读?

I just compiled the following on VS2010(with optimization turned off).

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;
}

The disassembly does not show the code blocks corresponding to the virtual functions or any calls to it, so Im assuming that it is because of the way virtual functions are looked up using the vftable. I'm using IDA Pro so it is probably not able to resolve such issues. Please correct me if I'm wrong.

I also have a few doubts in this regard.

  1. Is there any way I can view the virtual functions just as the other functions during disassembly? Any script(IDAPython)/method that I could use?
  2. Is there any way I can list all virtual functions in an executable?
  3. Suggested Reading?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

没有伤那来痛 2024-11-24 00:54:10

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

Virtual dispatch is only involved when the dynamic type of an object is different from its static type (pointer-to-Base pointing to a derived class). Since you don't even have inheritance, and an exact type at the call site, why should it do the lookup in the vtable?

夏末 2024-11-24 00:54:10

由于您已经在类定义中定义了虚拟函数,因此我认为编译器可能会内联您的函数,因为它知道调用站点的确切类型。尝试将函数体移出类体。那么它们肯定会出现在反汇编中。我怀疑他们现在可能被链接器彻底剥夺了。

Since you've defined your virtual functions inside the class definition, I think your functions might be being inlined by the compiler, as it knows the exact type at the call site. Try moving the function bodies out of the class body. They should definitely show up in disassembly then. I suspect they might be deadstripped by the linker at the moment.

一百个冬季 2024-11-24 00:54:10

正如其他人所指出的:您没有任何继承,因此编译器通过消除虚拟分派来变得聪明。

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

As others have noted: you don't have any inheritance, so the compiler is being smart by eliminating virtual dispatch.

Suggested reading: Stroustrup's The Design and Evolution of C++. It won't address all your questions, but give you a framework to help answer them or research their answer more effectively.

虐人心 2024-11-24 00:54:10

我没有你的编译器,这高度依赖于编译器和选项。使用 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

I don't have your compiler, and this is highly dependent on the compiler and options. With g++ 4.5, with the default options (and after fixing a few issues in the code) I have compiled into assembly (g++ -S -o test.asm test.cpp) the code and it does show the functions and the calls through the virtual dispatch mechanism (in main after calling the constructor it extracts the vptr, offsets it and calls through the value in the register).

Definition of Shape::function2 (note the .weak means inline)

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

Definition of Shape::function1 (again, .weak means inline)

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

Definition of the vtable itself for Shape:

.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

Definition of main:

.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 

As to what others have been saying that the compiler can elide the virtual dispatch completely or inline the function, that is true. This version of g++ doesn't do it for that particular piece of code, but by removing the pointer (using a Shape with static storage duration)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文