Skip to content

Monthly Archives: 八月 2008

问候某些人的妈!

我先要发自内心的问候一声他妈! 你爷爷难得双休,今儿在家刚睡天好觉,吃顿自在饭,多清净的一天. 就让你TM个赖孙的电话搅和了! 妈的,晚上十点四十了,正悠闲听歌,你打个电话,也不是我认识的号,接了你TM也不说话! 爷爷我还不挂?! 挂了你还来劲了,又打. 接起来你都给我说话都带话瓣儿,听你那说个话都说不顺溜! 要喝多回家睡别! 莫装B啊! 忍住你,你还上脸! 就非让爷回嘴骂你!? 你孙子真TM缺心眼! 打个电话不会说话,你傻啊还是想证明你有钱啊? 就算打错了,爷也没说啥啊!! 还又打个找骂,去你娘! 你爷最近很忙,杂TM能有时间招惹到你这号小人了! 真TM的晦气! 爷养了一天的心情都TM让你孙子毁了! 妈的火大了!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 你碰到这号孙子,选下你杂处理? 上面
]]>

一个普通美国人的工资&账本

首先介绍一下本文主人公背景:一个普通的美国人,大学毕业后两年。男性。单身。

工作:在一个商业机构当业务代表。

工资:打税和交费以后三千美元/月。美国人打税包括联邦税,州税,社会安全税,州残疾人税,全国医疗保险税。交费有退休基金约百分之十,工会费,人寿保险费,医药保险费
(3000$是很正常的工资薪水,美国年收入3万$一下就是低薪了)

父母帮他出了头期款,贷款买了一所房子。独栋房子,三房,一个饭厅,一个客厅,一个半浴室,一个厨房连早餐间,一个车房,后花园;每月自己每月还房贷1000$,地税保险:300$ (地税保险? 开始看到我也没明白,网上查了一下,我理解的是这样的: “地税保险”应该是”地税”和”保险“两样. 在美国买房是连土地一起购买的,所以要缴纳土地税,保险应该是购买的房屋资产保险,查了下美国的房屋保险,很有趣,保很多,有兴趣看看 美国标准房主保险(Homeowners-3, HO-3))

他买了一辆宝马325i轿车,汽车贷款是:300美元(占月收入百分之十),汽车保险:100美元(占月收入百分之3)
(美国的车险好贵啊,也去查了下. 美国汽车保险
美国的车险赔付比国内好很多,不管是不是自己的责任,保险公司都会赔)

手机花费(包括月费和电话费在内,他每月白天要打600分钟左右的电话,幸好美国的手机晚上9点以后和星期六、星期天都是免费时间):45美元(带税)(百分之一点五)
(很羡慕他们的电信资费,不像中国的移动那么贵! 人家从都不发短信,都用手机发Email,我估计是短信比通话贵吧. 难怪像电影里人家都带耳机,直接用手机当行动电话,和对讲机一样.)

有线电视:45美元(百分之一点五)
(这个嘛,中国似乎便宜点. 就算不用有线,自己接个锅也行. 但说回来了,毕竟人家很多电视台都已经数字化了,什么HDTV,数字点播,只是电视信号是无法满足的.)

汽油:35美元(占月收入百分之1点2)
根据美国劳工局《2006年消费者支出报告》,家庭平均年汽油支出为2227美元。
粗略按一家两辆车估算,单车月汽油支出应该在90美元。
所以36美元的数据可能是真的,但没有代表性。
( 不没那行头,无法考证. 猜想可能是家近吧,也可能是忙,不常有时间出去. 偶尔泡妞开开 )
汽车维修保养:因为宝马的新车在四年内是免费保养的,所以这方面免费。
洗车在家门口自己洗。 (老外有些事还是挺喜欢自己动手的)
水电煤气垃圾费:72美元(占月收入百分之2点4)
(和国内差距不大. 但建议他找个人同居,一个人灯也是要开,一锅饭做俩人的比俩人单独做还是省得. 这都是我爸熏陶我的)
吃:(占月收入百分之5点5)
早餐:吃煎鸡蛋,培根加牛奶麦片或者面包,水果(每月32美元)
(查了美国的鸡蛋一打12个是2$左右,每天吃4个才20$,至于面包,牛奶,在美国都是馒头价. 相对于工资比,他们的早餐就算很丰盛,也要比我们喝胡辣汤吃油条还便宜)

午餐:吃速食微波炉饭盒或者快餐(每月32美元)
(他们不太重视午餐,一般是应付一下,都攒劲晚上吃! 午餐吃饭时间一般也比我们晚)

晚餐:自己做,有时候到外面吃(每月100美元)
(看吧,晚餐费是午餐费的3倍多. 他们就算在家吃晚饭,一般也很丰盛. 谁给我说晚上吃多不好. 才发现我饮食很西方化. 晚上一定要吃饱)

零用:300美元(占月收入百分之10)
(这个有点小布什吧? 他们很爱玩的,泡吧,蹦迪,送礼物,买CD,DVD什么的,还都是正版的. 一般欧美家庭都是两周或一个月回去超市采购一次,都是大包小包装满一推车. 也可能这家伙是在软件公司上班,和我一样没时间玩)

存:639美元(占月收入百分之21),看完之后再算算你自己吧。。。
(这个比例的存款结余在美国已经算很高了. 我看网上公布的前几年的美国收入平均储蓄率只有10%,很多年轻人,特别是刚毕业的银行储蓄率都是负数,就是只有贷款,没有存款.)
不过该位仁兄的两个大数:月收入(3000美元)和消费占收入比例(79%),到都完全符合2006年的美国平均数,所以不算离谱。 蓝色的都是我后来加注的,不是原文所带. 根据网上搜索说理解的个人解释,如有类似不实内容,请告知布什.

[END]
]]>

一个普通美国人的工资&账本

首先介绍一下本文主人公背景:一个普通的美国人,大学毕业后两年。男性。单身。

工作:在一个商业机构当业务代表。

工资:打税和交费以后三千美元/月。美国人打税包括联邦税,州税,社会安全税,州残疾人税,全国医疗保险税。交费有退休基金约百分之十,工会费,人寿保险费,医药保险费
(3000$是很正常的工资薪水,美国年收入3万$一下就是低薪了)

父母帮他出了头期款,贷款买了一所房子。独栋房子,三房,一个饭厅,一个客厅,一个半浴室,一个厨房连早餐间,一个车房,后花园;每月自己每月还房贷1000$,地税保险:300$ (地税保险? 开始看到我也没明白,网上查了一下,我理解的是这样的: “地税保险”应该是”地税”和”保险“两样. 在美国买房是连土地一起购买的,所以要缴纳土地税,保险应该是购买的房屋资产保险,查了下美国的房屋保险,很有趣,保很多,有兴趣看看 美国标准房主保险(Homeowners-3, HO-3))

他买了一辆宝马325i轿车,汽车贷款是:300美元(占月收入百分之十),汽车保险:100美元(占月收入百分之3)
(美国的车险好贵啊,也去查了下. 美国汽车保险
美国的车险赔付比国内好很多,不管是不是自己的责任,保险公司都会赔)

手机花费(包括月费和电话费在内,他每月白天要打600分钟左右的电话,幸好美国的手机晚上9点以后和星期六、星期天都是免费时间):45美元(带税)(百分之一点五)
(很羡慕他们的电信资费,不像中国的移动那么贵! 人家从都不发短信,都用手机发Email,我估计是短信比通话贵吧. 难怪像电影里人家都带耳机,直接用手机当行动电话,和对讲机一样.)

有线电视:45美元(百分之一点五)
(这个嘛,中国似乎便宜点. 就算不用有线,自己接个锅也行. 但说回来了,毕竟人家很多电视台都已经数字化了,什么HDTV,数字点播,只是电视信号是无法满足的.)

汽油:35美元(占月收入百分之1点2)
根据美国劳工局《2006年消费者支出报告》,家庭平均年汽油支出为2227美元。
粗略按一家两辆车估算,单车月汽油支出应该在90美元。
所以36美元的数据可能是真的,但没有代表性。
( 不没那行头,无法考证. 猜想可能是家近吧,也可能是忙,不常有时间出去. 偶尔泡妞开开 )
汽车维修保养:因为宝马的新车在四年内是免费保养的,所以这方面免费。
洗车在家门口自己洗。 (老外有些事还是挺喜欢自己动手的)
水电煤气垃圾费:72美元(占月收入百分之2点4)
(和国内差距不大. 但建议他找个人同居,一个人灯也是要开,一锅饭做俩人的比俩人单独做还是省得. 这都是我爸熏陶我的)
吃:(占月收入百分之5点5)
早餐:吃煎鸡蛋,培根加牛奶麦片或者面包,水果(每月32美元)
(查了美国的鸡蛋一打12个是2$左右,每天吃4个才20$,至于面包,牛奶,在美国都是馒头价. 相对于工资比,他们的早餐就算很丰盛,也要比我们喝胡辣汤吃油条还便宜)

午餐:吃速食微波炉饭盒或者快餐(每月32美元)
(他们不太重视午餐,一般是应付一下,都攒劲晚上吃! 午餐吃饭时间一般也比我们晚)

晚餐:自己做,有时候到外面吃(每月100美元)
(看吧,晚餐费是午餐费的3倍多. 他们就算在家吃晚饭,一般也很丰盛. 谁给我说晚上吃多不好. 才发现我饮食很西方化. 晚上一定要吃饱)

零用:300美元(占月收入百分之10)
(这个有点小布什吧? 他们很爱玩的,泡吧,蹦迪,送礼物,买CD,DVD什么的,还都是正版的. 一般欧美家庭都是两周或一个月回去超市采购一次,都是大包小包装满一推车. 也可能这家伙是在软件公司上班,和我一样没时间玩)

存:639美元(占月收入百分之21),看完之后再算算你自己吧。。。
(这个比例的存款结余在美国已经算很高了. 我看网上公布的前几年的美国收入平均储蓄率只有10%,很多年轻人,特别是刚毕业的银行储蓄率都是负数,就是只有贷款,没有存款.)
不过该位仁兄的两个大数:月收入(3000美元)和消费占收入比例(79%),到都完全符合2006年的美国平均数,所以不算离谱。 蓝色的都是我后来加注的,不是原文所带. 根据网上搜索说理解的个人解释,如有类似不实内容,请告知布什.

[END]
]]>

Just one day

第一幕 / Chapter 1 昨天下班时间比较正常,所以晚上回来挺早. 进门就看见两俩脏兮兮的兔! 时常被狗连咬带舔,毛都粘在了一起. 脚上还粘着自己的大便.
烧了些水,决定给兔兔洗个澡. 它们太脏了! 这俩兔孙没一点兔样! 用了半盆温水加,一把清扬洗发水. 洗好了一只,还算挺老实,比较配合.
看着圆圆的小兔,一下水变得给老鼠一个样.
拍了两张,没洗的和洗过的以作比较. 同样洗了第二只,小名黑嘴,嘴角边长一拙黑毛. 它最活跃. 洗澡也最不老实!
洗完半天不还干. 我直接拿吹风机给它俩吹了吹怕它俩感冒 我一直分不清它们公母. 不过正像《木兰辞》中说的:”雄兔脚扑朔,雌兔眼迷离,双兔傍地走,安能辩我是雄雌?”
这是一种境界. 能陪你生活就好,别管公母与丑美.
第二幕 / Chapter 2 晚上12点上床睡觉.
躺下就一直鼻塞,出气不顺,总觉得鼻腔里有点鼻涕什么的,可怎么使劲擤鼻涕都没什么东西出来.
我感冒或扁桃体发炎,想发烧时就总是这样,鼻炎造成的.
前几天同事都一个个感冒了,也该我出症状了. 晚上就感到头蒙,鼻塞,喉咙发毛,还有痰. 鼻子不通,大脑缺氧,头晕. 鼻子不通,失去嗅觉,抽烟都没味.
… … 不知不觉2点多了.
我很想赶快发个烧,可很久都不发烧了. 总是有症状却爆发不出来.
别人说,发烧是自身免疫力对抗病毒和细菌的一次过程,每次发烧机体免疫力将得到提高和修复.
人一年发烧一两次是很正常的.
就像杀毒软件需要更新病毒库,系统需要更新和打补丁一样,身体也需要更新和自我维护.
难怪小孩会经常发烧,因为他的免疫力需要一次次刺激才能成长,变得更强.
我却不发烧,至少很久,好多年没烧过了. 这样说来,显然我的免疫力在下降.
还总是这样,症状都有,可发烧烧不出来,这感觉很是难受.
我给同事发了短信,说我很不舒服,明天可能去不了. 至少现在还没睡,去也可能很晚了. 第三幕 / Chapter 3 一觉醒来,下午2点多了. 昨天应该是3点多睡着得.
继续躺着. 躺着头晕的感觉颇好! 就象喝上了二两. 4点起来泡碗方便米线吃. 特意放了许些姜丝进去,还多加了点醋. 还想加个鸡蛋,可又很懒不想弄.
吃完挺晚了,没去单位. 虽然已告诉过同事,但还是给同事发了短信确认一下,并告知有些工事的话让他帮下忙. 我爸喂了狗,我去喂兔子.
给兔子喂食时发现,其中一只不怎么吃. 一看有一只眼睛似乎感染了.
有些红肿,还有很多眼屎,粘连的几乎张不开眼.
应该怪我. 可能是昨天给它洗澡,洗发水进了眼睛发炎了. 5点多去了超市,发现兜里竟然只有5块钱了? 虽然我对钱概念不大,可量变还是很清楚的.
又去取了钱,买了些日用消耗品. 回来到杜岭街的药店买了一瓶青霉素眼药水,只要0.5元.
除了医院,我买药一般都在那买,因为那的老板同一种病,用的同一种药,他们从不推荐你贵的.
用最少的钱并且达到最好的效果,这才是医德.
还有就是自己买药,尽量买OTC标志的药,就是非处方药,一般不会有不良反应.而且价格都是受国家限制的,很廉价. 回去就给那兔它眼睛擦干净,小心用了药. 它眼睛能挣开了! 第三幕 / Chapter 3 晚上吃饭时,我爸问我你不是丢钱了? 我说不知道.
他又说丢钱没你自己都不知道? 我说没丢啊. 因为我都不知道我兜里有多少,只是不想和他吵.
他说:哦,不是你掉的钱都好. 我想:啊!?
他开始讲了,说我出门买东西,他也去买菜了,结果他兜里也就几块钱,又上楼拿钱.
在楼梯上还埋怨自己老了,脑子不够用啥的. 然后发现楼梯上的墙角有钱,还没有人捡.
说拿起来一看20! 然后就没回家直接去买了块肉. 还给我夸他对钱特别敏感,这个月都捡两次了.
要我看见我也敏感! 我很怀疑那钱是我掉的! 所以吃饭时,我就觉得盘里那肉就是我的!
落幕 / End 这就是我的日志,讲述我的一日.
从晚上讲到晚上.
这要不叫日志,我都没法了! 这就是我的生活,这只是一天.
It’s my life, Just one day!

[END]
]]>

检查代码是否存在整数操作安全漏洞

 

检查代码是否存在整数操作安全漏洞

发布日期 : 09/02/2004 | 更新日期 : 09/02/2004

Michael Howard
Secure Windows Initiative

摘要: Michael Howard 提出关于整数操作安全漏洞的问题,并且阐述可以用来保护自己应用程序的安全性计划。

很多年以前,很少有人听说过整数溢出攻击,但现在好像每隔几天它就会出现一种新的形式。下面的简短列表就是在最近几个月内发现的一些整数溢出的安全性错误:

在本月的专栏中,我将阐述这些错误是如何出现的,如何在代码中搜寻它们以及如何修复它们。

在进入到本文的正题之前,我非常高兴的宣布“Writing Secure Code”接收到了在 2003 年 4 月于 San Francisco 召开的 RSA Security Conference 的“Conference Award for Industry Innovation”。

现在,回到整数攻击问题吧!

我不想解释什么是整数,我假设您知道它们是什么,并且知道有两种类型(有符号和无符号),其中当值是负数时,有符号整数的高位设置为 1,这是对 2 求补算法的结果。您也知道整数大小各有不同,最常见的长度为 64 位、32 位、16 位和 8 位的整数。这就是我所说的关于整数的全部内容,对于本文而言,如果您知道这些知识就足够了。

有三种主要整数操作可以导致安全性漏洞:

  • 上溢和下溢

  • 有符号与无符号的错误

  • 截断

取决于它们自己的情况,这些问题可能不会产生安全性错误。但是,如果您的代码显示有一个或多个这样的问题,并且您的代码会操作内存,那么产生缓冲区溢出错误或应用程序故障的可能性就会增加。让我们仔细查看一下每一项。

上溢和下溢

快速看一下这段代码有什么问题?

bool func(size_t cbSize) {
   if (cbSize < 1024) {
      // we never deal with a string trailing null
      char *buf = new char[cbSize-1];
      memset(buf,0,cbSize-1);

      // do stuff

      delete [] buf;

      return true;
   } else {
      return false;
   }
}

代码是正确的,对吗?它验证 cbSize 不大于 1 KB,并且 new 或 malloc 应该始终正确地分配 1 KB,对吗?让我们忽略以下事实,new 或 malloc 的返回值应该在此时进行检查。同样,cbSize 不能为负数,因为它是 size_t。但是,如果 cbSize 是零,又会如何呢?查看一下分配缓冲区的代码,它从缓冲区大小请求中减去一。从零减去一会产生 size_t 变量,这是一个无符号的整数,其限制为 0xFFFFFFFF(假设为 32 位的值)或者 4 GB。您的应用程序只有结束了,或者更糟!

请看下面相似的问题:

bool func(char *s1, size_t len1,
          char *s2, size_t len2) {
   if (1 + len1 + len2 > 64)
      return false;

   // accommodate for the trailing null in the addition
   char *buf = (char*)malloc(len1+len2+1);
   if (buf) {
      StringCchCopy(buf,len1+len2,s1);
      StringCchCat(buf,len1+len2,s2);
   }

   // do other stuff with buf

   if (buf) free(buf);

   return true;
}

同样,代码看起来编写得很好;它检查数据大小,验证 malloc 是否成功,并且使用 safe 字符串处理函数 StringCchCopy 和 StringCchCat(您可以从 http://msdn.microsoft.com/library/en-us/dnsecure/html/strsafe.asp 阅读更多关于这些字符串处理函数的内容)。但是,这段代码可能会受到整数上溢的危害。如果 len1 是 64,len2 是 0xFFFFFFFF,又会如何呢?确定缓冲区大小的代码合法地将 1、64 和 0xFFFFFFFF 加在一起,由于加操作的限制,会产生 64。接下来,代码仅分配了 64 个字节,然后代码生成了一个长度为 64 个字节的新字符串,然后将 0xFFFFFFFFF 字节与该字符串相连。同样,应用程序将会结束,在某些情况下,如果利用精心设计的大小进行攻击,代码可能会受到可用缓冲区溢出攻击。

此处的另外一个教训就是,如果缓冲区大小计算不正确,_safe 字符串处理函数就不安全。

返回页首

JScript 溢出攻击

当使用乘法时也会出现相同类型的上溢错误,这发生在 Microsoft JScript 错误中。该错误仅表明它自己在使用 JScript 稀疏数组支持时会出现:

var arr = new Array();
arr[1] = 1;
arr[2] = 2;
arr[0x40000001] = 3;

在这个示例中,数组具有三个元素,且长度为 0x40000001(十进制为 1073741825)。但是,由于该示例使用稀疏数组,它只占用内存的三个元素的数组。

实现 JScript 自定义排序例程的 C++ 代码在堆上分配临时的缓冲区、将三个元素复制到临时缓冲区中、使用自定义函数排序临时缓冲区,然后将临时缓冲区的内容移动回数组中。下面是分配临时缓冲区的代码:

TemporaryBuffer = (Element *)malloc(ElementCount * sizeof(Element));

Element 是一个 20 字节的数据结构,用于保存数组项。看起来程序将尝试为临时缓冲区分配大约 20 GB。您可能认为由于大多数人的计算机上不会有 20 GB 的内存,分配尝试将会失败。那么,JScript 常规内存不足处理例程将会处理该问题。遗憾的是,并没有发生这样的情况。

当使用 32 位的整数算法时,由于结果 (0x0000000500000014) 太大无法保存在 32 位的值中,我们会受到一个整数上溢攻击:

0x40000001  *  0x00000014  =   0x0000000500000014

C++ 会丢弃所有不符合的位,因此我们会得到 0x00000014。这就是分配并未失败的原因 - 分配没有尝试去分配 20 GB,而是仅仅尝试分配了 20 个字节。然后,排序例程会假设缓冲区对于保存稀疏数组中的三个元素来说足够大,因此它将组成这三个元素的 60 个字节复制到了 20 个字节的缓冲区中,这样就溢出缓冲区 40 个字节。实在太冒险了!

返回页首

有符号与无符号错误

快速查看下面的代码。它类似于第一个示例。看看您是否能够发现错误,如果您发现了错误,请试着确定该错误会产生什么结果。

bool func(char *s1, int len1,
          char *s2, int len2) {

   char buf[128];

   if (1 + len1 + len2 > 128)
      return false;

   if (buf) {
      strncpy(buf,s1,len1);
      strncat(buf,s2,len2);
   }

   return true;
}

此处的问题在于字符串的大小存储为有符号的整数,因此只要 len2 是负值,len1 就可以大于 128,从而和就小于 128 个字节。但是,到 strncpy 的调用将会溢出 buf 缓冲区。

返回页首

截断错误

让我们查看最后一种攻击类型,通过代码示例,您来猜猜看。

bool func(byte *name, DWORD cbBuf) {
   unsigned short cbCalculatedBufSize = cbBuf;
   byte *buf = (byte*)malloc(cbCalculatedBufSize);
   if (buf) {
      memcpy(buf, name, cbBuf);
      // do stuff with buf
      if (buf) free(buf);
      return true;
   }

   return false;
}

这种攻击,至少这种结果,与前面阐述的 JScript 错误有一点类似。如果 cbBuf 是 0x00010020,又会如何呢?cbCalculatedBufSize 只有 0x20,因为只从 0x00010020 复制了低 16 位。因此,仅分配了 0x20 个字节,并且 0x00010020 字节复制到新分配的目标缓冲区中。请注意,使用 Microsoft Visual C++?/W4 选项编译这段代码会生成:

warning C4244: 'initializing' : conversion from 'DWORD' to 'unsigned
short', possible loss of data

请注意类似下面的操作不要标记为一个警告:

int len = 16;
memcpy(buf, szData, len);

memcpy 的最后一个参数是 size_t,而参数 len 是有符号的。不会发出警告是因为 memcpy 始终假设第三个参数是无符号的,转换成无符号不会改变函数的输出。

注意,如果您尝试为 DWORD 分配一个 size_t,您将会收到一个警告,并不是因为在 32 位平台上可能会出现数据丢失,而是因为在 64 位平台上将会出现数据丢失。

warning C4267: '=' : conversion from 'size_t' to 'DWORD', possible loss
of data

您将收到这个警告,因为所有默认 C++ 项目都使用 -Wp64 选项进行编译,该选项会通知编译器监视 64 位可移植性问题。

返回页首

托管代码中的整数操作问题

整数操作错误可能会发生在托管语言中,例如 C# 和 Visual Basic?.NET,但是潜在的损害会由于代码不直接访问内存而显著地降低。但是,调用本机代码(假设您的代码被授予调用非托管代码的权限)仍然可能会引起类似于上述的安全性问题。通用语言规范 (CLS) 中的整数是有符号的,一个错误就是当在非托管代码中将变量视为无符号的整数时,在托管代码中验证是否为有符号的整数参数。

这个特定的例子提出了一个更通用的建议:始终检查要传递到未托管代码的内容。托管代码中的很多整数操作错误可能会引起 Visual Basic .NET 中的可靠性错误,因为如果发生上溢或下溢,所有这样的操作都将引发 System.OverflowException。

默认情况下,C# 并不引发这些异常。如果您希望检查这些问题,请使用 checked 关键字:

UInt32 i = 0xFFFFFFF0;
UInt32 j = 0x00000100;
UInt32 k;
checked {k = i + j;}

返回页首

补救措施

谁会想到只是操作整数就会导致安全性问题呢?对于易受攻击的代码的简单的补救措施如下所示:

if (A + B > MAX) return -1;

利用无符号整数使用该代码:

if (A + B >= A && A + B < MAX) {
   // cool!
}

第一个操作 A + B >= A,检查是否存在包围,第二个操作确保相加后的和小于目标大小。

对于 JScript 中的操作问题,您可以检查元素的数量不超过预定的值,而预定的值要小于您将要分配给内存的最大量。例如,下面的代码会潜在地分配多达 64 MB 的内存:

const size_t MAX = 1024 * 1024 * 64;
const size_t ELEM_SIZE = sizeof(ELEMENT);
const size_t MAX_ELEMS = MAX / ELEM_SIZE;

if (cElems >= MAX_ELEMS)
   return false;

最后,对于数组索引、缓冲区大小以及相似对象,请使用无符号的整数,例如 DWORD 和 size_t。

返回页首

关键代码检查点

当编译或检查与整数相关的问题的代码时,请记住下列要点:

  • 使用最高的警告级别 /W4 来编译 C 和 C++ 代码。

  • 对于缓冲区大小和元素计数,使用 size_t 或 DWORD。没有任何理由要为这些结构使用有符号的值。

  • 请牢记,size_t 会根据您所使用的平台来表示不同的类型。size_t 是内存地址的大小,因此在 32 位平台上,它是 32 位的值,但在 64 位平台上,它就是 64 位的值。

  • 如果代码执行任意类型的整数操作(加、乘等等),其中结果用于索引到数组或计算缓冲区大小,请确保操作数位于一个小的、容易理解的范围内。

  • 警惕内存分配函数(newmallocGlobalAlloc 等等)的有符号参数,因为它们将被视为无符号的整数。

  • 注意产生 C4018、C4389 和 C4244 警告的操作。

  • 注意抛弃 C4018、C4389 和 C4244 警告的转换。

  • 调查禁用 C4018、C4389 和 C4244 警告的 #pragma warning(disable, Cnnnn) 的所有使用。实际上,将它们标记为注释、重新编译,然后检查与整数相关的所有新的警告。

  • 从其他平台或编译器迁移的代码可能会使用不同的数据大小。千万要小心!

  • 如果从托管代码调用非托管代码,请确保它的符号是正确的。Win32 API 的很多参数都是无符号的 int 或 DWORD,而很多托管代码变量则是有符号的。

  • 最后,如果您使用托管代码,请确保在适当的时候使用 catch OverflowExceptions

返回页首

发现安全漏洞

很多人检查出了我上个月的问题。它是一个整数上溢攻击。那么这段 C# 代码有什么问题呢?

string Status = "No";
string sqlstring ="";
try {
    SqlConnection sql= new SqlConnection(
        @"data source=localhost;" +
        "user id=sa;password=password;");
    sql.Open();
    sqlstring="SELECT HasShipped" +
        " FROM detail WHERE ID='" + Id + "'";
    SqlCommand cmd = new SqlCommand(sqlstring,sql);
    if ((int)cmd.ExecuteScalar() != 0)
        Status = "Yes";
} catch (SqlException se) {
    Status = sqlstring + " failednr";
    foreach (SqlError e in se.Errors) {
        Status += e.Message + "nr";
    }
} catch (Exception e) {
    Status = e.ToString();
}

检查代码是否存在整数操作安全漏洞