闂傚倸鍊搁崐鎼佸磹閹间礁纾归柟闂寸绾惧綊鏌熼梻瀵割槮缁惧墽鎳撻—鍐偓锝庝簼閹癸綁鏌i鐐搭棞闁靛棙甯掗~婵嬫晲閸涱剙顥氬┑掳鍊楁慨鐑藉磻閻愮儤鍋嬮柣妯荤湽閳ь兛绶氬鎾閻樻爠鍥ㄧ厱閻忕偛澧介悡顖氼熆鐟欏嫭绀€闁宠鍨块、娆戠磼閹惧墎绐楅梻浣告啞椤棝宕橀敐鍡欌偓娲倵楠炲灝鍔氭繛鑼█瀹曟垿骞橀懜闈涙瀭闂佸憡娲﹂崜娑⑺囬鐔虹瘈闁冲皝鍋撻柛鏇炵仛閻や礁螖閻橀潧浠滄俊顐g箓椤曪綁顢氶埀顒€鐣烽悡搴唵妞ゅ繋鐒﹀▍濠囨煙椤旂瓔娈滈柡浣瑰姈閹柨鈹戦崼婵嗘瘓闂佽娴烽幊鎾诲箟閿涘嫭宕查柛鏇ㄥ幗椤洟鏌熼悜妯诲鞍缂傚秴娲弻鏇熺箾閸喖濮㈤梺鑽ゅ枂閸斿矂鈥旈崘顔嘉ч幖绮光偓鑼嚬缂傚倷绶¢崰妤呭箰閹间焦鍋╅柣鎴f绾偓闂佺粯鍔曠粔鍫曞窗閺嶎厼绠栨繛鍡樻尭缁狅絾绻濋棃娑欐悙妞わ腹鏅犲娲箮閼恒儲鏆犻梺鎼炲妼濠€鍗炍i幇鏉跨閻庢稒锚椤庢挻绻濆▓鍨灍闁糕晛鐗婄粋宥呪攽鐎n亞鐤勯梺闈浥堥弲娑㈡倷婵犲洦鐓忓┑鐐茬仢閳ь剚顨堢划璇差潩椤掑瀵岄梺闈涚墕濡稒鏅堕鍕厽闁哄啯鍨垫晶鎾煟閹垮啫澧存い銏☆殜瀹曟帒螖閳ь剚绂嶆ィ鍐╁仭婵炲棗绻愰顏嗙棯閻愵剚鍊愰柡灞剧⊕閹棃鏁愰崱妯荤槗闁诲孩顔栭崳顕€宕戞繝鍥╁祦婵☆垵鍋愮壕鍏间繆椤栨粎甯涙い蹇曞枛濮婄粯鎷呴懞銉с€婇梺闈╃秶缁犳捇鐛箛娑欐櫢闁跨噦鎷�濠电姷鏁告慨鐑藉极閸涘﹥鍙忛柣鎴f閺嬩線鏌涘☉姗堟敾闁告瑥绻橀弻锝夊箣閿濆棭妫勯梺鍝勵儎缁舵岸寮婚悢鍏尖拻閻庨潧澹婂Σ顔剧磼閻愵剙鍔ゆい顓犲厴瀵鏁愭径濠勭杸濡炪倖甯婇悞锕傚磿閹惧墎纾藉ù锝呮惈灏忛梺鍛婎殕婵炲﹤顕f繝姘亜闁稿繐鐨烽幏濠氭煟鎼淬劍娑у鐟帮工鍗辨い鏂垮⒔绾捐棄霉閿濆懏鎯堥崯鎼佹⒑閸濄儱校闁绘濮撮锝嗙節濮橆儵鈺呮煃閸濆嫬鈧憡绂嶅⿰鍫熲拺闁告稑锕︾粻鎾绘倵濮橆剚鍤囧┑顔瑰亾闂侀潧鐗嗗Λ娑㈠储闁秵鈷戦梻鍫熻儐瑜版帒纾块梺顒€绉撮悞鍨亜閹哄棗浜惧┑鐘亾闂侇剙绉寸粻鏌ユ煏韫囨洖袥婵℃彃鐗撻弻鏇$疀閺囩倫銏ゆ煠閺夎法浠㈤柍瑙勫灴閸┿儵宕卞Δ鍐ф樊婵$偑鍊栧▔锕傚炊椤垶顥夐柣搴$畭閸庨亶藝娴兼潙鐓曢柟瀵稿Х绾惧ジ鎮楅敐搴′航闁稿簺鍎甸弻娑欐償閵忕姴顫庣紓浣介哺鐢偤骞忛悩璇茬闁圭儤鎸婚鎺戔攽閻樻鏆滅紒杈ㄦ礋瀵偆鎷犻懠顒佹闂佺粯姊婚埛鍫ュ极瀹ュ棙鍙忔俊顖氥仒閸氼偊鏌℃径瀣€愭慨濠勭帛閹峰懘宕妷锔锯偓顔尖攽閳╁啨浠犻柛鏂块叄楠炲繒鈧綆鍠栭拑鐔兼煏婢跺牆鍔ら柨娑欑洴濮婅櫣鎲撮崟顐ゎ槰濡炪倖娉﹂崶褏顦ㄩ梺閫炲苯澧撮柟顔煎槻楗即宕橀悙顑芥瀰闁诲孩顔栭崰妤呭箖閸屾凹鍤曟い鏇楀亾鐎规洖銈搁幃銏ゅ传閸曨偅杈堥梻鍌氬€烽懗鍓佸垝椤栨娲冀椤撶偟锛欓梺闈╁瘜閸樻悂宕戦幘鎰佹僵闁绘劦鍓欓锟�
开发学院软件开发Shell 防止缓冲区溢出杜绝如今最常见的程序缺陷 阅读

防止缓冲区溢出杜绝如今最常见的程序缺陷

 2009-06-30 03:47:00 来源:WEB开发网 闂傚倸鍊搁崐鎼佸磹閹间礁纾归柟闂寸绾惧綊鏌熼梻瀵割槮缁惧墽鎳撻—鍐偓锝庝簻椤掋垺銇勯幇顖毿撻柟渚垮妼椤粓宕卞Δ鈧獮濠勭磽閸屾艾鈧懓顫濋妸鈺佺疅缂佸顑欓崥瀣煕椤愵偅绶氱紓鍐╂礋濮婂宕掑▎鎴М濠电姭鍋撻梺顒€绉甸幆鐐哄箹濞n剙濡肩紒鎰殜閺屸€愁吋鎼粹€茬敖婵炴垶鎸哥粔鐢稿Φ閸曨垰鍐€妞ゆ劦婢€濞岊亪姊虹紒妯诲蔼闁稿海鏁诲濠氭晲婢跺﹤宓嗛梺缁樺姈缁佹挳宕戦幘璇叉嵍妞ゆ挻绋戞禍鐐叏濡厧浜鹃悗姘炬嫹闂傚倸鍊搁崐鎼佸磹閹间礁纾归柟闂寸绾惧綊鏌熼梻瀵割槮缁惧墽鎳撻—鍐偓锝庝簼閹癸綁鏌i鐐搭棞闁靛棙甯掗~婵嬫晲閸涱剙顥氬┑掳鍊楁慨鐑藉磻濞戔懞鍥偨缁嬫寧鐎梺鐟板⒔缁垶宕戦幇鐗堢厵缂備焦锚缁椦囨煃瑜滈崜锕傚矗閸愵煈娼栭柛婵嗗珔瑜斿畷鎯邦槾濞寸姴銈稿铏规嫚閼碱剛顔夐梺鐓庣秺缁犳牠骞冩ィ鍐╁€婚柦妯侯槼閹芥洟姊洪棃娑辨濠碘€虫喘瀹曘垽鎮介崨濞炬嫼闁荤喐鐟ョ€氱兘宕箛娑欑厱闁绘ê纾晶鐢告煏閸℃鈧湱缂撴禒瀣窛濠电姴瀚獮鍫ユ⒑绾懎顥嶉柟娲讳簽濡叉劙寮撮悢鍝勨叞闂傚倸鍊风欢姘缚瑜嶇叅闁靛牆娲犻崑鎾愁潩椤愩垹绁梺缁樹緱閸o綁鐛幒鎳虫棃鍩€椤掑倻涓嶉柨婵嗘缁♀偓闂傚倸鐗婄粙鎴﹀汲濞嗗緷鐟扳堪閸垻鏆梺鍝勭焿缂嶄焦鎱ㄩ埀顒勬煃閹増纭炬繝鈧潏銊х彾闁哄洨鍠撶弧鈧┑顔斤供閸橀箖宕㈤悽鍛娾拺缂備焦锚婵箓鏌涢幘鏉戝摵闁诡喗蓱濞煎繘濡搁妶鍥╃暰闂備礁婀辩划顖滄暜閻愬瓨娅犳繛鎴炴皑绾捐偐绱撴担璐細婵炴彃顕埀顒冾潐濞叉牕鐣烽鍐簷闂備礁鎲¢崝鏇㈠疮閻樿绀堟繝闈涚墛瀹曞弶绻涢幋鐐ㄧ細闁哄棗妫楅埞鎴︽偐鏉堫偄鍘¢梺杞扮劍閻楁粎妲愰幘瀛樺濞寸姴顑呴幗鐢告⒑閸︻厽鍤€婵炲眰鍊濋幃楣冩倻閽樺顔婇梺瑙勬儗閸樹粙宕撻悽鍛娾拺闁荤喐婢橀幃渚€鏌i幒鐐电暤闁诡喗顨婇獮鏍ㄦ媴閸忓瀚藉┑鐐舵彧缁插潡宕曢妶澶婂惞闁逞屽墴濮婃椽骞栭悙娴嬪亾閺嶎厽鍋嬮柣妯垮吹瀹撲線鐓崶銊р姇闁哄懏鎮傞弻銊╂偆閸屾稑顏�婵犵數濮烽弫鍛婃叏閻戣棄鏋侀柛娑橈攻閸欏繘鏌i幋锝嗩棄闁哄绶氶弻娑樷槈濮楀牊鏁鹃梺鍛婄懃缁绘垿濡甸崟顖氱闁告鍋熸禒鑲╃磽娴e搫顎岄柛銊ョ埣瀵鈽夐姀鐘电杸闂傚倸鐗婄粙鎺楁倶閸儲鍊甸柣鐔哄閸熺偟绱掔拠鎻掓殻濠碉紕鏁诲畷鐔碱敍濮橀硸鍟嬮梺璇查叄濞佳囧箺濠婂牊鍋╁┑鍌氭啞閳锋垹鐥鐐村婵炲吋鍔栫换娑㈡嚑椤掆偓閺嬪孩銇勯銏㈢缂佽鲸甯掕灒闁兼祴鏅滈崵宀勬⒒娓氣偓閳ь剛鍋涢懟顖涙櫠椤旇偐鏆嗛柨婵嗙墕閸斿灚銇勯敂鐣屽弨闁诡噯绻濇俊鑸靛緞鐎n剙甯鹃梻浣稿閸嬪懐鎹㈤崘顔肩;妞ゅ繐鎳愮粻鍓р偓鐟板閸犳洜鑺辨繝姘畾闁绘柨鍚嬮埛鎴︽倵閸︻厼校闁靛棗鍟撮弻銈夊礃閼碱剙鐓熼悗瑙勬礃缁诲牓寮崘顔肩劦妞ゆ帒瀚ч埀顒佹瀹曟﹢顢欓崲澹洦鐓曢柍鈺佸枤濞堟﹢鏌i悢绋垮婵﹥妞介幃鈩冩償閳╁啯鐦i梻浣虹帛閻楁洟濡剁粙璺ㄦ殾闁绘垶岣跨弧鈧梺鎼炲劀閸愩劎銈梻鍌欑窔濞佳勵殽韫囨洘顫曢柡鍥ュ灩閸屻劍銇勮箛鎾跺闁抽攱鍨块弻鐔兼嚃閳轰椒绮堕梺鍛婃⒐椤ㄥ﹪寮婚敓鐘插窛妞ゆ棃鏁慨鍥╃磽娴gǹ鈧湱鏁悢濡撳洨鈧潧鎽滅壕濂稿级閸稑濡肩紒妤佺缁绘盯鎮℃惔锝囶啋闂佺硶鏂侀崜婵嬪箯閸涘瓨鐓ラ悗锝呯仛缂嶆姊婚崒姘偓宄懊归崶褜娴栭柕濞炬櫆閸婂潡鏌ㄩ弴鐐测偓鍝ョ不閺屻儲鐓曢柕澶樺枛婢ь噣鏌$€b晝绐旈柡宀€鍠栧畷婊嗩槾閻㈩垱鐩弻锟犲川椤旇棄鈧劙鏌$仦璇插闁诡喓鍊濆畷鎺戔槈濮楀棔绱�闂傚倸鍊搁崐鎼佸磹閹间礁纾归柟闂寸绾惧綊鏌熼梻瀵割槮缁惧墽鎳撻—鍐偓锝庝簻椤掋垺銇勯幇顖毿撻柟渚垮妼椤粓宕卞Δ鈧獮濠勭磽閸屾艾鈧懓顫濋妸鈺佺疅缂佸顑欓崥瀣煕椤愵偅绶氱紓鍐╂礋濮婂宕掑▎鎴М濠电姭鍋撻梺顒€绉甸幆鐐哄箹濞n剙濡肩紒鎰殜閺屸€愁吋鎼粹€茬敖婵炴垶鎸哥粔鐢稿Φ閸曨垰鍐€妞ゆ劦婢€濞岊亪姊虹紒妯诲蔼闁稿海鏁诲濠氭晲婢跺﹤宓嗛梺缁樺姈缁佹挳宕戦幘璇叉嵍妞ゆ挻绋戞禍鐐叏濡厧浜鹃悗姘炬嫹  闂傚倸鍊搁崐鎼佸磹閹间礁纾归柟闂寸绾惧綊鏌熼梻瀵割槮缁炬儳缍婇弻锝夊箣閿濆憛鎾绘煕閵堝懎顏柡灞诲€濆畷顐﹀Ψ閿旇姤鐦庡┑鐐差嚟婵潧顫濋妸褎顫曢柟鎹愵嚙绾惧吋绻涢崱妯虹瑨闁告﹫绱曠槐鎾寸瑹閸パ勭彯闂佹悶鍔岄悥鍏间繆閹绢喖绀冩い鏃傚帶缁愭盯姊洪崫鍕垫Ч闁搞劌缍婂畷銏犆洪鍛偓鍨殽閻愯尙浠㈤柛鏃€纰嶉妵鍕晜鐠囪尙浠搁悗瑙勬穿缁绘繈鐛惔銊﹀殟闁靛/鍐ㄥ闂傚倸饪撮崑鍕洪敃鈧叅闁哄秲鍔庢晶锟犳⒒閸屾瑦绁版い鏇嗗應鍋撻崹顐㈡诞鐎规洘绮撻幃銏$附婢跺绋侀梻浣瑰劤缁绘劕锕㈡潏鈺侇棜闁稿繘妫跨换鍡樸亜閺嶃劎顣查柟顖氱墛閵囧嫰顢曢姀鈶裤垺銇勯鍕殻濠碘€崇埣瀹曞崬螖閳ь剟锝炴惔銊︹拺闁告稑饪撮悞濂告煕閵夋垵鎳庡銊モ攽閻橆喖鐏辨繛澶嬬閻у矂姊虹紒妯荤叆闁告艾顑夐幃锟犲Ψ閳哄倸鈧敻鏌ㄥ┑鍡涱€楅柛妯绘尦閺屾稓鈧綆鍋呯亸鎵磼缂佹ḿ绠撴い顐g箞椤㈡ê鈽夊▎蹇d紪闂備浇宕甸崰鎰垝鎼淬垺娅犳俊銈呭暞閺嗘粓鏌熼悜妯诲暗妞も晜褰冮湁闁绘挸娴烽幗鐘绘煟閹惧瓨绀嬮柡宀€鍠栭獮鍡氼檨闁搞倗鍠栭弻宥夋寠婢舵ɑ鈻堥梺鍝勮嫰缁夊墎妲愰幒鎳崇喖鎳¢妶鍛辈濠碉紕鍋戦崐銈夊磻閸涱垱宕查柛顐犲劚缁犵姵绻濇繝鍌涘櫣闁哄鐗婃穱濠囶敍濠垫劕娈銈呯箰缂嶅﹤顫忔繝姘<婵炲棙鍩堝Σ顕€姊虹涵鍜佸殝缂佽鲸娲滈崚鎺戔枎閹惧磭顓洪梺鎸庢煥閹碱偅绂嶆總鍛娾拺闁告繂瀚峰Σ褰掓煕閵娧冩灈鐎殿喗鎮傚顕€宕奸悢鍝勫箰闂備礁鎲¢崝褏寰婇懞銉ь洸闁告挆鍛紳婵炶揪缍€濞咃絿鏁☉姘辩<閻庯綆鍋呯亸鎵磼閸屾稑娴柡浣稿暣瀹曟帒顫濋幉瀣簥濠电姵顔栭崰妤呮晝閳哄懎绀堥柨鏇炲€归崐鐢告煙閹澘袚闁抽攱甯掗湁闁挎繂鎳忛幉鎼佹煥濞戞ḿ肖缂佽鲸甯¢、姘跺川椤撶姳妗撴俊銈囧Х閸嬬偤宕归崹顔炬殾闁割偅娲﹂弫鍡涙煕鐏炵偓鐨戦柕鍫畵濮婅櫣鎷犻幓鎺戞瘣缂傚倸绉村Λ娆戠矉瀹ュ鍐€妞ゆ挾鍋熼崫妤佺箾鐎电ǹ孝妞ゆ垵妫濋幃鈥斥枎閹剧补鎷哄銈嗘尪閸斿酣鎮鹃崡鐑嗙唵鐟滄粓宕归柆宥呂﹂柛鏇ㄥ灠濡﹢鏌涢…鎴濇灀闁稿鎸鹃幉鎾礋椤撴稒鏁靛┑鐘垫暩婵潙煤閿曞倸纾归梺鍨儍娴滄粓鐓崶銊﹀碍妞ゅ繈鍊濋弻娑氣偓锝庡亝瀹曞瞼鈧鍠栭埀顒傚櫏濡俱劌鈹戦悙鎻掓倯闁绘娲熼崺鐐哄箣閿旇棄浜归柣搴℃贡婵挳藟濠靛鈷戠紒瀣劵椤箓鏌涢弬鍧楀弰妤犵偛顦~銏犵暆閳ь剟鎮块埀顒€鈹戦悙鏉戠仸瀹€锝呮健閹潡宕ㄧ€涙ǚ鎷洪梺闈╁瘜閸欌偓婵$偓鎮傞弻娑㈡偐閹颁焦鐤侀悗娈垮枟閻擄繝鐛弽銊﹀闁革富鍘煎鎶芥⒒娴h櫣甯涙繛鍙夌墵瀹曟劙宕烽娑樹壕婵ḿ鍋撶€氾拷
核心提示:什么是缓冲区溢出?缓冲区以前可能被定义为“包含相同数据类型的实例的一个连续计算机内存块”,在 C 和 C++ 中,防止缓冲区溢出杜绝如今最常见的程序缺陷,缓冲区通常是使用数组和诸如 malloc() 和 new 这样的内存分配例程来实现的,极其常见的缓冲区种类是简单的字符数组,而一些最受欢迎的措施可分组为以下类别: 基

  什么是缓冲区溢出?
  缓冲区以前可能被定义为“包含相同数据类型的实例的一个连续计算机内存块”。在 C 和 C++ 中,缓冲区通常是使用数组和诸如 malloc() 和 new 这样的内存分配例程来实现的。极其常见的缓冲区种类是简单的字符数组。溢出 是指数据被添加到分配给该缓冲区的内存块之外。
  
  如果攻击者能够导致缓冲区溢出,那么它就能控制程序中的其他值。虽然存在许多利用缓冲区溢出的方法,不过最常见的方法还是“stack-smashing”攻击。Elias Levy (又名为 Aleph One)的一篇经典文章“Smashing the Stack for Fun and Profit”解释了 stack-smashing 攻击,Elias Levy 是 Bugtraq 邮件列表(请参阅 参考资料 以获得相关链接)的前任主持人。
  
  为了理解 stack-smashing 攻击(或其他任何缓冲区攻击)是如何进行的,您需要了解一些关于计算机在机器语言级实际如何工作的知识。在类 UNIX 系统上,每个进程都可以划分为三个主要区域:文本、数据和堆栈。文本区域 包括代码和只读数据,通常不能对它执行写入操作。数据区域 同时包括静态分配的内存(比如全局和静态数据)和动态分配的内存(通常称为 堆)。堆栈区域 用于允许函数/方法调用;它用于记录函数完成之后的返回位置,存储函数中使用的本地变量,向函数传递参数,以及从函数返回值。每当调用一个函数,就会使用一个新的 堆栈帧 来支持该调用。了解这些之后,让我们来考察一个简单的程序。
  
  清单 1. 一个简单的程序
  
  void function1(int a, int b, int c) {
    char buffer1[5];
    gets(buffer1); /* DON'T DO THIS */
  }
  
  void main() {
   function(1,2,3);
  }
  
  假设使用 gcc 来编译清单 1 中的简单程序,在 X86 上的 Linux 中运行,并且紧跟在对 gets()的调用之后中止。此时的内存内容看起来像什么样子呢?答案是它看起来类似图 1,其中展示了从左边的低位地址到右边的高位地址排序的内存布局。
  
  内存的底部    内存的顶部 
   buffer1 sfp ret a b c 
  <--- 增长 --- [ ] [ ] [ ] [ ] [ ] [ ] ... 
  堆栈的顶部    堆栈的底部 
  
  许多计算机处理器,包括所有 x86 处理器,都支持从高位地址向低位地址“倒”增长堆栈。因此,每当一个函数调用另一个函数,更多的数据将被添加到左边(低位地址),直至系统的堆栈空间耗尽。在这个例子中,当 main() 调用 function1()时,它将 c 的值压入堆栈,然后压入 b 的值,最后压入 a 的值。之后它压入 return (ret)值,这个值在 function1()完成时告诉 function1() 返回到 main() 中的何处。它还把所谓的“已保存的帧指针(saved frame pointer,sfp)”记录到堆栈上;这并不是必须保存的内容,此处我们不需要理解它。在任何情况下,function1()在启动以后,它会为 buffer1()预留空间,这在图 1 中显示为具有一个低地址位置。
  
  现在假设攻击者发送了超过 buffer1() 所能处理的数据。接下来会发生什么情况呢?当然,C 和 C++ 程序员不会自动检查这个问题,因此除非程序员明确地阻止它,否则下一个值将进入内存中的“下一个”位置。那意味着攻击者能够改写 sfp(即已保存的帧指针),然后改写 ret(返回地址)。之后,当 function1() 完成时,它将“返回”—— 不过不是返回到 main(),而是返回到攻击者想要运行的任何代码。
  
  通常攻击者会使用它想要运行的恶意代码来使缓冲区溢出,然后攻击者会更改返回值以指向它们已发送的恶意代码。这意味着攻击者本质上能够在一个操作中完成整个攻击!Aleph On 的文章(请参阅 参考资料)详细介绍了这样的攻击代码是如何创建的。例如,将一个 ASCII 0 字符压入缓冲区通常是很困难的,而该文介绍了攻击者一般如何能够解决这个问题。
  
  除了 smashing-stack 和更改返回地址外,还存在利用缓冲区溢出缺陷的其他途径。与改写返回地址不同,攻击者可以 smashing-stack(使堆栈上的缓冲区溢出),然后改写局部变量以利用缓冲区溢出缺陷。缓冲区根本就不必在堆栈上 —— 它可以是堆中动态分配的内存(也称为“malloc”或“new”区域),或者在某些静态分配的内存中(比如“global”或“static”内存)。基本上,如果攻击者能够溢出缓冲区的边界,麻烦或许就会找上你了。 然而,最危险的缓冲区溢出攻击就是 stack-smashing 攻击,因为如果程序对攻击者很脆弱,攻击者获得整个机器的控制权就特别容易。
  
  为什么缓冲区溢出如此常见?
  在几乎所有计算机语言中,不管是新的语言还是旧的语言,使缓冲区溢出的任何尝试通常都会被该语言本身自动检测并阻止(比如通过引发一个异常或根据需要给缓冲区添加更多空间)。但是有两种语言不是这样:C 和 C++ 语言。C 和 C++ 语言通常只是让额外的数据乱写到其余内存的任何位置,而这种情况可能被利用从而导致恐怖的结果。更糟糕的是,用 C 和 C++ 编写正确的代码来始终如一地处理缓冲区溢出则更为困难;很容易就会意外地导致缓冲区溢出。除了 C 和 C++ 使用得 非常 广泛外,上述这些可能都是不相关的事实;例如,Red Hat Linux 7.1 中 86% 的代码行都是用 C 或 C ++ 编写的。因此,大量的代码对这个问题都是脆弱的,因为实现语言无法保护代码避免这个问题。
  
  在 C 和 C++ 语言本身中,这个问题是不容易解决的。该问题基于 C 语言的根本设计决定(特别是 C 语言中指针和数组的处理方式)。由于 C++ 是最兼容的 C 语言超集,它也具有相同的问题。存在一些能防止这个问题的 C/C++ 兼容版本,但是它们存在极其严重的性能问题。而且一旦改变 C 语言来防止这个问题,它就不再是 C 语言了。许多语言(比如 Java 和 C#)在语法上类似 C,但它们实际上是不同的语言,将现有 C 或 C++ 程序改为使用那些语言是一项艰巨的任务。
  
  然而,其他语言的用户也不应该沾沾自喜。有些语言存在允许缓冲区溢出发生的“转义”子句。Ada 一般会检测和防止缓冲区溢出(即针对这样的尝试引发一个异常),但是不同的程序可能会禁用这个特性。C# 一般会检测和防止缓冲区溢出,但是它允许程序员将某些例程定义为“不安全的”,而这样的代码 可能 会导致缓冲区溢出。因此如果您使用那些转义机制,就需要使用 C/C++ 程序所必须使用的相同种类的保护机制。许多语言都是用 C 语言来实现的(至少部分是用 C 语言来实现的 ),并且用任何语言编写的所有程序本质上都依赖用 C 或 C++ 编写的库。因此,所有程序都会继承那些问题,所以了解这些问题是很重要的。
  
  导致缓冲区溢出的常见 C 和 C++ 错误
  从根本上讲,在程序将数据读入或复制到缓冲区中的任何时候,它需要在复制 之前 检查是否有足够的空间。能够容易看出来的异常就不可能会发生 —— 但是程序通常会随时间而变更,从而使得不可能成为可能。
  
  遗憾的是,C 和 C++ 附带的大量危险函数(或普遍使用的库)甚至连这点(指检查空间)也无法做到。程序对这些函数的任何使用都是一个警告信号,因为除非慎重地使用它们,否则它们就会成为程序缺陷。您不需要记住这些函数的列表;我的真正目的是说明这个问题是多么普遍。这些函数包括 strcpy(3)、strcat(3)、sprintf(3)(及其同类 vsprintf(3))和 gets(3)。scanf()函数集(scanf(3)、fscanf(3)、sscanf(3)、vscanf(3)、vsscanf(3) 和 vfscanf(3))可能会导致问题,因为使用一个没有定义最大长度的格式是很容易的(当读取不受信任的输入时,使用格式“%s”总是一个错误)。
  
  其他危险的函数包括 realpath(3)、getopt(3)、getpass(3)、streadd(3)、strecpy(3) 和 strtrns(3)。 从理论上讲,snprintf()应该是相对安全的 —— 在现代 GNU/Linux 系统中的确是这样。但是非常老的 UNIX 和 Linux 系统没有实现 snprintf() 所应该实现的保护机制。
  
  Microsoft 的库中还有在相应平台上导致同类问题的其他函数(这些函数包括 wcscpy()、_tcscpy()、_mbscpy()、wcscat()、_tcscat()、_mbscat() 和 CopyMemory())。注意,如果使用 Microsoft 的 MultiByteToWideChar() 函数,还存在一个常见的危险错误 —— 该函数需要一个最大尺寸作为字符数目,但是程序员经常将该尺寸以字节计(更普遍的需要),结果导致缓冲区溢出缺陷。
  
  另一个问题是 C 和 C++ 对整数具有非常弱的类型检查,一般不会检测操作这些整数的问题。由于它们要求程序员手工做所有的问题检测工作,因此以某种可被利用的方式不正确地操作那些整数是很容易的。特别是,当您需要跟踪缓冲区长度或读取某个内容的长度时,通常就是这种情况。但是如果使用一个有符号的值来存储这个长度值会发生什么情况呢 —— 攻击者会使它“成为负值”,然后把该数据解释为一个实际上很大的正值吗?当数字值在不同的尺寸之间转换时,攻击者会利用这个操作吗?数值溢出可被利用吗? 有时处理整数的方式会导致程序缺陷。
  
  防止缓冲区溢出的新技术
  当然,要让程序员 不 犯常见错误是很难的,而让程序(以及程序员)改为使用另一种语言通常更为困难。那么为何不让底层系统自动保护程序避免这些问题呢?最起码,避免 stack-smashing 攻击是一件好事,因为 stack-smashing 攻击是特别容易做到的。
  
  一般来说,更改底层系统以避免常见的安全问题是一个极好的想法,我们在本文后面也会遇到这个主题。事实证明存在许多可用的防御措施,而一些最受欢迎的措施可分组为以下类别:
  
  基于探测方法(canary)的防御。这包括 StackGuard(由 Immunix 所使用)、ProPolice(由 OpenBSD 所使用)和 Microsoft 的 /GS 选项。
  
  非执行的堆栈防御。这包括 Solar D

Tags:防止 缓冲区 溢出

编辑录入:爽爽 [复制链接] [打 印]
[]
  • 好
  • 好的评价 如果觉得好,就请您
      0%(0)
  • 差
  • 差的评价 如果觉得差,就请您
      0%(0)
更多精彩
    赞助商链接

    热点阅读
      焦点图片
        最新推荐
          精彩阅读