《coredump问题原理探究》Linux x86版6.8节多继承coredump例子

下面看一个coredump的例子:

(gdb) bt
#0  0x08048662 in xuzhina_dump_c06_s5_ex_child::inheritFrom(char*, int) ()
#1  0x08048609 in main ()

先看一下xuzhina_dump_c06_s5_ex_child::inheritFrom的汇编:

(gdb) disassemble 0x08048662
Dump of assembler code for function _ZN28xuzhina_dump_c06_s5_ex_child11inheritFromEPci:
   0x08048640 <+0>:     push   %ebp
   0x08048641 <+1>:     mov    %esp,%ebp
   0x08048643 <+3>:     sub    $0x18,%esp
   0x08048646 <+6>:     mov    0x8(%ebp),%eax
   0x08048649 <+9>:     mov    (%eax),%eax
   0x0804864b <+11>:    mov    (%eax),%eax
   0x0804864d <+13>:    mov    0x8(%ebp),%edx
   0x08048650 <+16>:    mov    0xc(%ebp),%ecx
   0x08048653 <+19>:    mov    %ecx,0x4(%esp)
   0x08048657 <+23>:    mov    %edx,(%esp)
   0x0804865a <+26>:    call   *%eax
   0x0804865c <+28>:    mov    0x8(%ebp),%eax
   0x0804865f <+31>:    mov    0xc(%eax),%eax
=> 0x08048662 <+34>:    mov    (%eax),%eax
   0x08048664 <+36>:    mov    0x8(%ebp),%edx
   0x08048667 <+39>:    lea    0xc(%edx),%ecx
   0x0804866a <+42>:    mov    0x10(%ebp),%edx
   0x0804866d <+45>:    mov    %edx,0x4(%esp)
   0x08048671 <+49>:    mov    %ecx,(%esp)
   0x08048674 <+52>:    call   *%eax
   0x08048676 <+54>:    mov    0x8(%ebp),%eax
   0x08048679 <+57>:    movl   $0x1,0x14(%eax)
   0x08048680 <+64>:    leave
   0x08048681 <+65>:    ret
End of assembler dump.

   0x0804865c <+28>:    mov    0x8(%ebp),%eax
   0x0804865f <+31>:    mov    0xc(%eax),%eax
=> 0x08048662 <+34>:    mov    (%eax),%eax
   0x08048664 <+36>:    mov    0x8(%ebp),%edx
   0x08048667 <+39>:    lea    0xc(%edx),%ecx
   0x0804866a <+42>:    mov    0x10(%ebp),%edx
   0x0804866d <+45>:    mov    %edx,0x4(%esp)
   0x08048671 <+49>:    mov    %ecx,(%esp)
   0x08048674 <+52>:    call   *%eax

可以知道来看,eax是一个虚函数表指针

由崩溃指令来看,eax所指向地址非法,而eax是由this加上0xc偏移值得到,this放在ebp+0x8

看一下this所指向的内容

(gdb) x /x $ebp+8
0xbff59da0:     0x08c03008
(gdb) x /8x 0x08c03008
0x8c03008:      0x08048798      0x6c6c6548      0x726f576f      0x6854646c
0x8c03018:      0x73497369      0x69766544      0x0000006c      0x00020fe1

由于这个地址0x08c03008下一个单元0x08c0300c及后续几个单元的每个字节都少于0x80,有可能是ascii码.

而且还可以由

(gdb) i r eax
eax            0x6854646c       1750361196

看到eax的值放在0x8c03014这个单元。

看一下0x08c0300c开始的是不是字符串:

(gdb) x /s 0x08c0300c
0x8c0300c:       "HelloWorldThisIsDevil"
(gdb) x /s 0x8c03014
0x8c03014:       "ldThisIsDevil"

可见,确实是有一个字符串在里面,且this+0xc这个虚函数表指针刚好是字符串” ldThisIsDevil”.说明刚好是被前面的成员变量覆盖了.为什么被覆盖了?

在xuzhina_dump_c06_s5_ex!xuzhina_dump_c06_s5_ex_child::inheritFrom这个函数里,有两处调用.先看一下前一个调用是什么,有没有可能把这个虚函数表指针给覆盖掉,如果没有,就看一下main函数有没有调用这个类的其它成员函数了.

由这一段指令

   0x08048646 <+6>:     mov    0x8(%ebp),%eax
   0x08048649 <+9>:     mov    (%eax),%eax
   0x0804864b <+11>:    mov    (%eax),%eax
   0x0804864d <+13>:    mov    0x8(%ebp),%edx
   0x08048650 <+16>:    mov    0xc(%ebp),%ecx
   0x08048653 <+19>:    mov    %ecx,0x4(%esp)
   0x08048657 <+23>:    mov    %edx,(%esp)
   0x0804865a <+26>:    call   *%eax

可以知道,这个函数是从第一个虚函数表取出来的第一个函数.

(gdb) x /x $ebp+8
0xbff59da0:     0x08c03008
(gdb) x /4x 0x08c03008
0x8c03008:      0x08048798      0x6c6c6548      0x726f576f      0x6854646c
(gdb) x /4x 0x08048798
0x8048798 <_ZTV28xuzhina_dump_c06_s5_ex_child+8>:       0x08048614      0x08048640      0xfffffff4      0x08048800

从上面可以看到,是调用了setName这个函数,有一个参数.这个参数的值在xuzhina_dump_c06_s5_ex_child::inheritFrom由ebp+c传入.

看一下ebp+c的内容:

(gdb) x /x $ebp+0xc
0xbff59da4:     0xbff5a672
(gdb) x /s 0xbff5a672
0xbff5a672:      "HelloWorldThisIsDevil"

由这可以推断,是由xuzhina_dump_c06_s5_ex_father::setName这个函数导致第二个虚函数表指针被改写的.

看一下xuzhina_dump_c06_s5_ex_father::setName做了什么事情:

(gdb) disassemble _ZN29xuzhina_dump_c06_s5_ex_father7setNameEPc
Dump of assembler code for function _ZN29xuzhina_dump_c06_s5_ex_father7setNameEPc:
   0x08048614 <+0>:     push   %ebp
   0x08048615 <+1>:     mov    %esp,%ebp
   0x08048617 <+3>:     sub    $0x18,%esp
   0x0804861a <+6>:     mov    0x8(%ebp),%eax
   0x0804861d <+9>:     lea    0x4(%eax),%edx
   0x08048620 <+12>:    mov    0xc(%ebp),%eax
   0x08048623 <+15>:    mov    %eax,0x4(%esp)
   0x08048627 <+19>:    mov    %edx,(%esp)
   0x0804862a <+22>:    call   0x8048490 <[email protected]>
   0x0804862f <+27>:    leave
   0x08048630 <+28>:    ret
End of assembler dump.

通过逆向上面的汇编,可以得到这一个函数是参数1的值一个字符一个字符地复制到这个对象的第一个成员变量(this+4)里.在这个coredump里,参数1的值是”HelloWorldThisIsDevil”,长度为21,由第一个参数开始,即(+4).而这个对象的第二个虚函数表指针位于+c的位置,刚好被” ldThisIsDevil”来覆盖.

源代码如下:

  1 #include <string.h>
  2 class xuzhina_dump_c06_s5_ex_father
  3 {
  4     private:
  5         char m_name[8];
  6     public:
  7         virtual void setName( char* name )
  8         {
  9             strcpy( m_name, name );
 10         }
 11 };
 12
 13 class xuzhina_dump_c06_s5_ex_mother
 14 {
 15     private:
 16         int m_nature;
 17     public:
 18         virtual void setNature( int nature )
 19         {
 20             m_nature = nature;
 21         }
 22 };
 23
 24 class xuzhina_dump_c06_s5_ex_child: public xuzhina_dump_c06_s5_ex_father,
 25     public xuzhina_dump_c06_s5_ex_mother
 26 {
 27     private:
 28         int m_sweet;
 29     public:
 30         virtual void inheritFrom( char* lastName, int nature )
 31         {
 32             setName( lastName );
 33             setNature( nature );
 34             m_sweet = 1;
 35         }
 36 };
 37
38 int main( int argc, char* argv[] )
 39 {
 40     if ( argc < 2 )
 41     {
 42         return -1;
 43     }
 44
 45     xuzhina_dump_c06_s5_ex_child* child = new xuzhina_dump_c06_s5_ex_child;
 46     child->inheritFrom( argv[1], 1 );
 47
 48     return 0;
 49 }

时间: 2024-12-17 21:48:20

《coredump问题原理探究》Linux x86版6.8节多继承coredump例子的相关文章

《coredump问题原理探究》Linux x86版6.7节多继承

类的多继承大致可以分为两种情况.一种是无共同基类的.一种是有共同基类的. 先看一下第一种情况: 1 #include <stdio.h> 2 class xuzhina_dump_c06_s5_mother 3 { 4 private: 5 int m_age; 6 int m_beauty; 7 public: 8 virtual void print() 9 { 10 printf( "mother\n" ); 11 } 12 13 virtual void setBe

《coredump问题原理探究》Linux x86版6.6节单继承

在C++里,类的多态是通过继承由虚函数来体现的.那么在单继承中,类的成员变量和虚函数的分布又是怎样的呢? 看一下例子: 1 #include <stdio.h> 2 class xuzhina_dump_c06_s4_base 3 { 4 private: 5 int m_a; 6 public: 7 xuzhina_dump_c06_s4_base() { m_a = 1; } 8 virtual void inc() 9 { 10 m_a++; 11 } 12 virtual void p

《coredump问题原理探究》Windows版 笔记

<coredump问题原理探究>Windows版 笔记 Debug 一.环境搭建 1.Win7捕获程序dump 2.Windbg符号表设置(Symbols Search Path) 二.WinDbg命令 三.函数栈帧 1.栈内存布局 2.栈溢出 3.栈的规律 4.定位栈溢出问题的经验方法 四.函数逆向 五.C内存布局 1.基本类型 2.数组类型 3.结构体 六.C++内存布局 1.类的内存布局 2.this指针 3.虚函数表及虚表指针 4.单继承 5.多继承(无公共基类) 七.STL容器内存布

《coredump问题原理探究》Linux x86版6.3节有成员变量的类coredump例子

在探究完类成员变量分布后,来定位一个coredump例子来实践一把: (gdb) bt #0 0x0804863c in xuzhina_dump_c06_s2_ex::print() () #1 0x08048713 in main () 看一下xuzhina_dump_c06_s2_ex::print的汇编: (gdb) disassemble 0x0804863c Dump of assembler code for function _ZN22xuzhina_dump_c06_s2_ex

《coredump问题原理探究》Linux x86版7.2节vector coredump例子

看一个coredump的例子: [[email protected] s1_ex]$ gdb xuzhina_dump_c07_s1_ex core.27776 GNU gdb (GDB) Red Hat Enterprise Linux (7.2-75.el6) Copyright (C) 2010 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses

《coredump问题原理探究》Linux x86版6.2节C++风格数据结构内存布局之有成员变量的类

上面一节已经探究出this指针的辨别,由this指针就可以看到类的内容.在这里,就由this指针来看一下类的成员变量是如何排列. 先看一个例子 1 #include <stdio.h> 2 class xuzhina_dump_c06_s2 3 { 4 private: 5 short m_c; 6 char m_d; 7 int m_e; 8 9 public: 10 xuzhina_dump_c06_s2( int a, int b ) 11 { 12 m_c = (short)(a +

《coredump问题原理探究》Linux x86版7.5节 Map对象

先看一个例子: 1 #include <map> 2 3 int main() 4 { 5 std::map<int,int> iMap; 6 7 iMap[5] = 6; 8 iMap[8] = 20; 9 iMap[2] = 80; 10 11 return 0; 12 } 看一下汇编: (gdb) disassemble main Dump of assembler code for function main: 0x080486e4 <+0>: push %eb

《coredump问题原理探究》Linux x86版6.1节C++风格数据结构内存布局之无成员变量的类

在探究完C风格数据结构内存布局之后,接着探究C++风格数据结构内存布局. 虽然最简单的类是没有任何成员变量和成员函数,但由于没什么意义,不值得探究.在这里,就先探究一下没有任何成员变量和虚函数,只有成员函数的类. 先看一下例子: 1 #include <stdio.h> 2 class xuzhina_dump_c06_s1 3 { 4 public: 5 void hello() 6 { 7 printf( "hello\n" ); 8 } 9 void print()

《coredump问题原理探究》Linux x86版7.4节List coredump例子

看一个coredump例子: 看一个coredump例子: Core was generated by `./xuzhina_dump_c07_s2_ex'. Program terminated with signal 11, Segmentation fault. #0 0x0285b9b7 in std::_List_node_base::hook(std::_List_node_base*) () from /usr/lib/libstdc++.so.6 Missing separate