Chinaunix首页 | 论坛 | 博客
  • 博客访问: 29645
  • 博文数量: 6
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 69
  • 用 户 组: 普通用户
  • 注册时间: 2014-08-26 14:33
文章分类
文章存档

2014年(6)

我的朋友
最近访客

分类: C/C++

2014-12-26 10:00:46

起初遇到下面一个问题:
void fun()
{
char buffer[] = "2014/12/25 16:07:26";
char msg[10] = {0};


sscanf(buffer, "%s", msg);


printf("msg:-%s-\nbuffer:-%s-\n", msg, buffer);
}
屏幕输出结果:
msg:-2014/12/25-
buffer:-2014/12/25 16:07:26-
发现sscanf在遇到空格、字符'\0'时会停止截取,然把上述字符串
中的空格修改成'='后,出现了奇怪的问题。
void fun()
{
char buffer[] = "2014/12/25=16:07:26";
char msg[10] = {0};


sscanf(buffer, "%s", msg);


printf("msg:-%s-\nbuffer:-%s-\n", msg, buffer);
}
屏幕输出结果:
msg:-2014/12/25=16:07:26-
buffer:-6:07:26-
会发现buffer被修改了,原以为是在某些特定情况下sscanf会扰乱
源字符串,但仔细一想问题是处在了栈溢出上,msg的维数不够,
导致(高地址的)buffer的部分内容被篡改。


再仔细研究会发现:如果按照msg的维度10的话,buffer的内容会被
干扰到“=16:07:26”,事实上却是干扰到“6:07:26”。
推测是32位机上存在四个字节的对齐(为了提高查询速率)。
到VC6.0--DEBUG模式下调试
--- F:\C&C++\su\text.cpp  ---------------------------------------------------------------------------------------------------------------------------------
58:
59:
60:
61:   void fun()
62:   {
00401050   push        ebp
00401051   mov         ebp,esp
00401053   sub         esp,60h
00401056   push        ebx
00401057   push        esi
00401058   push        edi
00401059   lea         edi,[ebp-60h]
0040105C   mov         ecx,18h
00401061   mov         eax,0CCCCCCCCh
00401066   rep stos    dword ptr [edi]
63:       char buffer[] = "2014/12/25=16:07:26";
00401068   mov         ecx,5
0040106D   mov         esi,offset string "2014/12/25=16:07:26" (0041b120)
00401072   lea         edi,[ebp-14h]
00401075   rep movs    dword ptr [edi],dword ptr [esi]
64:       char msg[10] = {0};
00401077   mov         byte ptr [ebp-20h],0
0040107B   xor         eax,eax
0040107D   mov         dword ptr [ebp-1Fh],eax
00401080   mov         dword ptr [ebp-1Bh],eax
00401083   mov         byte ptr [ebp-17h],al
65:
66:       sscanf(buffer, "%s", msg);
00401086   lea         ecx,[ebp-20h]
00401089   push        ecx
0040108A   push        offset string "%s" (0041b11c)
0040108F   lea         edx,[ebp-14h]
00401092   push        edx
00401093   call        sscanf (00408240)
00401098   add         esp,0Ch
67:
68:       printf("msg:-%s-\nbuffer:-%s-\n", msg, buffer);
0040109B   lea         eax,[ebp-14h]
0040109E   push        eax
0040109F   lea         ecx,[ebp-20h]
004010A2   push        ecx
004010A3   push        offset string "msg:-%s-\nbuffer:-%s-\n" (0041b104)
004010A8   call        printf (00408180)
004010AD   add         esp,0Ch
69:   }
004010B0   pop         edi
004010B1   pop         esi
004010B2   pop         ebx
004010B3   add         esp,60h
004010B6   cmp         ebp,esp
004010B8   call        __chkesp (00408200)
004010BD   mov         esp,ebp
004010BF   pop         ebp
004010C0   ret
--- No source file  ---------------------------------------------------------------------------------------------------------------------------------------
004010C1   int         3
004010C2   int         3
004010C3   int         3
004010C4   int         3
004010C5   int         3
004010C6   int         3
004010C7   int         3
004010C8   int         3
004010C9   int         3
004010CA   int         3
004010CB   int         3
004010CC   int         3
004010CD   int         3
004010CE   int         3
004010CF   int         3
--- F:\C&C++\su\text.cpp  ---------------------------------------------------------------------------------------------------------------------------------
70:
71:
72:
73:   int main(int argc, char* argv[], char* argevn[])
74:   {
004010D0   push        ebp
004010D1   mov         ebp,esp
004010D3   sub         esp,40h
004010D6   push        ebx
004010D7   push        esi
004010D8   push        edi
004010D9   lea         edi,[ebp-40h]
004010DC   mov         ecx,10h
004010E1   mov         eax,0CCCCCCCCh
004010E6   rep stos    dword ptr [edi]
75:
76:       fun();
004010E8   call        fun (00401050)
77:
78:
79:
80:       return 0;
004010ED   xor         eax,eax
81:   }
004010EF   pop         edi
004010F0   pop         esi
004010F1   pop         ebx
004010F2   add         esp,40h
004010F5   cmp         ebp,esp
004010F7   call        __chkesp (00408200)
004010FC   mov         esp,ebp
004010FE   pop         ebp
004010FF   ret


根据在fun()函数被调用前sp(ESP = 0018FEFC)值可找到fun()的栈域起始,
&buffer = 0x0018fee0,&msg = 0x0018fed4则在sscanf()函数被调用前栈布局
大致如下:
0018FE84              48 FF 18 00  轧..H...
0018FE8C  00 00 00 00 00 E0 FD 7E  .....帻~
0018FE94  CC CC CC CC CC CC CC CC  烫烫烫烫
0018FE9C  CC CC CC CC CC CC CC CC  烫烫烫烫
0018FEA4  CC CC CC CC CC CC CC CC  烫烫烫烫
0018FEAC  CC CC CC CC CC CC CC CC  烫烫烫烫
0018FEB4  CC CC CC CC CC CC CC CC  烫烫烫烫
0018FEBC  CC CC CC CC CC CC CC CC  烫烫烫烫
0018FEC4  CC CC CC CC CC CC CC CC  烫烫烫烫
0018FECC  CC CC CC CC CC CC CC CC  烫烫烫烫
0018FED4  00 00 00 00 00 00 00 00  ........
0018FEDC  00 00 CC CC 32 30 31 34  ..烫2014
0018FEE4  2F 31 32 2F 32 35 3D 31  /12/25=1
0018FEEC  36 3A 30 37 3A 32 36 00  6:07:26.
0018FEF4  48 FF 18 00 ED 10 40 00  H.....@.
0018FEFC
fun()函数的调用大致发生如下事情:(1)sp = sp - 4;把ip压入栈中,
即0018FEF8处的004010ED(大端)为执行完fun()函数后,程序的跳转地址。
(2)sp = sp - 4;把bp的内容压入栈中,即0018FEF4处的0018FF48为bp的内容。
(3)sp = sp - 60H;为局部变量开辟了60H大小的空间
(4)依次把接下来要使用到的bx、si、di依次压入栈中,bx原值为7EFDE000,
si原值为00000000,di的原值为0018FF48
(5)将0018FE8C--0018FEEC的内容全部置为CC(int 3中断指令,防止内存中的
东东被意外执行)
(6)为buffer和msg分别赋值。其中会发现0018FEDE和0018FEDF两个字节仍为CC,
则此两个字节为编译期为4个字节边界对齐而留出来的。
(7)执行sscanf()函数,执行完sscanf()后内存大致布局
0018FE84              48 FF 18 00  轧..H...
0018FE8C  00 00 00 00 00 E0 FD 7E  .....帻~
0018FE94  CC CC CC CC CC CC CC CC  烫烫烫烫
0018FE9C  CC CC CC CC CC CC CC CC  烫烫烫烫
0018FEA4  CC CC CC CC CC CC CC CC  烫烫烫烫
0018FEAC  CC CC CC CC CC CC CC CC  烫烫烫烫
0018FEB4  CC CC CC CC CC CC CC CC  烫烫烫烫
0018FEBC  CC CC CC CC CC CC CC CC  烫烫烫烫
0018FEC4  CC CC CC CC CC CC CC CC  烫烫烫烫
0018FECC  CC CC CC CC CC CC CC CC  烫烫烫烫
0018FED4  32 30 31 34 2F 31 32 2F  2014/12/
0018FEDC  32 35 3D 31 36 3A 30 37  25=16:07
0018FEE4  3A 32 36 00 32 35 3D 31  :26.25=1
0018FEEC  36 3A 30 37 3A 32 36 00  6:07:26.
0018FEF4  48 FF 18 00 ED 10 40 00  H.....@.
0018FEFC
则0018FEDE-0018FEE8全部被扰乱。其中buffer的起始地址为0x0018fee0所以buffer也受到了
干扰。


然后依次将buffer的维度修改为9、10、11、12
void fun()
{
char buffer[] = "2014/12/25 16:07:26";
char msg[9] = {0};


sscanf(buffer, "%s", msg);


printf("msg:-%s-\nbuffer:-%s-\n", msg, buffer);
}
则屏幕输出结果一直为:
msg:-2014/12/25=16:07:26-
buffer:-6:07:26-


如果干扰的的程度有足够厉害,足可干扰到栈内bp、ip的值。将msg和buffer调整下位置
&buffer = 0x0018fedc,&msg = 0x0018fee8
void fun()
{
char msg[10] = {0};
char buffer[] = "2014/12/25=";



sscanf(buffer, "%s", msg);


printf("msg:-%s-\nbuffer:-%s-\n", msg, buffer);
}
在sizeof(buffer) = 12时
msg:-2014/12/25=-
buffer:-2014/12/25=-
0018FE8C  E8 FE 18 00 48 FF 18 00  棹..H...
0018FE94  00 00 00 00 00 E0 FD 7E  .....帻~
0018FE9C  CC CC CC CC CC CC CC CC  烫烫烫烫
0018FEA4  CC CC CC CC CC CC CC CC  烫烫烫烫
0018FEAC  CC CC CC CC CC CC CC CC  烫烫烫烫
0018FEB4  CC CC CC CC CC CC CC CC  烫烫烫烫
0018FEBC  CC CC CC CC CC CC CC CC  烫烫烫烫
0018FEC4  CC CC CC CC CC CC CC CC  烫烫烫烫
0018FECC  CC CC CC CC CC CC CC CC  烫烫烫烫
0018FED4  CC CC CC CC CC CC CC CC  烫烫烫烫
0018FEDC  32 30 31 34 2F 31 32 2F  2014/12/
0018FEE4  32 35 3D 00 32 30 31 34  25=.2014
0018FEEC  2F 31 32 2F 32 35 3D 00  /12/25=.
0018FEF4  48 FF 18 00 ED 10 40 00  H.....@.
0018FEFC


继续调整,在sizeof(buffer) = 13时 
void fun()
{
char msg[10] = {0};
char buffer[] = "2014/12/25=1";



sscanf(buffer, "%s", msg);


printf("msg:-%s-\nbuffer:-%s-\n", msg, buffer);
}
则会报栈失衡的错误:The value of ESP was not properly saved
across a function call.This is usually a result of calling
a function declared with one calling ...
sscanf()执行前
0018FE98  CC CC CC CC CC CC CC CC  烫烫烫烫
0018FEA0  CC CC CC CC CC CC CC CC  烫烫烫烫
0018FEA8  CC CC CC CC CC CC CC CC  烫烫烫烫
0018FEB0  CC CC CC CC CC CC CC CC  烫烫烫烫
0018FEB8  CC CC CC CC CC CC CC CC  烫烫烫烫
0018FEC0  CC CC CC CC CC CC CC CC  烫烫烫烫
0018FEC8  CC CC CC CC CC CC CC CC  烫烫烫烫
0018FED0  CC CC CC CC CC CC CC CC  烫烫烫烫
0018FED8  32 30 31 34 2F 31 32 2F  2014/12/
0018FEE0  32 35 3D 31 00 CC CC CC  25=1.烫.
0018FEE8  00 00 00 00 00 00 00 00  ........
0018FEF0  00 00 CC CC 48 FF 18 00  ..烫H...
0018FEF8  FD 10 40 00
sscanf()执行后
0018FE98  CC CC CC CC CC CC CC CC  烫烫烫烫
0018FEA0  CC CC CC CC CC CC CC CC  烫烫烫烫
0018FEA8  CC CC CC CC CC CC CC CC  烫烫烫烫
0018FEB0  CC CC CC CC CC CC CC CC  烫烫烫烫
0018FEB8  CC CC CC CC CC CC CC CC  烫烫烫烫
0018FEC0  CC CC CC CC CC CC CC CC  烫烫烫烫
0018FEC8  CC CC CC CC CC CC CC CC  烫烫烫烫
0018FED0  CC CC CC CC CC CC CC CC  烫烫烫烫
0018FED8  32 30 31 34 2F 31 32 2F  2014/12/
0018FEE0  32 35 3D 31 00 CC CC CC  25=1.烫.
0018FEE8  32 30 31 34 2F 31 32 2F  2014/12/
0018FEF0  32 35 3D 31 00 FF 18 00  25=1....
0018FEF8  FD 10 40 00 
其中0018FEF5为dp内容由48变成了00


继续调整,在sizeof(buffer) = 17时
void fun()
{
char msg[10] = {0};
char buffer[] = "2014/12/25=16:07";



sscanf(buffer, "%s", msg);


printf("msg:-%s-\nbuffer:-%s-\n", msg, buffer);
}
出现了久违的程序崩溃
sscanf()执行前
0018FE94  CC CC CC CC CC CC CC CC  烫烫烫烫
0018FE9C  CC CC CC CC CC CC CC CC  烫烫烫烫
0018FEA4  CC CC CC CC CC CC CC CC  烫烫烫烫
0018FEAC  CC CC CC CC CC CC CC CC  烫烫烫烫
0018FEB4  CC CC CC CC CC CC CC CC  烫烫烫烫
0018FEBC  CC CC CC CC CC CC CC CC  烫烫烫烫
0018FEC4  CC CC CC CC CC CC CC CC  烫烫烫烫
0018FECC  CC CC CC CC CC CC CC CC  烫烫烫烫
0018FED4  32 30 31 34 2F 31 32 2F  2014/12/
0018FEDC  32 35 3D 31 36 3A 30 37  25=16:07
0018FEE4  00 CC CC CC 00 00 00 00  .烫.....
0018FEEC  00 00 00 00 00 00 CC CC  ......烫
0018FEF4  48 FF 18 00 FD 10 40 00  H.....@.
0018FEFC
sscanf()执行后
0018FE94  CC CC CC CC CC CC CC CC  烫烫烫烫
0018FE9C  CC CC CC CC CC CC CC CC  烫烫烫烫
0018FEA4  CC CC CC CC CC CC CC CC  烫烫烫烫
0018FEAC  CC CC CC CC CC CC CC CC  烫烫烫烫
0018FEB4  CC CC CC CC CC CC CC CC  烫烫烫烫
0018FEBC  CC CC CC CC CC CC CC CC  烫烫烫烫
0018FEC4  CC CC CC CC CC CC CC CC  烫烫烫烫
0018FECC  CC CC CC CC CC CC CC CC  烫烫烫烫
0018FED4  32 30 31 34 2F 31 32 2F  2014/12/
0018FEDC  32 35 3D 31 36 3A 30 37  25=16:07
0018FEE4  00 CC CC CC 32 30 31 34  .烫.2014
0018FEEC  2F 31 32 2F 32 35 3D 31  /12/25=1
0018FEF4  36 3A 30 37 00 10 40 00  6:07..@.
0018FEFC
其中0018FEF8为dp内容由FD变成了00


总结:在VC6.0--DEBUG模式下栈溢出时可能会影响到(1)自己剩余的边界对齐字节
(2)其他更高地址的局部变量(3)bp值,栈失衡(4)ip值,程序的正确运行方向
(5)更高地址的内存......



由于VC6.0--RELEASE模式与DEBUG模式的不同之处是:release直接操作sp,而不会往
栈中压入bp。
 
阅读(1527) | 评论(0) | 转发(0) |
0

上一篇:写出像printf一样可变长参数的函数

下一篇:没有了

给主人留下些什么吧!~~