版权声明:本文为博主原创文章,未经博主允许不得转载。 https://cloud.tencent.com/developer/article/1344552
下面看一个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 <strcpy@plt>
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 }