﻿<?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++博客-xiaoguozi's Blog-随笔分类-Windows</title><link>http://www.cppblog.com/guojingjia2006/category/8042.html</link><description>Pay it forword - 我并不觉的自豪，我所尝试的事情都失败了······习惯原本生活的人不容易改变，就算现状很糟，他们也很难改变，在过程中，他们还是放弃了······他们一放弃，大家就都是输家······让爱传出去，很困难，也无法预料，人们需要更细心的观察别人，要随时注意才能保护别人，因为他们未必知道自己要什么·····</description><language>zh-cn</language><lastBuildDate>Thu, 21 Mar 2013 21:25:42 GMT</lastBuildDate><pubDate>Thu, 21 Mar 2013 21:25:42 GMT</pubDate><ttl>60</ttl><item><title>SEH异常处理学习总结 </title><link>http://www.cppblog.com/guojingjia2006/archive/2013/03/21/198679.html</link><dc:creator>小果子</dc:creator><author>小果子</author><pubDate>Thu, 21 Mar 2013 07:43:00 GMT</pubDate><guid>http://www.cppblog.com/guojingjia2006/archive/2013/03/21/198679.html</guid><wfw:comment>http://www.cppblog.com/guojingjia2006/comments/198679.html</wfw:comment><comments>http://www.cppblog.com/guojingjia2006/archive/2013/03/21/198679.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/guojingjia2006/comments/commentRss/198679.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/guojingjia2006/services/trackbacks/198679.html</trackback:ping><description><![CDATA[<div>前一段时间，在看异常处理一章内容的时候，发现这一部分还真的挺有尿水：）所以上网搜了一下有关内容，呦嗬，还挺丰富的。当然有些自己还是看不懂，现在就将这些宝贝拿出来跟大家共享一下。<br />首先我们看一下使用异常处理的几种情况：<br />A． 用来处理非致命的错误<br />B． 对API函数的参数合法性的检验（假设参数都是合法的，只有遇到异常的时候进行合法性检验）<br />C． 处理致命错误（退出时最好的选择，但是有的时候可以用异常处理函数在程序退出前释放资源，删除临时文件等，甚至可以详细记录产生异常的指令位置和环境）<br />D． 处理&#8220;计划内&#8221;的异常（我们可能更关心这种情况，因为可以做很多的手脚，哈哈）<br />接着我们看看Windows下异常处理的两种方式：1使用筛选器2&nbsp;SEH异常处理<br />一、 使用筛选器<br />因为这里我要重点关注的是SEH的处理方式，所以还是简单的提一下筛选器处理方式。筛选器异常处理是通过异常回调函数来指定程序处理异常。这种方式的回调函数必须是唯一的，设置新的回调函数后以前的将失效。适用于进程范围。看一下这个函数的定义<br />Invoke SetUnhandledExecpionFilter,offset_Handler<br />Mov lpPrevHandler,eax<br />(先到这里吧有些难受，明天接着来)<br />######题外话：想起&#8220;司令&#8221;的一句话，觉得挺有道理：明天不一定美好，但是更美好的明天一定会到来！祝福所有的朋友。######<br /><br />上午有会，什么也没有做，下午？还有会，我tm晕了，中午不睡觉了，不把事情做不完心里不踏实。<br />回调函数的格式：<br />_Handlerproc pExecptionInfo<br />看看pExecptionInfo这个指针参数指向的一个数据结构<br />EXCEPTION_POINTERS&nbsp;STRUCT&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pExceptionRecord&nbsp;&nbsp;DWORD&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;?&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ContextRecord&nbsp;&nbsp;&nbsp;&nbsp;DWORD&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;?&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;EXCEPTION_POINTERS&nbsp;ENDS<br />下面介绍&nbsp;EXCEPTION_RECORD和CONTEXT结构的定义:&nbsp;<br />&nbsp;&nbsp;<br />;//=====================&nbsp;以下是两个成员的详细结构=========================<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;EXCEPTION_RECORD&nbsp;STRUCT&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ExceptionCode&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DWORD&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;?&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;;//异常码&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ExceptionFlags&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DWORD&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;?&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;;//异常标志&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pExceptionRecord&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DWORD&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;?&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;;//指向另外一个EXCEPTION_RECORD的指针&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ExceptionAddress&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DWORD&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;?&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;;//异常发生的地址&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;NumberParameters&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DWORD&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;?&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;;//下面ExceptionInformation所含有的dword数目&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ExceptionInformation&nbsp;&nbsp;DWORD&nbsp;EXCEPTION_MAXIMUM_PARAMETERS&nbsp;dup(?)&nbsp;<br />&nbsp;&nbsp;&nbsp;EXCEPTION_RECORDENDS&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;;//EXCEPTION_MAXIMUM_PARAMETERS&nbsp;==15&nbsp;<br /><br />;//=============================具体解释================================<br /><br />ExceptionCode&nbsp;异常类型,SDK里面有很多类型,你可以在windows.inc里查找STATUS_来找到更多的异常类型,下面只给出hex值,具体标识定义请查阅windows.inc,你最可能遇到的几种类型如下:&nbsp;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;C0000005h----读写内存冲突&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;C0000094h----非法除0&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;C00000FDh----堆栈溢出或者说越界&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;80000001h----由Virtual&nbsp;Alloc建立起来的属性页冲突&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;C0000025h----不可持续异常,程序无法恢复执行,异常处理例程不应处理这个异&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;常&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;C0000026h----在异常处理过程中系统使用的代码,如果系统从某个例程莫名奇妙的返回,则出现此代码,&nbsp;如果RtlUnwind时没有Exception&nbsp;Record参数也同样会填入这个代码&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;80000003h----调试时因代码中int3中断&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;80000004h----处于被单步调试状态&nbsp;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;注:也可以自己定义异常代码,遵循如下规则:&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;____________________________________________________________________<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;位:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;31~30&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;29~28&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;27~16&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;15~0&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;____________________________________________________________________<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;含义:&nbsp;&nbsp;&nbsp;&nbsp;严重程度&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;29位&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;功能代码&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;异常代码&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;0==成功&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;0==Mcrosoft&nbsp;&nbsp;&nbsp;&nbsp;MICROSOFT定义&nbsp;&nbsp;用户定义&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;1==通知&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;1==客户&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;2==警告&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;28位&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;3==错误&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;被保留必须为0&nbsp;<br />ExceptionFlags&nbsp;异常标志&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;0----可修复异常&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;1----不可修复异常&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;2----正在展开,不要试图修复什么,需要的话,释放必要的资源&nbsp;<br />pExceptionRecord&nbsp;如果程序本身导致异常,指向那个异常结构&nbsp;<br />ExceptionAddress&nbsp;发生异常的eip地址&nbsp;<br />ExceptionInformation&nbsp;附加消息,在调用RaiseException可指定或者在异常号为C0000005h即内存异常时含义如下&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;第一个dword&nbsp;0==读冲突&nbsp;1==写冲突&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;第二个dword&nbsp;读写冲突地址&nbsp;<br />;//================================解释结束============================<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;off.&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CONTEXT&nbsp;STRUCT&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;;&nbsp;_&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ContextFlags&nbsp;&nbsp;DWORD&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;?&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;;&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;+0&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;iDr0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DWORD&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;?&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;;&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;+4&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;iDr1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DWORD&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;?&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;;&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;+8&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;iDr2&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DWORD&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;?&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;;&nbsp;&nbsp;&gt;调试寄存器&nbsp;&nbsp;+C&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;iDr3&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DWORD&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;?&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;;&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;+10&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;iDr6&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DWORD&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;?&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;;&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;+14&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;iDr7&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DWORD&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;?&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;;&nbsp;_|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;+18&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FloatSave&nbsp;&nbsp;&nbsp;&nbsp;FLOATING_SAVE_AREA&nbsp;&lt;&gt;&nbsp;&nbsp;;浮点寄存器区&nbsp;+1C~~~88h&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;regGs&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DWORD&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;?&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;;--|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;+8C&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;regFs&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DWORD&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;?&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;;&nbsp;&nbsp;|/段寄存器&nbsp;&nbsp;&nbsp;&nbsp;+90&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;regEs&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DWORD&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;?&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;;&nbsp;&nbsp;|/&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;+94&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;regDs&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DWORD&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;?&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;;--|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;+98&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;regEdi&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DWORD&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;?&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;;____________&nbsp;&nbsp;&nbsp;&nbsp;+9C&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;regEsi&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DWORD&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;?&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;通用&nbsp;&nbsp;+A0&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;regEbx&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DWORD&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;?&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;寄&nbsp;&nbsp;&nbsp;&nbsp;+A4&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;regEdx&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DWORD&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;?&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;存&nbsp;&nbsp;&nbsp;&nbsp;+A8&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;regEcx&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DWORD&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;?&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;器&nbsp;&nbsp;&nbsp;&nbsp;+AC&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;regEax&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DWORD&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;?&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;;_______|___组_&nbsp;&nbsp;+B0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;regEbp&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DWORD&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;?&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;;++++++++++++++++&nbsp;+B4&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;regEip&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DWORD&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;?&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;;&nbsp;&nbsp;&nbsp;&nbsp;|控制&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;+B8&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;regCs&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DWORD&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;?&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;;&nbsp;&nbsp;&nbsp;&nbsp;|寄存&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;+BC&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;regFlag&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DWORD&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;?&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;;&nbsp;&nbsp;&nbsp;&nbsp;|器组&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;+C0&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;regEsp&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DWORD&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;?&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;;&nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;+C4&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;regSs&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DWORD&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;?&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;;++++++++++++++++&nbsp;+C8&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ExtendedRegisters&nbsp;db&nbsp;MAXIMUM_SUPPORTED_EXTENSION&nbsp;dup(?)&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CONTEXT&nbsp;ENDS&nbsp;<br />;//============================以上是两个成员的详细结构============&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />程序使用筛选器异常处理时可以通过查看上面结构中的regEip来找到产生异常的地址！调试的时候可以改变EIP的值以达到越过异常程序，转到&#8220;安全&#8221;的地方。<br />最后看一下筛选器异常处理回调函数的返回值<br />EXECPTION_EXECUTE_HANDLER&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1；进程被终止，终止前不会出现提示错误的对话框<br />EXECPTION_CONTINUE_SEARCH 0；同样终止程序，显示错误对话框<br />EXECPTION_CONTINUE_EXECUTION -1；系统将CONTECT设置回去，继续执行程序<br /><br />使用筛选器程序是最简单的处理异常方法，不足：1&nbsp;不便于封装。2&nbsp;处理是全局性的也就是无法对每个线程或子程序设置一个私有的异常处理程序进行异常处理。<br />进入正题：SEH异常处理<br />首先解释一下什么是SEH异常处理：SEH("Structured&nbsp;Exception&nbsp;Handling"<img src="http://www.blogcn.com/images/wink.gif" alt="" border="0" hspace="2" vspace="2" />,即结构化异常处理.是操作系统提供给程序设计者的强有力的处理程序错误或异常的武器。<br />下面结合冷雨飘心的一个SEH异常处理程序来说明具体的用法：<br />;//====================================================================<br />;//&nbsp;ex.&nbsp;2,by&nbsp;Hume,2001&nbsp;&nbsp;线程相关的异常处理&nbsp;<br />;//====================================================================<br />.386&nbsp;<br />.model&nbsp;flat,&nbsp;stdcall&nbsp;<br />option&nbsp;casemap&nbsp;:none&nbsp;&nbsp;;&nbsp;case&nbsp;sensitive&nbsp;<br />include&nbsp;hd.h&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;;//相关的头文件，你自己维护一个吧&nbsp;<br />;//============================&nbsp;<br />.data&nbsp;<br />szCap&nbsp;&nbsp;&nbsp;&nbsp;db&nbsp;"By&nbsp;Hume[AfO],2001...",0&nbsp;<br />szMsgOK&nbsp;db&nbsp;"It's&nbsp;now&nbsp;in&nbsp;the&nbsp;Per_Thread&nbsp;handler!",0&nbsp;<br />szMsgERR1&nbsp;db&nbsp;"It&nbsp;would&nbsp;never&nbsp;Get&nbsp;here!",0&nbsp;<br />buff&nbsp;&nbsp;&nbsp;&nbsp;db&nbsp;200&nbsp;dup(0)&nbsp;<br /><br />.code&nbsp;<br />_start:&nbsp;<br />;//========prog&nbsp;begin====================&nbsp;<br />&nbsp;&nbsp;ASSUME&nbsp;FS:NOTHING&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;push&nbsp;&nbsp;&nbsp;&nbsp;offset&nbsp;perThread_Handler&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;push&nbsp;&nbsp;&nbsp;&nbsp;fs:[0]&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mov&nbsp;&nbsp;&nbsp;&nbsp;fs:[0],esp&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;;//建立SEH的基本ERR结构,如果不明白,就仔细研究一下吧&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;xor&nbsp;&nbsp;&nbsp;&nbsp;ecx,ecx&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mov&nbsp;&nbsp;&nbsp;&nbsp;eax,200&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cdq&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;；//双字扩展到四个字节，因为是除法<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;div&nbsp;&nbsp;&nbsp;&nbsp;ecx&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;;//以下永远不会被执行&nbsp;<br />&nbsp;invoke&nbsp;&nbsp;MessageBox,NULL,addr&nbsp;szMsgERR1,addr&nbsp;szCap,MB_OK+MB_ICONINFORMATION&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pop&nbsp;&nbsp;&nbsp;&nbsp;fs:[0]&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;add&nbsp;&nbsp;&nbsp;&nbsp;esp,4&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;invoke&nbsp;&nbsp;&nbsp;&nbsp;ExitProcess,NULL&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br /><br />;//============================&nbsp;<br />perThread_Handler:&nbsp;<br />&nbsp;invoke&nbsp;&nbsp;&nbsp;&nbsp;MessageBox,NULL,addr&nbsp;szMsgOK,addr&nbsp;szCap,MB_OK+MB_ICONINFORMATION&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mov&nbsp;&nbsp;&nbsp;&nbsp;eax,1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;;//ExceptionContinueSearch,不处理,由其他例程或系统处理&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;;mov&nbsp;&nbsp;&nbsp;&nbsp;eax,0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;;//ExceptionContinueExecution,表示已经修复CONTEXT,可从异常发生处继续执行&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;ret&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;;//这里如果返回0,你会陷入死循环,不断跳出对话框....&nbsp;<br /><br />;//=============================Prog&nbsp;Ends==============&nbsp;<br />end&nbsp;_start<br />程序本身很简单，注释也很详细。我们来看看是如何注册回调函数的<br />push&nbsp;&nbsp;&nbsp;&nbsp;offset&nbsp;perThread_Handler&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;push&nbsp;&nbsp;&nbsp;&nbsp;fs:[0]&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mov&nbsp;&nbsp;&nbsp;&nbsp;fs:[0],esp&nbsp;<br />仅仅三个语句就解决了~那么为什么要用fs这个段寄存器呢？这里又涉及一个重要的内容：TIB（Thread&nbsp;Information&nbsp;Block线程信息块）。我们来看看这个重要的数据结构（引用了《罗聪浅谈利用SEB实现反跟踪》的部分内容）<br />TEB(Thread&nbsp;Environment&nbsp;Block)&nbsp;在&nbsp;Windows&nbsp;9x&nbsp;系 列中被称为&nbsp;TIB(Thread&nbsp;Information&nbsp;Block)，它记录了线程的重要信息，而且每一个线程都会对应一个&nbsp;TEB&nbsp;结 构。&nbsp;Matt&nbsp;Pietrek&nbsp;大牛已经给我们列出了它的结构，我就不多说啦，见下：（摘 自&nbsp;Matt&nbsp;Pietrek&nbsp;的&nbsp;Under&nbsp;The&nbsp;Hood&nbsp;-&nbsp;MSJ&nbsp;1996）&nbsp;<br /><br />//===========================================================&nbsp;<br />//&nbsp;file:&nbsp;TIB.H&nbsp;<br />//&nbsp;Author:&nbsp;Matt&nbsp;Pietrek&nbsp;<br />//&nbsp;From:&nbsp;Microsoft&nbsp;Systems&nbsp;Journal&nbsp;"Under&nbsp;the&nbsp;Hood",&nbsp;May&nbsp;1996&nbsp;<br />//===========================================================&nbsp;<br />#pragma&nbsp;pack(1)&nbsp;<br /><br />typedef&nbsp;struct&nbsp;_EXCEPTION_REGISTRATION_RECORD&nbsp;<br />{&nbsp;<br />&nbsp;&nbsp;struct&nbsp;_EXCEPTION_REGISTRATION_RECORD&nbsp;*&nbsp;pNext;&nbsp;<br />&nbsp;&nbsp;FARPROC&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pfnHandler;&nbsp;<br />}&nbsp;EXCEPTION_REGISTRATION_RECORD,&nbsp;*PEXCEPTION_REGISTRATION_RECORD;&nbsp;<br /><br />typedef&nbsp;struct&nbsp;_TIB&nbsp;<br />{&nbsp;<br />PEXCEPTION_REGISTRATION_RECORD&nbsp;pvExcept;&nbsp;//&nbsp;00h&nbsp;Head&nbsp;of&nbsp;exception&nbsp;record&nbsp;list&nbsp;<br />PVOID&nbsp;&nbsp;pvStackUserTop;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;04h&nbsp;Top&nbsp;of&nbsp;user&nbsp;stack&nbsp;<br />PVOID&nbsp;&nbsp;pvStackUserBase;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;08h&nbsp;Base&nbsp;of&nbsp;user&nbsp;stack&nbsp;<br /><br />union&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;0Ch&nbsp;(NT/Win95&nbsp;differences)&nbsp;<br />{&nbsp;<br />&nbsp;&nbsp;struct&nbsp;&nbsp;//&nbsp;Win95&nbsp;fields&nbsp;<br />&nbsp;&nbsp;{&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;WORD&nbsp;&nbsp;&nbsp;&nbsp;pvTDB;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;0Ch&nbsp;TDB&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;WORD&nbsp;&nbsp;&nbsp;&nbsp;pvThunkSS;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;0Eh&nbsp;SS&nbsp;selector&nbsp;used&nbsp;for&nbsp;thunking&nbsp;to&nbsp;16&nbsp;bits&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DWORD&nbsp;&nbsp;unknown1;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;10h&nbsp;<br />&nbsp;&nbsp;}&nbsp;WIN95;&nbsp;<br /><br />&nbsp;&nbsp;struct&nbsp;&nbsp;//&nbsp;WinNT&nbsp;fields&nbsp;<br />&nbsp;&nbsp;{&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;PVOID&nbsp;SubSystemTib;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;0Ch&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ULONG&nbsp;FiberData;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;10h&nbsp;<br />&nbsp;&nbsp;}&nbsp;WINNT;&nbsp;<br />}&nbsp;TIB_UNION1;&nbsp;<br /><br />PVOID&nbsp;&nbsp;pvArbitrary;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;14h&nbsp;Available&nbsp;for&nbsp;application&nbsp;use&nbsp;<br />struct&nbsp;_tib&nbsp;*ptibSelf;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;18h&nbsp;Linear&nbsp;address&nbsp;of&nbsp;TIB&nbsp;structure&nbsp;<br /><br />union&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;1Ch&nbsp;(NT/Win95&nbsp;differences)&nbsp;<br />{&nbsp;<br />&nbsp;&nbsp;struct&nbsp;&nbsp;//&nbsp;Win95&nbsp;fields&nbsp;<br />&nbsp;&nbsp;{&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;WORD&nbsp;&nbsp;&nbsp;&nbsp;TIBFlags;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;1Ch&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;WORD&nbsp;&nbsp;&nbsp;&nbsp;Win16MutexCount;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;1Eh&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DWORD&nbsp;&nbsp;DebugContext;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;20h&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DWORD&nbsp;&nbsp;pCurrentPriority;&nbsp;&nbsp;//&nbsp;24h&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DWORD&nbsp;&nbsp;pvQueue;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;28h&nbsp;Message&nbsp;Queue&nbsp;selector&nbsp;<br />&nbsp;&nbsp;}&nbsp;WIN95;&nbsp;<br /><br />&nbsp;&nbsp;struct&nbsp;&nbsp;//&nbsp;WinNT&nbsp;fields&nbsp;<br />&nbsp;&nbsp;{&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DWORD&nbsp;unknown1;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;1Ch&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DWORD&nbsp;processID;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;20h&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DWORD&nbsp;threadID;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;24h&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DWORD&nbsp;unknown2;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;28h&nbsp;<br />&nbsp;&nbsp;}&nbsp;WINNT;&nbsp;<br />}&nbsp;TIB_UNION2;&nbsp;<br /><br />PVOID*&nbsp;&nbsp;pvTLSArray;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;2Ch&nbsp;Thread&nbsp;Local&nbsp;Storage&nbsp;array&nbsp;<br /><br />union&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;30h&nbsp;(NT/Win95&nbsp;differences)&nbsp;<br />{&nbsp;<br />&nbsp;&nbsp;struct&nbsp;&nbsp;//&nbsp;Win95&nbsp;fields&nbsp;<br />&nbsp;&nbsp;{&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;PVOID*&nbsp;&nbsp;pProcess;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;30h&nbsp;Pointer&nbsp;to&nbsp;owning&nbsp;process&nbsp;database&nbsp;<br />&nbsp;&nbsp;}&nbsp;WIN95;&nbsp;<br />}&nbsp;TIB_UNION3;&nbsp;<br /><br />}&nbsp;TIB,&nbsp;*PTIB;&nbsp;<br />#pragma&nbsp;pack()<br />让我们抬头看看上面的&nbsp;Matt&nbsp;Pietrek&nbsp;的代码，其中有这么一行：&nbsp;<br /><br />PEXCEPTION_REGISTRATION_RECORD&nbsp;pvExcept;&nbsp;//&nbsp;00h&nbsp;Head&nbsp;of&nbsp;exception&nbsp;record&nbsp;list&nbsp;<br /><br />注 意到&nbsp;PEXCEPTION_REGISTRATION_RECORD&nbsp;这个定义，它表示&nbsp;pvExcept&nbsp;这个变量正 是&nbsp;exception&nbsp;record&nbsp;list&nbsp;的入口，这个入口位于整个结构的&nbsp;0&nbsp;偏移处。同时， 在&nbsp;M&nbsp;的&nbsp;Intel&nbsp;i386&nbsp;Windows&nbsp;NT/2K/XP&nbsp;内核中，每当创建一个线程，OS&nbsp;均会为每个线程分配&nbsp;TEB&nbsp;，而 且&nbsp;TEB&nbsp;永远放在&nbsp;fs&nbsp;段选择器指定的数据段的&nbsp;0&nbsp;偏移处。&nbsp;<br />这样一来，你就明白了&nbsp;SEH&nbsp;注册的偏移为什么是在&nbsp;fs:[0]&nbsp;了吧？&nbsp;<br />事实上&nbsp;Windows&nbsp;系统都是通过这种方法来为应用程序提供信息的，比如有这样的例子：&nbsp;<br />struct&nbsp;_tib&nbsp;*ptibSelf;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;18h&nbsp;Linear&nbsp;address&nbsp;of&nbsp;TIB&nbsp;structure&nbsp;<br />DWORD&nbsp;threadID;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;24h&nbsp;<br /><br />Windows&nbsp;提供了一个&nbsp;API&nbsp;：GetCurrentThreadID()，它的内部工作原理其实是这样的：（利用了上面的这两个地址）&nbsp;<br /><br />mov&nbsp;eax,&nbsp;fs:[18h]&nbsp;&nbsp;&nbsp;&nbsp;;因为&nbsp;18h&nbsp;偏移处是&nbsp;TIB&nbsp;结构的线性偏移地址&nbsp;<br />mov&nbsp;eax,&nbsp;[eax&nbsp;+&nbsp;24h]&nbsp;;因为&nbsp;24h&nbsp;偏移处是&nbsp;threadID&nbsp;的地址&nbsp;<br />ret&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;;把&nbsp;eax&nbsp;中储存的&nbsp;threadID&nbsp;地址返回<br />注：为什么要声明assume&nbsp;fs:nothing?因为masm编译器默认将fs段寄存器定义为error，所以程序在使用fs前必须将它启动！<br />接下来看看SEH的回调函数<br />_Handler proc&nbsp;_lpExecptionRecord,&nbsp;_lpSEH,lp_context,lp_DispatcherContext<br />&nbsp;<br />_lpExecptionRecord指向一个EXECPTION_RECORD结构。<br />lp_context&nbsp;指向一个CONTEXT结构。<br />_lpSEH&nbsp;&nbsp;指向注册回调函数时使用的EXXCEPTION_REGISTRATION结构的地址。<br />返回值有四种取值：<br />ExecptionContinueExecution&nbsp;(&nbsp;0&nbsp;<img src="http://www.blogcn.com/images/wink.gif" alt="" border="0" hspace="2" vspace="2" />：系统将线程环境设置为_lpContext指向的CONTEXT结构并继续执行。<br />ExceptionContinueSearch（1）：回调函数拒绝处理这个异常，系统通过EXECPTION_REGISTRATION结构的prev字段得到前一个回调函数的地址并调用它。<br />ExecptionNestedExecption&nbsp;（2）：发生异常嵌套。<br />ExecptionCollidedUnwind&nbsp;&nbsp;（3）：异常展开操作。这一个部分不做多讲，有兴趣的可以看看罗云彬的书，其实是很重要的一部分。<br />如果一个程序既有筛选器异常处理又有SEH异常处理，而且系统还有默认的异常处理机制，那么他们被调用的先后次序是怎么样的呢？<br />发生异常时系统的处理顺序(by&nbsp;Jeremy&nbsp;Gordon):&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;1.系统首先判断异常是否应发送给目标程序的异常处理例程,如果决定应该发送,并且目标程序正在被调试,则系统挂起程序并向调试器发送EXCEPTION_DEBUG_EVENT消息.呵呵,这不是正好可以用来探测调试器的存在吗?&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;2.如果你的程序没有被调试或者调试器未能处理异常,系统就会继续查找你是否安装了线程相关的异常处理例程,如果你安装了线程相关的异常处理例程,系统就把异常发送给你的程序seh处理例程,交由其处理.<br />&nbsp;&nbsp;&nbsp;&nbsp;3.每个线程相关的异常处理例程可以处理或者不处理这个异常,如果他不处理并且安装了多个线程相关的异常处理例程,可交由链起来的其他例程处理.&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;4.如果这些例程均选择不处理异常,如果程序处于被调试状态,操作系统仍会再次挂起程序通知debugger.&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;5.如果程序未处于被调试状态或者debugger没有能够处理,并且你调用SetUnhandledExceptionFilter安装了最后异&nbsp;常处理例程的话,系统转向对它的调用.&nbsp;<br />6.如果你没有安装最后异常处理例程或者他没有处理这个异常,系统会调用默认的系统处理程序,通常显示一个对话框,&nbsp;你可以选择关闭或者最后将其附加到调试器上的调试按钮.如果没有调试器能被附加于其上或者调试器也处理不了,系统就调用ExitProcess终结程序.&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;7.不过在终结之前,系统仍然对发生异常的线程异常处理句柄来一次展开,这是线程异常处理例程最后清理的机会.<br /><br />说了这么多你也许会问SEH异常处理到底有什么用处呢？呵呵，且听小生慢慢道来~~~<br />第一道菜：病毒程序巧用SEH<br />这里简单的说一下如何利用SEH异常处理程序来躲避下毒软件的反病毒引擎。一个反病毒引擎在一个程序运行的时候会模拟程序的代码，当发现程序代码的疑点比较多的时候会报告成病毒。看看下面这段程序：<br />start:call&nbsp;Set_SEH;这句其实就是&nbsp;push&nbsp;offset&nbsp;CONTINUE<br />;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;JMP&nbsp;Set_SEH<br />CONTINUE:mov&nbsp;esp,&nbsp;[esp+8];&nbsp;[ESP+8]存储的是旧的堆栈地址。<br />push&nbsp;offset&nbsp;Start_Virus&nbsp;;----_&nbsp;把Start_Virus&nbsp;的地址压栈，当作返回地址<br />ret;----跳到Start_Virus去，是不是很magic?&nbsp;<br /><br />Set_SEH:sub&nbsp;edx,&nbsp;edx&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;;Edx&nbsp;=0&nbsp;<br />Assume&nbsp;fs:nothing&nbsp;<br />push&nbsp;dword&nbsp;ptr&nbsp;fs:[edx];把指去&nbsp;_EXCEPTIONAL_REGISTRATION_RECORD&nbsp;结构的指针入栈<br />mov&nbsp;fs:[edx],&nbsp;esp;安装一个seh<br />mov&nbsp;[edx],edx;引起一个内存读写冲突，发生异常因为edx=0&nbsp;<br />;如果反病毒引擎不处理异常，不进入seh&nbsp;处理程序(即&nbsp;CONTINUE:&nbsp;<img src="http://www.blogcn.com/images/wink.gif" alt="" border="0" hspace="2" vspace="2" />，继续模&nbsp;<br />;拟下个指令，也就是jmp&nbsp;start，那么就进入一个死循环，可能会引起死机。&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />jmp&nbsp;start&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />Start_Virus:&nbsp;&nbsp;&nbsp;&nbsp;.....<br />是不是很简单呢？就是让反病毒引擎不处理这个人为的异常时进入死循环~！！<br />第二道菜：TEB反跟踪初探<br />如果你的记性够好的话一定记得上面介绍过的TEB（TIB）线程信息块结构中有这么一句：<br />PVOID*&nbsp;&nbsp;pProcess;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;30h&nbsp;Pointer&nbsp;to&nbsp;owning&nbsp;process&nbsp;database&nbsp;<br />这 个偏移地址处的内容非常有用，它指向本线程的拥有者的&nbsp;PDB(Process&nbsp;Database)&nbsp;的线性地址。当你用动态调试器，例 如&nbsp;OllyDbg&nbsp;的时候，调试器是把调试的对象作为一个子线程进行跟踪的，在这种情况下，被调试的对象的&#8220;拥有者&#8221;就是调试器本身，也就是说，它 的&nbsp;TEB&nbsp;的&nbsp;30h&nbsp;处的偏移指向的内容肯定不为&nbsp;0&nbsp;，这样，我们就可以利用这一点，判断&nbsp;30h&nbsp;偏移指向的内容，来判断是否有调试器跟踪。&nbsp;<br />最后给出一个&nbsp;Anti-Debug&nbsp;的例子程序，用&nbsp;MASM&nbsp;编译完成后，请用&nbsp;OllyDbg&nbsp;来加载调试一下，看看与正常的运行结果有什么不同。&nbsp;<br />;*********************************************************&nbsp;<br />;程序名称：演示利用&nbsp;TEB&nbsp;结构进行&nbsp;Anti-Debug&nbsp;<br />;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;请用&nbsp;OllyDbg&nbsp;进行调试&nbsp;<br />;适用OS：Windows&nbsp;NT/2K/XP&nbsp;<br />;作者：罗聪&nbsp;<br />;日期：2003-2-9&nbsp;<br />;出处：<img alt="::URL::" src="http://www.blogcn.com/images/aurl.gif" align="absBottom" border="0" hspace="2" /><a href="http://www.luocong.com%EF%BC%88%E8%80%81%E7%BD%97%E7%9A%84%E7%BC%A4%E7%BA%B7%E5%A4%A9%E5%9C%B0%EF%BC%89/" target="_blank">http://www.LuoCong.com（老罗的缤纷天地）</a> &nbsp;<br />;注意事项：如欲转载，请保持本程序的完整，并注明：&nbsp;<br />;转载自&#8220;老罗的缤纷天地&#8221;（<img alt="::URL::" src="http://www.blogcn.com/images/aurl.gif" align="absBottom" border="0" hspace="2" /><a href="http://www.luocong.com%EF%BC%89/" target="_blank">http://www.LuoCong.com）</a> &nbsp;<br />;*********************************************************&nbsp;<br /><br />.386&nbsp;<br />.model&nbsp;flat,&nbsp;stdcall&nbsp;<br />option&nbsp;casemap:none&nbsp;<br /><br />include&nbsp;/masm32/include/windows.inc&nbsp;<br />include&nbsp;/masm32/include/kernel32.inc&nbsp;<br />include&nbsp;/masm32/include/user32.inc&nbsp;<br />includelib&nbsp;/masm32/lib/kernel32.lib&nbsp;<br />includelib&nbsp;/masm32/lib/user32.lib&nbsp;<br /><br />.data&nbsp;<br />szCaption&nbsp;&nbsp;db&nbsp;&nbsp;"Anti-Debug&nbsp;Demo&nbsp;by&nbsp;LC,&nbsp;2003-2-9",&nbsp;0&nbsp;<br />szDebugged&nbsp;&nbsp;db&nbsp;&nbsp;"Hah,&nbsp;let&nbsp;me&nbsp;guess...&nbsp;U&nbsp;r&nbsp;dEBUGGINg&nbsp;me!&nbsp;<img src="http://www.blogcn.com/images/smile.gif" alt="" border="0" hspace="2" vspace="2" />",&nbsp;0&nbsp;<br />szFine&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;db&nbsp;&nbsp;"Good&nbsp;boy,&nbsp;no&nbsp;dEBUGGEr&nbsp;detected!",&nbsp;0&nbsp;<br /><br />.code&nbsp;<br />main:&nbsp;<br />&nbsp;&nbsp;assume&nbsp;&nbsp;fs:nothing<br />&nbsp;&nbsp;mov&nbsp;&nbsp;&nbsp;&nbsp;eax,&nbsp;fs:[30h]&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;;指向&nbsp;PDB(Process&nbsp;Database)<br />&nbsp;&nbsp;movzx&nbsp;&nbsp;eax,&nbsp;byte&nbsp;ptr&nbsp;[eax&nbsp;+&nbsp;2h]；无符号数带零扩展<br />&nbsp;&nbsp;or&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;al,&nbsp;al<br />&nbsp;&nbsp;jz&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_Fine<br />_Debugged:<br />&nbsp;&nbsp;push&nbsp;&nbsp;&nbsp;&nbsp;MB_OK&nbsp;or&nbsp;MB_ICONHAND<br />&nbsp;&nbsp;push&nbsp;&nbsp;&nbsp;&nbsp;offset&nbsp;szCaption<br />&nbsp;&nbsp;push&nbsp;&nbsp;&nbsp;&nbsp;offset&nbsp;szDebugged<br />&nbsp;&nbsp;jmp&nbsp;&nbsp;&nbsp;&nbsp;_Output<br />_Fine:<br />&nbsp;&nbsp;push&nbsp;&nbsp;&nbsp;&nbsp;MB_OK&nbsp;or&nbsp;MB_ICONINformATION<br />&nbsp;&nbsp;push&nbsp;&nbsp;&nbsp;&nbsp;offset&nbsp;szCaption<br />&nbsp;&nbsp;push&nbsp;&nbsp;&nbsp;&nbsp;offset&nbsp;szFine<br />_Output:&nbsp;<br />&nbsp;&nbsp;push&nbsp;&nbsp;&nbsp;&nbsp;NULL<br />&nbsp;&nbsp;call&nbsp;&nbsp;&nbsp;&nbsp;MessageBoxA<br />&nbsp;&nbsp;invoke&nbsp;&nbsp;ExitProcess,&nbsp;0<br />&nbsp;end&nbsp;main<br />第三道菜：利用SEH执行shellcode<br />假设异常处理例程入口00401053,程序刚开始执行时esp是0012ffc4,以前的fs:[0]是0012ffe0<br />建立了TIB结构的第一个成员后堆栈的情况如下:<br /><br />&nbsp;&nbsp;内存低地址<br />&nbsp;&nbsp;<br />|&nbsp;E0&nbsp;|12ffbc(esp)<br />|&nbsp;FF&nbsp;|<br />|&nbsp;12&nbsp;|&nbsp;&nbsp;--ERR结构的第一个成员<br />|_00_|<br />|&nbsp;53&nbsp;|12ffc0<br />|&nbsp;10&nbsp;|<br />|&nbsp;40&nbsp;|&nbsp;&nbsp;--ERR结构的第二个成员<br />|&nbsp;00&nbsp;|<br /><br />&nbsp;&nbsp;内存高地址<br /><br />&nbsp;&nbsp;好了然后程序CALL一个函数,函数里面有一个局部变量并且在往其分配的空间中写入的数据时产生溢出.这时堆栈如下<br /><br />____<br />|&nbsp;&nbsp;&nbsp;&nbsp;|12f000&nbsp;局部变量分配的空间,并且向12ffc0方向溢出了.<br />|&nbsp;&nbsp;&nbsp;&nbsp;|<br />....<br />....<br />|_EBP|12ffb4&nbsp;函数中保存老的EBP<br />|&nbsp;xx&nbsp;|<br />|&nbsp;xx&nbsp;|<br />|&nbsp;xx&nbsp;|<br />|_EIP|12ffb8&nbsp;call函数时EIP进栈<br />|&nbsp;xx&nbsp;|<br />|&nbsp;xx&nbsp;|<br />|_xx_|<br />|&nbsp;E0&nbsp;|12ffbc(esp)&nbsp;&nbsp;&nbsp;{当SEH起作用的时候EBX刚好指向这个地址(也可说总是指向当前ERR结构)}<br />|&nbsp;FF&nbsp;|<br />|&nbsp;12&nbsp;|&nbsp;&nbsp;--ERR结构的第一个成员<br />|_00_|<br />|&nbsp;53&nbsp;|12ffc0<br />|&nbsp;10&nbsp;|<br />|&nbsp;40&nbsp;|&nbsp;&nbsp;--ERR结构的第二个成员<br />|_00_|<br />|&nbsp;&nbsp;&nbsp;&nbsp;|12ffc4<br />&nbsp;&nbsp;&nbsp;继 续看,假设溢出代码一直到了12ffc4,然后call的函数该返回了,因为保存的EIP被溢出代码代替所以程序出错(不会不出错吧?),这样ESH开始 起作用了(注:在这期间系统要执行一些操作,所以EBX才会指向当前ERR).这样一来程序就会跳到12ffc0里的地址去执行!而12ffc0里的东东 早已不是原来的00401053了.这样我们不就改变了程序的流向了么.12ffc0中该写入什么内容呢?应是内存中JMP&nbsp;EBX的代码的地址.这样跳 了3下后最终就会跳到12ffbc去执行.这个四字节可是宝贵的啊<img src="http://www.blogcn.com/images/smile.gif" alt="" border="0" hspace="2" vspace="2" />现在假设JMP&nbsp;EBX这个指令在内存中的地址是0x77e33f4d<br />那下具体看一下现在堆栈的情况:<br /><br />|&nbsp;EB&nbsp;|12ffbc(esp)&nbsp;&nbsp;&nbsp;{当ESH起作用的时候EBX刚好指向这个地址(也可说总是指向当前ERR结构)}<br />|&nbsp;06&nbsp;|<br />|&nbsp;90&nbsp;|&nbsp;&nbsp;--ERR结构的第一个成员,执行JMP&nbsp;EBX后就到这儿来执行了(EB&nbsp;06是短跳转JMP&nbsp;12FFC4的机器码)<br />|_90_|&nbsp;&nbsp;后面的90是nop空指令的机器码.<br />|&nbsp;4D&nbsp;|12ffc0<br />|&nbsp;3F&nbsp;|<br />|&nbsp;E3&nbsp;|&nbsp;&nbsp;--ERR结构的第二个成员,出错处理函数的入口地址(现在成了JMP&nbsp;EBX的地址)<br />|_77_|<br />|&nbsp;&nbsp;&nbsp;&nbsp;|12ffc4<br />....<br /><br />&nbsp;&nbsp;好现在来看看12ffc4里面有些什么代码.(简单的说这段代码的作用是计算真正的shellcode的起始地址,然后跳过去执行.<br /><br />低地址<br /><br />|&nbsp;&nbsp;&nbsp;&nbsp;|12f000(shellcode开始地址)<br />....<br />....<br />|&nbsp;81&nbsp;|12ffc4<br />|&nbsp;C3&nbsp;|&nbsp;&nbsp;add&nbsp;ebx,FFFFF03Ch(ebx=12ffc4,指令长度6,作用计算计算shellcode地址)<br />|&nbsp;3C&nbsp;|<br />|&nbsp;F0&nbsp;|<br />|&nbsp;FF&nbsp;|<br />|&nbsp;FF&nbsp;|<br />|&nbsp;FF&nbsp;|12ffca&nbsp;jmp&nbsp;ebx<br />|&nbsp;D3&nbsp;|&nbsp;&nbsp;<br /><br />高地址<br /><br />&nbsp;<br />测试程序<br /><br />-------------------------SEH.ASM------------------<br />.386<br />.model&nbsp;flat,stdcall<br />option&nbsp;casemap:none<br /><br />include&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;../include/user32.inc<br />includelib&nbsp;&nbsp;&nbsp;&nbsp;../lib/user32.lib<br />include&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;../include/kernel32.inc<br />includelib&nbsp;&nbsp;&nbsp;&nbsp;../lib/kernel32.lib<br /><br /><br /><br />.data<br />hello&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;db&nbsp;'利用一个读INI文件的API来演示WIN2000本地溢出',0<br />lpFileName&nbsp;&nbsp;&nbsp;&nbsp;db&nbsp;'./seh.ini',0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />lpAppName&nbsp;&nbsp;&nbsp;&nbsp;db&nbsp;'iam',0<br />lpKeyName&nbsp;&nbsp;&nbsp;&nbsp;db&nbsp;'czy',0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />lpDefault&nbsp;&nbsp;&nbsp;&nbsp;db&nbsp;'ddd',0<br />szCap&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;db&nbsp;"SEH&nbsp;TEST",0<br />szMsgOK&nbsp;db&nbsp;"OK,the&nbsp;exceptoin&nbsp;was&nbsp;handled&nbsp;by&nbsp;final&nbsp;handler!",0<br />szMsgERR1&nbsp;db&nbsp;"It&nbsp;would&nbsp;never&nbsp;Get&nbsp;here!",0<br /><br />.code<br /><br />testov&nbsp;&nbsp;&nbsp;&nbsp;proc<br />&nbsp;&nbsp;&nbsp;&nbsp;local&nbsp;&nbsp;&nbsp;lpReturnedString[2224]&nbsp;:&nbsp;byte&nbsp;&nbsp;&nbsp;&nbsp;;返回的字串搞成本地变量这样就和C语言一样了,它是在栈中&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;invoke&nbsp;&nbsp;&nbsp;&nbsp;GetPrivateProfileString,offset&nbsp;&nbsp;&nbsp;&nbsp;lpAppName,offset，lpKeyName,offset&nbsp;lpDefault,ADDR&nbsp;lpReturnedString,2249,offset&nbsp;lpFileName&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;invoke&nbsp;&nbsp;&nbsp;&nbsp;MessageBox,0,addr&nbsp;lpReturnedString,addr&nbsp;lpReturnedString,1<br />&nbsp;&nbsp;&nbsp;&nbsp;ret&nbsp;<br />testov&nbsp;&nbsp;&nbsp;&nbsp;endp<br />&nbsp;&nbsp;&nbsp;&nbsp;<br />start:<br />&nbsp;&nbsp;&nbsp;&nbsp;ASSUME&nbsp;fs:NOTHING<br />&nbsp;&nbsp;&nbsp;&nbsp;invoke&nbsp;&nbsp;MessageBox,0,addr&nbsp;szMsgERR1,addr&nbsp;szCap,30h+1000h&nbsp;;下断点&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;push&nbsp;&nbsp;&nbsp;&nbsp;offset&nbsp;Final_Handler&nbsp;&nbsp;&nbsp;&nbsp;;压入正常的出错处理程序入口地址<br />&nbsp;&nbsp;&nbsp;&nbsp;push&nbsp;&nbsp;&nbsp;&nbsp;FS:[0]&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;;把前一个TIB的地址压入<br />&nbsp;&nbsp;&nbsp;&nbsp;mov&nbsp;&nbsp;&nbsp;&nbsp;fs:[0],esp<br />&nbsp;&nbsp;&nbsp;&nbsp;call&nbsp;&nbsp;&nbsp;&nbsp;testov&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;pop&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fs:[0]&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;;还原FS:[0]&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;<br />Final_Handler:&nbsp;&nbsp;&nbsp;;由于溢出了下面的代码不会被执行.<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;invoke&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;MessageBox,0,addr&nbsp;szMsgOK,addr&nbsp;szCap,30h<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;invoke&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ExitProcess,0<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mov&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;eax,1<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ret<br />end&nbsp;start<br /><br />-----------------end-------------<br /><br />1<img src="http://www.blogcn.com/images/smile.gif" alt="" border="0" hspace="2" vspace="2" />如何更好的在内存中找JMP&nbsp;EBX的代码:<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;在softice中执行S&nbsp;10:0&nbsp;L&nbsp;FFFFFFFF&nbsp;FF&nbsp;D3就可以了,但实际上这样找到的<br />地址可能不能执行代码.所以用下面的方法:<br />&nbsp;&nbsp;&nbsp;map32&nbsp;kernel32(在当前进程中查找映射的kernel32&nbsp;DLL的信息)&nbsp;&nbsp;&nbsp;<br />一般有如下显示:<br />&nbsp;&nbsp;Owner&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Obj&nbsp;Name&nbsp;&nbsp;&nbsp;&nbsp;Obj#&nbsp;&nbsp;&nbsp;&nbsp;Address&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Size&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TYPE<br />kernel32&nbsp;&nbsp;&nbsp;&nbsp;.text&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;0001&nbsp;&nbsp;&nbsp;&nbsp;001b:77b61000&nbsp;&nbsp;&nbsp;&nbsp;0005d1ae&nbsp;code&nbsp;RO<br />......<br />&nbsp;&nbsp;然后<br />S&nbsp;77b61000&nbsp;L&nbsp;5d1ae&nbsp;FF&nbsp;D3<br />如果显示如下说明找到了:<br />&nbsp;&nbsp;Pattern&nbsp;Found&nbsp;at&nbsp;0023:77e61674&nbsp;....<br /><br />2)关于缓冲区的大小的问题:<br />&nbsp;&nbsp;利用SEH的办法就起码要设成1000个字节多,你的shellcode才不会被不知哪来的数据覆盖!<br />这道菜czy做的不好吃：（我感觉理解起来有些困难~！因为关于缓冲区溢出自己接触的太少，不过好东西要保留的，以后回过头看！<br />第四道菜：用&nbsp;SEH&nbsp;技术实现&nbsp;API&nbsp;Hook<br />这一部分不想展开了，给大家一个链接吧。<br /><br /><img alt="::URL::" src="http://www.blogcn.com/images/aurl.gif" align="absBottom" border="0" hspace="2" /><a href="http://www.luocong.com/articles/show_article.asp?Article_ID=25" target="_blank">http://www.luocong.com/articles/show_article.asp?Article_ID=25</a> <br /><br />最后作为结束语说说的缺点吧：）一个人只有正视自己的缺点才能不断地进步！呵呵<br />在 SEH异常处理链中最后一个被装载的SEH异常处理程序总是被第一个调用，想想如果自己花了一个星期才写出来一个异常处理程序，能够完美处理所有异常,并 希望异常全部由你来处理,但很不幸,比如你调用了一个外部模块,而这个模块自己安装了一个ugly的seh处理例程,他的动作是只要有异常发生就简单地终 止程序，哈哈，那就死悄悄了。又比如你想在你的加壳程序里面加密目标程序代码段,然后发生无效指令异常的时候用你自己安装的处理句柄来解密代码段继续执 行,听起来这的确是一个好主意,但遗憾的是大多数C/C++代码都用_try{}_except{}块来保证其正确运行,而这些异常处理例程是在你壳注册 的例程之后安装的,因而也就在链的前面,无效指令一执行,首先是C/C++编译器本身提供的处理例程或者程序其他的异常处理例程来处理,可能简单结束程序 或者....<br />好累！~~~~~~<br />写了两天，错了，应该是剪接+消化了两天，有很多的程序和文字是从hume,老罗，还有czy那里&#8220;剽窃&#8221;的：）希望高手们不要生气~~天下书籍一大抄。你们的必将是我的，当然我的也会共享给你们的。呵呵，现在还不行，级别不够啊。</div>转自:<div>http://blog.csdn.net/toberooter/article/details/308365</div><img src ="http://www.cppblog.com/guojingjia2006/aggbug/198679.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/guojingjia2006/" target="_blank">小果子</a> 2013-03-21 15:43 <a href="http://www.cppblog.com/guojingjia2006/archive/2013/03/21/198679.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>WINDOWS 7 配置驱动开发环境（wdk7.60）</title><link>http://www.cppblog.com/guojingjia2006/archive/2011/03/19/142211.html</link><dc:creator>小果子</dc:creator><author>小果子</author><pubDate>Sat, 19 Mar 2011 08:48:00 GMT</pubDate><guid>http://www.cppblog.com/guojingjia2006/archive/2011/03/19/142211.html</guid><wfw:comment>http://www.cppblog.com/guojingjia2006/comments/142211.html</wfw:comment><comments>http://www.cppblog.com/guojingjia2006/archive/2011/03/19/142211.html#Feedback</comments><slash:comments>9</slash:comments><wfw:commentRss>http://www.cppblog.com/guojingjia2006/comments/commentRss/142211.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/guojingjia2006/services/trackbacks/142211.html</trackback:ping><description><![CDATA[<div class="postTitle">
<a href="http://www.cnblogs.com/korykim/archive/2011/02/01/1948771.html" id="homepage1_HomePageDays_DaysList_DayItem_0_DayList_0_TitleUrl_0" class="postTitle2"><br /></a>
</div>
<div class="postCon">
<p>1.&nbsp; 安装VS2010,WDK7.60（GRMWDK_EN_7600_1）</p>
<p>2.&nbsp; 新建VC 控制台项目(选择为空项目) </p>
<p><a href="http://images.cnblogs.com/cnblogs_com/korykim/201102/201102011957215568.jpg"><img src="http://images.cnblogs.com/cnblogs_com/korykim/201102/201102011957245059.jpg" alt="1_thumb1" title="1_thumb1" style="background-image: none; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border: 0px none;" border="0" height="337" width="544" /></a></p>
<p>3.&nbsp; 新建项目配置&#8220;driver&#8221; ，点击下拉按钮-点击（配置管理器）</p>
<p><a href="http://images.cnblogs.com/cnblogs_com/korykim/201102/201102011957268289.jpg"><img src="http://images.cnblogs.com/cnblogs_com/korykim/201102/201102011957276752.jpg" alt="6_thumb5" title="6_thumb5" style="background-image: none; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border: 0px none;" border="0" height="140" width="311" /></a></p>
<p>输入名称（driver）点击确定就可以了，其他的不要动哦！</p>
<p><a href="http://images.cnblogs.com/cnblogs_com/korykim/201102/20110201195730670.jpg"><img src="http://images.cnblogs.com/cnblogs_com/korykim/201102/20110201195733934.jpg" alt="3_thumb3" title="3_thumb3" style="background-image: none; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border: 0px none;" border="0" height="355" width="511" /></a></p>
<p>完成后的效果！</p>
<p><a href="http://images.cnblogs.com/cnblogs_com/korykim/201102/201102011957395498.jpg"><img src="http://images.cnblogs.com/cnblogs_com/korykim/201102/201102011957509195.jpg" alt="2_thumb3" title="2_thumb3" style="background-image: none; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border: 0px none;" border="0" height="344" width="504" /></a></p>
<p>点击确定按钮之后呈现出来的画面</p>
<p><a href="http://images.cnblogs.com/cnblogs_com/korykim/201102/2011020119575382.jpg"><img src="http://images.cnblogs.com/cnblogs_com/korykim/201102/201102011957596216.jpg" alt="4_thumb6" title="4_thumb6" style="background-image: none; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border: 0px none;" border="0" height="277" width="490" /></a></p>
<p>鼠标右击新建的driver属性，会弹出以下窗口！</p>
<p><a href="http://images.cnblogs.com/cnblogs_com/korykim/201102/201102011958075405.jpg"><img src="http://images.cnblogs.com/cnblogs_com/korykim/201102/2011020119582255.jpg" alt="5_thumb1" title="5_thumb1" style="background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border: 0px none;" border="0" height="367" width="549" /></a>     <br />4.&nbsp; <span color="#0000ff" style="color: #0000ff;">设置VC++路径 </span></p>
<p>&lt;<span color="#9b00d3" style="color: #9b00d3;">我把wdk安装在E盘下</span>&gt;     <br />a.&nbsp; 配置可执行文件目录:E:\WinDDK\7600.16385.1\bin\x86;     <br />b.&nbsp; 配置包含目录：E:\WinDDK\7600.16385.1\inc\ddk&nbsp; <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; E:\WinDDK\7600.16385.1\inc\crt<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; E:\WinDDK\7600.16385.1\inc\api&nbsp;&nbsp; <br />c.&nbsp; 配置库目录:&nbsp;&nbsp;&nbsp; E:\WinDDK\7600.16385.1\lib\win7\i3865</p>
<p><span color="#f79646" style="color: #f79646;">&nbsp;</span></p>
<p><span color="#f79646" style="color: #f79646;">新建C/C++文件 不然无C/C++设置选项</span> </p>
<p>&lt;刚开始我们创建了一个空的项目所以项目里没有c++文件，现在要做的就是在空的项目-源文件-添加一个新建项c++文件&gt;</p>
<p> <span color="#0000ff" style="color: #0000ff;">常规&nbsp; <br /></span>目标文件扩展名：.sys&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //必选   </p>
<p>   <br /><span color="#0000ff" style="color: #0000ff;">6.&nbsp; 设置C/C++选项      <br /></span><span color="#0000ff" style="color: #0000ff;">常规选项卡</span>     <br />1 调试信息格式(C7 兼容(/Z7)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //可选     <br />2 警告等级&nbsp;&nbsp;&nbsp;&nbsp; （2 级(/W2)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //可选     <br />3 将警告视为错误&nbsp; (是(/wx)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //可选     <br />&nbsp; <br /><span color="#0000ff" style="color: #0000ff;">优化选项卡</span>     <br />优化(禁用/Od)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //可选     <br />&nbsp; <br /><span color="#0000ff" style="color: #0000ff;">预处理器</span>     <br />预处理器定义：WIN32=100;_X86_=1;WINVER=0x501;DBG=1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //必选     <br />&nbsp; <br /><span color="#0000ff" style="color: #0000ff;">代码生成      <br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 启用最小重新生成：否&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //可选&nbsp;&nbsp;&nbsp;&nbsp; </p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 基本运行时检查：默认值&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //可选    <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 运行时库：多线程调试(/MTd)&nbsp; 或&nbsp; 多线程(/MT)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //建议选<span color="#0000ff" style="color: #0000ff;"> &lt;本人选择的是多线程调试(/MTd)&gt;      <br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 缓冲区安全检查：否&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //可选     <br />&nbsp; (可避免出现&nbsp; LINK : error LNK2001:&nbsp; 无法解析外部符号&nbsp; __security_cookie)     <br /><span color="#0000ff" style="color: #0000ff;">高级      <br /></span>&nbsp;&nbsp;&nbsp;&nbsp; 调用约定&nbsp; __stdcall(/Gz)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //必选     <br />&nbsp; <br /><span color="#0000ff" style="color: #0000ff;">7.&nbsp; 链接器设置      <br /></span><span color="#0000ff" style="color: #0000ff;">常规</span>     <br />&nbsp;&nbsp;&nbsp;&nbsp; 启用增量链接：否(/INCREMENTAL:NO)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //建议 选上     <br />&nbsp;&nbsp;&nbsp;&nbsp; 忽略导入库：是&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 可选&nbsp; <br />&nbsp;&nbsp;&nbsp;&nbsp; ( 设置为此值时，必须在附加库目录中加： E:\WinDDK\7600.16385.1\lib\win7\i3865&nbsp; 这样项目就不会依赖 IDE 环境的设 置)&nbsp; </p>
<p>&nbsp;&nbsp;&nbsp;&nbsp; 如果否&nbsp; (&nbsp; 设置为此值时，将依赖&nbsp; IDE&nbsp; 的环境的相关设置&nbsp; )    <br />&nbsp; <br /><span color="#0000ff" style="color: #0000ff;">输入</span>     <br /><span color="#0000ff" style="color: #0000ff;">附加依赖项      <br /></span>ntoskrnl.lib;Hal.lib;wdm.lib;wdmsec.lib;wmilib.lib;ndis.lib;MSVCRT.LIB;LIBCMT.LIB&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //必选&nbsp;&nbsp;&nbsp; </p>
<p>//NT式驱动&nbsp; ntoskrnl.lib&nbsp;&nbsp;&nbsp; WDM式驱动&nbsp;&nbsp;&nbsp; wdm.lib    <br />( HalXXX 函数在Hal.lib， WmiXXX 函数在&nbsp; wmilib.lib&nbsp; ， NdisXXX函数在&nbsp; ndis.lib )     <br />(&nbsp; 必要时需要增加微软的标准库&nbsp; MSVCRT.LIB MSVCRTD.LIB(调试库) LIBCMT.LIBIBCMTD.LIB(调试库) )     <br />&nbsp; (&nbsp; 如果源码中有&nbsp; source&nbsp; 文件，那么该文件的&nbsp; TARGETLIBS&nbsp; 字段会列出该项 目需要的库&nbsp; )     </p>
<p>忽略所有默认库：&nbsp;&nbsp;&nbsp; 是 (/NODEFAULTLIB)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //必选&nbsp;&nbsp; </p>
<p><span color="#0000ff" style="color: #0000ff;">清单文件</span>：     <br />&nbsp; 启用用户账户控制（UAC）&nbsp;&nbsp; 否&nbsp; //必选&nbsp; </p>
<p>不然会出现&nbsp; &gt;LINK : fatal error LNK1295: &#8220;/MANIFESTUAC&#8221;与&#8220;/DRIVER&#8221;规范不兼容；链接时不使用&#8220;/MANIFESTUAC&#8221;&nbsp;&nbsp; <br />&nbsp; <br />&nbsp;&nbsp;&nbsp;&nbsp; <span color="#0000ff" style="color: #0000ff;">调试</span>：     <br />生成调试信息&nbsp; 是(/DEBUG)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //可选     <br />生成映像文件：是(/MAP)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //可选     <br />映像文件名：$(TargetDir)$(TargetName).map&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //可选     <br />&nbsp; <br />&nbsp;&nbsp;&nbsp; <span color="#0000ff" style="color: #0000ff;">系统(System)      <br /></span>&nbsp;&nbsp;&nbsp;&nbsp; 子系统:&nbsp; 控制台(/SUBSYSTEM:CONSOLE)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //必选     <br />&nbsp;&nbsp;&nbsp;&nbsp; 堆栈保留大小：4194304&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //可选     <br />&nbsp;&nbsp;&nbsp;&nbsp; 堆栈提交大小：&nbsp; 4096&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //可选     <br />&nbsp;&nbsp;&nbsp;&nbsp; 驱动程序:&nbsp;&nbsp;&nbsp; 驱动程序(/DRIVER)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //必选&nbsp;&nbsp; <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span color="#0000ff" style="color: #0000ff;">高级：</span>     <br />&nbsp;&nbsp;&nbsp; 入口点：DriverEntry&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //必选     <br />&nbsp;&nbsp;&nbsp; 随机基址:清空&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //<span color="#ff0000" style="color: #ff0000;">把框里的数据删掉。（yes也不是no也不是就是要一个干干净净的文本框）</span>&nbsp;&nbsp; //必选     <br />&nbsp;&nbsp;&nbsp; 不然会出现&nbsp; e:\xxx.sys : fatal error LNK1295:     <br />&#8220;/DYNAMICBASE&#8221;与&#8220;/DRIVER&#8221;规范不兼容；链接时不使用&#8220;/DYNAMICBASE&#8221; </p>
<p>   <br />&nbsp;&nbsp;&nbsp; 数据执行保护(DEP):&nbsp; 清空 //<span color="#ff0000" style="color: #ff0000;">把框里的数据删掉。（yes也不是no也不是就是要一个干干净净的文本框）</span> //必选&nbsp;&nbsp; <br />&nbsp;&nbsp;&nbsp;&nbsp; 不然会出现&nbsp; e:\xxx.sys : fatal error LNK1295:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />&#8220;/NXCOMPAT:NO&#8221;与&#8220;/DRIVER&#8221;规范不兼容；链接时不使用&#8220;/NXCOMPAT:NO&#8221;&nbsp;&nbsp;&nbsp; </p>
<p>&nbsp;</p>
<p>设置效应和：是(/RELEASE)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //可选    </p>
<p>基址：0x10000&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //建议选上&nbsp; <br />&nbsp;&nbsp;&nbsp; <br />&nbsp;<span color="#d16349" style="color: #d16349;">命令行：/SECTION:INIT,D /IGNORE:4078</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span color="#ff0000" style="color: #ff0000;">（建议不要写进去，会报错！）</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </p>
<p>最后给出一个超级简单的代码来测试一下我们配置的是否成功？？</p>
<p>#include "ntddk.h"</p>
<p>NTSTATUS    <br />DriverEntry(PDRIVER_OBJECT DriverObject,PUNICODE_STRING RegistryPath)     <br />{     <br />return STATUS_UNSUCCESSFUL;     <br />}</p>
<p>&nbsp;</p>
<p>如果没有报错那么恭喜你配置成功了！    </p>
</div><img src ="http://www.cppblog.com/guojingjia2006/aggbug/142211.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/guojingjia2006/" target="_blank">小果子</a> 2011-03-19 16:48 <a href="http://www.cppblog.com/guojingjia2006/archive/2011/03/19/142211.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>PE学习总结</title><link>http://www.cppblog.com/guojingjia2006/archive/2010/10/12/129621.html</link><dc:creator>小果子</dc:creator><author>小果子</author><pubDate>Tue, 12 Oct 2010 09:22:00 GMT</pubDate><guid>http://www.cppblog.com/guojingjia2006/archive/2010/10/12/129621.html</guid><wfw:comment>http://www.cppblog.com/guojingjia2006/comments/129621.html</wfw:comment><comments>http://www.cppblog.com/guojingjia2006/archive/2010/10/12/129621.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/guojingjia2006/comments/commentRss/129621.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/guojingjia2006/services/trackbacks/129621.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: Code highlighting produced by Actipro CodeHighlighter (freeware)http://www.CodeHighlighter.com/-->#include&nbsp;"windows.h"#include&nbsp;&lt;iostream&gt;using&nbsp;namespace&nbsp;std;#define&nbsp;NTSI...&nbsp;&nbsp;<a href='http://www.cppblog.com/guojingjia2006/archive/2010/10/12/129621.html'>阅读全文</a><img src ="http://www.cppblog.com/guojingjia2006/aggbug/129621.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/guojingjia2006/" target="_blank">小果子</a> 2010-10-12 17:22 <a href="http://www.cppblog.com/guojingjia2006/archive/2010/10/12/129621.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>PE文件格式(上)(转)</title><link>http://www.cppblog.com/guojingjia2006/archive/2010/10/12/129615.html</link><dc:creator>小果子</dc:creator><author>小果子</author><pubDate>Tue, 12 Oct 2010 08:38:00 GMT</pubDate><guid>http://www.cppblog.com/guojingjia2006/archive/2010/10/12/129615.html</guid><wfw:comment>http://www.cppblog.com/guojingjia2006/comments/129615.html</wfw:comment><comments>http://www.cppblog.com/guojingjia2006/archive/2010/10/12/129615.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/guojingjia2006/comments/commentRss/129615.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/guojingjia2006/services/trackbacks/129615.html</trackback:ping><description><![CDATA[<strong>摘要</strong> <br><br>　　 Windows NT
3.1引入了一种名为PE文件格式的新可执行文件格式。PE文件格式的规范包含在了MSDN的CD中（Specs and Strategy,
Specifications, Windows NT File Format Specifications），但是它非常之晦涩。 <br>　　 然而这一的文档并未提供足够的信息，所以开发者们无法很好地弄懂PE格式。本文旨在解决这一问题，它会对整个的PE文件格式作一个十分彻底的解释，另外，本文中还带有对所有必需结构的描述以及示范如何使用这些信息的源码示例。 <br>
为了获得PE文件中所包含的重要信息，我编写了一个名为PEFILE.DLL的动态链接库，本文中所有出现的源码示例亦均摘自于此。这个DLL和它的源代
码都作为PEFile示例程序的一部分包含在了CD中（译注：示例程序请在MSDN中寻找，本站恕不提供），你可以在你自己的应用程序中使用这个DLL；
同样，你亦可以依你所愿地使用并构建它的源码。在本文末尾，你会找到PEFILE.DLL的函数导出列表和一个如何使用它们的说明。我觉得你会发现这些函
数会让你从容应付PE文件格式的。 <br><br><strong>介绍</strong> <br><br>
Windows操作系统家族最近增加的Windows
NT为开发环境和应用程序本身带来了很大的改变，这之中一个最为重大的当属PE文件格式了。新的PE文件格式主要来自于UNIX操作系统所通用的COFF
规范，同时为了保证与旧版本MS-DOS及Windows操作系统的兼容，PE文件格式也保留了MS-DOS中那熟悉的MZ头部。 <br>　　 在本文之中，PE文件格式是以自顶而下的顺序解释的。在你从头开始研究文件内容的过程之中，本文会详细讨论PE文件的每一个组成部分。 <br>
许多单独的文件成分定义都来自于Microsoft Win32
SDK开发包中的WINNT.H文件，在这个文件中你会发现用来描述文件头部和数据目录等各种成分的结构类型定义。但是，在WINNT.H中缺少对PE文
件结构足够的定义，在这种情况下，我定义了自己的结构来存取文件数据。你会在PEFILE.DLL工程的PEFILE.H中找到这些结构的定义，整套的
PEFILE.H开发文件包含在PEFile示例程序之中。 <br>
本文配套的示例程序除了PEFILE.DLL示例代码之外，还有一个单独的Win32示例应用程序，名为EXEVIEW.EXE。创建这一示例目的有二：
首先，我需要测试PEFILE.DLL的函数，并且某些情况要求我同时查看多个文件；其次，很多解决PE文件格式的工作和直接观看数据有关。例如，要弄懂
导入地址名称表是如何构成的，我就得同时查看.idata段头部、导入映像数据目录、可选头部以及当前的.idata段实体，而EXEVIEW.EXE就
是查看这些信息的最佳示例。 <br>　　 闲话少叙，让我们开始吧。 <br><br><strong>PE文件结构 </strong><br><br>
PE文件格式被组织为一个线性的数据流，它由一个MS-DOS头部开始，接着是一个是模式的程序残余以及一个PE文件标志，这之后紧接着PE文件头和可选
头部。这些之后是所有的段头部，段头部之后跟随着所有的段实体。文件的结束处是一些其它的区域，其中是一些混杂的信息，包括重分配信息、符号表信息、行号
信息以及字串表数据。我将所有这些成分列于图1。<br><img  src="http://www.vckbase.com/document/journal/vckbase38/images/pe1.gif" height="413" width="104"><br><strong>图1.PE文件映像结构</strong> <br>
从MS-DOS文件头结构开始，我将按照PE文件格式各成分的出现顺序依次对其进行讨论，并且讨论的大部分是以示例代码为基础来示范如何获得文件的信息
的。所有的源码均摘自PEFILE.DLL模块的PEFILE.C文件。这些示例都利用了Windows
NT最酷的特色之一——内存映射文件，这一特色允许用户使用一个简单的指针来存取文件中所包含的数据，因此所有的示例都使用了内存映射文件来存取PE文件
中的数据。 <br>　　 注意：请查阅本文末尾关于如何使用PEFILE.DLL的那一段。 <br><br><strong>MS-DOS头部/实模式头部</strong> <br><br>
如上所述，PE文件格式的第一个组成部分是MS-DOS头部。在PE文件格式中，它并非一个新概念，因为它与MS-DOS
2.0以来就已有的MS-DOS头部是完全一样的。保留这个相同结构的最主要原因是，当你尝试在Windows 3.1以下或MS-DOS
2.0以上的系统下装载一个文件的时候，操作系统能够读取这个文件并明白它是和当前系统不相兼容的。换句话说，当你在MS-DOS
6.0下运行一个Windows NT可执行文件时，你会得到这样一条消息：&#8220;This program cannot be run in DOS
mode.&#8221;如果MS-DOS头部不是作为PE文件格式的第一部分的话，操作系统装载文件的时候就会失败，并提供一些完全没用的信息，例如：&#8220;The
name specified is not recognized as an internal or external command,
operable program or batch file.&#8221; <br>　　 MS-DOS头部占据了PE文件的头64个字节，描述它内容的结构如下：
<pre>//WINNT.H
typedef struct _IMAGE_DOS_HEADER { // DOS的.EXE头部
USHORT e_magic; // 魔术数字
USHORT e_cblp; // 文件最后页的字节数
USHORT e_cp; // 文件页数
USHORT e_crlc; // 重定义元素个数
USHORT e_cparhdr; // 头部尺寸，以段落为单位
USHORT e_minalloc; // 所需的最小附加段
USHORT e_maxalloc; // 所需的最大附加段
USHORT e_ss; // 初始的SS值（相对偏移量）
USHORT e_sp; // 初始的SP值
USHORT e_csum; // 校验和
USHORT e_ip; // 初始的IP值
USHORT e_cs; // 初始的CS值（相对偏移量）
USHORT e_lfarlc; // 重分配表文件地址
USHORT e_ovno; // 覆盖号
USHORT e_res[4]; // 保留字
USHORT e_oemid; // OEM标识符（相对e_oeminfo）
USHORT e_oeminfo; // OEM信息
USHORT e_res2[10]; // 保留字
LONG e_lfanew; // 新exe头部的文件地址
} IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;</pre>
第一个域e_magic，被称为魔术数字，它被用于表示一
个MS-DOS兼容的文件类型。所有MS-DOS兼容的可执行文件都将这个值设为0x5A4D，表示ASCII字符MZ。MS-DOS头部之所以有的时候
被称为MZ头部，就是这个缘故。还有许多其它的域对于MS-DOS操作系统来说都有用，但是对于Windows
NT来说，这个结构中只有一个有用的域——最后一个域e_lfnew，一个4字节的文件偏移量，PE文件头部就是由它定位的。对于Windows
NT的PE文件来说，PE文件头部是紧跟在MS-DOS头部和实模式程序残余之后的。 <br><br><strong>实模式残余程序</strong> <br><br>
实模式残余程序是一个在装载时能够被MS-DOS运行的实际程序。对于一个MS-DOS的可执行映像文件，应用程序就是从这里执行的。对于
Windows、OS/2、Windows
NT这些操作系统来说，MS-DOS残余程序就代替了主程序的位置被放在这里。这种残余程序通常什么也不做，而只是输出一行文本，例如：&#8220;This
program requires Microsoft Windows v3.1 or
greater.&#8221;当然，用户可以在此放入任何的残余程序，这就意味着你可能经常看到像这样的东西：&#8220;You can''t run a Windows
NT application on OS/2, it''s simply not possible.&#8221; <br>　　 当为Windows
3.1构建一个应用程序的时候，链接器将向你的可执行文件中链接一个名为WINSTUB.EXE的默认残余程序。你可以用一个基于MS-DOS的有效程序
取代WINSTUB，并且用STUB模块定义语句指示链接器，这样就能够取代链接器的默认行为。为Windows
NT开发的应用程序可以通过使用-STUB:链接器选项来实现。 <br><br><strong>PE文件头部与标志</strong> <br><br>　　 PE文件头部是由MS-DOS头部的e_lfanew域定位的，这个域只是给出了文件的偏移量，所以要确定PE头部的实际内存映射地址，就需要添加文件的内存映射基地址。例如，以下的宏是包含在PEFILE.H源文件之中的： <br>
<pre>//PEFILE.H
#define NTSIGNATURE(a) ((LPVOID)((BYTE *)a + \
((PIMAGE_DOS_HEADER)a)-&gt;e_lfanew))</pre>
在处理PE文件信息的时候，我发现文件之中有些位置需要经常查阅。既然这些位置仅仅是对文件的偏移量，那么用宏来实现这些定位就比较容易，因为它们较之函数有更好的表现。 <br>
请注意这个宏所获得的是PE文件标志，而并非PE文件头部的偏移量。那是由于自Windows与OS/2的可执行文件开始，.EXE文件都被赋予了目标操
作系统的标志。对于Windows
NT的PE文件格式而言，这一标志在PE文件头部结构之前。在Windows和OS/2的某些版本中，这一标志是文件头的第一个字。同样，对于PE文件格
式，Windows NT使用了一个DWORD值。 <br>
以上的宏返回了文件标志的偏移量，而不管它是哪种类型的可执行文件。所以，文件头部是在DWORD标志之后，还是在WORD标志处，是由这个标志是否
Windows NT文件标志所决定的。要解决这个问题，我编写了ImageFileType函数（如下），它返回了映像文件的类型： <br>
<pre>//PEFILE.C
DWORD WINAPI ImageFileType (LPVOID lpFile)
{
/* 首先出现的是DOS文件标志 */
if (*(USHORT *)lpFile == IMAGE_DOS_SIGNATURE)
{
/* 由DOS头部决定PE文件头部的位置 */
if (LOWORD (*(DWORD *)NTSIGNATURE (lpFile)) ==
IMAGE_OS2_SIGNATURE ||
LOWORD (*(DWORD *)NTSIGNATURE (lpFile)) ==
IMAGE_OS2_SIGNATURE_LE)
return (DWORD)LOWORD(*(DWORD *)NTSIGNATURE (lpFile));
else if (*(DWORD *)NTSIGNATURE (lpFile) ==
IMAGE_NT_SIGNATURE)
return IMAGE_NT_SIGNATURE;
else
return IMAGE_DOS_SIGNATURE;
}
else
/* 不明文件种类 */
return 0;
}
</pre>
以上列出的代码立即告诉了你NTSIGNATURE宏有多么有用。对于比较不同文件类型并且返回一个适当的文件种类来说，这个宏就会使这两件事变得非常简单。WINNT.H之中定义的四种不同文件类型有：
<pre>//WINNT.H
#define IMAGE_DOS_SIGNATURE 0x5A4D // MZ
#define IMAGE_OS2_SIGNATURE 0x454E // NE
#define IMAGE_OS2_SIGNATURE_LE 0x454C // LE
#define IMAGE_NT_SIGNATURE 0x00004550 // PE00
</pre>
首先，Windows的可执行文件类型没有出现在这一列表中，这一点看起来很奇怪。但是，在稍微研究一下之后，就能得到原因了：除了操作
系统版本规范的不同之外，Windows的可执行文件和OS/2的可执行文件实在没有什么区别。这两个操作系统拥有相同的可执行文件结构。 <br>　　 现在把我们的注意力转向Windows NT PE文件格式，我们会发现只要我们得到了文件标志的位置，PE文件之后就会有4个字节相跟随。下一个宏标识了PE文件的头部：
<pre>//PEFILE.C
#define PEFHDROFFSET(a) ((LPVOID)((BYTE *)a + \
((PIMAGE_DOS_HEADER)a)-&gt;e_lfanew + \
SIZE_OF_NT_SIGNATURE))
</pre>
这个宏与上一个宏的唯一不同是这个宏加入了一个常量SIZE_OF_NT_SIGNATURE。不幸的是，这个常量并未定义在WINNT.H之中，于是我将它定义在了PEFILE.H中，它是一个DWORD的大小。 <br>　　 既然我们知道了PE文件头的位置，那么就可以检查头部的数据了。我们只需要把这个位置赋值给一个结构，如下：
<pre>PIMAGE_FILE_HEADER pfh;
pfh = (PIMAGE_FILE_HEADER)PEFHDROFFSET(lpFile);</pre>
在这个例子中，lpFile表示一个指向可执行文件内存映像基地址的指针，这就显出了内存映射文件的好处：不需要执行文件的I/O，只需使用指针pfh就能存取文件中的信息。PE文件头结构被定义为：
<pre>//WINNT.H
typedef struct _IMAGE_FILE_HEADER {
USHORT Machine;
USHORT NumberOfSections;
ULONG TimeDateStamp;
ULONG PointerToSymbolTable;
ULONG NumberOfSymbols;
USHORT SizeOfOptionalHeader;
USHORT Characteristics;
} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;
#define IMAGE_SIZEOF_FILE_HEADER 20
</pre>
请注意这个文件头部的大小已经定义在这个包含文件之中了，这样一来，想要得到这个结构的大小就很方便了。但是我觉得对结构本身使用
sizeof运算符（译注：原文为&#8220;function&#8221;）更简单一些，因为这样的话我就不必记住这个常量的名字
IMAGE_SIZEOF_FILE_HEADER，而只需要记住结构IMAGE_FILE_HEADER的名字就可以了。另一方面，记住所有结构的名字
已经够有挑战性的了，尤其在是这些结构只有WINNT.H中才有的情况下。 <br>
PE文件中的信息基本上是一些高级信息，这些信息是被操作系统或者应用程序用来决定如何处理这个文件的。第一个域是用来表示这个可执行文件被构建的目标机
器种类，例如DEC(R) Alpha、MIPS R4000、Intel(R)
x86或一些其它处理器。系统使用这一信息来在读取这个文件的其它数据之前决定如何处理它。 <br>
Characteristics域表示了文件的一些特征。比如对于一个可执行文件而言，分离调试文件是如何操作的。调试器通常使用的方法是将调试信息从
PE文件中分离，并保存到一个调试文件（.DBG）中。要这么做的话，调试器需要了解是否要在一个单独的文件中寻找调试信息，以及这个文件是否已经将调试
信息分离了。我们可以通过深入可执行文件并寻找调试信息的方法来完成这一工作。要使调试器不在文件中查找的话，就需要用到
IMAGE_FILE_DEBUG_STRIPPED这个特征，它表示文件的调试信息是否已经被分离了。这样一来，调试器可以通过快速查看PE文件的头部
的方法来决定文件中是否存在着调试信息。 <br>　　 WINNT.H定义了若干其它表示文件头信息的标记，就和以上的例子差不多。我把研究这些标记的事情留给读者作为练习，由你们来看看它们是不是很有趣，这些标记位于WINNT.H中的IMAGE_FILE_HEADER结构之后。 <br>
PE文件头结构中另一个有用的入口是NumberOfSections域，它表示如果你要方便地提取文件信息的话，就需要了解多少个段——更明确一点来
说，有多少个段头部和多少个段实体。每一个段头部和段实体都在文件中连续地排列着，所以要决定段头部和段实体在哪里结束的话，段的数目是必需的。以下的函
数从PE文件头中提取了段的数目：
<pre>PEFILE.C
int WINAPI NumOfSections(LPVOID lpFile)
{
/* 文件头部中所表示出的段数目 */
return (int)((PIMAGE_FILE_HEADER)
PEFHDROFFSET (lpFile))-&gt;NumberOfSections);
}
</pre>
如你所见，PEFHDROFFSET以及其它宏用起来非常方便。<br><br><strong>PE可选头部</strong> <br><br>　　 PE可执行文件中接下来的224个字节组成了PE可选头部。虽然它的名字是&#8220;可选头部&#8221;，但是请确信：这个头部并非&#8220;可选&#8221;，而是&#8220;必需&#8221;的。OPTHDROFFSET宏可以获得指向可选头部的指针：
<pre>//PEFILE.H
#define OPTHDROFFSET(a) ((LPVOID)((BYTE *)a + \
((PIMAGE_DOS_HEADER)a)-&gt;e_lfanew + \
SIZE_OF_NT_SIGNATURE + \
sizeof(IMAGE_FILE_HEADER)))
</pre>
可选头部包含了很多关于可执行映像的重要信息，例如初始的堆栈大小、程序入口点的位置、首选基地址、操作系统版本、段对齐的信息等等。IMAGE_OPTIONAL_HEADER结构如下：
<pre>//WINNT.H
typedef struct _IMAGE_OPTIONAL_HEADER {
//
// 标准域
//
USHORT Magic;
UCHAR MajorLinkerVersion;
UCHAR MinorLinkerVersion;
ULONG SizeOfCode;
ULONG SizeOfInitializedData;
ULONG SizeOfUninitializedData;
ULONG AddressOfEntryPoint;
ULONG BaseOfCode;
ULONG BaseOfData;
//
// NT附加域
//
ULONG ImageBase;
ULONG SectionAlignment;
ULONG FileAlignment;
USHORT MajorOperatingSystemVersion;
USHORT MinorOperatingSystemVersion;
USHORT MajorImageVersion;
USHORT MinorImageVersion;
USHORT MajorSubsystemVersion;
USHORT MinorSubsystemVersion;
ULONG Reserved1;
ULONG SizeOfImage;
ULONG SizeOfHeaders;
ULONG CheckSum;
USHORT Subsystem;
USHORT DllCharacteristics;
ULONG SizeOfStackReserve;
ULONG SizeOfStackCommit;
ULONG SizeOfHeapReserve;
ULONG SizeOfHeapCommit;
ULONG LoaderFlags;
ULONG NumberOfRvaAndSizes;
IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
} IMAGE_OPTIONAL_HEADER, *PIMAGE_OPTIONAL_HEADER;
</pre>
如你所见，这个结构中所列出的域实在是冗长得过分。为了不让你对所有这些域感到厌烦，我会仅仅讨论有用的——就是说，对于探究PE文件格式而言有用的。 <br><br><strong>标准域</strong> <br><br>　　 首先，请注意这个结构被划分为&#8220;标准域&#8221;和&#8220;NT附加域&#8221;。所谓标准域，就是和UNIX可执行文件的COFF格式所公共的部分。虽然标准域保留了COFF中定义的名字，但是Windows NT仍然将它们用作了不同的目的——尽管换个名字更好一些。 <br>　　 &#183;Magic。我不知道这个域是干什么的，对于示例程序EXEVIEW.EXE示例程序而言，这个值是0x010B或267（译注：0x010B为.EXE，0x0107为ROM映像，这个信息我是从eXeScope上得来的）。 <br>　　 &#183;MajorLinkerVersion、MinorLinkerVersion。表示链接此映像的链接器版本。随Window NT build 438配套的Windows NT SDK包含的链接器版本是2.39（十六进制为2.27）。 <br>　　 &#183;SizeOfCode。可执行代码尺寸。 <br>　　 &#183;SizeOfInitializedData。已初始化的数据尺寸。 <br>　　 &#183;SizeOfUninitializedData。未初始化的数据尺寸。 <br>
&#183;AddressOfEntryPoint。在标准域中，AddressOfEntryPoint域是对PE文件格式来说最为有趣的了。这个域表示应用程
序入口点的位置。并且，对于系统黑客来说，这个位置就是导入地址表（IAT）的末尾。以下的函数示范了如何从可选头部获得Windows
NT可执行映像的入口点。
<pre>//PEFILE.C
LPVOID WINAPI GetModuleEntryPoint(LPVOID lpFile)
{
PIMAGE_OPTIONAL_HEADER poh;
poh = (PIMAGE_OPTIONAL_HEADER)OPTHDROFFSET(lpFile);
if (poh != NULL)
return (LPVOID)poh-&gt;AddressOfEntryPoint;
else
return NULL;
}
</pre>
&#183;BaseOfCode。已载入映像的代码（&#8220;.text&#8221;段）的相对偏移量。 <br>　　 &#183;BaseOfData。已载入映像的未初始化数据（&#8220;.bss&#8221;段）的相对偏移量。 <br><br><strong>Windows NT附加域</strong> <br><br>　　 添加到Windows NT PE文件格式中的附加域为Windows NT特定的进程行为提供了装载器的支持，以下为这些域的概述。 <br>　　 &#183;ImageBase。进程映像地址空间中的首选基地址。Windows NT的Microsoft Win32 SDK链接器将这个值默认设为0x00400000，但是你可以使用-BASE:linker开关改变这个值。 <br>　　 &#183;SectionAlignment。从ImageBase开始，每个段都被相继的装入进程的地址空间中。SectionAlignment则规定了装载时段能够占据的最小空间数量——就是说，段是关于SectionAlignment对齐的。 <br>　　 Windows NT虚拟内存管理器规定，段对齐不能少于页尺寸（当前的x86平台是4096字节），并且必须是成倍的页尺寸。4096字节是x86链接器的默认值，但是它可以通过-ALIGN: linker开关来设置。 <br>
&#183;FileAlignment。映像文件首先装载的最小的信息块间隔。例如，链接器将一个段实体（段的原始数据）加零扩展为文件中最接近的
FileAlignment边界。早先提及的2.39版链接器将映像文件以0x200字节的边界对齐，这个值可以被强制改为512到65535这么多。 <br>　　 &#183;MajorOperatingSystemVersion。表示Windows NT操作系统的主版本号；通常对Windows NT 1.0而言，这个值被设为1。 <br>　　 &#183;MinorOperatingSystemVersion。表示Windows NT操作系统的次版本号；通常对Windows NT 1.0而言，这个值被设为0。 <br>　　 &#183;MajorImageVersion。用来表示应用程序的主版本号；对于Microsoft Excel 4.0而言，这个值是4。 <br>　　 &#183;MinorImageVersion。用来表示应用程序的次版本号；对于Microsoft Excel 4.0而言，这个值是0。 <br>　　 &#183;MajorSubsystemVersion。表示Windows NT Win32子系统的主版本号；通常对于Windows NT 3.10而言，这个值被设为3。 <br>　　 &#183;MinorSubsystemVersion。表示Windows NT Win32子系统的次版本号；通常对于Windows NT 3.10而言，这个值被设为10。 <br>　　 &#183;Reserved1。未知目的，通常不被系统使用，并被链接器设为0。 <br>
&#183;SizeOfImage。表示载入的可执行映像的地址空间中要保留的地址空间大小，这个数字很大程度上受SectionAlignment的影响。例
如，考虑一个拥有固定页尺寸4096字节的系统，如果你有一个11个段的可执行文件，它的每个段都少于4096字节，并且关于65536字节边界对齐，那
么SizeOfImage域将会被设为11 * 65536 =
720896（176页）。而如果一个相同的文件关于4096字节对齐的话，那么SizeOfImage域的结果将是11 * 4096 =
45056（11页）。这只是个简单的例子，它说明每个段需要少于一个页面的内存。在现实中，链接器通过个别地计算每个段的方法来决定
SizeOfImage确切的值。它首先决定每个段需要多少字节，并且最后将页面总数向上取整至最接近的SectionAlignment边界，然后总数
就是每个段个别需求之和了。 <br>　　 &#183;SizeOfHeaders。这个域表示文件中有多少空间用来保存所有的文件头部，包括MS-DOS头部、PE文件头部、PE可选头部以及PE段头部。文件中所有的段实体就开始于这个位置。 <br>　　 &#183;CheckSum。校验和是用来在装载时验证可执行文件的，它是由链接器设置并检验的。由于创建这些校验和的算法是私有信息，所以在此不进行讨论。 <br>　　 &#183;Subsystem。用于标识该可执行文件目标子系统的域。每个可能的子系统取值列于WINNT.H的IMAGE_OPTIONAL_HEADER结构之后。 <br>　　 &#183;DllCharacteristics。用来表示一个DLL映像是否为进程和线程的初始化及终止包含入口点的标记。 <br>
&#183;SizeOfStackReserve、SizeOfStackCommit、SizeOfHeapReserve、
SizeOfHeapCommit。这些域控制要保留的地址空间数量，并且负责栈和默认堆的申请。在默认情况下，栈和堆都拥有1个页面的申请值以及16个
页面的保留值。这些值可以使用链接器开关-STACKSIZE:与-HEAPSIZE:来设置。 <br>　　 &#183;LoaderFlags。告知装载器是否在装载时中止和调试，或者默认地正常运行。 <br>　　 &#183;NumberOfRvaAndSizes。这个域标识了接下来的DataDirectory数组。请注意它被用来标识这个数组，而不是数组中的各个入口数字，这一点非常重要。 <br>　　 &#183;DataDirectory。数据目录表示文件中其它可执行信息重要组成部分的位置。它事实上就是一个IMAGE_DATA_DIRECTORY结构的数组，位于可选头部结构的末尾。当前的PE文件格式定义了16种可能的数据目录，这之中的11种现在在使用中。 <br><br><strong>数据目录</strong> <br><br>WINNT.H之中所定义的数据目录为：
<pre>//WINNT.H
// 目录入口
// 导出目录
#define IMAGE_DIRECTORY_ENTRY_EXPORT 0
// 导入目录
#define IMAGE_DIRECTORY_ENTRY_IMPORT 1
// 资源目录
#define IMAGE_DIRECTORY_ENTRY_RESOURCE 2
// 异常目录
#define IMAGE_DIRECTORY_ENTRY_EXCEPTION 3
// 安全目录
#define IMAGE_DIRECTORY_ENTRY_SECURITY 4
// 重定位基本表
#define IMAGE_DIRECTORY_ENTRY_BASERELOC 5
// 调试目录
#define IMAGE_DIRECTORY_ENTRY_DEBUG 6
// 描述字串
#define IMAGE_DIRECTORY_ENTRY_COPYRIGHT 7
// 机器值（MIPS GP）
#define IMAGE_DIRECTORY_ENTRY_GLOBALPTR 8
// TLS目录
#define IMAGE_DIRECTORY_ENTRY_TLS 9
// 载入配置目录
#define IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG 10
</pre>
基本上，每个数据目录都是一个被定义为IMAGE_DATA_DIRECTORY的结构。虽然数据目录入口本身是相同的，但是每个特定的目录种类却是完全唯一的。每个数据目录的定义在本文的以后部分被描述为&#8220;预定义段&#8221;。
<pre>//WINNT.H
typedef struct _IMAGE_DATA_DIRECTORY {
ULONG VirtualAddress;
ULONG Size;
} IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;
</pre>
每个数据目录入口指定了该目录的尺寸和相对虚拟地址。如果你要定义一个特定的目录的话，就需要从可选头部中的数据目录数组中决定相对的地址，
然后使用虚拟地址来决定该目录位于哪个段中。一旦你决定了哪个段包含了该目录，该段的段头部就会被用于查找数据目录的精确文件偏移量位置。 <br>　　 所以要获得一个数据目录的话，那么首先你需要了解段的概念。我在下面会对其进行描述，这个讨论之后还有一个有关如何定位数据目录的示例。 <br><br><strong>PE文件段</strong> <br><br>
PE文件规范由目前为止定义的那些头部以及一个名为&#8220;段&#8221;的一般对象组成。段包含了文件的内容，包括代码、数据、资源以及其它可执行信息，每个段都有一个
头部和一个实体（原始数据）。我将在下面描述段头部的有关信息，但是段实体则缺少一个严格的文件结构。因此，它们几乎可以被链接器按任何的方法组织，只要
它的头部填充了足够能够解释数据的信息。 <br><br><strong>段头部</strong> <br><br>　　 PE文件格式中，所有的段头部位于可选头部之后。每个段头部为40个字节长，并且没有任何的填充信息。段头部被定义为以下的结构：
<pre>//WINNT.H
#define IMAGE_SIZEOF_SHORT_NAME 8
typedef struct _IMAGE_SECTION_HEADER {
UCHAR Name[IMAGE_SIZEOF_SHORT_NAME];
union {
ULONG PhysicalAddress;
ULONG VirtualSize;
} Misc;
ULONG VirtualAddress;
ULONG SizeOfRawData;
ULONG PointerToRawData;
ULONG PointerToRelocations;
ULONG PointerToLinenumbers;
USHORT NumberOfRelocations;
USHORT NumberOfLinenumbers;
ULONG Characteristics;
} IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER;
</pre>
你如何才能获得一个特定段的段头部信息？既然段头部是被连续的组织起来的，而且没有一个特定的顺序，那么段头部必须由名称来定位。以下的函数示范了如何从一个给定了段名称的PE映像文件中获得一个段头部：
<pre>//PEFILE.C
BOOL WINAPI GetSectionHdrByName(LPVOID lpFile, IMAGE_SECTION_HEADER *sh, char *szSection)
{
PIMAGE_SECTION_HEADER psh;
int nSections = NumOfSections (lpFile);
int i;
if ((psh = (PIMAGE_SECTION_HEADER)SECHDROFFSET(lpFile))
!= NULL)
{
/* 由名称查找段 */
for (i = 0; i &lt; nSections; i++)
{
if (!strcmp(psh-&gt;Name, szSection))
{
/* 向头部复制数据 */
CopyMemory((LPVOID)sh, (LPVOID)psh,
sizeof(IMAGE_SECTION_HEADER));
return TRUE;
}
else
psh++;
}
}
return FALSE;
}</pre>
这个函数通过SECHDROFFSET宏将第一个段头部定位，然后它开始在所有段中循环，并将要寻找的段名称和每个段的名称相比较，直到找
到了正确的那一个为止。当找到了段的时候，函数将内存映像文件的数据复制到传入函数的结构中，然后IMAGE_SECTION_HEADER结构的各域就
能够被直接存取了。 <br><br><strong>段头部的域</strong> <br><br>　　 &#183;Name。每个段都有一个8字符长的名称域，并且第一个字符必须是一个句点。 <br>　　 &#183;PhysicalAddress或VirtualSize。第二个域是一个union域，现在已不使用了。 <br>
&#183;VirtualAddress。这个域标识了进程地址空间中要装载这个段的虚拟地址。实际的地址由将这个域的值加上可选头部结构中的ImageBase
虚拟地址得到。切记，如果这个映像文件是一个DLL，那么这个DLL就不一定会装载到ImageBase要求的位置。所以一旦这个文件被装载进入了一个进
程，实际的ImageBase值应该通过使用GetModuleHandle来检验。 <br>
&#183;SizeOfRawData。这个域表示了相对FileAlignment的段实体尺寸。文件中实际的段实体尺寸将少于或等于
FileAlignment的整倍数。一旦映像被装载进入了一个进程的地址空间，段实体的尺寸将会变得少于或等于FileAlignment的整倍数。 <br>　　 &#183;PointerToRawData。这是一个文件中段实体位置的偏移量。 <br>　　 &#183;PointerToRelocations、PointerToLinenumbers、NumberOfRelocations、NumberOfLinenumbers。这些域在PE格式中不使用。 <br>　　 &#183;Characteristics。定义了段的特征。这些值可以在WINNT.H及本光盘（译注：MSDN的光盘）的PE格式规范中找到。 <br><br>值 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;定义 <br>0x00000020 代码段 <br>0x00000040 已初始化数据段 <br>0x00000080 未初始化数据段 <br>0x04000000 该段数据不能被缓存 <br>0x08000000 该段不能被分页 <br>0x10000000 共享段 <br>0x20000000 可执行段 <br>0x40000000 可读段 <br>0x80000000 可写段 <br><br><strong>定位数据目录</strong> <br><br>　　 数据目录存在于它们相应的数据段中。典型地来说，数据目录是段实体中的第一个结构，但不是必需的。由于这个缘故，如果你需要定位一个指定的数据目录的话，就需要从段头部和可选头部中获得信息。 <br>　　 为了让这个过程简单一点，我编写了以下的函数来定位任何一个在WINNT.H之中定义的数据目录。
<pre>// PEFILE.C
LPVOID WINAPI ImageDirectoryOffset(LPVOID lpFile,
DWORD dwIMAGE_DIRECTORY)
{
PIMAGE_OPTIONAL_HEADER poh;
PIMAGE_SECTION_HEADER psh;
int nSections = NumOfSections(lpFile);
int i = 0;
LPVOID VAImageDir;
/* 必须为0到(NumberOfRvaAndSizes-1)之间 */
if (dwIMAGE_DIRECTORY &gt;= poh-&gt;NumberOfRvaAndSizes)
return NULL;
/* 获得可选头部和段头部的偏移量 */
poh = (PIMAGE_OPTIONAL_HEADER)OPTHDROFFSET(lpFile);
psh = (PIMAGE_SECTION_HEADER)SECHDROFFSET(lpFile);
/* 定位映像目录的相对虚拟地址 */
VAImageDir = (LPVOID)poh-&gt;DataDirectory
[dwIMAGE_DIRECTORY].VirtualAddress;
/* 定位包含映像目录的段 */
while (i++ &lt; nSections)
{
if (psh-&gt;VirtualAddress &lt;= (DWORD)VAImageDir &amp;&amp;
psh-&gt;VirtualAddress +
psh-&gt;SizeOfRawData &gt; (DWORD)VAImageDir)
break;
psh++;
}
if (i &gt; nSections)
return NULL;
/* 返回映像导入目录的偏移量 */
return (LPVOID)(((int)lpFile +
(int)VAImageDir. psh-&gt;VirtualAddress) +
(int)psh-&gt;PointerToRawData);
}
</pre>
该函数首先确认被请求的数据目录入口数字，然后它分别获取指向可选头部和第一个段头部的两个指针。它从可选头部决定数据目录的虚拟地址，
然后它使用这个值来决定数据目录定位在哪个段实体之中。如果适当的段实体已经被标识了，那么数据目录特定的位置就可以通过将它的相对虚拟地址转换为文件中
地址的方法来找到。 <img src ="http://www.cppblog.com/guojingjia2006/aggbug/129615.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/guojingjia2006/" target="_blank">小果子</a> 2010-10-12 16:38 <a href="http://www.cppblog.com/guojingjia2006/archive/2010/10/12/129615.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Windows完成端口与Linux epoll技术简介(转载)</title><link>http://www.cppblog.com/guojingjia2006/archive/2010/08/27/124945.html</link><dc:creator>小果子</dc:creator><author>小果子</author><pubDate>Fri, 27 Aug 2010 07:43:00 GMT</pubDate><guid>http://www.cppblog.com/guojingjia2006/archive/2010/08/27/124945.html</guid><wfw:comment>http://www.cppblog.com/guojingjia2006/comments/124945.html</wfw:comment><comments>http://www.cppblog.com/guojingjia2006/archive/2010/08/27/124945.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/guojingjia2006/comments/commentRss/124945.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/guojingjia2006/services/trackbacks/124945.html</trackback:ping><description><![CDATA[<span style="font-size: 8pt;">
<p style="font-family: courier new;"><strong>WINDOWS完成端口编程<br>
</strong>1、基本概念<br>
2、WINDOWS完成端口的特点<br>
3、完成端口（Completion Ports ）相关数据结构和创建<br>
4、完成端口线程的工作原理<br>
5、Windows完成端口的实例代码<br>
<strong>Linux的EPoll模型<br>
</strong>1、为什么select落后<br>
2、内核中提高I/O性能的新方法epoll<br>
3、epoll的优点<br>
4、epoll的工作模式 <br>
5、epoll的使用方法<br>
6、Linux下EPOll编程实例<br>
<strong>总结</strong></p>
<p style="font-family: courier new;"><strong>WINDOWS完成端口编程<br>
</strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
摘要：开发网络程序从来都不是一件容易的事情，尽管只需要遵守很少的一些规则;创建socket,发起连接，接受连接，发送和接受数据。真正的困难在于：
让你的程序可以适应从单单一个连接到几千个连接乃至于上万个连接。利用Windows平台完成端口进行重叠I/O的技术和Linux在2.6版本的内核中
引入的EPOll技术，可以很方便在在在Windows和Linux平台上开发出支持大量连接的网络服务程序。本文介绍在Windows和Linux平台
上使用的完成端口和EPoll模型开发的基本原理，同时给出实际的例子。本文主要关注C/S结构的服务器端程序，因为一般来说，开发一个大容量，具可扩展
性的winsock程序一般就是指服务程序。<br>
<strong><br>
1、基本概念<br>
</strong>&nbsp;&nbsp;&nbsp;
设备---windows操作系统上允许通信的任何东西，比如文件、目录、串行口、并行口、邮件槽、命名管道、无名管道、套接字、控制台、逻辑磁盘、物理
磁盘等。绝大多数与设备打交道的函数都是CreateFile/ReadFile/WriteFile等。所以我们不能看到**File函数就只想到文件
设备。与设备通信有两种方式，同步方式和异步方式。同步方式下，当调用ReadFile函数时，函数会等待系统执行完所要求的工作，然后才返回；异步方式
下，ReadFile这类函数会直接返回，系统自己去完成对设备的操作，然后以某种方式通知完成操作。<br>
重叠I/O----顾名思义，当你调用了某个函数（比如ReadFile）就立刻返回做自己的其他动作的时候，同时系统也在对I/0设备进行你要求的操
作，在这段时间内你的程序和系统的内部动作是重叠的，因此有更好的性能。所以，重叠I/O是用于异步方式下使用I/O设备的。
重叠I/O需要使用的一个非常重要的数据结构OVERLAPPED。<br>
<strong><br>
2、WINDOWS完成端口的特点<br>
</strong>&nbsp;&nbsp; Win32重叠I/O(Overlapped
I/O)机制允许发起一个操作，然后在操作完成之后接受到信息。对于那种需要很长时间才能完成的操作来说，重叠IO机制尤其有用，因为发起重叠操作的线程
在重叠请求发出后就可以自由的做别的事情了。在WinNT和Win2000上，提供的真正的可扩展的I/O模型就是使用完成端口（Completion
Port）的重叠I/O.完成端口---是一种WINDOWS内核对象。完成端口用于异步方式的重叠I/0情况下，当然重叠I/O不一定非使用完成端口不
可，还有设备内核对象、事件对象、告警I/0等。但是完成端口内部提供了线程池的管理，可以避免反复创建线程的开销，同时可以根据CPU的个数灵活的决定
线程个数，而且可以让减少线程调度的次数从而提高性能其实类似于WSAAsyncSelect和select函数的机制更容易兼容Unix，但是难以实现
我们想要的&#8220;扩展性&#8221;。而且windows的完成端口机制在操作系统内部已经作了优化，提供了更高的效率。所以，我们选择完成端口开始我们的服务器程序的
开发。<br>
1、发起操作不一定完成，系统会在完成的时候通知你，通过用户在完成端口上的等待，处理操作的结果。所以要有检查完成端口，取操作结果的线程。在完成端口
上守候的线程系统有优化，除非在执行的线程阻塞，不会有新的线程被激活，以此来减少线程切换造成的性能代价。所以如果程序中没有太多的阻塞操作，没有必要
启动太多的线程，CPU数量的两倍，一般这样来启动线程。<br>
2、操作与相关数据的绑定方式：在提交数据的时候用户对数据打相应的标记，记录操作的类型，在用户处理操作结果的时候，通过检查自己打的标记和系统的操作结果进行相应的处理。 <br>
3、操作返回的方式:一般操作完成后要通知程序进行后续处理。但写操作可以不通知用户，此时如果用户写操作不能马上完成，写操作的相关数据会被暂存到到非
交换缓冲区中，在操作完成的时候，系统会自动释放缓冲区。此时发起完写操作，使用的内存就可以释放了。此时如果占用非交换缓冲太多会使系统停止响应。<br>
<strong><br>
3、完成端口（Completion Ports ）相关数据结构和创建<br>
</strong>&nbsp;&nbsp;&nbsp; 其实可以把完成端口看成系统维护的一个队列，操作系统把重叠IO操作完成的事件通知放到该队列里，由于是暴露
&#8220;操作完成&#8221;的事件通知，所以命名为&#8220;完成端口&#8221;（COmpletion
Ports）。一个socket被创建后，可以在任何时刻和一个完成端口联系起来。<br>
完成端口相关最重要的是OVERLAPPED数据结构<br>
typedef struct _OVERLAPPED { <br>
&nbsp;&nbsp;&nbsp;   ULONG_PTR Internal;//被系统内部赋值，用来表示系统状态 <br>
&nbsp;&nbsp;&nbsp;   ULONG_PTR InternalHigh;// 被系统内部赋值，传输的字节数 <br>
&nbsp;&nbsp;&nbsp;   union { <br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;   struct { <br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;   DWORD Offset;//和OffsetHigh合成一个64位的整数，用来表示从文件头部的多少字节开始 <br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;   DWORD OffsetHigh;//操作，如果不是对文件I/O来操作，则必须设定为0 <br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;   }; <br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;   PVOID Pointer; <br>
&nbsp;&nbsp;&nbsp;   }; <br>
&nbsp;&nbsp;&nbsp;   HANDLE hEvent;//如果不使用，就务必设为0,否则请赋一个有效的Event句柄 <br>
} OVERLAPPED, *LPOVERLAPPED; <br>
<br>
下面是异步方式使用ReadFile的一个例子 <br>
OVERLAPPED Overlapped; <br>
Overlapped.Offset=345; <br>
Overlapped.OffsetHigh=0; <br>
Overlapped.hEvent=0; <br>
//假定其他参数都已经被初始化 <br>
ReadFile(hFile,buffer,sizeof(buffer),&amp;dwNumBytesRead,&amp;Overlapped); <br>
这样就完成了异步方式读文件的操作，然后ReadFile函数返回，由操作系统做自己的事情，下面介绍几个与OVERLAPPED结构相关的函数 <br>
等待重叠I/0操作完成的函数 <br>
BOOL GetOverlappedResult (<br>
HANDLE hFile,<br>
LPOVERLAPPED lpOverlapped,//接受返回的重叠I/0结构<br>
LPDWORD lpcbTransfer,//成功传输了多少字节数<br>
BOOL fWait //TRUE只有当操作完成才返回，FALSE直接返回，如果操作没有完成，通过调//用GetLastError ( )函数会返回ERROR_IO_INCOMPLETE <br>
);<br>
宏HasOverlappedIoCompleted可以帮助我们测试重叠I/0操作是否完成，该宏对OVERLAPPED结构的Internal成员进行了测试，查看是否等于STATUS_PENDING值。</p>
<p style="font-family: courier new;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
一般来说，一个应用程序可以创建多个工作线程来处理完成端口上的通知事件。工作线程的数量依赖于程序的具体需要。但是在理想的情况下，应该对应一个CPU
创建一个线程。因为在完成端口理想模型中，每个线程都可以从系统获得一个&#8220;原子&#8221;性的时间片，轮番运行并检查完成端口，线程的切换是额外的开销。在实际开
发的时候，还要考虑这些线程是否牵涉到其他堵塞操作的情况。如果某线程进行堵塞操作，系统则将其挂起，让别的线程获得运行时间。因此，如果有这样的情况，
可以多创建几个线程来尽量利用时间。<br>
应用完成端口：<br>
&nbsp;&nbsp;&nbsp;   创建完成端口：完成端口是一个内核对象，使用时他总是要和至少一个有效的设备句柄进行关联，完成端口是一个复杂的内核对象，创建它的函数是：<br>
HANDLE CreateIoCompletionPort( <br>
&nbsp;&nbsp;&nbsp;   IN HANDLE FileHandle, <br>
&nbsp;&nbsp;&nbsp;   IN HANDLE ExistingCompletionPort, <br>
&nbsp;&nbsp;&nbsp;   IN ULONG_PTR CompletionKey, <br>
&nbsp;&nbsp;&nbsp;   IN DWORD NumberOfConcurrentThreads <br>
&nbsp;&nbsp;&nbsp;   ); <br>
<br>
通常创建工作分两步：<br>
第一步，创建一个新的完成端口内核对象，可以使用下面的函数：<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;   HANDLE CreateNewCompletionPort(DWORD dwNumberOfThreads) <br>
{ <br>
&nbsp;&nbsp;&nbsp;&nbsp;   &nbsp;&nbsp;&nbsp;&nbsp;   return CreateIoCompletionPort(INVALID_HANDLE_VALUE,NULL,NULL,dwNumberOfThreads); <br>
};<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;   <br>
第二步，将刚创建的完成端口和一个有效的设备句柄关联起来，可以使用下面的函数：<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;   bool AssicoateDeviceWithCompletionPort(HANDLE hCompPort,HANDLE hDevice,DWORD dwCompKey) <br>
{ <br>
&nbsp;&nbsp;&nbsp;&nbsp;   &nbsp;&nbsp;&nbsp;&nbsp;   HANDLE h=CreateIoCompletionPort(hDevice,hCompPort,dwCompKey,0); <br>
&nbsp;&nbsp;&nbsp;&nbsp;   &nbsp;&nbsp;&nbsp;&nbsp;   return h==hCompPort; <br>
}; <br>
说明 <br>
1） CreateIoCompletionPort函数也可以一次性的既创建完成端口对象，又关联到一个有效的设备句柄 <br>
2） CompletionKey是一个可以自己定义的参数，我们可以把一个结构的地址赋给它，然后在合适的时候取出来使用，最好要保证结构里面的内存不是分配在栈上，除非你有十分的把握内存会保留到你要使用的那一刻。<br>
3）
NumberOfConcurrentThreads通常用来指定要允许同时运行的的线程的最大个数。通常我们指定为0，这样系统会根据CPU的个数来自
动确定。创建和关联的动作完成后，系统会将完成端口关联的设备句柄、完成键作为一条纪录加入到这个完成端口的设备列表中。如果你有多个完成端口，就会有多
个对应的设备列表。如果设备句柄被关闭，则表中自动删除该纪录。<br>
<strong><br>
4、完成端口线程的工作原理</strong><br>
完成端口可以帮助我们管理线程池，但是线程池中的线程需要我们使用_beginthreadex来创建，凭什么通知完成端口管理我们的新线程呢？答案在函数GetQueuedCompletionStatus。该函数原型： <br>
BOOL GetQueuedCompletionStatus( <br>
&nbsp;&nbsp;&nbsp;   IN HANDLE CompletionPort, <br>
&nbsp;&nbsp;&nbsp;   OUT LPDWORD lpNumberOfBytesTransferred, <br>
&nbsp;&nbsp;&nbsp;   OUT PULONG_PTR lpCompletionKey, <br>
&nbsp;&nbsp;&nbsp;   OUT LPOVERLAPPED *lpOverlapped, <br>
&nbsp;&nbsp;&nbsp;   IN DWORD dwMilliseconds <br>
); <br>
这个函数试图从指定的完成端口的I/0完成队列中抽取纪录。只有当重叠I/O动作完成的时候，完成队列中才有纪录。凡是调用这个函数的线程将被放入到完成
端口的等待线程队列中，因此完成端口就可以在自己的线程池中帮助我们维护这个线程。完成端口的I/0完成队列中存放了当重叠I/0完成的结果----
一条纪录，该纪录拥有四个字段，前三项就对应GetQueuedCompletionStatus函数的2、3、4参数，最后一个字段是错误信息
dwError。我们也可以通过调用PostQueudCompletionStatus模拟完成了一个重叠I/0操作。 <br>
当I/0完成队列中出现了纪录，完成端口将会检查等待线程队列，该队列中的线程都是通过调用GetQueuedCompletionStatus函数使自
己加入队列的。等待线程队列很简单，只是保存了这些线程的ID。完成端口会按照后进先出的原则将一个线程队列的ID放入到释放线程列表中，同时该线程将从
等待GetQueuedCompletionStatus函数返回的睡眠状态中变为可调度状态等待CPU的调度。所以我们的线程要想成为完成端口管理的线
程，就必须要调用GetQueuedCompletionStatus函数。出于性能的优化，实际上完成端口还维护了一个暂停线程列表，具体细节可以参考
《Windows高级编程指南》，我们现在知道的知识，已经足够了。
完成端口线程间数据传递线程间传递数据最常用的办法是在_beginthreadex函数中将参数传递给线程函数，或者使用全局变量。但是完成端口还有自
己的传递数据的方法，答案就在于CompletionKey和OVERLAPPED参数。<br>
CompletionKey被保存在完成端口的设备表中，是和设备句柄一一对应的，我们可以将与设备句柄相关的数据保存到CompletionKey中，
或者将CompletionKey表示为结构指针，这样就可以传递更加丰富的内容。这些内容只能在一开始关联完成端口和设备句柄的时候做，因此不能在以后
动态改变。<br>
OVERLAPPED参数是在每次调用ReadFile这样的支持重叠I/0的函数时传递给完成端口的。我们可以看到，如果我们不是对文件设备做操作，该
结构的成员变量就对我们几乎毫无作用。我们需要附加信息，可以创建自己的结构，然后将OVERLAPPED结构变量作为我们结构变量的第一个成员，然后传
递第一个成员变量的地址给ReadFile函数。因为类型匹配，当然可以通过编译。当GetQueuedCompletionStatus函数返回时，我
们可以获取到第一个成员变量的地址，然后一个简单的强制转换，我们就可以把它当作完整的自定义结构的指针使用，这样就可以传递很多附加的数据了。太好了！
只有一点要注意，如果跨线程传递，请注意将数据分配到堆上，并且接收端应该将数据用完后释放。我们通常需要将ReadFile这样的异步函数的所需要的缓
冲区放到我们自定义的结构中，这样当GetQueuedCompletionStatus被返回时，我们的自定义结构的缓冲区变量中就存放了I/0操作的
数据。CompletionKey和OVERLAPPED参数，都可以通过GetQueuedCompletionStatus函数获得。<br>
线程的安全退出<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;   很多线程为了不止一次的执行异步数据处理，需要使用如下语句<br>
while (true)<br>
{<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;   ......<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;   GetQueuedCompletionStatus(...); <br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;   ......<br>
}<br>
那么如何退出呢，答案就在于上面曾提到的PostQueudCompletionStatus函数，我们可以用它发送一个自定义的包含了OVERLAPPED成员变量的结构地址，里面包含一个状态变量，当状态变量为退出标志时，线程就执行清除动作然后退出。<br>
<strong><br>
5、Windows完成端口的实例代码：<br>
</strong>DWORD WINAPI WorkerThread(LPVOID lpParam)<br>
{ <br>
ULONG_PTR *PerHandleKey;<br>
OVERLAPPED *Overlap;<br>
OVERLAPPEDPLUS *OverlapPlus,<br>
*newolp;<br>
DWORD dwBytesXfered;<br>
while (1)<br>
{<br>
ret = GetQueuedCompletionStatus(<br>
hIocp,<br>
&amp;dwBytesXfered,<br>
(PULONG_PTR)&amp;PerHandleKey,<br>
&amp;Overlap,<br>
INFINITE);<br>
if (ret == 0)<br>
{<br>
// Operation failed<br>
continue;<br>
}<br>
OverlapPlus = CONTAINING_RECORD(Overlap, OVERLAPPEDPLUS, ol);<br>
switch (OverlapPlus-&gt;OpCode)<br>
{<br>
case OP_ACCEPT:<br>
// Client socket is contained in OverlapPlus.sclient<br>
// Add client to completion port<br>
CreateIoCompletionPort(<br>
(HANDLE)OverlapPlus-&gt;sclient,<br>
hIocp,<br>
(ULONG_PTR)0,<br>
0);<br>
// Need a new OVERLAPPEDPLUS structure<br>
// for the newly accepted socket. Perhaps<br>
// keep a look aside list of free structures.<br>
newolp = AllocateOverlappedPlus();<br>
if (!newolp)<br>
{<br>
// Error<br>
}<br>
newolp-&gt;s = OverlapPlus-&gt;sclient;<br>
newolp-&gt;OpCode = OP_READ;<br>
// This function divpares the data to be sent<br>
PrepareSendBuffer(&amp;newolp-&gt;wbuf);<br>
ret = WSASend(<br>
newolp-&gt;s,<br>
&amp;newolp-&gt;wbuf,<br>
1,<br>
&amp;newolp-&gt;dwBytes,<br>
0,<br>
&amp;newolp.ol,<br>
NULL);<br>
if (ret == SOCKET_ERROR)<br>
{<br>
if (WSAGetLastError() != WSA_IO_PENDING)<br>
{<br>
// Error<br>
}<br>
}<br>
// Put structure in look aside list for later use<br>
FreeOverlappedPlus(OverlapPlus);<br>
// Signal accept thread to issue another AcceptEx<br>
SetEvent(hAcceptThread);<br>
break;<br>
case OP_READ:<br>
// Process the data read <br>
// Repost the read if necessary, reusing the same<br>
// receive buffer as before<br>
memset(&amp;OverlapPlus-&gt;ol, 0, sizeof(OVERLAPPED));<br>
ret = WSARecv(<br>
OverlapPlus-&gt;s,<br>
&amp;OverlapPlus-&gt;wbuf,<br>
1,<br>
&amp;OverlapPlus-&gt;dwBytes,<br>
&amp;OverlapPlus-&gt;dwFlags,<br>
&amp;OverlapPlus-&gt;ol,<br>
NULL);<br>
if (ret == SOCKET_ERROR)<br>
{<br>
if (WSAGetLastError() != WSA_IO_PENDING)<br>
{<br>
// Error<br>
}<br>
}<br>
break;<br>
case OP_WRITE:<br>
// Process the data sent, etc.<br>
break;<br>
} // switch<br>
} // while<br>
} // WorkerThread<br>
</p>
<p style="font-family: courier new;">查看以上代码，注意如果Overlapped操作立刻失败（比如，返回SOCKET_ERROR或其他非WSA_IO_PENDING的错误），则
没有任何完成通知时间会被放到完成端口队列里。反之，则一定有相应的通知时间被放到完成端口队列。更完善的关于Winsock的完成端口机制，可以参考
MSDN的Microsoft PlatFormSDK，那里有完成端口的例子。访问<a  href="http://msdn.microsoft.com/library/techart/msdn_servrapp.htm" target="_blank">http://msdn.microsoft.com/library/techart/msdn_servrapp.htm</a>可以获得更多信息。</p>
<p style="font-family: courier new;"><strong>Linux的EPoll模型<br>
</strong>Linux 2.6内核中提高网络I/O性能的新方法-epoll I/O多路复用技术在比较多的TCP网络服务器中有使用，即比较多的用到select函数。<br>
<br>
<strong>1、为什么select落后<br>
</strong>首先，在Linux内核中，select所用到的FD_SET是有限的，即内核中有个参数__FD_SETSIZE定义了每个FD_SET的句柄个数，在我用的2.6.15-25-386内核中，该值是1024，搜索内核源代码得到：<br>
include/linux/posix_types.h:#define __FD_SETSIZE&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;   1024<br>
也就是说，如果想要同时检测1025个句柄的可读状态是不可能用select实现的。或者同时检测1025个句柄的可写状态也是不可能的。其次，内核中实
现select是用轮询方法，即每次检测都会遍历所有FD_SET中的句柄，显然，select函数执行时间与FD_SET中的句柄个数有一个比例关系，
即select要检测的句柄数越多就会越费时。当然，在前文中我并没有提及poll方法，事实上用select的朋友一定也试过poll，我个人觉得
select和poll大同小异，个人偏好于用select而已。</p>
<p style="font-family: courier new;"><strong>2、内核中提高I/O性能的新方法epoll</strong><br>
epoll是什么？按照man手册的说法：是为处理大批量句柄而作了改进的poll。要使用epoll只需要这三个系统调用：epoll_create(2)， epoll_ctl(2)， epoll_wait(2)。<br>
当然，这不是2.6内核才有的，它是在2.5.44内核中被引进的(epoll(4) is a new API introduced in Linux kernel 2.5.44)</p>
<p style="font-family: courier new;">Linux2.6内核epoll介绍<br>
先介绍2本书《The Linux Networking Architecture--Design and Implementation of
Network Protocols in the Linux Kernel》，以2.4内核讲解Linux
TCP/IP实现，相当不错.作为一个现实世界中的实现，很多时候你必须作很多权衡，这时候参考一个久经考验的系统更有实际意义。举个例子,linux内
核中sk_buff结构为了追求速度和安全，牺牲了部分内存，所以在发送TCP包的时候，无论应用层数据多大,sk_buff最小也有272的字节.其实
对于socket应用层程序来说，另外一本书《UNIX Network Programming Volume
1》意义更大一点.2003年的时候，这本书出了最新的第3版本，不过主要还是修订第2版本。其中第6章《I/O
Multiplexing》是最重要的。Stevens给出了网络IO的基本模型。在这里最重要的莫过于select模型和Asynchronous
I/O模型.从理论上说，AIO似乎是最高效的，你的IO操作可以立即返回，然后等待os告诉你IO操作完成。但是一直以来，如何实现就没有一个完美的方
案。最著名的windows完成端口实现的AIO,实际上也是内部用线程池实现的罢了，最后的结果是IO有个线程池，你应用也需要一个线程池......
很多文档其实已经指出了这带来的线程context-switch带来的代价。在linux
平台上，关于网络AIO一直是改动最多的地方，2.4的年代就有很多AIO内核patch,最著名的应该算是SGI那个。但是一直到2.6内核发布，网络
模块的AIO一直没有进入稳定内核版本(大部分都是使用用户线程模拟方法，在使用了NPTL的linux上面其实和windows的完成端口基本上差不多
了)。2.6内核所支持的AIO特指磁盘的AIO---支持io_submit(),io_getevents()以及对Direct
IO的支持(就是绕过VFS系统buffer直接写硬盘，对于流服务器在内存平稳性上有相当帮助)。<br>
所以，剩下的select模型基本上就是我们在linux上面的唯一选择，其实，如果加上no-block
socket的配置，可以完成一个"伪"AIO的实现，只不过推动力在于你而不是os而已。不过传统的select/poll函数有着一些无法忍受的缺
点，所以改进一直是2.4-2.5开发版本内核的任务，包括/dev/poll，realtime signal等等。最终，Davide
Libenzi开发的epoll进入2.6内核成为正式的解决方案<br>
<strong><br>
3、epoll的优点</strong><br>
&lt;1&gt;支持一个进程打开大数目的socket描述符(FD)<br>
select
最不能忍受的是一个进程所打开的FD是有一定限制的，由FD_SETSIZE设置，默认值是2048。对于那些需要支持的上万连接数目的IM服务器来说显
然太少了。这时候你一是可以选择修改这个宏然后重新编译内核，不过资料也同时指出这样会带来网络效率的下降，二是可以选择多进程的解决方案(传统的
Apache方案)，不过虽然linux上面创建进程的代价比较小，但仍旧是不可忽视的，加上进程间数据同步远比不上线程间同步的高效，所以也不是一种完
美的方案。不过
epoll则没有这个限制，它所支持的FD上限是最大可以打开文件的数目，这个数字一般远大于2048,举个例子,在1GB内存的机器上大约是10万左
右，具体数目可以cat /proc/sys/fs/file-max察看,一般来说这个数目和系统内存关系很大。<br>
&lt;2&gt;IO效率不随FD数目增加而线性下降<br>
传统的select/poll另一个致命弱点就是当你拥有一个很大的socket集合，不过由于网络延时，任一时间只有部分的socket是"活跃"的，
但是select/poll每次调用都会线性扫描全部的集合，导致效率呈现线性下降。但是epoll不存在这个问题，它只会对"活跃"的socket进行
操作---这是因为在内核实现中epoll是根据每个fd上面的callback函数实现的。那么，只有"活跃"的socket才会主动的去调用
callback函数，其他idle状态socket则不会，在这点上，epoll实现了一个"伪"AIO，因为这时候推动力在os内核。在一些
benchmark中，如果所有的socket基本上都是活跃的---比如一个高速LAN环境，epoll并不比select/poll有什么效率，相
反，如果过多使用epoll_ctl,效率相比还有稍微的下降。但是一旦使用idle
connections模拟WAN环境,epoll的效率就远在select/poll之上了。<br>
&lt;3&gt;使用mmap加速内核与用户空间的消息传递。<br>
这点实际上涉及到epoll的具体实现了。无论是select,poll还是epoll都需要内核把FD消息通知给用户空间，如何避免不必要的内存拷贝就
很重要，在这点上，epoll是通过内核于用户空间mmap同一块内存实现的。而如果你想我一样从2.5内核就关注epoll的话，一定不会忘记手工
mmap这一步的。<br>
&lt;4&gt;内核微调<br>
这一点其实不算epoll的优点了，而是整个linux平台的优点。也许你可以怀疑linux平台，但是你无法回避linux平台赋予你微调内核的能力。
比如，内核TCP/IP协议栈使用内存池管理sk_buff结构，那么可以在运行时期动态调整这个内存pool(skb_head_pool)的大小--
- 通过echo
XXXX&gt;/proc/sys/net/core/hot_list_length完成。再比如listen函数的第2个参数(TCP完成3次握手
的数据包队列长度)，也可以根据你平台内存大小动态调整。更甚至在一个数据包面数目巨大但同时每个数据包本身大小却很小的特殊系统上尝试最新的NAPI网
卡驱动架构。<br>
4、epoll的工作模式<br>
令人高兴的是，2.6内核的epoll比其2.5开发版本的/dev/epoll简洁了许多，所以，大部分情况下，强大的东西往往是简单的。唯一有点麻烦是epoll有2种工作方式:LT和ET。<br>
LT(level triggered)是缺省的工作方式，并且同时支持block和no-block
socket.在这种做法中，内核告诉你一个文件描述符是否就绪了，然后你可以对这个就绪的fd进行IO操作。如果你不作任何操作，内核还是会继续通知你
的，所以，这种模式编程出错误可能性要小一点。传统的select/poll都是这种模型的代表．<br>
ET (edge-triggered)是高速工作方式，只支持no-block
socket。在这种模式下，当描述符从未就绪变为就绪时，内核通过epoll告诉你。然后它会假设你知道文件描述符已经就绪，并且不会再为那个文件描述
符发送更多的就绪通知，直到你做了某些操作导致那个文件描述符不再为就绪状态了(比如，你在发送，接收或者接收请求，或者发送接收的数据少于一定量时导致
了一个EWOULDBLOCK 错误）。但是请注意，如果一直不对这个fd作IO操作(从而导致它再次变成未就绪)，内核不会发送更多的通知(only
once),不过在TCP协议中，ET模式的加速效用仍需要更多的benchmark确认。<br>
epoll只有epoll_create,epoll_ctl,epoll_wait 3个系统调用，具体用法请参考<a  href="http://www.xmailserver.org/linux-patches/nio-improve.html" target="_blank">http://www.xmailserver.org/linux-patches/nio-improve.html</a> ，在<a  href="http://www.kegel.com/rn/" target="_blank">http://www.kegel.com/rn/</a>也有一个完整的例子，大家一看就知道如何使用了<br>
Leader/follower模式线程pool实现，以及和epoll的配合。<br>
<br>
<strong>5、 epoll的使用方法</strong><br>
&nbsp;&nbsp;&nbsp; 首先通过create_epoll(int
maxfds)来创建一个epoll的句柄，其中maxfds为你epoll所支持的最大句柄数。这个函数会返回一个新的epoll句柄，之后的所有操作
将通过这个句柄来进行操作。在用完之后，记得用close()来关闭这个创建出来的epoll句柄。
之后在你的网络主循环里面，每一帧的调用epoll_wait(int epfd, epoll_event events, int max
events, int timeout)来查询所有的网络接口，看哪一个可以读，哪一个可以写了。基本的语法为： <br>
nfds = epoll_wait(kdpfd, events, maxevents, -1); <br>
其中kdpfd为用epoll_create创建之后的句柄，events是一个epoll_event*的指针，当epoll_wait这个函数操作成
功之后，epoll_events里面将储存所有的读写事件。max_events是当前需要监听的所有socket句柄数。最后一个timeout是
epoll_wait的超时，为0的时候表示马上返回，为-1的时候表示一直等下去，直到有事件范围，为任意正整数的时候表示等这么长的时间，如果一直没
有事件，则范围。一般如果网络主循环是单独的线程的话，可以用-1来等，这样可以保证一些效率，如果是和主逻辑在同一个线程的话，则可以用0来保证主循环
的效率。</p>
<p style="font-family: courier new;">epoll_wait范围之后应该是一个循环，遍利所有的事件： <br>
for(n = 0; n &lt; nfds; ++n) { <br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;   if(events[n].data.fd == listener) { //如果是主socket的事件的话，则表示有新连接进入了，进行新连接的处理。 <br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;   client = accept(listener, (struct sockaddr *) &amp;local, <br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;   &amp;addrlen); <br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;   if(client &lt; 0){ <br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;   perror("accept"); <br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;   continue; <br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;   } <br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;   setnonblocking(client); // 将新连接置于非阻塞模式 <br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;   ev.events = EPOLLIN | EPOLLET; // 并且将新连接也加入EPOLL的监听队列。 <br>
注意，这里的参数EPOLLIN | EPOLLET并没有设置对写socket的监听，如果有写操作的话，这个时候epoll是不会返回事件的，如果要对写操作也监听的话，应该是EPOLLIN | EPOLLOUT | EPOLLET <br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;   ev.data.fd = client; <br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;   if (epoll_ctl(kdpfd, EPOLL_CTL_ADD, client, &amp;ev) &lt; 0) { <br>
//
设置好event之后，将这个新的event通过epoll_ctl加入到epoll的监听队列里面，这里用EPOLL_CTL_ADD来加一个新的
epoll事件，通过EPOLL_CTL_DEL来减少一个epoll事件，通过EPOLL_CTL_MOD来改变一个事件的监听方式。 <br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;   fprintf(stderr, "epoll set insertion error: fd=%d0, <br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;   client); <br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;   return -1; <br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;   } <br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;   } <br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;   else // 如果不是主socket的事件的话，则代表是一个用户socket的事件，则来处理这个用户socket的事情，比如说read(fd,xxx)之类的，或者一些其他的处理。 <br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;   do_use_fd(events[n].data.fd); <br>
}</p>
<p style="font-family: courier new;">对，epoll的操作就这么简单，总共不过4个API：epoll_create, epoll_ctl, epoll_wait和close。 <br>
如果您对epoll的效率还不太了解，请参考我之前关于网络游戏的网络编程等相关的文章。</p>
<p style="font-family: courier new;"><br>
以前公司的服务器都是使用HTTP连接，但是这样的话，在手机目前的网络情况下不但显得速度较慢，而且不稳定。因此大家一致同意用SOCKET来进行连
接。虽然使用SOCKET之后，对于用户的费用可能会增加(由于是用了CMNET而非CMWAP)，但是，秉着用户体验至上的原则，相信大家还是能够接受
的(希望那些玩家月末收到帐单不后能够保持克制...)。<br>
这次的服务器设计中，最重要的一个突破，是使用了EPOLL模型，虽然对之也是一知半解，但是既然在各大PC网游中已经经过了如此严酷的考验，相信他不会让我们失望，使用后的结果，确实也是表现相当不错。在这里，我还是主要大致介绍一下这个模型的结构。<br>
6、Linux下EPOll编程实例<br>
EPOLL模型似乎只有一种格式，所以大家只要参考我下面的代码，就能够对EPOLL有所了解了，代码的解释都已经在注释中：</p>
<p style="font-family: courier new;">while (TRUE)<br>
{<br>
int nfds = epoll_wait (m_epoll_fd, m_events, MAX_EVENTS, EPOLL_TIME_OUT);//等待EPOLL时间的发生，相当于监听，至于相关的端口，需要在初始化EPOLL的时候绑定。<br>
if (nfds &lt;= 0)<br>
continue;<br>
m_bOnTimeChecking = FALSE;<br>
G_CurTime = time(NULL);<br>
for (int i=0; i<br>
{<br>
try<br>
{<br>
if (m_events.data.fd == m_listen_http_fd)//如果新监测到一个HTTP用户连接到绑定的HTTP端口，建立新的连接。由于我们新采用了SOCKET连接，所以基本没用。<br>
{<br>
OnAcceptHttpEpoll ();<br>
}<br>
else if (m_events.data.fd == m_listen_sock_fd)//如果新监测到一个SOCKET用户连接到了绑定的SOCKET端口，建立新的连接。<br>
{<br>
OnAcceptSockEpoll ();<br>
}<br>
else if (m_events.events &amp; EPOLLIN)//如果是已经连接的用户，并且收到数据，那么进行读入。<br>
{<br>
OnReadEpoll (i);<br>
}</p>
<p style="font-family: courier new;">OnWriteEpoll (i);//查看当前的活动连接是否有需要写出的数据。<br>
}<br>
catch (int)<br>
{<br>
PRINTF ("CATCH捕获错误\n");<br>
continue;<br>
}<br>
}<br>
m_bOnTimeChecking = TRUE;<br>
OnTimer ();//进行一些定时的操作，主要就是删除一些短线用户等。<br>
}<br>
其实EPOLL的精华，也就是上述的几段短短的代码，看来时代真的不同了，以前如何接受大量用户连接的问题，现在却被如此轻松的搞定，真是让人不得不感叹，对哪。</p>
<br style="font-family: courier new;">
<strong style="font-family: courier new;">总结<br>
</strong><span style="font-family: courier new;">Windows完成端口与Linux epoll技术方案是这2个平台上实现异步IO和设计开发一个大容量，具可扩展性的winsock程序指服务程序的很好的选择，本文对这2中技术的实现原理和实际的使用方法做了一个详细的介绍</span></span><img src ="http://www.cppblog.com/guojingjia2006/aggbug/124945.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/guojingjia2006/" target="_blank">小果子</a> 2010-08-27 15:43 <a href="http://www.cppblog.com/guojingjia2006/archive/2010/08/27/124945.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>伪句柄转化为真句柄</title><link>http://www.cppblog.com/guojingjia2006/archive/2010/04/28/113828.html</link><dc:creator>小果子</dc:creator><author>小果子</author><pubDate>Wed, 28 Apr 2010 02:59:00 GMT</pubDate><guid>http://www.cppblog.com/guojingjia2006/archive/2010/04/28/113828.html</guid><wfw:comment>http://www.cppblog.com/guojingjia2006/comments/113828.html</wfw:comment><comments>http://www.cppblog.com/guojingjia2006/archive/2010/04/28/113828.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/guojingjia2006/comments/commentRss/113828.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/guojingjia2006/services/trackbacks/113828.html</trackback:ping><description><![CDATA[<div style="background-color: #eeeeee; font-size: 13px; border: 1px solid #cccccc; padding: 4px 5px 4px 4px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #000000;">HANDLE&nbsp;hThreadParent;<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">CreateThread(NULL,0,ChildThread,(PVOID)hThreadParent,0,NULL);</span><span style="color: #008000;"><br></span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;DuplicateHandle(GetCurrentProcess(),GetCurrentThread(),GetCurrentProcess(),</span><span style="color: #000000;">&amp;</span><span style="color: #000000;">hThreadParent,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">0</span><span style="color: #000000;">,</span><span style="color: #0000ff;">false</span><span style="color: #000000;">,DUPLICATE_SAME_ACCESS);<br>&nbsp;&nbsp;&nbsp;&nbsp;_beginthreadex(NULL,</span><span style="color: #000000;">0</span><span style="color: #000000;">,ChildThread,(PVOID)hThreadParent,</span><span style="color: #000000;">0</span><span style="color: #000000;">,NULL);</span></div>
<br><img src ="http://www.cppblog.com/guojingjia2006/aggbug/113828.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/guojingjia2006/" target="_blank">小果子</a> 2010-04-28 10:59 <a href="http://www.cppblog.com/guojingjia2006/archive/2010/04/28/113828.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>枚举应用程序(转载microsoft)</title><link>http://www.cppblog.com/guojingjia2006/archive/2010/04/27/113696.html</link><dc:creator>小果子</dc:creator><author>小果子</author><pubDate>Tue, 27 Apr 2010 04:47:00 GMT</pubDate><guid>http://www.cppblog.com/guojingjia2006/archive/2010/04/27/113696.html</guid><wfw:comment>http://www.cppblog.com/guojingjia2006/comments/113696.html</wfw:comment><comments>http://www.cppblog.com/guojingjia2006/archive/2010/04/27/113696.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/guojingjia2006/comments/commentRss/113696.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/guojingjia2006/services/trackbacks/113696.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: Code highlighting produced by Actipro CodeHighlighter (freeware)http://www.CodeHighlighter.com/-->枚举顶层窗口如果将枚举进程与枚举桌面上的顶层窗口进行比较，那么枚举顶层窗口可能更容易一些。要枚举顶层窗口，请使用&nbsp;EnumWindows()&nbsp;函数。不要使用&nbsp;GetWindo...&nbsp;&nbsp;<a href='http://www.cppblog.com/guojingjia2006/archive/2010/04/27/113696.html'>阅读全文</a><img src ="http://www.cppblog.com/guojingjia2006/aggbug/113696.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/guojingjia2006/" target="_blank">小果子</a> 2010-04-27 12:47 <a href="http://www.cppblog.com/guojingjia2006/archive/2010/04/27/113696.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>操作系统版本</title><link>http://www.cppblog.com/guojingjia2006/archive/2010/04/27/113692.html</link><dc:creator>小果子</dc:creator><author>小果子</author><pubDate>Tue, 27 Apr 2010 03:10:00 GMT</pubDate><guid>http://www.cppblog.com/guojingjia2006/archive/2010/04/27/113692.html</guid><wfw:comment>http://www.cppblog.com/guojingjia2006/comments/113692.html</wfw:comment><comments>http://www.cppblog.com/guojingjia2006/archive/2010/04/27/113692.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/guojingjia2006/comments/commentRss/113692.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/guojingjia2006/services/trackbacks/113692.html</trackback:ping><description><![CDATA[
<div style="background-color: rgb(238, 238, 238); font-size: 13px; border-left-color: rgb(204, 204, 204); padding-right: 5px; padding-bottom: 4px; padding-left: 4px; padding-top: 4px; width: 98%; word-break: break-all; "><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #000000; ">#include&nbsp;</span><span style="color: #000000; ">&lt;</span><span style="color: #000000; ">windows.h</span><span style="color: #000000; ">&gt;</span><span style="color: #000000; "><br>#include&nbsp;</span><span style="color: #000000; ">&lt;</span><span style="color: #000000; ">stdio.h</span><span style="color: #000000; ">&gt;</span><span style="color: #000000; "><br><br><br>BOOL&nbsp;IsWin7&nbsp;()&nbsp;<br>{<br>&nbsp;&nbsp;&nbsp;OSVERSIONINFOEX&nbsp;osvi;<br>&nbsp;&nbsp;&nbsp;DWORDLONG&nbsp;dwlConditionMask&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">0</span><span style="color: #000000; ">;<br>&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">int</span><span style="color: #000000; ">&nbsp;op</span><span style="color: #000000; ">=</span><span style="color: #000000; ">VER_GREATER;<br><br>&nbsp;&nbsp;&nbsp;</span><span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;Initialize&nbsp;the&nbsp;OSVERSIONINFOEX&nbsp;structure.</span><span style="color: #008000; "><br></span><span style="color: #000000; "><br>&nbsp;&nbsp;&nbsp;ZeroMemory(</span><span style="color: #000000; ">&amp;</span><span style="color: #000000; ">osvi,&nbsp;</span><span style="color: #0000FF; ">sizeof</span><span style="color: #000000; ">(OSVERSIONINFOEX));<br>&nbsp;&nbsp;&nbsp;osvi.dwOSVersionInfoSize&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">sizeof</span><span style="color: #000000; ">(OSVERSIONINFOEX);<br>&nbsp;&nbsp;&nbsp;osvi.dwMajorVersion&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">6</span><span style="color: #000000; ">;<br>&nbsp;&nbsp;&nbsp;osvi.dwMinorVersion&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">1</span><span style="color: #000000; ">;<br><br>&nbsp;&nbsp;&nbsp;</span><span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;Initialize&nbsp;the&nbsp;condition&nbsp;mask.</span><span style="color: #008000; "><br></span><span style="color: #000000; "><br>&nbsp;&nbsp;&nbsp;VER_SET_CONDITION(&nbsp;dwlConditionMask,&nbsp;VER_MAJORVERSION,&nbsp;op&nbsp;);<br>&nbsp;&nbsp;&nbsp;VER_SET_CONDITION(&nbsp;dwlConditionMask,&nbsp;VER_MINORVERSION,&nbsp;op&nbsp;);<br>&nbsp;&nbsp;<br><br>&nbsp;&nbsp;&nbsp;</span><span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;Perform&nbsp;the&nbsp;test.</span><span style="color: #008000; "><br></span><span style="color: #000000; "><br>&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">return</span><span style="color: #000000; ">&nbsp;VerifyVersionInfo(<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000; ">&amp;</span><span style="color: #000000; ">osvi,&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;VER_MAJORVERSION&nbsp;</span><span style="color: #000000; ">|</span><span style="color: #000000; ">&nbsp;VER_MINORVERSION,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;dwlConditionMask);<br>}<br><br></span><span style="color: #0000FF; ">void</span><span style="color: #000000; ">&nbsp;main()<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">if</span><span style="color: #000000; ">(IsWin7())<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf(</span><span style="color: #000000; ">"</span><span style="color: #000000; ">yes.\n</span><span style="color: #000000; ">"</span><span style="color: #000000; ">);<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">else</span><span style="color: #000000; ">{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf(</span><span style="color: #000000; ">"</span><span style="color: #000000; ">no.\n</span><span style="color: #000000; ">"</span><span style="color: #000000; ">);<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>}</span></div><img src ="http://www.cppblog.com/guojingjia2006/aggbug/113692.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/guojingjia2006/" target="_blank">小果子</a> 2010-04-27 11:10 <a href="http://www.cppblog.com/guojingjia2006/archive/2010/04/27/113692.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>进程环境变量</title><link>http://www.cppblog.com/guojingjia2006/archive/2010/04/27/113690.html</link><dc:creator>小果子</dc:creator><author>小果子</author><pubDate>Tue, 27 Apr 2010 02:47:00 GMT</pubDate><guid>http://www.cppblog.com/guojingjia2006/archive/2010/04/27/113690.html</guid><wfw:comment>http://www.cppblog.com/guojingjia2006/comments/113690.html</wfw:comment><comments>http://www.cppblog.com/guojingjia2006/archive/2010/04/27/113690.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/guojingjia2006/comments/commentRss/113690.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/guojingjia2006/services/trackbacks/113690.html</trackback:ping><description><![CDATA[<div style="background-color: rgb(238, 238, 238); font-size: 13px; border-left-color: rgb(204, 204, 204); padding-right: 5px; padding-bottom: 4px; padding-left: 4px; padding-top: 4px; width: 98%; word-break: break-all; "><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #000000; ">#include&nbsp;</span><span style="color: #000000; ">&lt;</span><span style="color: #000000; ">iostream</span><span style="color: #000000; ">&gt;</span><span style="color: #000000; "><br>#include&nbsp;</span><span style="color: #000000; ">&lt;</span><span style="color: #000000; ">windows.h</span><span style="color: #000000; ">&gt;</span><span style="color: #000000; "><br>#include&nbsp;</span><span style="color: #000000; ">&lt;</span><span style="color: #000000; ">iostream</span><span style="color: #000000; ">&gt;</span><span style="color: #000000; "><br>#include&nbsp;</span><span style="color: #000000; ">&lt;</span><span style="color: #000000; ">psapi.h</span><span style="color: #000000; ">&gt;</span><span style="color: #000000; "><br>#include&nbsp;</span><span style="color: #000000; ">&lt;</span><span style="color: #000000; ">sstream</span><span style="color: #000000; ">&gt;</span><span style="color: #000000; "><br>#include&nbsp;</span><span style="color: #000000; ">&lt;</span><span style="color: #000000; ">fstream</span><span style="color: #000000; ">&gt;</span><span style="color: #000000; "><br><br></span><span style="color: #0000FF; ">using</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">namespace</span><span style="color: #000000; ">&nbsp;std;<br><br><br></span><span style="color: #0000FF; ">int</span><span style="color: #000000; ">&nbsp;_tmain(</span><span style="color: #0000FF; ">int</span><span style="color: #000000; ">&nbsp;argc,&nbsp;_TCHAR</span><span style="color: #000000; ">*</span><span style="color: #000000; ">&nbsp;argv[],TCHAR</span><span style="color: #000000; ">*</span><span style="color: #000000; ">&nbsp;envp[])<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000; ">//</span><span style="color: #008000; ">PTSTR&nbsp;pEnvBlock=::GetEnvironmentStrings();<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000; ">//</span><span style="color: #008000; ">TCHAR&nbsp;szName[MAX_PATH];<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000; ">//</span><span style="color: #008000; ">TCHAR&nbsp;szValue[MAX_PATH];</span><span style="color: #008000; "><br></span><span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">int</span><span style="color: #000000; ">&nbsp;current</span><span style="color: #000000; ">=</span><span style="color: #000000; ">0</span><span style="color: #000000; ">;<br>&nbsp;&nbsp;&nbsp;&nbsp;PTSTR</span><span style="color: #000000; ">*</span><span style="color: #000000; ">&nbsp;pElement&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">(PTSTR</span><span style="color: #000000; ">*</span><span style="color: #000000; ">)&nbsp;envp;<br>&nbsp;&nbsp;&nbsp;&nbsp;PTSTR&nbsp;pCurrent</span><span style="color: #000000; ">=</span><span style="color: #000000; ">NULL;<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">while</span><span style="color: #000000; ">(pElement</span><span style="color: #000000; ">!=</span><span style="color: #000000; ">NULL){&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pCurrent</span><span style="color: #000000; ">=</span><span style="color: #000000; ">(PTSTR)(</span><span style="color: #000000; ">*</span><span style="color: #000000; ">pElement);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">if</span><span style="color: #000000; ">(pCurrent</span><span style="color: #000000; ">==</span><span style="color: #000000; ">NULL){<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pElement</span><span style="color: #000000; ">=</span><span style="color: #000000; ">NULL;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span><span style="color: #0000FF; ">else</span><span style="color: #000000; ">{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_tprintf(TEXT(</span><span style="color: #000000; ">"</span><span style="color: #000000; ">[%u]&nbsp;%s\r\n</span><span style="color: #000000; ">"</span><span style="color: #000000; ">),current,pCurrent);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;current</span><span style="color: #000000; ">++</span><span style="color: #000000; ">;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pElement</span><span style="color: #000000; ">++</span><span style="color: #000000; ">;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>}</span></div><img src ="http://www.cppblog.com/guojingjia2006/aggbug/113690.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/guojingjia2006/" target="_blank">小果子</a> 2010-04-27 10:47 <a href="http://www.cppblog.com/guojingjia2006/archive/2010/04/27/113690.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>文件输入输出重定向</title><link>http://www.cppblog.com/guojingjia2006/archive/2009/03/11/76212.html</link><dc:creator>小果子</dc:creator><author>小果子</author><pubDate>Wed, 11 Mar 2009 05:15:00 GMT</pubDate><guid>http://www.cppblog.com/guojingjia2006/archive/2009/03/11/76212.html</guid><wfw:comment>http://www.cppblog.com/guojingjia2006/comments/76212.html</wfw:comment><comments>http://www.cppblog.com/guojingjia2006/archive/2009/03/11/76212.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/guojingjia2006/comments/commentRss/76212.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/guojingjia2006/services/trackbacks/76212.html</trackback:ping><description><![CDATA[<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; FONT-FAMILY: courier new; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #008080">&nbsp;1</span><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #000000">#include&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">iostream</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"><br></span><span style="COLOR: #008080">&nbsp;2</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>#include&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">windows.h</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"><br></span><span style="COLOR: #008080">&nbsp;3</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>#include&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">fstream</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"><br></span><span style="COLOR: #008080">&nbsp;4</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br></span><span style="COLOR: #008080">&nbsp;5</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #0000ff">using</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">namespace</span><span style="COLOR: #000000">&nbsp;std;<br></span><span style="COLOR: #008080">&nbsp;6</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;_tmain(</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;argc,&nbsp;_TCHAR</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">&nbsp;argv[])<br></span><span style="COLOR: #008080">&nbsp;7</span><span style="COLOR: #000000"><img id=Codehighlighter1_119_1069_Open_Image onclick="this.style.display='none'; Codehighlighter1_119_1069_Open_Text.style.display='none'; Codehighlighter1_119_1069_Closed_Image.style.display='inline'; Codehighlighter1_119_1069_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><img id=Codehighlighter1_119_1069_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_119_1069_Closed_Text.style.display='none'; Codehighlighter1_119_1069_Open_Image.style.display='inline'; Codehighlighter1_119_1069_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align=top></span><span id=Codehighlighter1_119_1069_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_119_1069_Open_Text><span style="COLOR: #000000">{<br></span><span style="COLOR: #008080">&nbsp;8</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;HANDLE&nbsp;hWrite,hRead;<br></span><span style="COLOR: #008080">&nbsp;9</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;SECURITY_ATTRIBUTES&nbsp;sa;<br></span><span style="COLOR: #008080">10</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;sa.bInheritHandle</span><span style="COLOR: #000000">=</span><span style="COLOR: #0000ff">true</span><span style="COLOR: #000000">;<br></span><span style="COLOR: #008080">11</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;sa.nLength</span><span style="COLOR: #000000">=</span><span style="COLOR: #0000ff">sizeof</span><span style="COLOR: #000000">(sa);<br></span><span style="COLOR: #008080">12</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;sa.lpSecurityDescriptor</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">NULL;<br></span><span style="COLOR: #008080">13</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top><br></span><span style="COLOR: #008080">14</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;HANDLE&nbsp;input</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">CreateFile(L</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">in.txt</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">,GENERIC_READ,NULL,</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">sa,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);<br></span><span style="COLOR: #008080">15</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;HANDLE&nbsp;output</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">CreateFile(L</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">out.txt</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">,GENERIC_WRITE</span><span style="COLOR: #000000">|</span><span style="COLOR: #000000">GENERIC_READ,NULL,</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">sa,OPEN_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL);<br></span><span style="COLOR: #008080">16</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top><br></span><span style="COLOR: #008080">17</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">::CreatePipe(&amp;hRead,&amp;hWrite,&amp;sa,0);</span><span style="COLOR: #008000"><br></span><span style="COLOR: #008080">18</span><span style="COLOR: #008000"><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;STARTUPINFO&nbsp;si;<br></span><span style="COLOR: #008080">19</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;ZeroMemory(</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">si,</span><span style="COLOR: #0000ff">sizeof</span><span style="COLOR: #000000">(si));<br></span><span style="COLOR: #008080">20</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;si.cb</span><span style="COLOR: #000000">=</span><span style="COLOR: #0000ff">sizeof</span><span style="COLOR: #000000">(si);<br></span><span style="COLOR: #008080">21</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;::GetStartupInfo(</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">si);<br></span><span style="COLOR: #008080">22</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;si.dwFlags&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;STARTF_USESHOWWINDOW&nbsp;</span><span style="COLOR: #000000">|</span><span style="COLOR: #000000">&nbsp;STARTF_USESTDHANDLES;<br></span><span style="COLOR: #008080">23</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;si.hStdError</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">;<br></span><span style="COLOR: #008080">24</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;si.hStdInput</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">input;<br></span><span style="COLOR: #008080">25</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;si.hStdOutput</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">output;<br></span><span style="COLOR: #008080">26</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;si.wShowWindow</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">SW_HIDE;<br></span><span style="COLOR: #008080">27</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top><br></span><span style="COLOR: #008080">28</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;PROCESS_INFORMATION&nbsp;pi;<br></span><span style="COLOR: #008080">29</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top><br></span><span style="COLOR: #008080">30</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;CreateProcess(L</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">..\\Debug\\test.exe</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">,</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">,</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">,</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">,</span><span style="COLOR: #0000ff">true</span><span style="COLOR: #000000">,</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">,</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">,</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">,</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">si,</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">pi);<br></span><span style="COLOR: #008080">31</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">::CloseHandle(hWrite);</span><span style="COLOR: #008000"><br></span><span style="COLOR: #008080">32</span><span style="COLOR: #008000"><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;WaitForSingleObject(pi.hProcess,INFINITE);<br></span><span style="COLOR: #008080">33</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;CloseHandle(input);<br></span><span style="COLOR: #008080">34</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;CloseHandle(output);<br></span><span style="COLOR: #008080">35</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">char&nbsp;mm[1000];<br></span><span style="COLOR: #008080">36</span><span style="COLOR: #008000"><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">memset(mm,0,sizeof(mm));<br></span><span style="COLOR: #008080">37</span><span style="COLOR: #008000"><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">DWORD&nbsp;d;<br></span><span style="COLOR: #008080">38</span><span style="COLOR: #008000"><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">ReadFile(hRead,mm,1000,&amp;d,0);<br></span><span style="COLOR: #008080">39</span><span style="COLOR: #008000"><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top><br></span><span style="COLOR: #008080">40</span><span style="COLOR: #008000"><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">cout&lt;&lt;mm&lt;&lt;endl;</span><span style="COLOR: #008000"><br></span><span style="COLOR: #008080">41</span><span style="COLOR: #008000"><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top></span><span style="COLOR: #000000"><br></span><span style="COLOR: #008080">42</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">;<br></span><span style="COLOR: #008080">43</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>}</span></span></div>
<img src ="http://www.cppblog.com/guojingjia2006/aggbug/76212.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/guojingjia2006/" target="_blank">小果子</a> 2009-03-11 13:15 <a href="http://www.cppblog.com/guojingjia2006/archive/2009/03/11/76212.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>win32-笔记</title><link>http://www.cppblog.com/guojingjia2006/archive/2008/08/25/59919.html</link><dc:creator>小果子</dc:creator><author>小果子</author><pubDate>Mon, 25 Aug 2008 08:05:00 GMT</pubDate><guid>http://www.cppblog.com/guojingjia2006/archive/2008/08/25/59919.html</guid><wfw:comment>http://www.cppblog.com/guojingjia2006/comments/59919.html</wfw:comment><comments>http://www.cppblog.com/guojingjia2006/archive/2008/08/25/59919.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/guojingjia2006/comments/commentRss/59919.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/guojingjia2006/services/trackbacks/59919.html</trackback:ping><description><![CDATA[<p>&#160;</p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; FONT-FAMILY: courier new; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #000000">1</span><span style="COLOR: #000000">.创建DirectDraw对象的方法,创建主DirectDraw对象并使用QueryInterface()得到一个IDirectDraw7接口.<br>或者直接用DirectDrawCreateEx()创建一个DirectDraw7的接口.<br>HRESULT&nbsp;WINAPI&nbsp;DirectDrawCreate(GUID&nbsp;FAR&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">lpGUID,</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">guid&nbsp;of&nbsp;object</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000">LPDIRECTDRAW&nbsp;FAR&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">lplpDD,</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">receives&nbsp;interface</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000">IUnknown&nbsp;FAR&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">pUnkOuter);</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">com&nbsp;stuff</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000">LpGUID</span><span style="COLOR: #000000">--</span><span style="COLOR: #000000">NULL,(视频卡驱动的Globally&nbsp;Unique&nbsp;Identifier)<br>lplpDD</span><span style="COLOR: #000000">--</span><span style="COLOR: #000000">返回一个DirectDraw的接口而不是DirectDraw7的接口.<br>pUnkOuter</span><span style="COLOR: #000000">--</span><span style="COLOR: #000000">NULL(always&nbsp;</span><span style="COLOR: #0000ff">set</span><span style="COLOR: #000000">&nbsp;to&nbsp;zero)</span></div>
<p>&nbsp;</p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; FONT-FAMILY: courier new; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #000000">自行发送消息:<br></span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">.SendMessage()</span><span style="COLOR: #000000">---</span><span style="COLOR: #000000">send&nbsp;a&nbsp;message&nbsp;which&nbsp;</span><span style="COLOR: #0000ff">is</span><span style="COLOR: #000000">&nbsp;processed&nbsp;immediately&nbsp;to&nbsp;a&nbsp;window.In&nbsp;fact,<br></span><span style="COLOR: #000000">it&nbsp;calls&nbsp;WinProc().<br></span><span style="COLOR: #000000">LRESULT&nbsp;SendMessage(HWND&nbsp;hWnd,UINT,WPARAM,LPARAM);<br></span><span style="COLOR: #000000"><br></span><span style="COLOR: #000000">2</span><span style="COLOR: #000000">.PostMessage()</span><span style="COLOR: #000000">---</span><span style="COLOR: #000000">send&nbsp;a&nbsp;message&nbsp;to&nbsp;the&nbsp;messagequeue.just&nbsp;that.</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">&nbsp;it</span><span style="COLOR: #000000">'</span><span style="COLOR: #000000">s&nbsp;succeed,it&nbsp;return&nbsp;a&nbsp;value(!0).</span><span style="COLOR: #000000"><br></span><span style="COLOR: #000000">BOOL&nbsp;PostMessage(HWND&nbsp;hWnd,UINT&nbsp;Msg,WPARAM&nbsp;wParam,LPARAM&nbsp;lParam);</span></div>
<p>&nbsp;</p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; FONT-FAMILY: courier new; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #000000">1</span><span style="COLOR: #000000">.SetBkMode(hdc,TRANSPARENT);<br></span><span style="COLOR: #000000">2</span><span style="COLOR: #000000">.FillRect(hdc,</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">r,(HBRUSH)GetStockObject(WHITE_BRUSH));<br></span><span style="COLOR: #000000">3</span><span style="COLOR: #000000">.CreateSolidBrush(RGB(</span><span style="COLOR: #000000">255</span><span style="COLOR: #000000">,</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">,</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">));<br></span><span style="COLOR: #000000">4</span><span style="COLOR: #000000">.wchar_t&nbsp;tmp[</span><span style="COLOR: #000000">20</span><span style="COLOR: #000000; FONT-FAMILY: courier new">];<br>&nbsp;&nbsp;&nbsp;&nbsp;GetDlgItemText(hDlg,IDC_EDIT1,tmp,</span><span style="COLOR: #000000">20</span><span style="COLOR: #000000">);<br>&nbsp;&nbsp;&nbsp;&nbsp;::wstringstream&nbsp;</span><span style="COLOR: #0000ff">is</span><span style="COLOR: #000000">;<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">is</span><span style="COLOR: #000000">&lt;&lt;</span><span style="COLOR: #000000">tmp;<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">is</span><span style="COLOR: #000000">&gt;&gt;</span><span style="COLOR: #000000">size;&nbsp;&nbsp;&nbsp;<br>5.InvalidateRect(hWnd,0,1);<br>6.DialogBox(hInst, MAKEINTRESOURCE(IDD_DIALOG1), hWnd, inputsize);<br>7.WM_CLOSE is sent before WM_DESTYOY.<br></span></div>
<br>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; FONT-FAMILY: courier new; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #008000">//</span><span style="COLOR: #008000">创建全屏(空白)模式窗口:</span><span style="COLOR: #008000"><br></span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">(</span><span style="COLOR: #000000">!</span><span style="COLOR: #000000">(hWnd&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;CreateWindowEx(NULL,</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">extend&nbsp;style</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000">WINDOW_CLASS_NAME,</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">class</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">BX</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">,</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">title</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000">WS_POP</span><span style="COLOR: #000000">|</span><span style="COLOR: #000000">WS_VISIBLE,<br></span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">,</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">,</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">initial&nbsp;x,y</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000">GetSystemMetrics(SM_CXSCREEN),</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">Initial&nbsp;width</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000">GetSystemMetrics(SM_CYSCREEN),</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">Initial&nbsp;height</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000">NULL,</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">handle&nbsp;to&nbsp;parent</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000">NULL,</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">handle&nbsp;to&nbsp;menu</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000">hinstance,</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">instance&nbsp;of&nbsp;this&nbsp;application</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000">NULL)))</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">extra&nbsp;creation&nbsp;parms</span><span style="COLOR: #008000"><br></span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;(</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">);</span></div>
<img src ="http://www.cppblog.com/guojingjia2006/aggbug/59919.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/guojingjia2006/" target="_blank">小果子</a> 2008-08-25 16:05 <a href="http://www.cppblog.com/guojingjia2006/archive/2008/08/25/59919.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>