当前位置: 首页 > news >正文

编写 网站 语言网页设计素材图标

编写 网站 语言,网页设计素材图标,重庆平台网站建设平台,绵阳优化网站排名整型溢出有点老生常谈了#xff0c;bla, bla, bla… 但似乎没有引起多少人的重视。整型溢出会有可能导致缓冲区溢出#xff0c;缓冲区溢出会导致各种黑客攻击#xff0c;比如最近OpenSSL的heartbleed事件#xff0c;就是一个buffer overread的事件。在这里写下这篇文章bla, bla, bla… 但似乎没有引起多少人的重视。整型溢出会有可能导致缓冲区溢出缓冲区溢出会导致各种黑客攻击比如最近OpenSSL的heartbleed事件就是一个buffer overread的事件。在这里写下这篇文章希望大家都了解一下整型溢出编译器的行为以及如何防范以写出更安全的代码。 什么是整型溢出 C语言的整型问题相信大家并不陌生了。对于整型溢出分为无符号整型溢出和有符号整型溢出。 对于unsigned整型溢出C的规范是有定义的——“溢出后的数会以2^(8*sizeof(type))作模运算”也就是说如果一个unsigned char1字符8bits溢出了会把溢出的值与256求模。例如 1 2 unsigned char x 0xff; printf(%d\n, x); 上面的代码会输出0 因为0xff 1是256与2^8求模后就是0 对于signed整型的溢出C的规范定义是“undefined behavior”也就是说编译器爱怎么实现就怎么实现。对于大多数编译器来说算得啥就是啥。比如 1 2 signed char x 0x7f; //注0xff就是-1了因为最高位是1也就是负数了 printf(%d\n, x); 上面的代码会输出-128因为0x7f 0×01得到0×80也就是二进制的1000 0000符号位为1负数后面为全0就是负的最小数即-128。 另外千万别以为signed整型溢出就是负数这个是不定的。比如 1 2 3 4 signed char x 0x7f; signed char y 0x05; signed char r x * y; printf(%d\n, r); 上面的代码会输出123 相信对于这些大家不会陌生了。 整型溢出的危害 下面说一下整型溢出的危害。 示例一整形溢出导致死循环 1 2 3 4 5 6 7 8 ... ... ... ... short len 0; ... ... while(len MAX_LEN) {     len readFromInput(fd, buf);     buf len; } 上面这段代码可能是很多程序员都喜欢写的代码我在很多代码里看到过多次其中的MAX_LEN 可能会是个比较大的整型比如32767我们知道short是16bits取值范围是-32768 到 32767 之间。但是上面的while循环代码有可能会造成整型溢出而len又是个有符号的整型所以可能会成负数导致不断地死循环。 示例二整形转型时的溢出 1 2 3 4 5 6 7 8 9 10 11 12 13 int copy_something(char *buf, int len) {     #define MAX_LEN 256     char mybuf[MAX_LEN];/pre pre     ... ...      ... ...      if(len MAX_LEN){ // ---- [1]          return -1;      }      return memcpy(mybuf, buf, len); } 上面这个例子中还是[1]处的if语句看上去没有会问题但是len是个signed int而memcpy则需一个size_t的len也就是一个unsigned 类型。于是len会被提升为unsigned此时如果我们给len传一个负数会通过了if的检查但在memcpy里会被提升为一个正数于是我们的mybuf就是overflow了。这个会导致mybuf缓冲区后面的数据被重写。 示例三分配内存 关于整数溢出导致堆溢出的很典型的例子是OpenSSH Challenge-Response SKEY/BSD_AUTH 远程缓冲区溢出漏洞。下面这段有问题的代码摘自OpenSSH的代码中的auth2-chall.c中的input_userauth_info_response() 函数: 1 2 3 4 5 6 nresp packet_get_int(); if (nresp 0) {     response xmalloc(nresp*sizeof(char*));     for (i 0; i nresp; i)         response[i] packet_get_string(NULL); } 上面这个代码中nresp是size_t类型size_t一般就是unsigned int/long int这个示例是一个解数据包的示例一般来说数据包中都会有一个len然后后面是data。如果我们精心准备一个len比如1073741825在32位系统上指针占4个字节unsigned int的最大值是0xffffffff我们只要提供0xffffffff/4 的值——0×40000000这里我们设置了0×4000000 1 nresp就会读到这个值然后nresp*sizeof(char*)就成了 1073741825 * 4于是溢出结果成为了 0×100000004然后求模得到4。于是malloc(4)于是后面的for循环1073741825 次就可以干环事了经过0×40000001的循环,用户的数据早已覆盖了xmalloc原先分配的4字节的空间以及后面的数据包括程序代码函数指针于是就可以改写程序逻辑。关于更多的东西你可以看一下这篇文章《Survey of Protections from Buffer-Overflow Attacks》。 示例四缓冲区溢出导致安全问题 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 int func(char *buf1, unsigned int len1,          char *buf2, unsigned int len2 ) {    char mybuf[256];    if((len1 len2) 256){    //--- [1]        return -1;    }    memcpy(mybuf, buf1, len1);    memcpy(mybuf len1, buf2, len2);    do_some_stuff(mybuf);    return 0; } 上面这个例子本来是想把buf1和buf2的内容copy到mybuf里其中怕len1 len2超过256 还做了判断但是如果len1len2溢出了根据unsigned的特性其会与2^32求模所以基本上来说上面代码中的[1]处有可能为假的。注通常来说在这种情况下如果你开启-O代码优化选项那个if语句块就全部被和谐掉了——被编译器给删除了比如你可以测试一下 len10×104 len2 0xfffffffc 的情况。 这样的例子有很多很多这些整型溢出的问题如果在关键的地方尤其是在搭配有用户输入的地方如果被黑客利用了就会导致很严重的安全问题。 关于编译器的行为 在谈一下如何正确的检查整型溢出之前我们还要来学习一下编译器的一些东西。请别怪我罗嗦。 编译器优化 如何检查整型溢出或是整型变量是否合法有时候是一件很麻烦的事情就像上面的第四个例子一样编译的优化参数-O/-O2/-O3基本上会假设你的程序不会有整形溢出。会把你的代码中检查溢出的代码给优化掉。 关于编译器的优化在这里再举个例子假设我们有下面的代码又是一个相当相当常见的代码 1 2 3 4 5 6 7 int len; char* data; if (data len data){     printf(invalid len\n);     exit(-1); } 上面这段代码中len 和 data 配套使用我们害怕len的值是非法的或是len溢出了于是我们写下了if语句来检查。这段代码在-O的参数下正常。但是在-O2的编译选项下整个if语句块被优化掉了。 你可以写个小程序在gcc下编译我的版本是4.4.7记得加上-O2和-g参数然后用gdb调试时用disass /m命信输出汇编你会看到下面的结果你可以看到整个if语句块没有任何的汇编代码——直接被编译器和谐掉了 1 2 3 4 5 6 7 8 9 10 11 12 13 14 7           int len 10; 8           char* data (char *)malloc(len);    0x00000000004004d4 4:     mov    $0xa,%edi    0x00000000004004d9 9:     callq  0x4003b8 mallocplt 9 10          if (data len data){ 11              printf(invalid len\n); 12              exit(-1); 13          } 14 15      }    0x00000000004004de 14:    add    $0x8,%rsp    0x00000000004004e2 18:    retq 对此你需要把上面 char* 转型成 uintptr_t 或是 size_t说白了也就是把char*转成unsigned的数据结构if语句块就无法被优化了。如下所示 1 2 3 if ((uintptr_t)data len (uintptr_t)data){     ... ... } 关于这个事你可以看一下C99的规范说明《 ISO/IEC 9899:1999 C specification 》第 §6.5.6 页第8点我截个图如下这段话的意思是定义了指针/-一个整型的行为如果越界了则行为是undefined 注意上面标红线的地方说如果指针指在数组范围内没事如果越界了就是undefined也就是说这事交给编译器实现了编译器想咋干咋干那怕你想把其优化掉也可以。在这里要重点说一下C语言中的一个大恶魔—— Undefined! 这里都是“野兽出没”的地方你一定要小心小心再小心。 花絮编译器的彩蛋 上面说了所谓的undefined行为就全权交给编译器实现gcc在1.17版本下对于undefined的行为还玩了个彩蛋参看Wikipedia。 下面gcc 1.17版本下的遭遇undefined行为时gcc在unix发行版下玩的彩蛋的源代码。我们可以看到它会去尝试去执行一些游戏NetHack Rogue 或是Emacs的 Towers of Hanoi如果找不到就输出一条NB的报错。 1 2 3 4 5 6 execl(/usr/games/hack, #pragma, 0); // try to run the game NetHack execl(/usr/games/rogue, #pragma, 0); // try to run the game Rogue // try to run the Towers of Hanoi simulation in Emacs. execl(/usr/new/emacs, -f,hanoi,9,-kill,0); execl(/usr/local/emacs,-f,hanoi,9,-kill,0); // same as above fatal(You are in a maze of twisty compiler features, all different); 正确检测整型溢出 在看过编译器的这些行为后你应该会明白——“在整型溢出之前一定要做检查不然就太晚了”。 我们来看一段代码 1 2 3 4 5 void foo(int m, int n) {     size_t s m n;     ....... } 上面这段代码有两个风险1有符号转无符号2整型溢出。这两个情况在前面的那些示例中你都应该看到了。所以你千万不要把任何检查的代码写在 s m n 这条语名后面不然就太晚了。undefined行为就会出现了——用句纯正的英文表达就是——“Dragon is here”——你什么也控制不住了。注意有些初学者也许会以为size_t是无符号的而根据优先级 m 和 n 会被提升到unsigned int。其实不是这样的m 和 n 还是signed intm n 的结果也是signed int然后再把这个结果转成unsigned int 赋值给s 比如下面的代码是错的 1 2 3 4 5 6 7 void foo(int m, int n) {     size_t s m n;     if ( m0 n0 (SIZE_MAX - m n) ){         //error handling...     } } 上面的代码中大家要注意 (SIZE_MAX – m n) 这个判断为什么不用m n SIZE_MAX呢因为如果 m n 溢出后就被截断了所以表达式恒真也就检测不出来了。另外这个表达式中m和n分别会被提升为unsigned。 但是上面的代码是错的因为 1检查的太晚了if之前编译器的undefined行为就已经出来了你不知道什么会发生。 2就像前面说的一样(SIZE_MAX – m n) 可能会被编译器优化掉。 3另外SIZE_MAX是size_t的最大值size_t在64位系统下是64位的严谨点应该用INT_MAX或是UINT_MAX 所以正确的代码应该是下面这样 1 2 3 4 5 6 7 8 9 void foo(int m, int n) {     size_t s 0;     if ( m0 n0 ( UINT_MAX - m n ) ){         //error handling...         return;     }     s (size_t)m (size_t)n; } 在《苹果安全编码规范》PDF中第28页的代码中 如果n和m都是signed int那么这段代码是错的。正确的应该像上面的那个例子一样至少要在n*m时要把 n 和 m 给 cast 成 size_t。因为n*m可能已经溢出了已经undefined了undefined的代码转成size_t已经没什么意义了。如果m和n是unsigned int也会溢出上面的代码仅在m和n是size_t的时候才有效。 不管怎么说《苹果安全编码规范》绝对值得你去读一读。 上溢出和下溢出的检查 前面的代码只判断了正数的上溢出overflow没有判断负数的下溢出underflow。让们来看看怎么判断 对于加法还好。 1 2 3 4 5 6 7 8 9 10 11 #include limits.h void f(signed int si_a, signed int si_b) {     signed int sum;     if (((si_b 0) (si_a (INT_MAX - si_b))) ||         ((si_b 0) (si_a (INT_MIN - si_b)))) {         /* Handle error */         return;     }     sum si_a si_b; } 对于乘法就会很复杂下面的代码太夸张了 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 void func(signed int si_a, signed int si_b) {   signed int result;   if (si_a 0) {  /* si_a is positive */     if (si_b 0) {  /* si_a and si_b are positive */       if (si_a (INT_MAX / si_b)) {         /* Handle error */       }     } else { /* si_a positive, si_b nonpositive */       if (si_b (INT_MIN / si_a)) {         /* Handle error */       }     } /* si_a positive, si_b nonpositive */   } else { /* si_a is nonpositive */     if (si_b 0) { /* si_a is nonpositive, si_b is positive */       if (si_a (INT_MIN / si_b)) {         /* Handle error */       }     } else { /* si_a and si_b are nonpositive */       if ( (si_a ! 0) (si_b (INT_MAX / si_a))) {         /* Handle error */       }     } /* End if si_a and si_b are nonpositive */   } /* End if si_a is nonpositive */   result si_a * si_b; } 更多的防止在操作中整型溢出的安全代码可以参看《INT32-C. Ensure that operations on signed integers do not result in overflow》 其它 对于C来说你应该使用STL中的numeric_limits::max() 来检查溢出。 另外微软的SafeInt类是一个可以帮你远理上面这些很tricky的类下载地址http://safeint.codeplex.com/ 对于Java 来说一种是用JDK 1.7中Math库下的safe打头的函数如safeAdd()和safeMultiply()另一种用更大尺寸的数据类型最大可以到BigInteger。 可见写一个安全的代码并不容易尤其对于C/C来说。对于黑客来说他们只需要搜一下开源软件中代码有memcpy/strcpy之类的地方然后看一看其周边的代码是否可以通过用户的输入来影响如果有的话你就惨了。 参考 Basic Integer Overflow OWASPInteger overflow C compilers may silently discard some wraparound checks Apple Secure Coding Guide Wikipedia: Undefined Behavior INT32-C. Ensure that operations on signed integers do not result in overflow 最后 不好意思这篇文章可能罗嗦了一些大家见谅。
http://www.pierceye.com/news/41825/

相关文章:

  • 上海设计网站大全网站优化的链接建设
  • 网站建设需注意哪些事项手机网站设计理念
  • 网站怎么做关键词搜索排面南昌网架公司
  • 为企业做网站赚钱吗北京广告制作公司
  • 什么网站可以免费做视频网站有哪些类型
  • 如何将自己做的网站wordpress单页展示主题
  • wordpress启用多站点wordpress主题学习
  • 重庆南川网站制作公司哪家好南宁网站排名优化公司
  • 目前网站在初级建设阶段 需要大量数据丰富做信息网站能挣钱吗
  • 做汽车保养的网站可以全部免费观看的平台
  • 网站开发php和ui如何建立网站站点
  • 郑州网站建设白杨网络app软件开发公司员工守则
  • 十年网站建设建设一个能看视频的网站
  • 公司网站设计主页部分怎么做排名第一的玉米品种
  • 一键制作网站软件商品管理系统
  • 网站怎么做站内美化义乌哪里做网站好
  • 免费网站知乎网站开发方案目录
  • 万维网网站域名续费北京网站设计工资多少
  • 深圳网站建设官网房产网站模板
  • 手机网站开发技术pdf商务局网站建设方案
  • 网站宣传海报乌兰浩特网站制作
  • 微信营销的10种方法技巧西安seo交流
  • asp.net网站开发菜鸟wordpress 遮罩图片
  • 杭州网站建设商城价格程序员用的编程软件
  • 移动端网站开发项目报告淘宝宝贝排名查询
  • 四川建设厅的网站备案网站主办者承诺书
  • 常州做网上废品收购网站wordpress 游戏 模板下载地址
  • 怎么做审核网站搜索引擎优化至少包括哪几步
  • 专业的网站建设找聚爱高价词网站源码
  • 前端开发就是做网站吗免费服务器试用