【Linux】栈保护 栈溢出 stack smashing detected 定位方法

编程入门 行业动态 更新时间:2024-10-25 08:21:05

【Linux】栈保护 栈溢出 stack smashing detected 定位<a href=https://www.elefans.com/category/jswz/34/1771314.html style=方法"/>

【Linux】栈保护 栈溢出 stack smashing detected 定位方法

栈保护 栈溢出 stack smashing detected 定位方法

  • 一、Linux开发环境
  • 二、关键词
  • 三、背景
  • 四、定位分析
    • 1)第一种情况:变量的值被篡改。
      • a)源代码(可不看)
      • b)编译
      • c)运行
      • d)定位
      • e)总结
    • 2)第二种情况:程序报”stack smashing detected”然后终止。
      • a)源代码(可不看)
      • b)编译
      • c)运行
      • d)定位
      • e)总结

一、Linux开发环境

OS:Ubuntu 16.04.1
编译工具:gcc 5.4.0
调试工具:gdb

二、关键词

栈保护
栈溢出
*** stack smashing detected ***
-fstack-protector
-fno-stack-protector

三、背景

gcc提供栈溢出保护机制,即默认编译时-fstack-protector选项为开。
在该保护机制下,如果程序中有栈溢出,会有以下报错信息,程序异常终止:
*** stack smashing detected ***: ./test terminated
Aborted (core dumped)若要关闭栈溢出保护,在gcc编译选项中增加-fno-stack-protector即可。
关闭后,如果程序中有栈溢出,仍可能会成功执行完,没有任何报错。
但实际上,栈溢出会导致程序中定义的变量被篡改。如果你的程序出现上面提到的两种异常:变量被篡改、或者栈溢出导致的异常终止,希望本文会对你有帮助。

四、定位分析

1)第一种情况:变量的值被篡改。

a)源代码(可不看)

#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "math.h"
#include <ctype.h>int c2i(char ch)
{//如果是数字,则用ascii 减去48//isdight 判断数字函数if(isdigit(ch)){return ch-48;}//判断字母if(ch<'A'||(ch>'F'&&ch<'a')||ch>'z'){return -1;}//大写字母减去55,小写字母减去87if(isalpha(ch)){return isupper(ch)?ch-55:ch-87;}
}int hex2dec(char *hex)
{int len, num,temp,bits,i;num = 0;len = strlen(hex);//printf("len = %d\n",len);for(i=0,temp=0;i<len;i++,temp=0){//printf("hex = %c\n",hex[i]);//printf("num = %d\n",num);temp = c2i(*(hex+i));//printf("temp = %d\n",temp);bits = (len-i-1)*4;//printf("bits = %d\n",bits);temp = temp << bits;//printf("temp = %d\n",temp);num = num|temp;}return num;
}char* itoa(long int num,char *str,int radix)
{char index[] = "0123456789ABCDEF";long unsigned unum;int i=0,j,k;if(radix==10&&num<0){unum = (unsigned) -num;str[i++] = '-';}elseunum = (unsigned)num;do{str[i++] = index[unum%(unsigned)radix];unum/=radix;}while(unum);//printf("str = %s\n",str);str[i] = '\0';if(str[0]=='-'){k = 1;}elsek = 0;for(j = k;j<=(i-1)/2;j++){char temp;temp = str[j];str[j] = str[i-1+k-j];str[i-1+k-j] = temp;}//printf("str = %s\n",str);return str;
}/******************************************************
生成command 的chksum函数
*******************************************************/
char *creatChksum(char *Commandinfo,char* chkstr)
{int temp = 0;int chksum = 0;for(int i=1;i<strlen(Commandinfo);i++){temp = Commandinfo[i]+temp;}//printf("creatChksum = %s\n",Commandinfo);//printf("creatChksum = %d\n",temp);sprintf(chkstr,"%04X",temp);return chkstr;
}double getRandData(int min,int max)
{double m1=(double)(rand()%101)/101;                        							  // 计算 0,1之间的随机小数,得到的值域近似为(0,1)min++;                                                                            	  //将 区间变为(min+1,max),double m2=(double)((rand()%(max-min+1))+min);    										  //计算 min+1,max 之间的随机整数,得到的值域为[min+1,max]m2=m2-1;                                                                        		  //令值域为[min,max-1]return m1+m2;                                                                			  //返回值域为(min,max),为所求随机浮点数
}int creatfloatstr(float num,char *str)
{int rtn = 0;long int tempdata;float mantissa = 0;int stepdata = 0;char tempstr[24];char mantissastr[24];char strstep[9];char strsteptemp[9];char floatstr[33];#if 1if(rtn == 0){memset(str,'\0',33);//printf("%f\n",num);if(rtn == 0){for(int i=1;i<20;i++){num = num/2;if(num<2){stepdata = i;break;}}mantissa = num -1;memset(mantissastr,'\0',24);long int mantissadata = mantissa*8388608;itoa(mantissadata,tempstr,2);if(strlen(tempstr)<23){int length = 23 -strlen(tempstr);for(int i=0;i<length;i++){mantissastr[i] = '0';}strncat(mantissastr,tempstr,23);}else{strncpy(mantissastr,tempstr,23);}}if(rtn == 0){memset(strsteptemp,'\0',9);memset(strstep,'\0',9);itoa(stepdata,strsteptemp,2);if(strlen(strsteptemp)<8){int length = 8 - strlen(strsteptemp);for(int i=0;i<length;i++){strstep[i] = '0';}strcat(strstep,strsteptemp);}else{strncpy(strstep,strsteptemp,8);}//printf("strstep = %s\n",strstep);}if(rtn == 0){if(num<0){strcat(str,"1");}else{strcat(str,"0");}strcat(str,strstep);strcat(str,mantissastr);for(int i = 0;i<strlen(str);i++){if(str[i] == '1')tempdata = tempdata + pow(2,31-i);}sprintf(str,"%08lX",tempdata);}//printf("str = %s\n",str);}#endifreturn rtn;
}unsigned int virtual_data(char *receivebuf,char *sendbuf)
{int rtn = 0;int chkNumber = 0;char chucksum[5];char cid2[3];char length[5];int datalength=0;char *commandinfo;char buf[10];char data[8];int len = strlen(receivebuf);memset(buf, '\0', 10);memcpy(buf, "ABCDEFGH", 8);printf("------- buf = %s, line[%d]\n", buf, __LINE__);if(rtn == 0){//首先chucksumif(rtn == 0){//字符串转数字,计算chksum值memset(chucksum,'\0',4);for(int i = 0;i<4;i++){chucksum[i] = receivebuf[len-6+i];}chucksum[4] = '\0';strncpy(chucksum,chucksum,4);for(int i = 1;i<len-6;i++){chkNumber = chkNumber + receivebuf[i];//printf("receivebuf[i]=%c\n",receivebuf[i]);	}chkNumber = chkNumber%65536;chkNumber = ~chkNumber+1+65536;if(chkNumber != hex2dec(chucksum)){//printf("chkNumber=%d\n",chkNumber);			//printf("hex2dec(chucksum)=%d\n",hex2dec(chucksum));rtn = -1;}}//解析设备类型,填充设备数据,主要解析cid2 length commandinfo chucksum#if 1if(rtn == 0){//填充sendbuf strncpy(sendbuf,receivebuf,7);memset(cid2,'\0',3);*(cid2) = *(receivebuf+7);*(cid2+1) = *(receivebuf+8);//printf("%s\n",cid2);if(strcmp(cid2,"41") == 0){//默认数据正常 rtn 赋值00strncat(sendbuf,"00",2);memset(length,'\0',5);//数据为浮点型数据,处理数据长度for(int i = 0;i<4;i++){length[i] = receivebuf[10+i];}strncat(sendbuf,length,4);length[3] = '\0';//printf("length = %s\n",length);datalength = hex2dec(length)/2;//printf("datalength = %d\n",datalength);for(int i=0;i<datalength;i++){memset(data,'\0',9);creatfloatstr(getRandData(0,100),data);strncat(sendbuf,data,8);}//memset(sendbuf,'\0',200);creatChksum(sendbuf,chucksum);strncat(sendbuf,chucksum,4);strncat(sendbuf,"CR",2);}if(strcmp(cid2,"42") == 0){//默认数据正常 rtn 赋值00strncat(sendbuf,"00",2);//数据为整型数据,处理数据长度for(int i = 0;i<4;i++){length[3-i] = receivebuf[13+i];}strncat(sendbuf,length,4);length[3] = '0';datalength = hex2dec(length);for(int i=0;i<datalength;i++){memset(data,'\0',8);sprintf(data,"%04X",rand()%101);strncat(sendbuf,data,8);}memset(sendbuf,'\0',4);creatChksum(sendbuf,chucksum);strncat(sendbuf,chucksum,4);strncat(sendbuf,"CR",2);}}#endif}	printf("------- buf = %s, line[%d]\n", buf, __LINE__);return rtn;
}int main()
{int rtn = 0;char *receivebuf = malloc(256*sizeof(char));strncpy(receivebuf,"~20012441E00201FD3ACR",32*sizeof(char));char sendbuf[200];rtn = virtual_data(receivebuf,sendbuf);//printf("send=%s\n",sendbuf);exit(0);return 0;
}

b)编译

gcc -g -o test main.c –lm

c)运行


发现buf中的数据被篡改!通过阅读程序,buf在virtual_data函数中定义,之后便再无赋值,那么应该 是在两次打印之间被篡改的。像这种情况,首先怀疑的就是发生了内存越界!

d)定位

e)总结

程序中能明确看到某个变量的值被篡改,这种情况一般定位思路:
使用watch命令观察该变量;
执行c继续运行,程序会停在观察点发生变化的地方;
执行where命令,查看当前的位置,即定位到哪行语句篡改了被观察的变量。

2)第二种情况:程序报”stack smashing detected”然后终止。

a)源代码(可不看)

#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "math.h"
#include <ctype.h>int c2i(char ch)
{//如果是数字,则用ascii 减去48//isdight 判断数字函数if(isdigit(ch)){return ch-48;}//判断字母if(ch<'A'||(ch>'F'&&ch<'a')||ch>'z'){return -1;}//大写字母减去55,小写字母减去87if(isalpha(ch)){return isupper(ch)?ch-55:ch-87;}
}int hex2dec(char *hex)
{int len, num,temp,bits,i;num = 0;len = strlen(hex);//printf("len = %d\n",len);for(i=0,temp=0;i<len;i++,temp=0){//printf("hex = %c\n",hex[i]);//printf("num = %d\n",num);temp = c2i(*(hex+i));//printf("temp = %d\n",temp);bits = (len-i-1)*4;//printf("bits = %d\n",bits);temp = temp << bits;//printf("temp = %d\n",temp);num = num|temp;}return num;
}char* itoa(long int num,char *str,int radix)
{char index[] = "0123456789ABCDEF";long unsigned unum;int i=0,j,k;if(radix==10&&num<0){unum = (unsigned) -num;str[i++] = '-';}elseunum = (unsigned)num;do{str[i++] = index[unum%(unsigned)radix];unum/=radix;}while(unum);//printf("str = %s\n",str);str[i] = '\0';if(str[0]=='-'){k = 1;}elsek = 0;for(j = k;j<=(i-1)/2;j++){char temp;temp = str[j];str[j] = str[i-1+k-j];str[i-1+k-j] = temp;}//printf("str = %s\n",str);return str;
}/******************************************************
生成command 的chksum函数
*******************************************************/
char *creatChksum(char *Commandinfo,char* chkstr)
{int temp = 0;int chksum = 0;for(int i=1;i<strlen(Commandinfo);i++){temp = Commandinfo[i]+temp;}//printf("creatChksum = %s\n",Commandinfo);//printf("creatChksum = %d\n",temp);sprintf(chkstr,"%04X",temp);return chkstr;
}double getRandData(int min,int max)
{double m1=(double)(rand()%101)/101;                        							  // 计算 0,1之间的随机小数,得到的值域近似为(0,1)min++;                                                                            	  //将 区间变为(min+1,max),double m2=(double)((rand()%(max-min+1))+min);    										  //计算 min+1,max 之间的随机整数,得到的值域为[min+1,max]m2=m2-1;                                                                        		  //令值域为[min,max-1]return m1+m2;                                                                			  //返回值域为(min,max),为所求随机浮点数
}int creatfloatstr(float num,char *str)
{int rtn = 0;long int tempdata;float mantissa = 0;int stepdata = 0;char tempstr[24];char mantissastr[24];char strstep[9];char strsteptemp[9];char floatstr[33];#if 1if(rtn == 0){memset(str,'\0',64);//printf("%f\n",num);if(rtn == 0){for(int i=1;i<20;i++){num = num/2;if(num<2){stepdata = i;break;}}mantissa = num -1;memset(mantissastr,'\0',24);long int mantissadata = mantissa*8388608;itoa(mantissadata,tempstr,2);if(strlen(tempstr)<23){int length = 23 -strlen(tempstr);for(int i=0;i<length;i++){mantissastr[i] = '0';}strncat(mantissastr,tempstr,23);}else{strncpy(mantissastr,tempstr,23);}}if(rtn == 0){memset(strsteptemp,'\0',9);memset(strstep,'\0',9);itoa(stepdata,strsteptemp,2);if(strlen(strsteptemp)<8){int length = 8 - strlen(strsteptemp);for(int i=0;i<length;i++){strstep[i] = '0';}strcat(strstep,strsteptemp);}else{strncpy(strstep,strsteptemp,8);}//printf("strstep = %s\n",strstep);}if(rtn == 0){if(num<0){strcat(str,"1");}else{strcat(str,"0");}strcat(str,strstep);strcat(str,mantissastr);for(int i = 0;i<strlen(str);i++){if(str[i] == '1')tempdata = tempdata + pow(2,31-i);}sprintf(str,"%08lX",tempdata);}//printf("str = %s\n",str);}#endifreturn rtn;
}unsigned int virtual_data(char *receivebuf,char *sendbuf)
{int rtn = 0;int chkNumber = 0;char chucksum[5];char cid2[3];char length[5];int datalength=0;char *commandinfo;char buf[10];char data[8];int len = strlen(receivebuf);memset(buf, '\0', 10);memcpy(buf, "ABCDEFGH", 8);//printf("------- buf = %s, line[%d]\n", buf, __LINE__);if(rtn == 0){//首先chucksumif(rtn == 0){//字符串转数字,计算chksum值memset(chucksum,'\0',4);for(int i = 0;i<4;i++){chucksum[i] = receivebuf[len-6+i];}chucksum[4] = '\0';strncpy(chucksum,chucksum,4);for(int i = 1;i<len-6;i++){chkNumber = chkNumber + receivebuf[i];//printf("receivebuf[i]=%c\n",receivebuf[i]);	}chkNumber = chkNumber%65536;chkNumber = ~chkNumber+1+65536;if(chkNumber != hex2dec(chucksum)){//printf("chkNumber=%d\n",chkNumber);			//printf("hex2dec(chucksum)=%d\n",hex2dec(chucksum));rtn = -1;}}//解析设备类型,填充设备数据,主要解析cid2 length commandinfo chucksum#if 1if(rtn == 0){//填充sendbuf strncpy(sendbuf,receivebuf,7);memset(cid2,'\0',3);*(cid2) = *(receivebuf+7);*(cid2+1) = *(receivebuf+8);//printf("%s\n",cid2);if(strcmp(cid2,"41") == 0){//默认数据正常 rtn 赋值00strncat(sendbuf,"00",2);memset(length,'\0',5);//数据为浮点型数据,处理数据长度for(int i = 0;i<4;i++){length[i] = receivebuf[10+i];}strncat(sendbuf,length,4);length[3] = '\0';//printf("length = %s\n",length);datalength = hex2dec(length)/2;//printf("datalength = %d\n",datalength);for(int i=0;i<datalength;i++){memset(data,'\0',9);creatfloatstr(getRandData(0,100),data);strncat(sendbuf,data,8);}//memset(sendbuf,'\0',200);creatChksum(sendbuf,chucksum);strncat(sendbuf,chucksum,4);strncat(sendbuf,"CR",2);}if(strcmp(cid2,"42") == 0){//默认数据正常 rtn 赋值00strncat(sendbuf,"00",2);//数据为整型数据,处理数据长度for(int i = 0;i<4;i++){length[3-i] = receivebuf[13+i];}strncat(sendbuf,length,4);length[3] = '0';datalength = hex2dec(length);for(int i=0;i<datalength;i++){memset(data,'\0',8);sprintf(data,"%04X",rand()%101);strncat(sendbuf,data,8);}memset(sendbuf,'\0',4);creatChksum(sendbuf,chucksum);strncat(sendbuf,chucksum,4);strncat(sendbuf,"CR",2);}}#endif}	//printf("------- buf = %s, line[%d]\n", buf, __LINE__);return rtn;
}int main()
{int rtn = 0;char *receivebuf = malloc(256*sizeof(char));strncpy(receivebuf,"~20012441E00201FD3ACR",32*sizeof(char));char sendbuf[200];rtn = virtual_data(receivebuf,sendbuf);//printf("send=%s\n",sendbuf);exit(0);return 0;
}

b)编译

gcc -g -o test main.c –lm

c)运行


此种情况看不到程序内部变量是否发生篡改,会直接退出程序,所以不适合用watch。但是又确实发生了栈溢出,在栈保护机制的作用下,程序并不会在执行到导致栈溢出的那行语句时就报错然后终止,而是把子函数全部执行完,再回到main函数中去。但是由于栈已经被破坏,在往main函数跳的时候,就无法获取main函数的栈空间了,所以异常终止。

d)定位

e)总结

即先看堆栈,大致确定是哪个函数。然后进到该函数中,逐条语句执行、查看堆栈信息,直到看到栈被破坏。
遇到函数调用层次比较多时,效率会比较低,但也算有效。

更多推荐

【Linux】栈保护 栈溢出 stack smashing detected 定位方法

本文发布于:2024-03-11 16:31:43,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1729401.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:方法   stack   Linux   detected   smashing

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!