首页
学习
活动
专区
圈层
工具
发布
21 篇文章
1
《coredump问题原理探究》Linux x86版6.3节有成员变量的类coredump例子
2
《coredump问题原理探究》Linux x86版6.5节虚函数的coredump例子
3
《coredump问题原理探究》Linux x86版6.8节多继承coredump例子
4
《coredump问题原理探究》Linux x86版7.2节vector coredump例子
5
《coredump问题原理探究》Linux x86版7.4节List coredump例子
6
《coredump问题原理探究》Linux x86版7.6节 Map coredump例子
7
《coredump问题原理探究》Linux x86版5.9节C风格数据结构内存布局之联合体
8
《coredump问题原理探究》Linux x86版6.1节C++风格数据结构内存布局之无成员变量的类
9
《coredump问题原理探究》Linux x86版6.2节C++风格数据结构内存布局之有成员变量的类
10
《coredump问题原理探究》Linux x86版4.5节函数的逆向之coredump例子
11
《coredump问题原理探究》Linux x86版5.1节C风格数据结构内存布局之引言
12
《coredump问题原理探究》Linux x86版5.2节C风格数据结构内存布局之基本数据类型
13
《coredump问题原理探究》Linux x86版5.3节C风格数据结构内存布局之数组
14
《coredump问题原理探究》Linux x86版5.4节C风格数据结构内存布局之数组coredump例子
15
《coredump问题原理探究》Linux x86版5.5节C风格数据结构内存布局之基本数据类型构成的结构体
16
《coredump问题原理探究》Linux x86版5.6节C风格数据结构内存布局之复合类型构成的结构体
17
《coredump问题原理探究》Linux x86版5.7节C风格数据结构内存布局之结构体数组
18
《coredump问题原理探究》Linux x86版5.8节C风格数据结构内存布局之结构体数组结构体coredump
19
《coredump问题原理探究》Linux x86版3.5节栈布局之-fomit-frame-pointer编译选项
20
《coredump问题原理探究》Linux x86版3.6节栈布局之gcc内嵌关键字
21
《coredump问题原理探究》Linux x86版3.8节栈布局之栈溢出coredump例子

《coredump问题原理探究》Linux x86版5.8节C风格数据结构内存布局之结构体数组结构体coredump

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://cloud.tencent.com/developer/article/1344503

上一节已经阐述完毕结构体的特征了,需要一个coredump例子:

代码语言:javascript
复制
(gdb) bt
#0  0x00000000 in ?? ()
#1  0x080485a1 in result(xuzhina_dump_c05_s3_ex*, int) ()
#2  0x080487f8 in main ()

从栈顶来看,顶层的地址竟然是0,eip的值也是0.会出现eip为0的情况,只可能是调用了函数指针,且函数指针为0.看一下result的汇编:

代码语言:javascript
复制
(gdb) disassemble result
Dump of assembler code for function _Z6resultP22xuzhina_dump_c05_s3_exi:
   0x08048540 <+0>:     push   %ebp
   0x08048541 <+1>:     mov    %esp,%ebp
   0x08048543 <+3>:     push   %ebx
   0x08048544 <+4>:     sub    $0x24,%esp
   0x08048547 <+7>:     movl   $0x0,-0xc(%ebp)
   0x0804854e <+14>:    movl   $0x0,-0x10(%ebp)
   0x08048555 <+21>:    jmp    0x80485a8 <_Z6resultP22xuzhina_dump_c05_s3_exi+104>
   0x08048557 <+23>:    mov    -0x10(%ebp),%edx
   0x0804855a <+26>:    mov    %edx,%eax
   0x0804855c <+28>:    add    %eax,%eax
   0x0804855e <+30>:    add    %edx,%eax
   0x08048560 <+32>:    shl    $0x2,%eax
   0x08048563 <+35>:    mov    %eax,%edx
   0x08048565 <+37>:    mov    0x8(%ebp),%eax
   0x08048568 <+40>:    add    %edx,%eax
   0x0804856a <+42>:    mov    0x8(%eax),%ecx
   0x0804856d <+45>:    mov    -0x10(%ebp),%edx
   0x08048570 <+48>:    mov    %edx,%eax
   0x08048572 <+50>:    add    %eax,%eax
   0x08048574 <+52>:    add    %edx,%eax
   0x08048576 <+54>:    shl    $0x2,%eax
   0x08048579 <+57>:    mov    %eax,%edx
   0x0804857b <+59>:    mov    0x8(%ebp),%eax
   0x0804857e <+62>:    add    %edx,%eax
   0x08048580 <+64>:    mov    0x4(%eax),%ebx
   0x08048583 <+67>:    mov    -0x10(%ebp),%edx
   0x08048586 <+70>:    mov    %edx,%eax
   0x08048588 <+72>:    add    %eax,%eax
   0x0804858a <+74>:    add    %edx,%eax
   0x0804858c <+76>:    shl    $0x2,%eax
   0x0804858f <+79>:    mov    %eax,%edx
   0x08048591 <+81>:    mov    0x8(%ebp),%eax
   0x08048594 <+84>:    add    %edx,%eax
   0x08048596 <+86>:    mov    (%eax),%eax
   0x08048598 <+88>:    mov    %ebx,0x4(%esp)
   0x0804859c <+92>:    mov    %eax,(%esp)

   0x0804859f <+95>:    call   *%ecx
   0x080485a1 <+97>:    add    %eax,-0xc(%ebp)

   0x080485a4 <+100>:   addl   $0x1,-0x10(%ebp)
   0x080485a8 <+104>:   mov    -0x10(%ebp),%eax
   0x080485ab <+107>:   cmp    0xc(%ebp),%eax
   0x080485ae <+110>:   setl   %al
   0x080485b1 <+113>:   test   %al,%al
   0x080485b3 <+115>:   jne    0x8048557 <_Z6resultP22xuzhina_dump_c05_s3_exi+23>
   0x080485b5 <+117>:   mov    -0xc(%ebp),%eax
   0x080485b8 <+120>:   add    $0x24,%esp
   0x080485bb <+123>:   pop    %ebx
   0x080485bc <+124>:   pop    %ebp
   0x080485bd <+125>:   ret    
End of assembler dump.

在上面汇编,指令地址0x08048557-0x080485b3是一个循环,循环条件是判断ebp-0x10单元的值是不是与函数第三个参数(ebp+0xc)相等,由此可知,ebp-0x10存放着循环计数,取名为cnt。而栈顶的返回值0x080485a1也位于这个循环里,

那么coredump指令是由

代码语言:javascript
复制
   0x0804859f <+95>:    call   *%ecx

引起,也就是说ecx为0,如下图。

代码语言:javascript
复制
(gdb) frame 1
#1  0x080485a1 in result(xuzhina_dump_c05_s3_ex*, int) ()
(gdb) i r
eax            0x3      3
ecx            0x0      0
edx            0x24     36
ebx            0x3      3
esp            0xbfac0250       0xbfac0250
ebp            0xbfac0278       0xbfac0278
esi            0x0      0
edi            0x0      0
eip            0x80485a1        0x80485a1 <result(xuzhina_dump_c05_s3_ex*, int)+97>
eflags         0x10296  [ PF AF SF IF RF ]
cs             0x73     115
ss             0x7b     123
ds             0x7b     123
es             0x7b     123
fs             0x0      0
gs             0x33     51

ecx这个函数指针是由下面的指令来获得:

代码语言:javascript
复制
   0x08048557 <+23>:    mov    -0x10(%ebp),%edx
   0x0804855a <+26>:    mov    %edx,%eax
   0x0804855c <+28>:    add    %eax,%eax
   0x0804855e <+30>:    add    %edx,%eax
   0x08048560 <+32>:    shl    $0x2,%eax
   0x08048563 <+35>:    mov    %eax,%edx
   0x08048565 <+37>:    mov    0x8(%ebp),%eax
   0x08048568 <+40>:    add    %edx,%eax
   0x0804856a <+42>:    mov    0x8(%eax),%ecx

ecx函数指针的第一个参数的获得:

代码语言:javascript
复制
   0x08048583 <+67>:    mov    -0x10(%ebp),%edx
   0x08048586 <+70>:    mov    %edx,%eax
   0x08048588 <+72>:    add    %eax,%eax
   0x0804858a <+74>:    add    %edx,%eax
   0x0804858c <+76>:    shl    $0x2,%eax
   0x0804858f <+79>:    mov    %eax,%edx
   0x08048591 <+81>:    mov    0x8(%ebp),%eax
   0x08048594 <+84>:    add    %edx,%eax
   0x08048596 <+86>:    mov    (%eax),%eax

ecx函数指针的第二个参数的获得:

代码语言:javascript
复制
   0x0804856d <+45>:    mov    -0x10(%ebp),%edx
   0x08048570 <+48>:    mov    %edx,%eax
   0x08048572 <+50>:    add    %eax,%eax
   0x08048574 <+52>:    add    %edx,%eax
   0x08048576 <+54>:    shl    $0x2,%eax
   0x08048579 <+57>:    mov    %eax,%edx
   0x0804857b <+59>:    mov    0x8(%ebp),%eax
   0x0804857e <+62>:    add    %edx,%eax
   0x08048580 <+64>:    mov    0x4(%eax),%ebx

由上面可以看到,这三个值的获取只有最后一条指令是不一样,其它都一样。

先分析一下前面相同的指令:

代码语言:javascript
复制
   0x0804856d <+45>:    mov    -0x10(%ebp),%edx		;把cnt(ebp-0x10)的内容放入edx
   0x08048570 <+48>:    mov    %edx,%eax			;eax = edx
   0x08048572 <+50>:    add    %eax,%eax				;eax *= 2
   0x08048574 <+52>:    add    %edx,%eax				;eax += edx = 3*edx
   0x08048576 <+54>:    shl    $0x2,%eax				;eax <<= 2. eax = 12*cnt
   0x08048579 <+57>:    mov    %eax,%edx			;edx = eax
   0x0804857b <+59>:    mov    0x8(%ebp),%eax		;result函数的第一个参数
   0x0804857e <+62>:    add    %edx,%eax				;eax += edx

由上面的汇编可以看出,取得ecx所指向的函数及它两个参数,都是在result函数的第一参数加一定偏移值来得到,而这个偏移值则是12*cnt。

而cnt在每次循环比较结束条件时,都会:

代码语言:javascript
复制
   0x080485a4 <+100>:   addl   $0x1,-0x10(%ebp)

即cnt++。也就是说,每次循环获取函数指针放入ecx及函数指针两个参数时,计算的偏移值都会比上一次循环的偏移值多上12,是一个固定值。根据数组的特征,可见result函数的第一个参数是一个数组,它每个元素的大小是12

且cnt在循环比较结束条件时,都会

代码语言:javascript
复制
   0x080485ab <+107>:   cmp    0xc(%ebp),%eax

可见,result函数的第二个参数是数组要遍历的个数。

再者,由于函数指针和它两个参数的获得只是最后一条指令不一样,且它们是以数组的元素为基地址的。可以推断它们是结构体。

所以,现在就是要看一下究竟是数组哪个元素的第三个成员为空。

由于cnt是放在ebp-0x10,看一下ebp-0x10的内容就知道:

代码语言:javascript
复制
(gdb) frame 
#1  0x080485a1 in result(xuzhina_dump_c05_s3_ex*, int) ()
(gdb)  x /x $ebp-0x10
0xbfac0268:     0x00000003

可见是数组的第四个元素的第三个成员为空。

看一下代码:

代码语言:javascript
复制
 typedef int (*operation)( int a, int b );
 struct xuzhina_dump_c05_s3_ex
 {
     int a;
     int b;
     operation oper;
 };
 
 int result( struct xuzhina_dump_c05_s3_ex test[], int num )
 {
     int res = 0;
     for ( int i = 0; i < num; i++ )
     {
         res += test[i].oper( test[i].a, test[i].b );
     }
	 
     return res;
 }
 
 int add( int a, int b )
 {
     return a+b;
 }
 int sub( int a, int b )
 {
     return a-b;
 }
 int mul( int a, int b )
 {
     return a*b;
 }
 
 void init( struct xuzhina_dump_c05_s3_ex test[], int num )
 {
      for( int i = 0; i < num; i++ )
      {
          switch( i % 4 )
          {
              case 0:
                  test[i].a = i/4;
                  test[i].b = 0;
                  test[i].oper = add;
                 break;
             case 1:
                 test[i].a = i/4;
                 test[i].b = i%4;
                 test[i].oper = mul;
                 break;
             case 2:
                 test[i].a = i%4;
                 test[i].b = i/4;
                 test[i].oper = sub;
                 break;
             default:
                 test[i].a = i;
                 test[i].b = i%4;
                 test[i].oper = 0;
                 break;
         }
     }
 }
 
 int main()
 {
     struct xuzhina_dump_c05_s3_ex test[15];
     init( test, 15 );
 
     return result( test, 15 );
 }

可见是由于init的这一块代码所导致的

代码语言:javascript
复制
54	             default:
 55	                 test[i].a = i;
 56	                 test[i].b = i%4;
 57	                 test[i].oper = 0;
 58	                 break;
下一篇
举报
领券